diff --git a/aci_tenants.tf b/aci_tenants.tf index aab90d9a..33cd83d4 100644 --- a/aci_tenants.tf +++ b/aci_tenants.tf @@ -1060,7 +1060,28 @@ locals { peer_prefix_policy = try("${peer.peer_prefix_policy}${local.defaults.apic.tenants.policies.bgp_peer_prefix_policies.name_suffix}", null) export_route_control = try("${peer.export_route_control}${local.defaults.apic.tenants.policies.route_control_route_maps.name_suffix}", null) import_route_control = try("${peer.import_route_control}${local.defaults.apic.tenants.policies.route_control_route_maps.name_suffix}", null) - }] + } if tenant.name != "infra"] + bgp_infra_peers = [for peer in try(np.bgp_infra_peers, []) : { + ip = peer.ip + remote_as = peer.remote_as + admin_state = try(peer.admin_state, local.defaults.apic.tenants.l3outs.node_profiles.bgp_infra_peers.admin_state) + description = try(peer.description, "") + allow_self_as = try(peer.allow_self_as, local.defaults.apic.tenants.l3outs.node_profiles.bgp_infra_peers.allow_self_as) + disable_peer_as_check = try(peer.disable_peer_as_check, local.defaults.apic.tenants.l3outs.node_profiles.bgp_infra_peers.disable_peer_as_check) + as_override = try(peer.as_override, local.defaults.apic.tenants.l3outs.node_profiles.bgp_infra_peers.as_override) + next_hop_self = try(peer.next_hop_self, local.defaults.apic.tenants.l3outs.node_profiles.bgp_infra_peers.next_hop_self) + send_community = try(peer.send_community, local.defaults.apic.tenants.l3outs.node_profiles.bgp_infra_peers.send_community) + send_ext_community = try(peer.send_ext_community, local.defaults.apic.tenants.l3outs.node_profiles.bgp_infra_peers.send_ext_community) + peer_type = try(peer.peer_type, local.defaults.apic.tenants.l3outs.node_profiles.bgp_infra_peers.peer_type) + bfd = try(peer.bfd, local.defaults.apic.tenants.l3outs.node_profiles.bgp_infra_peers.bfd) + password = try(peer.password, null) + ttl = try(peer.ttl, local.defaults.apic.tenants.l3outs.node_profiles.bgp_infra_peers.ttl) + local_as = try(peer.local_as, null) + as_propagate = try(peer.as_propagate, local.defaults.apic.tenants.l3outs.node_profiles.bgp_infra_peers.as_propagate) + source_interface_type = try(peer.peer_type, local.defaults.apic.tenants.l3outs.node_profiles.bgp_infra_peers.peer_type) == "wan" ? try(peer.source_interface_type, local.defaults.apic.tenants.l3outs.node_profiles.bgp_infra_peers.source_interface_type) : null + data_plane_address = try(peer.peer_type, local.defaults.apic.tenants.l3outs.node_profiles.bgp_infra_peers.peer_type) == "wan" && try(peer.source_interface_type, local.defaults.apic.tenants.l3outs.node_profiles.bgp_infra_peers.source_interface_type) == "routable-loopback" ? try(peer.data_plane_address, null) : null + peer_prefix_policy = try("${peer.peer_prefix_policy}${local.defaults.apic.tenants.policies.bgp_peer_prefix_policies.name_suffix}", null) + } if tenant.name == "infra"] } ] ] @@ -1081,6 +1102,7 @@ module "aci_l3out_node_profile_manual" { bgp_as_path_policy = each.value.bgp_as_path_policy nodes = each.value.nodes bgp_peers = each.value.bgp_peers + bgp_infra_peers = each.value.bgp_infra_peers bfd_multihop_node_policy = each.value.bfd_multihop_node_policy bfd_multihop_auth_key_id = each.value.bfd_multihop_auth_key_id bfd_multihop_auth_key = each.value.bfd_multihop_auth_key @@ -1159,7 +1181,28 @@ locals { peer_prefix_policy = try("${peer.peer_prefix_policy}${local.defaults.apic.tenants.policies.bgp_peer_prefix_policies.name_suffix}", null) export_route_control = try("${peer.export_route_control}${local.defaults.apic.tenants.policies.route_control_route_maps.name_suffix}", null) import_route_control = try("${peer.import_route_control}${local.defaults.apic.tenants.policies.route_control_route_maps.name_suffix}", null) - }] + } if tenant.name != "infra"] + bgp_infra_peers = [for peer in try(l3out.bgp_infra_peers, []) : { + ip = peer.ip + remote_as = peer.remote_as + admin_state = try(peer.admin_state, local.defaults.apic.tenants.l3outs.bgp_infra_peers.admin_state) + description = try(peer.description, "") + allow_self_as = try(peer.allow_self_as, local.defaults.apic.tenants.l3outs.bgp_infra_peers.allow_self_as) + disable_peer_as_check = try(peer.disable_peer_as_check, local.defaults.apic.tenants.l3outs.bgp_infra_peers.disable_peer_as_check) + as_override = try(peer.as_override, local.defaults.apic.tenants.l3outs.bgp_infra_peers.as_override) + next_hop_self = try(peer.next_hop_self, local.defaults.apic.tenants.l3outs.bgp_infra_peers.next_hop_self) + send_community = try(peer.send_community, local.defaults.apic.tenants.l3outs.bgp_infra_peers.send_community) + send_ext_community = try(peer.send_ext_community, local.defaults.apic.tenants.l3outs.bgp_infra_peers.send_ext_community) + peer_type = try(peer.peer_type, local.defaults.apic.tenants.l3outs.bgp_infra_peers.peer_type) + bfd = try(peer.bfd, local.defaults.apic.tenants.l3outs.bgp_infra_peers.bfd) + password = try(peer.password, null) + ttl = try(peer.ttl, local.defaults.apic.tenants.l3outs.bgp_infra_peers.ttl) + local_as = try(peer.local_as, null) + as_propagate = try(peer.as_propagate, local.defaults.apic.tenants.l3outs.bgp_infra_peers.as_propagate) + source_interface_type = try(peer.peer_type, local.defaults.apic.tenants.l3outs.bgp_infra_peers.peer_type) == "wan" ? try(peer.source_interface_type, local.defaults.apic.tenants.l3outs.bgp_infra_peers.source_interface_type) : null + data_plane_address = try(peer.peer_type, local.defaults.apic.tenants.l3outs.bgp_infra_peers.peer_type) == "wan" && try(peer.source_interface_type, local.defaults.apic.tenants.l3outs.bgp_infra_peers.source_interface_type) == "routable-loopback" ? try(peer.data_plane_address, null) : null + peer_prefix_policy = try("${peer.peer_prefix_policy}${local.defaults.apic.tenants.policies.bgp_peer_prefix_policies.name_suffix}", null) + } if tenant.name == "infra"] } if length(try(l3out.nodes, [])) != 0 ] ]) @@ -1179,6 +1222,7 @@ module "aci_l3out_node_profile_auto" { bgp_as_path_policy = each.value.bgp_as_path_policy nodes = each.value.nodes bgp_peers = each.value.bgp_peers + bgp_infra_peers = each.value.bgp_infra_peers bfd_multihop_node_policy = each.value.bfd_multihop_node_policy bfd_multihop_auth_key_id = each.value.bfd_multihop_auth_key_id bfd_multihop_auth_key = each.value.bfd_multihop_auth_key @@ -1706,6 +1750,9 @@ locals { local_as = try(peer.local_as, null) as_propagate = try(peer.as_propagate, local.defaults.apic.tenants.sr_mpls_l3outs.node_profiles.evpn_connectivity.as_propagate) peer_prefix_policy = try("${peer.peer_prefix_policy}${local.defaults.apic.tenants.policies.bgp_peer_prefix_policies.name_suffix}", null) + peer_type = "sr-mpls" + send_community = true + send_ext_community = true }] } ] diff --git a/defaults/defaults.yaml b/defaults/defaults.yaml index 8252d9b9..c32a15cd 100644 --- a/defaults/defaults.yaml +++ b/defaults/defaults.yaml @@ -952,6 +952,20 @@ defaults: multicast_address_family: true admin_state: true as_propagate: none + bgp_infra_peers: + name_suffix: "" + peer_type: wan + allow_self_as: false + disable_peer_as_check: false + send_community: false + send_ext_community: false + next_hop_self: false + as_override: false + ttl: 2 + bfd: false + admin_state: true + as_propagate: none + source_interface_type: l3out-loopback redistribution_route_maps: source: static dhcp_labels: @@ -1026,6 +1040,20 @@ defaults: multicast_address_family: true admin_state: true as_propagate: none + bgp_infra_peers: + name_suffix: "" + peer_type: wan + allow_self_as: false + disable_peer_as_check: false + send_community: false + send_ext_community: false + next_hop_self: false + as_override: false + ttl: 2 + bfd: false + admin_state: true + as_propagate: none + source_interface_type: l3out-loopback nodes: pod: 1 router_id_as_loopback: true diff --git a/modules/terraform-aci-l3out-node-profile/README.md b/modules/terraform-aci-l3out-node-profile/README.md index e50f247e..971f91d4 100644 --- a/modules/terraform-aci-l3out-node-profile/README.md +++ b/modules/terraform-aci-l3out-node-profile/README.md @@ -104,7 +104,7 @@ module "aci_l3out_node_profile" { | [multipod](#input\_multipod) | Multipod L3out flag. | `bool` | `false` | no | | [remote\_leaf](#input\_remote\_leaf) | Remote leaf L3out flag. | `bool` | `false` | no | | [sr\_mpls](#input\_sr\_mpls) | SR MPLS L3out flag. | `bool` | `false` | no | -| [bgp\_infra\_peers](#input\_bgp\_infra\_peers) | List of BGP EVPN peers for SR MPLS L3out. Allowed values `remote_as`: 0-4294967295. Default value `allow_self_as`: false. Default value `disable_peer_as_check`: false. Default value `bfd`: false. Default value `ttl`: 2. Default value `admin_state`: true. Allowed values `local_as`: 0-4294967295. Choices `as_propagate`: `none`, `no-prepend`, `replace-as`, `dual-as`. Default value `as_propagate`: `none`. |
list(object({
ip = string
remote_as = string
description = optional(string, "")
allow_self_as = optional(bool, false)
disable_peer_as_check = optional(bool, false)
password = optional(string)
bfd = optional(bool, false)
ttl = optional(number, 1)
admin_state = optional(bool, true)
local_as = optional(number)
as_propagate = optional(string, "none")
peer_prefix_policy = optional(string)
}))
| `[]` | no | +| [bgp\_infra\_peers](#input\_bgp\_infra\_peers) | List of BGP peers for Infra L3out. Allowed values `remote_as`: 0-4294967295. Default value `allow_self_as`: false. Default value `disable_peer_as_check`: false. Default value `bfd`: false. Default value `ttl`: 2. Default value `admin_state`: true. Allowed values `local_as`: 0-4294967295. Choices `as_propagate`: `none`, `no-prepend`, `replace-as`, `dual-as`. Default value `as_propagate`: `none`. Choices `peer_type`: `sr-mpls`, `wan`, `mdp-wan` or `intersite` |
list(object({
ip = string
remote_as = string
description = optional(string, "")
allow_self_as = optional(bool, false)
disable_peer_as_check = optional(bool, false)
as_override = optional(bool, false)
next_hop_self = optional(bool, false)
send_community = optional(bool, false)
send_ext_community = optional(bool, false)
password = optional(string)
bfd = optional(bool, false)
ttl = optional(number, 1)
admin_state = optional(bool, true)
local_as = optional(number)
as_propagate = optional(string, "none")
peer_prefix_policy = optional(string)
peer_type = optional(string)
source_interface_type = optional(string, "l3out-loopback")
data_plane_address = optional(string, null)
}))
| `[]` | no | | [mpls\_custom\_qos\_policy](#input\_mpls\_custom\_qos\_policy) | MPLS Customer QoS Policy | `string` | `""` | no | | [bfd\_multihop\_node\_policy](#input\_bfd\_multihop\_node\_policy) | BFD Multihop Node Policy | `string` | `""` | no | | [bgp\_protocol\_profile\_name](#input\_bgp\_protocol\_profile\_name) | BGP Protocol Name. | `string` | `""` | no | diff --git a/modules/terraform-aci-l3out-node-profile/main.tf b/modules/terraform-aci-l3out-node-profile/main.tf index f385f17f..958037ac 100644 --- a/modules/terraform-aci-l3out-node-profile/main.tf +++ b/modules/terraform-aci-l3out-node-profile/main.tf @@ -231,28 +231,30 @@ resource "aci_rest_managed" "bfdRsMhNodePol" { } resource "aci_rest_managed" "bgpInfraPeerP" { - for_each = { for peer in var.bgp_infra_peers : peer.ip => peer } + for_each = { for peer in var.bgp_infra_peers : peer.ip => peer if var.sr_mpls == true || (var.sr_mpls == false && peer.peer_type != "sr-mpls" && peer.peer_type != "vxlan-bgw") } dn = "${aci_rest_managed.l3extLNodeP.dn}/infraPeerP-[${each.value.ip}]" class_name = "bgpInfraPeerP" escape_html = false content = { - addr = each.value.ip - descr = each.value.description - ctrl = join(",", concat(each.value.allow_self_as == true ? ["allow-self-as"] : [], each.value.disable_peer_as_check == true ? ["dis-peer-as-check"] : [], ["send-com"], ["send-ext-com"])) - password = sensitive(each.value.password) - peerCtrl = join(",", concat(each.value.bfd == true ? ["bfd"] : [])) - peerT = "sr-mpls" - ttl = each.value.ttl - adminSt = each.value.admin_state == true ? "enabled" : "disabled" + addr = each.value.ip + descr = each.value.description + ctrl = join(",", concat(each.value.allow_self_as == true ? ["allow-self-as"] : [], each.value.as_override == true ? ["as-override"] : [], each.value.disable_peer_as_check == true ? ["dis-peer-as-check"] : [], each.value.next_hop_self == true ? ["nh-self"] : [], each.value.send_community == true ? ["send-com"] : [], each.value.send_ext_community == true ? ["send-ext-com"] : [])) + password = sensitive(each.value.password) + peerCtrl = join(",", concat(each.value.bfd == true ? ["bfd"] : [])) + peerT = each.value.peer_type + ttl = each.value.ttl + adminSt = each.value.admin_state == true ? "enabled" : "disabled" + srcIfT = each.value.source_interface_type + dataPlaneAddr = each.value.data_plane_address } lifecycle { - ignore_changes = [content["password"]] + ignore_changes = [content["password"], content["srcIfT"], content["peerT"]] } } resource "aci_rest_managed" "bgpAsP-bgpInfraPeerP" { - for_each = { for peer in var.bgp_infra_peers : peer.ip => peer } + for_each = { for peer in var.bgp_infra_peers : peer.ip => peer if var.sr_mpls || (var.sr_mpls == false && peer.peer_type != "sr-mpls" && peer.peer_type != "vxlan-bgw") } dn = "${aci_rest_managed.bgpInfraPeerP[each.key].dn}/as" class_name = "bgpAsP" content = { @@ -261,7 +263,7 @@ resource "aci_rest_managed" "bgpAsP-bgpInfraPeerP" { } resource "aci_rest_managed" "bgpLocalAsnP-bgpInfraPeerP" { - for_each = { for peer in var.bgp_infra_peers : peer.ip => peer if peer.local_as != null } + for_each = { for peer in var.bgp_infra_peers : peer.ip => peer if(var.sr_mpls || (var.sr_mpls == false && peer.peer_type != "sr-mpls" && peer.peer_type != "vxlan-bgw")) && peer.local_as != null } dn = "${aci_rest_managed.bgpInfraPeerP[each.key].dn}/localasn" class_name = "bgpLocalAsnP" content = { @@ -271,7 +273,7 @@ resource "aci_rest_managed" "bgpLocalAsnP-bgpInfraPeerP" { } resource "aci_rest_managed" "bgpRsPeerPfxPol-bgpInfraPeerP" { - for_each = { for peer in var.bgp_infra_peers : peer.ip => peer if peer.peer_prefix_policy != null } + for_each = { for peer in var.bgp_infra_peers : peer.ip => peer if(var.sr_mpls || (var.sr_mpls == false && peer.peer_type != "sr-mpls" && peer.peer_type != "vxlan-bgw")) && peer.peer_prefix_policy != null } dn = "${aci_rest_managed.bgpInfraPeerP[each.key].dn}/rspeerPfxPol" class_name = "bgpRsPeerPfxPol" content = { diff --git a/modules/terraform-aci-l3out-node-profile/variables.tf b/modules/terraform-aci-l3out-node-profile/variables.tf index 131bdc91..c4e68dda 100644 --- a/modules/terraform-aci-l3out-node-profile/variables.tf +++ b/modules/terraform-aci-l3out-node-profile/variables.tf @@ -215,13 +215,17 @@ variable "sr_mpls" { } variable "bgp_infra_peers" { - description = "List of BGP EVPN peers for SR MPLS L3out. Allowed values `remote_as`: 0-4294967295. Default value `allow_self_as`: false. Default value `disable_peer_as_check`: false. Default value `bfd`: false. Default value `ttl`: 2. Default value `admin_state`: true. Allowed values `local_as`: 0-4294967295. Choices `as_propagate`: `none`, `no-prepend`, `replace-as`, `dual-as`. Default value `as_propagate`: `none`." + description = "List of BGP peers for Infra L3out. Allowed values `remote_as`: 0-4294967295. Default value `allow_self_as`: false. Default value `disable_peer_as_check`: false. Default value `bfd`: false. Default value `ttl`: 2. Default value `admin_state`: true. Allowed values `local_as`: 0-4294967295. Choices `as_propagate`: `none`, `no-prepend`, `replace-as`, `dual-as`. Default value `as_propagate`: `none`. Choices `peer_type`: `sr-mpls`, `wan`, `mdp-wan` or `intersite`" type = list(object({ ip = string remote_as = string description = optional(string, "") allow_self_as = optional(bool, false) disable_peer_as_check = optional(bool, false) + as_override = optional(bool, false) + next_hop_self = optional(bool, false) + send_community = optional(bool, false) + send_ext_community = optional(bool, false) password = optional(string) bfd = optional(bool, false) ttl = optional(number, 1) @@ -229,6 +233,9 @@ variable "bgp_infra_peers" { local_as = optional(number) as_propagate = optional(string, "none") peer_prefix_policy = optional(string) + peer_type = optional(string) + source_interface_type = optional(string, "l3out-loopback") + data_plane_address = optional(string, null) })) default = [] @@ -266,6 +273,25 @@ variable "bgp_infra_peers" { ]) error_message = "`as_propagate`: Allowed value are: `none`, `no-prepend`, `replace-as` or `dual-as`." } + + validation { + condition = alltrue([ + for b in var.bgp_infra_peers : b.peer_type == null || try(contains(["sr-mpls", "wan", "mdp-wan", "vxlan-bgw"], b.peer_type), false) + ]) + error_message = "`peer_type`: Allowed value are: `sr-mpls`, `wan`, `mdp-wan` or 'vxlan-bgw'." + } + validation { + condition = alltrue([ + for b in var.bgp_infra_peers : try(contains(["l3out-loopback", "routable-loopback"], b.source_interface_type), false) + ]) + error_message = "`source_interface_type`: Allowed value are: `l3out-loopback` or `routable-loopback`." + } + validation { + condition = alltrue([ + for b in var.bgp_infra_peers : (b.data_plane_address == null && b.source_interface_type != "routable-loopback") || b.data_plane_address != null + ]) + error_message = "`data_plane_address`: Must be set if `source_interface_type` is `routable-loopback`." + } } variable "mpls_custom_qos_policy" {