Cisco ACI Preferred group, немножко inter-VRF leaking и L3Out

от автора

В последней статье мы обсудили детали реализации inter-VRF leaking с использованием двух самых обычных  EPG. Безусловно, L3Out тоже можно использовать похожим образом, например, для предоставления общего доступа в интернет. Впрочем, тут не обошлось без ложки дёгтя: есть один раздел в документе, описывающем контракты ACI, в котором мелким шрифтом написано следующее:

“Due to CSCvm63145, an EPG in a preferred group can consume an inter-VRF contract but cannot be a provider for an inter-VRF contract with an L3Out EPG as the consumer.”

Вольный перевод:

«Вследствие CSCvm63145 EPG, будучи частью preferred group, может потреблять inter-VRF контракт, однако не может предоставлять такой контракт, если потребитель – L3Out.»

И никакого дополнительного комментария, почему дела обстоят именно так. Если посмотреть описание бага, то можно найти чуть больше деталей: если EPG – provider для inter-VRF контракта, то он не может общаться внутри Preferred Group из-за некоего ограничивающего фильтра. Однако ведь подобные фильтры возникают при явном использовании контракта, не так ли? Спровоцируем баг и посмотрим, что же происходит на самом деле.

Host притворяется сразу тремя сущностями: предоставляет сервис (Provider), потребляет сервис (L3Out) и тихо-мирно ковыряется в носу в Preferred Group внутри TestVrf1 (TestEPG). Обмен префиксами между L3Out и Host происходит по OSPF. По задумке 2.2.2.2/32 использует сервис, расположенный по адресу 192.168.1.1. Provider и TestEPG находятся в одной подсети и, как следствие, в одном BD.

Определим Access Policy, чтобы разрешить подключение на физическом уровне фабрики:

resource "aci_vlan_pool" "TestPool" {   name  = "TestPool"   alloc_mode  = "static" } resource "aci_ranges" "TestRange" {   vlan_pool_dn  = aci_vlan_pool.TestPool.id   from = "vlan-1"   to = "vlan-1000"   alloc_mode = "static" } resource "aci_physical_domain" "PhysicalDomain" {   name = "PhysicalDomain"   relation_infra_rs_vlan_ns = aci_vlan_pool.TestPool.id } resource "aci_l3_domain_profile" "L3Domain" {   name = "L3Domain"   relation_infra_rs_vlan_ns = aci_vlan_pool.TestPool.id } resource "aci_attachable_access_entity_profile" "TestAAEP" {     name = "TestAAEP" } resource "aci_aaep_to_domain" "PhysicalDomain-to-TestAAEP" {   attachable_access_entity_profile_dn = aci_attachable_access_entity_profile.TestAAEP.id   domain_dn = aci_physical_domain.PhysicalDomain.id } resource "aci_aaep_to_domain" "L3Domain-to-TestAAEP" {   attachable_access_entity_profile_dn = aci_attachable_access_entity_profile.TestAAEP.id   domain_dn = aci_l3_domain_profile.L3Domain.id } resource "aci_leaf_interface_profile" "TestInterfaceProfile" {     name = "TestInterfaceProfile" } resource "aci_access_port_block" "TestAccessBlockSelector" {   access_port_selector_dn = aci_access_port_selector.TestAccessPortSelector.id   name = "TestAccessBlockSelector"   from_card = "1"   from_port = "2"   to_card = "1"   to_port = "4" } resource "aci_access_port_selector" "TestAccessPortSelector" {     leaf_interface_profile_dn = aci_leaf_interface_profile.TestInterfaceProfile.id     name = "TestAccessPortSelector"     access_port_selector_type = "range"     relation_infra_rs_acc_base_grp = aci_leaf_access_port_policy_group.TestAccessInterfacePolicy.id } resource "aci_leaf_access_port_policy_group" "TestAccessInterfacePolicy" {     name = "TestAccessInterfaceProfile"     relation_infra_rs_att_ent_p = aci_attachable_access_entity_profile.TestAAEP.id } resource "aci_leaf_profile" "TestSwitchProfile" {   name = "TestSwitchProfile"   leaf_selector {     name = "LeafSelector"     switch_association_type = "range"     node_block {       name  = "Block1"       from_ = "101"       to_   = "104"     }   }   relation_infra_rs_acc_port_p = [aci_leaf_interface_profile.TestInterfaceProfile.id] } 

