В конце 2023 года отечественный вендор B4com Tech анонсировал выпуск маршрутизаторов для провайдерского сегмента IP/MPLS. Среди новых моделей наше внимание привлекли те, которые поддерживают интерфейсы 100G, поскольку они стали стандартом подключения в современных центрах обработки данных (ЦОД).

В модельный ряд входят устройства MR-381 и MR-382, различающиеся интерфейсами, но построенные на одном чипе — Broadcom Qumran2C. Этот чип активно используется в таких маршрутизаторах, как Cisco NCS 5500/5700, Juniper ACX7000 и Edge-Core AGR400.

B4com MR-381
B4com MR-381

Программное обеспечение

На текущий момент используется B4comOS. Это операционная система, построенная изначально на OcNOS от IP Infusion, но с 2022 года полностью отделившаяся и развивающаяся самостоятельно.

Ниже — схема с описанием основных модулей, которые используются в ОС.

Схема архитектуры ПО
Схема архитектуры ПО

За время, пока я работаю с оборудованием этого вендора, не раз возникала потребность в подобной картинке. Например, периодически приходится обращаться к модулю HSL, который занимается программированием ASIC'а и, соответственно, может показывать информацию о FIB. Ещё интерес представляет модуль NSM, который отвечает за control-plane. Бывает так, что нужно и в него заглянуть. Поэтому хочется всё-таки не просто вводить какие-то команды и смотреть результаты вывода, а ещё и понимать, что происходит.

Первое наше знакомство с MR

С чипом мы уже знакомы и знаем его возможности. Но вопрос в том, как вендор смог адаптировать ASIC и насколько софт, скажем так, "сырой". В общем, в конце 2023 года мы взяли 2 коробки на тесты. Провели достаточно ограниченное тестирование на предмет использования этих маршрутизаторов в сети одного из наших заказчиков. Смотрели на базовый функционал: IS-IS, LDP, L3VPN (средствами MP-BGP VPNv4). Нагружали до 90 Gbps. Нашли мелкие нюансы, о которых знали заранее по работе с коммутаторами, и быстро их сами поправили. В целом, всё было нормально и без каких-либо подводных камней.

Однако следует понимать, что эти тесты были однобокими и удовлетворяли потребности только одного заказчика. А поскольку у нас их несколько, весной этого года возникла необходимость повторить тесты, но уже с более интересным и комплексным дизайном.

Речь идёт про EVPN-MPLS с Active-Active IRB и Anycast Gateway. Для тех, кто не знаком с этой темой, вот две полезные статьи: Статья 1 и Статья 2.

Тесты EVPN-MPLS

Топология

Наша тестовая среда включает два сегмента: EVPN-VXLAN и EVPN-MPLS.

Схема среды для тестирования
Схема среды для тестирования

Включения между сегментами выполнены для «проброса» двух сервисов: L3 и L2.

Для L3 используется стандартный Option-A, который с обоих сторон передаётся как type-5 EVPN, но на «стыке» разрывается и передаётся как чистый IPv4.

Пример конфигурации Option-A на PE и BL

Border-leaf

router bgp 300
!
address-family ipv4 vrf VRF-A
max-paths ebgp 2
neighbor 1.1.1.0 remote-as 500
neighbor 1.1.1.0 activate
no neighbor 1.1.1.0 send-community both
neighbor 1.1.1.2 remote-as 500
neighbor 1.1.1.2 activate
no neighbor 1.1.1.2 send-community both
neighbor 1.1.1.0 update-source 1.1.1.1
neighbor 1.1.1.2 update-source 1.1.1.3
exit-address-family
!
address-family ipv4 vrf VRF-B
max-paths ebgp 2
neighbor 2.2.2.0 remote-as 500
neighbor 2.2.2.0 activate
no neighbor 2.2.2.0 send-community both
neighbor 2.2.2.2 remote-as 500
neighbor 2.2.2.2 activate
no neighbor 2.2.2.2 send-community both
neighbor 2.2.2.0 update-source 2.2.2.1
neighbor 2.2.2.2 update-source 2.2.2.3
exit-address-family
!

