From cef4fd500765cf34080c2526b4f8bb99882eb7a7 Mon Sep 17 00:00:00 2001 From: ashenoy-arista <145506336+ashenoy-arista@users.noreply.github.com> Date: Fri, 31 Jan 2025 08:47:17 -0800 Subject: [PATCH] Feat(eos_designs): Add support for l3_port_channel_interfaces for WAN (#4752) Co-authored-by: Carl Buchmann Co-authored-by: Claus Holbech Co-authored-by: Guillaume Mulocher Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .../documentation/devices/inet-cloud.md | 38 +- .../documentation/devices/site3-wan1.md | 48 +- .../cv-pathfinder/group_vars/SITE3.yml | 19 +- .../cv-pathfinder/group_vars/TRANSPORTS.yml | 9 +- .../cv-pathfinder/images/ansible-groups.svg | 2 +- .../cv-pathfinder/images/site3-lan.svg | 2 +- .../cv-pathfinder/images/site3-physical.svg | 2 +- .../cv-pathfinder/images/wan-example-topo.svg | 2 +- .../intended/configs/inet-cloud.cfg | 16 +- .../intended/configs/site3-wan1.cfg | 26 +- .../structured_configs/inet-cloud.yml | 25 +- .../structured_configs/site3-wan1.yml | 45 +- ...ssing-on-l3-port-channel-wan-interface.yml | 27 + .../ipv4-acl-in-missing-on-wan-interface.yml | 2 +- ...l-sub-interface-with-member-interfaces.yml | 24 + ...3-port-channel-sub-interface-with-mode.yml | 22 + ...arent-of-l3-port-channel-sub-interface.yml | 27 + .../inventory/hosts.yml | 4 + .../intended/configs/cv-pathfinder-edge1.cfg | 103 +- .../configs/node-type-l3-port-channels.cfg | 314 ++ .../cv-pathfinder-edge1.yml | 199 +- .../cv-pathfinder-edge4A.yml | 4 + .../cv-pathfinder-edge4B.yml | 4 + .../node-type-l3-port-channels.yml | 521 ++ .../group_vars/CV_PATHFINDER_TESTS.yml | 85 +- .../host_vars/cv-pathfinder-edge1.yml | 7 + .../host_vars/node-type-l3-port-channels.yml | 164 + .../inventory/hosts.yml | 1 + .../avd/roles/eos_designs/docs/how-to/wan.md | 18 +- .../management-flow-tracking-settings.md | 10 + .../node-type-l3-interfaces-configuration.md | 22 +- ...ode-type-l3-port-channels-configuration.md | 741 +++ .../pyavd/_eos_designs/schema/__init__.py | 4612 ++++++++++++++++- .../schema/eos_designs.schema.yml | 231 +- .../defs_node_type.schema.yml | 8 +- .../defs_node_type_l3_interfaces.schema.yml | 2 +- ...defs_node_type_l3_port_channels.schema.yml | 235 + .../fabric_flow_tracking.schema.yml | 4 + .../shared_utils/flow_tracking.py | 4 + .../pyavd/_eos_designs/shared_utils/misc.py | 92 +- .../_eos_designs/shared_utils/routing.py | 2 +- .../pyavd/_eos_designs/shared_utils/wan.py | 96 +- .../structured_config/base/__init__.py | 6 +- .../structured_config/base/utils.py | 2 +- .../structured_config/metadata/cv_tags.py | 56 +- .../network_services/utils_wan.py | 10 +- .../structured_config/overlay/stun.py | 2 + .../underlay/ethernet_interfaces.py | 16 + .../underlay/ip_access_lists.py | 11 +- .../underlay/port_channel_interfaces.py | 45 + .../underlay/static_routes.py | 18 +- .../structured_config/underlay/utils.py | 227 +- .../api/interface_descriptions/__init__.py | 10 +- 53 files changed, 7973 insertions(+), 249 deletions(-) create mode 100644 ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/ipv4-acl-in-missing-on-l3-port-channel-wan-interface.yml create mode 100644 ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/l3-port-channel-sub-interface-with-member-interfaces.yml create mode 100644 ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/l3-port-channel-sub-interface-with-mode.yml create mode 100644 ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/missing-parent-of-l3-port-channel-sub-interface.yml create mode 100644 ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/configs/node-type-l3-port-channels.cfg create mode 100644 ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/node-type-l3-port-channels.yml create mode 100644 ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/host_vars/node-type-l3-port-channels.yml create mode 100644 ansible_collections/arista/avd/roles/eos_designs/docs/tables/node-type-l3-port-channels-configuration.md create mode 100644 python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_node_type_l3_port_channels.schema.yml diff --git a/ansible_collections/arista/avd/examples/cv-pathfinder/documentation/devices/inet-cloud.md b/ansible_collections/arista/avd/examples/cv-pathfinder/documentation/devices/inet-cloud.md index 0f797e3b44c..890cd6133c5 100644 --- a/ansible_collections/arista/avd/examples/cv-pathfinder/documentation/devices/inet-cloud.md +++ b/ansible_collections/arista/avd/examples/cv-pathfinder/documentation/devices/inet-cloud.md @@ -26,6 +26,7 @@ - [Internal VLAN Allocation Policy Device Configuration](#internal-vlan-allocation-policy-device-configuration) - [Interfaces](#interfaces) - [Ethernet Interfaces](#ethernet-interfaces) + - [Port-Channel Interfaces](#port-channel-interfaces) - [Loopback Interfaces](#loopback-interfaces) - [Routing](#routing) - [Service Routing Protocols Model](#service-routing-protocols-model) @@ -235,7 +236,7 @@ dhcp server | -------------- | --------- | --------- | | Ethernet5 | True | - | | Ethernet6 | True | - | -| Ethernet8 | True | - | +| Port-Channel8 | True | - | ## Monitoring @@ -306,7 +307,10 @@ vlan internal order ascending range 1006 1199 | Ethernet5 | site1-wan1-Ethernet4 | - | 100.64.10.1/24 | default | - | False | - | - | | Ethernet6 | site1-wan2-Ethernet4 | - | 100.64.11.1/24 | default | - | False | - | - | | Ethernet7 | site2-wan2-Ethernet4 | - | 100.64.21.1/24 | default | - | False | - | - | -| Ethernet8 | site3-wan1-Ethernet4 | - | 100.64.30.1/24 | default | - | False | - | - | +| Ethernet8 | - | 8 | *100.64.30.1/24 | **default | **- | *False | **- | **- | +| Ethernet9 | - | 8 | *100.64.30.1/24 | **default | **- | *False | **- | **- | + +*Inherited from Port-Channel Interface #### Ethernet Interfaces Device Configuration @@ -345,7 +349,35 @@ interface Ethernet7 ip address 100.64.21.1/24 ! interface Ethernet8 - description site3-wan1-Ethernet4 + no shutdown + channel-group 8 mode active +! +interface Ethernet9 + no shutdown + channel-group 8 mode active +``` + +### Port-Channel Interfaces + +#### Port-Channel Interfaces Summary + +##### L2 + +| Interface | Description | Mode | VLANs | Native VLAN | Trunk Group | LACP Fallback Timeout | LACP Fallback Mode | MLAG ID | EVPN ESI | +| --------- | ----------- | ---- | ----- | ----------- | ------------| --------------------- | ------------------ | ------- | -------- | + +##### IPv4 + +| Interface | Description | MLAG ID | IP Address | VRF | MTU | Shutdown | ACL In | ACL Out | +| --------- | ----------- | ------- | ---------- | --- | --- | -------- | ------ | ------- | +| Port-Channel8 | site3-wan1-Port-Channel4 | - | 100.64.30.1/24 | default | - | False | - | - | + +#### Port-Channel Interfaces Device Configuration + +```eos +! +interface Port-Channel8 + description site3-wan1-Port-Channel4 no shutdown no switchport ip address 100.64.30.1/24 diff --git a/ansible_collections/arista/avd/examples/cv-pathfinder/documentation/devices/site3-wan1.md b/ansible_collections/arista/avd/examples/cv-pathfinder/documentation/devices/site3-wan1.md index 734f7848491..ce35ebaff8e 100644 --- a/ansible_collections/arista/avd/examples/cv-pathfinder/documentation/devices/site3-wan1.md +++ b/ansible_collections/arista/avd/examples/cv-pathfinder/documentation/devices/site3-wan1.md @@ -33,6 +33,7 @@ - [Interfaces](#interfaces) - [DPS Interfaces](#dps-interfaces) - [Ethernet Interfaces](#ethernet-interfaces) + - [Port-Channel Interfaces](#port-channel-interfaces) - [Loopback Interfaces](#loopback-interfaces) - [VXLAN Interface](#vxlan-interface) - [Routing](#routing) @@ -287,7 +288,7 @@ daemon TerminAttr | Tracker Name | Record Export On Inactive Timeout | Record Export On Interval | Number of Exporters | Applied On | | ------------ | --------------------------------- | ------------------------- | ------------------- | ---------- | -| FLOW-TRACKER | 70000 | 5000 | 1 | Dps1
Ethernet1.666
Ethernet1.42
Ethernet4 | +| FLOW-TRACKER | 70000 | 5000 | 1 | Dps1
Ethernet1.666
Ethernet1.42
Port-Channel4 | ##### Exporters Summary @@ -430,7 +431,10 @@ interface Dps1 | --------- | ----------- | ------------- | ---------- | ----| ---- | -------- | ------ | ------- | | Ethernet1.42 | RED-TEST | - | 10.42.3.1/24 | RED | - | False | - | - | | Ethernet1.666 | BLUE-TEST | - | 10.66.3.1/24 | BLUE | - | False | - | - | -| Ethernet4 | REGION2-INTERNET-CORP_inet-site3-wan1_inet-cloud_Ethernet8 | - | dhcp | default | - | False | ACL-INTERNET-IN_Ethernet4 | - | +| Ethernet4 | inet-cloud_Ethernet8 | 4 | *dhcp | **default | **- | *False | *ACL-INTERNET-IN_Port-Channel4 | **- | +| Ethernet5 | inet-cloud_Ethernet9 | 4 | *dhcp | **default | **- | *False | *ACL-INTERNET-IN_Port-Channel4 | **- | + +*Inherited from Port-Channel Interface #### Ethernet Interfaces Device Configuration @@ -459,13 +463,43 @@ interface Ethernet1.666 ip address 10.66.3.1/24 ! interface Ethernet4 - description REGION2-INTERNET-CORP_inet-site3-wan1_inet-cloud_Ethernet8 + description inet-cloud_Ethernet8 + no shutdown + channel-group 4 mode active +! +interface Ethernet5 + description inet-cloud_Ethernet9 + no shutdown + channel-group 4 mode active +``` + +### Port-Channel Interfaces + +#### Port-Channel Interfaces Summary + +##### L2 + +| Interface | Description | Mode | VLANs | Native VLAN | Trunk Group | LACP Fallback Timeout | LACP Fallback Mode | MLAG ID | EVPN ESI | +| --------- | ----------- | ---- | ----- | ----------- | ------------| --------------------- | ------------------ | ------- | -------- | + +##### IPv4 + +| Interface | Description | MLAG ID | IP Address | VRF | MTU | Shutdown | ACL In | ACL Out | +| --------- | ----------- | ------- | ---------- | --- | --- | -------- | ------ | ------- | +| Port-Channel4 | REGION2-INTERNET-CORP_inet-site3-wan1_inet-cloud_Port-Channel8 | - | dhcp | default | - | False | ACL-INTERNET-IN_Port-Channel4 | - | + +#### Port-Channel Interfaces Device Configuration + +```eos +! +interface Port-Channel4 + description REGION2-INTERNET-CORP_inet-site3-wan1_inet-cloud_Port-Channel8 no shutdown no switchport flow tracker hardware FLOW-TRACKER ip address dhcp dhcp client accept default-route - ip access-group ACL-INTERNET-IN_Ethernet4 in + ip access-group ACL-INTERNET-IN_Port-Channel4 in ``` ### Loopback Interfaces @@ -1011,7 +1045,7 @@ ip extcommunity-list ECL-EVPN-SOO permit soo 192.168.255.11:203 ```eos ! -ip access-list ACL-INTERNET-IN_Ethernet4 +ip access-list ACL-INTERNET-IN_Port-Channel4 1 remark Not for PRODUCTION: This ACL is built this way because the lab has an out-of-band interface 10 permit udp any host 100.64.30.2 eq isakmp non500-isakmp 30 permit icmp any host 100.64.30.2 @@ -1168,7 +1202,7 @@ application traffic recognition | Interface name | Public address | STUN server profile(s) | | -------------- | -------------- | ---------------------- | -| Ethernet4 | - | INTERNET-pf1-Ethernet2
INTERNET-pf2-Ethernet2 | +| Port-Channel4 | - | INTERNET-pf1-Ethernet2
INTERNET-pf2-Ethernet2 | ###### Dynamic Peers Settings @@ -1206,7 +1240,7 @@ router path-selection path-group INTERNET id 102 ipsec profile CP-PROFILE ! - local interface Ethernet4 + local interface Port-Channel4 stun server-profile INTERNET-pf1-Ethernet2 INTERNET-pf2-Ethernet2 ! peer dynamic diff --git a/ansible_collections/arista/avd/examples/cv-pathfinder/group_vars/SITE3.yml b/ansible_collections/arista/avd/examples/cv-pathfinder/group_vars/SITE3.yml index c0d78381609..76390362f71 100644 --- a/ansible_collections/arista/avd/examples/cv-pathfinder/group_vars/SITE3.yml +++ b/ansible_collections/arista/avd/examples/cv-pathfinder/group_vars/SITE3.yml @@ -23,10 +23,21 @@ wan_router: id: 11 mgmt_ip: 192.168.17.20/24 uplink_switches: [site3-leaf1] - l3_interfaces: - - name: Ethernet4 - peer_interface: Ethernet8 + l3_port_channels: + - name: Port-Channel4 + mode: active + member_interfaces: + - name: Ethernet4 + peer_interface: Ethernet8 + - name: Ethernet5 + peer_interface: Ethernet9 + peer: inet-cloud + ip_address: dhcp dhcp_ip: 100.64.30.2 - profile: INTERNET-WAN-INTERFACE + dhcp_accept_default_route: true + ipv4_acl_in: ACL-INTERNET-IN + peer_port_channel: Port-Channel8 wan_carrier: REGION2-INTERNET-CORP wan_circuit_id: inet-site3-wan1 + flow_tracking: + enabled: true diff --git a/ansible_collections/arista/avd/examples/cv-pathfinder/group_vars/TRANSPORTS.yml b/ansible_collections/arista/avd/examples/cv-pathfinder/group_vars/TRANSPORTS.yml index 3a289d70903..2ec06ee7b45 100644 --- a/ansible_collections/arista/avd/examples/cv-pathfinder/group_vars/TRANSPORTS.yml +++ b/ansible_collections/arista/avd/examples/cv-pathfinder/group_vars/TRANSPORTS.yml @@ -50,8 +50,13 @@ spine: - name: Ethernet7 description: site2-wan2-Ethernet4 ip_address: 100.64.21.1/24 - - name: Ethernet8 - description: site3-wan1-Ethernet4 + l3_port_channels: + - name: Port-Channel8 + mode: active + description: site3-wan1-Port-Channel4 + member_interfaces: + - name: Ethernet8 + - name: Ethernet9 ip_address: 100.64.30.1/24 structured_config: dhcp_server_ipv4: true diff --git a/ansible_collections/arista/avd/examples/cv-pathfinder/images/ansible-groups.svg b/ansible_collections/arista/avd/examples/cv-pathfinder/images/ansible-groups.svg index 1db98ae59d6..5f1accd7cb7 100644 --- a/ansible_collections/arista/avd/examples/cv-pathfinder/images/ansible-groups.svg +++ b/ansible_collections/arista/avd/examples/cv-pathfinder/images/ansible-groups.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/ansible_collections/arista/avd/examples/cv-pathfinder/images/site3-lan.svg b/ansible_collections/arista/avd/examples/cv-pathfinder/images/site3-lan.svg index e8d9328a302..357ffab3b13 100644 --- a/ansible_collections/arista/avd/examples/cv-pathfinder/images/site3-lan.svg +++ b/ansible_collections/arista/avd/examples/cv-pathfinder/images/site3-lan.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/ansible_collections/arista/avd/examples/cv-pathfinder/images/site3-physical.svg b/ansible_collections/arista/avd/examples/cv-pathfinder/images/site3-physical.svg index ccd5dd5fed7..ab2342a9edf 100644 --- a/ansible_collections/arista/avd/examples/cv-pathfinder/images/site3-physical.svg +++ b/ansible_collections/arista/avd/examples/cv-pathfinder/images/site3-physical.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/ansible_collections/arista/avd/examples/cv-pathfinder/images/wan-example-topo.svg b/ansible_collections/arista/avd/examples/cv-pathfinder/images/wan-example-topo.svg index 0261a952bcb..3645aa945b0 100644 --- a/ansible_collections/arista/avd/examples/cv-pathfinder/images/wan-example-topo.svg +++ b/ansible_collections/arista/avd/examples/cv-pathfinder/images/wan-example-topo.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/ansible_collections/arista/avd/examples/cv-pathfinder/intended/configs/inet-cloud.cfg b/ansible_collections/arista/avd/examples/cv-pathfinder/intended/configs/inet-cloud.cfg index f38e4cdf0e6..5e761acc3dc 100644 --- a/ansible_collections/arista/avd/examples/cv-pathfinder/intended/configs/inet-cloud.cfg +++ b/ansible_collections/arista/avd/examples/cv-pathfinder/intended/configs/inet-cloud.cfg @@ -54,6 +54,13 @@ management api http-commands ! aaa authorization exec default local ! +interface Port-Channel8 + description site3-wan1-Port-Channel4 + no shutdown + no switchport + ip address 100.64.30.1/24 + dhcp server ipv4 +! interface Ethernet1 description pf1-Ethernet2 no shutdown @@ -87,11 +94,12 @@ interface Ethernet7 ip address 100.64.21.1/24 ! interface Ethernet8 - description site3-wan1-Ethernet4 no shutdown - no switchport - ip address 100.64.30.1/24 - dhcp server ipv4 + channel-group 8 mode active +! +interface Ethernet9 + no shutdown + channel-group 8 mode active ! interface Loopback0 description ROUTER_ID diff --git a/ansible_collections/arista/avd/examples/cv-pathfinder/intended/configs/site3-wan1.cfg b/ansible_collections/arista/avd/examples/cv-pathfinder/intended/configs/site3-wan1.cfg index 58fbee377cb..f5ab8876274 100644 --- a/ansible_collections/arista/avd/examples/cv-pathfinder/intended/configs/site3-wan1.cfg +++ b/ansible_collections/arista/avd/examples/cv-pathfinder/intended/configs/site3-wan1.cfg @@ -104,7 +104,7 @@ router path-selection path-group INTERNET id 102 ipsec profile CP-PROFILE ! - local interface Ethernet4 + local interface Port-Channel4 stun server-profile INTERNET-pf1-Ethernet2 INTERNET-pf2-Ethernet2 ! peer dynamic @@ -196,6 +196,15 @@ ip security key controller profile DP-PROFILE ! +interface Port-Channel4 + description REGION2-INTERNET-CORP_inet-site3-wan1_inet-cloud_Port-Channel8 + no shutdown + no switchport + flow tracker hardware FLOW-TRACKER + ip address dhcp + dhcp client accept default-route + ip access-group ACL-INTERNET-IN_Port-Channel4 in +! interface Dps1 description DPS Interface mtu 9194 @@ -225,13 +234,14 @@ interface Ethernet1.666 ip address 10.66.3.1/24 ! interface Ethernet4 - description REGION2-INTERNET-CORP_inet-site3-wan1_inet-cloud_Ethernet8 + description inet-cloud_Ethernet8 no shutdown - no switchport - flow tracker hardware FLOW-TRACKER - ip address dhcp - dhcp client accept default-route - ip access-group ACL-INTERNET-IN_Ethernet4 in + channel-group 4 mode active +! +interface Ethernet5 + description inet-cloud_Ethernet9 + no shutdown + channel-group 4 mode active ! interface Loopback0 description ROUTER_ID @@ -296,7 +306,7 @@ application traffic recognition field-set l4-port VOICE-PORTS 666-667 ! -ip access-list ACL-INTERNET-IN_Ethernet4 +ip access-list ACL-INTERNET-IN_Port-Channel4 1 remark Not for PRODUCTION: This ACL is built this way because the lab has an out-of-band interface 10 permit udp any host 100.64.30.2 eq isakmp non500-isakmp 30 permit icmp any host 100.64.30.2 diff --git a/ansible_collections/arista/avd/examples/cv-pathfinder/intended/structured_configs/inet-cloud.yml b/ansible_collections/arista/avd/examples/cv-pathfinder/intended/structured_configs/inet-cloud.yml index bf33eea9e9a..23a49aa1091 100644 --- a/ansible_collections/arista/avd/examples/cv-pathfinder/intended/structured_configs/inet-cloud.yml +++ b/ansible_collections/arista/avd/examples/cv-pathfinder/intended/structured_configs/inet-cloud.yml @@ -56,13 +56,17 @@ ethernet_interfaces: switchport: enabled: false - name: Ethernet8 - description: site3-wan1-Ethernet4 shutdown: false - ip_address: 100.64.30.1/24 - dhcp_server_ipv4: true - peer_type: l3_interface - switchport: - enabled: false + channel_group: + id: 8 + mode: active + peer_type: l3_port_channel_member +- name: Ethernet9 + shutdown: false + channel_group: + id: 8 + mode: active + peer_type: l3_port_channel_member hostname: inet-cloud ip_name_servers: - ip_address: 192.168.17.1 @@ -112,6 +116,15 @@ ntp: - name: 0.pool.ntp.org preferred: true vrf: MGMT +port_channel_interfaces: +- name: Port-Channel8 + description: site3-wan1-Port-Channel4 + shutdown: false + ip_address: 100.64.30.1/24 + dhcp_server_ipv4: true + peer_type: l3_port_channel + switchport: + enabled: false router_bgp: as: '65666' router_id: 172.31.255.23 diff --git a/ansible_collections/arista/avd/examples/cv-pathfinder/intended/structured_configs/site3-wan1.yml b/ansible_collections/arista/avd/examples/cv-pathfinder/intended/structured_configs/site3-wan1.yml index 127e2f149e7..07130255cb7 100644 --- a/ansible_collections/arista/avd/examples/cv-pathfinder/intended/structured_configs/site3-wan1.yml +++ b/ansible_collections/arista/avd/examples/cv-pathfinder/intended/structured_configs/site3-wan1.yml @@ -114,18 +114,23 @@ ethernet_interfaces: peer_interface: Ethernet1 VLAN 42 peer_type: l2leaf - name: Ethernet4 - description: REGION2-INTERNET-CORP_inet-site3-wan1_inet-cloud_Ethernet8 + description: inet-cloud_Ethernet8 shutdown: false - flow_tracker: - hardware: FLOW-TRACKER - ip_address: dhcp - dhcp_client_accept_default_route: true - access_group_in: ACL-INTERNET-IN_Ethernet4 + channel_group: + id: 4 + mode: active peer: inet-cloud peer_interface: Ethernet8 - peer_type: l3_interface - switchport: - enabled: false + peer_type: l3_port_channel_member +- name: Ethernet5 + description: inet-cloud_Ethernet9 + shutdown: false + channel_group: + id: 4 + mode: active + peer: inet-cloud + peer_interface: Ethernet9 + peer_type: l3_port_channel_member flow_tracking: hardware: trackers: @@ -141,7 +146,7 @@ flow_tracking: shutdown: false hostname: site3-wan1 ip_access_lists: -- name: ACL-INTERNET-IN_Ethernet4 +- name: ACL-INTERNET-IN_Port-Channel4 entries: - sequence: 1 remark: 'Not for PRODUCTION: This ACL is built this way because the lab has an out-of-band interface' @@ -276,7 +281,7 @@ metadata: tags: - name: Type value: lan - - interface: Ethernet4 + - interface: Port-Channel4 tags: - name: Type value: wan @@ -295,7 +300,7 @@ metadata: - vtep_ip: 192.168.42.1 - vtep_ip: 192.168.42.2 interfaces: - - name: Ethernet4 + - name: Port-Channel4 carrier: REGION2-INTERNET-CORP circuit_id: inet-site3-wan1 pathgroup: INTERNET @@ -307,6 +312,20 @@ ntp: - name: 0.pool.ntp.org preferred: true vrf: MGMT +port_channel_interfaces: +- name: Port-Channel4 + description: REGION2-INTERNET-CORP_inet-site3-wan1_inet-cloud_Port-Channel8 + shutdown: false + ip_address: dhcp + dhcp_client_accept_default_route: true + access_group_in: ACL-INTERNET-IN_Port-Channel4 + flow_tracker: + hardware: FLOW-TRACKER + peer: inet-cloud + peer_interface: Port-Channel8 + peer_type: l3_port_channel + switchport: + enabled: false prefix_lists: - name: PL-LOOPBACKS-EVPN-OVERLAY sequence_numbers: @@ -532,7 +551,7 @@ router_path_selection: id: 102 ipsec_profile: CP-PROFILE local_interfaces: - - name: Ethernet4 + - name: Port-Channel4 stun: server_profiles: - INTERNET-pf1-Ethernet2 diff --git a/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/ipv4-acl-in-missing-on-l3-port-channel-wan-interface.yml b/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/ipv4-acl-in-missing-on-l3-port-channel-wan-interface.yml new file mode 100644 index 00000000000..0c17fe88e1a --- /dev/null +++ b/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/ipv4-acl-in-missing-on-l3-port-channel-wan-interface.yml @@ -0,0 +1,27 @@ +--- +type: wan_router +wan_mode: cv-pathfinder +wan_router: + nodes: + - bgp_as: 65000 + name: ipv4-acl-in-missing-on-l3-port-channel-wan-interface + id: 1 + loopback_ipv4_pool: 192.168.0.0/24 + vtep_loopback_ipv4_pool: 192.168.1.0/24 + l3_port_channels: + - name: Port-Channel5 + wan_carrier: BAR + ip_address: 172.16.0.2/30 + # ipv4_acl_in: TEST-IPV4-ACL-WITH-IP-FIELDS-IN Testing not setting ipv4_acl_in will raise an error. + +wan_carriers: + - name: BAR + path_group: INTERNET + +wan_path_groups: + - id: 100 + name: INTERNET + +expected_error_message: >- + 'ipv4_acl_in' must be set on WAN interfaces where 'wan_carrier' is set, + unless the carrier is configured as 'trusted' under 'wan_carriers'. 'ipv4_acl_in' is missing on L3 Port-Channel 'Port-Channel5'. diff --git a/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/ipv4-acl-in-missing-on-wan-interface.yml b/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/ipv4-acl-in-missing-on-wan-interface.yml index 0c2656b2281..5930aa1e75e 100644 --- a/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/ipv4-acl-in-missing-on-wan-interface.yml +++ b/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/ipv4-acl-in-missing-on-wan-interface.yml @@ -24,4 +24,4 @@ wan_path_groups: expected_error_message: >- 'ipv4_acl_in' must be set on WAN interfaces where 'wan_carrier' is set, - unless the carrier is configured as 'trusted' under 'wan_carriers'. 'ipv4_acl_in' is missing on interface 'Ethernet1'. + unless the carrier is configured as 'trusted' under 'wan_carriers'. 'ipv4_acl_in' is missing on L3 interface 'Ethernet1'. diff --git a/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/l3-port-channel-sub-interface-with-member-interfaces.yml b/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/l3-port-channel-sub-interface-with-member-interfaces.yml new file mode 100644 index 00000000000..d8da59055d5 --- /dev/null +++ b/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/l3-port-channel-sub-interface-with-member-interfaces.yml @@ -0,0 +1,24 @@ +--- +type: l3leaf +l3leaf: + nodes: + - bgp_as: 65000 + name: l3-port-channel-sub-interface-with-member-interfaces + id: 1 + loopback_ipv4_pool: 192.168.0.0/24 + vtep_loopback_ipv4_pool: 192.168.1.0/24 + l3_port_channels: + - name: Port-Channel5 + member_interfaces: + - name: Ethernet1/19 + peer_interface: Ethernet1/19 + # This is the offending sub interface + - name: Port-Channel5.108 + encapsulation_dot1q_vlan: 108 + member_interfaces: + - name: Ethernet1/19 + peer_interface: Ethernet1/19 + ip_address: 172.16.0.2/30 + +expected_error_message: >- + L3 Port-Channel sub-interface 'Port-Channel5.108' has 'member_interfaces' set. This is not a valid setting. diff --git a/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/l3-port-channel-sub-interface-with-mode.yml b/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/l3-port-channel-sub-interface-with-mode.yml new file mode 100644 index 00000000000..c4644223504 --- /dev/null +++ b/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/l3-port-channel-sub-interface-with-mode.yml @@ -0,0 +1,22 @@ +--- +type: l3leaf +l3leaf: + nodes: + - name: l3-port-channel-sub-interface-with-mode + bgp_as: 65000 + id: 1 + loopback_ipv4_pool: 192.168.0.0/24 + vtep_loopback_ipv4_pool: 192.168.1.0/24 + l3_port_channels: + - name: Port-Channel5 + member_interfaces: + - name: Ethernet1/19 + peer_interface: Ethernet1/19 + - name: Port-Channel5.108 + encapsulation_dot1q_vlan: 108 + # This is the offending input + mode: passive + ip_address: 172.16.0.2/30 + +expected_error_message: >- + L3 Port-Channel sub-interface 'Port-Channel5.108' has 'mode' set. This is not a valid setting. diff --git a/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/missing-parent-of-l3-port-channel-sub-interface.yml b/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/missing-parent-of-l3-port-channel-sub-interface.yml new file mode 100644 index 00000000000..282cca6d14e --- /dev/null +++ b/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/missing-parent-of-l3-port-channel-sub-interface.yml @@ -0,0 +1,27 @@ +--- +type: wan_router +wan_mode: cv-pathfinder +wan_router: + nodes: + - bgp_as: 65000 + name: missing-parent-of-l3-port-channel-sub-interface + id: 1 + loopback_ipv4_pool: 192.168.0.0/24 + vtep_loopback_ipv4_pool: 192.168.1.0/24 + l3_port_channels: + - name: Port-Channel5.108 + encapsulation_dot1q_vlan: 108 + wan_carrier: FOO + ip_address: 192.168.100.115/31 + peer: peer2 + peer_port_channel: Port-Channel15 + peer_ip: 192.168.1.15 +wan_carriers: + - name: FOO + path_group: INTERNET + trusted: true +wan_path_groups: + - id: 100 + name: INTERNET +expected_error_message: >- + One or more L3 Port-Channels 'Port-Channel5' need to be specified as they have sub-interfaces referencing them. 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 f06d98e4406..f23d7226e82 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 @@ -113,10 +113,14 @@ all: failure-adapter-ptp-profile-does-not-exist: failure-svi-grandparent-profile-does-not-exist: failure-svi-parent-profile-does-not-exist: + ipv4-acl-in-missing-on-l3-port-channel-wan-interface: ipv4-acl-in-missing-on-wan-interface: ipv4-acls: isis-system-id-format-missing-node-id: + l3-port-channel-sub-interface-with-member-interfaces: + l3-port-channel-sub-interface-with-mode: missing-avt-id-cv-pathfinder: + missing-parent-of-l3-port-channel-sub-interface: missing-prefix-list-in-cv-pathfinder: missing-prefix-list-definition-cv-pathfinder: missing-data-plane_cpu-allocation-max: diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/configs/cv-pathfinder-edge1.cfg b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/configs/cv-pathfinder-edge1.cfg index 9962486a0d2..7c51003d166 100644 --- a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/configs/cv-pathfinder-edge1.cfg +++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/configs/cv-pathfinder-edge1.cfg @@ -163,6 +163,15 @@ router path-selection local interface Ethernet3 stun server-profile INET-cv-pathfinder-pathfinder1-Ethernet1 INET-cv-pathfinder-pathfinder2-Ethernet1 ! + local interface Port-Channel1 + stun server-profile INET-cv-pathfinder-pathfinder1-Ethernet1 INET-cv-pathfinder-pathfinder2-Ethernet1 + ! + local interface Port-Channel450 + stun server-profile INET-cv-pathfinder-pathfinder1-Ethernet1 INET-cv-pathfinder-pathfinder2-Ethernet1 + ! + local interface Port-Channel540 + stun server-profile INET-cv-pathfinder-pathfinder1-Ethernet1 INET-cv-pathfinder-pathfinder2-Ethernet1 + ! peer dynamic ! peer static router-ip 192.168.144.2 @@ -323,12 +332,56 @@ ip security key controller profile DP-PROFILE ! +interface Port-Channel1 + description ATT_404_peerDeviceA_Port-Channel2 + no shutdown + no switchport + flow tracker hardware FLOW-TRACKER + ip address 172.15.5.7/31 +! +interface Port-Channel450 + description Orange_peerDevice10_Port-Channel455 + no shutdown + no switchport + ip address 172.15.5.8/31 +! +interface Port-Channel540 + description Comcast_peerDevice11_Port-Channel545 + no shutdown + no switchport + ip address 172.15.6.9/31 + ip access-group TEST-IPV4-ACL-WITH-IP-FIELDS-IN_Port-Channel540 in + ip access-group TEST-IPV4-ACL-WITH-IP-FIELDS-OUT_Port-Channel540 out +! interface Dps1 description DPS Interface mtu 9194 flow tracker hardware FLOW-TRACKER ip address 192.168.142.2/32 ! +interface Ethernet1/10 + description peerDevice10 + no shutdown + speed forced 10000full + channel-group 450 mode on +! +interface Ethernet1/16 + description peerDevice11 + no shutdown + speed auto 10000full + channel-group 540 mode active +! +interface Ethernet1/17 + description peerDevice11 + no shutdown + channel-group 540 mode active +! +interface Ethernet1/18 + description peerDevice11 + no shutdown + speed 1000full + channel-group 540 mode active +! interface Ethernet1/49 no shutdown no switchport @@ -367,6 +420,18 @@ interface Ethernet5 ip address dhcp dhcp client accept default-route ! +interface Ethernet6 + description peerDevice1_PeerDevIntf1 + no shutdown + speed forced 10000full + channel-group 1 mode active +! +interface Ethernet7 + description peerDeviceA + no shutdown + speed forced 10000full + channel-group 1 mode active +! interface Ethernet52 description P2P_site-ha-disabled-leaf_Ethernet2 no shutdown @@ -590,6 +655,14 @@ ip access-list TEST-IPV4-ACL-WITH-IP-FIELDS-IN_Ethernet1_49.3 15 deny ip any host 172.24.49.3 permit ip host 172.24.49.2 host 172.24.49.3 ! +ip access-list TEST-IPV4-ACL-WITH-IP-FIELDS-IN_Port-Channel540 + 15 deny ip any host 172.15.6.9 + permit ip host 172.31.0.11 host 172.15.6.9 +! +ip access-list TEST-IPV4-ACL-WITH-IP-FIELDS-OUT_Port-Channel540 + remark Some remark will not require source and destination fields. + permit ip host 172.15.6.9 any +! ip routing ip routing vrf ATTRACTED-VRF-FROM-UPLINK ip routing vrf IT @@ -603,7 +676,7 @@ ip prefix-list ALLOW-DEFAULT ! ip prefix-list PL2 seq 10 permit 5.0.0.0/0 - seq 20 deny 10.00.0.0/24 + seq 20 deny 10.0.0.0/24 ! ip prefix-list PL-LOOPBACKS-EVPN-OVERLAY seq 10 permit 192.168.42.0/24 eq 32 @@ -611,6 +684,9 @@ ip prefix-list PL-LOOPBACKS-EVPN-OVERLAY ip route 10.37.121.1/32 172.31.0.1 name IE-ZSCALER-PRI ip route 10.39.77.1/32 172.31.0.1 name IE-ZSCALER-SEC ip route 10.50.9.1/32 172.31.0.1 name IE-ZSCALER-TER +ip route 172.16.0.0/16 172.31.0.1 +ip route 172.17.0.0/16 172.31.0.10 +ip route 172.18.0.0/16 172.31.0.11 ! ip nat pool PORT-ONLY-POOL port-only port range 1500 65535 @@ -628,6 +704,21 @@ route-map RM-BGP-172.29.0.13-OUT permit 10 ! route-map RM-BGP-172.29.0.13-OUT deny 20 ! +route-map RM-BGP-172.31.0.1-IN permit 10 + match ip address prefix-list PL2 + set community no-advertise additive +! +route-map RM-BGP-172.31.0.1-OUT permit 10 + match ip address prefix-list ALLOW-DEFAULT +! +route-map RM-BGP-172.31.0.1-OUT deny 20 +! +route-map RM-BGP-172.31.0.10-IN permit 10 + match ip address prefix-list PL2 + set community no-advertise additive +! +route-map RM-BGP-172.31.0.10-OUT deny 10 +! route-map RM-BGP-UNDERLAY-PEERS-IN permit 40 description Mark prefixes originated from the LAN set extcommunity soo 192.168.42.2:511 additive @@ -676,6 +767,14 @@ router bgp 65000 neighbor 172.29.0.13 remote-as 64520 neighbor 172.29.0.13 route-map RM-BGP-172.29.0.13-IN in neighbor 172.29.0.13 route-map RM-BGP-172.29.0.13-OUT out + neighbor 172.31.0.1 remote-as 64520 + neighbor 172.31.0.1 description ATT_404_peerDeviceA_Port-Channel2 + neighbor 172.31.0.1 route-map RM-BGP-172.31.0.1-IN in + neighbor 172.31.0.1 route-map RM-BGP-172.31.0.1-OUT out + neighbor 172.31.0.10 remote-as 64520 + neighbor 172.31.0.10 description Orange_peerDevice10_Port-Channel455 + neighbor 172.31.0.10 route-map RM-BGP-172.31.0.10-IN in + neighbor 172.31.0.10 route-map RM-BGP-172.31.0.10-OUT out neighbor 192.168.144.2 peer group WAN-OVERLAY-PEERS neighbor 192.168.144.2 description cv-pathfinder-pathfinder1_Dps1 neighbor 192.168.144.3 peer group WAN-OVERLAY-PEERS @@ -693,6 +792,8 @@ router bgp 65000 no neighbor WAN-OVERLAY-PEERS activate neighbor 172.28.0.14 activate neighbor 172.29.0.13 activate + neighbor 172.31.0.1 activate + neighbor 172.31.0.10 activate ! address-family ipv4 sr-te neighbor WAN-OVERLAY-PEERS activate diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/configs/node-type-l3-port-channels.cfg b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/configs/node-type-l3-port-channels.cfg new file mode 100644 index 00000000000..72f3795e717 --- /dev/null +++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/configs/node-type-l3-port-channels.cfg @@ -0,0 +1,314 @@ +! +no enable password +no aaa root +! +agent KernelFib environment KERNELFIB_PROGRAM_ALL_ECMP=1 +! +flow tracking hardware + tracker FLOW-TRACKER + record export on inactive timeout 70000 + record export on interval 300000 + exporter CV-TELEMETRY + collector 127.0.0.1 + local interface Loopback0 + template interval 3600000 + no shutdown +! +service routing protocols model multi-agent +! +hostname node-type-l3-port-channels +! +router adaptive-virtual-topology + topology role edge + region AVD_Land_East id 43 + zone AVD_Land_East-ZONE id 1 + site Site511 id 511 + ! + policy DEFAULT-POLICY-WITH-CP + ! + match application-profile APP-PROFILE-CONTROL-PLANE + avt profile DEFAULT-POLICY-CONTROL-PLANE + ! + match application-profile default + avt profile DEFAULT-POLICY-DEFAULT + ! + profile DEFAULT-POLICY-CONTROL-PLANE + path-selection load-balance LB-DEFAULT-POLICY-CONTROL-PLANE + ! + profile DEFAULT-POLICY-DEFAULT + path-selection load-balance LB-DEFAULT-POLICY-DEFAULT + ! + vrf default + avt policy DEFAULT-POLICY-WITH-CP + avt profile DEFAULT-POLICY-DEFAULT id 1 + avt profile DEFAULT-POLICY-CONTROL-PLANE id 254 +! +router path-selection + tcp mss ceiling ipv4 ingress + ! + path-group INET id 101 + ipsec profile CP-PROFILE + ! + local interface Port-Channel2 + ! + local interface Port-Channel5 + ! + local interface Port-Channel5.100 + ! + local interface Port-Channel8 + ! + local interface Port-Channel19 + ! + peer dynamic + ! + load-balance policy LB-DEFAULT-POLICY-CONTROL-PLANE + path-group INET + ! + load-balance policy LB-DEFAULT-POLICY-DEFAULT + path-group INET +! +spanning-tree mode none +! +vrf instance MGMT +! +management api http-commands + protocol https + no shutdown + ! + vrf MGMT + no shutdown +! +management security + ! + ssl profile STUN-DTLS + tls versions 1.2 + trust certificate aristaDeviceCertProvisionerDefaultRootCA.crt + certificate STUN-DTLS.crt key STUN-DTLS.key +! +ip security + ike policy CP-IKE-POLICY + local-id 192.168.142.1 + ! + sa policy CP-SA-POLICY + esp encryption aes256gcm128 + pfs dh-group 14 + ! + sa policy DP-SA-POLICY + esp encryption aes256gcm128 + pfs dh-group 14 + ! + profile CP-PROFILE + ike-policy CP-IKE-POLICY + sa-policy CP-SA-POLICY + connection start + shared-key 7 ABCDEF1234567890 + dpd 10 50 clear + mode transport + ! + profile DP-PROFILE + sa-policy DP-SA-POLICY + connection start + shared-key 7 ABCDEF1234567890666 + dpd 10 50 clear + mode transport + ! + key controller + profile DP-PROFILE +! +interface Port-Channel2 + description Cybercast_101_peer1_Port-Channel10 + no shutdown + no switchport + flow tracker hardware FLOW-TRACKER + ip address 192.168.1.102/31 + service-profile TEST-QOS-PROFILE1 +! +interface Port-Channel5 + description StreamFast_102_peer2_Port-Channel15 + no shutdown + no switchport + ip address 192.168.1.105/31 + service-policy type qos input TEST_POLICY + service-profile TEST-QOS-PROFILE1 + ! TEST RAW_EOS_CLI + +! +interface Port-Channel5.100 + description ExtremeCable_105_peer2_Port-Channel15 + no shutdown + encapsulation dot1q vlan 108 + flow tracker hardware FLOW-TRACKER + ip address 192.168.100.115/31 + service-profile TEST-QOS-PROFILE2 +! +interface Port-Channel5.105 + description peer2_Port-Channel16 + no shutdown + encapsulation dot1q vlan 105 + flow tracker hardware FLOW-TRACKER + ip address 192.168.100.116/31 + service-profile TEST-QOS-PROFILE2 +! +interface Port-Channel8 + description BlizzardFast_peerDevice3_Port-Channel18 + no shutdown + no switchport + flow tracker hardware FLOW-TRACKER + ip address dhcp + dhcp client accept default-route + service-profile TEST-QOS-PROFILE3 + ! TEST RAW_EOS_CLI 123 + +! +interface Port-Channel19 + description BlizzardFast_peerDevice4_Port-Channel20 + shutdown + no switchport + ip address 192.168.1.19/31 +! +interface Dps1 + description DPS Interface + mtu 9194 + flow tracker hardware FLOW-TRACKER + ip address 192.168.142.1/32 +! +interface Ethernet1 + description peerDevice1_Ethernet11 + no shutdown + speed forced 10000full + channel-group 2 mode active +! +interface Ethernet1/4 + description peerDevice2_Ethernet1/12 + no shutdown + speed forced 10000full + channel-group 5 mode passive +! +interface Ethernet1/5 + description peer2 + no shutdown + speed forced 10000full + channel-group 5 mode passive +! +interface Ethernet1/10 + description peerDevice3_Ethernet1/10 + no shutdown + speed forced 1000full + channel-group 8 mode on +! +interface Ethernet1/19 + description peerDevice4_Ethernet1/19 + shutdown + channel-group 19 mode active +! +interface Ethernet1/20 + description peerDevice4_Ethernet1/20 + shutdown + channel-group 19 mode active +! +interface Ethernet2 + description peer1 + no shutdown + speed forced 10000full + channel-group 2 mode active +! +interface Ethernet3 + description Custom eth3 description + no shutdown + channel-group 2 mode active +! +interface Loopback0 + description ROUTER_ID + no shutdown + ip address 192.168.255.1/32 +! +interface Vxlan1 + description node-type-l3-port-channels_VTEP + vxlan source-interface Dps1 + vxlan udp-port 4789 + vxlan vrf default vni 1 +! +application traffic recognition + ! + application ipv4 APP-CONTROL-PLANE + destination prefix field-set PFX-PATHFINDERS + ! + application-profile APP-PROFILE-CONTROL-PLANE + application APP-CONTROL-PLANE + ! + field-set ipv4 prefix PFX-PATHFINDERS +! +ip routing +no ip routing vrf MGMT +! +ip extcommunity-list ECL-EVPN-SOO permit soo 192.168.255.1:511 +! +ip prefix-list PL-LOOPBACKS-EVPN-OVERLAY + seq 10 permit 192.168.255.0/24 eq 32 +! +ip route 0.0.0.0/0 192.168.1.103 +! +route-map RM-CONN-2-BGP permit 10 + match ip address prefix-list PL-LOOPBACKS-EVPN-OVERLAY + set extcommunity soo 192.168.255.1:511 additive +! +route-map RM-EVPN-EXPORT-VRF-DEFAULT permit 10 + match extcommunity ECL-EVPN-SOO +! +route-map RM-EVPN-SOO-IN deny 10 + match extcommunity ECL-EVPN-SOO +! +route-map RM-EVPN-SOO-IN permit 20 +! +route-map RM-EVPN-SOO-OUT permit 10 + set extcommunity soo 192.168.255.1:511 additive +! +router bfd + multihop interval 300 min-rx 300 multiplier 3 +! +router bgp 65005 + router-id 192.168.255.1 + update wait-install + no bgp default ipv4-unicast + maximum-paths 16 + neighbor WAN-OVERLAY-PEERS peer group + neighbor WAN-OVERLAY-PEERS remote-as 65005 + neighbor WAN-OVERLAY-PEERS update-source Dps1 + neighbor WAN-OVERLAY-PEERS bfd + neighbor WAN-OVERLAY-PEERS bfd interval 1000 min-rx 1000 multiplier 10 + neighbor WAN-OVERLAY-PEERS ttl maximum-hops 1 + neighbor WAN-OVERLAY-PEERS password 7 htm4AZe9mIQOO1uiMuGgYQ== + neighbor WAN-OVERLAY-PEERS send-community + neighbor WAN-OVERLAY-PEERS maximum-routes 0 + redistribute connected route-map RM-CONN-2-BGP + ! + address-family evpn + neighbor WAN-OVERLAY-PEERS activate + neighbor WAN-OVERLAY-PEERS route-map RM-EVPN-SOO-IN in + neighbor WAN-OVERLAY-PEERS route-map RM-EVPN-SOO-OUT out + neighbor WAN-OVERLAY-PEERS encapsulation path-selection + ! + address-family ipv4 + no neighbor WAN-OVERLAY-PEERS activate + ! + address-family ipv4 sr-te + neighbor WAN-OVERLAY-PEERS activate + ! + address-family link-state + neighbor WAN-OVERLAY-PEERS activate + path-selection + ! + address-family path-selection + bgp additional-paths receive + bgp additional-paths send any + neighbor WAN-OVERLAY-PEERS activate + ! + vrf default + rd 192.168.255.1:1 + route-target import evpn 1:1 + route-target export evpn 1:1 + route-target export evpn route-map RM-EVPN-EXPORT-VRF-DEFAULT +! +router traffic-engineering +! +end diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-edge1.yml b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-edge1.yml index 4f8bb0bc3be..2720f73d95e 100644 --- a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-edge1.yml +++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-edge1.yml @@ -166,6 +166,60 @@ ethernet_interfaces: peer_type: l3_interface switchport: enabled: false +- name: Ethernet6 + description: peerDevice1_PeerDevIntf1 + shutdown: false + speed: forced 10000full + channel_group: + id: 1 + mode: active + peer: peerDevice1 + peer_interface: PeerDevIntf1 + peer_type: l3_port_channel_member +- name: Ethernet7 + description: peerDeviceA + shutdown: false + speed: forced 10000full + channel_group: + id: 1 + mode: active + peer: peerDeviceA + peer_type: l3_port_channel_member +- name: Ethernet1/10 + description: peerDevice10 + shutdown: false + speed: forced 10000full + channel_group: + id: 450 + mode: 'on' + peer: peerDevice10 + peer_type: l3_port_channel_member +- name: Ethernet1/16 + description: peerDevice11 + shutdown: false + speed: auto 10000full + channel_group: + id: 540 + mode: active + peer: peerDevice11 + peer_type: l3_port_channel_member +- name: Ethernet1/17 + description: peerDevice11 + shutdown: false + channel_group: + id: 540 + mode: active + peer: peerDevice11 + peer_type: l3_port_channel_member +- name: Ethernet1/18 + description: peerDevice11 + shutdown: false + speed: 1000full + channel_group: + id: 540 + mode: active + peer: peerDevice11 + peer_type: l3_port_channel_member flow_tracking: hardware: trackers: @@ -193,6 +247,24 @@ ip_access_lists: protocol: ip source: 172.24.49.2 destination: 172.24.49.3 +- name: TEST-IPV4-ACL-WITH-IP-FIELDS-IN_Port-Channel540 + entries: + - sequence: 15 + action: deny + protocol: ip + source: any + destination: 172.15.6.9 + - action: permit + protocol: ip + source: 172.31.0.11 + destination: 172.15.6.9 +- name: TEST-IPV4-ACL-WITH-IP-FIELDS-OUT_Port-Channel540 + entries: + - remark: Some remark will not require source and destination fields. + - action: permit + protocol: ip + source: 172.15.6.9 + destination: any - name: ACL-NAT-IE-DIRECT entries: - sequence: 10 @@ -404,6 +476,26 @@ metadata: tags: - name: Type value: lan + - interface: Port-Channel1 + tags: + - name: Type + value: wan + - name: Carrier + value: ATT + - name: Circuit + value: '404' + - interface: Port-Channel450 + tags: + - name: Type + value: wan + - name: Carrier + value: Orange + - interface: Port-Channel540 + tags: + - name: Type + value: wan + - name: Carrier + value: Comcast cv_pathfinder: role: edge region: AVD_Land_East @@ -427,6 +519,16 @@ metadata: carrier: ATT circuit_id: '404' pathgroup: INET + - name: Port-Channel1 + carrier: ATT + circuit_id: '404' + pathgroup: INET + - name: Port-Channel450 + carrier: Orange + pathgroup: INET + - name: Port-Channel540 + carrier: Comcast + pathgroup: INET internet_exit_policies: - name: ZSCALER-EXIT-POLICY-1 type: zscaler @@ -571,13 +673,45 @@ monitor_connectivity: local_interfaces: SET-Tunnel112 address_only: false url: http://gateway.zscalerbeta.net/vpntest +port_channel_interfaces: +- name: Port-Channel1 + description: ATT_404_peerDeviceA_Port-Channel2 + shutdown: false + ip_address: 172.15.5.7/31 + flow_tracker: + hardware: FLOW-TRACKER + peer: peerDeviceA + peer_interface: Port-Channel2 + peer_type: l3_port_channel + switchport: + enabled: false +- name: Port-Channel450 + description: Orange_peerDevice10_Port-Channel455 + shutdown: false + ip_address: 172.15.5.8/31 + peer: peerDevice10 + peer_interface: Port-Channel455 + peer_type: l3_port_channel + switchport: + enabled: false +- name: Port-Channel540 + description: Comcast_peerDevice11_Port-Channel545 + shutdown: false + ip_address: 172.15.6.9/31 + access_group_in: TEST-IPV4-ACL-WITH-IP-FIELDS-IN_Port-Channel540 + access_group_out: TEST-IPV4-ACL-WITH-IP-FIELDS-OUT_Port-Channel540 + peer: peerDevice11 + peer_interface: Port-Channel545 + peer_type: l3_port_channel + switchport: + enabled: false prefix_lists: - name: PL2 sequence_numbers: - sequence: 10 action: permit 5.0.0.0/0 - sequence: 20 - action: deny 10.00.0.0/24 + action: deny 10.0.0.0/24 - name: ALLOW-DEFAULT sequence_numbers: - sequence: 10 @@ -609,6 +743,34 @@ route_maps: - ip address prefix-list PL2 - sequence: 20 type: deny +- name: RM-BGP-172.31.0.1-IN + sequence_numbers: + - sequence: 10 + type: permit + match: + - ip address prefix-list PL2 + set: + - community no-advertise additive +- name: RM-BGP-172.31.0.1-OUT + sequence_numbers: + - sequence: 10 + type: permit + match: + - ip address prefix-list ALLOW-DEFAULT + - sequence: 20 + type: deny +- name: RM-BGP-172.31.0.10-IN + sequence_numbers: + - sequence: 10 + type: permit + match: + - ip address prefix-list PL2 + set: + - community no-advertise additive +- name: RM-BGP-172.31.0.10-OUT + sequence_numbers: + - sequence: 10 + type: deny - name: RM-CONN-2-BGP sequence_numbers: - sequence: 10 @@ -773,6 +935,16 @@ router_bgp: - ip_address: 172.28.0.14 remote_as: '64520' route_map_out: RM-BGP-172.28.0.14-OUT + - ip_address: 172.31.0.1 + remote_as: '64520' + description: ATT_404_peerDeviceA_Port-Channel2 + route_map_in: RM-BGP-172.31.0.1-IN + route_map_out: RM-BGP-172.31.0.1-OUT + - ip_address: 172.31.0.10 + remote_as: '64520' + description: Orange_peerDevice10_Port-Channel455 + route_map_in: RM-BGP-172.31.0.10-IN + route_map_out: RM-BGP-172.31.0.10-OUT - ip_address: 172.17.0.2 peer_group: IPv4-UNDERLAY-PEERS remote_as: '65199' @@ -808,6 +980,10 @@ router_bgp: activate: true - ip_address: 172.28.0.14 activate: true + - ip_address: 172.31.0.1 + activate: true + - ip_address: 172.31.0.10 + activate: true address_family_ipv4_sr_te: peer_groups: - name: WAN-OVERLAY-PEERS @@ -965,6 +1141,21 @@ router_path_selection: server_profiles: - INET-cv-pathfinder-pathfinder1-Ethernet1 - INET-cv-pathfinder-pathfinder2-Ethernet1 + - name: Port-Channel1 + stun: + server_profiles: + - INET-cv-pathfinder-pathfinder1-Ethernet1 + - INET-cv-pathfinder-pathfinder2-Ethernet1 + - name: Port-Channel450 + stun: + server_profiles: + - INET-cv-pathfinder-pathfinder1-Ethernet1 + - INET-cv-pathfinder-pathfinder2-Ethernet1 + - name: Port-Channel540 + stun: + server_profiles: + - INET-cv-pathfinder-pathfinder1-Ethernet1 + - INET-cv-pathfinder-pathfinder2-Ethernet1 dynamic_peers: enabled: true static_peers: @@ -1048,6 +1239,12 @@ service_routing_protocols_model: multi-agent spanning_tree: mode: none static_routes: +- destination_address_prefix: 172.16.0.0/16 + gateway: 172.31.0.1 +- destination_address_prefix: 172.17.0.0/16 + gateway: 172.31.0.10 +- destination_address_prefix: 172.18.0.0/16 + gateway: 172.31.0.11 - destination_address_prefix: 10.37.121.1/32 gateway: 172.31.0.1 name: IE-ZSCALER-PRI diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-edge4A.yml b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-edge4A.yml index 8f91a70f7d4..e8ab29b97c0 100644 --- a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-edge4A.yml +++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-edge4A.yml @@ -218,6 +218,10 @@ metadata: tags: - name: Type value: lan + - interface: Port-Channel666 + tags: + - name: Type + value: lan cv_pathfinder: role: transit region region: AVD_Land_West diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-edge4B.yml b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-edge4B.yml index 6693af1984b..6dd80f67716 100644 --- a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-edge4B.yml +++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-edge4B.yml @@ -218,6 +218,10 @@ metadata: tags: - name: Type value: lan + - interface: Port-Channel666 + tags: + - name: Type + value: lan cv_pathfinder: role: transit region region: AVD_Land_West diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/node-type-l3-port-channels.yml b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/node-type-l3-port-channels.yml new file mode 100644 index 00000000000..2fc5d5425ad --- /dev/null +++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/node-type-l3-port-channels.yml @@ -0,0 +1,521 @@ +aaa_root: + disabled: true +agents: +- name: KernelFib + environment_variables: + - name: KERNELFIB_PROGRAM_ALL_ECMP + value: '1' +application_traffic_recognition: + field_sets: + ipv4_prefixes: + - name: PFX-PATHFINDERS + applications: + ipv4_applications: + - name: APP-CONTROL-PLANE + dest_prefix_set_name: PFX-PATHFINDERS + application_profiles: + - name: APP-PROFILE-CONTROL-PLANE + applications: + - name: APP-CONTROL-PLANE +config_end: true +dps_interfaces: +- name: Dps1 + description: DPS Interface + mtu: 9194 + ip_address: 192.168.142.1/32 + flow_tracker: + hardware: FLOW-TRACKER +enable_password: + disabled: true +ethernet_interfaces: +- name: Ethernet1 + description: peerDevice1_Ethernet11 + shutdown: false + speed: forced 10000full + channel_group: + id: 2 + mode: active + peer: peerDevice1 + peer_interface: Ethernet11 + peer_type: l3_port_channel_member +- name: Ethernet2 + description: peer1 + shutdown: false + speed: forced 10000full + channel_group: + id: 2 + mode: active + peer: peer1 + peer_type: l3_port_channel_member +- name: Ethernet3 + description: Custom eth3 description + shutdown: false + channel_group: + id: 2 + mode: active + peer: peer1 + peer_type: l3_port_channel_member +- name: Ethernet1/4 + description: peerDevice2_Ethernet1/12 + shutdown: false + speed: forced 10000full + channel_group: + id: 5 + mode: passive + peer: peerDevice2 + peer_interface: Ethernet1/12 + peer_type: l3_port_channel_member +- name: Ethernet1/5 + description: peer2 + shutdown: false + speed: forced 10000full + channel_group: + id: 5 + mode: passive + peer: peer2 + peer_type: l3_port_channel_member +- name: Ethernet1/10 + description: peerDevice3_Ethernet1/10 + shutdown: false + speed: forced 1000full + channel_group: + id: 8 + mode: 'on' + peer: peerDevice3 + peer_interface: Ethernet1/10 + peer_type: l3_port_channel_member +- name: Ethernet1/19 + description: peerDevice4_Ethernet1/19 + shutdown: true + channel_group: + id: 19 + mode: active + peer: peerDevice4 + peer_interface: Ethernet1/19 + peer_type: l3_port_channel_member +- name: Ethernet1/20 + description: peerDevice4_Ethernet1/20 + shutdown: true + channel_group: + id: 19 + mode: active + peer: peerDevice4 + peer_interface: Ethernet1/20 + peer_type: l3_port_channel_member +flow_tracking: + hardware: + trackers: + - name: FLOW-TRACKER + record_export: + on_inactive_timeout: 70000 + on_interval: 300000 + exporters: + - name: CV-TELEMETRY + collector: + host: 127.0.0.1 + local_interface: Loopback0 + template_interval: 3600000 + shutdown: false +hostname: node-type-l3-port-channels +ip_extcommunity_lists: +- name: ECL-EVPN-SOO + entries: + - type: permit + extcommunities: soo 192.168.255.1:511 +ip_routing: true +ip_security: + ike_policies: + - name: CP-IKE-POLICY + local_id: 192.168.142.1 + sa_policies: + - name: DP-SA-POLICY + esp: + encryption: aes256gcm128 + pfs_dh_group: 14 + - name: CP-SA-POLICY + esp: + encryption: aes256gcm128 + pfs_dh_group: 14 + profiles: + - name: DP-PROFILE + sa_policy: DP-SA-POLICY + connection: start + shared_key: ABCDEF1234567890666 + dpd: + interval: 10 + time: 50 + action: clear + mode: transport + - name: CP-PROFILE + ike_policy: CP-IKE-POLICY + sa_policy: CP-SA-POLICY + connection: start + shared_key: ABCDEF1234567890 + dpd: + interval: 10 + time: 50 + action: clear + mode: transport + key_controller: + profile: DP-PROFILE +is_deployed: true +loopback_interfaces: +- name: Loopback0 + description: ROUTER_ID + shutdown: false + ip_address: 192.168.255.1/32 +management_api_http: + enable_https: true + enable_vrfs: + - name: MGMT +management_security: + ssl_profiles: + - name: STUN-DTLS + tls_versions: '1.2' + trust_certificate: + certificates: + - aristaDeviceCertProvisionerDefaultRootCA.crt + certificate: + file: STUN-DTLS.crt + key: STUN-DTLS.key +metadata: + fabric_name: EOS_DESIGNS_UNIT_TESTS + cv_tags: + device_tags: + - name: Role + value: edge + - name: Region + value: AVD_Land_East + - name: Zone + value: AVD_Land_East-ZONE + - name: Site + value: Site511 + interface_tags: + - interface: Port-Channel2 + tags: + - name: Type + value: wan + - name: Carrier + value: Cybercast + - name: Circuit + value: '101' + - interface: Port-Channel5 + tags: + - name: Type + value: wan + - name: Carrier + value: StreamFast + - name: Circuit + value: '102' + - interface: Port-Channel5.100 + tags: + - name: Type + value: wan + - name: Carrier + value: ExtremeCable + - name: Circuit + value: '105' + - interface: Port-Channel5.105 + tags: + - name: Type + value: lan + - interface: Port-Channel8 + tags: + - name: Type + value: wan + - name: Carrier + value: BlizzardFast + - interface: Port-Channel19 + tags: + - name: Type + value: wan + - name: Carrier + value: BlizzardFast + cv_pathfinder: + role: edge + region: AVD_Land_East + zone: AVD_Land_East-ZONE + site: Site511 + vtep_ip: 192.168.142.1 + ssl_profile: STUN-DTLS + interfaces: + - name: Port-Channel2 + carrier: Cybercast + circuit_id: '101' + pathgroup: INET + - name: Port-Channel5 + carrier: StreamFast + circuit_id: '102' + pathgroup: INET + - name: Port-Channel5.100 + carrier: ExtremeCable + circuit_id: '105' + pathgroup: INET + - name: Port-Channel8 + carrier: BlizzardFast + pathgroup: INET + - name: Port-Channel19 + carrier: BlizzardFast + pathgroup: INET +port_channel_interfaces: +- name: Port-Channel2 + description: Cybercast_101_peer1_Port-Channel10 + shutdown: false + ip_address: 192.168.1.102/31 + service_profile: TEST-QOS-PROFILE1 + flow_tracker: + hardware: FLOW-TRACKER + peer: peer1 + peer_interface: Port-Channel10 + peer_type: l3_port_channel + switchport: + enabled: false +- name: Port-Channel5 + description: StreamFast_102_peer2_Port-Channel15 + shutdown: false + service_policy: + qos: + input: TEST_POLICY + ip_address: 192.168.1.105/31 + service_profile: TEST-QOS-PROFILE1 + peer: peer2 + peer_interface: Port-Channel15 + peer_type: l3_port_channel + switchport: + enabled: false + eos_cli: '! TEST RAW_EOS_CLI + + ' +- name: Port-Channel5.100 + description: ExtremeCable_105_peer2_Port-Channel15 + shutdown: false + encapsulation_dot1q: + vlan: 108 + ip_address: 192.168.100.115/31 + service_profile: TEST-QOS-PROFILE2 + flow_tracker: + hardware: FLOW-TRACKER + peer: peer2 + peer_interface: Port-Channel15 + peer_type: l3_port_channel +- name: Port-Channel5.105 + description: peer2_Port-Channel16 + shutdown: false + encapsulation_dot1q: + vlan: 105 + ip_address: 192.168.100.116/31 + service_profile: TEST-QOS-PROFILE2 + flow_tracker: + hardware: FLOW-TRACKER + peer: peer2 + peer_interface: Port-Channel16 + peer_type: l3_port_channel +- name: Port-Channel8 + description: BlizzardFast_peerDevice3_Port-Channel18 + shutdown: false + ip_address: dhcp + dhcp_client_accept_default_route: true + service_profile: TEST-QOS-PROFILE3 + flow_tracker: + hardware: FLOW-TRACKER + peer: peerDevice3 + peer_interface: Port-Channel18 + peer_type: l3_port_channel + switchport: + enabled: false + eos_cli: '! TEST RAW_EOS_CLI 123 + + ' +- name: Port-Channel19 + description: BlizzardFast_peerDevice4_Port-Channel20 + shutdown: true + ip_address: 192.168.1.19/31 + peer: peerDevice4 + peer_interface: Port-Channel20 + peer_type: l3_port_channel + switchport: + enabled: false +prefix_lists: +- name: PL-LOOPBACKS-EVPN-OVERLAY + sequence_numbers: + - sequence: 10 + action: permit 192.168.255.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 + set: + - extcommunity soo 192.168.255.1:511 additive +- name: RM-EVPN-SOO-IN + sequence_numbers: + - sequence: 10 + type: deny + match: + - extcommunity ECL-EVPN-SOO + - sequence: 20 + type: permit +- name: RM-EVPN-SOO-OUT + sequence_numbers: + - sequence: 10 + type: permit + set: + - extcommunity soo 192.168.255.1:511 additive +- name: RM-EVPN-EXPORT-VRF-DEFAULT + sequence_numbers: + - sequence: 10 + type: permit + match: + - extcommunity ECL-EVPN-SOO +router_adaptive_virtual_topology: + topology_role: edge + region: + name: AVD_Land_East + id: 43 + zone: + name: AVD_Land_East-ZONE + id: 1 + site: + name: Site511 + id: 511 + profiles: + - name: DEFAULT-POLICY-CONTROL-PLANE + load_balance_policy: LB-DEFAULT-POLICY-CONTROL-PLANE + - name: DEFAULT-POLICY-DEFAULT + load_balance_policy: LB-DEFAULT-POLICY-DEFAULT + policies: + - name: DEFAULT-POLICY-WITH-CP + matches: + - application_profile: APP-PROFILE-CONTROL-PLANE + avt_profile: DEFAULT-POLICY-CONTROL-PLANE + - application_profile: default + avt_profile: DEFAULT-POLICY-DEFAULT + vrfs: + - name: default + policy: DEFAULT-POLICY-WITH-CP + profiles: + - name: DEFAULT-POLICY-CONTROL-PLANE + id: 254 + - name: DEFAULT-POLICY-DEFAULT + id: 1 +router_bfd: + multihop: + interval: 300 + min_rx: 300 + multiplier: 3 +router_bgp: + as: '65005' + router_id: 192.168.255.1 + maximum_paths: + paths: 16 + updates: + wait_install: true + bgp: + default: + ipv4_unicast: false + peer_groups: + - name: WAN-OVERLAY-PEERS + type: wan + remote_as: '65005' + update_source: Dps1 + bfd: true + bfd_timers: + interval: 1000 + min_rx: 1000 + multiplier: 10 + password: htm4AZe9mIQOO1uiMuGgYQ== + send_community: all + maximum_routes: 0 + ttl_maximum_hops: 1 + redistribute: + connected: + enabled: true + route_map: RM-CONN-2-BGP + address_family_evpn: + peer_groups: + - name: WAN-OVERLAY-PEERS + activate: true + route_map_in: RM-EVPN-SOO-IN + route_map_out: RM-EVPN-SOO-OUT + encapsulation: path-selection + address_family_ipv4: + peer_groups: + - name: WAN-OVERLAY-PEERS + activate: false + address_family_ipv4_sr_te: + peer_groups: + - name: WAN-OVERLAY-PEERS + activate: true + address_family_link_state: + peer_groups: + - name: WAN-OVERLAY-PEERS + activate: true + path_selection: + roles: + producer: true + address_family_path_selection: + bgp: + additional_paths: + receive: true + send: any + peer_groups: + - name: WAN-OVERLAY-PEERS + activate: true + vrfs: + - name: default + rd: 192.168.255.1:1 + route_targets: + import: + - address_family: evpn + route_targets: + - '1:1' + export: + - address_family: evpn + route_targets: + - '1:1' + - route-map RM-EVPN-EXPORT-VRF-DEFAULT +router_path_selection: + path_groups: + - name: INET + id: 101 + ipsec_profile: CP-PROFILE + local_interfaces: + - name: Port-Channel2 + - name: Port-Channel5 + - name: Port-Channel5.100 + - name: Port-Channel8 + - name: Port-Channel19 + dynamic_peers: + enabled: true + load_balance_policies: + - name: LB-DEFAULT-POLICY-CONTROL-PLANE + path_groups: + - name: INET + - name: LB-DEFAULT-POLICY-DEFAULT + path_groups: + - name: INET + tcp_mss_ceiling: + ipv4_segment_size: auto +router_traffic_engineering: + enabled: true +service_routing_protocols_model: multi-agent +spanning_tree: + mode: none +static_routes: +- destination_address_prefix: 0.0.0.0/0 + gateway: 192.168.1.103 +transceiver_qsfp_default_mode_4x10: false +vrfs: +- name: MGMT + ip_routing: false +vxlan_interface: + vxlan1: + description: node-type-l3-port-channels_VTEP + vxlan: + source_interface: Dps1 + udp_port: 4789 + vrfs: + - name: default + vni: 1 diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/group_vars/CV_PATHFINDER_TESTS.yml b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/group_vars/CV_PATHFINDER_TESTS.yml index d68dd43849a..d5064b2e910 100644 --- a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/group_vars/CV_PATHFINDER_TESTS.yml +++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/group_vars/CV_PATHFINDER_TESTS.yml @@ -15,7 +15,7 @@ ipv4_prefix_list_catalog: - sequence: 10 action: permit 5.0.0.0/0 - sequence: 20 - action: deny 10.00.0.0/24 + action: deny 10.0.0.0/24 cv_pathfinder_regions: - name: AVD_Land_West @@ -105,8 +105,8 @@ wan_router: # cv-pathfinder-edge is not configured on cv-pathfinder-edge1 - group: Site511 uplink_type: p2p-vrfs - uplink_switches: [ site-ha-disabled-leaf ] - uplink_interfaces: [ Ethernet52 ] + uplink_switches: [site-ha-disabled-leaf] + uplink_interfaces: [Ethernet52] cv_pathfinder_region: AVD_Land_East cv_pathfinder_site: Site511 wan_ha: @@ -212,6 +212,77 @@ wan_router: bgp: peer_as: 64520 ipv4_prefix_list_out: PL2 + l3_port_channels: + - # Port-Channel with 2 member ports + name: Port-Channel1 + mode: active + member_interfaces: + - name: Ethernet6 + peer: peerDevice1 + peer_interface: PeerDevIntf1 + speed: "forced 10000full" + - # peer, peer_interface not set, use peer from parent L3 Port-Channel + name: Ethernet7 + speed: "forced 10000full" + ip_address: 172.15.5.7/31 + # Using peer_ip same as the one specified for Ethernet3 under l3_interfaces above. + # This will cause identical nexthop for Zscaler tunnel destinations to be configured via ip route. + # instead of multiple routes to same Zscaler destination via different nexthops. + peer: peerDeviceA + peer_ip: 172.31.0.1 + peer_port_channel: Port-Channel2 + wan_carrier: ATT + wan_circuit_id: 404 + static_routes: + - prefix: 172.16.0.0/16 + bgp: + peer_as: 64520 + ipv4_prefix_list_in: PL2 + ipv4_prefix_list_out: ALLOW-DEFAULT + flow_tracking: + enabled: true + - # Port-Channel with 1 member ports + name: Port-Channel450 + mode: "on" + member_interfaces: + - name: Ethernet1/10 + speed: "forced 10000full" + ip_address: 172.15.5.8/31 + peer: peerDevice10 + peer_ip: 172.31.0.10 + peer_port_channel: Port-Channel455 + wan_carrier: Orange + connected_to_pathfinder: false + static_routes: + - prefix: 172.17.0.0/16 + bgp: + peer_as: 64520 + ipv4_prefix_list_in: PL2 + flow_tracking: + enabled: false + - # Port-Channel with 3 member ports + name: Port-Channel540 + # use default mode + member_interfaces: + - name: Ethernet1/16 + speed: "auto 10000full" + - name: Ethernet1/17 + # interface speed not specified + - name: Ethernet1/18 + speed: "1000full" + ip_address: 172.15.6.9/31 + public_ip: 10.36.36.100 + peer: peerDevice11 + peer_ip: 172.31.0.11 + peer_port_channel: Port-Channel545 + wan_carrier: Comcast + connected_to_pathfinder: true + static_routes: + - prefix: 172.18.0.0/16 + # flow_tracking not set, hence not configured + ipv4_acl_in: TEST-IPV4-ACL-WITH-IP-FIELDS-IN + ipv4_acl_out: TEST-IPV4-ACL-WITH-IP-FIELDS-OUT + # SITE_HA_ENABLED # Because HA is enabled, this allow to test that MPLS-ONLY, present on # cv-pathfinder-edge2B (because of Colt) is being configured on cv-pathfinder-edge2A @@ -220,8 +291,8 @@ wan_router: cv_pathfinder_region: AVD_Land_West cv_pathfinder_site: Site423 uplink_type: p2p-vrfs - uplink_switches: [ site-ha-enabled-leaf2A, site-ha-enabled-leaf2B ] - uplink_interfaces: [ Ethernet52, Ethernet53 ] + uplink_switches: [site-ha-enabled-leaf2A, site-ha-enabled-leaf2B] + uplink_interfaces: [Ethernet52, Ethernet53] wan_ha: enabled: true # TODO AVD4.8.0: Remove once WAN HA is GA. nodes: @@ -251,8 +322,8 @@ wan_router: always_include_vrfs_in_tenants: [TenantA, TenantB] uplink_ipv4_pool: 172.17.0.0/16 uplink_type: p2p-vrfs - uplink_switches: [ site-ha-enabled-leaf1 ] - uplink_interfaces: [ Ethernet52 ] + uplink_switches: [site-ha-enabled-leaf1] + uplink_interfaces: [Ethernet52] cv_pathfinder_transit_mode: region # Disable HA IPsec wan_ha: diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/host_vars/cv-pathfinder-edge1.yml b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/host_vars/cv-pathfinder-edge1.yml index 85aa8d95d2c..a052889692f 100644 --- a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/host_vars/cv-pathfinder-edge1.yml +++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/host_vars/cv-pathfinder-edge1.yml @@ -21,6 +21,13 @@ ipv4_acls: protocol: ip source: peer_ip destination: interface_ip + - name: TEST-IPV4-ACL-WITH-IP-FIELDS-OUT + entries: + - remark: Some remark will not require source and destination fields. + - action: permit + protocol: ip + source: interface_ip + destination: any - name: ACL-NAT-IE-ZSCALER entries: - sequence: 10 diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/host_vars/node-type-l3-port-channels.yml b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/host_vars/node-type-l3-port-channels.yml new file mode 100644 index 00000000000..34ffef765c6 --- /dev/null +++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/host_vars/node-type-l3-port-channels.yml @@ -0,0 +1,164 @@ +--- +# This yml file is being used to test the various supported schema attributes for L3 Port-Channel +# for cv-pathfinder deployment use-case. +type: wan_router + +cv_pathfinder_regions: + - name: AVD_Land_East + id: 43 + description: AVD Region + sites: + - name: Site511 + id: 511 + location: Miami + +bgp_peer_groups: + wan_overlay_peers: + password: "htm4AZe9mIQOO1uiMuGgYQ==" + listen_range_prefixes: + - 192.168.142.0/24 + - 192.168.143.0/24 + +wan_ipsec_profiles: + control_plane: + shared_key: ABCDEF1234567890 + data_plane: + shared_key: ABCDEF1234567890666 + +wan_router: + node_groups: + - group: Site511 + uplink_type: p2p-vrfs + cv_pathfinder_region: AVD_Land_East + cv_pathfinder_site: Site511 + nodes: + - name: node-type-l3-port-channels + id: 1 + loopback_ipv4_pool: 192.168.255.0/24 + vtep_loopback_ipv4_pool: 192.168.142.0/24 + bgp_as: 65005 + l3_port_channels: + - # Port-Channel with 3 member ports + name: Port-Channel2 + mode: active + member_interfaces: + - name: Ethernet1 + peer: peerDevice1 + peer_interface: Ethernet11 + speed: "forced 10000full" + - # if peer not set, use one from parent L3 Port-Channel + name: Ethernet2 + speed: "forced 10000full" + - name: Ethernet3 + description: "Custom eth3 description" + ip_address: 192.168.1.102/31 + peer: peer1 + peer_port_channel: Port-Channel10 + peer_ip: 192.168.1.103 + static_routes: + - prefix: 0.0.0.0/0 + qos_profile: TEST-QOS-PROFILE1 + wan_carrier: Cybercast + wan_circuit_id: 101 + flow_tracking: + enabled: true + - # Port-Channel with 2 member ports + name: Port-Channel5 + mode: passive + member_interfaces: + - name: Ethernet1/4 + peer: peerDevice2 + peer_interface: Ethernet1/12 + speed: "forced 10000full" + - # if peer not set, use parent L3 Port-Channel peer + name: Ethernet1/5 + speed: "forced 10000full" + ip_address: 192.168.1.105/31 + peer: peer2 + peer_port_channel: Port-Channel15 + peer_ip: 192.168.1.104 + qos_profile: TEST-QOS-PROFILE1 + wan_carrier: StreamFast + wan_circuit_id: 102 + flow_tracking: + enabled: false + structured_config: + service_policy: + qos: + input: TEST_POLICY + raw_eos_cli: | + ! TEST RAW_EOS_CLI + - # sub-interface for Port-Channel with user-specfied encapsulation_dot1q_vlan + name: Port-Channel5.100 + encapsulation_dot1q_vlan: 108 + ip_address: 192.168.100.115/31 + peer: peer2 + peer_port_channel: Port-Channel15 + peer_ip: 192.168.100.114 + qos_profile: TEST-QOS-PROFILE2 + wan_carrier: ExtremeCable + wan_circuit_id: 105 + flow_tracking: + enabled: true + - # sub-interface for Port-Channel without wan_carrier set + name: Port-Channel5.105 + ip_address: 192.168.100.116/31 + peer: peer2 + peer_port_channel: Port-Channel16 + peer_ip: 192.168.100.117 + qos_profile: TEST-QOS-PROFILE2 + flow_tracking: + enabled: true + - # Port-Channel with 1 member port + name: Port-Channel8 + mode: 'on' + member_interfaces: + - name: Ethernet1/10 + peer: peerDevice3 + peer_interface: Ethernet1/10 + structured_config: + # specify interface speed via structured_config + speed: "forced 1000full" + peer: peerDevice3 + peer_port_channel: Port-Channel18 + peer_ip: 192.168.1.18 + qos_profile: TEST-QOS-PROFILE3 + wan_carrier: BlizzardFast + ip_address: dhcp + dhcp_ip: 10.15.16.17 + dhcp_accept_default_route: true + flow_tracking: + enabled: true + raw_eos_cli: | + ! TEST RAW_EOS_CLI 123 + - # Port-Channel interface is shutdown (`enabled: false`), member ports to inherit this. + # Port-Channel mode is not set. + name: Port-Channel19 + enabled: false + ip_address: 192.168.1.19/31 + member_interfaces: + - name: Ethernet1/19 + peer_interface: Ethernet1/19 + - name: Ethernet1/20 + peer_interface: Ethernet1/20 + peer: peerDevice4 + peer_port_channel: Port-Channel20 + peer_ip: 192.168.1.18 + wan_carrier: BlizzardFast +wan_carriers: + - name: Cybercast + path_group: INET + trusted: true + - name: StreamFast + path_group: INET + trusted: true + - name: ExtremeCable + path_group: INET + trusted: true + - name: BlizzardFast + path_group: INET + trusted: true + +wan_path_groups: + - name: INET + id: 101 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 dd347a9704b..90647098219 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 @@ -51,6 +51,7 @@ all: spanning-tree-mode-rapid-pvst: node-type-l3-interfaces: node-type-l3-interfaces-bgp: + node-type-l3-port-channels: ipv4-acls: only-connected-endpoints: platform_settings: diff --git a/ansible_collections/arista/avd/roles/eos_designs/docs/how-to/wan.md b/ansible_collections/arista/avd/roles/eos_designs/docs/how-to/wan.md index 8fb877adec1..2501f8519b9 100644 --- a/ansible_collections/arista/avd/roles/eos_designs/docs/how-to/wan.md +++ b/ansible_collections/arista/avd/roles/eos_designs/docs/how-to/wan.md @@ -64,6 +64,7 @@ Please familiarize yourself with the Arista WAN terminology before proceeding: - LAN support is limited to single L2 using `uplink_type: lan` and eBGP L3 using `uplink_type: p2p-vrfs` in conjunction of `underlay_routing_protocol: ebgp`. - All the WAN routers must have a common path-group with at least one WAN route server to be able to inject the default control-plane match statement in the VRF default WAN policy. - For the default VRF, routes received over BGP peering configured under tenants in `network_services` will not be automatically advertised to the WAN (they will be advertised toward the LAN if eBGP is used). To advertise them towards the WAN, they need to be injected in EVPN and this can be achieved by adding a route-map to mark them with the site SOO. +- Internet exit policies are not supported under WAN port-channel interfaces. ### Future work @@ -356,7 +357,7 @@ wan_router: ### WAN interfaces -A WAN interface in AVD is defined under the node settings under the `l3_interfaces` list. To be considered as a WAN interface by AVD, the `l3_interface` must have the `wan_carrier` key defined (which will allow to detect the path-group thanks to the carrier to path-group mapping). The `wan_circuit_id` is optional and used on CVaaS to provide more information in the visualization as well as in the AVD generated interface description. Finally the key `connected_to_pathfinder` allows to disable the static peering configuration on a given path-group. +A WAN interface in AVD is defined under the node settings either under the `l3_interfaces` or the `l3_port_channels` list. To be considered as a WAN interface by AVD, an `l3_interface` pr `l3_port_channel` must have the `wan_carrier` key defined (which will allow to detect the path-group thanks to the carrier to path-group mapping). The `wan_circuit_id` is optional and used on CVaaS to provide more information in the visualization as well as in the AVD generated interface description. Finally the key `connected_to_pathfinder` allows to disable the static peering configuration on a given path-group. !!! Danger @@ -402,6 +403,21 @@ wan_router: # This is NOT a WAN interface - name: Ethernet3 ip_address: 172.20.20.20/31 + l3_port_channels: + # This is a WAN interface because `wan_carrier` is defined + - name: Port-Channel1 + mode: active + peer: peer4 + peer_interface: Port-Channel12 + wan_carrier: ISP-3 + ipv4_acl_in: TEST-IPV4-ACL-WITH-IP-FIELDS-IN + ipv4_acl_out: TEST-IPV4-ACL-WITH-IP-FIELDS-OUT + dhcp_accept_default_route: true + ip_address: dhcp + dhcp_ip: 42.42.42.42 + member_interfaces: + - name: Ethernet4 + - name: Ethernet5 ipv4_prefix_list_catalog: - name: ALLOW-DEFAULT diff --git a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/management-flow-tracking-settings.md b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/management-flow-tracking-settings.md index e7b90025efc..e288d93ba24 100644 --- a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/management-flow-tracking-settings.md +++ b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/management-flow-tracking-settings.md @@ -29,6 +29,9 @@ | [  l3_interfaces](## "fabric_flow_tracking.l3_interfaces") | Dictionary | | | | Enable flow-tracking on all node.l3_interfaces and network-services tenants.vrfs.l3_interfaces. | | [    enabled](## "fabric_flow_tracking.l3_interfaces.enabled") | Boolean | | `False` | | | | [    name](## "fabric_flow_tracking.l3_interfaces.name") | String | | `FLOW-TRACKER` | | Flow tracker name as defined in flow_tracking_settings. | + | [  l3_port_channels](## "fabric_flow_tracking.l3_port_channels") | Dictionary | | | | Enable flow-tracking on all node.l3_port_channels. | + | [    enabled](## "fabric_flow_tracking.l3_port_channels.enabled") | Boolean | | `False` | | | + | [    name](## "fabric_flow_tracking.l3_port_channels.name") | String | | `FLOW-TRACKER` | | Flow tracker name as defined in flow_tracking_settings. | | [  dps_interfaces](## "fabric_flow_tracking.dps_interfaces") | Dictionary | | | | Enable flow-tracking on all dps_interfaces. | | [    enabled](## "fabric_flow_tracking.dps_interfaces.enabled") | Boolean | | `True` | | | | [    name](## "fabric_flow_tracking.dps_interfaces.name") | String | | `FLOW-TRACKER` | | Flow tracker name as defined in flow_tracking_settings. | @@ -124,6 +127,13 @@ # Flow tracker name as defined in flow_tracking_settings. name: + # Enable flow-tracking on all node.l3_port_channels. + l3_port_channels: + enabled: + + # Flow tracker name as defined in flow_tracking_settings. + name: + # Enable flow-tracking on all dps_interfaces. dps_interfaces: enabled: diff --git a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/node-type-l3-interfaces-configuration.md b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/node-type-l3-interfaces-configuration.md index 178fe5709e5..c3f39baf1a3 100644 --- a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/node-type-l3-interfaces-configuration.md +++ b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/node-type-l3-interfaces-configuration.md @@ -9,9 +9,9 @@ | -------- | ---- | -------- | ------- | ------------------ | ----------- | | [<node_type_keys.key>](## "") | Dictionary | | | | | | [  defaults](## ".defaults") | Dictionary | | | | Define variables for all nodes of this type. | - | [    l3_interfaces](## ".defaults.l3_interfaces") | List, items: Dictionary | | | | L3 Interfaces to configure on the node.
Used to define the node for WAN interfaces when `wan_carrier` is set. | + | [    l3_interfaces](## ".defaults.l3_interfaces") | List, items: Dictionary | | | | L3 Interfaces to configure on the node. | | [      - profile](## ".defaults.l3_interfaces.[].profile") | String | | | | L3 interface profile name. Profile defined under `l3_interface_profiles`.
| - | [        name](## ".defaults.l3_interfaces.[].name") | String | Required, Unique | | Pattern: `Ethernet[\d/]+(.[\d]+)?` | Ethernet interface name like 'Ethernet2' or subinterface name like 'Ethernet2.42'.
For a subinterface, the parent physical interface is automatically created. | + | [        name](## ".defaults.l3_interfaces.[].name") | String | Required, Unique | | Pattern: `Ethernet[\d/]+(\.[\d]+)?` | Ethernet interface name like 'Ethernet2' or subinterface name like 'Ethernet2.42'.
For a subinterface, the parent physical interface is automatically created. | | [        description](## ".defaults.l3_interfaces.[].description") | String | | | | Interface description.
If not set a default description will be configured with '[[ ]]'. | | [        ip_address](## ".defaults.l3_interfaces.[].ip_address") | String | | | | Node IPv4 address/Mask or 'dhcp'. | | [        dhcp_ip](## ".defaults.l3_interfaces.[].dhcp_ip") | String | | | | When the `ip_address` is `dhcp`, this optional field allows to indicate the expected
IPv4 address (without mask) to be allocated on the interface if known.
This is not rendered in the configuration but can be used for substitution of 'interface_ip' in the Access-list
set under `ipv4_acl_in` and `ipv4_acl_out`. | @@ -48,9 +48,9 @@ | [    - group](## ".node_groups.[].group") | String | Required, Unique | | | The Node Group Name is used for MLAG domain unless set with 'mlag_domain_id'.
The Node Group Name is also used for peer description on downstream switches' uplinks.
| | [      nodes](## ".node_groups.[].nodes") | List, items: Dictionary | | | | Define variables per node. | | [        - name](## ".node_groups.[].nodes.[].name") | String | Required, Unique | | | The Node Name is used as "hostname". | - | [          l3_interfaces](## ".node_groups.[].nodes.[].l3_interfaces") | List, items: Dictionary | | | | L3 Interfaces to configure on the node.
Used to define the node for WAN interfaces when `wan_carrier` is set. | + | [          l3_interfaces](## ".node_groups.[].nodes.[].l3_interfaces") | List, items: Dictionary | | | | L3 Interfaces to configure on the node. | | [            - profile](## ".node_groups.[].nodes.[].l3_interfaces.[].profile") | String | | | | L3 interface profile name. Profile defined under `l3_interface_profiles`.
| - | [              name](## ".node_groups.[].nodes.[].l3_interfaces.[].name") | String | Required, Unique | | Pattern: `Ethernet[\d/]+(.[\d]+)?` | Ethernet interface name like 'Ethernet2' or subinterface name like 'Ethernet2.42'.
For a subinterface, the parent physical interface is automatically created. | + | [              name](## ".node_groups.[].nodes.[].l3_interfaces.[].name") | String | Required, Unique | | Pattern: `Ethernet[\d/]+(\.[\d]+)?` | Ethernet interface name like 'Ethernet2' or subinterface name like 'Ethernet2.42'.
For a subinterface, the parent physical interface is automatically created. | | [              description](## ".node_groups.[].nodes.[].l3_interfaces.[].description") | String | | | | Interface description.
If not set a default description will be configured with '[[ ]]'. | | [              ip_address](## ".node_groups.[].nodes.[].l3_interfaces.[].ip_address") | String | | | | Node IPv4 address/Mask or 'dhcp'. | | [              dhcp_ip](## ".node_groups.[].nodes.[].l3_interfaces.[].dhcp_ip") | String | | | | When the `ip_address` is `dhcp`, this optional field allows to indicate the expected
IPv4 address (without mask) to be allocated on the interface if known.
This is not rendered in the configuration but can be used for substitution of 'interface_ip' in the Access-list
set under `ipv4_acl_in` and `ipv4_acl_out`. | @@ -83,9 +83,9 @@ | [                enabled](## ".node_groups.[].nodes.[].l3_interfaces.[].flow_tracking.enabled") | Boolean | | | | | | [                name](## ".node_groups.[].nodes.[].l3_interfaces.[].flow_tracking.name") | String | | | | Flow tracker name as defined in flow_tracking_settings. | | [              structured_config](## ".node_groups.[].nodes.[].l3_interfaces.[].structured_config") | Dictionary | | | | Custom structured config for the Ethernet interface. | - | [      l3_interfaces](## ".node_groups.[].l3_interfaces") | List, items: Dictionary | | | | L3 Interfaces to configure on the node.
Used to define the node for WAN interfaces when `wan_carrier` is set. | + | [      l3_interfaces](## ".node_groups.[].l3_interfaces") | List, items: Dictionary | | | | L3 Interfaces to configure on the node. | | [        - profile](## ".node_groups.[].l3_interfaces.[].profile") | String | | | | L3 interface profile name. Profile defined under `l3_interface_profiles`.
| - | [          name](## ".node_groups.[].l3_interfaces.[].name") | String | Required, Unique | | Pattern: `Ethernet[\d/]+(.[\d]+)?` | Ethernet interface name like 'Ethernet2' or subinterface name like 'Ethernet2.42'.
For a subinterface, the parent physical interface is automatically created. | + | [          name](## ".node_groups.[].l3_interfaces.[].name") | String | Required, Unique | | Pattern: `Ethernet[\d/]+(\.[\d]+)?` | Ethernet interface name like 'Ethernet2' or subinterface name like 'Ethernet2.42'.
For a subinterface, the parent physical interface is automatically created. | | [          description](## ".node_groups.[].l3_interfaces.[].description") | String | | | | Interface description.
If not set a default description will be configured with '[[ ]]'. | | [          ip_address](## ".node_groups.[].l3_interfaces.[].ip_address") | String | | | | Node IPv4 address/Mask or 'dhcp'. | | [          dhcp_ip](## ".node_groups.[].l3_interfaces.[].dhcp_ip") | String | | | | When the `ip_address` is `dhcp`, this optional field allows to indicate the expected
IPv4 address (without mask) to be allocated on the interface if known.
This is not rendered in the configuration but can be used for substitution of 'interface_ip' in the Access-list
set under `ipv4_acl_in` and `ipv4_acl_out`. | @@ -120,9 +120,9 @@ | [          structured_config](## ".node_groups.[].l3_interfaces.[].structured_config") | Dictionary | | | | Custom structured config for the Ethernet interface. | | [  nodes](## ".nodes") | List, items: Dictionary | | | | Define variables per node. | | [    - name](## ".nodes.[].name") | String | Required, Unique | | | The Node Name is used as "hostname". | - | [      l3_interfaces](## ".nodes.[].l3_interfaces") | List, items: Dictionary | | | | L3 Interfaces to configure on the node.
Used to define the node for WAN interfaces when `wan_carrier` is set. | + | [      l3_interfaces](## ".nodes.[].l3_interfaces") | List, items: Dictionary | | | | L3 Interfaces to configure on the node. | | [        - profile](## ".nodes.[].l3_interfaces.[].profile") | String | | | | L3 interface profile name. Profile defined under `l3_interface_profiles`.
| - | [          name](## ".nodes.[].l3_interfaces.[].name") | String | Required, Unique | | Pattern: `Ethernet[\d/]+(.[\d]+)?` | Ethernet interface name like 'Ethernet2' or subinterface name like 'Ethernet2.42'.
For a subinterface, the parent physical interface is automatically created. | + | [          name](## ".nodes.[].l3_interfaces.[].name") | String | Required, Unique | | Pattern: `Ethernet[\d/]+(\.[\d]+)?` | Ethernet interface name like 'Ethernet2' or subinterface name like 'Ethernet2.42'.
For a subinterface, the parent physical interface is automatically created. | | [          description](## ".nodes.[].l3_interfaces.[].description") | String | | | | Interface description.
If not set a default description will be configured with '[[ ]]'. | | [          ip_address](## ".nodes.[].l3_interfaces.[].ip_address") | String | | | | Node IPv4 address/Mask or 'dhcp'. | | [          dhcp_ip](## ".nodes.[].l3_interfaces.[].dhcp_ip") | String | | | | When the `ip_address` is `dhcp`, this optional field allows to indicate the expected
IPv4 address (without mask) to be allocated on the interface if known.
This is not rendered in the configuration but can be used for substitution of 'interface_ip' in the Access-list
set under `ipv4_acl_in` and `ipv4_acl_out`. | @@ -157,7 +157,7 @@ | [          structured_config](## ".nodes.[].l3_interfaces.[].structured_config") | Dictionary | | | | Custom structured config for the Ethernet interface. | | [l3_interface_profiles](## "l3_interface_profiles") | List, items: Dictionary | | | | Profiles to inherit common settings for l3_interfaces defined under the node type key.
These profiles will *not* work for `l3_interfaces` defined under `vrfs`. | | [  - profile](## "l3_interface_profiles.[].profile") | String | Required, Unique | | | L3 interface profile name. Any variable supported under `l3_interfaces` can be inherited from a profile. | - | [    name](## "l3_interface_profiles.[].name") | String | | | Pattern: `Ethernet[\d/]+(.[\d]+)?` | Ethernet interface name like 'Ethernet2' or subinterface name like 'Ethernet2.42'.
For a subinterface, the parent physical interface is automatically created. | + | [    name](## "l3_interface_profiles.[].name") | String | | | Pattern: `Ethernet[\d/]+(\.[\d]+)?` | Ethernet interface name like 'Ethernet2' or subinterface name like 'Ethernet2.42'.
For a subinterface, the parent physical interface is automatically created. | | [    description](## "l3_interface_profiles.[].description") | String | | | | Interface description.
If not set a default description will be configured with '[[ ]]'. | | [    ip_address](## "l3_interface_profiles.[].ip_address") | String | | | | Node IPv4 address/Mask or 'dhcp'. | | [    dhcp_ip](## "l3_interface_profiles.[].dhcp_ip") | String | | | | When the `ip_address` is `dhcp`, this optional field allows to indicate the expected
IPv4 address (without mask) to be allocated on the interface if known.
This is not rendered in the configuration but can be used for substitution of 'interface_ip' in the Access-list
set under `ipv4_acl_in` and `ipv4_acl_out`. | @@ -200,7 +200,6 @@ defaults: # L3 Interfaces to configure on the node. - # Used to define the node for WAN interfaces when `wan_carrier` is set. l3_interfaces: # L3 interface profile name. Profile defined under `l3_interface_profiles`. @@ -341,7 +340,6 @@ - name: # L3 Interfaces to configure on the node. - # Used to define the node for WAN interfaces when `wan_carrier` is set. l3_interfaces: # L3 interface profile name. Profile defined under `l3_interface_profiles`. @@ -469,7 +467,6 @@ structured_config: # L3 Interfaces to configure on the node. - # Used to define the node for WAN interfaces when `wan_carrier` is set. l3_interfaces: # L3 interface profile name. Profile defined under `l3_interface_profiles`. @@ -603,7 +600,6 @@ - name: # L3 Interfaces to configure on the node. - # Used to define the node for WAN interfaces when `wan_carrier` is set. l3_interfaces: # L3 interface profile name. Profile defined under `l3_interface_profiles`. diff --git a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/node-type-l3-port-channels-configuration.md b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/node-type-l3-port-channels-configuration.md new file mode 100644 index 00000000000..132226d1cc7 --- /dev/null +++ b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/node-type-l3-port-channels-configuration.md @@ -0,0 +1,741 @@ + +=== "Table" + + | Variable | Type | Required | Default | Value Restrictions | Description | + | -------- | ---- | -------- | ------- | ------------------ | ----------- | + | [<node_type_keys.key>](## "") | Dictionary | | | | | + | [  defaults](## ".defaults") | Dictionary | | | | Define variables for all nodes of this type. | + | [    l3_port_channels](## ".defaults.l3_port_channels") | List, items: Dictionary | | | | L3 Port-Channel interfaces to configure on the node. | + | [      - name](## ".defaults.l3_port_channels.[].name") | String | Required, Unique | | Pattern: `Port-Channel[\d/]+(\.[\d]+)?` | Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'.
For a Port-Channel subinterface, the parent Port-Channel interface must be defined as well. | + | [        description](## ".defaults.l3_port_channels.[].description") | String | | | | Interface description.
If not set, a default description will be configured with '[[ ]]'. | + | [        mode](## ".defaults.l3_port_channels.[].mode") | String | | `active` | Valid Values:
- active
- passive
- on | Port-Channel mode.
Should not be set on Port-Channel subinterfaces. | + | [        member_interfaces](## ".defaults.l3_port_channels.[].member_interfaces") | List, items: Dictionary | | | | Port-Channel member interfaces.
Should not be set on Port-Channel subinterfaces. | + | [          - name](## ".defaults.l3_port_channels.[].member_interfaces.[].name") | String | Required, Unique | | Pattern: `Ethernet[\d/]+` | Ethernet interface name like 'Ethernet2'.
Member interface cannot be subinterface. | + | [            description](## ".defaults.l3_port_channels.[].member_interfaces.[].description") | String | | | | Interface description for this member.
If not set, a default description will be configured with '[[ ]]'. | + | [            peer](## ".defaults.l3_port_channels.[].member_interfaces.[].peer") | String | | | | The peer device name. Used for description and documentation.
If not set, this inherits the peer setting on the port-channel interface. | + | [            peer_interface](## ".defaults.l3_port_channels.[].member_interfaces.[].peer_interface") | String | | | | The peer device interface. Used for description and documentation. | + | [            speed](## ".defaults.l3_port_channels.[].member_interfaces.[].speed") | String | | | | Speed should be set in the format `` or `forced ` or `auto `. | + | [            structured_config](## ".defaults.l3_port_channels.[].member_interfaces.[].structured_config") | Dictionary | | | | Custom structured config for the member ethernet interface. | + | [        ip_address](## ".defaults.l3_port_channels.[].ip_address") | String | | | | Node IPv4 address/Mask or 'dhcp'. | + | [        dhcp_ip](## ".defaults.l3_port_channels.[].dhcp_ip") | String | | | | When the `ip_address` is `dhcp`, this optional field allows to indicate the expected
IPv4 address (without mask) to be allocated on the interface if known.
This is not rendered in the configuration but can be used for substitution of 'interface_ip' in the Access-list
set under `ipv4_acl_in` and `ipv4_acl_out`. | + | [        public_ip](## ".defaults.l3_port_channels.[].public_ip") | String | | | | Node IPv4 address (no mask).

This is used to get the public IP (if known) when the device is behind NAT.
This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP
with the following preference:
`wan_route_servers.path_groups.interfaces.ip_address`
-> `l3_port_channels.public_ip`
-> `l3_port_channels.ip_address`

The determined Public IP is used by WAN routers when peering with this interface. | + | [        encapsulation_dot1q_vlan](## ".defaults.l3_port_channels.[].encapsulation_dot1q_vlan") | Integer | | | Min: 1
Max: 4094 | For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be specified. | + | [        dhcp_accept_default_route](## ".defaults.l3_port_channels.[].dhcp_accept_default_route") | Boolean | | `True` | | Accept a default route from DHCP if `ip_address` is set to `dhcp`. | + | [        enabled](## ".defaults.l3_port_channels.[].enabled") | Boolean | | `True` | | Enable or Shutdown the interface. | + | [        peer](## ".defaults.l3_port_channels.[].peer") | String | | | | The peer device name. Used for description and documentation. | + | [        peer_port_channel](## ".defaults.l3_port_channels.[].peer_port_channel") | String | | | | The peer device port-channel interface. Used for description and documentation. | + | [        peer_ip](## ".defaults.l3_port_channels.[].peer_ip") | String | | | | The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true and `ip` is an IP address. | + | [        bgp](## ".defaults.l3_port_channels.[].bgp") | Dictionary | | | | Enforce IPv4 BGP peering for the peer | + | [          peer_as](## ".defaults.l3_port_channels.[].bgp.peer_as") | String | Required | | | BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>".
For asdot notation in YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float number. | + | [          ipv4_prefix_list_in](## ".defaults.l3_port_channels.[].bgp.ipv4_prefix_list_in") | String | | | | Prefix List Name. Accept routes for only these prefixes from the peer.
Required for wan interfaces. | + | [          ipv4_prefix_list_out](## ".defaults.l3_port_channels.[].bgp.ipv4_prefix_list_out") | String | | | | Prefix List Name. Advertise routes for only these prefixes.
If not specified, nothing would be advertised. | + | [        ipv4_acl_in](## ".defaults.l3_port_channels.[].ipv4_acl_in") | String | | | | Name of the IPv4 access-list to be assigned in the ingress direction.
The access-list must be defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip".
Required for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under `wan_carriers`. | + | [        ipv4_acl_out](## ".defaults.l3_port_channels.[].ipv4_acl_out") | String | | | | Name of the IPv4 Access-list to be assigned in the egress direction.
The access-list must be defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". | + | [        static_routes](## ".defaults.l3_port_channels.[].static_routes") | List, items: Dictionary | | | Min Length: 1 | Configure IPv4 static routes pointing to `peer_ip`. | + | [          - prefix](## ".defaults.l3_port_channels.[].static_routes.[].prefix") | String | Required, Unique | | | IPv4_network/Mask. | + | [        qos_profile](## ".defaults.l3_port_channels.[].qos_profile") | String | | | | QOS service profile. | + | [        wan_carrier](## ".defaults.l3_port_channels.[].wan_carrier") | String | | | | The WAN carrier this interface is connected to.
This is used to infer the path-groups in which this interface should be configured.
Unless the carrier is marked as 'trusted' under `wan_carriers`, `ipv4_acl_in` is also required on all WAN interfaces. | + | [        wan_circuit_id](## ".defaults.l3_port_channels.[].wan_circuit_id") | String | | | | The WAN circuit ID for this interface.
This is not rendered in the configuration but used for WAN designs. | + | [        connected_to_pathfinder](## ".defaults.l3_port_channels.[].connected_to_pathfinder") | Boolean | | `True` | | For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. | + | [        raw_eos_cli](## ".defaults.l3_port_channels.[].raw_eos_cli") | String | | | | EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration. | + | [        flow_tracking](## ".defaults.l3_port_channels.[].flow_tracking") | Dictionary | | | | Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` setting. | + | [          enabled](## ".defaults.l3_port_channels.[].flow_tracking.enabled") | Boolean | | | | | + | [          name](## ".defaults.l3_port_channels.[].flow_tracking.name") | String | | | | Flow tracker name as defined in flow_tracking_settings. | + | [        structured_config](## ".defaults.l3_port_channels.[].structured_config") | Dictionary | | | | Custom structured config for the Port-Channel interface. | + | [  node_groups](## ".node_groups") | List, items: Dictionary | | | | Define variables related to all nodes part of this group. | + | [    - group](## ".node_groups.[].group") | String | Required, Unique | | | The Node Group Name is used for MLAG domain unless set with 'mlag_domain_id'.
The Node Group Name is also used for peer description on downstream switches' uplinks.
| + | [      nodes](## ".node_groups.[].nodes") | List, items: Dictionary | | | | Define variables per node. | + | [        - name](## ".node_groups.[].nodes.[].name") | String | Required, Unique | | | The Node Name is used as "hostname". | + | [          l3_port_channels](## ".node_groups.[].nodes.[].l3_port_channels") | List, items: Dictionary | | | | L3 Port-Channel interfaces to configure on the node. | + | [            - name](## ".node_groups.[].nodes.[].l3_port_channels.[].name") | String | Required, Unique | | Pattern: `Port-Channel[\d/]+(\.[\d]+)?` | Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'.
For a Port-Channel subinterface, the parent Port-Channel interface must be defined as well. | + | [              description](## ".node_groups.[].nodes.[].l3_port_channels.[].description") | String | | | | Interface description.
If not set, a default description will be configured with '[[ ]]'. | + | [              mode](## ".node_groups.[].nodes.[].l3_port_channels.[].mode") | String | | `active` | Valid Values:
- active
- passive
- on | Port-Channel mode.
Should not be set on Port-Channel subinterfaces. | + | [              member_interfaces](## ".node_groups.[].nodes.[].l3_port_channels.[].member_interfaces") | List, items: Dictionary | | | | Port-Channel member interfaces.
Should not be set on Port-Channel subinterfaces. | + | [                - name](## ".node_groups.[].nodes.[].l3_port_channels.[].member_interfaces.[].name") | String | Required, Unique | | Pattern: `Ethernet[\d/]+` | Ethernet interface name like 'Ethernet2'.
Member interface cannot be subinterface. | + | [                  description](## ".node_groups.[].nodes.[].l3_port_channels.[].member_interfaces.[].description") | String | | | | Interface description for this member.
If not set, a default description will be configured with '[[ ]]'. | + | [                  peer](## ".node_groups.[].nodes.[].l3_port_channels.[].member_interfaces.[].peer") | String | | | | The peer device name. Used for description and documentation.
If not set, this inherits the peer setting on the port-channel interface. | + | [                  peer_interface](## ".node_groups.[].nodes.[].l3_port_channels.[].member_interfaces.[].peer_interface") | String | | | | The peer device interface. Used for description and documentation. | + | [                  speed](## ".node_groups.[].nodes.[].l3_port_channels.[].member_interfaces.[].speed") | String | | | | Speed should be set in the format `` or `forced ` or `auto `. | + | [                  structured_config](## ".node_groups.[].nodes.[].l3_port_channels.[].member_interfaces.[].structured_config") | Dictionary | | | | Custom structured config for the member ethernet interface. | + | [              ip_address](## ".node_groups.[].nodes.[].l3_port_channels.[].ip_address") | String | | | | Node IPv4 address/Mask or 'dhcp'. | + | [              dhcp_ip](## ".node_groups.[].nodes.[].l3_port_channels.[].dhcp_ip") | String | | | | When the `ip_address` is `dhcp`, this optional field allows to indicate the expected
IPv4 address (without mask) to be allocated on the interface if known.
This is not rendered in the configuration but can be used for substitution of 'interface_ip' in the Access-list
set under `ipv4_acl_in` and `ipv4_acl_out`. | + | [              public_ip](## ".node_groups.[].nodes.[].l3_port_channels.[].public_ip") | String | | | | Node IPv4 address (no mask).

This is used to get the public IP (if known) when the device is behind NAT.
This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP
with the following preference:
`wan_route_servers.path_groups.interfaces.ip_address`
-> `l3_port_channels.public_ip`
-> `l3_port_channels.ip_address`

The determined Public IP is used by WAN routers when peering with this interface. | + | [              encapsulation_dot1q_vlan](## ".node_groups.[].nodes.[].l3_port_channels.[].encapsulation_dot1q_vlan") | Integer | | | Min: 1
Max: 4094 | For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be specified. | + | [              dhcp_accept_default_route](## ".node_groups.[].nodes.[].l3_port_channels.[].dhcp_accept_default_route") | Boolean | | `True` | | Accept a default route from DHCP if `ip_address` is set to `dhcp`. | + | [              enabled](## ".node_groups.[].nodes.[].l3_port_channels.[].enabled") | Boolean | | `True` | | Enable or Shutdown the interface. | + | [              peer](## ".node_groups.[].nodes.[].l3_port_channels.[].peer") | String | | | | The peer device name. Used for description and documentation. | + | [              peer_port_channel](## ".node_groups.[].nodes.[].l3_port_channels.[].peer_port_channel") | String | | | | The peer device port-channel interface. Used for description and documentation. | + | [              peer_ip](## ".node_groups.[].nodes.[].l3_port_channels.[].peer_ip") | String | | | | The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true and `ip` is an IP address. | + | [              bgp](## ".node_groups.[].nodes.[].l3_port_channels.[].bgp") | Dictionary | | | | Enforce IPv4 BGP peering for the peer | + | [                peer_as](## ".node_groups.[].nodes.[].l3_port_channels.[].bgp.peer_as") | String | Required | | | BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>".
For asdot notation in YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float number. | + | [                ipv4_prefix_list_in](## ".node_groups.[].nodes.[].l3_port_channels.[].bgp.ipv4_prefix_list_in") | String | | | | Prefix List Name. Accept routes for only these prefixes from the peer.
Required for wan interfaces. | + | [                ipv4_prefix_list_out](## ".node_groups.[].nodes.[].l3_port_channels.[].bgp.ipv4_prefix_list_out") | String | | | | Prefix List Name. Advertise routes for only these prefixes.
If not specified, nothing would be advertised. | + | [              ipv4_acl_in](## ".node_groups.[].nodes.[].l3_port_channels.[].ipv4_acl_in") | String | | | | Name of the IPv4 access-list to be assigned in the ingress direction.
The access-list must be defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip".
Required for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under `wan_carriers`. | + | [              ipv4_acl_out](## ".node_groups.[].nodes.[].l3_port_channels.[].ipv4_acl_out") | String | | | | Name of the IPv4 Access-list to be assigned in the egress direction.
The access-list must be defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". | + | [              static_routes](## ".node_groups.[].nodes.[].l3_port_channels.[].static_routes") | List, items: Dictionary | | | Min Length: 1 | Configure IPv4 static routes pointing to `peer_ip`. | + | [                - prefix](## ".node_groups.[].nodes.[].l3_port_channels.[].static_routes.[].prefix") | String | Required, Unique | | | IPv4_network/Mask. | + | [              qos_profile](## ".node_groups.[].nodes.[].l3_port_channels.[].qos_profile") | String | | | | QOS service profile. | + | [              wan_carrier](## ".node_groups.[].nodes.[].l3_port_channels.[].wan_carrier") | String | | | | The WAN carrier this interface is connected to.
This is used to infer the path-groups in which this interface should be configured.
Unless the carrier is marked as 'trusted' under `wan_carriers`, `ipv4_acl_in` is also required on all WAN interfaces. | + | [              wan_circuit_id](## ".node_groups.[].nodes.[].l3_port_channels.[].wan_circuit_id") | String | | | | The WAN circuit ID for this interface.
This is not rendered in the configuration but used for WAN designs. | + | [              connected_to_pathfinder](## ".node_groups.[].nodes.[].l3_port_channels.[].connected_to_pathfinder") | Boolean | | `True` | | For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. | + | [              raw_eos_cli](## ".node_groups.[].nodes.[].l3_port_channels.[].raw_eos_cli") | String | | | | EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration. | + | [              flow_tracking](## ".node_groups.[].nodes.[].l3_port_channels.[].flow_tracking") | Dictionary | | | | Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` setting. | + | [                enabled](## ".node_groups.[].nodes.[].l3_port_channels.[].flow_tracking.enabled") | Boolean | | | | | + | [                name](## ".node_groups.[].nodes.[].l3_port_channels.[].flow_tracking.name") | String | | | | Flow tracker name as defined in flow_tracking_settings. | + | [              structured_config](## ".node_groups.[].nodes.[].l3_port_channels.[].structured_config") | Dictionary | | | | Custom structured config for the Port-Channel interface. | + | [      l3_port_channels](## ".node_groups.[].l3_port_channels") | List, items: Dictionary | | | | L3 Port-Channel interfaces to configure on the node. | + | [        - name](## ".node_groups.[].l3_port_channels.[].name") | String | Required, Unique | | Pattern: `Port-Channel[\d/]+(\.[\d]+)?` | Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'.
For a Port-Channel subinterface, the parent Port-Channel interface must be defined as well. | + | [          description](## ".node_groups.[].l3_port_channels.[].description") | String | | | | Interface description.
If not set, a default description will be configured with '[[ ]]'. | + | [          mode](## ".node_groups.[].l3_port_channels.[].mode") | String | | `active` | Valid Values:
- active
- passive
- on | Port-Channel mode.
Should not be set on Port-Channel subinterfaces. | + | [          member_interfaces](## ".node_groups.[].l3_port_channels.[].member_interfaces") | List, items: Dictionary | | | | Port-Channel member interfaces.
Should not be set on Port-Channel subinterfaces. | + | [            - name](## ".node_groups.[].l3_port_channels.[].member_interfaces.[].name") | String | Required, Unique | | Pattern: `Ethernet[\d/]+` | Ethernet interface name like 'Ethernet2'.
Member interface cannot be subinterface. | + | [              description](## ".node_groups.[].l3_port_channels.[].member_interfaces.[].description") | String | | | | Interface description for this member.
If not set, a default description will be configured with '[[ ]]'. | + | [              peer](## ".node_groups.[].l3_port_channels.[].member_interfaces.[].peer") | String | | | | The peer device name. Used for description and documentation.
If not set, this inherits the peer setting on the port-channel interface. | + | [              peer_interface](## ".node_groups.[].l3_port_channels.[].member_interfaces.[].peer_interface") | String | | | | The peer device interface. Used for description and documentation. | + | [              speed](## ".node_groups.[].l3_port_channels.[].member_interfaces.[].speed") | String | | | | Speed should be set in the format `` or `forced ` or `auto `. | + | [              structured_config](## ".node_groups.[].l3_port_channels.[].member_interfaces.[].structured_config") | Dictionary | | | | Custom structured config for the member ethernet interface. | + | [          ip_address](## ".node_groups.[].l3_port_channels.[].ip_address") | String | | | | Node IPv4 address/Mask or 'dhcp'. | + | [          dhcp_ip](## ".node_groups.[].l3_port_channels.[].dhcp_ip") | String | | | | When the `ip_address` is `dhcp`, this optional field allows to indicate the expected
IPv4 address (without mask) to be allocated on the interface if known.
This is not rendered in the configuration but can be used for substitution of 'interface_ip' in the Access-list
set under `ipv4_acl_in` and `ipv4_acl_out`. | + | [          public_ip](## ".node_groups.[].l3_port_channels.[].public_ip") | String | | | | Node IPv4 address (no mask).

This is used to get the public IP (if known) when the device is behind NAT.
This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP
with the following preference:
`wan_route_servers.path_groups.interfaces.ip_address`
-> `l3_port_channels.public_ip`
-> `l3_port_channels.ip_address`

The determined Public IP is used by WAN routers when peering with this interface. | + | [          encapsulation_dot1q_vlan](## ".node_groups.[].l3_port_channels.[].encapsulation_dot1q_vlan") | Integer | | | Min: 1
Max: 4094 | For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be specified. | + | [          dhcp_accept_default_route](## ".node_groups.[].l3_port_channels.[].dhcp_accept_default_route") | Boolean | | `True` | | Accept a default route from DHCP if `ip_address` is set to `dhcp`. | + | [          enabled](## ".node_groups.[].l3_port_channels.[].enabled") | Boolean | | `True` | | Enable or Shutdown the interface. | + | [          peer](## ".node_groups.[].l3_port_channels.[].peer") | String | | | | The peer device name. Used for description and documentation. | + | [          peer_port_channel](## ".node_groups.[].l3_port_channels.[].peer_port_channel") | String | | | | The peer device port-channel interface. Used for description and documentation. | + | [          peer_ip](## ".node_groups.[].l3_port_channels.[].peer_ip") | String | | | | The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true and `ip` is an IP address. | + | [          bgp](## ".node_groups.[].l3_port_channels.[].bgp") | Dictionary | | | | Enforce IPv4 BGP peering for the peer | + | [            peer_as](## ".node_groups.[].l3_port_channels.[].bgp.peer_as") | String | Required | | | BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>".
For asdot notation in YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float number. | + | [            ipv4_prefix_list_in](## ".node_groups.[].l3_port_channels.[].bgp.ipv4_prefix_list_in") | String | | | | Prefix List Name. Accept routes for only these prefixes from the peer.
Required for wan interfaces. | + | [            ipv4_prefix_list_out](## ".node_groups.[].l3_port_channels.[].bgp.ipv4_prefix_list_out") | String | | | | Prefix List Name. Advertise routes for only these prefixes.
If not specified, nothing would be advertised. | + | [          ipv4_acl_in](## ".node_groups.[].l3_port_channels.[].ipv4_acl_in") | String | | | | Name of the IPv4 access-list to be assigned in the ingress direction.
The access-list must be defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip".
Required for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under `wan_carriers`. | + | [          ipv4_acl_out](## ".node_groups.[].l3_port_channels.[].ipv4_acl_out") | String | | | | Name of the IPv4 Access-list to be assigned in the egress direction.
The access-list must be defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". | + | [          static_routes](## ".node_groups.[].l3_port_channels.[].static_routes") | List, items: Dictionary | | | Min Length: 1 | Configure IPv4 static routes pointing to `peer_ip`. | + | [            - prefix](## ".node_groups.[].l3_port_channels.[].static_routes.[].prefix") | String | Required, Unique | | | IPv4_network/Mask. | + | [          qos_profile](## ".node_groups.[].l3_port_channels.[].qos_profile") | String | | | | QOS service profile. | + | [          wan_carrier](## ".node_groups.[].l3_port_channels.[].wan_carrier") | String | | | | The WAN carrier this interface is connected to.
This is used to infer the path-groups in which this interface should be configured.
Unless the carrier is marked as 'trusted' under `wan_carriers`, `ipv4_acl_in` is also required on all WAN interfaces. | + | [          wan_circuit_id](## ".node_groups.[].l3_port_channels.[].wan_circuit_id") | String | | | | The WAN circuit ID for this interface.
This is not rendered in the configuration but used for WAN designs. | + | [          connected_to_pathfinder](## ".node_groups.[].l3_port_channels.[].connected_to_pathfinder") | Boolean | | `True` | | For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. | + | [          raw_eos_cli](## ".node_groups.[].l3_port_channels.[].raw_eos_cli") | String | | | | EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration. | + | [          flow_tracking](## ".node_groups.[].l3_port_channels.[].flow_tracking") | Dictionary | | | | Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` setting. | + | [            enabled](## ".node_groups.[].l3_port_channels.[].flow_tracking.enabled") | Boolean | | | | | + | [            name](## ".node_groups.[].l3_port_channels.[].flow_tracking.name") | String | | | | Flow tracker name as defined in flow_tracking_settings. | + | [          structured_config](## ".node_groups.[].l3_port_channels.[].structured_config") | Dictionary | | | | Custom structured config for the Port-Channel interface. | + | [  nodes](## ".nodes") | List, items: Dictionary | | | | Define variables per node. | + | [    - name](## ".nodes.[].name") | String | Required, Unique | | | The Node Name is used as "hostname". | + | [      l3_port_channels](## ".nodes.[].l3_port_channels") | List, items: Dictionary | | | | L3 Port-Channel interfaces to configure on the node. | + | [        - name](## ".nodes.[].l3_port_channels.[].name") | String | Required, Unique | | Pattern: `Port-Channel[\d/]+(\.[\d]+)?` | Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'.
For a Port-Channel subinterface, the parent Port-Channel interface must be defined as well. | + | [          description](## ".nodes.[].l3_port_channels.[].description") | String | | | | Interface description.
If not set, a default description will be configured with '[[ ]]'. | + | [          mode](## ".nodes.[].l3_port_channels.[].mode") | String | | `active` | Valid Values:
- active
- passive
- on | Port-Channel mode.
Should not be set on Port-Channel subinterfaces. | + | [          member_interfaces](## ".nodes.[].l3_port_channels.[].member_interfaces") | List, items: Dictionary | | | | Port-Channel member interfaces.
Should not be set on Port-Channel subinterfaces. | + | [            - name](## ".nodes.[].l3_port_channels.[].member_interfaces.[].name") | String | Required, Unique | | Pattern: `Ethernet[\d/]+` | Ethernet interface name like 'Ethernet2'.
Member interface cannot be subinterface. | + | [              description](## ".nodes.[].l3_port_channels.[].member_interfaces.[].description") | String | | | | Interface description for this member.
If not set, a default description will be configured with '[[ ]]'. | + | [              peer](## ".nodes.[].l3_port_channels.[].member_interfaces.[].peer") | String | | | | The peer device name. Used for description and documentation.
If not set, this inherits the peer setting on the port-channel interface. | + | [              peer_interface](## ".nodes.[].l3_port_channels.[].member_interfaces.[].peer_interface") | String | | | | The peer device interface. Used for description and documentation. | + | [              speed](## ".nodes.[].l3_port_channels.[].member_interfaces.[].speed") | String | | | | Speed should be set in the format `` or `forced ` or `auto `. | + | [              structured_config](## ".nodes.[].l3_port_channels.[].member_interfaces.[].structured_config") | Dictionary | | | | Custom structured config for the member ethernet interface. | + | [          ip_address](## ".nodes.[].l3_port_channels.[].ip_address") | String | | | | Node IPv4 address/Mask or 'dhcp'. | + | [          dhcp_ip](## ".nodes.[].l3_port_channels.[].dhcp_ip") | String | | | | When the `ip_address` is `dhcp`, this optional field allows to indicate the expected
IPv4 address (without mask) to be allocated on the interface if known.
This is not rendered in the configuration but can be used for substitution of 'interface_ip' in the Access-list
set under `ipv4_acl_in` and `ipv4_acl_out`. | + | [          public_ip](## ".nodes.[].l3_port_channels.[].public_ip") | String | | | | Node IPv4 address (no mask).

This is used to get the public IP (if known) when the device is behind NAT.
This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP
with the following preference:
`wan_route_servers.path_groups.interfaces.ip_address`
-> `l3_port_channels.public_ip`
-> `l3_port_channels.ip_address`

The determined Public IP is used by WAN routers when peering with this interface. | + | [          encapsulation_dot1q_vlan](## ".nodes.[].l3_port_channels.[].encapsulation_dot1q_vlan") | Integer | | | Min: 1
Max: 4094 | For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be specified. | + | [          dhcp_accept_default_route](## ".nodes.[].l3_port_channels.[].dhcp_accept_default_route") | Boolean | | `True` | | Accept a default route from DHCP if `ip_address` is set to `dhcp`. | + | [          enabled](## ".nodes.[].l3_port_channels.[].enabled") | Boolean | | `True` | | Enable or Shutdown the interface. | + | [          peer](## ".nodes.[].l3_port_channels.[].peer") | String | | | | The peer device name. Used for description and documentation. | + | [          peer_port_channel](## ".nodes.[].l3_port_channels.[].peer_port_channel") | String | | | | The peer device port-channel interface. Used for description and documentation. | + | [          peer_ip](## ".nodes.[].l3_port_channels.[].peer_ip") | String | | | | The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true and `ip` is an IP address. | + | [          bgp](## ".nodes.[].l3_port_channels.[].bgp") | Dictionary | | | | Enforce IPv4 BGP peering for the peer | + | [            peer_as](## ".nodes.[].l3_port_channels.[].bgp.peer_as") | String | Required | | | BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>".
For asdot notation in YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float number. | + | [            ipv4_prefix_list_in](## ".nodes.[].l3_port_channels.[].bgp.ipv4_prefix_list_in") | String | | | | Prefix List Name. Accept routes for only these prefixes from the peer.
Required for wan interfaces. | + | [            ipv4_prefix_list_out](## ".nodes.[].l3_port_channels.[].bgp.ipv4_prefix_list_out") | String | | | | Prefix List Name. Advertise routes for only these prefixes.
If not specified, nothing would be advertised. | + | [          ipv4_acl_in](## ".nodes.[].l3_port_channels.[].ipv4_acl_in") | String | | | | Name of the IPv4 access-list to be assigned in the ingress direction.
The access-list must be defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip".
Required for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under `wan_carriers`. | + | [          ipv4_acl_out](## ".nodes.[].l3_port_channels.[].ipv4_acl_out") | String | | | | Name of the IPv4 Access-list to be assigned in the egress direction.
The access-list must be defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". | + | [          static_routes](## ".nodes.[].l3_port_channels.[].static_routes") | List, items: Dictionary | | | Min Length: 1 | Configure IPv4 static routes pointing to `peer_ip`. | + | [            - prefix](## ".nodes.[].l3_port_channels.[].static_routes.[].prefix") | String | Required, Unique | | | IPv4_network/Mask. | + | [          qos_profile](## ".nodes.[].l3_port_channels.[].qos_profile") | String | | | | QOS service profile. | + | [          wan_carrier](## ".nodes.[].l3_port_channels.[].wan_carrier") | String | | | | The WAN carrier this interface is connected to.
This is used to infer the path-groups in which this interface should be configured.
Unless the carrier is marked as 'trusted' under `wan_carriers`, `ipv4_acl_in` is also required on all WAN interfaces. | + | [          wan_circuit_id](## ".nodes.[].l3_port_channels.[].wan_circuit_id") | String | | | | The WAN circuit ID for this interface.
This is not rendered in the configuration but used for WAN designs. | + | [          connected_to_pathfinder](## ".nodes.[].l3_port_channels.[].connected_to_pathfinder") | Boolean | | `True` | | For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. | + | [          raw_eos_cli](## ".nodes.[].l3_port_channels.[].raw_eos_cli") | String | | | | EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration. | + | [          flow_tracking](## ".nodes.[].l3_port_channels.[].flow_tracking") | Dictionary | | | | Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` setting. | + | [            enabled](## ".nodes.[].l3_port_channels.[].flow_tracking.enabled") | Boolean | | | | | + | [            name](## ".nodes.[].l3_port_channels.[].flow_tracking.name") | String | | | | Flow tracker name as defined in flow_tracking_settings. | + | [          structured_config](## ".nodes.[].l3_port_channels.[].structured_config") | Dictionary | | | | Custom structured config for the Port-Channel interface. | + +=== "YAML" + + ```yaml + : + + # Define variables for all nodes of this type. + defaults: + + # L3 Port-Channel interfaces to configure on the node. + l3_port_channels: + + # Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'. + # For a Port-Channel subinterface, the parent Port-Channel interface must be defined as well. + - name: + + # Interface description. + # If not set, a default description will be configured with '[[ ]]'. + description: + + # Port-Channel mode. + # Should not be set on Port-Channel subinterfaces. + mode: + + # Port-Channel member interfaces. + # Should not be set on Port-Channel subinterfaces. + member_interfaces: + + # Ethernet interface name like 'Ethernet2'. + # Member interface cannot be subinterface. + - name: + + # Interface description for this member. + # If not set, a default description will be configured with '[[ ]]'. + description: + + # The peer device name. Used for description and documentation. + # If not set, this inherits the peer setting on the port-channel interface. + peer: + + # The peer device interface. Used for description and documentation. + peer_interface: + + # Speed should be set in the format `` or `forced ` or `auto `. + speed: + + # Custom structured config for the member ethernet interface. + structured_config: + + # Node IPv4 address/Mask or 'dhcp'. + ip_address: + + # When the `ip_address` is `dhcp`, this optional field allows to indicate the expected + # IPv4 address (without mask) to be allocated on the interface if known. + # This is not rendered in the configuration but can be used for substitution of 'interface_ip' in the Access-list + # set under `ipv4_acl_in` and `ipv4_acl_out`. + dhcp_ip: + + # Node IPv4 address (no mask). + # + # This is used to get the public IP (if known) when the device is behind NAT. + # This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP + # with the following preference: + # `wan_route_servers.path_groups.interfaces.ip_address` + # -> `l3_port_channels.public_ip` + # -> `l3_port_channels.ip_address` + # + # The determined Public IP is used by WAN routers when peering with this interface. + public_ip: + + # For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be specified. + encapsulation_dot1q_vlan: + + # Accept a default route from DHCP if `ip_address` is set to `dhcp`. + dhcp_accept_default_route: + + # Enable or Shutdown the interface. + enabled: + + # The peer device name. Used for description and documentation. + peer: + + # The peer device port-channel interface. Used for description and documentation. + peer_port_channel: + + # The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true and `ip` is an IP address. + peer_ip: + + # Enforce IPv4 BGP peering for the peer + bgp: + + # BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>". + # For asdot notation in YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float number. + peer_as: + + # Prefix List Name. Accept routes for only these prefixes from the peer. + # Required for wan interfaces. + ipv4_prefix_list_in: + + # Prefix List Name. Advertise routes for only these prefixes. + # If not specified, nothing would be advertised. + ipv4_prefix_list_out: + + # Name of the IPv4 access-list to be assigned in the ingress direction. + # The access-list must be defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + # Required for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under `wan_carriers`. + ipv4_acl_in: + + # Name of the IPv4 Access-list to be assigned in the egress direction. + # The access-list must be defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + ipv4_acl_out: + + # Configure IPv4 static routes pointing to `peer_ip`. + static_routes: # >=1 items + + # IPv4_network/Mask. + - prefix: + + # QOS service profile. + qos_profile: + + # The WAN carrier this interface is connected to. + # This is used to infer the path-groups in which this interface should be configured. + # Unless the carrier is marked as 'trusted' under `wan_carriers`, `ipv4_acl_in` is also required on all WAN interfaces. + wan_carrier: + + # The WAN circuit ID for this interface. + # This is not rendered in the configuration but used for WAN designs. + wan_circuit_id: + + # For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. + connected_to_pathfinder: + + # EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration. + raw_eos_cli: + + # Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` setting. + flow_tracking: + enabled: + + # Flow tracker name as defined in flow_tracking_settings. + name: + + # Custom structured config for the Port-Channel interface. + structured_config: + + # Define variables related to all nodes part of this group. + node_groups: + + # The Node Group Name is used for MLAG domain unless set with 'mlag_domain_id'. + # The Node Group Name is also used for peer description on downstream switches' uplinks. + - group: + + # Define variables per node. + nodes: + + # The Node Name is used as "hostname". + - name: + + # L3 Port-Channel interfaces to configure on the node. + l3_port_channels: + + # Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'. + # For a Port-Channel subinterface, the parent Port-Channel interface must be defined as well. + - name: + + # Interface description. + # If not set, a default description will be configured with '[[ ]]'. + description: + + # Port-Channel mode. + # Should not be set on Port-Channel subinterfaces. + mode: + + # Port-Channel member interfaces. + # Should not be set on Port-Channel subinterfaces. + member_interfaces: + + # Ethernet interface name like 'Ethernet2'. + # Member interface cannot be subinterface. + - name: + + # Interface description for this member. + # If not set, a default description will be configured with '[[ ]]'. + description: + + # The peer device name. Used for description and documentation. + # If not set, this inherits the peer setting on the port-channel interface. + peer: + + # The peer device interface. Used for description and documentation. + peer_interface: + + # Speed should be set in the format `` or `forced ` or `auto `. + speed: + + # Custom structured config for the member ethernet interface. + structured_config: + + # Node IPv4 address/Mask or 'dhcp'. + ip_address: + + # When the `ip_address` is `dhcp`, this optional field allows to indicate the expected + # IPv4 address (without mask) to be allocated on the interface if known. + # This is not rendered in the configuration but can be used for substitution of 'interface_ip' in the Access-list + # set under `ipv4_acl_in` and `ipv4_acl_out`. + dhcp_ip: + + # Node IPv4 address (no mask). + # + # This is used to get the public IP (if known) when the device is behind NAT. + # This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP + # with the following preference: + # `wan_route_servers.path_groups.interfaces.ip_address` + # -> `l3_port_channels.public_ip` + # -> `l3_port_channels.ip_address` + # + # The determined Public IP is used by WAN routers when peering with this interface. + public_ip: + + # For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be specified. + encapsulation_dot1q_vlan: + + # Accept a default route from DHCP if `ip_address` is set to `dhcp`. + dhcp_accept_default_route: + + # Enable or Shutdown the interface. + enabled: + + # The peer device name. Used for description and documentation. + peer: + + # The peer device port-channel interface. Used for description and documentation. + peer_port_channel: + + # The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true and `ip` is an IP address. + peer_ip: + + # Enforce IPv4 BGP peering for the peer + bgp: + + # BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>". + # For asdot notation in YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float number. + peer_as: + + # Prefix List Name. Accept routes for only these prefixes from the peer. + # Required for wan interfaces. + ipv4_prefix_list_in: + + # Prefix List Name. Advertise routes for only these prefixes. + # If not specified, nothing would be advertised. + ipv4_prefix_list_out: + + # Name of the IPv4 access-list to be assigned in the ingress direction. + # The access-list must be defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + # Required for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under `wan_carriers`. + ipv4_acl_in: + + # Name of the IPv4 Access-list to be assigned in the egress direction. + # The access-list must be defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + ipv4_acl_out: + + # Configure IPv4 static routes pointing to `peer_ip`. + static_routes: # >=1 items + + # IPv4_network/Mask. + - prefix: + + # QOS service profile. + qos_profile: + + # The WAN carrier this interface is connected to. + # This is used to infer the path-groups in which this interface should be configured. + # Unless the carrier is marked as 'trusted' under `wan_carriers`, `ipv4_acl_in` is also required on all WAN interfaces. + wan_carrier: + + # The WAN circuit ID for this interface. + # This is not rendered in the configuration but used for WAN designs. + wan_circuit_id: + + # For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. + connected_to_pathfinder: + + # EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration. + raw_eos_cli: + + # Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` setting. + flow_tracking: + enabled: + + # Flow tracker name as defined in flow_tracking_settings. + name: + + # Custom structured config for the Port-Channel interface. + structured_config: + + # L3 Port-Channel interfaces to configure on the node. + l3_port_channels: + + # Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'. + # For a Port-Channel subinterface, the parent Port-Channel interface must be defined as well. + - name: + + # Interface description. + # If not set, a default description will be configured with '[[ ]]'. + description: + + # Port-Channel mode. + # Should not be set on Port-Channel subinterfaces. + mode: + + # Port-Channel member interfaces. + # Should not be set on Port-Channel subinterfaces. + member_interfaces: + + # Ethernet interface name like 'Ethernet2'. + # Member interface cannot be subinterface. + - name: + + # Interface description for this member. + # If not set, a default description will be configured with '[[ ]]'. + description: + + # The peer device name. Used for description and documentation. + # If not set, this inherits the peer setting on the port-channel interface. + peer: + + # The peer device interface. Used for description and documentation. + peer_interface: + + # Speed should be set in the format `` or `forced ` or `auto `. + speed: + + # Custom structured config for the member ethernet interface. + structured_config: + + # Node IPv4 address/Mask or 'dhcp'. + ip_address: + + # When the `ip_address` is `dhcp`, this optional field allows to indicate the expected + # IPv4 address (without mask) to be allocated on the interface if known. + # This is not rendered in the configuration but can be used for substitution of 'interface_ip' in the Access-list + # set under `ipv4_acl_in` and `ipv4_acl_out`. + dhcp_ip: + + # Node IPv4 address (no mask). + # + # This is used to get the public IP (if known) when the device is behind NAT. + # This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP + # with the following preference: + # `wan_route_servers.path_groups.interfaces.ip_address` + # -> `l3_port_channels.public_ip` + # -> `l3_port_channels.ip_address` + # + # The determined Public IP is used by WAN routers when peering with this interface. + public_ip: + + # For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be specified. + encapsulation_dot1q_vlan: + + # Accept a default route from DHCP if `ip_address` is set to `dhcp`. + dhcp_accept_default_route: + + # Enable or Shutdown the interface. + enabled: + + # The peer device name. Used for description and documentation. + peer: + + # The peer device port-channel interface. Used for description and documentation. + peer_port_channel: + + # The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true and `ip` is an IP address. + peer_ip: + + # Enforce IPv4 BGP peering for the peer + bgp: + + # BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>". + # For asdot notation in YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float number. + peer_as: + + # Prefix List Name. Accept routes for only these prefixes from the peer. + # Required for wan interfaces. + ipv4_prefix_list_in: + + # Prefix List Name. Advertise routes for only these prefixes. + # If not specified, nothing would be advertised. + ipv4_prefix_list_out: + + # Name of the IPv4 access-list to be assigned in the ingress direction. + # The access-list must be defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + # Required for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under `wan_carriers`. + ipv4_acl_in: + + # Name of the IPv4 Access-list to be assigned in the egress direction. + # The access-list must be defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + ipv4_acl_out: + + # Configure IPv4 static routes pointing to `peer_ip`. + static_routes: # >=1 items + + # IPv4_network/Mask. + - prefix: + + # QOS service profile. + qos_profile: + + # The WAN carrier this interface is connected to. + # This is used to infer the path-groups in which this interface should be configured. + # Unless the carrier is marked as 'trusted' under `wan_carriers`, `ipv4_acl_in` is also required on all WAN interfaces. + wan_carrier: + + # The WAN circuit ID for this interface. + # This is not rendered in the configuration but used for WAN designs. + wan_circuit_id: + + # For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. + connected_to_pathfinder: + + # EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration. + raw_eos_cli: + + # Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` setting. + flow_tracking: + enabled: + + # Flow tracker name as defined in flow_tracking_settings. + name: + + # Custom structured config for the Port-Channel interface. + structured_config: + + # Define variables per node. + nodes: + + # The Node Name is used as "hostname". + - name: + + # L3 Port-Channel interfaces to configure on the node. + l3_port_channels: + + # Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'. + # For a Port-Channel subinterface, the parent Port-Channel interface must be defined as well. + - name: + + # Interface description. + # If not set, a default description will be configured with '[[ ]]'. + description: + + # Port-Channel mode. + # Should not be set on Port-Channel subinterfaces. + mode: + + # Port-Channel member interfaces. + # Should not be set on Port-Channel subinterfaces. + member_interfaces: + + # Ethernet interface name like 'Ethernet2'. + # Member interface cannot be subinterface. + - name: + + # Interface description for this member. + # If not set, a default description will be configured with '[[ ]]'. + description: + + # The peer device name. Used for description and documentation. + # If not set, this inherits the peer setting on the port-channel interface. + peer: + + # The peer device interface. Used for description and documentation. + peer_interface: + + # Speed should be set in the format `` or `forced ` or `auto `. + speed: + + # Custom structured config for the member ethernet interface. + structured_config: + + # Node IPv4 address/Mask or 'dhcp'. + ip_address: + + # When the `ip_address` is `dhcp`, this optional field allows to indicate the expected + # IPv4 address (without mask) to be allocated on the interface if known. + # This is not rendered in the configuration but can be used for substitution of 'interface_ip' in the Access-list + # set under `ipv4_acl_in` and `ipv4_acl_out`. + dhcp_ip: + + # Node IPv4 address (no mask). + # + # This is used to get the public IP (if known) when the device is behind NAT. + # This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP + # with the following preference: + # `wan_route_servers.path_groups.interfaces.ip_address` + # -> `l3_port_channels.public_ip` + # -> `l3_port_channels.ip_address` + # + # The determined Public IP is used by WAN routers when peering with this interface. + public_ip: + + # For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be specified. + encapsulation_dot1q_vlan: + + # Accept a default route from DHCP if `ip_address` is set to `dhcp`. + dhcp_accept_default_route: + + # Enable or Shutdown the interface. + enabled: + + # The peer device name. Used for description and documentation. + peer: + + # The peer device port-channel interface. Used for description and documentation. + peer_port_channel: + + # The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true and `ip` is an IP address. + peer_ip: + + # Enforce IPv4 BGP peering for the peer + bgp: + + # BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>". + # For asdot notation in YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float number. + peer_as: + + # Prefix List Name. Accept routes for only these prefixes from the peer. + # Required for wan interfaces. + ipv4_prefix_list_in: + + # Prefix List Name. Advertise routes for only these prefixes. + # If not specified, nothing would be advertised. + ipv4_prefix_list_out: + + # Name of the IPv4 access-list to be assigned in the ingress direction. + # The access-list must be defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + # Required for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under `wan_carriers`. + ipv4_acl_in: + + # Name of the IPv4 Access-list to be assigned in the egress direction. + # The access-list must be defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + ipv4_acl_out: + + # Configure IPv4 static routes pointing to `peer_ip`. + static_routes: # >=1 items + + # IPv4_network/Mask. + - prefix: + + # QOS service profile. + qos_profile: + + # The WAN carrier this interface is connected to. + # This is used to infer the path-groups in which this interface should be configured. + # Unless the carrier is marked as 'trusted' under `wan_carriers`, `ipv4_acl_in` is also required on all WAN interfaces. + wan_carrier: + + # The WAN circuit ID for this interface. + # This is not rendered in the configuration but used for WAN designs. + wan_circuit_id: + + # For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. + connected_to_pathfinder: + + # EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration. + raw_eos_cli: + + # Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` setting. + flow_tracking: + enabled: + + # Flow tracker name as defined in flow_tracking_settings. + name: + + # Custom structured config for the Port-Channel interface. + structured_config: + ``` diff --git a/python-avd/pyavd/_eos_designs/schema/__init__.py b/python-avd/pyavd/_eos_designs/schema/__init__.py index 7b97aab9e76..e7f93fd31ea 100644 --- a/python-avd/pyavd/_eos_designs/schema/__init__.py +++ b/python-avd/pyavd/_eos_designs/schema/__init__.py @@ -3583,6 +3583,46 @@ def __init__( L3Interfaces. + Subclass of AvdModel. + + Args: + enabled: enabled + name: Flow tracker name as defined in flow_tracking_settings. + _custom_data: _custom_data + + """ + + class L3PortChannels(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "enabled": {"type": bool, "default": False}, + "name": {"type": str, "default": "FLOW-TRACKER"}, + "_custom_data": {"type": dict}, + } + enabled: bool + """Default value: `False`""" + name: str + """ + Flow tracker name as defined in flow_tracking_settings. + + Default value: `"FLOW-TRACKER"` + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + enabled: bool | UndefinedType = Undefined, + name: str | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + L3PortChannels. + + Subclass of AvdModel. Args: @@ -3680,6 +3720,7 @@ def __init__( "core_interfaces": {"type": CoreInterfaces}, "mlag_interfaces": {"type": MlagInterfaces}, "l3_interfaces": {"type": L3Interfaces}, + "l3_port_channels": {"type": L3PortChannels}, "dps_interfaces": {"type": DpsInterfaces}, "direct_wan_ha_links": {"type": DirectWanHaLinks}, "_custom_data": {"type": dict}, @@ -3723,6 +3764,12 @@ def __init__( l3_interfaces: L3Interfaces """ Enable flow-tracking on all node.l3_interfaces and network-services tenants.vrfs.l3_interfaces. + Subclass of AvdModel. + """ + l3_port_channels: L3PortChannels + """ + Enable flow-tracking on all node.l3_port_channels. + Subclass of AvdModel. """ dps_interfaces: DpsInterfaces @@ -3751,6 +3798,7 @@ def __init__( core_interfaces: CoreInterfaces | UndefinedType = Undefined, mlag_interfaces: MlagInterfaces | UndefinedType = Undefined, l3_interfaces: L3Interfaces | UndefinedType = Undefined, + l3_port_channels: L3PortChannels | UndefinedType = Undefined, dps_interfaces: DpsInterfaces | UndefinedType = Undefined, direct_wan_ha_links: DirectWanHaLinks | UndefinedType = Undefined, _custom_data: dict[str, Any] | UndefinedType = Undefined, @@ -3788,6 +3836,10 @@ def __init__( Subclass of AvdModel. l3_interfaces: Enable flow-tracking on all node.l3_interfaces and network-services tenants.vrfs.l3_interfaces. + Subclass of AvdModel. + l3_port_channels: + Enable flow-tracking on all node.l3_port_channels. + Subclass of AvdModel. dps_interfaces: Enable flow-tracking on all dps_interfaces. @@ -21535,6 +21587,550 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): L3Interfaces._item_type = L3InterfacesItem + class L3PortChannelsItem(AvdModel): + """Subclass of AvdModel.""" + + class MemberInterfacesItem(AvdModel): + """Subclass of AvdModel.""" + + class StructuredConfig(EosCliConfigGen.EthernetInterfacesItem): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "name": {"type": str}, + "description": {"type": str}, + "peer": {"type": str}, + "peer_interface": {"type": str}, + "speed": {"type": str}, + "structured_config": {"type": StructuredConfig}, + "_custom_data": {"type": dict}, + } + name: str + """ + Ethernet interface name like 'Ethernet2'. + Member interface cannot be subinterface. + """ + description: str | None + """ + Interface description for this member. + If not set, a default description will be configured with + '[[ ]]'. + """ + peer: str | None + """ + The peer device name. Used for description and documentation. + If not set, this inherits the peer + setting on the port-channel interface. + """ + peer_interface: str | None + """The peer device interface. Used for description and documentation.""" + speed: str | None + """ + Speed should be set in the format `` or `forced ` or `auto + `. + """ + structured_config: StructuredConfig + """ + Custom structured config for the member ethernet interface. + + Subclass of AvdModel. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + name: str | UndefinedType = Undefined, + description: str | None | UndefinedType = Undefined, + peer: str | None | UndefinedType = Undefined, + peer_interface: str | None | UndefinedType = Undefined, + speed: str | None | UndefinedType = Undefined, + structured_config: StructuredConfig | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + MemberInterfacesItem. + + + Subclass of AvdModel. + + Args: + name: + Ethernet interface name like 'Ethernet2'. + Member interface cannot be subinterface. + description: + Interface description for this member. + If not set, a default description will be configured with + '[[ ]]'. + peer: + The peer device name. Used for description and documentation. + If not set, this inherits the peer + setting on the port-channel interface. + peer_interface: The peer device interface. Used for description and documentation. + speed: + Speed should be set in the format `` or `forced ` or `auto + `. + structured_config: + Custom structured config for the member ethernet interface. + + Subclass of AvdModel. + _custom_data: _custom_data + + """ + + class MemberInterfaces(AvdIndexedList[str, MemberInterfacesItem]): + """Subclass of AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`).""" + + _primary_key: ClassVar[str] = "name" + + MemberInterfaces._item_type = MemberInterfacesItem + + class Bgp(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "peer_as": {"type": str}, + "ipv4_prefix_list_in": {"type": str}, + "ipv4_prefix_list_out": {"type": str}, + "_custom_data": {"type": dict}, + } + peer_as: str + """ + BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>". + For asdot notation in + YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float + number. + """ + ipv4_prefix_list_in: str | None + """ + Prefix List Name. Accept routes for only these prefixes from the peer. + Required for wan interfaces. + """ + ipv4_prefix_list_out: str | None + """ + Prefix List Name. Advertise routes for only these prefixes. + If not specified, nothing would be + advertised. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + peer_as: str | UndefinedType = Undefined, + ipv4_prefix_list_in: str | None | UndefinedType = Undefined, + ipv4_prefix_list_out: str | None | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + Bgp. + + + Subclass of AvdModel. + + Args: + peer_as: + BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>". + For asdot notation in + YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float + number. + ipv4_prefix_list_in: + Prefix List Name. Accept routes for only these prefixes from the peer. + Required for wan interfaces. + ipv4_prefix_list_out: + Prefix List Name. Advertise routes for only these prefixes. + If not specified, nothing would be + advertised. + _custom_data: _custom_data + + """ + + class StaticRoutesItem(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = {"prefix": {"type": str}, "_custom_data": {"type": dict}} + prefix: str + """IPv4_network/Mask.""" + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, *, prefix: str | UndefinedType = Undefined, _custom_data: dict[str, Any] | UndefinedType = Undefined + ) -> None: + """ + StaticRoutesItem. + + + Subclass of AvdModel. + + Args: + prefix: IPv4_network/Mask. + _custom_data: _custom_data + + """ + + class StaticRoutes(AvdIndexedList[str, StaticRoutesItem]): + """Subclass of AvdIndexedList with `StaticRoutesItem` items. Primary key is `prefix` (`str`).""" + + _primary_key: ClassVar[str] = "prefix" + + StaticRoutes._item_type = StaticRoutesItem + + class FlowTracking(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = {"enabled": {"type": bool}, "name": {"type": str}, "_custom_data": {"type": dict}} + enabled: bool | None + name: str | None + """Flow tracker name as defined in flow_tracking_settings.""" + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + enabled: bool | None | UndefinedType = Undefined, + name: str | None | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + FlowTracking. + + + Subclass of AvdModel. + + Args: + enabled: enabled + name: Flow tracker name as defined in flow_tracking_settings. + _custom_data: _custom_data + + """ + + class StructuredConfig(EosCliConfigGen.PortChannelInterfacesItem): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "name": {"type": str}, + "description": {"type": str}, + "mode": {"type": str, "default": "active"}, + "member_interfaces": {"type": MemberInterfaces}, + "ip_address": {"type": str}, + "dhcp_ip": {"type": str}, + "public_ip": {"type": str}, + "encapsulation_dot1q_vlan": {"type": int}, + "dhcp_accept_default_route": {"type": bool, "default": True}, + "enabled": {"type": bool, "default": True}, + "peer": {"type": str}, + "peer_port_channel": {"type": str}, + "peer_ip": {"type": str}, + "bgp": {"type": Bgp}, + "ipv4_acl_in": {"type": str}, + "ipv4_acl_out": {"type": str}, + "static_routes": {"type": StaticRoutes}, + "qos_profile": {"type": str}, + "wan_carrier": {"type": str}, + "wan_circuit_id": {"type": str}, + "connected_to_pathfinder": {"type": bool, "default": True}, + "raw_eos_cli": {"type": str}, + "flow_tracking": {"type": FlowTracking}, + "structured_config": {"type": StructuredConfig}, + "_custom_data": {"type": dict}, + } + name: str + """ + Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'. + For a + Port-Channel subinterface, the parent Port-Channel interface must be defined as well. + """ + description: str | None + """ + Interface description. + If not set, a default description will be configured with '[[ + ]]'. + """ + mode: Literal["active", "passive", "on"] + """ + Port-Channel mode. + Should not be set on Port-Channel subinterfaces. + + Default value: `"active"` + """ + member_interfaces: MemberInterfaces + """ + Port-Channel member interfaces. + Should not be set on Port-Channel subinterfaces. + + Subclass of + AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`). + """ + ip_address: str | None + """Node IPv4 address/Mask or 'dhcp'.""" + dhcp_ip: str | None + """ + When the `ip_address` is `dhcp`, this optional field allows to indicate the expected + IPv4 address + (without mask) to be allocated on the interface if known. + This is not rendered in the configuration + but can be used for substitution of 'interface_ip' in the Access-list + set under `ipv4_acl_in` and + `ipv4_acl_out`. + """ + public_ip: str | None + """ + Node IPv4 address (no mask). + + This is used to get the public IP (if known) when the device is behind + NAT. + This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP + with the following preference: + `wan_route_servers.path_groups.interfaces.ip_address` + -> + `l3_port_channels.public_ip` + -> `l3_port_channels.ip_address` + + The determined Public IP is + used by WAN routers when peering with this interface. + """ + encapsulation_dot1q_vlan: int | None + """ + For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be + specified. + """ + dhcp_accept_default_route: bool + """ + Accept a default route from DHCP if `ip_address` is set to `dhcp`. + + Default value: `True` + """ + enabled: bool + """ + Enable or Shutdown the interface. + + Default value: `True` + """ + peer: str | None + """The peer device name. Used for description and documentation.""" + peer_port_channel: str | None + """The peer device port-channel interface. Used for description and documentation.""" + peer_ip: str | None + """ + The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true + and `ip` is an IP address. + """ + bgp: Bgp + """ + Enforce IPv4 BGP peering for the peer + + Subclass of AvdModel. + """ + ipv4_acl_in: str | None + """ + Name of the IPv4 access-list to be assigned in the ingress direction. + The access-list must be + defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + Required + for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under + `wan_carriers`. + """ + ipv4_acl_out: str | None + """ + Name of the IPv4 Access-list to be assigned in the egress direction. + The access-list must be defined + under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + """ + static_routes: StaticRoutes + """ + Configure IPv4 static routes pointing to `peer_ip`. + + Subclass of AvdIndexedList with + `StaticRoutesItem` items. Primary key is `prefix` (`str`). + """ + qos_profile: str | None + """QOS service profile.""" + wan_carrier: str | None + """ + The WAN carrier this interface is connected to. + This is used to infer the path-groups in which this + interface should be configured. + Unless the carrier is marked as 'trusted' under `wan_carriers`, + `ipv4_acl_in` is also required on all WAN interfaces. + """ + wan_circuit_id: str | None + """ + The WAN circuit ID for this interface. + This is not rendered in the configuration but used for WAN + designs. + """ + connected_to_pathfinder: bool + """ + For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. + + Default value: `True` + """ + raw_eos_cli: str | None + """EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration.""" + flow_tracking: FlowTracking + """ + Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` + setting. + + Subclass of AvdModel. + """ + structured_config: StructuredConfig + """ + Custom structured config for the Port-Channel interface. + + Subclass of AvdModel. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + name: str | UndefinedType = Undefined, + description: str | None | UndefinedType = Undefined, + mode: Literal["active", "passive", "on"] | UndefinedType = Undefined, + member_interfaces: MemberInterfaces | UndefinedType = Undefined, + ip_address: str | None | UndefinedType = Undefined, + dhcp_ip: str | None | UndefinedType = Undefined, + public_ip: str | None | UndefinedType = Undefined, + encapsulation_dot1q_vlan: int | None | UndefinedType = Undefined, + dhcp_accept_default_route: bool | UndefinedType = Undefined, + enabled: bool | UndefinedType = Undefined, + peer: str | None | UndefinedType = Undefined, + peer_port_channel: str | None | UndefinedType = Undefined, + peer_ip: str | None | UndefinedType = Undefined, + bgp: Bgp | UndefinedType = Undefined, + ipv4_acl_in: str | None | UndefinedType = Undefined, + ipv4_acl_out: str | None | UndefinedType = Undefined, + static_routes: StaticRoutes | UndefinedType = Undefined, + qos_profile: str | None | UndefinedType = Undefined, + wan_carrier: str | None | UndefinedType = Undefined, + wan_circuit_id: str | None | UndefinedType = Undefined, + connected_to_pathfinder: bool | UndefinedType = Undefined, + raw_eos_cli: str | None | UndefinedType = Undefined, + flow_tracking: FlowTracking | UndefinedType = Undefined, + structured_config: StructuredConfig | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + L3PortChannelsItem. + + + Subclass of AvdModel. + + Args: + name: + Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'. + For a + Port-Channel subinterface, the parent Port-Channel interface must be defined as well. + description: + Interface description. + If not set, a default description will be configured with '[[ + ]]'. + mode: + Port-Channel mode. + Should not be set on Port-Channel subinterfaces. + member_interfaces: + Port-Channel member interfaces. + Should not be set on Port-Channel subinterfaces. + + Subclass of + AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`). + ip_address: Node IPv4 address/Mask or 'dhcp'. + dhcp_ip: + When the `ip_address` is `dhcp`, this optional field allows to indicate the expected + IPv4 address + (without mask) to be allocated on the interface if known. + This is not rendered in the configuration + but can be used for substitution of 'interface_ip' in the Access-list + set under `ipv4_acl_in` and + `ipv4_acl_out`. + public_ip: + Node IPv4 address (no mask). + + This is used to get the public IP (if known) when the device is behind + NAT. + This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP + with the following preference: + `wan_route_servers.path_groups.interfaces.ip_address` + -> + `l3_port_channels.public_ip` + -> `l3_port_channels.ip_address` + + The determined Public IP is + used by WAN routers when peering with this interface. + encapsulation_dot1q_vlan: + For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be + specified. + dhcp_accept_default_route: Accept a default route from DHCP if `ip_address` is set to `dhcp`. + enabled: Enable or Shutdown the interface. + peer: The peer device name. Used for description and documentation. + peer_port_channel: The peer device port-channel interface. Used for description and documentation. + peer_ip: + The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true + and `ip` is an IP address. + bgp: + Enforce IPv4 BGP peering for the peer + + Subclass of AvdModel. + ipv4_acl_in: + Name of the IPv4 access-list to be assigned in the ingress direction. + The access-list must be + defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + Required + for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under + `wan_carriers`. + ipv4_acl_out: + Name of the IPv4 Access-list to be assigned in the egress direction. + The access-list must be defined + under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + static_routes: + Configure IPv4 static routes pointing to `peer_ip`. + + Subclass of AvdIndexedList with + `StaticRoutesItem` items. Primary key is `prefix` (`str`). + qos_profile: QOS service profile. + wan_carrier: + The WAN carrier this interface is connected to. + This is used to infer the path-groups in which this + interface should be configured. + Unless the carrier is marked as 'trusted' under `wan_carriers`, + `ipv4_acl_in` is also required on all WAN interfaces. + wan_circuit_id: + The WAN circuit ID for this interface. + This is not rendered in the configuration but used for WAN + designs. + connected_to_pathfinder: For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. + raw_eos_cli: EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration. + flow_tracking: + Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` + setting. + + Subclass of AvdModel. + structured_config: + Custom structured config for the Port-Channel interface. + + Subclass of AvdModel. + _custom_data: _custom_data + + """ + + class L3PortChannels(AvdIndexedList[str, L3PortChannelsItem]): + """Subclass of AvdIndexedList with `L3PortChannelsItem` items. Primary key is `name` (`str`).""" + + _primary_key: ClassVar[str] = "name" + + L3PortChannels._item_type = L3PortChannelsItem + _fields: ClassVar[dict] = { "id": {"type": int}, "platform": {"type": str}, @@ -21639,6 +22235,7 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): "wan_ha": {"type": WanHa}, "dps_mss_ipv4": {"type": str, "default": "auto"}, "l3_interfaces": {"type": L3Interfaces}, + "l3_port_channels": {"type": L3PortChannels}, "data_plane_cpu_allocation_max": {"type": int}, "flow_tracker_type": {"type": str}, "_custom_data": {"type": dict}, @@ -22420,11 +23017,16 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): l3_interfaces: L3Interfaces """ L3 Interfaces to configure on the node. - Used to define the node for WAN interfaces when - `wan_carrier` is set. - Subclass of AvdIndexedList with `L3InterfacesItem` items. Primary key is - `name` (`str`). + Subclass of AvdIndexedList with `L3InterfacesItem` items. + Primary key is `name` (`str`). + """ + l3_port_channels: L3PortChannels + """ + L3 Port-Channel interfaces to configure on the node. + + Subclass of AvdIndexedList with + `L3PortChannelsItem` items. Primary key is `name` (`str`). """ data_plane_cpu_allocation_max: int | None """ @@ -22549,6 +23151,7 @@ def __init__( wan_ha: WanHa | UndefinedType = Undefined, dps_mss_ipv4: str | UndefinedType = Undefined, l3_interfaces: L3Interfaces | UndefinedType = Undefined, + l3_port_channels: L3PortChannels | UndefinedType = Undefined, data_plane_cpu_allocation_max: int | None | UndefinedType = Undefined, flow_tracker_type: Literal["sampled", "hardware"] | None | UndefinedType = Undefined, _custom_data: dict[str, Any] | UndefinedType = Undefined, @@ -23105,11 +23708,14 @@ def __init__( dps_mss_ipv4: IPv4 MSS value configured under "router path-selection" on WAN Devices. l3_interfaces: L3 Interfaces to configure on the node. - Used to define the node for WAN interfaces when - `wan_carrier` is set. - Subclass of AvdIndexedList with `L3InterfacesItem` items. Primary key is - `name` (`str`). + Subclass of AvdIndexedList with `L3InterfacesItem` items. + Primary key is `name` (`str`). + l3_port_channels: + L3 Port-Channel interfaces to configure on the node. + + Subclass of AvdIndexedList with + `L3PortChannelsItem` items. Primary key is `name` (`str`). data_plane_cpu_allocation_max: Set the maximum number of CPU used for the data plane. This setting is useful on virtual Route @@ -25080,6 +25686,550 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): L3Interfaces._item_type = L3InterfacesItem + class L3PortChannelsItem(AvdModel): + """Subclass of AvdModel.""" + + class MemberInterfacesItem(AvdModel): + """Subclass of AvdModel.""" + + class StructuredConfig(EosCliConfigGen.EthernetInterfacesItem): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "name": {"type": str}, + "description": {"type": str}, + "peer": {"type": str}, + "peer_interface": {"type": str}, + "speed": {"type": str}, + "structured_config": {"type": StructuredConfig}, + "_custom_data": {"type": dict}, + } + name: str + """ + Ethernet interface name like 'Ethernet2'. + Member interface cannot be subinterface. + """ + description: str | None + """ + Interface description for this member. + If not set, a default description will be configured with + '[[ ]]'. + """ + peer: str | None + """ + The peer device name. Used for description and documentation. + If not set, this inherits the peer + setting on the port-channel interface. + """ + peer_interface: str | None + """The peer device interface. Used for description and documentation.""" + speed: str | None + """ + Speed should be set in the format `` or `forced ` or `auto + `. + """ + structured_config: StructuredConfig + """ + Custom structured config for the member ethernet interface. + + Subclass of AvdModel. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + name: str | UndefinedType = Undefined, + description: str | None | UndefinedType = Undefined, + peer: str | None | UndefinedType = Undefined, + peer_interface: str | None | UndefinedType = Undefined, + speed: str | None | UndefinedType = Undefined, + structured_config: StructuredConfig | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + MemberInterfacesItem. + + + Subclass of AvdModel. + + Args: + name: + Ethernet interface name like 'Ethernet2'. + Member interface cannot be subinterface. + description: + Interface description for this member. + If not set, a default description will be configured with + '[[ ]]'. + peer: + The peer device name. Used for description and documentation. + If not set, this inherits the peer + setting on the port-channel interface. + peer_interface: The peer device interface. Used for description and documentation. + speed: + Speed should be set in the format `` or `forced ` or `auto + `. + structured_config: + Custom structured config for the member ethernet interface. + + Subclass of AvdModel. + _custom_data: _custom_data + + """ + + class MemberInterfaces(AvdIndexedList[str, MemberInterfacesItem]): + """Subclass of AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`).""" + + _primary_key: ClassVar[str] = "name" + + MemberInterfaces._item_type = MemberInterfacesItem + + class Bgp(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "peer_as": {"type": str}, + "ipv4_prefix_list_in": {"type": str}, + "ipv4_prefix_list_out": {"type": str}, + "_custom_data": {"type": dict}, + } + peer_as: str + """ + BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>". + For asdot notation in + YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float + number. + """ + ipv4_prefix_list_in: str | None + """ + Prefix List Name. Accept routes for only these prefixes from the peer. + Required for wan interfaces. + """ + ipv4_prefix_list_out: str | None + """ + Prefix List Name. Advertise routes for only these prefixes. + If not specified, nothing would be + advertised. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + peer_as: str | UndefinedType = Undefined, + ipv4_prefix_list_in: str | None | UndefinedType = Undefined, + ipv4_prefix_list_out: str | None | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + Bgp. + + + Subclass of AvdModel. + + Args: + peer_as: + BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>". + For asdot notation in + YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float + number. + ipv4_prefix_list_in: + Prefix List Name. Accept routes for only these prefixes from the peer. + Required for wan interfaces. + ipv4_prefix_list_out: + Prefix List Name. Advertise routes for only these prefixes. + If not specified, nothing would be + advertised. + _custom_data: _custom_data + + """ + + class StaticRoutesItem(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = {"prefix": {"type": str}, "_custom_data": {"type": dict}} + prefix: str + """IPv4_network/Mask.""" + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, *, prefix: str | UndefinedType = Undefined, _custom_data: dict[str, Any] | UndefinedType = Undefined + ) -> None: + """ + StaticRoutesItem. + + + Subclass of AvdModel. + + Args: + prefix: IPv4_network/Mask. + _custom_data: _custom_data + + """ + + class StaticRoutes(AvdIndexedList[str, StaticRoutesItem]): + """Subclass of AvdIndexedList with `StaticRoutesItem` items. Primary key is `prefix` (`str`).""" + + _primary_key: ClassVar[str] = "prefix" + + StaticRoutes._item_type = StaticRoutesItem + + class FlowTracking(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = {"enabled": {"type": bool}, "name": {"type": str}, "_custom_data": {"type": dict}} + enabled: bool | None + name: str | None + """Flow tracker name as defined in flow_tracking_settings.""" + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + enabled: bool | None | UndefinedType = Undefined, + name: str | None | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + FlowTracking. + + + Subclass of AvdModel. + + Args: + enabled: enabled + name: Flow tracker name as defined in flow_tracking_settings. + _custom_data: _custom_data + + """ + + class StructuredConfig(EosCliConfigGen.PortChannelInterfacesItem): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "name": {"type": str}, + "description": {"type": str}, + "mode": {"type": str, "default": "active"}, + "member_interfaces": {"type": MemberInterfaces}, + "ip_address": {"type": str}, + "dhcp_ip": {"type": str}, + "public_ip": {"type": str}, + "encapsulation_dot1q_vlan": {"type": int}, + "dhcp_accept_default_route": {"type": bool, "default": True}, + "enabled": {"type": bool, "default": True}, + "peer": {"type": str}, + "peer_port_channel": {"type": str}, + "peer_ip": {"type": str}, + "bgp": {"type": Bgp}, + "ipv4_acl_in": {"type": str}, + "ipv4_acl_out": {"type": str}, + "static_routes": {"type": StaticRoutes}, + "qos_profile": {"type": str}, + "wan_carrier": {"type": str}, + "wan_circuit_id": {"type": str}, + "connected_to_pathfinder": {"type": bool, "default": True}, + "raw_eos_cli": {"type": str}, + "flow_tracking": {"type": FlowTracking}, + "structured_config": {"type": StructuredConfig}, + "_custom_data": {"type": dict}, + } + name: str + """ + Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'. + For a + Port-Channel subinterface, the parent Port-Channel interface must be defined as well. + """ + description: str | None + """ + Interface description. + If not set, a default description will be configured with '[[ + ]]'. + """ + mode: Literal["active", "passive", "on"] + """ + Port-Channel mode. + Should not be set on Port-Channel subinterfaces. + + Default value: `"active"` + """ + member_interfaces: MemberInterfaces + """ + Port-Channel member interfaces. + Should not be set on Port-Channel subinterfaces. + + Subclass of + AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`). + """ + ip_address: str | None + """Node IPv4 address/Mask or 'dhcp'.""" + dhcp_ip: str | None + """ + When the `ip_address` is `dhcp`, this optional field allows to indicate the expected + IPv4 address + (without mask) to be allocated on the interface if known. + This is not rendered in the configuration + but can be used for substitution of 'interface_ip' in the Access-list + set under `ipv4_acl_in` and + `ipv4_acl_out`. + """ + public_ip: str | None + """ + Node IPv4 address (no mask). + + This is used to get the public IP (if known) when the device is behind + NAT. + This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP + with the following preference: + `wan_route_servers.path_groups.interfaces.ip_address` + -> + `l3_port_channels.public_ip` + -> `l3_port_channels.ip_address` + + The determined Public IP is + used by WAN routers when peering with this interface. + """ + encapsulation_dot1q_vlan: int | None + """ + For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be + specified. + """ + dhcp_accept_default_route: bool + """ + Accept a default route from DHCP if `ip_address` is set to `dhcp`. + + Default value: `True` + """ + enabled: bool + """ + Enable or Shutdown the interface. + + Default value: `True` + """ + peer: str | None + """The peer device name. Used for description and documentation.""" + peer_port_channel: str | None + """The peer device port-channel interface. Used for description and documentation.""" + peer_ip: str | None + """ + The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true + and `ip` is an IP address. + """ + bgp: Bgp + """ + Enforce IPv4 BGP peering for the peer + + Subclass of AvdModel. + """ + ipv4_acl_in: str | None + """ + Name of the IPv4 access-list to be assigned in the ingress direction. + The access-list must be + defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + Required + for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under + `wan_carriers`. + """ + ipv4_acl_out: str | None + """ + Name of the IPv4 Access-list to be assigned in the egress direction. + The access-list must be defined + under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + """ + static_routes: StaticRoutes + """ + Configure IPv4 static routes pointing to `peer_ip`. + + Subclass of AvdIndexedList with + `StaticRoutesItem` items. Primary key is `prefix` (`str`). + """ + qos_profile: str | None + """QOS service profile.""" + wan_carrier: str | None + """ + The WAN carrier this interface is connected to. + This is used to infer the path-groups in which this + interface should be configured. + Unless the carrier is marked as 'trusted' under `wan_carriers`, + `ipv4_acl_in` is also required on all WAN interfaces. + """ + wan_circuit_id: str | None + """ + The WAN circuit ID for this interface. + This is not rendered in the configuration but used for WAN + designs. + """ + connected_to_pathfinder: bool + """ + For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. + + Default value: `True` + """ + raw_eos_cli: str | None + """EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration.""" + flow_tracking: FlowTracking + """ + Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` + setting. + + Subclass of AvdModel. + """ + structured_config: StructuredConfig + """ + Custom structured config for the Port-Channel interface. + + Subclass of AvdModel. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + name: str | UndefinedType = Undefined, + description: str | None | UndefinedType = Undefined, + mode: Literal["active", "passive", "on"] | UndefinedType = Undefined, + member_interfaces: MemberInterfaces | UndefinedType = Undefined, + ip_address: str | None | UndefinedType = Undefined, + dhcp_ip: str | None | UndefinedType = Undefined, + public_ip: str | None | UndefinedType = Undefined, + encapsulation_dot1q_vlan: int | None | UndefinedType = Undefined, + dhcp_accept_default_route: bool | UndefinedType = Undefined, + enabled: bool | UndefinedType = Undefined, + peer: str | None | UndefinedType = Undefined, + peer_port_channel: str | None | UndefinedType = Undefined, + peer_ip: str | None | UndefinedType = Undefined, + bgp: Bgp | UndefinedType = Undefined, + ipv4_acl_in: str | None | UndefinedType = Undefined, + ipv4_acl_out: str | None | UndefinedType = Undefined, + static_routes: StaticRoutes | UndefinedType = Undefined, + qos_profile: str | None | UndefinedType = Undefined, + wan_carrier: str | None | UndefinedType = Undefined, + wan_circuit_id: str | None | UndefinedType = Undefined, + connected_to_pathfinder: bool | UndefinedType = Undefined, + raw_eos_cli: str | None | UndefinedType = Undefined, + flow_tracking: FlowTracking | UndefinedType = Undefined, + structured_config: StructuredConfig | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + L3PortChannelsItem. + + + Subclass of AvdModel. + + Args: + name: + Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'. + For a + Port-Channel subinterface, the parent Port-Channel interface must be defined as well. + description: + Interface description. + If not set, a default description will be configured with '[[ + ]]'. + mode: + Port-Channel mode. + Should not be set on Port-Channel subinterfaces. + member_interfaces: + Port-Channel member interfaces. + Should not be set on Port-Channel subinterfaces. + + Subclass of + AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`). + ip_address: Node IPv4 address/Mask or 'dhcp'. + dhcp_ip: + When the `ip_address` is `dhcp`, this optional field allows to indicate the expected + IPv4 address + (without mask) to be allocated on the interface if known. + This is not rendered in the configuration + but can be used for substitution of 'interface_ip' in the Access-list + set under `ipv4_acl_in` and + `ipv4_acl_out`. + public_ip: + Node IPv4 address (no mask). + + This is used to get the public IP (if known) when the device is behind + NAT. + This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP + with the following preference: + `wan_route_servers.path_groups.interfaces.ip_address` + -> + `l3_port_channels.public_ip` + -> `l3_port_channels.ip_address` + + The determined Public IP is + used by WAN routers when peering with this interface. + encapsulation_dot1q_vlan: + For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be + specified. + dhcp_accept_default_route: Accept a default route from DHCP if `ip_address` is set to `dhcp`. + enabled: Enable or Shutdown the interface. + peer: The peer device name. Used for description and documentation. + peer_port_channel: The peer device port-channel interface. Used for description and documentation. + peer_ip: + The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true + and `ip` is an IP address. + bgp: + Enforce IPv4 BGP peering for the peer + + Subclass of AvdModel. + ipv4_acl_in: + Name of the IPv4 access-list to be assigned in the ingress direction. + The access-list must be + defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + Required + for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under + `wan_carriers`. + ipv4_acl_out: + Name of the IPv4 Access-list to be assigned in the egress direction. + The access-list must be defined + under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + static_routes: + Configure IPv4 static routes pointing to `peer_ip`. + + Subclass of AvdIndexedList with + `StaticRoutesItem` items. Primary key is `prefix` (`str`). + qos_profile: QOS service profile. + wan_carrier: + The WAN carrier this interface is connected to. + This is used to infer the path-groups in which this + interface should be configured. + Unless the carrier is marked as 'trusted' under `wan_carriers`, + `ipv4_acl_in` is also required on all WAN interfaces. + wan_circuit_id: + The WAN circuit ID for this interface. + This is not rendered in the configuration but used for WAN + designs. + connected_to_pathfinder: For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. + raw_eos_cli: EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration. + flow_tracking: + Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` + setting. + + Subclass of AvdModel. + structured_config: + Custom structured config for the Port-Channel interface. + + Subclass of AvdModel. + _custom_data: _custom_data + + """ + + class L3PortChannels(AvdIndexedList[str, L3PortChannelsItem]): + """Subclass of AvdIndexedList with `L3PortChannelsItem` items. Primary key is `name` (`str`).""" + + _primary_key: ClassVar[str] = "name" + + L3PortChannels._item_type = L3PortChannelsItem + _fields: ClassVar[dict] = { "name": {"type": str}, "downlink_pools": {"type": DownlinkPools}, @@ -25186,6 +26336,7 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): "wan_ha": {"type": WanHa}, "dps_mss_ipv4": {"type": str, "default": "auto"}, "l3_interfaces": {"type": L3Interfaces}, + "l3_port_channels": {"type": L3PortChannels}, "data_plane_cpu_allocation_max": {"type": int}, "flow_tracker_type": {"type": str}, "_custom_data": {"type": dict}, @@ -25977,11 +27128,16 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): l3_interfaces: L3Interfaces """ L3 Interfaces to configure on the node. - Used to define the node for WAN interfaces when - `wan_carrier` is set. - Subclass of AvdIndexedList with `L3InterfacesItem` items. Primary key is - `name` (`str`). + Subclass of AvdIndexedList with `L3InterfacesItem` items. + Primary key is `name` (`str`). + """ + l3_port_channels: L3PortChannels + """ + L3 Port-Channel interfaces to configure on the node. + + Subclass of AvdIndexedList with + `L3PortChannelsItem` items. Primary key is `name` (`str`). """ data_plane_cpu_allocation_max: int | None """ @@ -26108,6 +27264,7 @@ def __init__( wan_ha: WanHa | UndefinedType = Undefined, dps_mss_ipv4: str | UndefinedType = Undefined, l3_interfaces: L3Interfaces | UndefinedType = Undefined, + l3_port_channels: L3PortChannels | UndefinedType = Undefined, data_plane_cpu_allocation_max: int | None | UndefinedType = Undefined, flow_tracker_type: Literal["sampled", "hardware"] | None | UndefinedType = Undefined, _custom_data: dict[str, Any] | UndefinedType = Undefined, @@ -26671,11 +27828,14 @@ def __init__( dps_mss_ipv4: IPv4 MSS value configured under "router path-selection" on WAN Devices. l3_interfaces: L3 Interfaces to configure on the node. - Used to define the node for WAN interfaces when - `wan_carrier` is set. - Subclass of AvdIndexedList with `L3InterfacesItem` items. Primary key is - `name` (`str`). + Subclass of AvdIndexedList with `L3InterfacesItem` items. + Primary key is `name` (`str`). + l3_port_channels: + L3 Port-Channel interfaces to configure on the node. + + Subclass of AvdIndexedList with + `L3PortChannelsItem` items. Primary key is `name` (`str`). data_plane_cpu_allocation_max: Set the maximum number of CPU used for the data plane. This setting is useful on virtual Route @@ -28579,6 +29739,550 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): L3Interfaces._item_type = L3InterfacesItem + class L3PortChannelsItem(AvdModel): + """Subclass of AvdModel.""" + + class MemberInterfacesItem(AvdModel): + """Subclass of AvdModel.""" + + class StructuredConfig(EosCliConfigGen.EthernetInterfacesItem): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "name": {"type": str}, + "description": {"type": str}, + "peer": {"type": str}, + "peer_interface": {"type": str}, + "speed": {"type": str}, + "structured_config": {"type": StructuredConfig}, + "_custom_data": {"type": dict}, + } + name: str + """ + Ethernet interface name like 'Ethernet2'. + Member interface cannot be subinterface. + """ + description: str | None + """ + Interface description for this member. + If not set, a default description will be configured with + '[[ ]]'. + """ + peer: str | None + """ + The peer device name. Used for description and documentation. + If not set, this inherits the peer + setting on the port-channel interface. + """ + peer_interface: str | None + """The peer device interface. Used for description and documentation.""" + speed: str | None + """ + Speed should be set in the format `` or `forced ` or `auto + `. + """ + structured_config: StructuredConfig + """ + Custom structured config for the member ethernet interface. + + Subclass of AvdModel. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + name: str | UndefinedType = Undefined, + description: str | None | UndefinedType = Undefined, + peer: str | None | UndefinedType = Undefined, + peer_interface: str | None | UndefinedType = Undefined, + speed: str | None | UndefinedType = Undefined, + structured_config: StructuredConfig | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + MemberInterfacesItem. + + + Subclass of AvdModel. + + Args: + name: + Ethernet interface name like 'Ethernet2'. + Member interface cannot be subinterface. + description: + Interface description for this member. + If not set, a default description will be configured with + '[[ ]]'. + peer: + The peer device name. Used for description and documentation. + If not set, this inherits the peer + setting on the port-channel interface. + peer_interface: The peer device interface. Used for description and documentation. + speed: + Speed should be set in the format `` or `forced ` or `auto + `. + structured_config: + Custom structured config for the member ethernet interface. + + Subclass of AvdModel. + _custom_data: _custom_data + + """ + + class MemberInterfaces(AvdIndexedList[str, MemberInterfacesItem]): + """Subclass of AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`).""" + + _primary_key: ClassVar[str] = "name" + + MemberInterfaces._item_type = MemberInterfacesItem + + class Bgp(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "peer_as": {"type": str}, + "ipv4_prefix_list_in": {"type": str}, + "ipv4_prefix_list_out": {"type": str}, + "_custom_data": {"type": dict}, + } + peer_as: str + """ + BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>". + For asdot notation in + YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float + number. + """ + ipv4_prefix_list_in: str | None + """ + Prefix List Name. Accept routes for only these prefixes from the peer. + Required for wan interfaces. + """ + ipv4_prefix_list_out: str | None + """ + Prefix List Name. Advertise routes for only these prefixes. + If not specified, nothing would be + advertised. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + peer_as: str | UndefinedType = Undefined, + ipv4_prefix_list_in: str | None | UndefinedType = Undefined, + ipv4_prefix_list_out: str | None | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + Bgp. + + + Subclass of AvdModel. + + Args: + peer_as: + BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>". + For asdot notation in + YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float + number. + ipv4_prefix_list_in: + Prefix List Name. Accept routes for only these prefixes from the peer. + Required for wan interfaces. + ipv4_prefix_list_out: + Prefix List Name. Advertise routes for only these prefixes. + If not specified, nothing would be + advertised. + _custom_data: _custom_data + + """ + + class StaticRoutesItem(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = {"prefix": {"type": str}, "_custom_data": {"type": dict}} + prefix: str + """IPv4_network/Mask.""" + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, *, prefix: str | UndefinedType = Undefined, _custom_data: dict[str, Any] | UndefinedType = Undefined + ) -> None: + """ + StaticRoutesItem. + + + Subclass of AvdModel. + + Args: + prefix: IPv4_network/Mask. + _custom_data: _custom_data + + """ + + class StaticRoutes(AvdIndexedList[str, StaticRoutesItem]): + """Subclass of AvdIndexedList with `StaticRoutesItem` items. Primary key is `prefix` (`str`).""" + + _primary_key: ClassVar[str] = "prefix" + + StaticRoutes._item_type = StaticRoutesItem + + class FlowTracking(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = {"enabled": {"type": bool}, "name": {"type": str}, "_custom_data": {"type": dict}} + enabled: bool | None + name: str | None + """Flow tracker name as defined in flow_tracking_settings.""" + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + enabled: bool | None | UndefinedType = Undefined, + name: str | None | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + FlowTracking. + + + Subclass of AvdModel. + + Args: + enabled: enabled + name: Flow tracker name as defined in flow_tracking_settings. + _custom_data: _custom_data + + """ + + class StructuredConfig(EosCliConfigGen.PortChannelInterfacesItem): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "name": {"type": str}, + "description": {"type": str}, + "mode": {"type": str, "default": "active"}, + "member_interfaces": {"type": MemberInterfaces}, + "ip_address": {"type": str}, + "dhcp_ip": {"type": str}, + "public_ip": {"type": str}, + "encapsulation_dot1q_vlan": {"type": int}, + "dhcp_accept_default_route": {"type": bool, "default": True}, + "enabled": {"type": bool, "default": True}, + "peer": {"type": str}, + "peer_port_channel": {"type": str}, + "peer_ip": {"type": str}, + "bgp": {"type": Bgp}, + "ipv4_acl_in": {"type": str}, + "ipv4_acl_out": {"type": str}, + "static_routes": {"type": StaticRoutes}, + "qos_profile": {"type": str}, + "wan_carrier": {"type": str}, + "wan_circuit_id": {"type": str}, + "connected_to_pathfinder": {"type": bool, "default": True}, + "raw_eos_cli": {"type": str}, + "flow_tracking": {"type": FlowTracking}, + "structured_config": {"type": StructuredConfig}, + "_custom_data": {"type": dict}, + } + name: str + """ + Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'. + For a + Port-Channel subinterface, the parent Port-Channel interface must be defined as well. + """ + description: str | None + """ + Interface description. + If not set, a default description will be configured with '[[ + ]]'. + """ + mode: Literal["active", "passive", "on"] + """ + Port-Channel mode. + Should not be set on Port-Channel subinterfaces. + + Default value: `"active"` + """ + member_interfaces: MemberInterfaces + """ + Port-Channel member interfaces. + Should not be set on Port-Channel subinterfaces. + + Subclass of + AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`). + """ + ip_address: str | None + """Node IPv4 address/Mask or 'dhcp'.""" + dhcp_ip: str | None + """ + When the `ip_address` is `dhcp`, this optional field allows to indicate the expected + IPv4 address + (without mask) to be allocated on the interface if known. + This is not rendered in the configuration + but can be used for substitution of 'interface_ip' in the Access-list + set under `ipv4_acl_in` and + `ipv4_acl_out`. + """ + public_ip: str | None + """ + Node IPv4 address (no mask). + + This is used to get the public IP (if known) when the device is behind + NAT. + This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP + with the following preference: + `wan_route_servers.path_groups.interfaces.ip_address` + -> + `l3_port_channels.public_ip` + -> `l3_port_channels.ip_address` + + The determined Public IP is + used by WAN routers when peering with this interface. + """ + encapsulation_dot1q_vlan: int | None + """ + For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be + specified. + """ + dhcp_accept_default_route: bool + """ + Accept a default route from DHCP if `ip_address` is set to `dhcp`. + + Default value: `True` + """ + enabled: bool + """ + Enable or Shutdown the interface. + + Default value: `True` + """ + peer: str | None + """The peer device name. Used for description and documentation.""" + peer_port_channel: str | None + """The peer device port-channel interface. Used for description and documentation.""" + peer_ip: str | None + """ + The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true + and `ip` is an IP address. + """ + bgp: Bgp + """ + Enforce IPv4 BGP peering for the peer + + Subclass of AvdModel. + """ + ipv4_acl_in: str | None + """ + Name of the IPv4 access-list to be assigned in the ingress direction. + The access-list must be + defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + Required + for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under + `wan_carriers`. + """ + ipv4_acl_out: str | None + """ + Name of the IPv4 Access-list to be assigned in the egress direction. + The access-list must be defined + under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + """ + static_routes: StaticRoutes + """ + Configure IPv4 static routes pointing to `peer_ip`. + + Subclass of AvdIndexedList with + `StaticRoutesItem` items. Primary key is `prefix` (`str`). + """ + qos_profile: str | None + """QOS service profile.""" + wan_carrier: str | None + """ + The WAN carrier this interface is connected to. + This is used to infer the path-groups in which this + interface should be configured. + Unless the carrier is marked as 'trusted' under `wan_carriers`, + `ipv4_acl_in` is also required on all WAN interfaces. + """ + wan_circuit_id: str | None + """ + The WAN circuit ID for this interface. + This is not rendered in the configuration but used for WAN + designs. + """ + connected_to_pathfinder: bool + """ + For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. + + Default value: `True` + """ + raw_eos_cli: str | None + """EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration.""" + flow_tracking: FlowTracking + """ + Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` + setting. + + Subclass of AvdModel. + """ + structured_config: StructuredConfig + """ + Custom structured config for the Port-Channel interface. + + Subclass of AvdModel. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + name: str | UndefinedType = Undefined, + description: str | None | UndefinedType = Undefined, + mode: Literal["active", "passive", "on"] | UndefinedType = Undefined, + member_interfaces: MemberInterfaces | UndefinedType = Undefined, + ip_address: str | None | UndefinedType = Undefined, + dhcp_ip: str | None | UndefinedType = Undefined, + public_ip: str | None | UndefinedType = Undefined, + encapsulation_dot1q_vlan: int | None | UndefinedType = Undefined, + dhcp_accept_default_route: bool | UndefinedType = Undefined, + enabled: bool | UndefinedType = Undefined, + peer: str | None | UndefinedType = Undefined, + peer_port_channel: str | None | UndefinedType = Undefined, + peer_ip: str | None | UndefinedType = Undefined, + bgp: Bgp | UndefinedType = Undefined, + ipv4_acl_in: str | None | UndefinedType = Undefined, + ipv4_acl_out: str | None | UndefinedType = Undefined, + static_routes: StaticRoutes | UndefinedType = Undefined, + qos_profile: str | None | UndefinedType = Undefined, + wan_carrier: str | None | UndefinedType = Undefined, + wan_circuit_id: str | None | UndefinedType = Undefined, + connected_to_pathfinder: bool | UndefinedType = Undefined, + raw_eos_cli: str | None | UndefinedType = Undefined, + flow_tracking: FlowTracking | UndefinedType = Undefined, + structured_config: StructuredConfig | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + L3PortChannelsItem. + + + Subclass of AvdModel. + + Args: + name: + Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'. + For a + Port-Channel subinterface, the parent Port-Channel interface must be defined as well. + description: + Interface description. + If not set, a default description will be configured with '[[ + ]]'. + mode: + Port-Channel mode. + Should not be set on Port-Channel subinterfaces. + member_interfaces: + Port-Channel member interfaces. + Should not be set on Port-Channel subinterfaces. + + Subclass of + AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`). + ip_address: Node IPv4 address/Mask or 'dhcp'. + dhcp_ip: + When the `ip_address` is `dhcp`, this optional field allows to indicate the expected + IPv4 address + (without mask) to be allocated on the interface if known. + This is not rendered in the configuration + but can be used for substitution of 'interface_ip' in the Access-list + set under `ipv4_acl_in` and + `ipv4_acl_out`. + public_ip: + Node IPv4 address (no mask). + + This is used to get the public IP (if known) when the device is behind + NAT. + This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP + with the following preference: + `wan_route_servers.path_groups.interfaces.ip_address` + -> + `l3_port_channels.public_ip` + -> `l3_port_channels.ip_address` + + The determined Public IP is + used by WAN routers when peering with this interface. + encapsulation_dot1q_vlan: + For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be + specified. + dhcp_accept_default_route: Accept a default route from DHCP if `ip_address` is set to `dhcp`. + enabled: Enable or Shutdown the interface. + peer: The peer device name. Used for description and documentation. + peer_port_channel: The peer device port-channel interface. Used for description and documentation. + peer_ip: + The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true + and `ip` is an IP address. + bgp: + Enforce IPv4 BGP peering for the peer + + Subclass of AvdModel. + ipv4_acl_in: + Name of the IPv4 access-list to be assigned in the ingress direction. + The access-list must be + defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + Required + for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under + `wan_carriers`. + ipv4_acl_out: + Name of the IPv4 Access-list to be assigned in the egress direction. + The access-list must be defined + under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + static_routes: + Configure IPv4 static routes pointing to `peer_ip`. + + Subclass of AvdIndexedList with + `StaticRoutesItem` items. Primary key is `prefix` (`str`). + qos_profile: QOS service profile. + wan_carrier: + The WAN carrier this interface is connected to. + This is used to infer the path-groups in which this + interface should be configured. + Unless the carrier is marked as 'trusted' under `wan_carriers`, + `ipv4_acl_in` is also required on all WAN interfaces. + wan_circuit_id: + The WAN circuit ID for this interface. + This is not rendered in the configuration but used for WAN + designs. + connected_to_pathfinder: For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. + raw_eos_cli: EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration. + flow_tracking: + Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` + setting. + + Subclass of AvdModel. + structured_config: + Custom structured config for the Port-Channel interface. + + Subclass of AvdModel. + _custom_data: _custom_data + + """ + + class L3PortChannels(AvdIndexedList[str, L3PortChannelsItem]): + """Subclass of AvdIndexedList with `L3PortChannelsItem` items. Primary key is `name` (`str`).""" + + _primary_key: ClassVar[str] = "name" + + L3PortChannels._item_type = L3PortChannelsItem + _fields: ClassVar[dict] = { "group": {"type": str}, "nodes": {"type": Nodes}, @@ -28685,6 +30389,7 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): "wan_ha": {"type": WanHa}, "dps_mss_ipv4": {"type": str, "default": "auto"}, "l3_interfaces": {"type": L3Interfaces}, + "l3_port_channels": {"type": L3PortChannels}, "data_plane_cpu_allocation_max": {"type": int}, "flow_tracker_type": {"type": str}, "_custom_data": {"type": dict}, @@ -29479,11 +31184,16 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): l3_interfaces: L3Interfaces """ L3 Interfaces to configure on the node. - Used to define the node for WAN interfaces when - `wan_carrier` is set. - Subclass of AvdIndexedList with `L3InterfacesItem` items. Primary key is - `name` (`str`). + Subclass of AvdIndexedList with `L3InterfacesItem` items. + Primary key is `name` (`str`). + """ + l3_port_channels: L3PortChannels + """ + L3 Port-Channel interfaces to configure on the node. + + Subclass of AvdIndexedList with + `L3PortChannelsItem` items. Primary key is `name` (`str`). """ data_plane_cpu_allocation_max: int | None """ @@ -29610,6 +31320,7 @@ def __init__( wan_ha: WanHa | UndefinedType = Undefined, dps_mss_ipv4: str | UndefinedType = Undefined, l3_interfaces: L3Interfaces | UndefinedType = Undefined, + l3_port_channels: L3PortChannels | UndefinedType = Undefined, data_plane_cpu_allocation_max: int | None | UndefinedType = Undefined, flow_tracker_type: Literal["sampled", "hardware"] | None | UndefinedType = Undefined, _custom_data: dict[str, Any] | UndefinedType = Undefined, @@ -30175,11 +31886,14 @@ def __init__( dps_mss_ipv4: IPv4 MSS value configured under "router path-selection" on WAN Devices. l3_interfaces: L3 Interfaces to configure on the node. - Used to define the node for WAN interfaces when - `wan_carrier` is set. - Subclass of AvdIndexedList with `L3InterfacesItem` items. Primary key is - `name` (`str`). + Subclass of AvdIndexedList with `L3InterfacesItem` items. + Primary key is `name` (`str`). + l3_port_channels: + L3 Port-Channel interfaces to configure on the node. + + Subclass of AvdIndexedList with + `L3PortChannelsItem` items. Primary key is `name` (`str`). data_plane_cpu_allocation_max: Set the maximum number of CPU used for the data plane. This setting is useful on virtual Route @@ -32152,6 +33866,550 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): L3Interfaces._item_type = L3InterfacesItem + class L3PortChannelsItem(AvdModel): + """Subclass of AvdModel.""" + + class MemberInterfacesItem(AvdModel): + """Subclass of AvdModel.""" + + class StructuredConfig(EosCliConfigGen.EthernetInterfacesItem): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "name": {"type": str}, + "description": {"type": str}, + "peer": {"type": str}, + "peer_interface": {"type": str}, + "speed": {"type": str}, + "structured_config": {"type": StructuredConfig}, + "_custom_data": {"type": dict}, + } + name: str + """ + Ethernet interface name like 'Ethernet2'. + Member interface cannot be subinterface. + """ + description: str | None + """ + Interface description for this member. + If not set, a default description will be configured with + '[[ ]]'. + """ + peer: str | None + """ + The peer device name. Used for description and documentation. + If not set, this inherits the peer + setting on the port-channel interface. + """ + peer_interface: str | None + """The peer device interface. Used for description and documentation.""" + speed: str | None + """ + Speed should be set in the format `` or `forced ` or `auto + `. + """ + structured_config: StructuredConfig + """ + Custom structured config for the member ethernet interface. + + Subclass of AvdModel. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + name: str | UndefinedType = Undefined, + description: str | None | UndefinedType = Undefined, + peer: str | None | UndefinedType = Undefined, + peer_interface: str | None | UndefinedType = Undefined, + speed: str | None | UndefinedType = Undefined, + structured_config: StructuredConfig | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + MemberInterfacesItem. + + + Subclass of AvdModel. + + Args: + name: + Ethernet interface name like 'Ethernet2'. + Member interface cannot be subinterface. + description: + Interface description for this member. + If not set, a default description will be configured with + '[[ ]]'. + peer: + The peer device name. Used for description and documentation. + If not set, this inherits the peer + setting on the port-channel interface. + peer_interface: The peer device interface. Used for description and documentation. + speed: + Speed should be set in the format `` or `forced ` or `auto + `. + structured_config: + Custom structured config for the member ethernet interface. + + Subclass of AvdModel. + _custom_data: _custom_data + + """ + + class MemberInterfaces(AvdIndexedList[str, MemberInterfacesItem]): + """Subclass of AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`).""" + + _primary_key: ClassVar[str] = "name" + + MemberInterfaces._item_type = MemberInterfacesItem + + class Bgp(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "peer_as": {"type": str}, + "ipv4_prefix_list_in": {"type": str}, + "ipv4_prefix_list_out": {"type": str}, + "_custom_data": {"type": dict}, + } + peer_as: str + """ + BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>". + For asdot notation in + YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float + number. + """ + ipv4_prefix_list_in: str | None + """ + Prefix List Name. Accept routes for only these prefixes from the peer. + Required for wan interfaces. + """ + ipv4_prefix_list_out: str | None + """ + Prefix List Name. Advertise routes for only these prefixes. + If not specified, nothing would be + advertised. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + peer_as: str | UndefinedType = Undefined, + ipv4_prefix_list_in: str | None | UndefinedType = Undefined, + ipv4_prefix_list_out: str | None | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + Bgp. + + + Subclass of AvdModel. + + Args: + peer_as: + BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>". + For asdot notation in + YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float + number. + ipv4_prefix_list_in: + Prefix List Name. Accept routes for only these prefixes from the peer. + Required for wan interfaces. + ipv4_prefix_list_out: + Prefix List Name. Advertise routes for only these prefixes. + If not specified, nothing would be + advertised. + _custom_data: _custom_data + + """ + + class StaticRoutesItem(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = {"prefix": {"type": str}, "_custom_data": {"type": dict}} + prefix: str + """IPv4_network/Mask.""" + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, *, prefix: str | UndefinedType = Undefined, _custom_data: dict[str, Any] | UndefinedType = Undefined + ) -> None: + """ + StaticRoutesItem. + + + Subclass of AvdModel. + + Args: + prefix: IPv4_network/Mask. + _custom_data: _custom_data + + """ + + class StaticRoutes(AvdIndexedList[str, StaticRoutesItem]): + """Subclass of AvdIndexedList with `StaticRoutesItem` items. Primary key is `prefix` (`str`).""" + + _primary_key: ClassVar[str] = "prefix" + + StaticRoutes._item_type = StaticRoutesItem + + class FlowTracking(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = {"enabled": {"type": bool}, "name": {"type": str}, "_custom_data": {"type": dict}} + enabled: bool | None + name: str | None + """Flow tracker name as defined in flow_tracking_settings.""" + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + enabled: bool | None | UndefinedType = Undefined, + name: str | None | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + FlowTracking. + + + Subclass of AvdModel. + + Args: + enabled: enabled + name: Flow tracker name as defined in flow_tracking_settings. + _custom_data: _custom_data + + """ + + class StructuredConfig(EosCliConfigGen.PortChannelInterfacesItem): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "name": {"type": str}, + "description": {"type": str}, + "mode": {"type": str, "default": "active"}, + "member_interfaces": {"type": MemberInterfaces}, + "ip_address": {"type": str}, + "dhcp_ip": {"type": str}, + "public_ip": {"type": str}, + "encapsulation_dot1q_vlan": {"type": int}, + "dhcp_accept_default_route": {"type": bool, "default": True}, + "enabled": {"type": bool, "default": True}, + "peer": {"type": str}, + "peer_port_channel": {"type": str}, + "peer_ip": {"type": str}, + "bgp": {"type": Bgp}, + "ipv4_acl_in": {"type": str}, + "ipv4_acl_out": {"type": str}, + "static_routes": {"type": StaticRoutes}, + "qos_profile": {"type": str}, + "wan_carrier": {"type": str}, + "wan_circuit_id": {"type": str}, + "connected_to_pathfinder": {"type": bool, "default": True}, + "raw_eos_cli": {"type": str}, + "flow_tracking": {"type": FlowTracking}, + "structured_config": {"type": StructuredConfig}, + "_custom_data": {"type": dict}, + } + name: str + """ + Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'. + For a + Port-Channel subinterface, the parent Port-Channel interface must be defined as well. + """ + description: str | None + """ + Interface description. + If not set, a default description will be configured with '[[ + ]]'. + """ + mode: Literal["active", "passive", "on"] + """ + Port-Channel mode. + Should not be set on Port-Channel subinterfaces. + + Default value: `"active"` + """ + member_interfaces: MemberInterfaces + """ + Port-Channel member interfaces. + Should not be set on Port-Channel subinterfaces. + + Subclass of + AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`). + """ + ip_address: str | None + """Node IPv4 address/Mask or 'dhcp'.""" + dhcp_ip: str | None + """ + When the `ip_address` is `dhcp`, this optional field allows to indicate the expected + IPv4 address + (without mask) to be allocated on the interface if known. + This is not rendered in the configuration + but can be used for substitution of 'interface_ip' in the Access-list + set under `ipv4_acl_in` and + `ipv4_acl_out`. + """ + public_ip: str | None + """ + Node IPv4 address (no mask). + + This is used to get the public IP (if known) when the device is behind + NAT. + This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP + with the following preference: + `wan_route_servers.path_groups.interfaces.ip_address` + -> + `l3_port_channels.public_ip` + -> `l3_port_channels.ip_address` + + The determined Public IP is + used by WAN routers when peering with this interface. + """ + encapsulation_dot1q_vlan: int | None + """ + For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be + specified. + """ + dhcp_accept_default_route: bool + """ + Accept a default route from DHCP if `ip_address` is set to `dhcp`. + + Default value: `True` + """ + enabled: bool + """ + Enable or Shutdown the interface. + + Default value: `True` + """ + peer: str | None + """The peer device name. Used for description and documentation.""" + peer_port_channel: str | None + """The peer device port-channel interface. Used for description and documentation.""" + peer_ip: str | None + """ + The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true + and `ip` is an IP address. + """ + bgp: Bgp + """ + Enforce IPv4 BGP peering for the peer + + Subclass of AvdModel. + """ + ipv4_acl_in: str | None + """ + Name of the IPv4 access-list to be assigned in the ingress direction. + The access-list must be + defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + Required + for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under + `wan_carriers`. + """ + ipv4_acl_out: str | None + """ + Name of the IPv4 Access-list to be assigned in the egress direction. + The access-list must be defined + under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + """ + static_routes: StaticRoutes + """ + Configure IPv4 static routes pointing to `peer_ip`. + + Subclass of AvdIndexedList with + `StaticRoutesItem` items. Primary key is `prefix` (`str`). + """ + qos_profile: str | None + """QOS service profile.""" + wan_carrier: str | None + """ + The WAN carrier this interface is connected to. + This is used to infer the path-groups in which this + interface should be configured. + Unless the carrier is marked as 'trusted' under `wan_carriers`, + `ipv4_acl_in` is also required on all WAN interfaces. + """ + wan_circuit_id: str | None + """ + The WAN circuit ID for this interface. + This is not rendered in the configuration but used for WAN + designs. + """ + connected_to_pathfinder: bool + """ + For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. + + Default value: `True` + """ + raw_eos_cli: str | None + """EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration.""" + flow_tracking: FlowTracking + """ + Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` + setting. + + Subclass of AvdModel. + """ + structured_config: StructuredConfig + """ + Custom structured config for the Port-Channel interface. + + Subclass of AvdModel. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + name: str | UndefinedType = Undefined, + description: str | None | UndefinedType = Undefined, + mode: Literal["active", "passive", "on"] | UndefinedType = Undefined, + member_interfaces: MemberInterfaces | UndefinedType = Undefined, + ip_address: str | None | UndefinedType = Undefined, + dhcp_ip: str | None | UndefinedType = Undefined, + public_ip: str | None | UndefinedType = Undefined, + encapsulation_dot1q_vlan: int | None | UndefinedType = Undefined, + dhcp_accept_default_route: bool | UndefinedType = Undefined, + enabled: bool | UndefinedType = Undefined, + peer: str | None | UndefinedType = Undefined, + peer_port_channel: str | None | UndefinedType = Undefined, + peer_ip: str | None | UndefinedType = Undefined, + bgp: Bgp | UndefinedType = Undefined, + ipv4_acl_in: str | None | UndefinedType = Undefined, + ipv4_acl_out: str | None | UndefinedType = Undefined, + static_routes: StaticRoutes | UndefinedType = Undefined, + qos_profile: str | None | UndefinedType = Undefined, + wan_carrier: str | None | UndefinedType = Undefined, + wan_circuit_id: str | None | UndefinedType = Undefined, + connected_to_pathfinder: bool | UndefinedType = Undefined, + raw_eos_cli: str | None | UndefinedType = Undefined, + flow_tracking: FlowTracking | UndefinedType = Undefined, + structured_config: StructuredConfig | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + L3PortChannelsItem. + + + Subclass of AvdModel. + + Args: + name: + Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'. + For a + Port-Channel subinterface, the parent Port-Channel interface must be defined as well. + description: + Interface description. + If not set, a default description will be configured with '[[ + ]]'. + mode: + Port-Channel mode. + Should not be set on Port-Channel subinterfaces. + member_interfaces: + Port-Channel member interfaces. + Should not be set on Port-Channel subinterfaces. + + Subclass of + AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`). + ip_address: Node IPv4 address/Mask or 'dhcp'. + dhcp_ip: + When the `ip_address` is `dhcp`, this optional field allows to indicate the expected + IPv4 address + (without mask) to be allocated on the interface if known. + This is not rendered in the configuration + but can be used for substitution of 'interface_ip' in the Access-list + set under `ipv4_acl_in` and + `ipv4_acl_out`. + public_ip: + Node IPv4 address (no mask). + + This is used to get the public IP (if known) when the device is behind + NAT. + This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP + with the following preference: + `wan_route_servers.path_groups.interfaces.ip_address` + -> + `l3_port_channels.public_ip` + -> `l3_port_channels.ip_address` + + The determined Public IP is + used by WAN routers when peering with this interface. + encapsulation_dot1q_vlan: + For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be + specified. + dhcp_accept_default_route: Accept a default route from DHCP if `ip_address` is set to `dhcp`. + enabled: Enable or Shutdown the interface. + peer: The peer device name. Used for description and documentation. + peer_port_channel: The peer device port-channel interface. Used for description and documentation. + peer_ip: + The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true + and `ip` is an IP address. + bgp: + Enforce IPv4 BGP peering for the peer + + Subclass of AvdModel. + ipv4_acl_in: + Name of the IPv4 access-list to be assigned in the ingress direction. + The access-list must be + defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + Required + for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under + `wan_carriers`. + ipv4_acl_out: + Name of the IPv4 Access-list to be assigned in the egress direction. + The access-list must be defined + under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + static_routes: + Configure IPv4 static routes pointing to `peer_ip`. + + Subclass of AvdIndexedList with + `StaticRoutesItem` items. Primary key is `prefix` (`str`). + qos_profile: QOS service profile. + wan_carrier: + The WAN carrier this interface is connected to. + This is used to infer the path-groups in which this + interface should be configured. + Unless the carrier is marked as 'trusted' under `wan_carriers`, + `ipv4_acl_in` is also required on all WAN interfaces. + wan_circuit_id: + The WAN circuit ID for this interface. + This is not rendered in the configuration but used for WAN + designs. + connected_to_pathfinder: For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. + raw_eos_cli: EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration. + flow_tracking: + Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` + setting. + + Subclass of AvdModel. + structured_config: + Custom structured config for the Port-Channel interface. + + Subclass of AvdModel. + _custom_data: _custom_data + + """ + + class L3PortChannels(AvdIndexedList[str, L3PortChannelsItem]): + """Subclass of AvdIndexedList with `L3PortChannelsItem` items. Primary key is `name` (`str`).""" + + _primary_key: ClassVar[str] = "name" + + L3PortChannels._item_type = L3PortChannelsItem + _fields: ClassVar[dict] = { "name": {"type": str}, "downlink_pools": {"type": DownlinkPools}, @@ -32258,6 +34516,7 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): "wan_ha": {"type": WanHa}, "dps_mss_ipv4": {"type": str, "default": "auto"}, "l3_interfaces": {"type": L3Interfaces}, + "l3_port_channels": {"type": L3PortChannels}, "data_plane_cpu_allocation_max": {"type": int}, "flow_tracker_type": {"type": str}, "_custom_data": {"type": dict}, @@ -33049,11 +35308,16 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): l3_interfaces: L3Interfaces """ L3 Interfaces to configure on the node. - Used to define the node for WAN interfaces when - `wan_carrier` is set. - Subclass of AvdIndexedList with `L3InterfacesItem` items. Primary key is - `name` (`str`). + Subclass of AvdIndexedList with `L3InterfacesItem` items. + Primary key is `name` (`str`). + """ + l3_port_channels: L3PortChannels + """ + L3 Port-Channel interfaces to configure on the node. + + Subclass of AvdIndexedList with + `L3PortChannelsItem` items. Primary key is `name` (`str`). """ data_plane_cpu_allocation_max: int | None """ @@ -33180,6 +35444,7 @@ def __init__( wan_ha: WanHa | UndefinedType = Undefined, dps_mss_ipv4: str | UndefinedType = Undefined, l3_interfaces: L3Interfaces | UndefinedType = Undefined, + l3_port_channels: L3PortChannels | UndefinedType = Undefined, data_plane_cpu_allocation_max: int | None | UndefinedType = Undefined, flow_tracker_type: Literal["sampled", "hardware"] | None | UndefinedType = Undefined, _custom_data: dict[str, Any] | UndefinedType = Undefined, @@ -33743,11 +36008,14 @@ def __init__( dps_mss_ipv4: IPv4 MSS value configured under "router path-selection" on WAN Devices. l3_interfaces: L3 Interfaces to configure on the node. - Used to define the node for WAN interfaces when - `wan_carrier` is set. - Subclass of AvdIndexedList with `L3InterfacesItem` items. Primary key is - `name` (`str`). + Subclass of AvdIndexedList with `L3InterfacesItem` items. + Primary key is `name` (`str`). + l3_port_channels: + L3 Port-Channel interfaces to configure on the node. + + Subclass of AvdIndexedList with + `L3PortChannelsItem` items. Primary key is `name` (`str`). data_plane_cpu_allocation_max: Set the maximum number of CPU used for the data plane. This setting is useful on virtual Route @@ -42580,6 +44848,550 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): L3Interfaces._item_type = L3InterfacesItem + class L3PortChannelsItem(AvdModel): + """Subclass of AvdModel.""" + + class MemberInterfacesItem(AvdModel): + """Subclass of AvdModel.""" + + class StructuredConfig(EosCliConfigGen.EthernetInterfacesItem): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "name": {"type": str}, + "description": {"type": str}, + "peer": {"type": str}, + "peer_interface": {"type": str}, + "speed": {"type": str}, + "structured_config": {"type": StructuredConfig}, + "_custom_data": {"type": dict}, + } + name: str + """ + Ethernet interface name like 'Ethernet2'. + Member interface cannot be subinterface. + """ + description: str | None + """ + Interface description for this member. + If not set, a default description will be configured with + '[[ ]]'. + """ + peer: str | None + """ + The peer device name. Used for description and documentation. + If not set, this inherits the peer + setting on the port-channel interface. + """ + peer_interface: str | None + """The peer device interface. Used for description and documentation.""" + speed: str | None + """ + Speed should be set in the format `` or `forced ` or `auto + `. + """ + structured_config: StructuredConfig + """ + Custom structured config for the member ethernet interface. + + Subclass of AvdModel. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + name: str | UndefinedType = Undefined, + description: str | None | UndefinedType = Undefined, + peer: str | None | UndefinedType = Undefined, + peer_interface: str | None | UndefinedType = Undefined, + speed: str | None | UndefinedType = Undefined, + structured_config: StructuredConfig | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + MemberInterfacesItem. + + + Subclass of AvdModel. + + Args: + name: + Ethernet interface name like 'Ethernet2'. + Member interface cannot be subinterface. + description: + Interface description for this member. + If not set, a default description will be configured with + '[[ ]]'. + peer: + The peer device name. Used for description and documentation. + If not set, this inherits the peer + setting on the port-channel interface. + peer_interface: The peer device interface. Used for description and documentation. + speed: + Speed should be set in the format `` or `forced ` or `auto + `. + structured_config: + Custom structured config for the member ethernet interface. + + Subclass of AvdModel. + _custom_data: _custom_data + + """ + + class MemberInterfaces(AvdIndexedList[str, MemberInterfacesItem]): + """Subclass of AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`).""" + + _primary_key: ClassVar[str] = "name" + + MemberInterfaces._item_type = MemberInterfacesItem + + class Bgp(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "peer_as": {"type": str}, + "ipv4_prefix_list_in": {"type": str}, + "ipv4_prefix_list_out": {"type": str}, + "_custom_data": {"type": dict}, + } + peer_as: str + """ + BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>". + For asdot notation in + YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float + number. + """ + ipv4_prefix_list_in: str | None + """ + Prefix List Name. Accept routes for only these prefixes from the peer. + Required for wan interfaces. + """ + ipv4_prefix_list_out: str | None + """ + Prefix List Name. Advertise routes for only these prefixes. + If not specified, nothing would be + advertised. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + peer_as: str | UndefinedType = Undefined, + ipv4_prefix_list_in: str | None | UndefinedType = Undefined, + ipv4_prefix_list_out: str | None | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + Bgp. + + + Subclass of AvdModel. + + Args: + peer_as: + BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>". + For asdot notation in + YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float + number. + ipv4_prefix_list_in: + Prefix List Name. Accept routes for only these prefixes from the peer. + Required for wan interfaces. + ipv4_prefix_list_out: + Prefix List Name. Advertise routes for only these prefixes. + If not specified, nothing would be + advertised. + _custom_data: _custom_data + + """ + + class StaticRoutesItem(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = {"prefix": {"type": str}, "_custom_data": {"type": dict}} + prefix: str + """IPv4_network/Mask.""" + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, *, prefix: str | UndefinedType = Undefined, _custom_data: dict[str, Any] | UndefinedType = Undefined + ) -> None: + """ + StaticRoutesItem. + + + Subclass of AvdModel. + + Args: + prefix: IPv4_network/Mask. + _custom_data: _custom_data + + """ + + class StaticRoutes(AvdIndexedList[str, StaticRoutesItem]): + """Subclass of AvdIndexedList with `StaticRoutesItem` items. Primary key is `prefix` (`str`).""" + + _primary_key: ClassVar[str] = "prefix" + + StaticRoutes._item_type = StaticRoutesItem + + class FlowTracking(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = {"enabled": {"type": bool}, "name": {"type": str}, "_custom_data": {"type": dict}} + enabled: bool | None + name: str | None + """Flow tracker name as defined in flow_tracking_settings.""" + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + enabled: bool | None | UndefinedType = Undefined, + name: str | None | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + FlowTracking. + + + Subclass of AvdModel. + + Args: + enabled: enabled + name: Flow tracker name as defined in flow_tracking_settings. + _custom_data: _custom_data + + """ + + class StructuredConfig(EosCliConfigGen.PortChannelInterfacesItem): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "name": {"type": str}, + "description": {"type": str}, + "mode": {"type": str, "default": "active"}, + "member_interfaces": {"type": MemberInterfaces}, + "ip_address": {"type": str}, + "dhcp_ip": {"type": str}, + "public_ip": {"type": str}, + "encapsulation_dot1q_vlan": {"type": int}, + "dhcp_accept_default_route": {"type": bool, "default": True}, + "enabled": {"type": bool, "default": True}, + "peer": {"type": str}, + "peer_port_channel": {"type": str}, + "peer_ip": {"type": str}, + "bgp": {"type": Bgp}, + "ipv4_acl_in": {"type": str}, + "ipv4_acl_out": {"type": str}, + "static_routes": {"type": StaticRoutes}, + "qos_profile": {"type": str}, + "wan_carrier": {"type": str}, + "wan_circuit_id": {"type": str}, + "connected_to_pathfinder": {"type": bool, "default": True}, + "raw_eos_cli": {"type": str}, + "flow_tracking": {"type": FlowTracking}, + "structured_config": {"type": StructuredConfig}, + "_custom_data": {"type": dict}, + } + name: str + """ + Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'. + For a + Port-Channel subinterface, the parent Port-Channel interface must be defined as well. + """ + description: str | None + """ + Interface description. + If not set, a default description will be configured with '[[ + ]]'. + """ + mode: Literal["active", "passive", "on"] + """ + Port-Channel mode. + Should not be set on Port-Channel subinterfaces. + + Default value: `"active"` + """ + member_interfaces: MemberInterfaces + """ + Port-Channel member interfaces. + Should not be set on Port-Channel subinterfaces. + + Subclass of + AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`). + """ + ip_address: str | None + """Node IPv4 address/Mask or 'dhcp'.""" + dhcp_ip: str | None + """ + When the `ip_address` is `dhcp`, this optional field allows to indicate the expected + IPv4 address + (without mask) to be allocated on the interface if known. + This is not rendered in the configuration + but can be used for substitution of 'interface_ip' in the Access-list + set under `ipv4_acl_in` and + `ipv4_acl_out`. + """ + public_ip: str | None + """ + Node IPv4 address (no mask). + + This is used to get the public IP (if known) when the device is behind + NAT. + This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP + with the following preference: + `wan_route_servers.path_groups.interfaces.ip_address` + -> + `l3_port_channels.public_ip` + -> `l3_port_channels.ip_address` + + The determined Public IP is + used by WAN routers when peering with this interface. + """ + encapsulation_dot1q_vlan: int | None + """ + For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be + specified. + """ + dhcp_accept_default_route: bool + """ + Accept a default route from DHCP if `ip_address` is set to `dhcp`. + + Default value: `True` + """ + enabled: bool + """ + Enable or Shutdown the interface. + + Default value: `True` + """ + peer: str | None + """The peer device name. Used for description and documentation.""" + peer_port_channel: str | None + """The peer device port-channel interface. Used for description and documentation.""" + peer_ip: str | None + """ + The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true + and `ip` is an IP address. + """ + bgp: Bgp + """ + Enforce IPv4 BGP peering for the peer + + Subclass of AvdModel. + """ + ipv4_acl_in: str | None + """ + Name of the IPv4 access-list to be assigned in the ingress direction. + The access-list must be + defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + Required + for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under + `wan_carriers`. + """ + ipv4_acl_out: str | None + """ + Name of the IPv4 Access-list to be assigned in the egress direction. + The access-list must be defined + under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + """ + static_routes: StaticRoutes + """ + Configure IPv4 static routes pointing to `peer_ip`. + + Subclass of AvdIndexedList with + `StaticRoutesItem` items. Primary key is `prefix` (`str`). + """ + qos_profile: str | None + """QOS service profile.""" + wan_carrier: str | None + """ + The WAN carrier this interface is connected to. + This is used to infer the path-groups in which this + interface should be configured. + Unless the carrier is marked as 'trusted' under `wan_carriers`, + `ipv4_acl_in` is also required on all WAN interfaces. + """ + wan_circuit_id: str | None + """ + The WAN circuit ID for this interface. + This is not rendered in the configuration but used for WAN + designs. + """ + connected_to_pathfinder: bool + """ + For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. + + Default value: `True` + """ + raw_eos_cli: str | None + """EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration.""" + flow_tracking: FlowTracking + """ + Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` + setting. + + Subclass of AvdModel. + """ + structured_config: StructuredConfig + """ + Custom structured config for the Port-Channel interface. + + Subclass of AvdModel. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + name: str | UndefinedType = Undefined, + description: str | None | UndefinedType = Undefined, + mode: Literal["active", "passive", "on"] | UndefinedType = Undefined, + member_interfaces: MemberInterfaces | UndefinedType = Undefined, + ip_address: str | None | UndefinedType = Undefined, + dhcp_ip: str | None | UndefinedType = Undefined, + public_ip: str | None | UndefinedType = Undefined, + encapsulation_dot1q_vlan: int | None | UndefinedType = Undefined, + dhcp_accept_default_route: bool | UndefinedType = Undefined, + enabled: bool | UndefinedType = Undefined, + peer: str | None | UndefinedType = Undefined, + peer_port_channel: str | None | UndefinedType = Undefined, + peer_ip: str | None | UndefinedType = Undefined, + bgp: Bgp | UndefinedType = Undefined, + ipv4_acl_in: str | None | UndefinedType = Undefined, + ipv4_acl_out: str | None | UndefinedType = Undefined, + static_routes: StaticRoutes | UndefinedType = Undefined, + qos_profile: str | None | UndefinedType = Undefined, + wan_carrier: str | None | UndefinedType = Undefined, + wan_circuit_id: str | None | UndefinedType = Undefined, + connected_to_pathfinder: bool | UndefinedType = Undefined, + raw_eos_cli: str | None | UndefinedType = Undefined, + flow_tracking: FlowTracking | UndefinedType = Undefined, + structured_config: StructuredConfig | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + L3PortChannelsItem. + + + Subclass of AvdModel. + + Args: + name: + Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'. + For a + Port-Channel subinterface, the parent Port-Channel interface must be defined as well. + description: + Interface description. + If not set, a default description will be configured with '[[ + ]]'. + mode: + Port-Channel mode. + Should not be set on Port-Channel subinterfaces. + member_interfaces: + Port-Channel member interfaces. + Should not be set on Port-Channel subinterfaces. + + Subclass of + AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`). + ip_address: Node IPv4 address/Mask or 'dhcp'. + dhcp_ip: + When the `ip_address` is `dhcp`, this optional field allows to indicate the expected + IPv4 address + (without mask) to be allocated on the interface if known. + This is not rendered in the configuration + but can be used for substitution of 'interface_ip' in the Access-list + set under `ipv4_acl_in` and + `ipv4_acl_out`. + public_ip: + Node IPv4 address (no mask). + + This is used to get the public IP (if known) when the device is behind + NAT. + This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP + with the following preference: + `wan_route_servers.path_groups.interfaces.ip_address` + -> + `l3_port_channels.public_ip` + -> `l3_port_channels.ip_address` + + The determined Public IP is + used by WAN routers when peering with this interface. + encapsulation_dot1q_vlan: + For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be + specified. + dhcp_accept_default_route: Accept a default route from DHCP if `ip_address` is set to `dhcp`. + enabled: Enable or Shutdown the interface. + peer: The peer device name. Used for description and documentation. + peer_port_channel: The peer device port-channel interface. Used for description and documentation. + peer_ip: + The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true + and `ip` is an IP address. + bgp: + Enforce IPv4 BGP peering for the peer + + Subclass of AvdModel. + ipv4_acl_in: + Name of the IPv4 access-list to be assigned in the ingress direction. + The access-list must be + defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + Required + for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under + `wan_carriers`. + ipv4_acl_out: + Name of the IPv4 Access-list to be assigned in the egress direction. + The access-list must be defined + under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + static_routes: + Configure IPv4 static routes pointing to `peer_ip`. + + Subclass of AvdIndexedList with + `StaticRoutesItem` items. Primary key is `prefix` (`str`). + qos_profile: QOS service profile. + wan_carrier: + The WAN carrier this interface is connected to. + This is used to infer the path-groups in which this + interface should be configured. + Unless the carrier is marked as 'trusted' under `wan_carriers`, + `ipv4_acl_in` is also required on all WAN interfaces. + wan_circuit_id: + The WAN circuit ID for this interface. + This is not rendered in the configuration but used for WAN + designs. + connected_to_pathfinder: For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. + raw_eos_cli: EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration. + flow_tracking: + Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` + setting. + + Subclass of AvdModel. + structured_config: + Custom structured config for the Port-Channel interface. + + Subclass of AvdModel. + _custom_data: _custom_data + + """ + + class L3PortChannels(AvdIndexedList[str, L3PortChannelsItem]): + """Subclass of AvdIndexedList with `L3PortChannelsItem` items. Primary key is `name` (`str`).""" + + _primary_key: ClassVar[str] = "name" + + L3PortChannels._item_type = L3PortChannelsItem + _fields: ClassVar[dict] = { "id": {"type": int}, "platform": {"type": str}, @@ -42684,6 +45496,7 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): "wan_ha": {"type": WanHa}, "dps_mss_ipv4": {"type": str, "default": "auto"}, "l3_interfaces": {"type": L3Interfaces}, + "l3_port_channels": {"type": L3PortChannels}, "data_plane_cpu_allocation_max": {"type": int}, "flow_tracker_type": {"type": str}, "_custom_data": {"type": dict}, @@ -43465,11 +46278,16 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): l3_interfaces: L3Interfaces """ L3 Interfaces to configure on the node. - Used to define the node for WAN interfaces when - `wan_carrier` is set. - Subclass of AvdIndexedList with `L3InterfacesItem` items. Primary key is - `name` (`str`). + Subclass of AvdIndexedList with `L3InterfacesItem` items. + Primary key is `name` (`str`). + """ + l3_port_channels: L3PortChannels + """ + L3 Port-Channel interfaces to configure on the node. + + Subclass of AvdIndexedList with + `L3PortChannelsItem` items. Primary key is `name` (`str`). """ data_plane_cpu_allocation_max: int | None """ @@ -43594,6 +46412,7 @@ def __init__( wan_ha: WanHa | UndefinedType = Undefined, dps_mss_ipv4: str | UndefinedType = Undefined, l3_interfaces: L3Interfaces | UndefinedType = Undefined, + l3_port_channels: L3PortChannels | UndefinedType = Undefined, data_plane_cpu_allocation_max: int | None | UndefinedType = Undefined, flow_tracker_type: Literal["sampled", "hardware"] | None | UndefinedType = Undefined, _custom_data: dict[str, Any] | UndefinedType = Undefined, @@ -44150,11 +46969,14 @@ def __init__( dps_mss_ipv4: IPv4 MSS value configured under "router path-selection" on WAN Devices. l3_interfaces: L3 Interfaces to configure on the node. - Used to define the node for WAN interfaces when - `wan_carrier` is set. - Subclass of AvdIndexedList with `L3InterfacesItem` items. Primary key is - `name` (`str`). + Subclass of AvdIndexedList with `L3InterfacesItem` items. + Primary key is `name` (`str`). + l3_port_channels: + L3 Port-Channel interfaces to configure on the node. + + Subclass of AvdIndexedList with + `L3PortChannelsItem` items. Primary key is `name` (`str`). data_plane_cpu_allocation_max: Set the maximum number of CPU used for the data plane. This setting is useful on virtual Route @@ -46125,6 +48947,550 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): L3Interfaces._item_type = L3InterfacesItem + class L3PortChannelsItem(AvdModel): + """Subclass of AvdModel.""" + + class MemberInterfacesItem(AvdModel): + """Subclass of AvdModel.""" + + class StructuredConfig(EosCliConfigGen.EthernetInterfacesItem): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "name": {"type": str}, + "description": {"type": str}, + "peer": {"type": str}, + "peer_interface": {"type": str}, + "speed": {"type": str}, + "structured_config": {"type": StructuredConfig}, + "_custom_data": {"type": dict}, + } + name: str + """ + Ethernet interface name like 'Ethernet2'. + Member interface cannot be subinterface. + """ + description: str | None + """ + Interface description for this member. + If not set, a default description will be configured with + '[[ ]]'. + """ + peer: str | None + """ + The peer device name. Used for description and documentation. + If not set, this inherits the peer + setting on the port-channel interface. + """ + peer_interface: str | None + """The peer device interface. Used for description and documentation.""" + speed: str | None + """ + Speed should be set in the format `` or `forced ` or `auto + `. + """ + structured_config: StructuredConfig + """ + Custom structured config for the member ethernet interface. + + Subclass of AvdModel. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + name: str | UndefinedType = Undefined, + description: str | None | UndefinedType = Undefined, + peer: str | None | UndefinedType = Undefined, + peer_interface: str | None | UndefinedType = Undefined, + speed: str | None | UndefinedType = Undefined, + structured_config: StructuredConfig | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + MemberInterfacesItem. + + + Subclass of AvdModel. + + Args: + name: + Ethernet interface name like 'Ethernet2'. + Member interface cannot be subinterface. + description: + Interface description for this member. + If not set, a default description will be configured with + '[[ ]]'. + peer: + The peer device name. Used for description and documentation. + If not set, this inherits the peer + setting on the port-channel interface. + peer_interface: The peer device interface. Used for description and documentation. + speed: + Speed should be set in the format `` or `forced ` or `auto + `. + structured_config: + Custom structured config for the member ethernet interface. + + Subclass of AvdModel. + _custom_data: _custom_data + + """ + + class MemberInterfaces(AvdIndexedList[str, MemberInterfacesItem]): + """Subclass of AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`).""" + + _primary_key: ClassVar[str] = "name" + + MemberInterfaces._item_type = MemberInterfacesItem + + class Bgp(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "peer_as": {"type": str}, + "ipv4_prefix_list_in": {"type": str}, + "ipv4_prefix_list_out": {"type": str}, + "_custom_data": {"type": dict}, + } + peer_as: str + """ + BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>". + For asdot notation in + YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float + number. + """ + ipv4_prefix_list_in: str | None + """ + Prefix List Name. Accept routes for only these prefixes from the peer. + Required for wan interfaces. + """ + ipv4_prefix_list_out: str | None + """ + Prefix List Name. Advertise routes for only these prefixes. + If not specified, nothing would be + advertised. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + peer_as: str | UndefinedType = Undefined, + ipv4_prefix_list_in: str | None | UndefinedType = Undefined, + ipv4_prefix_list_out: str | None | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + Bgp. + + + Subclass of AvdModel. + + Args: + peer_as: + BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>". + For asdot notation in + YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float + number. + ipv4_prefix_list_in: + Prefix List Name. Accept routes for only these prefixes from the peer. + Required for wan interfaces. + ipv4_prefix_list_out: + Prefix List Name. Advertise routes for only these prefixes. + If not specified, nothing would be + advertised. + _custom_data: _custom_data + + """ + + class StaticRoutesItem(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = {"prefix": {"type": str}, "_custom_data": {"type": dict}} + prefix: str + """IPv4_network/Mask.""" + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, *, prefix: str | UndefinedType = Undefined, _custom_data: dict[str, Any] | UndefinedType = Undefined + ) -> None: + """ + StaticRoutesItem. + + + Subclass of AvdModel. + + Args: + prefix: IPv4_network/Mask. + _custom_data: _custom_data + + """ + + class StaticRoutes(AvdIndexedList[str, StaticRoutesItem]): + """Subclass of AvdIndexedList with `StaticRoutesItem` items. Primary key is `prefix` (`str`).""" + + _primary_key: ClassVar[str] = "prefix" + + StaticRoutes._item_type = StaticRoutesItem + + class FlowTracking(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = {"enabled": {"type": bool}, "name": {"type": str}, "_custom_data": {"type": dict}} + enabled: bool | None + name: str | None + """Flow tracker name as defined in flow_tracking_settings.""" + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + enabled: bool | None | UndefinedType = Undefined, + name: str | None | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + FlowTracking. + + + Subclass of AvdModel. + + Args: + enabled: enabled + name: Flow tracker name as defined in flow_tracking_settings. + _custom_data: _custom_data + + """ + + class StructuredConfig(EosCliConfigGen.PortChannelInterfacesItem): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "name": {"type": str}, + "description": {"type": str}, + "mode": {"type": str, "default": "active"}, + "member_interfaces": {"type": MemberInterfaces}, + "ip_address": {"type": str}, + "dhcp_ip": {"type": str}, + "public_ip": {"type": str}, + "encapsulation_dot1q_vlan": {"type": int}, + "dhcp_accept_default_route": {"type": bool, "default": True}, + "enabled": {"type": bool, "default": True}, + "peer": {"type": str}, + "peer_port_channel": {"type": str}, + "peer_ip": {"type": str}, + "bgp": {"type": Bgp}, + "ipv4_acl_in": {"type": str}, + "ipv4_acl_out": {"type": str}, + "static_routes": {"type": StaticRoutes}, + "qos_profile": {"type": str}, + "wan_carrier": {"type": str}, + "wan_circuit_id": {"type": str}, + "connected_to_pathfinder": {"type": bool, "default": True}, + "raw_eos_cli": {"type": str}, + "flow_tracking": {"type": FlowTracking}, + "structured_config": {"type": StructuredConfig}, + "_custom_data": {"type": dict}, + } + name: str + """ + Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'. + For a + Port-Channel subinterface, the parent Port-Channel interface must be defined as well. + """ + description: str | None + """ + Interface description. + If not set, a default description will be configured with '[[ + ]]'. + """ + mode: Literal["active", "passive", "on"] + """ + Port-Channel mode. + Should not be set on Port-Channel subinterfaces. + + Default value: `"active"` + """ + member_interfaces: MemberInterfaces + """ + Port-Channel member interfaces. + Should not be set on Port-Channel subinterfaces. + + Subclass of + AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`). + """ + ip_address: str | None + """Node IPv4 address/Mask or 'dhcp'.""" + dhcp_ip: str | None + """ + When the `ip_address` is `dhcp`, this optional field allows to indicate the expected + IPv4 address + (without mask) to be allocated on the interface if known. + This is not rendered in the configuration + but can be used for substitution of 'interface_ip' in the Access-list + set under `ipv4_acl_in` and + `ipv4_acl_out`. + """ + public_ip: str | None + """ + Node IPv4 address (no mask). + + This is used to get the public IP (if known) when the device is behind + NAT. + This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP + with the following preference: + `wan_route_servers.path_groups.interfaces.ip_address` + -> + `l3_port_channels.public_ip` + -> `l3_port_channels.ip_address` + + The determined Public IP is + used by WAN routers when peering with this interface. + """ + encapsulation_dot1q_vlan: int | None + """ + For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be + specified. + """ + dhcp_accept_default_route: bool + """ + Accept a default route from DHCP if `ip_address` is set to `dhcp`. + + Default value: `True` + """ + enabled: bool + """ + Enable or Shutdown the interface. + + Default value: `True` + """ + peer: str | None + """The peer device name. Used for description and documentation.""" + peer_port_channel: str | None + """The peer device port-channel interface. Used for description and documentation.""" + peer_ip: str | None + """ + The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true + and `ip` is an IP address. + """ + bgp: Bgp + """ + Enforce IPv4 BGP peering for the peer + + Subclass of AvdModel. + """ + ipv4_acl_in: str | None + """ + Name of the IPv4 access-list to be assigned in the ingress direction. + The access-list must be + defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + Required + for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under + `wan_carriers`. + """ + ipv4_acl_out: str | None + """ + Name of the IPv4 Access-list to be assigned in the egress direction. + The access-list must be defined + under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + """ + static_routes: StaticRoutes + """ + Configure IPv4 static routes pointing to `peer_ip`. + + Subclass of AvdIndexedList with + `StaticRoutesItem` items. Primary key is `prefix` (`str`). + """ + qos_profile: str | None + """QOS service profile.""" + wan_carrier: str | None + """ + The WAN carrier this interface is connected to. + This is used to infer the path-groups in which this + interface should be configured. + Unless the carrier is marked as 'trusted' under `wan_carriers`, + `ipv4_acl_in` is also required on all WAN interfaces. + """ + wan_circuit_id: str | None + """ + The WAN circuit ID for this interface. + This is not rendered in the configuration but used for WAN + designs. + """ + connected_to_pathfinder: bool + """ + For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. + + Default value: `True` + """ + raw_eos_cli: str | None + """EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration.""" + flow_tracking: FlowTracking + """ + Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` + setting. + + Subclass of AvdModel. + """ + structured_config: StructuredConfig + """ + Custom structured config for the Port-Channel interface. + + Subclass of AvdModel. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + name: str | UndefinedType = Undefined, + description: str | None | UndefinedType = Undefined, + mode: Literal["active", "passive", "on"] | UndefinedType = Undefined, + member_interfaces: MemberInterfaces | UndefinedType = Undefined, + ip_address: str | None | UndefinedType = Undefined, + dhcp_ip: str | None | UndefinedType = Undefined, + public_ip: str | None | UndefinedType = Undefined, + encapsulation_dot1q_vlan: int | None | UndefinedType = Undefined, + dhcp_accept_default_route: bool | UndefinedType = Undefined, + enabled: bool | UndefinedType = Undefined, + peer: str | None | UndefinedType = Undefined, + peer_port_channel: str | None | UndefinedType = Undefined, + peer_ip: str | None | UndefinedType = Undefined, + bgp: Bgp | UndefinedType = Undefined, + ipv4_acl_in: str | None | UndefinedType = Undefined, + ipv4_acl_out: str | None | UndefinedType = Undefined, + static_routes: StaticRoutes | UndefinedType = Undefined, + qos_profile: str | None | UndefinedType = Undefined, + wan_carrier: str | None | UndefinedType = Undefined, + wan_circuit_id: str | None | UndefinedType = Undefined, + connected_to_pathfinder: bool | UndefinedType = Undefined, + raw_eos_cli: str | None | UndefinedType = Undefined, + flow_tracking: FlowTracking | UndefinedType = Undefined, + structured_config: StructuredConfig | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + L3PortChannelsItem. + + + Subclass of AvdModel. + + Args: + name: + Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'. + For a + Port-Channel subinterface, the parent Port-Channel interface must be defined as well. + description: + Interface description. + If not set, a default description will be configured with '[[ + ]]'. + mode: + Port-Channel mode. + Should not be set on Port-Channel subinterfaces. + member_interfaces: + Port-Channel member interfaces. + Should not be set on Port-Channel subinterfaces. + + Subclass of + AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`). + ip_address: Node IPv4 address/Mask or 'dhcp'. + dhcp_ip: + When the `ip_address` is `dhcp`, this optional field allows to indicate the expected + IPv4 address + (without mask) to be allocated on the interface if known. + This is not rendered in the configuration + but can be used for substitution of 'interface_ip' in the Access-list + set under `ipv4_acl_in` and + `ipv4_acl_out`. + public_ip: + Node IPv4 address (no mask). + + This is used to get the public IP (if known) when the device is behind + NAT. + This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP + with the following preference: + `wan_route_servers.path_groups.interfaces.ip_address` + -> + `l3_port_channels.public_ip` + -> `l3_port_channels.ip_address` + + The determined Public IP is + used by WAN routers when peering with this interface. + encapsulation_dot1q_vlan: + For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be + specified. + dhcp_accept_default_route: Accept a default route from DHCP if `ip_address` is set to `dhcp`. + enabled: Enable or Shutdown the interface. + peer: The peer device name. Used for description and documentation. + peer_port_channel: The peer device port-channel interface. Used for description and documentation. + peer_ip: + The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true + and `ip` is an IP address. + bgp: + Enforce IPv4 BGP peering for the peer + + Subclass of AvdModel. + ipv4_acl_in: + Name of the IPv4 access-list to be assigned in the ingress direction. + The access-list must be + defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + Required + for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under + `wan_carriers`. + ipv4_acl_out: + Name of the IPv4 Access-list to be assigned in the egress direction. + The access-list must be defined + under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + static_routes: + Configure IPv4 static routes pointing to `peer_ip`. + + Subclass of AvdIndexedList with + `StaticRoutesItem` items. Primary key is `prefix` (`str`). + qos_profile: QOS service profile. + wan_carrier: + The WAN carrier this interface is connected to. + This is used to infer the path-groups in which this + interface should be configured. + Unless the carrier is marked as 'trusted' under `wan_carriers`, + `ipv4_acl_in` is also required on all WAN interfaces. + wan_circuit_id: + The WAN circuit ID for this interface. + This is not rendered in the configuration but used for WAN + designs. + connected_to_pathfinder: For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. + raw_eos_cli: EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration. + flow_tracking: + Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` + setting. + + Subclass of AvdModel. + structured_config: + Custom structured config for the Port-Channel interface. + + Subclass of AvdModel. + _custom_data: _custom_data + + """ + + class L3PortChannels(AvdIndexedList[str, L3PortChannelsItem]): + """Subclass of AvdIndexedList with `L3PortChannelsItem` items. Primary key is `name` (`str`).""" + + _primary_key: ClassVar[str] = "name" + + L3PortChannels._item_type = L3PortChannelsItem + _fields: ClassVar[dict] = { "name": {"type": str}, "downlink_pools": {"type": DownlinkPools}, @@ -46231,6 +49597,7 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): "wan_ha": {"type": WanHa}, "dps_mss_ipv4": {"type": str, "default": "auto"}, "l3_interfaces": {"type": L3Interfaces}, + "l3_port_channels": {"type": L3PortChannels}, "data_plane_cpu_allocation_max": {"type": int}, "flow_tracker_type": {"type": str}, "_custom_data": {"type": dict}, @@ -47022,11 +50389,16 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): l3_interfaces: L3Interfaces """ L3 Interfaces to configure on the node. - Used to define the node for WAN interfaces when - `wan_carrier` is set. - Subclass of AvdIndexedList with `L3InterfacesItem` items. Primary key is - `name` (`str`). + Subclass of AvdIndexedList with `L3InterfacesItem` items. + Primary key is `name` (`str`). + """ + l3_port_channels: L3PortChannels + """ + L3 Port-Channel interfaces to configure on the node. + + Subclass of AvdIndexedList with + `L3PortChannelsItem` items. Primary key is `name` (`str`). """ data_plane_cpu_allocation_max: int | None """ @@ -47153,6 +50525,7 @@ def __init__( wan_ha: WanHa | UndefinedType = Undefined, dps_mss_ipv4: str | UndefinedType = Undefined, l3_interfaces: L3Interfaces | UndefinedType = Undefined, + l3_port_channels: L3PortChannels | UndefinedType = Undefined, data_plane_cpu_allocation_max: int | None | UndefinedType = Undefined, flow_tracker_type: Literal["sampled", "hardware"] | None | UndefinedType = Undefined, _custom_data: dict[str, Any] | UndefinedType = Undefined, @@ -47716,11 +51089,14 @@ def __init__( dps_mss_ipv4: IPv4 MSS value configured under "router path-selection" on WAN Devices. l3_interfaces: L3 Interfaces to configure on the node. - Used to define the node for WAN interfaces when - `wan_carrier` is set. - Subclass of AvdIndexedList with `L3InterfacesItem` items. Primary key is - `name` (`str`). + Subclass of AvdIndexedList with `L3InterfacesItem` items. + Primary key is `name` (`str`). + l3_port_channels: + L3 Port-Channel interfaces to configure on the node. + + Subclass of AvdIndexedList with + `L3PortChannelsItem` items. Primary key is `name` (`str`). data_plane_cpu_allocation_max: Set the maximum number of CPU used for the data plane. This setting is useful on virtual Route @@ -49624,6 +53000,550 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): L3Interfaces._item_type = L3InterfacesItem + class L3PortChannelsItem(AvdModel): + """Subclass of AvdModel.""" + + class MemberInterfacesItem(AvdModel): + """Subclass of AvdModel.""" + + class StructuredConfig(EosCliConfigGen.EthernetInterfacesItem): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "name": {"type": str}, + "description": {"type": str}, + "peer": {"type": str}, + "peer_interface": {"type": str}, + "speed": {"type": str}, + "structured_config": {"type": StructuredConfig}, + "_custom_data": {"type": dict}, + } + name: str + """ + Ethernet interface name like 'Ethernet2'. + Member interface cannot be subinterface. + """ + description: str | None + """ + Interface description for this member. + If not set, a default description will be configured with + '[[ ]]'. + """ + peer: str | None + """ + The peer device name. Used for description and documentation. + If not set, this inherits the peer + setting on the port-channel interface. + """ + peer_interface: str | None + """The peer device interface. Used for description and documentation.""" + speed: str | None + """ + Speed should be set in the format `` or `forced ` or `auto + `. + """ + structured_config: StructuredConfig + """ + Custom structured config for the member ethernet interface. + + Subclass of AvdModel. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + name: str | UndefinedType = Undefined, + description: str | None | UndefinedType = Undefined, + peer: str | None | UndefinedType = Undefined, + peer_interface: str | None | UndefinedType = Undefined, + speed: str | None | UndefinedType = Undefined, + structured_config: StructuredConfig | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + MemberInterfacesItem. + + + Subclass of AvdModel. + + Args: + name: + Ethernet interface name like 'Ethernet2'. + Member interface cannot be subinterface. + description: + Interface description for this member. + If not set, a default description will be configured with + '[[ ]]'. + peer: + The peer device name. Used for description and documentation. + If not set, this inherits the peer + setting on the port-channel interface. + peer_interface: The peer device interface. Used for description and documentation. + speed: + Speed should be set in the format `` or `forced ` or `auto + `. + structured_config: + Custom structured config for the member ethernet interface. + + Subclass of AvdModel. + _custom_data: _custom_data + + """ + + class MemberInterfaces(AvdIndexedList[str, MemberInterfacesItem]): + """Subclass of AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`).""" + + _primary_key: ClassVar[str] = "name" + + MemberInterfaces._item_type = MemberInterfacesItem + + class Bgp(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "peer_as": {"type": str}, + "ipv4_prefix_list_in": {"type": str}, + "ipv4_prefix_list_out": {"type": str}, + "_custom_data": {"type": dict}, + } + peer_as: str + """ + BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>". + For asdot notation in + YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float + number. + """ + ipv4_prefix_list_in: str | None + """ + Prefix List Name. Accept routes for only these prefixes from the peer. + Required for wan interfaces. + """ + ipv4_prefix_list_out: str | None + """ + Prefix List Name. Advertise routes for only these prefixes. + If not specified, nothing would be + advertised. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + peer_as: str | UndefinedType = Undefined, + ipv4_prefix_list_in: str | None | UndefinedType = Undefined, + ipv4_prefix_list_out: str | None | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + Bgp. + + + Subclass of AvdModel. + + Args: + peer_as: + BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>". + For asdot notation in + YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float + number. + ipv4_prefix_list_in: + Prefix List Name. Accept routes for only these prefixes from the peer. + Required for wan interfaces. + ipv4_prefix_list_out: + Prefix List Name. Advertise routes for only these prefixes. + If not specified, nothing would be + advertised. + _custom_data: _custom_data + + """ + + class StaticRoutesItem(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = {"prefix": {"type": str}, "_custom_data": {"type": dict}} + prefix: str + """IPv4_network/Mask.""" + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, *, prefix: str | UndefinedType = Undefined, _custom_data: dict[str, Any] | UndefinedType = Undefined + ) -> None: + """ + StaticRoutesItem. + + + Subclass of AvdModel. + + Args: + prefix: IPv4_network/Mask. + _custom_data: _custom_data + + """ + + class StaticRoutes(AvdIndexedList[str, StaticRoutesItem]): + """Subclass of AvdIndexedList with `StaticRoutesItem` items. Primary key is `prefix` (`str`).""" + + _primary_key: ClassVar[str] = "prefix" + + StaticRoutes._item_type = StaticRoutesItem + + class FlowTracking(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = {"enabled": {"type": bool}, "name": {"type": str}, "_custom_data": {"type": dict}} + enabled: bool | None + name: str | None + """Flow tracker name as defined in flow_tracking_settings.""" + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + enabled: bool | None | UndefinedType = Undefined, + name: str | None | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + FlowTracking. + + + Subclass of AvdModel. + + Args: + enabled: enabled + name: Flow tracker name as defined in flow_tracking_settings. + _custom_data: _custom_data + + """ + + class StructuredConfig(EosCliConfigGen.PortChannelInterfacesItem): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "name": {"type": str}, + "description": {"type": str}, + "mode": {"type": str, "default": "active"}, + "member_interfaces": {"type": MemberInterfaces}, + "ip_address": {"type": str}, + "dhcp_ip": {"type": str}, + "public_ip": {"type": str}, + "encapsulation_dot1q_vlan": {"type": int}, + "dhcp_accept_default_route": {"type": bool, "default": True}, + "enabled": {"type": bool, "default": True}, + "peer": {"type": str}, + "peer_port_channel": {"type": str}, + "peer_ip": {"type": str}, + "bgp": {"type": Bgp}, + "ipv4_acl_in": {"type": str}, + "ipv4_acl_out": {"type": str}, + "static_routes": {"type": StaticRoutes}, + "qos_profile": {"type": str}, + "wan_carrier": {"type": str}, + "wan_circuit_id": {"type": str}, + "connected_to_pathfinder": {"type": bool, "default": True}, + "raw_eos_cli": {"type": str}, + "flow_tracking": {"type": FlowTracking}, + "structured_config": {"type": StructuredConfig}, + "_custom_data": {"type": dict}, + } + name: str + """ + Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'. + For a + Port-Channel subinterface, the parent Port-Channel interface must be defined as well. + """ + description: str | None + """ + Interface description. + If not set, a default description will be configured with '[[ + ]]'. + """ + mode: Literal["active", "passive", "on"] + """ + Port-Channel mode. + Should not be set on Port-Channel subinterfaces. + + Default value: `"active"` + """ + member_interfaces: MemberInterfaces + """ + Port-Channel member interfaces. + Should not be set on Port-Channel subinterfaces. + + Subclass of + AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`). + """ + ip_address: str | None + """Node IPv4 address/Mask or 'dhcp'.""" + dhcp_ip: str | None + """ + When the `ip_address` is `dhcp`, this optional field allows to indicate the expected + IPv4 address + (without mask) to be allocated on the interface if known. + This is not rendered in the configuration + but can be used for substitution of 'interface_ip' in the Access-list + set under `ipv4_acl_in` and + `ipv4_acl_out`. + """ + public_ip: str | None + """ + Node IPv4 address (no mask). + + This is used to get the public IP (if known) when the device is behind + NAT. + This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP + with the following preference: + `wan_route_servers.path_groups.interfaces.ip_address` + -> + `l3_port_channels.public_ip` + -> `l3_port_channels.ip_address` + + The determined Public IP is + used by WAN routers when peering with this interface. + """ + encapsulation_dot1q_vlan: int | None + """ + For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be + specified. + """ + dhcp_accept_default_route: bool + """ + Accept a default route from DHCP if `ip_address` is set to `dhcp`. + + Default value: `True` + """ + enabled: bool + """ + Enable or Shutdown the interface. + + Default value: `True` + """ + peer: str | None + """The peer device name. Used for description and documentation.""" + peer_port_channel: str | None + """The peer device port-channel interface. Used for description and documentation.""" + peer_ip: str | None + """ + The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true + and `ip` is an IP address. + """ + bgp: Bgp + """ + Enforce IPv4 BGP peering for the peer + + Subclass of AvdModel. + """ + ipv4_acl_in: str | None + """ + Name of the IPv4 access-list to be assigned in the ingress direction. + The access-list must be + defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + Required + for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under + `wan_carriers`. + """ + ipv4_acl_out: str | None + """ + Name of the IPv4 Access-list to be assigned in the egress direction. + The access-list must be defined + under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + """ + static_routes: StaticRoutes + """ + Configure IPv4 static routes pointing to `peer_ip`. + + Subclass of AvdIndexedList with + `StaticRoutesItem` items. Primary key is `prefix` (`str`). + """ + qos_profile: str | None + """QOS service profile.""" + wan_carrier: str | None + """ + The WAN carrier this interface is connected to. + This is used to infer the path-groups in which this + interface should be configured. + Unless the carrier is marked as 'trusted' under `wan_carriers`, + `ipv4_acl_in` is also required on all WAN interfaces. + """ + wan_circuit_id: str | None + """ + The WAN circuit ID for this interface. + This is not rendered in the configuration but used for WAN + designs. + """ + connected_to_pathfinder: bool + """ + For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. + + Default value: `True` + """ + raw_eos_cli: str | None + """EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration.""" + flow_tracking: FlowTracking + """ + Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` + setting. + + Subclass of AvdModel. + """ + structured_config: StructuredConfig + """ + Custom structured config for the Port-Channel interface. + + Subclass of AvdModel. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + name: str | UndefinedType = Undefined, + description: str | None | UndefinedType = Undefined, + mode: Literal["active", "passive", "on"] | UndefinedType = Undefined, + member_interfaces: MemberInterfaces | UndefinedType = Undefined, + ip_address: str | None | UndefinedType = Undefined, + dhcp_ip: str | None | UndefinedType = Undefined, + public_ip: str | None | UndefinedType = Undefined, + encapsulation_dot1q_vlan: int | None | UndefinedType = Undefined, + dhcp_accept_default_route: bool | UndefinedType = Undefined, + enabled: bool | UndefinedType = Undefined, + peer: str | None | UndefinedType = Undefined, + peer_port_channel: str | None | UndefinedType = Undefined, + peer_ip: str | None | UndefinedType = Undefined, + bgp: Bgp | UndefinedType = Undefined, + ipv4_acl_in: str | None | UndefinedType = Undefined, + ipv4_acl_out: str | None | UndefinedType = Undefined, + static_routes: StaticRoutes | UndefinedType = Undefined, + qos_profile: str | None | UndefinedType = Undefined, + wan_carrier: str | None | UndefinedType = Undefined, + wan_circuit_id: str | None | UndefinedType = Undefined, + connected_to_pathfinder: bool | UndefinedType = Undefined, + raw_eos_cli: str | None | UndefinedType = Undefined, + flow_tracking: FlowTracking | UndefinedType = Undefined, + structured_config: StructuredConfig | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + L3PortChannelsItem. + + + Subclass of AvdModel. + + Args: + name: + Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'. + For a + Port-Channel subinterface, the parent Port-Channel interface must be defined as well. + description: + Interface description. + If not set, a default description will be configured with '[[ + ]]'. + mode: + Port-Channel mode. + Should not be set on Port-Channel subinterfaces. + member_interfaces: + Port-Channel member interfaces. + Should not be set on Port-Channel subinterfaces. + + Subclass of + AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`). + ip_address: Node IPv4 address/Mask or 'dhcp'. + dhcp_ip: + When the `ip_address` is `dhcp`, this optional field allows to indicate the expected + IPv4 address + (without mask) to be allocated on the interface if known. + This is not rendered in the configuration + but can be used for substitution of 'interface_ip' in the Access-list + set under `ipv4_acl_in` and + `ipv4_acl_out`. + public_ip: + Node IPv4 address (no mask). + + This is used to get the public IP (if known) when the device is behind + NAT. + This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP + with the following preference: + `wan_route_servers.path_groups.interfaces.ip_address` + -> + `l3_port_channels.public_ip` + -> `l3_port_channels.ip_address` + + The determined Public IP is + used by WAN routers when peering with this interface. + encapsulation_dot1q_vlan: + For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be + specified. + dhcp_accept_default_route: Accept a default route from DHCP if `ip_address` is set to `dhcp`. + enabled: Enable or Shutdown the interface. + peer: The peer device name. Used for description and documentation. + peer_port_channel: The peer device port-channel interface. Used for description and documentation. + peer_ip: + The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true + and `ip` is an IP address. + bgp: + Enforce IPv4 BGP peering for the peer + + Subclass of AvdModel. + ipv4_acl_in: + Name of the IPv4 access-list to be assigned in the ingress direction. + The access-list must be + defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + Required + for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under + `wan_carriers`. + ipv4_acl_out: + Name of the IPv4 Access-list to be assigned in the egress direction. + The access-list must be defined + under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + static_routes: + Configure IPv4 static routes pointing to `peer_ip`. + + Subclass of AvdIndexedList with + `StaticRoutesItem` items. Primary key is `prefix` (`str`). + qos_profile: QOS service profile. + wan_carrier: + The WAN carrier this interface is connected to. + This is used to infer the path-groups in which this + interface should be configured. + Unless the carrier is marked as 'trusted' under `wan_carriers`, + `ipv4_acl_in` is also required on all WAN interfaces. + wan_circuit_id: + The WAN circuit ID for this interface. + This is not rendered in the configuration but used for WAN + designs. + connected_to_pathfinder: For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. + raw_eos_cli: EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration. + flow_tracking: + Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` + setting. + + Subclass of AvdModel. + structured_config: + Custom structured config for the Port-Channel interface. + + Subclass of AvdModel. + _custom_data: _custom_data + + """ + + class L3PortChannels(AvdIndexedList[str, L3PortChannelsItem]): + """Subclass of AvdIndexedList with `L3PortChannelsItem` items. Primary key is `name` (`str`).""" + + _primary_key: ClassVar[str] = "name" + + L3PortChannels._item_type = L3PortChannelsItem + _fields: ClassVar[dict] = { "group": {"type": str}, "nodes": {"type": Nodes}, @@ -49730,6 +53650,7 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): "wan_ha": {"type": WanHa}, "dps_mss_ipv4": {"type": str, "default": "auto"}, "l3_interfaces": {"type": L3Interfaces}, + "l3_port_channels": {"type": L3PortChannels}, "data_plane_cpu_allocation_max": {"type": int}, "flow_tracker_type": {"type": str}, "_custom_data": {"type": dict}, @@ -50524,11 +54445,16 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): l3_interfaces: L3Interfaces """ L3 Interfaces to configure on the node. - Used to define the node for WAN interfaces when - `wan_carrier` is set. - Subclass of AvdIndexedList with `L3InterfacesItem` items. Primary key is - `name` (`str`). + Subclass of AvdIndexedList with `L3InterfacesItem` items. + Primary key is `name` (`str`). + """ + l3_port_channels: L3PortChannels + """ + L3 Port-Channel interfaces to configure on the node. + + Subclass of AvdIndexedList with + `L3PortChannelsItem` items. Primary key is `name` (`str`). """ data_plane_cpu_allocation_max: int | None """ @@ -50655,6 +54581,7 @@ def __init__( wan_ha: WanHa | UndefinedType = Undefined, dps_mss_ipv4: str | UndefinedType = Undefined, l3_interfaces: L3Interfaces | UndefinedType = Undefined, + l3_port_channels: L3PortChannels | UndefinedType = Undefined, data_plane_cpu_allocation_max: int | None | UndefinedType = Undefined, flow_tracker_type: Literal["sampled", "hardware"] | None | UndefinedType = Undefined, _custom_data: dict[str, Any] | UndefinedType = Undefined, @@ -51220,11 +55147,14 @@ def __init__( dps_mss_ipv4: IPv4 MSS value configured under "router path-selection" on WAN Devices. l3_interfaces: L3 Interfaces to configure on the node. - Used to define the node for WAN interfaces when - `wan_carrier` is set. - Subclass of AvdIndexedList with `L3InterfacesItem` items. Primary key is - `name` (`str`). + Subclass of AvdIndexedList with `L3InterfacesItem` items. + Primary key is `name` (`str`). + l3_port_channels: + L3 Port-Channel interfaces to configure on the node. + + Subclass of AvdIndexedList with + `L3PortChannelsItem` items. Primary key is `name` (`str`). data_plane_cpu_allocation_max: Set the maximum number of CPU used for the data plane. This setting is useful on virtual Route @@ -53197,6 +57127,550 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): L3Interfaces._item_type = L3InterfacesItem + class L3PortChannelsItem(AvdModel): + """Subclass of AvdModel.""" + + class MemberInterfacesItem(AvdModel): + """Subclass of AvdModel.""" + + class StructuredConfig(EosCliConfigGen.EthernetInterfacesItem): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "name": {"type": str}, + "description": {"type": str}, + "peer": {"type": str}, + "peer_interface": {"type": str}, + "speed": {"type": str}, + "structured_config": {"type": StructuredConfig}, + "_custom_data": {"type": dict}, + } + name: str + """ + Ethernet interface name like 'Ethernet2'. + Member interface cannot be subinterface. + """ + description: str | None + """ + Interface description for this member. + If not set, a default description will be configured with + '[[ ]]'. + """ + peer: str | None + """ + The peer device name. Used for description and documentation. + If not set, this inherits the peer + setting on the port-channel interface. + """ + peer_interface: str | None + """The peer device interface. Used for description and documentation.""" + speed: str | None + """ + Speed should be set in the format `` or `forced ` or `auto + `. + """ + structured_config: StructuredConfig + """ + Custom structured config for the member ethernet interface. + + Subclass of AvdModel. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + name: str | UndefinedType = Undefined, + description: str | None | UndefinedType = Undefined, + peer: str | None | UndefinedType = Undefined, + peer_interface: str | None | UndefinedType = Undefined, + speed: str | None | UndefinedType = Undefined, + structured_config: StructuredConfig | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + MemberInterfacesItem. + + + Subclass of AvdModel. + + Args: + name: + Ethernet interface name like 'Ethernet2'. + Member interface cannot be subinterface. + description: + Interface description for this member. + If not set, a default description will be configured with + '[[ ]]'. + peer: + The peer device name. Used for description and documentation. + If not set, this inherits the peer + setting on the port-channel interface. + peer_interface: The peer device interface. Used for description and documentation. + speed: + Speed should be set in the format `` or `forced ` or `auto + `. + structured_config: + Custom structured config for the member ethernet interface. + + Subclass of AvdModel. + _custom_data: _custom_data + + """ + + class MemberInterfaces(AvdIndexedList[str, MemberInterfacesItem]): + """Subclass of AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`).""" + + _primary_key: ClassVar[str] = "name" + + MemberInterfaces._item_type = MemberInterfacesItem + + class Bgp(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "peer_as": {"type": str}, + "ipv4_prefix_list_in": {"type": str}, + "ipv4_prefix_list_out": {"type": str}, + "_custom_data": {"type": dict}, + } + peer_as: str + """ + BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>". + For asdot notation in + YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float + number. + """ + ipv4_prefix_list_in: str | None + """ + Prefix List Name. Accept routes for only these prefixes from the peer. + Required for wan interfaces. + """ + ipv4_prefix_list_out: str | None + """ + Prefix List Name. Advertise routes for only these prefixes. + If not specified, nothing would be + advertised. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + peer_as: str | UndefinedType = Undefined, + ipv4_prefix_list_in: str | None | UndefinedType = Undefined, + ipv4_prefix_list_out: str | None | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + Bgp. + + + Subclass of AvdModel. + + Args: + peer_as: + BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>". + For asdot notation in + YAML inputs, the value must be put in quotes, to prevent it from being interpreted as a float + number. + ipv4_prefix_list_in: + Prefix List Name. Accept routes for only these prefixes from the peer. + Required for wan interfaces. + ipv4_prefix_list_out: + Prefix List Name. Advertise routes for only these prefixes. + If not specified, nothing would be + advertised. + _custom_data: _custom_data + + """ + + class StaticRoutesItem(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = {"prefix": {"type": str}, "_custom_data": {"type": dict}} + prefix: str + """IPv4_network/Mask.""" + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, *, prefix: str | UndefinedType = Undefined, _custom_data: dict[str, Any] | UndefinedType = Undefined + ) -> None: + """ + StaticRoutesItem. + + + Subclass of AvdModel. + + Args: + prefix: IPv4_network/Mask. + _custom_data: _custom_data + + """ + + class StaticRoutes(AvdIndexedList[str, StaticRoutesItem]): + """Subclass of AvdIndexedList with `StaticRoutesItem` items. Primary key is `prefix` (`str`).""" + + _primary_key: ClassVar[str] = "prefix" + + StaticRoutes._item_type = StaticRoutesItem + + class FlowTracking(AvdModel): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = {"enabled": {"type": bool}, "name": {"type": str}, "_custom_data": {"type": dict}} + enabled: bool | None + name: str | None + """Flow tracker name as defined in flow_tracking_settings.""" + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + enabled: bool | None | UndefinedType = Undefined, + name: str | None | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + FlowTracking. + + + Subclass of AvdModel. + + Args: + enabled: enabled + name: Flow tracker name as defined in flow_tracking_settings. + _custom_data: _custom_data + + """ + + class StructuredConfig(EosCliConfigGen.PortChannelInterfacesItem): + """Subclass of AvdModel.""" + + _fields: ClassVar[dict] = { + "name": {"type": str}, + "description": {"type": str}, + "mode": {"type": str, "default": "active"}, + "member_interfaces": {"type": MemberInterfaces}, + "ip_address": {"type": str}, + "dhcp_ip": {"type": str}, + "public_ip": {"type": str}, + "encapsulation_dot1q_vlan": {"type": int}, + "dhcp_accept_default_route": {"type": bool, "default": True}, + "enabled": {"type": bool, "default": True}, + "peer": {"type": str}, + "peer_port_channel": {"type": str}, + "peer_ip": {"type": str}, + "bgp": {"type": Bgp}, + "ipv4_acl_in": {"type": str}, + "ipv4_acl_out": {"type": str}, + "static_routes": {"type": StaticRoutes}, + "qos_profile": {"type": str}, + "wan_carrier": {"type": str}, + "wan_circuit_id": {"type": str}, + "connected_to_pathfinder": {"type": bool, "default": True}, + "raw_eos_cli": {"type": str}, + "flow_tracking": {"type": FlowTracking}, + "structured_config": {"type": StructuredConfig}, + "_custom_data": {"type": dict}, + } + name: str + """ + Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'. + For a + Port-Channel subinterface, the parent Port-Channel interface must be defined as well. + """ + description: str | None + """ + Interface description. + If not set, a default description will be configured with '[[ + ]]'. + """ + mode: Literal["active", "passive", "on"] + """ + Port-Channel mode. + Should not be set on Port-Channel subinterfaces. + + Default value: `"active"` + """ + member_interfaces: MemberInterfaces + """ + Port-Channel member interfaces. + Should not be set on Port-Channel subinterfaces. + + Subclass of + AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`). + """ + ip_address: str | None + """Node IPv4 address/Mask or 'dhcp'.""" + dhcp_ip: str | None + """ + When the `ip_address` is `dhcp`, this optional field allows to indicate the expected + IPv4 address + (without mask) to be allocated on the interface if known. + This is not rendered in the configuration + but can be used for substitution of 'interface_ip' in the Access-list + set under `ipv4_acl_in` and + `ipv4_acl_out`. + """ + public_ip: str | None + """ + Node IPv4 address (no mask). + + This is used to get the public IP (if known) when the device is behind + NAT. + This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP + with the following preference: + `wan_route_servers.path_groups.interfaces.ip_address` + -> + `l3_port_channels.public_ip` + -> `l3_port_channels.ip_address` + + The determined Public IP is + used by WAN routers when peering with this interface. + """ + encapsulation_dot1q_vlan: int | None + """ + For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be + specified. + """ + dhcp_accept_default_route: bool + """ + Accept a default route from DHCP if `ip_address` is set to `dhcp`. + + Default value: `True` + """ + enabled: bool + """ + Enable or Shutdown the interface. + + Default value: `True` + """ + peer: str | None + """The peer device name. Used for description and documentation.""" + peer_port_channel: str | None + """The peer device port-channel interface. Used for description and documentation.""" + peer_ip: str | None + """ + The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true + and `ip` is an IP address. + """ + bgp: Bgp + """ + Enforce IPv4 BGP peering for the peer + + Subclass of AvdModel. + """ + ipv4_acl_in: str | None + """ + Name of the IPv4 access-list to be assigned in the ingress direction. + The access-list must be + defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + Required + for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under + `wan_carriers`. + """ + ipv4_acl_out: str | None + """ + Name of the IPv4 Access-list to be assigned in the egress direction. + The access-list must be defined + under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + """ + static_routes: StaticRoutes + """ + Configure IPv4 static routes pointing to `peer_ip`. + + Subclass of AvdIndexedList with + `StaticRoutesItem` items. Primary key is `prefix` (`str`). + """ + qos_profile: str | None + """QOS service profile.""" + wan_carrier: str | None + """ + The WAN carrier this interface is connected to. + This is used to infer the path-groups in which this + interface should be configured. + Unless the carrier is marked as 'trusted' under `wan_carriers`, + `ipv4_acl_in` is also required on all WAN interfaces. + """ + wan_circuit_id: str | None + """ + The WAN circuit ID for this interface. + This is not rendered in the configuration but used for WAN + designs. + """ + connected_to_pathfinder: bool + """ + For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. + + Default value: `True` + """ + raw_eos_cli: str | None + """EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration.""" + flow_tracking: FlowTracking + """ + Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` + setting. + + Subclass of AvdModel. + """ + structured_config: StructuredConfig + """ + Custom structured config for the Port-Channel interface. + + Subclass of AvdModel. + """ + _custom_data: dict[str, Any] + + if TYPE_CHECKING: + + def __init__( + self, + *, + name: str | UndefinedType = Undefined, + description: str | None | UndefinedType = Undefined, + mode: Literal["active", "passive", "on"] | UndefinedType = Undefined, + member_interfaces: MemberInterfaces | UndefinedType = Undefined, + ip_address: str | None | UndefinedType = Undefined, + dhcp_ip: str | None | UndefinedType = Undefined, + public_ip: str | None | UndefinedType = Undefined, + encapsulation_dot1q_vlan: int | None | UndefinedType = Undefined, + dhcp_accept_default_route: bool | UndefinedType = Undefined, + enabled: bool | UndefinedType = Undefined, + peer: str | None | UndefinedType = Undefined, + peer_port_channel: str | None | UndefinedType = Undefined, + peer_ip: str | None | UndefinedType = Undefined, + bgp: Bgp | UndefinedType = Undefined, + ipv4_acl_in: str | None | UndefinedType = Undefined, + ipv4_acl_out: str | None | UndefinedType = Undefined, + static_routes: StaticRoutes | UndefinedType = Undefined, + qos_profile: str | None | UndefinedType = Undefined, + wan_carrier: str | None | UndefinedType = Undefined, + wan_circuit_id: str | None | UndefinedType = Undefined, + connected_to_pathfinder: bool | UndefinedType = Undefined, + raw_eos_cli: str | None | UndefinedType = Undefined, + flow_tracking: FlowTracking | UndefinedType = Undefined, + structured_config: StructuredConfig | UndefinedType = Undefined, + _custom_data: dict[str, Any] | UndefinedType = Undefined, + ) -> None: + """ + L3PortChannelsItem. + + + Subclass of AvdModel. + + Args: + name: + Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'. + For a + Port-Channel subinterface, the parent Port-Channel interface must be defined as well. + description: + Interface description. + If not set, a default description will be configured with '[[ + ]]'. + mode: + Port-Channel mode. + Should not be set on Port-Channel subinterfaces. + member_interfaces: + Port-Channel member interfaces. + Should not be set on Port-Channel subinterfaces. + + Subclass of + AvdIndexedList with `MemberInterfacesItem` items. Primary key is `name` (`str`). + ip_address: Node IPv4 address/Mask or 'dhcp'. + dhcp_ip: + When the `ip_address` is `dhcp`, this optional field allows to indicate the expected + IPv4 address + (without mask) to be allocated on the interface if known. + This is not rendered in the configuration + but can be used for substitution of 'interface_ip' in the Access-list + set under `ipv4_acl_in` and + `ipv4_acl_out`. + public_ip: + Node IPv4 address (no mask). + + This is used to get the public IP (if known) when the device is behind + NAT. + This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP + with the following preference: + `wan_route_servers.path_groups.interfaces.ip_address` + -> + `l3_port_channels.public_ip` + -> `l3_port_channels.ip_address` + + The determined Public IP is + used by WAN routers when peering with this interface. + encapsulation_dot1q_vlan: + For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be + specified. + dhcp_accept_default_route: Accept a default route from DHCP if `ip_address` is set to `dhcp`. + enabled: Enable or Shutdown the interface. + peer: The peer device name. Used for description and documentation. + peer_port_channel: The peer device port-channel interface. Used for description and documentation. + peer_ip: + The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true + and `ip` is an IP address. + bgp: + Enforce IPv4 BGP peering for the peer + + Subclass of AvdModel. + ipv4_acl_in: + Name of the IPv4 access-list to be assigned in the ingress direction. + The access-list must be + defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + Required + for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under + `wan_carriers`. + ipv4_acl_out: + Name of the IPv4 Access-list to be assigned in the egress direction. + The access-list must be defined + under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + static_routes: + Configure IPv4 static routes pointing to `peer_ip`. + + Subclass of AvdIndexedList with + `StaticRoutesItem` items. Primary key is `prefix` (`str`). + qos_profile: QOS service profile. + wan_carrier: + The WAN carrier this interface is connected to. + This is used to infer the path-groups in which this + interface should be configured. + Unless the carrier is marked as 'trusted' under `wan_carriers`, + `ipv4_acl_in` is also required on all WAN interfaces. + wan_circuit_id: + The WAN circuit ID for this interface. + This is not rendered in the configuration but used for WAN + designs. + connected_to_pathfinder: For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. + raw_eos_cli: EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration. + flow_tracking: + Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` + setting. + + Subclass of AvdModel. + structured_config: + Custom structured config for the Port-Channel interface. + + Subclass of AvdModel. + _custom_data: _custom_data + + """ + + class L3PortChannels(AvdIndexedList[str, L3PortChannelsItem]): + """Subclass of AvdIndexedList with `L3PortChannelsItem` items. Primary key is `name` (`str`).""" + + _primary_key: ClassVar[str] = "name" + + L3PortChannels._item_type = L3PortChannelsItem + _fields: ClassVar[dict] = { "name": {"type": str}, "downlink_pools": {"type": DownlinkPools}, @@ -53303,6 +57777,7 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): "wan_ha": {"type": WanHa}, "dps_mss_ipv4": {"type": str, "default": "auto"}, "l3_interfaces": {"type": L3Interfaces}, + "l3_port_channels": {"type": L3PortChannels}, "data_plane_cpu_allocation_max": {"type": int}, "flow_tracker_type": {"type": str}, "_custom_data": {"type": dict}, @@ -54094,11 +58569,16 @@ class L3Interfaces(AvdIndexedList[str, L3InterfacesItem]): l3_interfaces: L3Interfaces """ L3 Interfaces to configure on the node. - Used to define the node for WAN interfaces when - `wan_carrier` is set. - Subclass of AvdIndexedList with `L3InterfacesItem` items. Primary key is - `name` (`str`). + Subclass of AvdIndexedList with `L3InterfacesItem` items. + Primary key is `name` (`str`). + """ + l3_port_channels: L3PortChannels + """ + L3 Port-Channel interfaces to configure on the node. + + Subclass of AvdIndexedList with + `L3PortChannelsItem` items. Primary key is `name` (`str`). """ data_plane_cpu_allocation_max: int | None """ @@ -54225,6 +58705,7 @@ def __init__( wan_ha: WanHa | UndefinedType = Undefined, dps_mss_ipv4: str | UndefinedType = Undefined, l3_interfaces: L3Interfaces | UndefinedType = Undefined, + l3_port_channels: L3PortChannels | UndefinedType = Undefined, data_plane_cpu_allocation_max: int | None | UndefinedType = Undefined, flow_tracker_type: Literal["sampled", "hardware"] | None | UndefinedType = Undefined, _custom_data: dict[str, Any] | UndefinedType = Undefined, @@ -54788,11 +59269,14 @@ def __init__( dps_mss_ipv4: IPv4 MSS value configured under "router path-selection" on WAN Devices. l3_interfaces: L3 Interfaces to configure on the node. - Used to define the node for WAN interfaces when - `wan_carrier` is set. - Subclass of AvdIndexedList with `L3InterfacesItem` items. Primary key is - `name` (`str`). + Subclass of AvdIndexedList with `L3InterfacesItem` items. + Primary key is `name` (`str`). + l3_port_channels: + L3 Port-Channel interfaces to configure on the node. + + Subclass of AvdIndexedList with + `L3PortChannelsItem` items. Primary key is `name` (`str`). data_plane_cpu_allocation_max: Set the maximum number of CPU used for the data plane. This setting is useful on virtual Route 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 db3774dc129..b77ab51aa7b 100644 --- a/python-avd/pyavd/_eos_designs/schema/eos_designs.schema.yml +++ b/python-avd/pyavd/_eos_designs/schema/eos_designs.schema.yml @@ -1509,6 +1509,10 @@ keys: tenants.vrfs.l3_interfaces. type: dict $ref: eos_designs#/keys/fabric_flow_tracking/keys/uplinks + l3_port_channels: + description: Enable flow-tracking on all node.l3_port_channels. + type: dict + $ref: eos_designs#/keys/fabric_flow_tracking/keys/uplinks dps_interfaces: description: Enable flow-tracking on all dps_interfaces. type: dict @@ -9451,9 +9455,7 @@ $defs: $ref: eos_designs#/$defs/node_type_l3_interfaces documentation_options: table: node-type-l3-interfaces-configuration - description: 'L3 Interfaces to configure on the node. - - Used to define the node for WAN interfaces when `wan_carrier` is set.' + description: L3 Interfaces to configure on the node. items: type: dict keys: @@ -9462,6 +9464,12 @@ $defs: description: 'L3 interface profile name. Profile defined under `l3_interface_profiles`. ' + l3_port_channels: + type: list + $ref: eos_designs#/$defs/node_type_l3_port_channels + documentation_options: + table: node-type-l3-port-channels-configuration + description: L3 Port-Channel interfaces to configure on the node. data_plane_cpu_allocation_max: documentation_options: table: system-settings @@ -9570,7 +9578,7 @@ $defs: name like ''Ethernet2.42''. For a subinterface, the parent physical interface is automatically created.' - pattern: Ethernet[\d/]+(.[\d]+)? + pattern: Ethernet[\d/]+(\.[\d]+)? description: type: str description: 'Interface description. @@ -9746,6 +9754,221 @@ $defs: hide_keys: true description: Custom structured config for the Ethernet interface. $ref: eos_cli_config_gen#/keys/ethernet_interfaces/items + node_type_l3_port_channels: + type: list + primary_key: name + items: + type: dict + keys: + name: + type: str + required: true + description: 'Port-Channel interface name like ''Port-Channel2'' or subinterface + name like ''Port-Channel2.42''. + + For a Port-Channel subinterface, the parent Port-Channel interface must + be defined as well.' + pattern: Port-Channel[\d/]+(\.[\d]+)? + description: + type: str + description: 'Interface description. + + If not set, a default description will be configured with ''[[ ]]''.' + mode: + type: str + description: 'Port-Channel mode. + + Should not be set on Port-Channel subinterfaces.' + valid_values: + - active + - passive + - 'on' + default: active + member_interfaces: + description: 'Port-Channel member interfaces. + + Should not be set on Port-Channel subinterfaces.' + type: list + primary_key: name + items: + type: dict + keys: + name: + type: str + required: true + description: 'Ethernet interface name like ''Ethernet2''. + + Member interface cannot be subinterface.' + pattern: Ethernet[\d/]+ + description: + type: str + description: 'Interface description for this member. + + If not set, a default description will be configured with ''[[ + ]]''.' + peer: + type: str + description: 'The peer device name. Used for description and documentation. + + If not set, this inherits the peer setting on the port-channel interface.' + peer_interface: + type: str + description: The peer device interface. Used for description and documentation. + speed: + type: str + description: Speed should be set in the format `` + or `forced ` or `auto `. + structured_config: + type: dict + documentation_options: + hide_keys: true + description: Custom structured config for the member ethernet interface. + $ref: eos_cli_config_gen#/keys/ethernet_interfaces/items + ip_address: + type: str + description: Node IPv4 address/Mask or 'dhcp'. + dhcp_ip: + type: str + description: 'When the `ip_address` is `dhcp`, this optional field allows + to indicate the expected + + IPv4 address (without mask) to be allocated on the interface if known. + + This is not rendered in the configuration but can be used for substitution + of ''interface_ip'' in the Access-list + + set under `ipv4_acl_in` and `ipv4_acl_out`.' + public_ip: + type: str + description: "Node IPv4 address (no mask).\n\nThis is used to get the public + IP (if known) when the device is behind NAT.\nThis is only used for `wan_rr` + routers (AutoVPN RRs and Pathfinders) to determine the Public IP\nwith + the following preference:\n `wan_route_servers.path_groups.interfaces.ip_address`\n + \ -> `l3_port_channels.public_ip`\n -> `l3_port_channels.ip_address`\n\nThe + determined Public IP is used by WAN routers when peering with this interface." + encapsulation_dot1q_vlan: + description: For subinterfaces the dot1q vlan is derived from the interface + name by default, but can also be specified. + type: int + convert_types: + - str + min: 1 + max: 4094 + dhcp_accept_default_route: + type: bool + default: true + description: Accept a default route from DHCP if `ip_address` is set to + `dhcp`. + enabled: + type: bool + default: true + description: Enable or Shutdown the interface. + peer: + type: str + description: The peer device name. Used for description and documentation. + peer_port_channel: + type: str + description: The peer device port-channel interface. Used for description + and documentation. + peer_ip: + type: str + description: The peer device IPv4 address (no mask). Used as default route + gateway if `set_default_route` is true and `ip` is an IP address. + bgp: + type: dict + description: Enforce IPv4 BGP peering for the peer + keys: + peer_as: + type: str + required: true + convert_types: + - int + description: 'BGP AS <1-4294967295> or AS number in asdot notation "<1-65535>.<0-65535>". + + For asdot notation in YAML inputs, the value must be put in quotes, + to prevent it from being interpreted as a float number.' + ipv4_prefix_list_in: + type: str + description: 'Prefix List Name. Accept routes for only these prefixes + from the peer. + + Required for wan interfaces.' + ipv4_prefix_list_out: + type: str + description: 'Prefix List Name. Advertise routes for only these prefixes. + + If not specified, nothing would be advertised.' + ipv4_acl_in: + description: 'Name of the IPv4 access-list to be assigned in the ingress + direction. + + The access-list must be defined under `ipv4_acls` and supports field substitution + for "interface_ip" and "peer_ip". + + Required for all WAN interfaces (`wan_carrier` is set) unless the carrier + is marked as ''trusted'' under `wan_carriers`.' + type: str + convert_types: + - int + ipv4_acl_out: + description: 'Name of the IPv4 Access-list to be assigned in the egress + direction. + + The access-list must be defined under `ipv4_acls` and supports field substitution + for "interface_ip" and "peer_ip".' + type: str + convert_types: + - int + static_routes: + description: Configure IPv4 static routes pointing to `peer_ip`. + type: list + min_length: 1 + primary_key: prefix + items: + type: dict + keys: + prefix: + type: str + description: IPv4_network/Mask. + qos_profile: + type: str + description: QOS service profile. + wan_carrier: + type: str + description: 'The WAN carrier this interface is connected to. + + This is used to infer the path-groups in which this interface should be + configured. + + Unless the carrier is marked as ''trusted'' under `wan_carriers`, `ipv4_acl_in` + is also required on all WAN interfaces.' + wan_circuit_id: + type: str + convert_types: + - int + description: 'The WAN circuit ID for this interface. + + This is not rendered in the configuration but used for WAN designs.' + connected_to_pathfinder: + type: bool + default: true + description: For a WAN interface (`wan_carrier` is set), allow to disable + the static tunnel towards Pathfinders. + raw_eos_cli: + type: str + description: EOS CLI rendered directly on the Port-Channel interface in + the final EOS configuration. + flow_tracking: + type: dict + $ref: eos_designs#/$defs/flow_tracking_link + description: Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` + setting. + structured_config: + type: dict + documentation_options: + hide_keys: true + description: Custom structured config for the Port-Channel interface. + $ref: eos_cli_config_gen#/keys/port_channel_interfaces/items p2p_links: type: list items: 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 f00202794a3..cc0e8010d22 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 @@ -1400,7 +1400,6 @@ $defs: table: node-type-l3-interfaces-configuration description: |- L3 Interfaces to configure on the node. - Used to define the node for WAN interfaces when `wan_carrier` is set. items: type: dict keys: @@ -1408,6 +1407,13 @@ $defs: type: str description: | L3 interface profile name. Profile defined under `l3_interface_profiles`. + l3_port_channels: + type: list + $ref: "eos_designs#/$defs/node_type_l3_port_channels" + documentation_options: + table: node-type-l3-port-channels-configuration + description: |- + L3 Port-Channel interfaces to configure on the node. data_plane_cpu_allocation_max: documentation_options: table: system-settings diff --git a/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_node_type_l3_interfaces.schema.yml b/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_node_type_l3_interfaces.schema.yml index c8ec13cb031..21caa4463fd 100644 --- a/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_node_type_l3_interfaces.schema.yml +++ b/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_node_type_l3_interfaces.schema.yml @@ -17,7 +17,7 @@ $defs: description: |- Ethernet interface name like 'Ethernet2' or subinterface name like 'Ethernet2.42'. For a subinterface, the parent physical interface is automatically created. - pattern: "Ethernet[\\d/]+(.[\\d]+)?" + pattern: "Ethernet[\\d/]+(\\.[\\d]+)?" description: type: str description: |- diff --git a/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_node_type_l3_port_channels.schema.yml b/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_node_type_l3_port_channels.schema.yml new file mode 100644 index 00000000000..a2a8a079bc9 --- /dev/null +++ b/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_node_type_l3_port_channels.schema.yml @@ -0,0 +1,235 @@ +# Copyright (c) 2023-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. +# yaml-language-server: $schema=../../../_schema/avd_meta_schema.json +# Line above is used by RedHat's YAML Schema vscode extension +# Use Ctrl + Space to get suggestions for every field. Autocomplete will pop up after typing 2 letters. +type: dict +$defs: + node_type_l3_port_channels: + type: list + primary_key: name + items: + type: dict + keys: + name: + type: str + required: true + description: |- + Port-Channel interface name like 'Port-Channel2' or subinterface name like 'Port-Channel2.42'. + For a Port-Channel subinterface, the parent Port-Channel interface must be defined as well. + pattern: "Port-Channel[\\d/]+(\\.[\\d]+)?" + description: + type: str + description: |- + Interface description. + If not set, a default description will be configured with '[[ ]]'. + mode: + type: str + description: |- + Port-Channel mode. + Should not be set on Port-Channel subinterfaces. + valid_values: + - "active" + - "passive" + - "on" + default: "active" + member_interfaces: + description: |- + Port-Channel member interfaces. + Should not be set on Port-Channel subinterfaces. + type: list + primary_key: name + items: + type: dict + keys: + name: + type: str + required: true + description: |- + Ethernet interface name like 'Ethernet2'. + Member interface cannot be subinterface. + pattern: "Ethernet[\\d/]+" + description: + type: str + description: |- + Interface description for this member. + If not set, a default description will be configured with '[[ ]]'. + peer: + type: str + description: |- + The peer device name. Used for description and documentation. + If not set, this inherits the peer setting on the port-channel interface. + peer_interface: + type: str + description: |- + The peer device interface. Used for description and documentation. + speed: + type: str + description: |- + Speed should be set in the format `` or `forced ` or `auto `. + structured_config: + type: dict + documentation_options: + hide_keys: true + description: |- + Custom structured config for the member ethernet interface. + $ref: "eos_cli_config_gen#/keys/ethernet_interfaces/items" + ip_address: + type: str + description: Node IPv4 address/Mask or 'dhcp'. + dhcp_ip: + type: str + description: |- + When the `ip_address` is `dhcp`, this optional field allows to indicate the expected + IPv4 address (without mask) to be allocated on the interface if known. + This is not rendered in the configuration but can be used for substitution of 'interface_ip' in the Access-list + set under `ipv4_acl_in` and `ipv4_acl_out`. + public_ip: + type: str + description: |- + Node IPv4 address (no mask). + + This is used to get the public IP (if known) when the device is behind NAT. + This is only used for `wan_rr` routers (AutoVPN RRs and Pathfinders) to determine the Public IP + with the following preference: + `wan_route_servers.path_groups.interfaces.ip_address` + -> `l3_port_channels.public_ip` + -> `l3_port_channels.ip_address` + + The determined Public IP is used by WAN routers when peering with this interface. + encapsulation_dot1q_vlan: + description: For subinterfaces the dot1q vlan is derived from the interface name by default, but can also be specified. + type: int + convert_types: + - str + min: 1 + max: 4094 + dhcp_accept_default_route: + type: bool + default: true + description: Accept a default route from DHCP if `ip_address` is set to `dhcp`. + enabled: + type: bool + default: true + description: Enable or Shutdown the interface. + peer: + type: str + description: |- + The peer device name. Used for description and documentation. + peer_port_channel: + type: str + description: |- + The peer device port-channel interface. Used for description and documentation. + peer_ip: + type: str + description: |- + The peer device IPv4 address (no mask). Used as default route gateway if `set_default_route` is true and `ip` is an IP address. + bgp: + type: dict + description: |- + Enforce IPv4 BGP peering for the peer + keys: + peer_as: + type: str + required: true + convert_types: + - int + description: 'BGP AS <1-4294967295> or AS number in asdot notation + "<1-65535>.<0-65535>". + + For asdot notation in YAML inputs, the value must be put in + quotes, to prevent it from being interpreted as a float number.' + ipv4_prefix_list_in: + type: str + description: |- + Prefix List Name. Accept routes for only these prefixes from the peer. + Required for wan interfaces. + ipv4_prefix_list_out: + type: str + description: |- + Prefix List Name. Advertise routes for only these prefixes. + If not specified, nothing would be advertised. + ipv4_acl_in: + description: |- + Name of the IPv4 access-list to be assigned in the ingress direction. + The access-list must be defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + Required for all WAN interfaces (`wan_carrier` is set) unless the carrier is marked as 'trusted' under `wan_carriers`. + type: str + convert_types: + - int + ipv4_acl_out: + description: |- + Name of the IPv4 Access-list to be assigned in the egress direction. + The access-list must be defined under `ipv4_acls` and supports field substitution for "interface_ip" and "peer_ip". + type: str + convert_types: + - int + static_routes: + description: Configure IPv4 static routes pointing to `peer_ip`. + type: list + min_length: 1 + primary_key: prefix + items: + type: dict + keys: + prefix: + type: str + description: IPv4_network/Mask. + qos_profile: + type: str + description: QOS service profile. + wan_carrier: + type: str + description: |- + The WAN carrier this interface is connected to. + This is used to infer the path-groups in which this interface should be configured. + Unless the carrier is marked as 'trusted' under `wan_carriers`, `ipv4_acl_in` is also required on all WAN interfaces. + wan_circuit_id: + type: str + convert_types: + - int + description: |- + The WAN circuit ID for this interface. + This is not rendered in the configuration but used for WAN designs. + connected_to_pathfinder: + type: bool + default: true + description: |- + For a WAN interface (`wan_carrier` is set), allow to disable the static tunnel towards Pathfinders. + # TODO: Enable this after EOS side change to support 'direct' internet exit using port-channel interface + # cv_pathfinder_internet_exit: + # description: |- + # PREVIEW: This key is in preview mode + # type: dict + # keys: + # policies: + # type: list + # primary_key: name + # description: List of Internet-exit policies using this interface as exit. + # items: + # type: dict + # keys: + # name: + # type: str + # description: Internet-exit policy name. + # tunnel_interface_numbers: + # type: str + # description: |- + # Number range to use for Tunnel interfaces to an internet-exit service provider using this local interface. + # Examples: '1-3' or '100,200,300' + raw_eos_cli: + type: str + description: EOS CLI rendered directly on the Port-Channel interface in the final EOS configuration. + flow_tracking: + type: dict + $ref: "eos_designs#/$defs/flow_tracking_link" + description: |- + Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.l3_port_channels` setting. + structured_config: + type: dict + documentation_options: + hide_keys: true + description: |- + Custom structured config for the Port-Channel interface. + $ref: "eos_cli_config_gen#/keys/port_channel_interfaces/items" diff --git a/python-avd/pyavd/_eos_designs/schema/schema_fragments/fabric_flow_tracking.schema.yml b/python-avd/pyavd/_eos_designs/schema/schema_fragments/fabric_flow_tracking.schema.yml index 5b25f4a1e1d..fa4af77d0ba 100644 --- a/python-avd/pyavd/_eos_designs/schema/schema_fragments/fabric_flow_tracking.schema.yml +++ b/python-avd/pyavd/_eos_designs/schema/schema_fragments/fabric_flow_tracking.schema.yml @@ -50,6 +50,10 @@ keys: description: Enable flow-tracking on all node.l3_interfaces and network-services tenants.vrfs.l3_interfaces. type: dict $ref: eos_designs#/keys/fabric_flow_tracking/keys/uplinks + l3_port_channels: + description: Enable flow-tracking on all node.l3_port_channels. + type: dict + $ref: eos_designs#/keys/fabric_flow_tracking/keys/uplinks dps_interfaces: description: Enable flow-tracking on all dps_interfaces. type: dict diff --git a/python-avd/pyavd/_eos_designs/shared_utils/flow_tracking.py b/python-avd/pyavd/_eos_designs/shared_utils/flow_tracking.py index 1bb2417ce62..c5fdfdd4b4b 100644 --- a/python-avd/pyavd/_eos_designs/shared_utils/flow_tracking.py +++ b/python-avd/pyavd/_eos_designs/shared_utils/flow_tracking.py @@ -23,6 +23,7 @@ | EosDesigns.L3Edge.P2pLinksItem.FlowTracking | EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.WanHa.FlowTracking | EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3InterfacesItem.FlowTracking + | EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3PortChannelsItem.FlowTracking | EosDesigns.FabricFlowTracking.MlagInterfaces | EosDesigns.FabricFlowTracking.DpsInterfaces | EosDesigns.FabricFlowTracking.Uplinks @@ -71,6 +72,9 @@ def get_flow_tracker(self: SharedUtilsProtocol, flow_tracking: FlowTracking) -> case EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3InterfacesItem.FlowTracking(): enabled: bool = default(flow_tracking.enabled, self.inputs.fabric_flow_tracking.l3_interfaces.enabled) name: str = default(flow_tracking.name, self.inputs.fabric_flow_tracking.l3_interfaces.name) + case EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3PortChannelsItem.FlowTracking(): + enabled: bool = default(flow_tracking.enabled, self.inputs.fabric_flow_tracking.l3_port_channels.enabled) + name: str = default(flow_tracking.name, self.inputs.fabric_flow_tracking.l3_port_channels.name) case ( EosDesigns.FabricFlowTracking.MlagInterfaces() | EosDesigns.FabricFlowTracking.DpsInterfaces() diff --git a/python-avd/pyavd/_eos_designs/shared_utils/misc.py b/python-avd/pyavd/_eos_designs/shared_utils/misc.py index 52394b77062..fdb781b20cb 100644 --- a/python-avd/pyavd/_eos_designs/shared_utils/misc.py +++ b/python-avd/pyavd/_eos_designs/shared_utils/misc.py @@ -6,13 +6,14 @@ from functools import cached_property from typing import TYPE_CHECKING, Any, Protocol +from pyavd._eos_designs.schema import EosDesigns from pyavd._errors import AristaAvdError, AristaAvdInvalidInputsError, AristaAvdMissingVariableError from pyavd._utils import default, get +from pyavd.api.interface_descriptions import InterfaceDescriptionData from pyavd.j2filters import range_expand if TYPE_CHECKING: from pyavd._eos_designs.eos_designs_facts import EosDesignsFacts - from pyavd._eos_designs.schema import EosDesigns from . import SharedUtilsProtocol @@ -232,3 +233,92 @@ def _get_ipv4_acl_field_with_substitution(field_value: str, replacements: dict[s raise AristaAvdError(msg) return replacement_value + + def get_l3_generic_interface_bgp_neighbors( + self: SharedUtilsProtocol, + l3_generic_interfaces: ( + EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3Interfaces + | EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3PortChannels + ), + ) -> list: + """ + Fetches bgp neighbors for given L3 interface placeholder. + + Fetches bgp neighbors (list of dict) for all interfaces under given interface type. + 'l3_generic_interfaces' is expected to be set to either property - self.l3_interfaces or self.l3_port_channels. + """ + neighbors = [] + is_l3_interface = False + if isinstance(l3_generic_interfaces, EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3Interfaces): + is_l3_interface = True + schema_key = "l3_interfaces" + else: + # implies we intend to query all L3 Port-Channels + schema_key = "l3_port_channels" + + for interface in l3_generic_interfaces: + if not (interface.peer_ip and interface.bgp): + continue + + if interface.bgp.peer_as is None: + msg = f"'{schema_key}[{interface.name}].bgp.peer_as' needs to be set to enable BGP." + raise AristaAvdInvalidInputsError(msg) + + is_intf_wan = bool(interface.wan_carrier) + + if not interface.bgp.ipv4_prefix_list_in and is_intf_wan: + msg = f"BGP is enabled but 'bgp.ipv4_prefix_list_in' is not configured for {schema_key}[{interface.name}]" + raise AristaAvdInvalidInputsError(msg) + + description = interface.description + if not description: + if is_l3_interface: + description = self.interface_descriptions.underlay_ethernet_interface( + InterfaceDescriptionData( + shared_utils=self, + interface=interface.name, + peer=interface.peer, + peer_interface=interface.peer_interface, + wan_carrier=interface.wan_carrier, + wan_circuit_id=interface.wan_circuit_id, + ), + ) + else: + # build description for L3 Port-Channel interface + description = self.interface_descriptions.underlay_port_channel_interface( + InterfaceDescriptionData( + shared_utils=self, + interface=interface.name, + peer=interface.peer, + peer_interface=interface.peer_port_channel, + wan_carrier=interface.wan_carrier, + wan_circuit_id=interface.wan_circuit_id, + ), + ) + + neighbor = { + "ip_address": interface.peer_ip, + "remote_as": interface.bgp.peer_as, + "description": description, + } + + neighbor["ipv4_prefix_list_in"] = interface.bgp.ipv4_prefix_list_in + neighbor["ipv4_prefix_list_out"] = interface.bgp.ipv4_prefix_list_out + if is_intf_wan: + neighbor["set_no_advertise"] = True + + # The inbound route-map is only used if there is a prefix list or no-advertise + if neighbor["ipv4_prefix_list_in"] or neighbor.get("set_no_advertise") is True: + neighbor["route_map_in"] = f"RM-BGP-{neighbor['ip_address']}-IN" + neighbor["route_map_out"] = f"RM-BGP-{neighbor['ip_address']}-OUT" + + neighbors.append(neighbor) + + return neighbors + + @cached_property + def l3_bgp_neighbors(self: SharedUtilsProtocol) -> list: + """Returns the consolidated list of L3 bgp neighbors referenced by L3 Interfaces and L3 Port-Channels.""" + l3_bgp_neighbors = self.get_l3_generic_interface_bgp_neighbors(self.l3_interfaces) + l3_bgp_neighbors.extend(self.get_l3_generic_interface_bgp_neighbors(self.node_config.l3_port_channels)) + return l3_bgp_neighbors diff --git a/python-avd/pyavd/_eos_designs/shared_utils/routing.py b/python-avd/pyavd/_eos_designs/shared_utils/routing.py index 3758ad8546c..85ac883dcba 100644 --- a/python-avd/pyavd/_eos_designs/shared_utils/routing.py +++ b/python-avd/pyavd/_eos_designs/shared_utils/routing.py @@ -54,7 +54,7 @@ def bgp(self: SharedUtilsProtocol) -> bool: ) or self.bgp_in_network_services ) - ) or bool(self.l3_interfaces_bgp_neighbors) + ) or bool(self.l3_bgp_neighbors) @cached_property def router_id(self: SharedUtilsProtocol) -> str | None: diff --git a/python-avd/pyavd/_eos_designs/shared_utils/wan.py b/python-avd/pyavd/_eos_designs/shared_utils/wan.py index 27dd1dc6313..9aab848c918 100644 --- a/python-avd/pyavd/_eos_designs/shared_utils/wan.py +++ b/python-avd/pyavd/_eos_designs/shared_utils/wan.py @@ -72,26 +72,44 @@ def cv_pathfinder_transit_mode(self: SharedUtilsProtocol) -> Literal["region", " @cached_property def wan_interfaces(self: SharedUtilsProtocol) -> EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3Interfaces: """ - As a first approach, only interfaces under node config l3_interfaces can be considered as WAN interfaces. + Returns the list of the device L3 interfaces (not including port-channels) which are WAN interfaces. - This may need to be made wider. - This also may require a different format for the dictionaries inside the list. + Interfaces under node config l3_interfaces where wan_carrier is set are considered as WAN interfaces. """ if not self.is_wan_router: return EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3Interfaces() - wan_interfaces = EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3Interfaces( + return EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3Interfaces( [interface for interface in self.l3_interfaces if interface.wan_carrier] ) - if not wan_interfaces: - msg = "At least one WAN interface must be configured on a WAN router. Add WAN interfaces under `l3_interfaces` node setting with `wan_carrier` set." - raise AristaAvdError(msg) - return wan_interfaces + + @cached_property + def wan_port_channels(self: SharedUtilsProtocol) -> EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3PortChannels: + """ + Returns the list of the device Port-Channels which are WAN interfaces. + + Interfaces under node config l3_port_channels where wan_carrier is set are considered as WAN interfaces. + """ + if not self.is_wan_router: + return EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3PortChannels() + + return EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3PortChannels( + [port_channel for port_channel in self.node_config.l3_port_channels if port_channel.wan_carrier] + ) + + @cached_property + def _wan_port_channel_member_interfaces(self: SharedUtilsProtocol) -> dict: + """Dictionary with mapping of member ethernet interface to wan port_channel for a device.""" + member_intfs = {} + for port_channel_intf in self.wan_port_channels: + for member_eth_intf in port_channel_intf.member_interfaces: + member_intfs[member_eth_intf.name] = port_channel_intf.name + return member_intfs @cached_property def wan_local_carriers(self: SharedUtilsProtocol) -> list: """ - List of carriers present on this router based on the wan_interfaces with the associated WAN interfaces. + List of carriers present on this router based on the wan_interfaces and wan_port_channels with the associated WAN interfaces. interfaces: - name: ... @@ -100,17 +118,49 @@ def wan_local_carriers(self: SharedUtilsProtocol) -> list: if not self.is_wan_router: return [] - local_carriers_dict = {} - for interface in self.wan_interfaces: - interface_carrier: str = interface.wan_carrier - if interface_carrier not in local_carriers_dict: - if interface_carrier not in self.inputs.wan_carriers: - msg = f"WAN carrier {interface_carrier} is not in the available carriers defined in `wan_carriers`" + # Combining WAN carrier information from both L3 Interfaces and L3 Port-Channels configured as WAN interfaces. + if not self.wan_interfaces and not self.wan_port_channels: + msg = ( + "At least one WAN interface must be configured on a WAN router. " + "Add WAN interfaces under 'l3_interfaces' or 'l3_port_channels' node setting with 'wan_carrier' set." + ) + raise AristaAvdError(msg) + + wan_carriers_dict = {} + # Collect WAN carriers information for WAN l3_interfaces + self.update_wan_local_carriers(wan_carriers_dict, self.wan_interfaces) + # Collect WAN carriers information for WAN l3_port_channels + self.update_wan_local_carriers(wan_carriers_dict, self.wan_port_channels) + + return list(wan_carriers_dict.values()) + + def update_wan_local_carriers( + self: SharedUtilsProtocol, + local_carriers_dict: dict, + l3_generic_interfaces: ( + EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3Interfaces + | EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3PortChannels + ), + ) -> None: + """ + In-place update the dictionary of carriers relevant to this router. + + Such update is done for either `wan_interfaces` or `wan_port_channels` representing WAN interfaces. + carrier: + interfaces: + - name: ... + public_ip: ... (for route-servers the IP may come from wan_route_servers) and so on. + """ + for interface in l3_generic_interfaces: + if interface.wan_carrier not in local_carriers_dict: + if interface.wan_carrier not in self.inputs.wan_carriers: + msg = f"WAN carrier {interface.wan_carrier} is not in the available carriers defined in `wan_carriers`" raise AristaAvdInvalidInputsError(msg) - local_carriers_dict[interface_carrier] = self.inputs.wan_carriers[interface_carrier]._as_dict(include_default_values=True) - local_carriers_dict[interface_carrier]["interfaces"] = [] - local_carriers_dict[interface_carrier]["interfaces"].append( + local_carriers_dict[interface.wan_carrier] = self.inputs.wan_carriers[interface.wan_carrier]._as_dict(include_default_values=True) + local_carriers_dict[interface.wan_carrier]["interfaces"] = [] + + local_carriers_dict[interface.wan_carrier]["interfaces"].append( strip_empties_from_dict( { "name": interface.name, @@ -121,8 +171,6 @@ def wan_local_carriers(self: SharedUtilsProtocol) -> list: ), ) - return list(local_carriers_dict.values()) - @cached_property def wan_local_path_groups(self: SharedUtilsProtocol) -> EosDesigns.WanPathGroups: """ @@ -171,11 +219,13 @@ def wan_ha_peer_path_group_names(self: SharedUtilsProtocol) -> list: return [path_group["name"] for path_group in self.wan_ha_peer_path_groups] def get_public_ip_for_wan_interface( - self: SharedUtilsProtocol, interface: EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3InterfacesItem + self: SharedUtilsProtocol, + interface: ( + EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3InterfacesItem + | EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3PortChannelsItem + ), ) -> str: """ - Takes a dict which looks like `l3_interface` from node config. - If not a WAN route-server this returns public IP and if not found then the interface IP without a mask. For WAN route-servers we try to find the IP under wan_route_servers.path_groups.interfaces. diff --git a/python-avd/pyavd/_eos_designs/structured_config/base/__init__.py b/python-avd/pyavd/_eos_designs/structured_config/base/__init__.py index 38c3448e64b..bbb48bc2dba 100644 --- a/python-avd/pyavd/_eos_designs/structured_config/base/__init__.py +++ b/python-avd/pyavd/_eos_designs/structured_config/base/__init__.py @@ -107,7 +107,7 @@ def router_bgp(self) -> dict | None: ) l3_interfaces_neighbors = [] - for neighbor_info in self.shared_utils.l3_interfaces_bgp_neighbors: + for neighbor_info in self.shared_utils.l3_bgp_neighbors: neighbor = { "ip_address": neighbor_info["ip_address"], "remote_as": neighbor_info["remote_as"], @@ -699,7 +699,7 @@ def ip_http_client_source_interfaces(self) -> list | None: def prefix_lists(self) -> list | None: prefix_lists = [] prefix_lists_in_use = set() - for neighbor in self.shared_utils.l3_interfaces_bgp_neighbors: + for neighbor in self.shared_utils.l3_bgp_neighbors: if (prefix_list_in := get(neighbor, "ipv4_prefix_list_in")) and prefix_list_in not in prefix_lists_in_use: pfx_list = self._get_prefix_list(prefix_list_in)._as_dict() prefix_lists.append(pfx_list) @@ -721,7 +721,7 @@ def _get_prefix_list(self, name: str) -> EosDesigns.Ipv4PrefixListCatalogItem: @cached_property def route_maps(self) -> list | None: route_maps = [] - for neighbor in self.shared_utils.l3_interfaces_bgp_neighbors: + for neighbor in self.shared_utils.l3_bgp_neighbors: # RM-BGP--IN if prefix_list_in := get(neighbor, "ipv4_prefix_list_in"): sequence_numbers = [ diff --git a/python-avd/pyavd/_eos_designs/structured_config/base/utils.py b/python-avd/pyavd/_eos_designs/structured_config/base/utils.py index 02e81f9fd67..71d9baf2293 100644 --- a/python-avd/pyavd/_eos_designs/structured_config/base/utils.py +++ b/python-avd/pyavd/_eos_designs/structured_config/base/utils.py @@ -65,7 +65,7 @@ def _build_source_interfaces( @cached_property def _router_bgp_redistribute_routes(self: AvdStructuredConfigBaseProtocol) -> dict | None: """Return structured config for router_bgp.redistribute.""" - if not (self.shared_utils.underlay_bgp or self.shared_utils.is_wan_router or self.shared_utils.l3_interfaces_bgp_neighbors): + if not (self.shared_utils.underlay_bgp or self.shared_utils.is_wan_router or self.shared_utils.l3_bgp_neighbors): return None if self.shared_utils.overlay_routing_protocol != "none" and self.inputs.underlay_filter_redistribute_connected: diff --git a/python-avd/pyavd/_eos_designs/structured_config/metadata/cv_tags.py b/python-avd/pyavd/_eos_designs/structured_config/metadata/cv_tags.py index a3609dae902..e811c8fefae 100644 --- a/python-avd/pyavd/_eos_designs/structured_config/metadata/cv_tags.py +++ b/python-avd/pyavd/_eos_designs/structured_config/metadata/cv_tags.py @@ -11,6 +11,7 @@ if TYPE_CHECKING: from pyavd._eos_cli_config_gen.schema import EosCliConfigGen + from pyavd._eos_designs.schema import EosDesigns from . import AvdStructuredConfigMetadataProtocol @@ -185,11 +186,23 @@ def _get_interface_tags(self: AvdStructuredConfigMetadataProtocol) -> list: if tags: interface_tags.append({"interface": ethernet_interface.name, "tags": tags}) + # handle tags for L3 port-channel interfaces (cv_pathfinder use case) + for port_channel_intf in self.structured_config.port_channel_interfaces: + tags = [] + if self.shared_utils.is_cv_pathfinder_router: + tags.extend(self._get_cv_pathfinder_interface_tags(port_channel_intf)) + if tags: + interface_tags.append({"interface": port_channel_intf.name, "tags": tags}) + return interface_tags - def _get_cv_pathfinder_interface_tags(self: AvdStructuredConfigMetadataProtocol, ethernet_interface: EosCliConfigGen.EthernetInterfacesItem) -> list: + def _get_cv_pathfinder_interface_tags( + self: AvdStructuredConfigMetadataProtocol, generic_interface: EosCliConfigGen.EthernetInterfacesItem | EosCliConfigGen.PortChannelInterfacesItem + ) -> list: """ - Return list of device_tags for cv_pathfinder solution. + Return list of interface tags for cv_pathfinder solution. + + generic_interface is either ethernet or port_channel interface. Example: [ {"name": "Type", <"lan" or "wan">}, @@ -197,14 +210,33 @@ def _get_cv_pathfinder_interface_tags(self: AvdStructuredConfigMetadataProtocol, {"name": "Circuit", } ]. """ - if ethernet_interface.name in self.shared_utils.wan_interfaces: - wan_interface = self.shared_utils.wan_interfaces[ethernet_interface.name] - return strip_empties_from_list( - [ - self._tag_dict("Type", "wan"), - self._tag_dict("Carrier", wan_interface.wan_carrier), - self._tag_dict("Circuit", wan_interface.wan_circuit_id), - ], - ) - + if generic_interface.name in self.shared_utils.wan_interfaces: + wan_interface = self.shared_utils.wan_interfaces[generic_interface.name] + return self._get_cv_pathfinder_wan_interface_tags(wan_interface) + if generic_interface.name in self.shared_utils.wan_port_channels: + wan_port_channel_intf = self.shared_utils.wan_port_channels[generic_interface.name] + return self._get_cv_pathfinder_wan_interface_tags(wan_port_channel_intf) + # Check if input eth interface is member of any L3 Port-Channel wan interface + # if so, skip generation of interface tags for such member interface. + # TODO: Consider if we should skip this for all port-channel members, + # since we would now set it on the port-channel instead. + if generic_interface.name in self.shared_utils._wan_port_channel_member_interfaces: + return [] return [self._tag_dict("Type", "lan")] + + # Generate wan interface tags while accounting for wan interface to be either L3 interface or L3 Port-Channel type + def _get_cv_pathfinder_wan_interface_tags( + self: AvdStructuredConfigMetadataProtocol, + wan_interface: ( + EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3InterfacesItem + | EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3PortChannelsItem + ), + ) -> list: + """Return list of wan interface tags for cv_pathfinder solution for a given wan interface.""" + return strip_empties_from_list( + [ + self._tag_dict("Type", "wan"), + self._tag_dict("Carrier", wan_interface.wan_carrier), + self._tag_dict("Circuit", wan_interface.wan_circuit_id), + ], + ) diff --git a/python-avd/pyavd/_eos_designs/structured_config/network_services/utils_wan.py b/python-avd/pyavd/_eos_designs/structured_config/network_services/utils_wan.py index 28eb7ac9c46..eeedd851fd7 100644 --- a/python-avd/pyavd/_eos_designs/structured_config/network_services/utils_wan.py +++ b/python-avd/pyavd/_eos_designs/structured_config/network_services/utils_wan.py @@ -624,19 +624,21 @@ def _filtered_internet_exit_policies_and_connections( internet_exit_policies = [] for internet_exit_policy in candidate_internet_exit_policies: - local_interfaces = EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3Interfaces( + local_wan_l3_interfaces = EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3Interfaces( [ wan_interface for wan_interface in self.shared_utils.wan_interfaces if internet_exit_policy.name in wan_interface.cv_pathfinder_internet_exit.policies ] ) - if not local_interfaces: + if not local_wan_l3_interfaces: # No local interface for this policy + # implies policy present in input yml, but not associated with any interface yet # TODO: Decide if we should raise here instead continue - - connections = self.get_internet_exit_connections(internet_exit_policy, local_interfaces) + # fetch connections associated with given internet exit policy that + # applies to one or more wan interfaces + connections = self.get_internet_exit_connections(internet_exit_policy, local_wan_l3_interfaces) internet_exit_policies.append((internet_exit_policy, connections)) return internet_exit_policies diff --git a/python-avd/pyavd/_eos_designs/structured_config/overlay/stun.py b/python-avd/pyavd/_eos_designs/structured_config/overlay/stun.py index a8b53bca23c..4e912215540 100644 --- a/python-avd/pyavd/_eos_designs/structured_config/overlay/stun.py +++ b/python-avd/pyavd/_eos_designs/structured_config/overlay/stun.py @@ -29,6 +29,8 @@ def stun(self: AvdStructuredConfigOverlayProtocol) -> dict | None: stun = {} if self.shared_utils.is_wan_server: local_interfaces = [wan_interface.name for wan_interface in self.shared_utils.wan_interfaces] + local_wan_port_channels = [wan_port_channel.name for wan_port_channel in self.shared_utils.wan_port_channels] + local_interfaces.extend(local_wan_port_channels) stun["server"] = { "local_interfaces": local_interfaces, "ssl_profile": self.shared_utils.wan_stun_dtls_profile_name, diff --git a/python-avd/pyavd/_eos_designs/structured_config/underlay/ethernet_interfaces.py b/python-avd/pyavd/_eos_designs/structured_config/underlay/ethernet_interfaces.py index 8a298a47f1b..d26636a2d67 100644 --- a/python-avd/pyavd/_eos_designs/structured_config/underlay/ethernet_interfaces.py +++ b/python-avd/pyavd/_eos_designs/structured_config/underlay/ethernet_interfaces.py @@ -305,6 +305,22 @@ def ethernet_interfaces(self: AvdStructuredConfigUnderlayProtocol) -> list | Non context_keys=["name", "peer", "peer_interface"], ) + # Member ethernet ports for Port-Channel interface + for l3_port_channel in self.shared_utils.node_config.l3_port_channels: + # sub-interface for l3_port_channel cannot have member eth ports + # skip any logic to generate member port config for such sub-interfaces + if "." in l3_port_channel.name: + continue + member_eth_intfs = self._get_l3_port_channel_member_ports_cfg(l3_port_channel) + for member_eth_intf in member_eth_intfs: + append_if_not_duplicate( + list_of_dicts=ethernet_interfaces, + primary_key="name", + new_dict=member_eth_intf, + context=f"Ethernet interface defined under 'member_interfaces' for {self.shared_utils.node_type_key_data.key} l3_port_channels", + context_keys=["name", "peer", "peer_interface"], + ) + if ethernet_interfaces: return ethernet_interfaces diff --git a/python-avd/pyavd/_eos_designs/structured_config/underlay/ip_access_lists.py b/python-avd/pyavd/_eos_designs/structured_config/underlay/ip_access_lists.py index 737b0be4fe2..c575df49870 100644 --- a/python-avd/pyavd/_eos_designs/structured_config/underlay/ip_access_lists.py +++ b/python-avd/pyavd/_eos_designs/structured_config/underlay/ip_access_lists.py @@ -4,6 +4,7 @@ from __future__ import annotations from functools import cached_property +from itertools import chain from typing import TYPE_CHECKING, Protocol from pyavd._utils import append_if_not_duplicate @@ -25,15 +26,15 @@ def ip_access_lists(self: AvdStructuredConfigUnderlayProtocol) -> list | None: """ Return structured config for ip_access_lists. - Covers ipv4_acl_in/out defined under node l3_interfaces. + Covers ipv4_acl_in/out defined under node l3_interfaces or l3_port_channels. """ - if not self._l3_interface_acls: + if not self._l3_interface_acls and not self._l3_port_channel_acls: return None ip_access_lists = [] - - for interface_acls in self._l3_interface_acls.values(): + context_str = "IPv4 Access lists for node l3_interfaces or l3_port_channels" + for interface_acls in chain(self._l3_interface_acls.values(), self._l3_port_channel_acls.values()): for acl in interface_acls.values(): - append_if_not_duplicate(ip_access_lists, "name", acl, context="IPv4 Access lists for node l3_interfaces", context_keys=["name"]) + append_if_not_duplicate(ip_access_lists, "name", acl, context=context_str, context_keys=["name"]) return natural_sort(ip_access_lists, "name") diff --git a/python-avd/pyavd/_eos_designs/structured_config/underlay/port_channel_interfaces.py b/python-avd/pyavd/_eos_designs/structured_config/underlay/port_channel_interfaces.py index 0d0e9c42d80..9cda227b5e7 100644 --- a/python-avd/pyavd/_eos_designs/structured_config/underlay/port_channel_interfaces.py +++ b/python-avd/pyavd/_eos_designs/structured_config/underlay/port_channel_interfaces.py @@ -7,8 +7,10 @@ from typing import TYPE_CHECKING, Protocol from pyavd._eos_cli_config_gen.schema import EosCliConfigGen +from pyavd._errors import AristaAvdInvalidInputsError from pyavd._utils import append_if_not_duplicate, get, short_esi_to_route_target, strip_null_from_data from pyavd.api.interface_descriptions import InterfaceDescriptionData +from pyavd.j2filters import natural_sort if TYPE_CHECKING: from . import AvdStructuredConfigUnderlayProtocol @@ -111,6 +113,49 @@ def port_channel_interfaces(self: AvdStructuredConfigUnderlayProtocol) -> list | port_channel_interfaces.append(port_channel_interface) + # Support l3_port_channels including sub-interfaces + subif_parent_port_channel_names = set() + regular_l3_port_channel_names = set() + for l3_port_channel in self.shared_utils.node_config.l3_port_channels: + interface_name = l3_port_channel.name + is_subinterface = "." in interface_name + if not is_subinterface: + # This is a regular Port-Channel (not sub-interface) + regular_l3_port_channel_names.add(interface_name) + continue + # This is a subinterface for a port-channel interface. + # We need to ensure that parent port-channel interface is also included explicitly + # within list of Port-Channel interfaces. + parent_port_channel_name = interface_name.split(".", maxsplit=1)[0] + subif_parent_port_channel_names.add(parent_port_channel_name) + if l3_port_channel.member_interfaces: + msg = f"L3 Port-Channel sub-interface '{interface_name}' has 'member_interfaces' set. This is not a valid setting." + raise AristaAvdInvalidInputsError(msg) + if l3_port_channel._get("mode"): + # implies 'mode' is set when not applicable for a sub-interface + msg = f"L3 Port-Channel sub-interface '{interface_name}' has 'mode' set. This is not a valid setting." + raise AristaAvdInvalidInputsError(msg) + + # Sanity check if there are any sub-interfaces for which parent Port-channel is not explicitly specified + if missing_parent_port_channels := subif_parent_port_channel_names.difference(regular_l3_port_channel_names): + msg = ( + f"One or more L3 Port-Channels '{', '.join(natural_sort(missing_parent_port_channels))}' " + "need to be specified as they have sub-interfaces referencing them." + ) + raise AristaAvdInvalidInputsError(msg) + + # Now that validation is complete, we can make another pass at all l3_port_channels + # (subinterfaces or otherwise) and generate their structured config. + for l3_port_channel in self.shared_utils.node_config.l3_port_channels: + port_channel_interface = self._get_l3_port_channel_cfg(l3_port_channel) + append_if_not_duplicate( + list_of_dicts=port_channel_interfaces, + primary_key="name", + new_dict=port_channel_interface, + context=f"L3 Port-Channel interfaces defined under {self.shared_utils.node_type_key_data.key} l3_port_channels", + context_keys=["name", "peer", "peer_port_channel"], + ) + # WAN HA interface for direct connection if (port_channel_interface := self._get_direct_ha_port_channel_interface()) is not None: append_if_not_duplicate( diff --git a/python-avd/pyavd/_eos_designs/structured_config/underlay/static_routes.py b/python-avd/pyavd/_eos_designs/structured_config/underlay/static_routes.py index 2a2ddc17a2c..e0edaa6dd3a 100644 --- a/python-avd/pyavd/_eos_designs/structured_config/underlay/static_routes.py +++ b/python-avd/pyavd/_eos_designs/structured_config/underlay/static_routes.py @@ -4,6 +4,7 @@ from __future__ import annotations from functools import cached_property +from itertools import chain from typing import TYPE_CHECKING, Protocol from pyavd._errors import AristaAvdInvalidInputsError @@ -25,21 +26,22 @@ def static_routes(self: AvdStructuredConfigUnderlayProtocol) -> list[dict] | Non Returns structured config for static_routes. Consist of - - static_routes configured under node type l3 interfaces + - static_routes configured under node type l3_interfaces and l3_port_channels """ static_routes = [] - - for l3_interface in self.shared_utils.l3_interfaces: - if not l3_interface.static_routes: + for l3_generic_interface in chain(self.shared_utils.l3_interfaces, self.shared_utils.node_config.l3_port_channels): + if not l3_generic_interface.static_routes: continue - if not l3_interface.peer_ip: - msg = f"Cannot set a static_route route for interface {l3_interface.name} because 'peer_ip' is missing." + if not l3_generic_interface.peer_ip: + # TODO: add better context to error message once source is available + # to hint whether interface is L3 interface vs L3 Port-Channel + msg = f"Cannot set a static_route route for interface {l3_generic_interface.name} because 'peer_ip' is missing." raise AristaAvdInvalidInputsError(msg) static_routes.extend( - {"destination_address_prefix": l3_interface_static_route.prefix, "gateway": l3_interface.peer_ip} - for l3_interface_static_route in l3_interface.static_routes + {"destination_address_prefix": l3_generic_interface_static_route.prefix, "gateway": l3_generic_interface.peer_ip} + for l3_generic_interface_static_route in l3_generic_interface.static_routes ) if static_routes: diff --git a/python-avd/pyavd/_eos_designs/structured_config/underlay/utils.py b/python-avd/pyavd/_eos_designs/structured_config/underlay/utils.py index 6c1b653a1d0..f06813f28a4 100644 --- a/python-avd/pyavd/_eos_designs/structured_config/underlay/utils.py +++ b/python-avd/pyavd/_eos_designs/structured_config/underlay/utils.py @@ -7,14 +7,13 @@ from typing import TYPE_CHECKING, Protocol from pyavd._eos_cli_config_gen.schema import EosCliConfigGen +from pyavd._eos_designs.schema import EosDesigns from pyavd._errors import AristaAvdError, AristaAvdMissingVariableError from pyavd._utils import Undefined, default, get, get_ip_from_ip_prefix, get_item, strip_empties_from_dict from pyavd.api.interface_descriptions import InterfaceDescriptionData from pyavd.j2filters import natural_sort, range_expand if TYPE_CHECKING: - from pyavd._eos_designs.schema import EosDesigns - from . import AvdStructuredConfigUnderlayProtocol @@ -149,8 +148,11 @@ def _uplinks(self: AvdStructuredConfigUnderlayProtocol) -> list: def _get_l3_interface_cfg( self: AvdStructuredConfigUnderlayProtocol, l3_interface: EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3InterfacesItem - ) -> dict | None: + ) -> dict: """Returns structured_configuration for one L3 interface.""" + # build common portion of the interface cfg + interface = self._get_l3_common_interface_cfg(l3_interface) + interface_description = l3_interface.description if not interface_description: interface_description = self.shared_utils.interface_descriptions.underlay_ethernet_interface( @@ -163,42 +165,19 @@ def _get_l3_interface_cfg( wan_circuit_id=l3_interface.wan_circuit_id, ), ) - - # TODO: catch if ip_address is not valid or not dhcp - if not l3_interface.ip_address: - msg = f"{self.shared_utils.node_type_key_data.key}.nodes[name={self.shared_utils.hostname}].l3_interfaces[name={l3_interface.name}].ip_address" - raise AristaAvdMissingVariableError(msg) - - interface = { - "name": l3_interface.name, - "peer_type": "l3_interface", - "peer": l3_interface.peer, - "peer_interface": l3_interface.peer_interface, - "ip_address": l3_interface.ip_address, - "shutdown": not l3_interface.enabled, - "switchport": {"enabled": False if "." not in l3_interface.name else None}, - "description": interface_description, - "speed": l3_interface.speed, - "service_profile": l3_interface.qos_profile, - "access_group_in": get(self._l3_interface_acls, f"{l3_interface.name}..ipv4_acl_in..name", separator=".."), - "access_group_out": get(self._l3_interface_acls, f"{l3_interface.name}..ipv4_acl_out..name", separator=".."), - "eos_cli": l3_interface.raw_eos_cli, - "flow_tracker": self.shared_utils.get_flow_tracker(l3_interface.flow_tracking), - } + interface["description"] = interface_description + interface["peer_type"] = "l3_interface" + interface["peer_interface"] = l3_interface.peer_interface + interface["speed"] = l3_interface.speed if l3_interface.structured_config: self.custom_structured_configs.nested.ethernet_interfaces.obtain(l3_interface.name)._deepmerge( l3_interface.structured_config, list_merge=self.custom_structured_configs.list_merge_strategy ) - if self.inputs.fabric_sflow.l3_interfaces is not None: interface["sflow"] = {"enable": self.inputs.fabric_sflow.l3_interfaces} - - if "." in l3_interface.name: - interface["encapsulation_dot1q"] = {"vlan": default(l3_interface.encapsulation_dot1q_vlan, int(l3_interface.name.split(".", maxsplit=1)[-1]))} - - if l3_interface.ip_address == "dhcp" and l3_interface.dhcp_accept_default_route: - interface["dhcp_client_accept_default_route"] = True + interface["access_group_in"] = get(self._l3_interface_acls, f"{l3_interface.name}..ipv4_acl_in..name", separator="..") + interface["access_group_out"] = get(self._l3_interface_acls, f"{l3_interface.name}..ipv4_acl_out..name", separator="..") if ( self.shared_utils.is_wan_router @@ -208,12 +187,138 @@ def _get_l3_interface_cfg( ): msg = ( "'ipv4_acl_in' must be set on WAN interfaces where 'wan_carrier' is set, unless the carrier is configured as 'trusted' " - f"under 'wan_carriers'. 'ipv4_acl_in' is missing on interface '{l3_interface.name}'." + f"under 'wan_carriers'. 'ipv4_acl_in' is missing on L3 interface '{l3_interface.name}'." ) raise AristaAvdError(msg) + return strip_empties_from_dict(interface) + + def _get_l3_port_channel_cfg( + self: AvdStructuredConfigUnderlayProtocol, l3_port_channel: EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3PortChannelsItem + ) -> dict: + """Returns structured_configuration for one L3 Port-Channel.""" + # build common portion of the interface cfg + interface = self._get_l3_common_interface_cfg(l3_port_channel) + interface_description = l3_port_channel.description + if not interface_description: + interface_description = self.shared_utils.interface_descriptions.underlay_port_channel_interface( + InterfaceDescriptionData( + shared_utils=self.shared_utils, + interface=l3_port_channel.name, + peer=l3_port_channel.peer, + peer_interface=l3_port_channel.peer_port_channel, + wan_carrier=l3_port_channel.wan_carrier, + wan_circuit_id=l3_port_channel.wan_circuit_id, + ), + ) + interface["description"] = interface_description + interface["peer_type"] = "l3_port_channel" + interface["peer_interface"] = l3_port_channel.peer_port_channel + # speed is not applicable for port-channel, hence not set + + if l3_port_channel.structured_config: + self.custom_structured_configs.nested.port_channel_interfaces.obtain(l3_port_channel.name)._deepmerge( + l3_port_channel.structured_config, list_merge=self.custom_structured_configs.list_merge_strategy + ) + interface["access_group_in"] = get(self._l3_port_channel_acls, f"{l3_port_channel.name}..ipv4_acl_in..name", separator="..") + interface["access_group_out"] = get(self._l3_port_channel_acls, f"{l3_port_channel.name}..ipv4_acl_out..name", separator="..") + + if ( + self.shared_utils.is_wan_router + and (wan_carrier_name := l3_port_channel.wan_carrier) is not None + and interface["access_group_in"] is None + and (wan_carrier_name not in self.inputs.wan_carriers or not self.inputs.wan_carriers[wan_carrier_name].trusted) + ): + msg = ( + "'ipv4_acl_in' must be set on WAN interfaces where 'wan_carrier' is set, unless the carrier is configured as 'trusted' " + f"under 'wan_carriers'. 'ipv4_acl_in' is missing on L3 Port-Channel '{l3_port_channel.name}'." + ) + raise AristaAvdError(msg) return strip_empties_from_dict(interface) + def _get_l3_common_interface_cfg( + self: AvdStructuredConfigUnderlayProtocol, + l3_generic_interface: EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3InterfacesItem + | EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3PortChannelsItem, + ) -> dict: + """Returns common structured_configuration for L3 interface or L3 Port-Channel.""" + # variables being set for constructing appropriate validation error + if isinstance(l3_generic_interface, EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3InterfacesItem): + node_type_in_schema = "l3_interfaces" + else: + # implies interface is "L3 Port-Channel" + node_type_in_schema = "l3_port_channels" + + # logic below is common to l3_interface and l3_port_channel interface types + + # TODO: catch if ip_address is not valid or not dhcp + if not l3_generic_interface.ip_address: + msg = f"{self.shared_utils.node_type_key_data.key}.nodes[name={self.shared_utils.hostname}].{node_type_in_schema}" + msg += f"[name={l3_generic_interface.name}].ip_address" + raise AristaAvdMissingVariableError(msg) + + is_subinterface = "." in l3_generic_interface.name + interface = { + "name": l3_generic_interface.name, + "peer": l3_generic_interface.peer, + "ip_address": l3_generic_interface.ip_address, + "shutdown": not l3_generic_interface.enabled, + "switchport": {"enabled": False if "." not in l3_generic_interface.name else None}, + "service_profile": l3_generic_interface.qos_profile, + "eos_cli": l3_generic_interface.raw_eos_cli, + "flow_tracker": self.shared_utils.get_flow_tracker(l3_generic_interface.flow_tracking), + } + + if is_subinterface: + interface["encapsulation_dot1q"] = { + "vlan": default(l3_generic_interface.encapsulation_dot1q_vlan, int(l3_generic_interface.name.split(".", maxsplit=1)[-1])) + } + if l3_generic_interface.ip_address == "dhcp" and l3_generic_interface.dhcp_accept_default_route: + interface["dhcp_client_accept_default_route"] = True + + return interface + + # only being called for l3_port_channel which is not a sub-interface + def _get_l3_port_channel_member_ports_cfg( + self: AvdStructuredConfigUnderlayProtocol, l3_port_channel: EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3PortChannelsItem + ) -> list: + """Returns structured_configuration (list of ethernet interfaces) representing member ports for one L3 Port-Channel.""" + ethernet_interfaces = [] + channel_group_id = l3_port_channel.name.split("Port-Channel")[-1] + for member_intf in l3_port_channel.member_interfaces: + interface_description = member_intf.description + # derive values for peer from parent L3 port-channel + # if not defined explicitly for member interface + peer = member_intf.peer if member_intf.peer else l3_port_channel.peer + if not interface_description: + interface_description = self.shared_utils.interface_descriptions.underlay_ethernet_interface( + InterfaceDescriptionData( + shared_utils=self.shared_utils, + interface=member_intf.name, + peer=peer, + peer_interface=member_intf.peer_interface, + ), + ) + ethernet_interface = { + "name": member_intf.name, + "description": interface_description, + "peer_type": "l3_port_channel_member", + "peer": peer, + "peer_interface": member_intf.peer_interface, + "shutdown": not l3_port_channel.enabled, + "speed": member_intf.speed if member_intf.speed else None, + "channel_group": { + "id": int(channel_group_id), + "mode": l3_port_channel.mode, + }, + } + if member_intf.structured_config: + self.custom_structured_configs.nested.ethernet_interfaces.obtain(member_intf.name)._deepmerge( + member_intf.structured_config, list_merge=self.custom_structured_configs.list_merge_strategy + ) + ethernet_interfaces.append(strip_empties_from_dict(ethernet_interface)) + return ethernet_interfaces + def _get_l3_uplink_with_l2_as_subint(self: AvdStructuredConfigUnderlayProtocol, link: dict) -> tuple[dict, list[dict]]: """Return a tuple with main uplink interface, list of subinterfaces representing each SVI.""" vlans = [int(vlan) for vlan in range_expand(link["vlans"])] @@ -318,33 +423,67 @@ def _l3_interface_acls(self: AvdStructuredConfigUnderlayProtocol) -> dict[str, d "ipv4_acl_out": , } + Only contains L3 interfaces with ACLs and only the ACLs that are set. + """ + return self._get_l3_generic_interface_acls(self.shared_utils.l3_interfaces) + + @cached_property + def _l3_port_channel_acls(self: AvdStructuredConfigUnderlayProtocol) -> dict[str, dict[str, dict]]: + """ + Return dict of l3 Port-Channel ACLs. + + : { + "ipv4_acl_in": , + "ipv4_acl_out": , + } + + Only contains L3 Port-Channel with ACLs and only the ACLs that are set. + """ + return self._get_l3_generic_interface_acls(self.shared_utils.node_config.l3_port_channels) + + def _get_l3_generic_interface_acls( + self: AvdStructuredConfigUnderlayProtocol, + l3_generic_interfaces: ( + EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3Interfaces + | EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3PortChannels + ), + ) -> dict[str, dict[str, dict]]: + """ + Return dict of l3 interface ACLs referenced by either L3 interfaces or L3 Port-Channels. + + : { + "ipv4_acl_in": , + "ipv4_acl_out": , + } + Only contains interfaces with ACLs and only the ACLs that are set, - so use `get(self._l3_interface_acls, f"{interface_name}.ipv4_acl_in")` to get the value. + so use `get(self._get_l3_generic_interface_acls(), f"{interface_name}.ipv4_acl_in")` to get the value. + where ` is either 'self.shared_utils.l3_interfaces' or 'self.shared_utils.l3_port_channels'` """ l3_interface_acls = {} - for l3_interface in self.shared_utils.l3_interfaces: - ipv4_acl_in = l3_interface.ipv4_acl_in - ipv4_acl_out = l3_interface.ipv4_acl_out + for l3_generic_interface in l3_generic_interfaces: + ipv4_acl_in = l3_generic_interface.ipv4_acl_in + ipv4_acl_out = l3_generic_interface.ipv4_acl_out if ipv4_acl_in is None and ipv4_acl_out is None: continue - interface_ip = l3_interface.dhcp_ip if (ip_address := l3_interface.ip_address) == "dhcp" else ip_address + interface_ip = l3_generic_interface.dhcp_ip if (ip_address := l3_generic_interface.ip_address) == "dhcp" else ip_address if interface_ip is not None and "/" in interface_ip: interface_ip = get_ip_from_ip_prefix(interface_ip) if ipv4_acl_in is not None: - l3_interface_acls.setdefault(l3_interface.name, {})["ipv4_acl_in"] = self.shared_utils.get_ipv4_acl( + l3_interface_acls.setdefault(l3_generic_interface.name, {})["ipv4_acl_in"] = self.shared_utils.get_ipv4_acl( name=ipv4_acl_in, - interface_name=l3_interface.name, + interface_name=l3_generic_interface.name, interface_ip=interface_ip, - peer_ip=l3_interface.peer_ip, + peer_ip=l3_generic_interface.peer_ip, )._as_dict() if ipv4_acl_out is not None: - l3_interface_acls.setdefault(l3_interface.name, {})["ipv4_acl_out"] = self.shared_utils.get_ipv4_acl( + l3_interface_acls.setdefault(l3_generic_interface.name, {})["ipv4_acl_out"] = self.shared_utils.get_ipv4_acl( name=ipv4_acl_out, - interface_name=l3_interface.name, + interface_name=l3_generic_interface.name, interface_ip=interface_ip, - peer_ip=l3_interface.peer_ip, + peer_ip=l3_generic_interface.peer_ip, )._as_dict() return l3_interface_acls diff --git a/python-avd/pyavd/api/interface_descriptions/__init__.py b/python-avd/pyavd/api/interface_descriptions/__init__.py index 0b8359d3719..b7973701a13 100644 --- a/python-avd/pyavd/api/interface_descriptions/__init__.py +++ b/python-avd/pyavd/api/interface_descriptions/__init__.py @@ -105,7 +105,9 @@ def underlay_port_channel_interface(self, data: InterfaceDescriptionData) -> str - mpls_overlay_role - mpls_lsr - overlay_routing_protocol - - type. + - type + - wan_carrier + - wan_circuit_id. """ if template_path := self.shared_utils.node_type_key_data.interface_descriptions.underlay_port_channel_interfaces: return self._template( @@ -123,9 +125,13 @@ def underlay_port_channel_interface(self, data: InterfaceDescriptionData) -> str description = data.port_channel_description elif data.link_type in ("l3_edge", "core_interfaces"): description = self.inputs.default_underlay_p2p_port_channel_description - else: + elif data.link_type == "underlay_l2": # This is for L2 port-channels description = self.inputs.underlay_l2_port_channel_description + else: + # This is for L3 port-channels + elems = [data.wan_carrier, data.wan_circuit_id, data.peer, data.peer_interface] + return "_".join([elem for elem in elems if elem]) return AvdStringFormatter().format( description,