Затем можно настроить tenant с нужными EPG и конструкциями сетевого уровня:

resource "aci_tenant" "TestTenant" {     name = "TestTenant" } resource "aci_vrf" "TestVrf1" {     tenant_dn = aci_tenant.TestTenant.id     name = "TestVrf1" } resource "aci_vrf" "TestVrf2" {     tenant_dn = aci_tenant.TestTenant.id     name = "TestVrf2" } resource "aci_bridge_domain" "TestBD1" {     tenant_dn = aci_tenant.TestTenant.id     name  = "TestBD1"     relation_fv_rs_ctx = aci_vrf.TestVrf1.id } resource "aci_subnet" "ProviderSubnet" {     parent_dn = aci_application_epg.Provider.id     ip = "192.168.1.1/32"     scope = ["public", "shared"]     ctrl = ["no-default-gateway"] } resource "aci_subnet" "TestEPGSubnet" {     parent_dn = aci_bridge_domain.TestBD1.id     ip = "192.168.1.254/24"     scope = ["public", "shared"] } resource "aci_application_profile" "TestAP" {     tenant_dn = aci_tenant.TestTenant.id     name = "TestAP" } resource "aci_application_epg" "Provider" {     application_profile_dn = aci_application_profile.TestAP.id     name = "Provider"     relation_fv_rs_bd = aci_bridge_domain.TestBD1.id     pref_gr_memb = "include" } resource "aci_application_epg" "TestEPG" {     application_profile_dn = aci_application_profile.TestAP.id     name = "TestEPG"     relation_fv_rs_bd = aci_bridge_domain.TestBD1.id     pref_gr_memb = "include" } resource "aci_epg_to_domain" "ProviderDomain" {     application_epg_dn = aci_application_epg.Provider.id     tdn = aci_physical_domain.PhysicalDomain.id } resource "aci_epg_to_domain" "TestEPGDomain" {     application_epg_dn = aci_application_epg.TestEPG.id     tdn = aci_physical_domain.PhysicalDomain.id } resource "aci_bulk_epg_to_static_path" "ProviderStaticPath" {   application_epg_dn = aci_application_epg.Provider.id   static_path {     interface_dn = "topology/pod-1/paths-101/pathep-[eth1/2]"     encap = "vlan-100"   } } resource "aci_bulk_epg_to_static_path" "TestEPGStaticPath" {   application_epg_dn = aci_application_epg.TestEPG.id   static_path {     interface_dn = "topology/pod-1/paths-101/pathep-[eth1/2]"     encap = "vlan-101"   } }

Зададим контракт, который разрешает любой тип трафика, и назначим его Provider:

resource "aci_contract" "TestContract" {     tenant_dn = aci_tenant.TestTenant.id     name = "TestContract"     scope = "tenant" } resource "aci_contract_subject" "TestSubject" {     contract_dn = aci_contract.TestContract.id     name = "TestSubject" } resource "aci_contract_subject_filter" "PermitIPSubj" {   contract_subject_dn = aci_contract_subject.TestSubject.id   filter_dn = aci_filter.PermitIPFilter.id } resource "aci_filter" "PermitIPFilter" {     tenant_dn = aci_tenant.TestTenant.id     name = "PermitIPFilter" } resource "aci_filter_entry" "PermitIPFilterEntry" {     filter_dn = aci_filter.PermitIPFilter.id     name = "demo_entry"     d_to_port = "unspecified"     ether_t = "ip" } resource "aci_application_epg" "Provider" {     application_profile_dn = aci_application_profile.TestAP.id     name = "Provider"     relation_fv_rs_bd = aci_bridge_domain.TestBD1.id     relation_fv_rs_prov = [aci_contract.TestContract.id]     pref_gr_memb = "include" }

Теперь мы можем настроить Host и проверить связность с фабрикой. Это позволит нам убедиться в том, что предыдущие шаги выполнены успешно, а все обязательные параметры уже определены.