PE

router bgp 500
!
address-family ipv4 vrf VRF-A
max-paths ebgp 2
neighbor 1.1.1.1 remote-as 300
neighbor 1.1.1.1 activate
neighbor 1.1.1.5 remote-as 301
neighbor 1.1.1.5 activate
neighbor 1.1.1.1 update-source 1.1.1.0
neighbor 1.1.1.5 update-source 1.1.1.4
exit-address-family
!
address-family ipv4 vrf VRF-B
max-paths ebgp 2
neighbor 2.2.2.1 remote-as 300
neighbor 2.2.2.1 activate
neighbor 2.2.2.5 remote-as 301
neighbor 2.2.2.5 activate
neighbor 2.2.2.1 update-source 2.2.2.0
neighbor 2.2.2.5 update-source 2.2.2.4
exit-address-family
!
exit
!

L2 включает более сложные сценарии. Оба сегмента используют EVPN-MH (EVPN Multi-Homing), можно назвать back-to-back evpn-mh (аналогично back-to-back vpc). Объединение выполнено в один общий LAG на 4 физических интерфейсах с разными ESI на парах.

Пример конфигурации L2 на PE и BL

Border-leaf

interface ce2
channel-group 1 mode active
lldp-agent
set lldp port-id-tlv if-name
exit
!
interface po1
switchport
load-interval 30
mtu 9216
evpn multi-homed system-mac 0000.1111.bbbb
port-channel load-balance rtag7

PE

interface ce22 
channel‑group 1 mode active
lldp‑agent
set lldp port‑id‑tlv if‑name
exit
!
interface po1 
switchport
load‑interval 30 
mtu 9216 
evpn multi‑homed system‑mac 0000.1111.aaaa
!

В стенде у нас 2500 таких растянутых L2-сетей, соответственно, такое же количество IRB-интерфейсов на обоих PE, всё это в режиме Active-Active с Anycast Gateway.

Пример конфигурации сервиса на PE

указываем MAC для AGW

evpn irb-forwarding anycast-gateway-mac 0011.2233.4455

создаём 2500 L2 сервисов

mac vrf vni_1000
rd 20.0.0.1:1000
route-target both 500:1000
...
mac vrf vni_3499
rd 20.0.0.1:3499
route-target both 500:3499

создаём 2500 интерфейсов

interface irb1000
ip vrf forwarding VRF-A
evpn irb-if-forwarding anycast-gateway-mac
ip address 30.0.0.1/24
...
interface irb3499
ip vrf forwarding VRF-A
evpn irb-if-forwarding anycast-gateway-mac
ip address 30.9.195.1/24

создаём 2500 evpn-id

evpn mpls id 1000
host-reachability-protocol evpn-bgp vni_1000
evpn irb irb1000
...
evpn mpls id 3499
host-reachability-protocol evpn-bgp vni_3499
evpn irb irb3499

создаём 2500 l2-subinterface

interface po1.1000 switchport
encapsulation dot1q 1000
rewrite pop
mtu 9216
access-if-evpn
map vpn-id 1000
...
interface po1.3499 switchport
encapsulation dot1q 3499
rewrite pop
mtu 9216
access-if-evpn
map vpn-id 3499

На BL настройка чуть проще, так как не требуется использовать IRB и L2-subinterface, растягиваем чистый L2 по EVPN-VXLAN домену.

Пример конфигурации сервиса на BL

создаём 2500 L2 сервисов

nvo vxlan id 11000 ingress-replication inner-vid-disabled
vxlan host-reachability-protocol evpn-bgp vni_11000
vni-name vni_11000
...
nvo vxlan id 13499 ingress-replication inner-vid-disabled
vxlan host-reachability-protocol evpn-bgp vni_13499
vni-name vni_13499

привязываем 2500 сервисов к целевому порту

nvo vxlan access-if port-vlan po1 1000
map vni-name vni_11000
...
nvo vxlan access-if port-vlan po1 3499
map vni-name vni_13499

Методика тестирования

Для генерации трафика использовался TRex.

