Unequal Cost Multi-Path
Hoje vamos falar um pouco sobre FIB Hashing, e iremos implementar UCMP utilizando BGP.
Aproveite e fique ligado na TechRebels e siga-me no Medium clicando follow lá em cima para acompanhar os próximos posts.
O multipathing nos permite instalar simultaneamente diversas rotas para o mesmo destino na tabela de roteamento, com o objetivo de distribuir o tráfego entre diversos next-hops. Após aprender a rota e instalar o prefixo na RIB e FIB, vem a parte mais importante: Como o tráfego de trânsito é distribuído entre os caminhos/next-hops?
Existe suporte a multipath em todos os protocolos de roteamento (isso mesmo, static, ospf2/3, isis, eigrp, bgp, etc), desde que a métrica do protocolo seja a mesma para todas as entradas, e as entradas devem ser idênticas. Isso mesmo. Para se instalar vários caminhos a um prefixo X, todos os atributos devem ser idênticos (com exceção do next-hop, é claro) para que sejam todas consideradas iguais, e inseridas na tabela. Obviamente, os prefixos devem ter sido aprendidos pelo mesmo protocolo de roteamento.
Alguns routers fazem a distribuição per-packet. Isso é, ele distribui os pacotes um a um de maneira igual entre os next-hops. Isso é conhecido também como round-robin.
Este método possui algumas desvantagens, pois a distribuição não é determinística. Isso quer dizer que pacotes do mesmo fluxo não necessariamente serão encaminhados pelo mesmo caminho, causando assimetria no tráfego.
Alguns comportamentos bem conhecidos e comuns são causados por esta assimetria, como a chegada dos pacotes fora de ordem e perda de state (caso exista(m) firewalls ou NAT no caminho).
No entanto, o tópico de hoje tem a ver com um outro tipo de distribuição de tráfego, que utiliza o que chamamos de FIB Hashing.
O FIB hashing consiste em avaliar o cabeçalho do pacote e associá-lo à uma determinada entrada na FIB — o que faz com que um mesmo fluxo sempre seja associado com a mesma entrada. Isso ocorre pois um fluxo é categorizado por [src_ip + dst_ip + src_port + dst_port] — resultando sempre no mesmo hash. (Apesar do exemplo acima, as “tuples” são geralmente configuráveis)
A maneira exata como a decisão de forwarding é tomada depende da plataforma, onde vários fatores tais como arquitetura de linecards e FIB variam de plataforma para plataforma.
Por default, quando existem mais de uma rota para o mesmo destino, a maioria dos equipamentos implementa o que chamamos de “ECMP”, ou Equal Cost Multi Path.
Com o ECMP, os fluxos (e não pacotes!!) serão distribuídos igualmente entre os next-hop, ocasionando em um comportamento determinístico durante o caminho entre o source e o destination (bem, assumindo que todos no caminho fazem este tipo de hashing). Em outras palavras, o mesmo flow sempre gerará o mesmo resultado hash, o que será sempre associado à mesma interface (ou next-hop, ou FIB entry).
Algumas implementações nos permitem influenciar este hashing — nos dando mais controle sobre como o tráfego é encaminhado para um determinado destino. Podendo influenciar este hashing, conseguimos implementar o que é conhecido como UCMP -Unequal Cost Multi Path.
Atualmente, EIGRP e BGP suportam UCMP. O EIGRP o faz com a feature conhecida como “variance”. Porem, o foco de hoje sera na implementação de UCMP via BGP, utilizando a community extended “Link BW Community”.
Link BW Community
Especificado inicialmente em 2009 pelo draft “ draft-rfernando-idr-link-bandwidth-00 “, a community Link Bandwidth é uma extended community Optional Non-transitive ( Valor 0x4004 ), e foi especificada com o intuito de sinalizar internamente ( aos peers iBGP ) as características de um link externo ( onde ocorre o peering eBGP ). Desta forma, os routers internos podem tomar uma decisão de roteamento mais específica. E, quando utilizado junto com a feature “multipath”, resulta em UCMP.
Até então, o uso desta community se dava principalmente em casos de peering em WANs, onde o uso de links de menor capacidade eram a única opção.
Por um bom tempo, o suporte desta feature em equipamentos Cisco (IOS) se restringia ao valor de BW da interface em que o peering é estabelecido:
Configuração básica (usando links de capacidades distintas):
##Edge1Edge1#sh run | sec bgp
router bgp 65000
bgp log-neighbor-changes
bgp dmzlink-bw
neighbor 10.0.0.0 remote-as 100
neighbor 10.0.0.0 dmzlink-bw
neighbor 10.10.10.10 remote-as 65000
neighbor 10.10.10.10 update-source Loopback0
neighbor 10.10.10.10 next-hop-self
neighbor 10.10.10.10 send-community bothEdge1#sh run int e0/1
Building configuration…Current configuration : 79 bytes
!
interface Ethernet0/1
ip address 10.0.0.1 255.255.255.254
duplex auto
endEdge1#sh ip b 8.8.8.8
BGP routing table entry for 8.8.8.8/32, version 2
Paths: (1 available, best #1, table default)
Advertised to update-groups:
2
Refresh Epoch 1
100
10.0.0.0 from 10.0.0.0 (8.8.8.8)
Origin IGP, metric 0, localpref 100, valid, external, best
DMZ-Link Bw 1250 kbytes
rx pathid: 0, tx pathid: 0x0Edge1#sh int e0/1
Ethernet0/1 is up, line protocol is up
Hardware is AmdP2, address is aabb.cc00.8110 (bia aabb.cc00.8110)
Internet address is 10.0.0.1/31
MTU 1500 bytes, BW 10000 Kbit/sec, DLY 1000 usec,###Edge2Edge2#sh run | sec bgp
router bgp 65000
bgp log-neighbor-changes
bgp dmzlink-bw
neighbor 10.0.1.0 remote-as 100
neighbor 10.0.1.0 dmzlink-bw
neighbor 10.10.10.10 remote-as 65000
neighbor 10.10.10.10 update-source Loopback0
neighbor 10.10.10.10 next-hop-self
neighbor 10.10.10.10 send-community bothEdge2# sh run int e0/1
Building configuration…Current configuration : 95 bytes
!
interface Ethernet0/1
bandwidth 2000
ip address 10.0.1.1 255.255.255.254
duplex auto
endEdge2#sh ip bgp 8.8.8.8
BGP routing table entry for 8.8.8.8/32, version 4
Paths: (1 available, best #1, table default)
Advertised to update-groups:
2
Refresh Epoch 3
100
10.0.1.0 from 10.0.1.0 (8.8.8.8)
Origin IGP, metric 0, localpref 100, valid, external, best
DMZ-Link Bw 250 kbytes
rx pathid: 0, tx pathid: 0x0Edge2#sh int e0/1
Ethernet0/1 is up, line protocol is up
Hardware is AmdP2, address is aabb.cc00.7110 (bia aabb.cc00.7110)
Internet address is 10.0.1.1/31
MTU 1500 bytes, BW 2000 Kbit/sec, DLY 1000 usec,
###CoreCORE#sh run | sec bgp
router bgp 65000
bgp log-neighbor-changes
bgp dmzlink-bw
neighbor IBGP peer-group
neighbor IBGP remote-as 65000
neighbor IBGP update-source Loopback0
neighbor IBGP next-hop-self
neighbor 1.1.1.1 peer-group IBGP
neighbor 2.2.2.2 peer-group IBGP
maximum-paths eibgp 20CORE#sh ip b 8.8.8.8
BGP routing table entry for 8.8.8.8/32, version 6
Paths: (2 available, best #1, table default)
Multipath: eiBGP
Not advertised to any peer
Refresh Epoch 1
100
2.2.2.2 (metric 11) from 2.2.2.2 (2.2.2.2)
Origin IGP, metric 0, localpref 100, valid, internal, multipath, best
DMZ-Link Bw 250 kbytes
rx pathid: 0, tx pathid: 0x0
Refresh Epoch 1
100
1.1.1.1 (metric 11) from 1.1.1.1 (172.16.50.1)
Origin IGP, metric 0, localpref 100, valid, internal, multipath(oldest)
DMZ-Link Bw 1250 kbytes
rx pathid: 0, tx pathid: 0CORE#sh ip route 8.8.8.8
Routing entry for 8.8.8.8/32
Known via “bgp 65000”, distance 200, metric 0
Tag 100, type internal
Last update from 2.2.2.2 00:00:13 ago
Routing Descriptor Blocks:
2.2.2.2, from 2.2.2.2, 00:00:13 ago
Route metric is 0, traffic share count is 1
AS Hops 1
Route tag 100
MPLS label: none
* 1.1.1.1, from 1.1.1.1, 00:00:13 ago
Route metric is 0, traffic share count is 5
AS Hops 1
Route tag 100
MPLS label: none
No exemplo acima, temos dois links em dois routers distintos, Edge1 possui um link de 10Mb e Edge2 possui um link de 2Mb. Ao configurar a feature de DMZ-Link BW, estes valores sao associados ao prefixo recebido do next-hop (8.8.8.8, no caso) em bytes/s.
Em seguida, validamos a tabela de roteamento, indicando uma distribuição de 5/1.
Em algumas plataformas (IOS-XR, Junos), este valor pode ser configurado manualmente. Com esta flexibilidade, podemos distribuir o fluxo de dados de uma forma bem granular.
Porém, vamos pensar no seguinte cenário. Temos aqui 4 servidores, que fornecem o mesmo serviço (NTP, DNS, etc. UDP, para simplificar). Num cenário ideal, gostaríamos sempre de ter nosso setup de uma maneira homogênea, com todos os dispositivos com capacidade semelhante e operacionalmente idênticos.
Não é bem o que acontece no mundo real, não é?
Então, vamos supor que, destes 4 servidores, o SERVER4 e SERVER2 são inferiores, com a metade da memória. Com o comportamento ECMP, todos os 4 servidores receberão aproximadamente a mesma carga. Eventualmente, os de capacidade inferior chegarão próximo do limite — o que pode degradar o tempo de resposta — ou até mesmo interferir no funcionamento do sistema operacional (que pode ou não hospedar outras aplicações — piorando o efeito).
Neste caso, podemos empregar o conceito de UCMP.
Para exemplificar o cenário, usarei a seguinte topologia:
Nossos IOS-XR e Junos atuarão como “Spine”, e teremos quatro routers IOS simulando “servidores”, ou até mesmo “Leaf” switches. A lógica que usaremos é a seguinte:
Caso o prefixo possua uma determinada community standard, utilizamos uma route-policy para transforma-la na community LB. Caso não haja nenhuma community (ou qualquer outro valor que não sejam os configurados explicitamente), associamos um valor mínimo:
LB_STD_16 --> LB_EXT_16 --> 64512:16000
LB_STD_32 --> LB_EXT_32 --> 64512:32000
LB_STD_64 --> LB_EXT_64 --> 64512:64000
ANY . --> LB_EXT_MIN -> 64512:8000
Voltando ao exemplo anterior, estes serão os valores que vamos configurar:
SERVER1 --> 64512:32000
SERVER2 --> 64512:16000
SERVER3 --> 64512:32000
SERVER4 --> 64512:16000
Agora as configurações básicas:
###Servidor:hostname Server4
!
interface Loopback0
ip address 4.4.4.4 255.255.255.255
ip ospf 1 area 0
!
interface Loopback1
description Anycast
ip address 172.16.10.1 255.255.255.255
!
interface Ethernet0/0
ip address 10.0.0.6 255.255.255.254
ip ospf network point-to-point
ip ospf 1 area 0
!
interface Ethernet0/1
ip address 10.0.1.6 255.255.255.254
ip ospf network point-to-point
ip ospf 1 area 0
!
router ospf 1
router-id 4.4.4.4
prefix-suppression
passive-interface Loopback0
!
router bgp 64512
neighbor SPINE peer-group
neighbor SPINE remote-as 64512
neighbor SPINE update-source Loopback0
neighbor 10.10.10.10 peer-group SPINE
neighbor 20.20.20.20 peer-group SPINE
!
address-family ipv4
network 172.16.10.1 mask 255.255.255.255
neighbor SPINE send-community
neighbor SPINE next-hop-self
neighbor 10.10.10.10 activate
neighbor 20.20.20.20 activate
exit-address-family!###Spine (XR):hostname SPINE1
interface Loopback0
ipv4 address 10.10.10.10 255.255.255.255
!
interface GigabitEthernet0/0/0/0
ipv4 address 10.0.0.1 255.255.255.254
!
interface GigabitEthernet0/0/0/1
ipv4 address 10.0.0.3 255.255.255.254
!
interface GigabitEthernet0/0/0/2
ipv4 address 10.0.0.5 255.255.255.254
!
interface GigabitEthernet0/0/0/3
ipv4 address 10.0.0.7 255.255.255.254
!
prefix-set HOST_ROUTES
0.0.0.0/0 eq 32
end-set
!
route-policy ANYCAST_IN
if destination in HOST_ROUTES then
done
else
drop
endif
end-policy
!
router ospf 1
address-family ipv4
area 0
interface Loopback0
!
interface GigabitEthernet0/0/0/0
network point-to-point
!
interface GigabitEthernet0/0/0/1
network point-to-point
!
interface GigabitEthernet0/0/0/2
network point-to-point
!
interface GigabitEthernet0/0/0/3
network point-to-point
!
!
!
router bgp 64512
bgp router-id 10.10.10.10
address-family ipv4 unicast
maximum-paths ibgp 4
!
neighbor-group IBGP
remote-as 64512
update-source Loopback0
address-family ipv4 unicast
route-policy ANYCAST_IN in
!
!
neighbor 1.1.1.1
use neighbor-group IBGP
!
neighbor 2.2.2.2
use neighbor-group IBGP
!
neighbor 3.3.3.3
use neighbor-group IBGP
!
neighbor 4.4.4.4
use neighbor-group IBGP
!###Spine (Junos)
Nota: !!! NUNCA usem "bgp allow 0.0.0.0/0" em um router em produção!!!!set interfaces ge-0/0/0 unit 0 family inet address 10.0.1.1/31
set interfaces ge-0/0/1 unit 0 family inet address 10.0.1.3/31
set interfaces ge-0/0/2 unit 0 family inet address 10.0.1.5/31
set interfaces ge-0/0/3 unit 0 family inet address 10.0.1.7/31
set interfaces lo0 unit 0 family inet address 20.20.20.20/32set routing-options router-id 20.20.20.20
set routing-options autonomous-system 64512
set protocols bgp group IBGP local-address 20.20.20.20
set protocols bgp group IBGP multipathset protocols bgp group IBGP import ANYCAST_INset protocols bgp group IBGP family inet unicast local-ipv4-address 20.20.20.20
set protocols bgp group IBGP peer-as 64512
set protocols bgp group IBGP allow 0.0.0.0/0set protocols ospf area 0.0.0.0 interface ge-0/0/0.0 interface-type p2p
set protocols ospf area 0.0.0.0 interface ge-0/0/1.0 interface-type p2p
set protocols ospf area 0.0.0.0 interface ge-0/0/2.0 interface-type p2p
set protocols ospf area 0.0.0.0 interface ge-0/0/3.0 interface-type p2p
set protocols ospf area 0.0.0.0 interface lo0.0 metric 1set policy-options policy-statement ANYCAST_IN term ALLOW from source-address-filter 172.16.10.1/32 exact
set policy-options policy-statement ANYCAST_IN term ALLOW then accept
set policy-options policy-statement ANYCAST_IN term DROP then reject
Agora vamos ver a tabela de roteamento. Vemos o prefixo 172.16.10.1/32 através de 4 diferentes next-hops. Em destaque, podemos ver a distribuição entre os next-hops:
### IOS-XR (Sem Community):RP/0/0/CPU0:SPINE1# sh bgp 172.16.10.1
Wed Nov 21 10:52:26.466 UTC
BGP routing table entry for 172.16.10.1/32
Versions:
Process bRIB/RIB SendTblVer
Speaker 22 22
Last Modified: Nov 21 10:50:30.583 for 00:01:55
Paths: (4 available, best #1)
Not advertised to any peer
Path #1: Received by speaker 0
Not advertised to any peer
Local
1.1.1.1 (metric 2) from 1.1.1.1 (172.16.10.1)
Origin IGP, metric 0, localpref 100, valid, internal, best, group-best, multipath
Received Path ID 0, Local Path ID 1, version 22
Path #2: Received by speaker 0
Not advertised to any peer
Local
2.2.2.2 (metric 2) from 2.2.2.2 (172.16.10.1)
Origin IGP, metric 0, localpref 100, valid, internal, multipath
Received Path ID 0, Local Path ID 0, version 0
Path #3: Received by speaker 0
Not advertised to any peer
Local
3.3.3.3 (metric 2) from 3.3.3.3 (172.16.10.1)
Origin IGP, metric 0, localpref 100, valid, internal, multipath
Received Path ID 0, Local Path ID 0, version 0
Path #4: Received by speaker 0
Not advertised to any peer
Local
4.4.4.4 (metric 2) from 4.4.4.4 (172.16.10.1)
Origin IGP, metric 0, localpref 100, valid, internal, multipath
Received Path ID 0, Local Path ID 0, version 0RP/0/0/CPU0:SPINE1# show cef ipv4 172.16.10.1 det
Wed Nov 21 10:53:02.903 UTC
172.16.10.1/32, version 94, internal 0x5000001 0x0 (ptr 0xa13f1ef4) [1], 0x0 (0x0), 0x0 (0x0)<snip>Load distribution: 0 1 2 3 (refcount 1)Hash OK Interface Address
0 Y GigabitEthernet0/0/0/0 10.0.0.0
1 Y GigabitEthernet0/0/0/1 10.0.0.2
2 Y GigabitEthernet0/0/0/2 10.0.0.4
3 Y GigabitEthernet0/0/0/3 10.0.0.6###Junos (Sem community):@SPINE2> show route 172.16.10.1/32inet.0: 20 destinations, 23 routes (20 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both172.16.10.1/32 *[BGP/170] 00:01:11, MED 0, localpref 100, from 1.1.1.1
AS path: I, validation-state: unverified
> to 10.0.1.0 via ge-0/0/0.0
[BGP/170] 00:01:11, MED 0, localpref 100, from 2.2.2.2
AS path: I, validation-state: unverified
> to 10.0.1.2 via ge-0/0/1.0
[BGP/170] 00:01:11, MED 0, localpref 100, from 3.3.3.3
AS path: I, validation-state: unverified
> to 10.0.1.4 via ge-0/0/2.0
[BGP/170] 00:01:11, MED 0, localpref 100, from 4.4.4.4
AS path: I, validation-state: unverified
> to 10.0.1.6 via ge-0/0/3.0@SPINE2# run show route 172.16.10.1 detailinet.0: 20 destinations, 23 routes (20 active, 0 holddown, 0 hidden)
172.16.10.1/32 (4 entries, 1 announced)
*BGP Preference: 170/-101
Next hop type: Indirect, Next hop index: 0
Address: 0xcb68130
Next-hop reference count: 2
Source: 1.1.1.1
Next hop type: Router, Next hop index: 560
Next hop: 10.0.1.0 via ge-0/0/0.0, selected
Session Id: 0x0
Protocol next hop: 1.1.1.1
Indirect next hop: 0xb31a400 262142 INH Session ID: 0x0
State: <Active Int Ext>
Local AS: 64512 Peer AS: 64512
Age: 1:43 Metric: 0 Metric2: 2
Validation State: unverified
Task: BGP_64512.1.1.1.1+54924
Announcement bits (2): 0-KRT 4-Resolve tree 1
AS path: I
Accepted
Localpref: 100
Router ID: 172.16.10.1
Agora, após aplicar a policy para inserir a community nos prefixos, vamos verificar para ver o que mudou:
#### IOS-XR (community default):extcommunity-set bandwidth LB_EXT_16
64512:16000
end-set
!
extcommunity-set bandwidth LB_EXT_32
64512:32000
end-set
!
extcommunity-set bandwidth LB_EXT_64
64512:64000
end-set
!
extcommunity-set bandwidth LB_EXT_MIN
64512:8000
end-set
!
community-set LB_STD_16
64512:16000
end-set
!
community-set LB_STD_32
64512:32000
end-set
!
community-set LB_STD_64
64512:64000
end-set
!
route-policy UNEQUAL_LB
if community matches-any LB_STD_16 then
set extcommunity bandwidth LB_EXT_16 additive
elseif community matches-any LB_STD_32 then
set extcommunity bandwidth LB_EXT_32 additive
elseif community matches-any LB_STD_64 then
set extcommunity bandwidth LB_EXT_64 additive
else
set extcommunity bandwidth LB_EXT_MIN additive
endif
end-policy
!
route-policy ANYCAST_IN
apply UNEQUAL_LB
if destination in HOST_ROUTES then
done
else
drop
endif
end-policy
!##VerificandoRP/0/0/CPU0:SPINE1# sh bgp 172.16.10.1
Wed Nov 21 10:31:03.304 UTC
BGP routing table entry for 172.16.10.1/32
Versions:
Process bRIB/RIB SendTblVer
Speaker 13 13
Last Modified: Nov 21 10:30:50.583 for 00:00:12
Paths: (4 available, best #1)
Not advertised to any peer
Path #1: Received by speaker 0
Not advertised to any peer
Local
1.1.1.1 (metric 2) from 1.1.1.1 (172.16.10.1)
Origin IGP, metric 0, localpref 100, valid, internal, best, group-best, multipath
Received Path ID 0, Local Path ID 1, version 13
Extended community: LB:64512:64
Path #2: Received by speaker 0
Not advertised to any peer
Local
2.2.2.2 (metric 2) from 2.2.2.2 (172.16.10.1)
Origin IGP, metric 0, localpref 100, valid, internal, multipath
Received Path ID 0, Local Path ID 0, version 0
Extended community: LB:64512:64
Path #3: Received by speaker 0
Not advertised to any peer
Local
3.3.3.3 (metric 2) from 3.3.3.3 (172.16.10.1)
Origin IGP, metric 0, localpref 100, valid, internal, multipath
Received Path ID 0, Local Path ID 0, version 0
Extended community: LB:64512:64
Path #4: Received by speaker 0
Not advertised to any peer
Local
4.4.4.4 (metric 2) from 4.4.4.4 (172.16.10.1)
Origin IGP, metric 0, localpref 100, valid, internal, multipath
Received Path ID 0, Local Path ID 0, version 0
Extended community: LB:64512:64RP/0/0/CPU0:SPINE1#sh cef ipv4 172.16.10.1 det
Wed Nov 21 10:31:14.823 UTC
172.16.10.1/32, version 70, internal 0x5000001 0x0 (ptr 0xa13f21f4) <snip>Weight distribution:
slot 0, weight 64, normalized_weight 1, class 0
slot 1, weight 64, normalized_weight 1, class 0
slot 2, weight 64, normalized_weight 1, class 0
slot 3, weight 64, normalized_weight 1, class 0Load distribution: 0 1 2 3 (refcount 1)Hash OK Interface Address
0 Y GigabitEthernet0/0/0/0 10.0.0.0
1 Y GigabitEthernet0/0/0/1 10.0.0.2
2 Y GigabitEthernet0/0/0/2 10.0.0.4
3 Y GigabitEthernet0/0/0/3 10.0.0.6###Junos (Community default)set policy-options policy-statement UCMP term BW_64 from community LB_STD_64
set policy-options policy-statement UCMP term BW_64 then community set LB_EXT_64
set policy-options policy-statement UCMP term BW_64 then next policy
set policy-options policy-statement UCMP term BW_32 from community LB_STD_32
set policy-options policy-statement UCMP term BW_32 then community set LB_EXT_32
set policy-options policy-statement UCMP term BW_32 then next policy
set policy-options policy-statement UCMP term BW_16 from community LB_STD_16
set policy-options policy-statement UCMP term BW_16 then community set LB_EXT_16
set policy-options policy-statement UCMP term BW_16 then next policy
set policy-options policy-statement UCMP term DEFAULT then community set LB_EXT_MINset policy-options community LB_EXT_16 members bandwidth:64512:16000
set policy-options community LB_EXT_32 members bandwidth:64512:32000
set policy-options community LB_EXT_64 members bandwidth:64512:64000
set policy-options community LB_EXT_MIN members bandwidth:64512:8000set policy-options community LB_STD_16 members 64512:16000
set policy-options community LB_STD_32 members 64512:32000
set policy-options community LB_STD_64 members 64512:64000set protocols bgp group IBGP import UCMP
set protocols bgp group IBGP import ANYCAST_IN##Verificando@SPINE2> show route 172.16.10.1 detailinet.0: 20 destinations, 23 routes (20 active, 0 holddown, 0 hidden)
172.16.10.1/32 (4 entries, 1 announced)
*BGP Preference: 170/-101
Next hop type: Indirect, Next hop index: 0
Address: 0xb779ef0
Next-hop reference count: 2
Source: 1.1.1.1
Next hop type: Router, Next hop index: 560
Next hop: 10.0.1.0 via ge-0/0/0.0
Session Id: 0x0
Next hop type: Router, Next hop index: 561
Next hop: 10.0.1.2 via ge-0/0/1.0, selected
Session Id: 0x0
Next hop type: Router, Next hop index: 562
Next hop: 10.0.1.4 via ge-0/0/2.0
Session Id: 0x0
Next hop type: Router, Next hop index: 563
Next hop: 10.0.1.6 via ge-0/0/3.0
Session Id: 0x0
Protocol next hop: 1.1.1.1 Balance: 25%
Indirect next hop: 0xb31a400 262142 INH Session ID: 0x0
Protocol next hop: 2.2.2.2 Balance: 25%
Indirect next hop: 0xb31a280 262143 INH Session ID: 0x0
Protocol next hop: 3.3.3.3 Balance: 25%
Indirect next hop: 0xb31a880 - INH Session ID: 0x0
Protocol next hop: 4.4.4.4 Balance: 25%
Indirect next hop: 0xb31ad00 - INH Session ID: 0x0
State: <Active Int Ext>
Local AS: 64512 Peer AS: 64512
Age: 9 Metric: 0 Metric2: 2
Validation State: unverified
Task: BGP_64512.1.1.1.1+54924
Announcement bits (3): 0-KRT 4-Resolve tree 1 6-BGP_Listen.0.0.0.0+179
AS path: I
Communities: bandwidth:64512:8000
Accepted Multipath
Localpref: 100
Router ID: 172.16.10.1<snip>
Agora, em itálico, vemos a distribuição de carga entre os caminhos. Neste exemplo ainda temos os valores idênticos, resultando em ECMP. Repare que, no IOS-XR, o valor configurado é em bytes/s, e o weight nos mostra em kilobits/s . Diferentemente, o Junos nos retorna a porcentagem de carga associada a cada entrada, conforme exemplo acima.
Nota: Com a community de LB, o comportamento de load sharing so é alterado caso todos os prefixos tenham um valor de LB community. Caso algum caminho não tenha esta community, os valores são ignorados e o ECMP é utilizado.
Agora vamos associar o valor de communities da seguinte maneira:
SERVER1 --> 64512:32000
SERVER2 --> 64512:16000
SERVER3 --> 64512:32000
SERVER4 --> 64512:16000
Enviando a community aos SPINE:
###Server1:ip bgp-community new-format
!
route-map LB_STD permit 5
set community 64512:32000
!
router bgp 64512
address-family ipv4
network 172.16.10.1 mask 255.255.255.255 route-map LB_STD###Server2ip bgp-community new-format
!
route-map LB_STD permit 5
set community 64512:16000
!
router bgp 64512
address-family ipv4
neighbor SPINE route-map LB_STD out###Server3ip bgp-community new-format
!
route-map LB_STD permit 5
set community 64512:32000
!
router bgp 64512
address-family ipv4
neighbor SPINE route-map LB_STD out##Server4ip bgp-community new-format
!
route-map LB_STD permit 5
set community 64512:16000
!
router bgp 64512
address-family ipv4
network 172.16.10.1 mask 255.255.255.255 route-map LB_STD
Verificando se recebemos este valor de community:
###IOS-XRRP/0/0/CPU0:SPINE1#sh bgp ipv4 u 172.16.10.1 | i "from|mmuni"
Wed Dec 5 10:03:51.611 UTC
1.1.1.1 (metric 2) from 1.1.1.1 (172.16.10.1)
Community: 64512:32000
Extended community: LB:64512:256
2.2.2.2 (metric 2) from 2.2.2.2 (172.16.10.1)
Community: 64512:16000
Extended community: LB:64512:128
3.3.3.3 (metric 2) from 3.3.3.3 (172.16.10.1)
Community: 64512:32000
Extended community: LB:64512:256
4.4.4.4 (metric 2) from 4.4.4.4 (172.16.10.1)
Community: 64512:16000
Extended community: LB:64512:128RP/0/0/CPU0:SPINE1#show cef ipv4 172.16.10.1 det | i "via|idx|eight|Interface|$
Wed Dec 5 10:07:05.747 UTC
via 1.1.1.1/32, 2 dependencies, recursive, bgp-multipath [flags 0x6080]
path-idx 0 NHID 0x0 [0xa13f1d74 0x0]
next hop 1.1.1.1/32 via 1.1.1.1/32
via 2.2.2.2/32, 2 dependencies, recursive, bgp-multipath [flags 0x6080]
path-idx 1 NHID 0x0 [0xa13f1df4 0x0]
next hop 2.2.2.2/32 via 2.2.2.2/32
via 3.3.3.3/32, 2 dependencies, recursive, bgp-multipath [flags 0x6080]
path-idx 2 NHID 0x0 [0xa13f1e74 0x0]
next hop 3.3.3.3/32 via 3.3.3.3/32
via 4.4.4.4/32, 2 dependencies, recursive, bgp-multipath [flags 0x6080]
path-idx 3 NHID 0x0 [0xa13f1cf4 0x0]
next hop 4.4.4.4/32 via 4.4.4.4/32 Weight distribution:
slot 0, weight 256, normalized_weight 2, class 0
slot 1, weight 128, normalized_weight 1, class 0
slot 2, weight 256, normalized_weight 2, class 0
slot 3, weight 128, normalized_weight 1, class 0 Load distribution: 0 0 1 2 2 3 (refcount 1) Hash OK Interface Address
0 Y GigabitEthernet0/0/0/0 10.0.0.0
1 Y GigabitEthernet0/0/0/0 10.0.0.0
2 Y GigabitEthernet0/0/0/1 10.0.0.2
3 Y GigabitEthernet0/0/0/2 10.0.0.4
4 Y GigabitEthernet0/0/0/2 10.0.0.4
5 Y GigabitEthernet0/0/0/3 10.0.0.6###Junos@SPINE2> ...2.16.10.1 detail | match "source|comm" | except Inac
Source: 1.1.1.1
Communities: bandwidth:64512:32000
Source: 2.2.2.2
Communities: bandwidth:64512:16000
Source: 3.3.3.3
Communities: bandwidth:64512:32000
Source: 4.4.4.4
Communities: bandwidth:64512:16000@SPINE2> show route 172.16.10.1 detail | match "Protocol next"
Protocol next hop: 1.1.1.1 Balance: 33%
Protocol next hop: 2.2.2.2 Balance: 17%
Protocol next hop: 3.3.3.3 Balance: 33%
Protocol next hop: 4.4.4.4 Balance: 17%
Como podemos ver, ambas as plataformas nos mostram a distribuição entre os next-hop “desiguais”. Com esta configuração, o resultado é que, os servidores 2 e 4 receberão cada um aproximadamente 50% dos fluxos recebidos pelos de número 1 e 3. Da mesma maneira, caso desejamos novamente alterar esta distribuição, basta alterar o valor da community standard anunciado pelo próprio servidor. Bem fácil, né?
Conclusão
Nesse post, abordamos brevemente os conceitos de FIB Hashing e Multipathing; com foco em Unequal Cost Multipath em BGP através da Community de link BW. Também demonstramos dois casos de uso para tal feature:
- Distribuição de carga em links de capacidades diferentes (eBGP)
- UCMP no “fabric” do Data Center, permitindo distribuição de carga desigual para servidores usando Anycast (usando iBGP).
Seguem mais referências sobre o tema:
https://tools.ietf.org/html/draft-ietf-idr-link-bandwidth-07
https://tools.ietf.org/html/rfc4360
https://www.juniper.net/documentation/en_US/junos/topics/example/bgp-multipath-unequal.html
Se gostou do conteúdo, peço para compartilhar com outros do ramo. Não se esqueça de seguir a mim e ao TechRebels clicando follow aí embaixo :)
Sobre o autor:
Bernardo, CCIE #57862
Cloud Network Engineer