Host# show run vrf Provider interface Ethernet1/1.100   vrf member Provider vrf context Provider   ip route 0.0.0.0/0 192.168.1.254   address-family ipv4 unicast Host# Host# show vrf Provider interface  Interface                 VRF-Name                        VRF-ID  Site-of-Origin Ethernet1/1.100           Provider                             3  -- Host# Host# show run interface e1/1.100 interface Ethernet1/1.100   encapsulation dot1q 100   mac-address 0000.0000.0001   vrf member Provider   ip address 192.168.1.1/24 Host# Host# show run vrf TestEPG interface Ethernet1/1.101   vrf member TestEPG vrf context TestEPG   ip route 0.0.0.0/0 192.168.1.254   address-family ipv4 unicast Host# Host# show vrf TestEPG interface Interface                 VRF-Name                        VRF-ID  Site-of-Origin Ethernet1/1.101           TestEPG                              5  -- Host# Host# show run interface e1/1.101 interface Ethernet1/1.101   encapsulation dot1q 101   mac-address 0000.0000.0002   vrf member TestEPG   ip address 192.168.1.2/24

Subinterface наследуют MAC адрес родительского интерфейса по умолчанию. Поскольку физический интерфейс один и тот же, ACI будет некорректно считать, что оба IP принадлежат одному MAC и, как следствие, одному EPG. Простое решение – использовать разные MAC адреса, поэтому мы и задали их вручную.

Host# ping 192.168.1.254 vrf Provider PING 192.168.1.254 (192.168.1.254): 56 data bytes 64 bytes from 192.168.1.254: icmp_seq=0 ttl=63 time=1.145 ms 64 bytes from 192.168.1.254: icmp_seq=1 ttl=63 time=0.898 ms 64 bytes from 192.168.1.254: icmp_seq=2 ttl=63 time=1.008 ms 64 bytes from 192.168.1.254: icmp_seq=3 ttl=63 time=0.97 ms 64 bytes from 192.168.1.254: icmp_seq=4 ttl=63 time=1.023 ms  --- 192.168.1.254 ping statistics --- 5 packets transmitted, 5 packets received, 0.00% packet loss round-trip min/avg/max = 0.898/1.008/1.145 ms Host# Host# ping 192.168.1.254 vrf TestEPG PING 192.168.1.254 (192.168.1.254): 56 data bytes 64 bytes from 192.168.1.254: icmp_seq=0 ttl=63 time=1.24 ms 64 bytes from 192.168.1.254: icmp_seq=1 ttl=63 time=0.961 ms 64 bytes from 192.168.1.254: icmp_seq=2 ttl=63 time=1.021 ms 64 bytes from 192.168.1.254: icmp_seq=3 ttl=63 time=0.744 ms 64 bytes from 192.168.1.254: icmp_seq=4 ttl=63 time=0.785 ms  --- 192.168.1.254 ping statistics --- 5 packets transmitted, 5 packets received, 0.00% packet loss round-trip min/avg/max = 0.744/0.95/1.24 ms

Наконец, создадим L3Out и назначим ему определённый ранее контракт:

resource "aci_l3_outside" "L3Out" {     tenant_dn = aci_tenant.TestTenant.id     name = "L3Out"     enforce_rtctrl = ["export", "import"]     relation_l3ext_rs_ectx = aci_vrf.TestVrf2.id     relation_l3ext_rs_l3_dom_att = aci_l3_domain_profile.L3Domain.id } resource "aci_logical_node_profile" "L3OutNodeProfile" {     l3_outside_dn = aci_l3_outside.L3Out.id     name = "L3OutNodeProfile" } resource "aci_logical_interface_profile" "L3OutLogicalInterfaceProfile" {     logical_node_profile_dn = aci_logical_node_profile.L3OutNodeProfile.id     name = "L3OutLogicalInterfaceProfile" } resource "aci_logical_node_to_fabric_node" "NodetoFabric" {   logical_node_profile_dn = aci_logical_node_profile.L3OutNodeProfile.id   tdn = "topology/pod-1/node-103"   rtr_id = "1.1.1.1" } resource "aci_l3out_path_attachment" "InterfaceMapping" {   logical_interface_profile_dn = aci_logical_interface_profile.L3OutLogicalInterfaceProfile.id   target_dn = "topology/pod-1/paths-103/pathep-[eth1/3]"   if_inst_t = "l3-port"   encap = "unknown"   addr = "192.168.2.254/24" } resource "aci_l3out_ospf_external_policy" "L3OutOSPF" {   l3_outside_dn = aci_l3_outside.L3Out.id   area_id = "0.0.0.0"   area_type = "regular" } resource "aci_ospf_interface_policy" "L3OutOSPFPolicy" {     tenant_dn = aci_tenant.TestTenant.id     name = "L3OutOSPFPolicy"     ctrl = ["mtu-ignore"]     dead_intvl = "40"     hello_intvl = "10" } resource "aci_l3out_ospf_interface_profile" "L3OutOSPFInterface" {   logical_interface_profile_dn = aci_logical_interface_profile.L3OutLogicalInterfaceProfile.id   relation_ospf_rs_if_pol = aci_ospf_interface_policy.L3OutOSPFPolicy.id   auth_key = "key" } resource "aci_external_network_instance_profile" "Consumer" {     l3_outside_dn = aci_l3_outside.L3Out.id     name = "Consumer"     relation_fv_rs_cons = [aci_contract.TestContract.id] } resource "aci_l3_ext_subnet" "ConsumerSubnet" {   external_network_instance_profile_dn = aci_external_network_instance_profile.Consumer.id   ip = "2.2.2.2/32"   scope = ["import-rtctrl", "import-security", "shared-security", "shared-rtctrl"] }