В тесте запускались 2500 потоков, каждый с уникальным source IP и dot1q тегом, но общим destination IP. Это обеспечивает достаточную энтропию для балансировки и тестирует все 2500 IRB-интерфейсов, через которые маршрутизируется трафик.

Пример скрипта для генерации трафика
from trex_stl_lib.api import *
import argparse
import os

class STLS1(object):
    def __init__(self):
        self.mac_counter = 0  # Initialize a counter for generating MAC addresses

    def generate_mac(self):
        base_mac = [0x10, 0x70, 0x00, 0x00, 0x00, 0x00]
        mac_suffix = self.mac_counter * 4096  # Increment by 4096 for each new MAC
        for i in range(5, 1, -1):
            base_mac[i] = mac_suffix & 0xFF
            mac_suffix >>= 8
        self.mac_counter += 1
        return ':'.join('{:02x}'.format(b) for b in base_mac)

    def create_stream(self, vlan_id, src_ip, src_mac, pkt_size=1400):
        # Calculate the payload size needed to reach the desired packet size
        header_size = len(Ether() / Dot1Q() / IP() / UDP())
        payload_size = pkt_size - header_size
        payload = 'x' * payload_size

        return STLStream(
            packet=STLPktBuilder(pkt=Ether(src=src_mac, dst="00:11:22:33:44:55") /
                                  Dot1Q(prio=1, vlan=vlan_id) /
                                  IP(src=src_ip, dst="10.200.0.5") /
                                  UDP(dport=12, sport=1025) / payload),
            mode=STLTXCont(pps=10),
            # mac_dst_override_mode=STLStreamDstMAC_PKT # another way to explicitly take it
        )

    def get_streams(self, direction, tunables, **kwargs):
        parser = argparse.ArgumentParser(description='Argparser for {}'.format(os.path.basename(__file__)),
                                         formatter_class=argparse.ArgumentDefaultsHelpFormatter)

        args = parser.parse_args(tunables)
        streams = []
        # Loop to generate streams for varying VLAN IDs and source IP addresses
        vlan_id = 1000
        for i in range(0, 10):  # second octet range
            for j in range(0, 256):  # third octet range
                src_ip = f"30.{i}.{j}.10"
                src_mac = self.generate_mac()
                streams.append(self.create_stream(vlan_id, src_ip, src_mac))
                vlan_id += 1  # Increment VLAN ID for each stream
                if vlan_id > 1010:
                    break
            if vlan_id > 1010:
                break
        return streams

# dynamic load - used for trex console or simulator
def register():
    return STLS1()

Сервис L2 растянут до хоста, а на PE (Provider Edge) этот сервис терминируется через IRB-интерфейсы. Конфигурации этих интерфейсов были описаны ранее.

Как видно из вышеописанного, мы предполагаем нагрузочное тестирование и пускаем трафик через большой объем сервисов, в данном случае 2500 штук. Это позволяет заранее выявить узкие места и создать качественную архитектуру.

Что касается полосы пропускания, то мы используем сценарий постепенного набора с шагом в 1% от максимума на порту, то есть 1 Gbps. Вначале запускаем трафик на 1 Gbps, который приблизительно равномерно распределяется по всем созданным сервисам, и затем начинаем наращивать объем.

Мы отслеживаем состояние как control plane, так и data plane. С контрольной плоскостью все понятно: достаточно включить логи и наблюдать за активностью используемых протоколов. Они должны быть стабильными и не должны флапать или перестраиваться. В отношении data plane сначала анализируем счетчики на дашборде TRex, и если необходимо, смотрим аналогичную информацию на самих узлах.

Результат тестов

При базовой нагрузке (1 Gbps) проблем не возникает.

DF/Non-DF выбираются корректно. Принцип выбора соответствует RFC7432 и подробно разобран в статьях, которые я приложил выше.

PE1-MR381#sh evpn mpls 
EVPN-MPLS Information 
================= 
   Codes: NW - Network Port 
          AC - Access Port 
         (u) - Untagged 

