Cisco ACI FTAG: деревья внутри

от автора

Порядок передачи unicast трафика внутри фабрики Cisco ACI подробно описан в различных источниках, хотя внимательно изучить их и не свихнуться – та ещё задачка. Распространению BUM внутри overlay посвящены несколько секций, но вот то, что происходит в underlay, на мой взгляд, сознательно вынесено из основного документа. Тут вовлечена некая сущность – FTAG: один из spine становится корнем дерева, к которому присоединяются все leaf-коммутаторы. Общее количество активных FTAG – 12; очевидно, так сделали, чтобы обеспечить отказоусточивость и некую балансировку нагрузки.

Описание выше разумно, однако оно вызывает несколько вопросов:

  1. Как происходит передача BUM трафика, когда uplink на leaf-коммутаторе выходит из строя? Если только один spine участвует в построении дерева, то трафик при таком сценарии некуда слать, значит, придётся отбросить – не очень-то отказоустойчиво получается.

  2. Рассмотрим применение Remote Leaf: RL отправляют BUM трафик на anycast адрес spine-коммутаторов. Что произойдёт, если такой трафик попадёт на spine, который не участвует в нужном FTAG? Тот же самый вопрос справедлив и для Multi-Site архитектуры.

На сайте CiscoLive есть хороший семинар, который поможет нам ответить на эти вопросы. Схема лабы очень проста:

Всё, что нам нужно – это поднять связность между двумя endpoint в одном EPG.

Модуль Tenant:

resource "aci_tenant" "TestTenant" {     name                = "TestTenant" } resource "aci_vrf" "TestVrf" {     tenant_dn           = aci_tenant.TestTenant.id     name                = "TestVrf" } resource "aci_bridge_domain" "TestBD1" {     tenant_dn           = aci_tenant.TestTenant.id     name                = "TestBD1"     relation_fv_rs_ctx  = aci_vrf.TestVrf.id } resource "aci_subnet" "Subnet1" {     parent_dn        = aci_bridge_domain.TestBD1.id     ip               = "192.168.0.254/24"     scope            = ["private", "shared"] } resource "aci_application_profile" "TestAP" {     tenant_dn           = aci_tenant.TestTenant.id     name                = "TestAP" } resource "aci_application_epg" "TestEPG1" {     application_profile_dn  = aci_application_profile.TestAP.id     name                    = "TestEPG1"     relation_fv_rs_bd       = aci_bridge_domain.TestBD1.id } resource "aci_epg_to_domain" "EPG1Domain" {     application_epg_dn  = aci_application_epg.TestEPG1.id     tdn                 = aci_physical_domain.PhysicalDomain.id } resource "aci_bulk_epg_to_static_path" "TestEPG1StaticPath" {   application_epg_dn = aci_application_epg.TestEPG1.id   static_path {     interface_dn         = "topology/pod-1/paths-101/pathep-[eth1/2]"     encap                = "vlan-101"   }   static_path {     interface_dn         = "topology/pod-1/paths-104/pathep-[eth1/2]"     encap                = "vlan-101"   } }

Модуль Access policies:

resource "aci_vlan_pool" "TestPool" {   name  = "TestPool"   description = "From Terraform"   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_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_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                 = "2" } 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  = "Leaf101"       from_ = "101"       to_   = "101"     }     node_block {       name  = "Leaf104"       from_ = "104"       to_   = "104"     }   }   relation_infra_rs_acc_port_p = [aci_leaf_interface_profile.TestInterfaceProfile.id] }

Если пробежаться по презентации, можно заметить, что схема FTAG немного отличается от таковой в документации: spine-коммутаторы, которые не являются корневыми, всё равно участвуют в FTAG, подключаясь к дереву через один-единственный leaf. Помните, что выбор корня FTAG происходит через расширение IS-IS? Заглянем в консоль:

Spine202# show isis internal mcast routes ftag <output omitted>  FTAG ID:   0 [Root] [Enabled] Cost:(   2/  13/   0)  ----------------------------------     Root port: Ethernet1/1.68     OIF List:   FTAG ID:   1 [Root] [Enabled] Cost:(   0/   0/   0)  ----------------------------------     Root port: -     OIF List:       Ethernet1/1.68       Ethernet1/2.67       Ethernet1/3.70       Ethernet1/4.69   FTAG ID:   2 [Root] [Enabled] Cost:(   0/   0/   0)  ----------------------------------     Root port: -     OIF List:       Ethernet1/1.68       Ethernet1/2.67       Ethernet1/3.70       Ethernet1/4.69   FTAG ID:   3 [Root] [Enabled] Cost:(   0/   0/   0)  ----------------------------------     Root port: -     OIF List:       Ethernet1/1.68       Ethernet1/2.67       Ethernet1/3.70       Ethernet1/4.69   FTAG ID:   4 [Root] [Enabled] Cost:(   0/   0/   0)  ----------------------------------     Root port: -     OIF List:       Ethernet1/1.68       Ethernet1/2.67       Ethernet1/3.70       Ethernet1/4.69   FTAG ID:   5  [Enabled] Cost:(   2/   7/   0)  ----------------------------------     Root port: Ethernet1/3.70     OIF List:   FTAG ID:   6  [Enabled] Cost:(   2/   8/   0)  ----------------------------------     Root port: Ethernet1/2.67     OIF List:   FTAG ID:   7  [Enabled] Cost:(   2/   9/   0)  ----------------------------------     Root port: Ethernet1/2.67     OIF List:   FTAG ID:   8  [Enabled] Cost:(   2/   8/   0)  ----------------------------------     Root port: Ethernet1/3.70     OIF List:   FTAG ID:   9  [Enabled] Cost:(   2/   7/   0)  ----------------------------------     Root port: Ethernet1/4.69     OIF List:   FTAG ID:  10  [Enabled] Cost:(   2/  12/   0)  ----------------------------------     Root port: Ethernet1/1.68     OIF List:   FTAG ID:  11 [Root] [Enabled] Cost:(   0/   0/   0)  ----------------------------------     Root port: -     OIF List:       Ethernet1/1.68       Ethernet1/2.67       Ethernet1/3.70       Ethernet1/4.69   FTAG ID:  12 [Root] [Enabled] Cost:(   0/   0/   0)  ----------------------------------     Root port: -     OIF List:       Ethernet1/1.68       Ethernet1/2.67       Ethernet1/3.70       Ethernet1/4.69   FTAG ID:  13 [Disabled]   FTAG ID:  14 [Disabled]   FTAG ID:  15 [Disabled]
Spine201# show isis internal mcast route ftag <output omitted>  FTAG ID:   0 [Root] [Enabled] Cost:(   0/   0/   0)  ----------------------------------     Root port: -     OIF List:       Ethernet1/1.68       Ethernet1/2.67       Ethernet1/3.69       Ethernet1/4.70   FTAG ID:   1  [Enabled] Cost:(   2/   8/   0)  ----------------------------------     Root port: Ethernet1/2.67     OIF List:   FTAG ID:   2  [Enabled] Cost:(   2/   9/   0)  ----------------------------------     Root port: Ethernet1/2.67     OIF List:   FTAG ID:   3  [Enabled] Cost:(   2/   8/   0)  ----------------------------------     Root port: Ethernet1/3.69     OIF List:   FTAG ID:   4  [Enabled] Cost:(   2/   8/   0)  ----------------------------------     Root port: Ethernet1/4.70     OIF List:   FTAG ID:   5 [Root] [Enabled] Cost:(   0/   0/   0)  ----------------------------------     Root port: -     OIF List:       Ethernet1/1.68       Ethernet1/2.67       Ethernet1/3.69       Ethernet1/4.70   FTAG ID:   6 [Root] [Enabled] Cost:(   0/   0/   0)  ----------------------------------     Root port: -     OIF List:       Ethernet1/1.68       Ethernet1/2.67       Ethernet1/3.69       Ethernet1/4.70   FTAG ID:   7 [Root] [Enabled] Cost:(   0/   0/   0)  ----------------------------------     Root port: -     OIF List:       Ethernet1/1.68       Ethernet1/2.67       Ethernet1/3.69       Ethernet1/4.70   FTAG ID:   8 [Root] [Enabled] Cost:(   0/   0/   0)  ----------------------------------     Root port: -     OIF List:       Ethernet1/1.68       Ethernet1/2.67       Ethernet1/3.69       Ethernet1/4.70   FTAG ID:   9 [Root] [Enabled] Cost:(   0/   0/   0)  ----------------------------------     Root port: -     OIF List:       Ethernet1/1.68       Ethernet1/2.67       Ethernet1/3.69       Ethernet1/4.70   FTAG ID:  10 [Root] [Enabled] Cost:(   0/   0/   0)  ----------------------------------     Root port: -     OIF List:       Ethernet1/1.68       Ethernet1/2.67       Ethernet1/3.69       Ethernet1/4.70   FTAG ID:  11  [Enabled] Cost:(   2/  12/   0)  ----------------------------------     Root port: Ethernet1/1.68     OIF List:   FTAG ID:  12  [Enabled] Cost:(   2/  13/   0)  ----------------------------------     Root port: Ethernet1/1.68     OIF List:   FTAG ID:  13 [Disabled]   FTAG ID:  14 [Disabled]   FTAG ID:  15 [Disabled]

Действительно, все spine-коммутаторы участвуют в FTAG: если spine не является корнем, то у него не пуст Root port вместо OIL. GIPo адрес группы, которая соответствует BD – 225.0.69.80, поэтому она должна попадать в FTAG 0:

Такая топология позволяет естественным образом ответить на первый вопрос: если Leaf104 потеряет uplink в сторону Spine201, то он сможет использовать путь через Spine202 для передачи трафика внутри FTAG 0:

Spine202# show isis internal mcast routes ftag <output omitted>  FTAG ID:   0 [Root][DEFERED] [Enabled] Cost:(   2/  13/   0)  ----------------------------------     Root port: Ethernet1/1.68     OIF List:       Ethernet1/4.69        <--------- link towards Leaf104 <output omitted>
Leaf104# show isis internal mcast routes ftag <output omitted>  FTAG ID:   0  [Enabled] Cost:(   3/  13/   0)  ----------------------------------     Root port: Ethernet1/50.12        <--------- link towards Spine202     OIF List: <output omitted>

Ответ на второй вопрос тоже понятен: если трафик попадает на некорневой spine, тот передаёт полученные пакеты через один из leaf-коммутаторов в нужный FTAG.

Spine202# show isis internal mcast route gipo <output omitted>  GIPo: 225.0.69.80 [LOCAL]     OIF List:       Ethernet1/1.68       Ethernet1/4.70       Tunnel4        <--------- Multi-Site tunnel <output omitted>

Должен существовать некий механизм, предотвращающий отправку «внешнего» трафика обратно в сторону Remote Leaf или другого Site, но я не смог найти информацию о том, как именно он реализован (ставлю на некий бит в iVXLAN заголовке).

Имеет ли описанное выше какое-либо значение для эксплуатации ACI? Пожалуй, нет, в конце концов ACI – это решение «под ключ», которое прячет сложность внутри себя, в отличие от подхода «сделай сам». Впрочем, мне всё же кажется, было бы неплохо понимать, что именно происходит внутри подобной системы, а также иметь возможность в общем виде связать между собой подходы, присущие разным этапам эволюции продукта.

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

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


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


Комментарии

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

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