Поднимем OSPF на Host, чтобы получить маршруты от ACI:

Host# show run vrf Consumer interface loopback0   vrf member Consumer interface Ethernet1/2   vrf member Consumer vrf context Consumer   address-family ipv4 unicast router ospf 1   vrf Consumer Host# Host# show vrf B interface  Interface                 VRF-Name                        VRF-ID  Site-of-Origin loopback0                 Consumer                             4  -- Ethernet1/2               Consumer                             4  -- Host# Host# show run interface lo0 interface loopback0   vrf member Consumer   ip address 2.2.2.2/32   ip router ospf 1 area 0.0.0.0 Host# Host# show run interface e1/2 interface Ethernet1/2   no switchport   vrf member Consumer   ip address 192.168.2.1/24   ip ospf mtu-ignore   ip router ospf 1 area 0.0.0.0

На этом этапе контракт назначен только Provider и L3Out, поэтому между ними должна быть связность. TestEPG всё так же остаётся один в своей песочнице:

Host# ping 192.168.1.2 vrf Provider PING 192.168.1.2 (192.168.1.2): 56 data bytes 36 bytes from 192.168.1.1: Destination Host Unreachable Request 0 timed out Request 1 timed out Request 2 timed out Request 3 timed out Request 4 timed out --- 192.168.1.2 ping statistics --- 5 packets transmitted, 0 packets received, 100.00% packet loss Host# Host# ping 192.168.1.1 vrf Consumer source 2.2.2.2 PING 192.168.1.1 (192.168.1.1) from 2.2.2.2: 56 data bytes 64 bytes from 192.168.1.1: icmp_seq=0 ttl=252 time=1.691 ms 64 bytes from 192.168.1.1: icmp_seq=1 ttl=252 time=1.489 ms 64 bytes from 192.168.1.1: icmp_seq=2 ttl=252 time=1.529 ms 64 bytes from 192.168.1.1: icmp_seq=3 ttl=252 time=1.525 ms 64 bytes from 192.168.1.1: icmp_seq=4 ttl=252 time=1.533 ms

Чтобы трафик мог попасть с border leaf на Provider, на Leaf-103 должен быть статический маршрут до EPG, который определяет ClassID точки назначения, а так же целевой VNID.

Leaf-103# show ip route vrf TestTenant:TestVrf2 <output omitted> 1.1.1.1/32, ubest/mbest: 2/0, attached, direct     *via 1.1.1.1, Lo6, [0/0], 00:08:30, direct     *via 1.1.1.1, Lo6, [0/0], 00:08:30, local, local 2.2.2.2/32, ubest/mbest: 1/0     *via 192.168.2.1, Eth1/3, [110/5], 00:07:41, ospf-default, intra 192.168.1.1/32, ubest/mbest: 1/0, attached, direct, pervasive     *via 10.0.96.64%overlay-1, [1/0], 00:03:54, static, tag 4294967292 192.168.2.0/24, ubest/mbest: 1/0, attached, direct     *via 192.168.2.254, Eth1/3, [0/0], 00:08:27, direct 192.168.2.254/32, ubest/mbest: 1/0, attached     *via 192.168.2.254, Eth1/3, [0/0], 00:08:27, local, local Leaf-103# Leaf-103# show ip route vrf TestTenant:TestVrf2 192.168.1.1/32 det <output omitted> 192.168.1.1/32, ubest/mbest: 1/0, attached, direct, pervasive     *via 10.0.96.64%overlay-1, [1/0], 00:15:41, static, tag 4294967292          recursive next hop: 10.0.96.64/32%overlay-1          vrf crossing information:  VNID:0x288000 ClassId:0x1562 Flush#:0x3