VPN-ID   EVI-Name     EVI-Type Type Interface ESI                           VLAN      DF-Status Src-Addr         Dst-Addr        
_______________________________________________________________________________________________________________________________
1000     ----         L2       NW   ----      ----                          ----      ----      20.0.0.1         20.0.0.3        
1000     ----         --       AC   po1.1000  00:00:00:11:11:aa:aa:00:00:00 ----      DF        ----             ----            
1001     ----         L2       NW   ----      ----                          ----      ----      20.0.0.1         20.0.0.3        
1001     ----         --       AC   po1.1001  00:00:00:11:11:aa:aa:00:00:00 ----      NON-DF    ----             ----            
1002     ----         L2       NW   ----      ----                          ----      ----      20.0.0.1         20.0.0.3        
1002     ----         --       AC   po1.1002  00:00:00:11:11:aa:aa:00:00:00 ----      DF        ----             ----            

.....

3497     ----         L2       NW   ----      ----                          ----      ----      20.0.0.1         20.0.0.3        
3497     ----         --       AC   po1.3497  00:00:00:11:11:aa:aa:00:00:00 ----      NON-DF    ----             ----            
3498     ----         L2       NW   ----      ----                          ----      ----      20.0.0.1         20.0.0.3        
3498     ----         --       AC   po1.3498  00:00:00:11:11:aa:aa:00:00:00 ----      DF        ----             ----            
3499     ----         L2       NW   ----      ----                          ----      ----      20.0.0.1         20.0.0.3        
3499     ----         --       AC   po1.3499  00:00:00:11:11:aa:aa:00:00:00 ----      NON-DF    ----             ----     

Аналогичная история с Aliasing и ESI label.

PE1-MR381#sh evpn mpls label alias 
S - Self
R - Remote
ESI                            PE-IP-ADDRESS        TENANT               ALIAS-LABEL         
=============================================================================================
00:00:00:11:11:aa:aa:00:00:00  20.0.0.1(S)          1000                   30
00:00:00:11:11:aa:aa:00:00:00  20.0.0.1(S)          1001                   29
00:00:00:11:11:aa:aa:00:00:00  20.0.0.1(S)          1002                   28

....

00:00:00:11:11:aa:aa:00:00:00  20.0.0.3(R)          3497                31959
00:00:00:11:11:aa:aa:00:00:00  20.0.0.3(R)          3498                31958
00:00:00:11:11:aa:aa:00:00:00  20.0.0.3(R)          3499                31961
PE1-MR381#sh evpn mpls label esi 
S - Self
R - Remote
ESI                            PE-IP-ADDRESS        ESI-LABEL           
================================================================
00:00:00:11:11:aa:aa:00:00:00  20.0.0.1(S)            18
00:00:00:11:11:aa:aa:00:00:00  20.0.0.3(R)            18

Продолжая увеличивать нагрузку, мы заметили, что при использовании UDP в качестве заголовков трафик на PE неверно классифицируется и попадает в другую очередь, где в дальнейшем отбрасывается.

Вывод с MR
Вывод с MR

При использовании TCP подобной проблемы не возникает, и весь трафик классифицируется корректно.

После общения с вендором и корректировки данного поведения для UDP потоков с помощью патча, мы повторили тесты и успешно достигли целевой нагрузки.

Вывод с TRex
Вывод с TRex

Также счетчики на очередях показывают корректные значения.

Вывод с MR
Вывод с MR

Выводы

Этот опыт показал важность комплексного тестирования. Без нагрузочных тестов мы могли бы перейти к следующей фазе и не обратить внимание на особенности реализации, что могло бы привести к проблемам на этапе ПНР или, что еще хуже, на ПСИ. В такой ситуации времени на разбор полетов уже не будет, и придется действовать быстро и решительно. Также мы проверили готовность вендора к быстрому реагированию на выявленные недостатки, что является важным фактором для дальнейшего взаимодействия.

Подписывайтесь на мой канал: https://t.me/like_a_bus_channel. Пишу о тестах, своем опыте и прочем, с чем сталкиваюсь на работе и не только!

Комментарии (1)


  1. eskhaliot
    04.08.2024 00:44

    Ждём полноценный hvpls