Несложно догадаться, что 0x288000 (2654208) – это VNID, назначенный TestVrf1:

ClassID 0x1562 (5474) соответствует Provider EPG:

Глобальный pcTag (5475) назначен External EPG на L3Out. Вы же помните, что контракт всегда реализует consumer leaf? Так вот, ingress enforcement контракта (настройка VRF) требует обратного – выполнять контракт на compute leaf вместо border leaf. В нашем случае compute leaf является provider leaf; чтобы применить контракт, он должен знать pcTag на L3Out, а это значит, что L3Out EPG должен иметь глобальный pcTag.

Запутались? Вообще непонятно, где же в конечном счёте происходит применение контракта? Давайте разбираться. Заглянем в душу border leaf, чтобы понять, какие политики он реализует со своей стороны:

Leaf-103# show zoning-rule scope 2818048 +---------+--------+--------+----------+----------------+---------+---------+-------------------------+----------+------------------------+ | Rule ID | SrcEPG | DstEPG | FilterID |      Dir       |  operSt |  Scope  |           Name          |  Action  |        Priority        | +---------+--------+--------+----------+----------------+---------+---------+-------------------------+----------+------------------------+ |   4102  |   0    |   0    | implarp  |    uni-dir     | enabled | 2818048 |                         |  permit  |   any_any_filter(17)   | |   4099  |   0    |   0    | implicit |    uni-dir     | enabled | 2818048 |                         | deny,log |    any_any_any(21)     | |   4098  |   0    |   15   | implicit |    uni-dir     | enabled | 2818048 |                         | deny,log |  any_vrf_any_deny(22)  | |   4108  |  5474  |   0    | implicit |    uni-dir     | enabled | 2818048 |                         | deny,log | shsrc_any_any_deny(12) | |   4111  |  5474  |  5475  |    4     | uni-dir-ignore | enabled | 2818048 | TestTenant:TestContract |  permit  |     fully_qual(7)      | |   4110  |  5475  |  5474  |    4     |     bi-dir     | enabled | 2818048 | TestTenant:TestContract |  permit  |     fully_qual(7)      | +---------+--------+--------+----------+----------------+---------+---------+-------------------------+----------+------------------------+ 

Пройдёмся по правилам фильтрации для TestVrf2:

  • ID 4102: разрешает ARP, from any to any;

  • ID 4099: запрещает любой трафик, from any to any;

  • ID 4098: запрещает любой трафик, from any to 0.0.0.0/0, который анонсирует L3Out внутрь фабрики (запись должна присутствовать в случае, если настроена Preferred Group);

  • ID 4108: запрещает любой трафик, from Provider (с глобальным pcTag) to any – всегда присутствует в consumer VRF, чтобы отбрасывать трафик, не попадающий в контракт (provider VRF не реализует обычно политику);

  • ID 4110-4111: разрешает трафик между Provider и L3Out EPG согласно фильтру 4.

 С border leaf покончено, самое время посмотреть на provider leaf.

Leaf-101# show ip route vrf TestTenant:TestVrf1  <output omitted> 2.2.2.2/32, ubest/mbest: 1/0     *via 10.0.88.68%overlay-1, [200/5], 00:20:18, bgp-65000, internal, tag 65000 192.168.1.0/24, ubest/mbest: 1/0, attached, direct, pervasive, dcs     *via 10.0.96.64%overlay-1, [1/0], 00:16:31, static 192.168.1.1/32, ubest/mbest: 1/0, attached, direct, pervasive, dcs     *via 10.0.96.64%overlay-1, [1/0], 00:17:58, static 192.168.1.254/32, ubest/mbest: 1/0, attached, pervasive     *via 192.168.1.254, Vlan4, [0/0], 00:16:31, local, local  Leaf-101# Leaf-101# show ip route vrf TestTenant:TestVrf1 2.2.2.2/32 det <output omitted> 2.2.2.2/32, ubest/mbest: 1/0     *via 10.0.88.68%overlay-1, [200/5], 00:20:28, bgp-65000, internal, tag 65000          client-specific data: 1d                recursive next hop: 10.0.88.68/32%overlay-1           BGP extended route information: BGP origin AS 65000 BGP peer AS 65000 rw-vnid: 0x2b0000 table-id: 0xe rw-mac: 0

Ситуация с compute leaf несколько отличается от того, что мы уже видели. За распространение внешних префиксов внутри фабрики отвечает MP-BGP. Обновления BGP содержат префикс и соответствующий VNID, поэтому специальный статический маршрут для перезаписи VNID не нужен. ClassID, по всей видимости, всё так же задан статически, так как в BGP соответствующей информации нет. Более того, соответствие между pcTag и префиксом можно получить совершенно другой командой:

Leaf-101# show system internal policy-mgr prefix  Requested prefix data  Vrf-Vni VRF-Id Table-Id Table-State  VRF-Name                    Addr                                Class Shared Remote Complete Svc_ena ======= ======  =========== =======  ============================ ================================= ====== ====== ====== ======== ======== 2752512 7      0x7           Up     common:default                                       0.0.0.0/0   15      False  False  False    False    2752512 7      0x80000007    Up     common:default                                            ::/0   15      False  False  False    False    2654208 15     0x8000000f    Up     TestTenant:TestVrf1                                       ::/0   15      False  False  False    False    2654208 15     0xf           Up     TestTenant:TestVrf1                                  0.0.0.0/0   15      False  False  False    False    2654208 15     0xf           Up     TestTenant:TestVrf1                                  2.2.2.2/32  5475    True   True   False    False   

Что насчёт контрактов? Применяет ли их и provider leaf, раз уж L3Out EPG получил глобальный pcTag?

Leaf-101# show zoning-rule scope 2654208 +---------+--------+--------+----------+----------------+---------+---------+-------------------------+-----------------+----------------------+ | Rule ID | SrcEPG | DstEPG | FilterID |      Dir       |  operSt |  Scope  |           Name          |      Action     |       Priority       | +---------+--------+--------+----------+----------------+---------+---------+-------------------------+-----------------+----------------------+ |   4104  |   0    | 49153  | implicit |    uni-dir     | enabled | 2654208 |                         |      permit     |   any_dest_any(16)   | |   4101  |   0    |   0    | implarp  |    uni-dir     | enabled | 2654208 |                         |      permit     |  any_any_filter(17)  | |   4103  |   0    |   0    | implicit |    uni-dir     | enabled | 2654208 |                         |     deny,log    |   any_any_any(21)    | |   4102  |   0    |   15   | implicit |    uni-dir     | enabled | 2654208 |                         |     deny,log    | any_vrf_any_deny(22) | |   4113  |  5475  |  5474  |    4     |     bi-dir     | enabled | 2654208 | TestTenant:TestContract |      permit     |    fully_qual(7)     | |   4115  |  5474  |   14   | implicit |    uni-dir     | enabled | 2654208 |                         | permit_override |    src_dst_any(9)    | |   4111  |  5474  |  5475  |    4     | uni-dir-ignore | enabled | 2654208 | TestTenant:TestContract |      permit     |    fully_qual(7)     | +---------+--------+--------+----------+----------------+---------+---------+-------------------------+-----------------+----------------------+

Похоже, что и compute leaf, и provider leaf реализуют контракты:

  • ID 4104: разрешает любой трафик, from any to TestBD1 – flooding внутри BD;

  • ID 4101: разрешает ARP, from any to any;

  • ID 4103: запрещает любой трафик, from any to any;

  • ID 4102: запрещает любой трафик, from any to 0.0.0.0/0, который анонсирует L3Out внутрь фабрики (запись должна присутствовать в случае, если настроена Preferred Group);

  • ID 4115: разрешает обратный трафик, from Provider to consumer VRF;

  • ID 4111, 4113: разрешает трафик между Provider и L3Out EPG согласно фильтру 4.

Впрочем, это не означает, что применение политики происходит дважды. Как только пакет успешно проходит все фильтры, коммутатор выставляет биты SP и DP в заголовке iVXLAN исходящего пакета, так что двойной работы никто не выполняет. Неочевидность точки применения политики – безусловно, лишнее использование TCAM – пожалуй, да, но излишней обработки пакетов не происходит.

Вернёмся к нашим баранам. Представим, что TestEPG жутко понадобилось начать общаться с Provider, но есть некое ограничение, которое делает использование контракта не самым удобным решением. В такой ситуации кажется, что Preferred Group является подходящим инструментом, поскольку члены такой группы могут общаться между собой без определения какого-либо контракта. На данном этапе EPG входят в группу, но сама функция не включена на уровне VRF, так что никакого эффекта мы не видим. Включим Preferred Group через GUI, так как я не нашёл соответствующей опции в Terraform (provider версии 2.5.2).

Сломалась ли связность, как предсказывал white paper?

Host# ping 192.168.1.1 vrf Provider source 2.2.2.2 PING 192.168.1.1 (192.168.1.1) from 2.2.2.2: 56 data bytes 64 bytes from 192.168.1.1: icmp_seq=0 ttl=252 time=1.832 ms 64 bytes from 192.168.1.1: icmp_seq=1 ttl=252 time=1.254 ms 64 bytes from 192.168.1.1: icmp_seq=2 ttl=252 time=1.285 ms 64 bytes from 192.168.1.1: icmp_seq=3 ttl=252 time=1.529 ms 64 bytes from 192.168.1.1: icmp_seq=4 ttl=252 time=1.579 ms  --- 192.168.1.1 ping statistics --- 5 packets transmitted, 5 packets received, 0.00% packet loss round-trip min/avg/max = 1.254/1.495/1.832 ms Host# Host# ping 192.168.1.254 vrf TestEPG PING 192.168.1.254 (192.168.1.254): 56 data bytes 64 bytes from 192.168.1.254: icmp_seq=0 ttl=63 time=1.256 ms 64 bytes from 192.168.1.254: icmp_seq=1 ttl=63 time=0.943 ms 64 bytes from 192.168.1.254: icmp_seq=2 ttl=63 time=1.002 ms 64 bytes from 192.168.1.254: icmp_seq=3 ttl=63 time=1.02 ms 64 bytes from 192.168.1.254: icmp_seq=4 ttl=63 time=0.993 ms  --- 192.168.1.254 ping statistics --- 5 packets transmitted, 5 packets received, 0.00% packet loss round-trip min/avg/max = 0.943/1.042/1.256 ms Host# Host# ping 192.168.1.2 vrf Provider PING 192.168.1.2 (192.168.1.2): 56 data bytes Request 0 timed out Request 1 timed out Request 2 timed out Request 3 timed out Request 4 timed out  --- 192.168.1.2 ping statistics --- 5 packets transmitted, 0 packets received, 100.00% packet loss

2.2.2.2/32 всё ещё может добраться до 192.168.1.1/32, а вот от Preferred Group толку нет. Уберём Provider из контракта:

Host# ping 192.168.1.2 vrf A PING 192.168.1.2 (192.168.1.2): 56 data bytes 64 bytes from 192.168.1.2: icmp_seq=0 ttl=254 time=1.926 ms 64 bytes from 192.168.1.2: icmp_seq=1 ttl=254 time=1.484 ms 64 bytes from 192.168.1.2: icmp_seq=2 ttl=254 time=1.248 ms 64 bytes from 192.168.1.2: icmp_seq=3 ttl=254 time=1.272 ms 64 bytes from 192.168.1.2: icmp_seq=4 ttl=254 time=1.521 ms  --- 192.168.1.2 ping statistics --- 5 packets transmitted, 5 packets received, 0.00% packet loss round-trip min/avg/max = 1.248/1.49/1.926 ms

Вуаля, очнулась связность в Preferred Group, хоть и ценой невозможности предоставить контракт L3Out из другого VRF.

+---------+--------+--------+----------+---------+---------+---------+------+----------+----------------------------+ | Rule ID | SrcEPG | DstEPG | FilterID |   Dir   |  operSt |  Scope  | Name |  Action  |          Priority          | +---------+--------+--------+----------+---------+---------+---------+------+----------+----------------------------+ |   4104  |   0    | 49153  | implicit | uni-dir | enabled | 2654208 |      |  permit  |      any_dest_any(16)      | |   4101  |   0    |   0    | implarp  | uni-dir | enabled | 2654208 |      |  permit  |     any_any_filter(17)     | |   4103  |   0    |   0    | implicit | uni-dir | enabled | 2654208 |      |  permit  | grp_any_any_any_permit(20) | |   4102  |   0    |   15   | implicit | uni-dir | enabled | 2654208 |      | deny,log | grp_any_dest_any_deny(19)  | |   4114  | 32770  |   0    | implicit | uni-dir | enabled | 2654208 |      | deny,log |  grp_src_any_any_deny(18)  | +---------+--------+--------+----------+---------+---------+---------+------+----------+----------------------------+

Читатель мог заметить небольшие изменения в таблице с фильтрами. Посмотрим на правило ID 4103: вместо deny оно использует permit. Это следствие Preferred Group: трафик внутри VRF разрешён по умолчанию. Если бы у нас были ещё EPG, которые не входили бы в Preferred Group, то их трафик был бы явным образом запрещён. Трафик, приходящий из L3Out, использует pcTag, назначенный VRF; такой трафик не является частью Preferred Group, поэтому его также нужно явно запретить – так возикает правило ID 4114.

Вернёмся на шаг назад, когда контракт был ещё в силе:

Leaf-101# show zoning-rule scope 2654208 +---------+--------+--------+----------+----------------+---------+---------+-------------------------+-----------------+----------------------------+ | Rule ID | SrcEPG | DstEPG | FilterID |      Dir       |  operSt |  Scope  |           Name          |      Action     |          Priority          | +---------+--------+--------+----------+----------------+---------+---------+-------------------------+-----------------+----------------------------+ |   4104  |   0    | 49153  | implicit |    uni-dir     | enabled | 2654208 |                         |      permit     |      any_dest_any(16)      | |   4101  |   0    |   0    | implarp  |    uni-dir     | enabled | 2654208 |                         |      permit     |     any_any_filter(17)     | |   4103  |   0    |   0    | implicit |    uni-dir     | enabled | 2654208 |                         |      permit     | grp_any_any_any_permit(20) | |   4102  |   0    |   15   | implicit |    uni-dir     | enabled | 2654208 |                         |     deny,log    | grp_any_dest_any_deny(19)  | |   4113  |  5475  |  5474  |    4     |     bi-dir     | enabled | 2654208 | TestTenant:TestContract |      permit     |       fully_qual(7)        | |   4115  |  5474  |   14   | implicit |    uni-dir     | enabled | 2654208 |                         | permit_override |       src_dst_any(9)       | |   4111  |  5474  |  5475  |    4     | uni-dir-ignore | enabled | 2654208 | TestTenant:TestContract |      permit     |       fully_qual(7)        | |   4112  |  5474  |   0    | implicit |    uni-dir     | enabled | 2654208 |                         |     deny,log    |  grp_src_any_any_deny(18)  | |   4114  | 32770  |   0    | implicit |    uni-dir     | enabled | 2654208 |                         |     deny,log    |  grp_src_any_any_deny(18)  | +---------+--------+--------+----------+----------------+---------+---------+-------------------------+-----------------+----------------------------+

Если совместить фильтры, соответствующие применению контракта и включению Preferred Group, можно заметить одну «лишнюю» запись – ID 4112. Это и есть герой сегодняшней статьи: трафик от Provider к TestEPG попадает под это правило и отправляется в цифровой рай досрочно. Именно такой фильтр и указан в оригинальном описании дефекта. В white paper есть объяснение похожего фильтра, однако его приоритет отличается от того, что нам нужно (src_any_any_deny vs grp_src_any_any_deny). Мне так и не удалось найти объяснение, что именно означает это правило или почему оно появляется в описанном сценарии.

Впрочем, практического смысла в выполненном упражнении нет: ограничение явным образом упомянуто в документации. Сложные системы (такие, как ACI) нужно использовать только согласно одобренным сценариям, а не полагаться на разумность решения или общеприменимые соображения. Сложность только в том, чтобы найти такие сценарии, которые ещё и полностью отвечают требованиям, или же внимательно прочесть всю документацию по продукту. Что касается статьи, я надеюсь, мне удалось добавить немного контекста к дефекту, чтобы сузить его от загадочного ограничения в white paper до одной-единственной строчки в zoning table.

Спасибо за рецензию: Анастасии Куралёвой

Канал в Телеграме: https://t.me/networking_it_ru


ссылка на оригинал статьи https://habr.com/ru/post/712012/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *