Apuntes · Capítulo 6Routing

BGP y políticas entre redes

BGP y políticas entre redes

La semana pasada una red entera aprendió sus caminos sola. Con OSPF, cada router de un mismo dominio describe sus enlaces, todos arman el mismo mapa y cada uno calcula el camino de menor costo. Funciona porque hay una sola organización al mando: ella define los costos, ella decide cuándo un camino es mejor que otro.

Internet no es así. Es una colección de decenas de miles de redes, cada una con sus dueños, sus contratos y sus secretos comerciales. Ninguna de esas redes le va a mostrar su mapa a la competencia, y ninguna va a llevar tráfico ajeno gratis solo porque un algoritmo dijo que era el camino más corto. Entre estas redes la pregunta deja de ser “¿cuál es el camino más barato?” y pasa a ser “¿qué caminos me conviene usar, y cuáles estoy dispuesto a ofrecerle a los demás?”. El protocolo que responde esa pregunta es BGP, y esta semana lo vamos a mirar por dentro.

En la Sesión A vemos qué es un sistema autónomo, cómo funciona un vector de caminos, qué mensajes viajan por una sesión BGP y cómo elige un router la mejor ruta entre varias. También vemos cómo convive BGP con OSPF dentro de una misma red. En la Sesión B entra el dinero: clientes, proveedores y peers, las reglas de importación y exportación que se siguen de quién le paga a quién, y por qué esas reglas mantienen estable a Internet. Terminamos con las herramientas de FRRouting para escribir políticas, con anycast y con los pasos para que una organización aparezca en Internet.

Todo lo que se muestra aquí salió de tres topologías de Containerlab que ustedes pueden levantar. Los tiempos, las versiones de tabla y los contadores de mensajes cambian en cada ejecución. Los caminos no deben cambiar.

Ruta de lectura.

Antes de clase (obligatorio, unos 15 a 20 minutos). Sesión A: la introducción de Sistemas autónomos: por qué hace falta otro protocolo, Vector de caminos, la introducción de Sesiones sobre TCP y Atributos: lo que acompaña a un prefijo. Sesión B: Quién le paga a quién, Las reglas de importación y exportación y El problema: tránsito gratis.

En clase. Sesión A: Los seis AS de esta semana, Una sesión, en la captura, Leer una tabla BGP, eBGP e iBGP: BGP dentro de un AS y Elegir la mejor ruta. Sesión B: Caminos valle-libre, Políticas en FRRouting, Lo que debe pasar con las políticas puestas y Anycast.

Después de clase. Repasen con el Resumen y los Ejercicios, y preparen El laboratorio de la semana y make test. Opcional: MED y cold potato, Por qué estas reglas dan estabilidad y Cómo llega una organización a Internet. Para profundizar, las lecturas del libro y las gratuitas de la semana:

Este capítulo acompaña a Kurose y Ross, Computer Networking: A Top-Down Approach (9.ª ed.). Para la Sesión A, las secciones 5.4.1 The Role of BGP, 5.4.2 Advertising BGP Route Information y 5.4.3 Determining the Best Routes. Para la Sesión B, las secciones 5.4.4 IP-Anycast, 5.4.5 Routing Policy y 5.4.6 Putting the Pieces Together. Lecturas libres de CS168: BGP y BGP Implementation and Issues. Referencia de las políticas: FRRouting, BGP. Complementaria: RFC 4271, BGP-4. El código de la semana está en code/week-06/.

Sistemas autónomos: por qué hace falta otro protocolo

Un sistema autónomo (AS) es un conjunto de routers bajo una misma administración, que frente al resto del mundo se presenta con una sola política de routing. Lo identifica un número de AS. Son ejemplos de AS un ISP, una universidad grande, una empresa de contenido o un proveedor de cloud. Una organización puede tener varios, y muchas organizaciones chicas no tienen ninguno, porque viven dentro del AS de su proveedor.

Los números de AS tienen 32 bits. Hay rangos reservados para uso privado, igual que las direcciones de la RFC 1918: 64512–65534 entre los antiguos de 16 bits. Todo el curso usa ese rango.

Con esto el routing se parte en dos problemas distintos:

Dentro de un AS (intradominio) Entre AS (interdominio)
Protocolo típico OSPF, IS-IS BGP
Quién manda Una sola administración Cada AS manda solo en el suyo
Qué se busca El camino de menor costo El camino que convenga según la política
Qué se comparte El mapa entero Solo qué prefijos se alcanzan, y por dónde
Tamaño Cientos o miles de routers Toda Internet

¿Por qué no se usa OSPF para todo? Por tres razones, y las tres importan.

Escala. OSPF inunda cada cambio de cada enlace a todos los routers, y todos recalculan. Con toda Internet, ese mapa tendría cientos de miles de redes cambiando a cada momento.

Autonomía. Un costo de OSPF solo tiene sentido dentro de la red que lo definió. Si un AS pone costo 10 a un enlace de 100 Gb/s y otro AS pone costo 10 a uno de 10 Mb/s, sumarlos no significa nada. Además, ningún operador quiere publicar su topología interna, y cada uno debe poder usar el protocolo interno que prefiera.

Política. Esta es la razón de fondo. Un AS puede tener un camino corto y aun así no querer usarlo, porque pasa por un competidor, o porque es caro, o porque un contrato lo prohíbe. Y puede tener un camino y no querer ofrecérselo a un vecino. Un algoritmo que minimiza una suma no sabe expresar nada de eso.

Idea clave. Dentro de un AS manda la eficiencia. Entre sistemas autónomos manda la política. BGP no resuelve un problema de optimización: permite que cada AS aplique sus propias reglas, y aun así la red como un todo funcione.

BGP (Border Gateway Protocol, RFC 4271) le da a cada AS tres cosas. Primero, una forma de anunciar al resto del mundo “este prefijo existe, y está aquí”. Segundo, una forma de enterarse de qué prefijos se alcanzan a través de sus vecinos. Tercero, una forma de decidir entre varios caminos con sus propios criterios. Lo que un router aprende por BGP termina en la misma forwarding table de siempre: BGP es routing, y el forwarding sigue siendo longest prefix match.

Los seis AS de esta semana

Vamos a usar esta red. Cada router rN es un AS entero, el 6460N:

Los seis AS con el proveedor arriba y el cliente abajo. r5, AS 64605, y r6, AS 64606, están arriba y son peers por 100.64.5.128/30. r5 es proveedor de r2, AS 64602, por 100.64.5.132/30. r6 es proveedor de r4, AS 64604, por 100.64.6.128/30, y de r3, AS 64603, por 100.64.6.132/30. r2 y r4 son proveedores de r1, AS 64601, por 100.64.2.128/30 y 100.64.4.128/30. Cada rN es owner de 100.64.N.0/24. h1 cuelga de r1, y h3 de r3Los seis AS con el proveedor arriba y el cliente abajo. r5, AS 64605, y r6, AS 64606, están arriba y son peers por 100.64.5.128/30. r5 es proveedor de r2, AS 64602, por 100.64.5.132/30. r6 es proveedor de r4, AS 64604, por 100.64.6.128/30, y de r3, AS 64603, por 100.64.6.132/30. r2 y r4 son proveedores de r1, AS 64601, por 100.64.2.128/30 y 100.64.4.128/30. Cada rN es owner de 100.64.N.0/24. h1 cuelga de r1, y h3 de r3
Los seis AS, con el prefijo de cada uno. Cada enlace se numera con direcciones del bloque del proveedor.

Por ahora no hemos hablado de dinero, así que tomen ese dibujo solo como un grafo. En la Sesión B vamos a leer qué significa cada línea. Lo que importa de la topología:

  • Cada AS es owner de 100.64.N.0/24 y lo anuncia entero.
  • Dentro de ese bloque, la parte baja (100.64.N.0/25) es para hosts y la alta (100.64.N.128/25) para enlaces. 100.64.N.1 siempre es una dirección de rN.
  • Un enlace entre dos AS se numera con direcciones del bloque del proveedor. Por ejemplo, el enlace r1–r2 es 100.64.2.128/30. Así es en la realidad, y tiene una consecuencia práctica: esas direcciones son alcanzables desde afuera y traceroute puede mostrarlas. Si un enlace usara direcciones que nadie anuncia, la respuesta de ese salto nunca volvería.

Por cada router hay un frr.conf. Este es el de r2, completo:

frr defaults traditional
hostname r2
! AS 64602: proveedor de r1 y cliente de r5.
interface lo
 ip address 100.64.2.1/32
interface eth1
 description hacia r1 (cliente)
 ip address 100.64.2.129/30
interface eth2
 description hacia r5 (proveedor)
 ip address 100.64.5.134/30
ip route 100.64.2.0/24 Null0
router bgp 64602
 bgp router-id 100.64.2.1
 no bgp ebgp-requires-policy
 neighbor 100.64.2.130 remote-as 64601
 neighbor 100.64.5.133 remote-as 64605
 address-family ipv4 unicast
  network 100.64.2.0/24
 exit-address-family

Lo leemos línea por línea:

  • router bgp 64602 dice cuál es el número de AS de este router.
  • neighbor 100.64.2.130 remote-as 64601 declara un vecino, su dirección y su AS. BGP no descubre vecinos, a diferencia de OSPF: cada sesión se configura a mano, en los dos lados. Es a propósito, porque cada sesión representa un contrato.
  • network 100.64.2.0/24 pide anunciar ese prefijo. Atención: network en BGP no significa lo mismo que en OSPF. Aquí solo anuncia un prefijo que ya esté en la tabla de routing con esa misma máscara.
  • Por eso está ip route 100.64.2.0/24 Null0. Es una ruta que bota lo que llega, y parece absurda. Pero cualquier ruta más específica, como las de los enlaces o las LANs, le gana por longest prefix match, así que solo cae en Null0 lo que no corresponde a nada que exista. Es la forma estándar de sostener el anuncio de un agregado.
  • no bgp ebgp-requires-policy apaga un seguro. La RFC 8212 pide que un router no acepte ni anuncie nada por eBGP si no tiene políticas configuradas, y FRRouting lo cumple por defecto. Lo apagamos porque primero queremos ver a BGP sin políticas.

¿Qué pasa si se olvidan de esa línea? La sesión sube, pero no se intercambia nada. Lo probamos en un router de otra topología, activando el seguro:

Neighbor        V         AS   MsgRcvd   MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd   PfxSnt Desc
100.64.130.133  4      65300        13        12        7    0    0 00:00:07     (Policy) (Policy) N/A

Cuando vean (Policy) en las dos últimas columnas, ya saben qué falta. Con el seguro puesto, cada vecino eBGP necesita una política de entrada y otra de salida. En producción es lo recomendable.

Vector de caminos

Recuerden el vector de distancias de la semana pasada: cada router le dice a sus vecinos “llego a este destino con costo 7”. Tiene dos problemas para Internet. Un costo no se puede comparar entre redes de distintos dueños, y puede caer en count to infinity, porque nadie sabe si el camino de su vecino pasa por él mismo.

Path vector es la misma idea con un cambio. En vez de anunciar un número, cada AS anuncia la lista de sistemas autónomos que hay que cruzar para llegar al prefijo. Esa lista es el atributo AS_PATH. La regla de construcción es:

  1. El AS que es owner del prefijo lo anuncia a sus vecinos, con AS_PATH igual a su número.
  2. Un AS que recibe una ruta y decide reenviarla agrega su propio número al principio.
  3. Un AS que recibe una ruta cuyo AS_PATH ya contiene su número la descarta.

La regla 3 elimina los ciclos sin necesidad de ningún mapa global. Veamos cómo se propaga 100.64.3.0/24, de r3 hacia r1:

Animación de la propagación de 100.64.3.0/24 sobre los seis AS. r3 lo anuncia a r6 con AS_PATH 64603. r6 lo reenvía a r4 y a r5 con 64606 64603, y r5 a r2 con 64605 64606 64603. A r1 le llegan dos caminos: 64604 64606 64603 por r4 y 64602 64605 64606 64603 por r2, y elige el primero, que es más corto. En otra ruta, que veremos en la captura de la sesión, r2 le ofrece a r1 el prefijo 100.64.1.0/24 con 64601 en el AS_PATH, y r1 lo descarta. Al final, de vuelta en 100.64.3.0/24, el tráfico va al revés: r1, r4, r6 y r3, como muestra el traceroute de h1 a h3Animación de la propagación de 100.64.3.0/24 sobre los seis AS. r3 lo anuncia a r6 con AS_PATH 64603. r6 lo reenvía a r4 y a r5 con 64606 64603, y r5 a r2 con 64605 64606 64603. A r1 le llegan dos caminos: 64604 64606 64603 por r4 y 64602 64605 64606 64603 por r2, y elige el primero, que es más corto. En otra ruta, que veremos en la captura de la sesión, r2 le ofrece a r1 el prefijo 100.64.1.0/24 con 64601 en el AS_PATH, y r1 lo descarta. Al final, de vuelta en 100.64.3.0/24, el tráfico va al revés: r1, r4, r6 y r3, como muestra el traceroute de h1 a h3
Cada AS agrega su número al reenviar, y con eso basta para elegir y para evitar ciclos. El tráfico recorre en sentido contrario el camino del anuncio.

El anuncio viaja en un sentido, y el tráfico irá en el contrario: r1 manda a r4, r4 a r6, r6 a r3. Una ruta anunciada es una promesa: “si me mandas paquetes para este prefijo, yo los llevo”.

Y AS_PATH hace más que evitar ciclos: le muestra a cada AS por dónde pasaría su tráfico. Eso es lo que permite aplicar políticas como “nunca por este competidor”, que en un vector de distancias serían imposibles. Lo que no dice es nada sobre retardo, ancho de banda o cuántos routers hay dentro de cada AS.

Una consecuencia importante: BGP anuncia solo el camino que el AS eligió, no todos los que conoce. Un AS no puede usar un camino que su vecino no decidió anunciarle. Una red sabe de Internet lo que sus vecinos quieren contarle.

Error común. Decir que BGP “calcula” el camino como OSPF. No hay ningún algoritmo global. Cada AS elige por su cuenta entre lo que le anunciaron, y le cuenta su elección a quien quiera. El camino final es el resultado de todas esas decisiones locales, y nadie lo ve completo.

Sesiones sobre TCP

Dos routers que hablan BGP son peers BGP, y lo que hay entre ellos es una sesión BGP. (Más adelante veremos que “peer” también es un tipo de relación comercial; son dos usos distintos de la misma palabra. Cuando haya dudas, diremos “vecino BGP” para la sesión y “peer” para el negocio.)

La sesión corre sobre una conexión TCP al puerto 179. Eso simplifica mucho el protocolo: BGP no tiene que preocuparse por retransmisiones, orden ni fragmentos. Y a diferencia de OSPF, BGP no refresca sus rutas: una vez anunciadas valen hasta que se retiran o hasta que la sesión cae. Por eso el costo de un BGP tranquilo es casi nulo, aunque la tabla tenga un millón de rutas.

Hay cuatro mensajes básicos. Todos empiezan con el mismo header de 19 bytes: un marcador de 16 bytes en ff, el largo y el tipo.

Tipo Mensaje Para qué
1 OPEN Abre la sesión: versión, número de AS, hold time, identificador y capacidades.
2 UPDATE Anuncia rutas nuevas con sus atributos y retira las que ya no valen.
3 NOTIFICATION Informa un error o un cierre, y la sesión termina.
4 KEEPALIVE Solo dice “sigo aquí”. Es únicamente el header.

Si un router no recibe nada de su vecino durante el hold time, da la sesión por muerta y retira todas las rutas que aprendió de él. El KEEPALIVE se manda por lo general cada tercio de ese tiempo, para que una sesión tranquila no caiga. Con los valores por defecto que vemos abajo, una falla silenciosa del otro lado puede tardar hasta tres minutos en notarse. En un enlace directo que se cae, el router se entera al instante por la interfaz.

Una sesión, en la captura

Pasemos a verlo. Levanten la red:

make up-ases
docker exec clab-w06-ases-r2 vtysh -c 'show bgp summary'
IPv4 Unicast Summary:
BGP router identifier 100.64.2.1, local AS number 64602 VRF default vrf-id 0
BGP table version 6
RIB entries 11, using 1408 bytes of memory
Peers 2, using 33 KiB of memory

Neighbor        V         AS   MsgRcvd   MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd   PfxSnt Desc
100.64.2.130    4      64601         9         9        6    0    0 00:00:10            4        6 N/A
100.64.5.133    4      64605         9        10        6    0    0 00:00:10            4        6 N/A

Total number of neighbors 2

Hay una trampa de lectura. La columna State/PfxRcd muestra el estado de la sesión mientras no esté establecida. Si muestra un número, la sesión está en Established y ese número es cuántos prefijos se recibieron. PfxSnt es cuántos se anunciaron.

Los estados por los que pasa una sesión son Idle, Connect, Active, OpenSent, OpenConfirm y Established. Los nombres confunden: Active significa que el router está intentando abrir la conexión TCP sin lograrlo, es decir, que algo anda mal.

Para capturar el inicio de una sesión, la apagamos desde r1. Empezamos a capturar y la volvemos a prender:

docker exec clab-w06-ases-r1 vtysh -c 'configure terminal' -c 'router bgp 64601' \
    -c 'neighbor 100.64.2.129 shutdown'
docker exec clab-w06-ases-r1 vtysh -c 'show bgp summary'
Neighbor        V         AS   MsgRcvd   MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd   PfxSnt Desc
100.64.2.129    4      64602         9        11        0    0    0 00:00:02 Idle (Admin)        0 N/A
100.64.4.129    4      64604        11        13        9    0    0 00:00:12            5        6 N/A
docker exec -d clab-w06-ases-r1 sh -c 'tcpdump -U -i eth2 -w /tmp/s.pcap tcp port 179'
docker exec clab-w06-ases-r1 vtysh -c 'configure terminal' -c 'router bgp 64601' \
    -c 'no neighbor 100.64.2.129 shutdown'

Después de unos segundos, detenemos tcpdump, copiamos el archivo a la carpeta y lo leemos con tshark:

    1   0.000000 100.64.2.130 → 100.64.2.129 TCP 74 35516 → 179 [SYN] Seq=0 Win=64240 Len=0 MSS=1460
    2   0.000033 100.64.2.129 → 100.64.2.130 TCP 74 179 → 35516 [SYN, ACK] Seq=0 Ack=1 Win=65160 Len=0
    3   0.000044 100.64.2.130 → 100.64.2.129 TCP 66 35516 → 179 [ACK] Seq=1 Ack=1 Win=64256 Len=0
    4   0.000582 100.64.2.129 → 100.64.2.130 BGP 165 OPEN Message
    5   0.000595 100.64.2.130 → 100.64.2.129 TCP 66 35516 → 179 [ACK] Seq=1 Ack=100 Win=64256 Len=0
    6   0.001513 100.64.2.130 → 100.64.2.129 BGP 165 OPEN Message
    7   0.001533 100.64.2.129 → 100.64.2.130 TCP 66 179 → 35516 [ACK] Seq=100 Ack=100 Win=65280 Len=0
    8   0.001724 100.64.2.129 → 100.64.2.130 BGP 85 KEEPALIVE Message
    9   0.001738 100.64.2.130 → 100.64.2.129 BGP 85 KEEPALIVE Message
   12   1.152823 100.64.2.129 → 100.64.2.130 BGP 436 UPDATE Message, UPDATE Message, UPDATE Message, ...
   14   1.153378 100.64.2.130 → 100.64.2.129 BGP 436 UPDATE Message, UPDATE Message, UPDATE Message, ...

(Recortamos el final de cada línea, quitamos algunos ACK y dejamos afuera los UPDATE que siguen.) Se ve la historia completa. El handshake de TCP hacia el puerto 179. Un OPEN en cada sentido. Un KEEPALIVE en cada sentido, que confirma el OPEN del otro y deja la sesión en Established. Y recién entonces, las rutas. Ojo con el último detalle: un solo segmento TCP puede llevar varios mensajes BGP, porque para TCP son solo bytes de un stream.

Diagrama de tiempo de la captura entre r1, 100.64.2.130 puerto 35516, y r2, 100.64.2.129 puerto 179. r1 envía el SYN en 0,000000 s, r2 el SYN ACK en 0,000033 y r1 el ACK en 0,000044. r2 envía su OPEN, con AS 64602 y hold time 180, en 0,000582, y r1 el suyo en 0,001513. KEEPALIVE de r2 en 0,001724 y de r1 en 0,001738, y queda Established. Más de un segundo después van los UPDATE, en 1,152823 y 1,153378, y luego un KEEPALIVE cada 60 sDiagrama de tiempo de la captura entre r1, 100.64.2.130 puerto 35516, y r2, 100.64.2.129 puerto 179. r1 envía el SYN en 0,000000 s, r2 el SYN ACK en 0,000033 y r1 el ACK en 0,000044. r2 envía su OPEN, con AS 64602 y hold time 180, en 0,000582, y r1 el suyo en 0,001513. KEEPALIVE de r2 en 0,001724 y de r1 en 0,001738, y queda Established. Más de un segundo después van los UPDATE, en 1,152823 y 1,153378, y luego un KEEPALIVE cada 60 s
La misma captura en orden, sin los ACK sueltos. Primero TCP, después los OPEN y los KEEPALIVE, y recién entonces las rutas, más de un segundo después.

Abramos un OPEN con tshark -O bgp:

Border Gateway Protocol - OPEN Message
    Marker: ffffffffffffffffffffffffffffffff
    Length: 99
    Type: OPEN Message (1)
    Version: 4
    My AS: 64602
    Hold Time: 180
    BGP Identifier: 100.64.2.1
    Optional Parameters Length: 70
    Optional Parameters
        Optional Parameter: Capability
            Parameter Type: Capability (2)
            Parameter Length: 6
            Capability: Multiprotocol extensions capability
                Type: Multiprotocol extensions capability (1)
                Length: 4
                AFI: IPv4 (1)
                Reserved: 00
                SAFI: Unicast (1)

Están los campos que importan: versión 4, el AS del que habla, un hold time de 180 segundos y un identificador con forma de dirección IPv4. Las capacidades sirven para que los dos lados acuerden extensiones: aquí IPv4 unicast, y más abajo en la misma captura, números de AS de 4 bytes.

Si el AS del OPEN no coincide con el remote-as que el otro configuró, la sesión no sube. Esa es la primera defensa contra un error de escritura.

Ahora un UPDATE que r1 le manda a r2. Quitamos los bits de cada campo de flags:

Border Gateway Protocol - UPDATE Message
    Marker: ffffffffffffffffffffffffffffffff
    Length: 55
    Type: UPDATE Message (2)
    Withdrawn Routes Length: 0
    Total Path Attribute Length: 28
    Path attributes
        Path Attribute - ORIGIN: IGP
            Flags: 0x40, Transitive, Well-known, Complete
            Type Code: ORIGIN (1)
            Length: 1
            Origin: IGP (0)
        Path Attribute - AS_PATH: 64601
            Flags: 0x50, Transitive, Extended-Length, Well-known, Complete
            Type Code: AS_PATH (2)
            Length: 6
            AS Path segment: 64601
                Segment type: AS_SEQUENCE (2)
                Segment length (number of ASN): 1
                AS4: 64601
        Path Attribute - NEXT_HOP: 100.64.2.130
            Flags: 0x40, Transitive, Well-known, Complete
            Type Code: NEXT_HOP (3)
            Length: 4
            Next hop: 100.64.2.130
        Path Attribute - MULTI_EXIT_DISC: 0
            Flags: 0x80, Optional, Non-transitive, Complete
            Type Code: MULTI_EXIT_DISC (4)
            Length: 4
            Multiple exit discriminator: 0
    Network Layer Reachability Information (NLRI)
        100.64.1.0/24
            NLRI prefix length: 24
            NLRI prefix: 100.64.1.0

La estructura de un UPDATE es: rutas retiradas, atributos, y los prefijos a los que se aplican esos atributos (NLRI, Network Layer Reachability Information). Un UPDATE que solo retira rutas no lleva atributos. Y un UPDATE sin rutas ni retiros es el marcador de End-of-RIB, con el que el vecino dice “ya te conté todo lo que tenía”.

El mismo tráfico se puede leer con tcpdump -vv, que muestra otra cosa interesante. Esto es lo que r2 le mandó a r1 en esa misma captura:

	Update Message (2), length: 64
	  Origin (1), length: 1, Flags [T]: IGP
	  AS Path (2), length: 22, Flags [TE]: 64602 64605 64606 64604 64601 
	  Next Hop (3), length: 4, Flags [T]: 100.64.2.129
	  Updated routes:
	    100.64.1.0/24

¡r2 le está ofreciendo a r1 una ruta hacia el propio prefijo de r1! Mientras la sesión estaba apagada, r2 aprendió 100.64.1.0/24 por el camino largo, a través de r4, y como acaba de volver el vecino, se lo cuenta. r1 ve su número en el AS_PATH y la descarta. Eso explica lo que muestra show bgp summary en r1, ya con la sesión arriba:

Neighbor        V         AS   MsgRcvd   MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd   PfxSnt Desc
100.64.2.129    4      64602        20        22       11    0    0 00:00:02            4        6 N/A

r2 conoce seis prefijos y le manda los seis, pero r1 registra solo cuatro como recibidos. Los otros dos traen 64601 en el AS_PATH: su propio prefijo y 100.64.4.0/24, al que r2 llega a través de r1. Es la regla 3 del vector de caminos, funcionando en una captura real.

Si apagamos la sesión de nuevo, vemos el último mensaje:

Border Gateway Protocol - NOTIFICATION Message
    Marker: ffffffffffffffffffffffffffffffff
    Length: 23
    Type: NOTIFICATION Message (3)
    Major error Code: Cease (6)
    Minor error Code (Cease): Hard Reset (9)
    Data: 0602

Cease es el código de “cierro a propósito”. Otros errores tienen otros códigos: un AS inesperado en el OPEN, por ejemplo, o un atributo mal formado. Después de una NOTIFICATION se cierra la conexión TCP y se retiran las rutas.

Un detalle más de la captura: los mensajes BGP de esta sesión viajan con TTL 1, en los dos sentidos. Lo verifica test_ases.py. Una sesión eBGP entre vecinos directos no debería cruzar ningún router, y con TTL 1 un paquete muere en el primer salto: así, una sesión mal configurada hacia un router lejano no llega a formarse. Ojo, esto no es una defensa contra un atacante, que desde lejos puede mandar paquetes con un TTL alto. La defensa es la inversa (GTSM, RFC 5082): mandar con TTL 255 y aceptar solo 254 o más, un valor que nadie puede lograr desde más lejos. FRRouting muestra el límite en show bgp neighbors:

BGP neighbor is 100.64.2.129, remote AS 64602, local AS 64601, external link
  BGP state = Established, up for 00:00:05
  Hold time is 180 seconds, keepalive interval is 60 seconds
  Minimum time between advertisement runs is 0 seconds
  External BGP neighbor may be up to 1 hops away.

En la práctica. Una tabla BGP completa de Internet tiene alrededor de un millón de prefijos IPv4. Un router que la recibe por primera vez recibe cientos de miles de UPDATE. Después, solo los cambios. Esa es la ventaja de que BGP sea incremental. Pero también significa que, si una sesión con un vecino grande se reinicia, hay que volver a mandarlo todo.

Leer una tabla BGP

Cada router guarda todo lo que le anunciaron, elige un mejor camino por prefijo e instala ese en la forwarding table. Esta es la tabla de r1:

docker exec clab-w06-ases-r1 vtysh -c 'show bgp ipv4'
BGP table version is 16, local router ID is 100.64.1.1, vrf id 0
Default local pref 100, local AS 64601
Status codes:  s suppressed, d damped, h history, u unsorted, * valid, > best, = multipath,
               i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes:  i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found

     Network          Next Hop            Metric LocPrf Weight Path
 *>  100.64.1.0/24    0.0.0.0                  0         32768 i
 *>  100.64.2.0/24    100.64.2.129             0             0 64602 i
 *>  100.64.3.0/24    100.64.4.129                           0 64604 64606 64603 i
 *                    100.64.2.129                           0 64602 64605 64606 64603 i
 *>  100.64.4.0/24    100.64.4.129             0             0 64604 i
 *>  100.64.5.0/24    100.64.2.129                           0 64602 64605 i
 *                    100.64.4.129                           0 64604 64606 64605 i
 *>  100.64.6.0/24    100.64.4.129                           0 64604 64606 i
 *                    100.64.2.129                           0 64602 64605 64606 i

Displayed 6 routes and 9 total paths

La columna de la izquierda dice * si el camino es válido y > si es el elegido. Una línea sin prefijo es otro camino hacia el prefijo de la línea anterior. Path se lee de izquierda a derecha: el primero es el vecino, el último el origen, y la letra final es el atributo ORIGIN. Observen cuatro cosas:

  • r1 no aparece en ningún AS_PATH de su propia tabla. Un AS agrega su número al anunciar, no al recibir.
  • Next Hop es la dirección a la que hay que mandar el paquete. 0.0.0.0 significa que la ruta es propia.
  • Hacia 100.64.4.0/24 solo se ve un camino, aunque también existe por r2, porque r2 eligió llegar a ese prefijo a través de r1 (lo veremos en la Sesión B) y el camino de regreso contiene 64601.
  • La columna Metric trae el MED. Solo la tienen los prefijos que originó el vecino directo, y es porque ese atributo no cruza más de un AS.

Weight es un valor local de este router: no es un atributo de BGP y no viaja. 32768 es el que FRRouting le da a lo que origina él mismo.

Para ver por qué ganó un camino, se pide el detalle:

docker exec clab-w06-ases-r1 vtysh -c 'show bgp ipv4 100.64.3.0/24'
BGP routing table entry for 100.64.3.0/24, version 5
Paths: (2 available, best #1, table default)
  Advertised to non peer-group peers:
  100.64.2.129 100.64.4.129
  64604 64606 64603
    100.64.4.129 from 100.64.4.129 (100.64.4.1)
      Origin IGP, valid, external, best (AS Path)
      Last update: Mon Nov  2 07:47:09 2026
  64602 64605 64606 64603
    100.64.2.129 from 100.64.2.129 (100.64.2.1)
      Origin IGP, valid, external
      Last update: Mon Nov  2 07:47:33 2026

best (AS Path) es la razón por la que ganó, y es muy útil para aprender: cada vez que tengan dudas sobre por qué un router eligió algo, lean esa palabra. external significa que lo aprendió por eBGP.

Y lo elegido termina en la tabla del kernel, con proto bgp:

docker exec clab-w06-ases-r1 ip route
100.64.1.0/25 dev eth1 proto kernel scope link src 100.64.1.1 
blackhole 100.64.1.0/24 proto 196 metric 20 
100.64.2.0/24 nhid 27 via 100.64.2.129 dev eth2 proto bgp metric 20 
100.64.2.128/30 dev eth2 proto kernel scope link src 100.64.2.130 
100.64.3.0/24 nhid 30 via 100.64.4.129 dev eth3 proto bgp metric 20 
100.64.4.0/24 nhid 30 via 100.64.4.129 dev eth3 proto bgp metric 20 
100.64.4.128/30 dev eth3 proto kernel scope link src 100.64.4.130 
100.64.5.0/24 nhid 27 via 100.64.2.129 dev eth2 proto bgp metric 20 
100.64.6.0/24 nhid 30 via 100.64.4.129 dev eth3 proto bgp metric 20 
172.90.6.0/26 dev eth0 proto kernel scope link src 172.90.6.2 

Aquí se ve también lo que hace la ruta a Null0: un blackhole para el /24 propio, con 100.64.1.0/25 más específico encima de él. (La última línea es la red de gestión de Docker.)

Y por último, el camino real de un paquete, de h1 a h3:

traceroute to 100.64.3.10 (100.64.3.10), 30 hops max, 46 byte packets
 1  100.64.1.1  0.006 ms
 2  100.64.4.129  0.003 ms
 3  100.64.6.129  0.003 ms
 4  100.64.6.134  0.003 ms
 5  100.64.3.10  0.002 ms

Corresponde al AS_PATH elegido: r1, r4, r6, r3 y el host. (Corrimos traceroute con -n -w 1 -q 1, una sola prueba por salto. No lean los tiempos: en esta red los enlaces son virtuales.)

Atributos: lo que acompaña a un prefijo

Una ruta BGP es un prefijo más sus atributos. Estos son los que necesitamos:

Atributo Qué dice Quién lo pone y hasta dónde llega
ORIGIN De dónde salió la ruta: i (IGP, con network), e (EGP, histórico) o ? (por ejemplo, redistribuida) El origen. Viaja por todas partes.
AS_PATH Los AS que cruzó Cada AS al anunciar a otro AS. Viaja por todas partes.
NEXT_HOP A qué dirección mandar los paquetes Se cambia al pasar por eBGP. Dentro de un AS, no cambia sin que se pida.
LOCAL_PREF Cuánto le gusta esta ruta a este AS Se pone al entrar. Viaja solo por iBGP: nunca sale del AS.
MED Por cuál de mis enlaces prefiero que me entren Lo pone el AS vecino. Se compara y no pasa al siguiente AS.
Comunidad Una etiqueta de 32 bits que no tiene significado propio La pone cualquiera. Viaja mientras nadie la quite.

Vean cómo la tabla de arriba confirma las dos últimas filas sobre el MED. El vecino directo lo manda (la captura trae MULTI_EXIT_DISC: 0), y por eso se ve la columna Metric en 64602 i. El camino 64604 64606 64603 i tiene esa columna vacía: el MED no pasó de un AS al siguiente.

Los atributos se clasifican según lo que el protocolo obliga a hacer con ellos, y esas categorías aparecen en la captura como Well-known, Optional, Transitive. Por ejemplo, ORIGIN, AS_PATH y NEXT_HOP son well-known y obligatorios: todo router debe entenderlos y deben venir en cada anuncio. El MED es optional y non-transitive. Las comunidades son optional y transitive, así que un router que no las entienda las debe dejar pasar.

eBGP e iBGP: BGP dentro de un AS

Hasta ahora cada AS era un solo router. Un AS real tiene muchos routers, y varios de ellos pueden ser de borde. Si b1 aprende una ruta de un vecino externo, ¿cómo se enteran los demás routers del AS?

Aquí hay dos variantes de la misma sesión BGP:

  • eBGP (external): entre routers de distintos AS, normalmente conectados directo.
  • iBGP (internal): entre routers del mismo AS, que pueden estar a varios saltos.

El mensaje y el puerto son los mismos. Las diferencias son de reglas: qué se hace con AS_PATH, con NEXT_HOP y con LOCAL_PREF al pasar la ruta. FRRouting decide cuál es según si el remote-as coincide con el propio.

Tampoco se debe confundir iBGP con OSPF, porque hacen trabajos distintos:

  • OSPF enseña a cada router del AS cómo llegar a los demás routers del AS.
  • iBGP les enseña a todos qué prefijos externos se alcanzan, y por cuál router de borde.

Para llegar a un destino externo, un router hace dos búsquedas: BGP le dice “ese prefijo está detrás del next hop X”, y OSPF le dice “para llegar a X, sal por esta interfaz”. Por eso las rutas externas no se meten en OSPF. Serían un millón de rutas inundadas a cada router, justo lo que queríamos evitar.

Vamos a la segunda topología, con un AS de tránsito de cuatro routers y un vecino externo que se conecta a los dos extremos:

       +----- x (65200) ------+
       |                      |
      b1 ---- b2 ---- b3 ---- b4        AS 65100: OSPF e iBGP entre los cuatro

Los routers b1 a b4 tienen OSPF en sus enlaces internos y en una loopback (100.64.100.N/32), y los enlaces hacia x (10.207.1.0/30 y 10.207.4.0/30) no están en OSPF. Entre ellos hay una sesión iBGP por cada par. Este es el trozo de b1 que nos importa:

router ospf
 ospf router-id 100.64.100.1
router bgp 65100
 bgp router-id 100.64.100.1
 no bgp ebgp-requires-policy
 ! Malla completa de iBGP: una sesión con cada otro router, entre loopbacks.
 ! Las sesiones esperan a OSPF: se reintenta cada 5 s, en vez de los 120 s por defecto.
 neighbor 100.64.100.2 remote-as 65100
 neighbor 100.64.100.2 update-source lo
 neighbor 100.64.100.2 timers connect 5

Las sesiones se abren entre loopbacks y no entre interfaces. Así una sesión no depende de un enlace: mientras OSPF encuentre algún camino, sigue arriba. Por eso update-source lo.

make up-ibgp
docker exec clab-w06-ibgp-b2 vtysh -c 'show bgp summary'
Neighbor        V         AS   MsgRcvd   MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd   PfxSnt Desc
100.64.100.1    4      65100         5         3        2    0    0 00:00:09            2        0 FRRouting/10.3.1_git
100.64.100.3    4      65100         3         3        2    0    0 00:00:10            0        0 FRRouting/10.3.1_git
100.64.100.4    4      65100         5         3        2    0    0 00:00:09            2        0 FRRouting/10.3.1_git

El problema del NEXT_HOP

x anuncia 100.64.120.0/24, y b1 lo pasa a sus compañeros por iBGP. Veamos qué le llega a b2:

docker exec clab-w06-ibgp-b2 vtysh -c 'show bgp ipv4 100.64.120.0/24'
BGP routing table entry for 100.64.120.0/24, version 0
Paths: (2 available, no best path)
  Not advertised to any peer
  65200
    10.207.4.2 (inaccessible, import-check enabled) from 100.64.100.4 (100.64.100.4)
      Origin IGP, metric 0, localpref 100, invalid, internal
      Last update: Mon Nov  2 07:48:35 2026
  65200
    10.207.1.2 (inaccessible, import-check enabled) from 100.64.100.1 (100.64.100.1)
      Origin IGP, metric 0, localpref 100, invalid, internal
      Last update: Mon Nov  2 07:48:35 2026

b2 conoce la ruta y no la puede usar: no best path. La razón está a la vista. Por iBGP el NEXT_HOP no cambia, así que sigue siendo 10.207.1.2, la dirección de x. Y a ese enlace b2 no sabe llegar, porque no está en OSPF. Como la tabla del kernel de b2 lo confirma, no hay ninguna entrada para ese prefijo:

10.207.12.0/30 dev eth1 proto kernel scope link src 10.207.12.2 
10.207.23.0/30 dev eth2 proto kernel scope link src 10.207.23.1 
10.207.34.0/30 nhid 22 via 10.207.23.2 dev eth2 proto ospf metric 20 
100.64.100.0/24 nhid 24 via 10.207.12.1 dev eth1 proto bgp metric 20 
100.64.100.1 nhid 24 via 10.207.12.1 dev eth1 proto ospf metric 20 
100.64.100.3 nhid 22 via 10.207.23.2 dev eth2 proto ospf metric 20 
100.64.100.4 nhid 22 via 10.207.23.2 dev eth2 proto ospf metric 20 
172.90.6.64/26 dev eth0 proto kernel scope link src 172.90.6.69 

Hay dos arreglos. Uno es meter los enlaces de borde en OSPF. El otro, el más común, es que el router de borde se ponga a sí mismo como next hop al pasar la ruta por iBGP:

! En b1: las rutas que pasa por iBGP llevan como NEXT_HOP su propia loopback,
! que los demás conocen por OSPF.
router bgp 65100
 address-family ipv4 unicast
  neighbor 100.64.100.2 next-hop-self
  neighbor 100.64.100.3 next-hop-self
  neighbor 100.64.100.4 next-hop-self
 exit-address-family

Cargamos ese archivo, y uno igual en b4:

docker cp ibgp/nhs_b1.conf clab-w06-ibgp-b1:/tmp/n.conf
docker exec clab-w06-ibgp-b1 vtysh -f /tmp/n.conf
docker cp ibgp/nhs_b4.conf clab-w06-ibgp-b4:/tmp/n.conf
docker exec clab-w06-ibgp-b4 vtysh -f /tmp/n.conf
docker exec clab-w06-ibgp-b2 vtysh -c 'show bgp ipv4 100.64.120.0/24'
BGP routing table entry for 100.64.120.0/24, version 3
Paths: (2 available, best #1, table default)
  Not advertised to any peer
  65200
    100.64.100.1 (metric 10) from 100.64.100.1 (100.64.100.1)
      Origin IGP, metric 0, localpref 100, valid, internal, best (IGP Metric)
      Last update: Mon Nov  2 07:48:44 2026
  65200
    100.64.100.4 (metric 20) from 100.64.100.4 (100.64.100.4)
      Origin IGP, metric 0, localpref 100, valid, internal
      Last update: Mon Nov  2 07:48:44 2026

Ahora el next hop es una loopback, y (metric 10) es la distancia OSPF hasta ella. Ya tenemos la interacción entre los dos protocolos en una sola línea.

Compárenlo con la vista de OSPF en el mismo router: solo trae loopbacks y enlaces internos, y de 100.64.120.0/24 no sabe nada.

============ OSPF network routing table ============
N    10.207.12.0/30        [10] area: 0.0.0.0
                           directly attached to eth1
N    10.207.23.0/30        [10] area: 0.0.0.0
                           directly attached to eth2
N    10.207.34.0/30        [20] area: 0.0.0.0
                           via 10.207.23.2, eth2
N    100.64.100.1/32       [10] area: 0.0.0.0
                           via 10.207.12.1, eth1
N    100.64.100.2/32       [0] area: 0.0.0.0
                           directly attached to lo
N    100.64.100.3/32       [10] area: 0.0.0.0
                           via 10.207.23.2, eth2
N    100.64.100.4/32       [20] area: 0.0.0.0
                           via 10.207.23.2, eth2

iBGP no reenvía a iBGP

En eBGP, los ciclos se evitan con AS_PATH. Dentro de un AS eso no sirve: el número de AS se agrega al salir, así que una ruta que da vueltas entre routers del mismo AS no cambia su AS_PATH, y nadie la reconocería. La solución de BGP es tajante:

Una ruta aprendida por iBGP no se reenvía a otro vecino iBGP.

Un router de borde le cuenta directamente lo que aprendió afuera a cada router del AS, y por eso hace falta una malla completa: una sesión iBGP por cada par. Con n routers son n(n-1)/2 sesiones. Con cuatro son seis. Con 500, son 124 750.

Se puede comprobar. Apagamos en b3 las sesiones con b1 y con b4, y le dejamos solo la que tiene con b2, que sí conoce la ruta:

docker exec clab-w06-ibgp-b3 vtysh -c 'configure terminal' -c 'router bgp 65100' \
    -c 'neighbor 100.64.100.1 shutdown' -c 'neighbor 100.64.100.4 shutdown'
docker exec clab-w06-ibgp-b3 vtysh -c 'show bgp summary'
Neighbor        V         AS   MsgRcvd   MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd   PfxSnt Desc
100.64.100.1    4      65100         7         4        0    0    0 00:00:03 Idle (Admin)        0 FRRouting/10.3.1_git
100.64.100.2    4      65100         3         3        3    0    0 00:00:19            0        0 FRRouting/10.3.1_git
100.64.100.4    4      65100         7         4        0    0    0 00:00:03 Idle (Admin)        0 FRRouting/10.3.1_git

La sesión con b2 está arriba y trae cero prefijos. Y en b3:

% Network not in table
PING 100.64.120.1 (100.64.120.1) from 100.64.100.3: 56 data bytes
ping: sendto: Network unreachable

Mientras tanto, b2 tiene los dos caminos elegidos sin problema:

 *>i 100.64.120.0/24  100.64.100.1             0    100      0 65200 i
 * i                  100.64.100.4             0    100      0 65200 i

La i después de *> significa que la aprendió por iBGP. El paquete de b3 podría cruzar por b2 sin problema, pero nadie le contó a b3 que el destino existe.

En la práctica. Una malla completa no escala. Las redes grandes usan route reflectors (RFC 4456), routers a los que se les permite reenviar lo aprendido por iBGP, bajo ciertas reglas y con atributos propios para evitar ciclos. Cada router solo habla con los reflectores. El resultado es el mismo que da la malla: todos se enteran de todo.

Error común. Olvidar que iBGP necesita un camino interno. iBGP no reemplaza a OSPF: corre encima de él. Sin OSPF, las loopbacks no se alcanzan y las sesiones se quedan en Active.

Elegir la mejor ruta

Cuando un router tiene varios caminos válidos hacia un mismo prefijo, los compara con una lista de criterios en orden. Se detiene en el primero que desempata. En FRRouting, los que nos importan son estos:

Orden Criterio Gana Razón que muestra FRRouting
1 Weight El mayor (local al router, no es un atributo de BGP) Weight
2 LOCAL_PREF El mayor Local Pref
3 Ruta originada localmente La propia Local Route
4 Largo de AS_PATH El menor AS Path
5 ORIGIN i antes que e, y e antes que ? Origin
6 MED El menor, solo entre rutas que vienen del mismo AS vecino MED
7 eBGP contra iBGP eBGP Peer Type
8 Costo IGP hasta el NEXT_HOP El menor IGP Metric
9 Desempates finales El camino más antiguo entre rutas eBGP, luego el menor router ID, luego otros Older Path, Router ID

Las filas 2 y 4 en ese orden son la frase más importante de esta semana: la política va primero. Un AS usa LOCAL_PREF para decidir antes de que el largo del camino siquiera se mire. La fila 1 es propia de la implementación, y en este curso no vamos a usar weight: lo que hagamos debe valer para todo el AS, y por eso se hace con LOCAL_PREF.

Kurose y Ross resumen la lista en cuatro pasos: LOCAL_PREF, AS_PATH más corto, next hop más cercano y criterios adicionales. Es la misma idea, sin el detalle.

Cada criterio, en nuestras tablas

Ya vimos best (AS Path) en r1. Los demás aparecen en la topología con iBGP. En b2 y b3 el LOCAL_PREF, el AS_PATH, el ORIGIN y el MED son iguales, y además son dos rutas iBGP, así que decide la fila 8. Cada uno se va por su salida más cercana:

$ docker exec clab-w06-ibgp-b2 vtysh -c 'show bgp ipv4 100.64.120.0/24'
  65200
    100.64.100.1 (metric 10) from 100.64.100.1 (100.64.100.1)
      Origin IGP, metric 0, localpref 100, valid, internal, best (IGP Metric)
  65200
    100.64.100.4 (metric 20) from 100.64.100.4 (100.64.100.4)
      Origin IGP, metric 0, localpref 100, valid, internal

$ docker exec clab-w06-ibgp-b3 vtysh -c 'show bgp ipv4 100.64.120.0/24'
  65200
    100.64.100.4 (metric 10) from 100.64.100.4 (100.64.100.4)
      Origin IGP, metric 0, localpref 100, valid, internal, best (IGP Metric)
  65200
    100.64.100.1 (metric 20) from 100.64.100.1 (100.64.100.1)
      Origin IGP, metric 0, localpref 100, valid, internal

Quitamos de la salida las líneas de fecha. Los paquetes lo confirman:

traceroute to 100.64.120.1 (100.64.120.1) from 100.64.100.2, 30 hops max, 46 byte packets
 1  10.207.12.1  0.009 ms
 2  100.64.120.1  0.002 ms

traceroute to 100.64.120.1 (100.64.120.1) from 100.64.100.3, 30 hops max, 46 byte packets
 1  10.207.34.2  0.004 ms
 2  100.64.120.1  0.001 ms

Dos routers del mismo AS, hacia el mismo destino, sacan el tráfico por puntas opuestas. Esto se llama hot potato: como una papa caliente, el AS se deshace del paquete lo antes posible. Le conviene porque cada kilómetro dentro de su red le cuesta, y el resto del camino es problema de otro.

En b1, en cambio, la fila 7 decide antes de llegar a la 8:

BGP routing table entry for 100.64.120.0/24, version 2
Paths: (2 available, best #1, table default)
  Advertised to non peer-group peers:
  10.207.1.2 100.64.100.2 100.64.100.3 100.64.100.4
  65200
    10.207.1.2 from 10.207.1.2 (100.64.120.1)
      Origin IGP, metric 0, valid, external, best (Peer Type)
      Last update: Mon Nov  2 07:48:21 2026
  65200
    100.64.100.4 (metric 30) from 100.64.100.4 (100.64.100.4)
      Origin IGP, metric 0, localpref 100, valid, internal
      Last update: Mon Nov  2 07:48:45 2026

MED y cold potato

Ahora veamos a x. A él no le da igual dónde le entre el tráfico: supongamos que su servidor está cerca de su enlace con b4. Puede pedirle a su vecino que use esa entrada, con un MED menor:

! En x: pide que el tráfico hacia su prefijo entre por b4 (MED menor gana).
route-map MED_LOW permit 10
 set metric 10
route-map MED_HIGH permit 10
 set metric 50
router bgp 65200
 address-family ipv4 unicast
  neighbor 10.207.4.1 route-map MED_LOW out
  neighbor 10.207.1.1 route-map MED_HIGH out
 exit-address-family

(Un adelanto de los route-map, que veremos en detalle en la Sesión B. Aquí solo cambian un número en lo que se anuncia.)

docker cp ibgp/med_x.conf clab-w06-ibgp-x:/tmp/n.conf
docker exec clab-w06-ibgp-x vtysh -f /tmp/n.conf
docker exec clab-w06-ibgp-b1 vtysh -c 'show bgp ipv4 100.64.120.0/24'
BGP routing table entry for 100.64.120.0/24, version 5
Paths: (2 available, best #1, table default)
  Advertised to non peer-group peers:
  10.207.1.2
  65200
    100.64.100.4 (metric 30) from 100.64.100.4 (100.64.100.4)
      Origin IGP, metric 10, localpref 100, valid, internal, best (MED)
      Last update: Mon Nov  2 07:49:05 2026
  65200
    10.207.1.2 from 10.207.1.2 (100.64.120.1)
      Origin IGP, metric 50, valid, external
      Last update: Mon Nov  2 07:49:10 2026

Lean esta salida con calma, porque es sorprendente. b1 tiene un enlace directo con x, y aun así elige un camino a través de todo el AS, porque la fila 6 (MED) va antes que la 7 (eBGP) y que la 8 (IGP). El tráfico lo muestra:

traceroute to 100.64.120.1 (100.64.120.1) from 100.64.100.1, 30 hops max, 46 byte packets
 1  10.207.12.2  0.004 ms
 2  10.207.23.2  0.002 ms
 3  10.207.34.2  0.001 ms
 4  100.64.120.1  0.002 ms

Y hay un segundo efecto. Un router solo anuncia su mejor camino, y si ese camino lo aprendió por iBGP no se lo reenvía a otro vecino iBGP. Como el mejor camino de b1 ahora viene de b4, b1 deja de ofrecer su ruta externa, y b2 se queda con una sola opción:

BGP routing table entry for 100.64.120.0/24, version 5
Paths: (1 available, best #1, table default)
  Not advertised to any peer
  65200
    100.64.100.4 (metric 20) from 100.64.100.4 (100.64.100.4)
      Origin IGP, metric 10, localpref 100, valid, internal, best (First path received)
      Last update: Mon Nov  2 07:49:05 2026

First path received aparece cuando hay un solo camino y no hubo nada que comparar. Esto se llama cold potato: el AS 65100 carga el paquete por su red hasta el punto que x pidió. Si 65100 obedece, está pagando la distancia que antes se ahorraba. Por eso un AS acepta el MED de un vecino cuando le conviene o cuando un contrato lo exige (típicamente, cuando el vecino es su cliente). Si no quiere, le basta con quitarlo en su política de entrada.

Animación en el AS 65100, con cuatro routers en línea, b1 a b4, y x conectado a b1 y a b4. Primero, b2 envía hacia x por b1, porque su costo IGP es 10 contra 20; traceroute: 10.207.12.1 y 100.64.120.1. Luego, b3 envía por b4 con el mismo criterio; traceroute: 10.207.34.2 y 100.64.120.1. Por último, x anuncia MED 50 hacia b1 y MED 10 hacia b4, y b1 cruza todo el AS hasta b4; traceroute: 10.207.12.2, 10.207.23.2, 10.207.34.2 y 100.64.120.1Animación en el AS 65100, con cuatro routers en línea, b1 a b4, y x conectado a b1 y a b4. Primero, b2 envía hacia x por b1, porque su costo IGP es 10 contra 20; traceroute: 10.207.12.1 y 100.64.120.1. Luego, b3 envía por b4 con el mismo criterio; traceroute: 10.207.34.2 y 100.64.120.1. Por último, x anuncia MED 50 hacia b1 y MED 10 hacia b4, y b1 cruza todo el AS hasta b4; traceroute: 10.207.12.2, 10.207.23.2, 10.207.34.2 y 100.64.120.1
Los tres traceroute de esta sección sobre la misma red. Con hot potato, cada router suelta el paquete en la salida más cercana. Con cold potato, el AS lo carga hasta donde pidió x.
Hot potato Cold potato
Regla Salgo por la salida más cercana a mí Llevo el paquete hasta la entrada que prefiere el otro
Quién carga la distancia El siguiente AS Yo
A quién favorece Al AS que manda el tráfico Al AS que lo recibe, y a menudo al usuario
Efecto típico Caminos asimétricos Caminos más controlados

Un apunte sobre la asimetría: si dos AS usan hot potato entre sí, el tráfico de ida sale por un punto y el de vuelta por otro, y es perfectamente normal. Un traceroute solo les muestra la ida.

Error común. Creer que BGP busca el camino de menor retardo. No conoce el retardo: ningún atributo lo mide. El AS_PATH más corto tampoco es el primer criterio, y solo cuenta sistemas autónomos: un AS puede ser un edificio o un continente. Dos saltos de AS pueden ser mucho peores que cinco. En la Sesión B veremos a r1 usar a propósito un camino más largo en AS.

Idea clave. La lista de criterios tiene un orden con sentido. Primero lo que el AS quiere (LOCAL_PREF). Después lo que le sugieren los demás (AS_PATH, MED). Y solo al final, lo que sale más barato dentro del AS (hot potato).

Quién le paga a quién

Empezamos la Sesión B. Sabemos cómo funciona BGP: ahora la pregunta es qué hacer con él. La respuesta no sale de ningún algoritmo. Sale de los contratos.

Entre dos AS vecinos hay, casi siempre, una de dos relaciones:

  • Cliente y proveedor (customer-provider). El cliente le paga al proveedor para que este lo conecte con todo Internet. El pago suele depender del tráfico que cruza ese enlace, en cualquiera de los dos sentidos. Un ISP de hogares es cliente de un ISP regional, y ese es cliente de uno mundial. A este servicio se le llama transit.
  • Peers (peering). Dos AS acuerdan intercambiar tráfico entre sus propias redes y sus clientes, por lo general sin pagarse nada. No es un servicio de acceso a Internet: un peer no te da salida hacia el resto. Se hace porque, si dos redes intercambian mucho tráfico, conectarse directo les ahorra lo que pagarían a sus proveedores.

Con esa información, cada enlace se traduce en dinero:

Tráfico en un enlace con mi… Efecto
cliente Gano dinero, en cualquier sentido
peer No gano ni pierdo, salvo el costo del enlace
proveedor Pago dinero, en cualquier sentido

Volvamos ahora al dibujo de los seis AS, que antes leímos como un grafo:

El mismo dibujo de los seis AS. Ahora cada línea que sube es un contrato: el de abajo le paga al de arriba. r5 y r6 son peers, y no se pagan. r1 tiene dos proveedores, r2 y r4; r2 tiene a r5, r4 y r3 tienen a r6, y r5 y r6 no tienen proveedorEl mismo dibujo de los seis AS. Ahora cada línea que sube es un contrato: el de abajo le paga al de arriba. r5 y r6 son peers, y no se pagan. r1 tiene dos proveedores, r2 y r4; r2 tiene a r5, r4 y r3 tienen a r6, y r5 y r6 no tienen proveedor
Ahora con dinero: cada línea que sube es un pago del cliente a su proveedor, y la doble línea de arriba es un peering sin pago.
AS Router Proveedores Peers Clientes
64601 r1 r2, r4
64602 r2 r5 r1
64603 r3 r6
64604 r4 r6 r1
64605 r5 r6 r2
64606 r6 r5 r3, r4

r5 y r6 no tienen proveedor: son la parte de arriba de esta pequeña Internet, y para alcanzarse dependen de su enlace de peers. r1 es lo que se llama multihomed: una organización con dos proveedores, para no quedarse sin red si uno falla.

Idea clave. Una ruta anunciada es una oferta de llevar tráfico. Anunciar una ruta a un vecino es ofrecerle transportar sus paquetes por ese camino. Por eso la exportación es una decisión de negocio, y no un detalle técnico.

Las reglas de importación y exportación

De esa tabla salen dos reglas.

Importación: a qué ruta le doy preferencia. Si un AS conoce un mismo prefijo por varios vecinos, prefiere la ruta de un cliente, luego la de un peer y por último la de un proveedor, sin importar el largo del AS_PATH. Mandar el tráfico por un cliente le da ingresos; por un peer, le sale gratis; por un proveedor, le cuesta. Se implementa con LOCAL_PREF, que como vimos gana antes de mirar el largo del camino.

Exportación: qué le cuento a quién. Antes de anunciar una ruta, un AS se pregunta: “si este vecino me manda tráfico por aquí, ¿quién paga?”.

La ruta viene de mi… ¿A un cliente? ¿A un peer? ¿A un proveedor?
propia red Sí Sí Sí
cliente Sí Sí Sí
peer Sí No No
proveedor Sí No No

Leamos dos casos. Una ruta de un cliente se anuncia a todos, porque todo el tráfico que llegue por ella termina cruzando el enlace con ese cliente, y eso le genera ingresos. En cambio, si anuncio a un peer una ruta que aprendí de mi proveedor, ese peer me podría mandar tráfico que yo le llevaría a mi proveedor, pagando, sin que me den nada a cambio. Le estaría regalando transit.

A los clientes se les anuncia todo: es justamente el servicio por el que pagan.

Error común. Pensar que un peer da acceso a todo Internet. Un peer te da acceso a él y a sus clientes. Por eso, si r5 y r6 dejan de tener peering, los clientes de uno no alcanzan a los del otro, aunque ambos sigan conectados. Este tipo de corte se ha visto en la realidad, cuando dos redes grandes se pelean por quién debe pagar.

El problema: tránsito gratis

Ya podemos leer lo que ocurre en la red sin políticas. Aquí hay un AS que está regalando su enlace. Es el paso 3 del laboratorio, y les recomendamos buscarlo antes de seguir leyendo: miren las tablas de r2 y r4, y busquen un AS_PATH que no tenga sentido comercial.

docker exec clab-w06-ases-r2 vtysh -c 'show bgp ipv4 100.64.4.0/24'
BGP routing table entry for 100.64.4.0/24, version 16
Paths: (2 available, best #1, table default)
  Advertised to non peer-group peers:
  100.64.2.130 100.64.5.133
  64601 64604
    100.64.2.130 from 100.64.2.130 (100.64.1.1)
      Origin IGP, valid, external, best (AS Path)
      Last update: Mon Nov  2 07:47:33 2026
  64605 64606 64604
    100.64.5.133 from 100.64.5.133 (100.64.5.1)
      Origin IGP, valid, external
      Last update: Mon Nov  2 07:47:09 2026

r2 llega a r4 a través de r1, que es su cliente. Y r4 llega a r2 de la misma forma. El tráfico real lo confirma:

traceroute to 100.64.4.1 (100.64.4.1) from 100.64.2.1, 30 hops max, 46 byte packets
 1  100.64.2.130  0.012 ms
 2  100.64.4.1  0.003 ms

¿Por qué ocurre? Porque r1 les anuncia todo a todos:

docker exec clab-w06-ases-r1 vtysh -c 'show bgp ipv4 neighbors 100.64.2.129 advertised-routes'
     Network          Next Hop            Metric LocPrf Weight Path
 *>  100.64.1.0/24    0.0.0.0                  0         32768 i
 *>  100.64.2.0/24    100.64.2.129             0             0 64602 i
 *>  100.64.3.0/24    100.64.4.129                           0 64604 64606 64603 i
 *   100.64.3.0/24    100.64.2.129                           0 64602 64605 64606 64603 i
 *>  100.64.4.0/24    100.64.4.129             0             0 64604 i
 *>  100.64.5.0/24    100.64.2.129                           0 64602 64605 i
 *   100.64.5.0/24    100.64.4.129                           0 64604 64606 64605 i
 *>  100.64.6.0/24    100.64.4.129                           0 64604 64606 i
 *   100.64.6.0/24    100.64.2.129                           0 64602 64605 64606 i

Total number of prefixes 6

Esta salida también muestra las filas *, que no son el mejor camino. Solo se le manda al vecino la que tiene *>, una por prefijo: por eso el total dice 6, y no 9.

Hagamos las cuentas. Lo que r2 manda hacia r4 entra por el enlace r2–r1, y r1 le paga a r2 por ese tráfico. Luego sale por el enlace r1–r4, y r1 también le paga a r4 por él. El AS más chico de la red está pagando dos veces para llevar el tráfico entre sus dos proveedores, que no le dan nada a cambio. Y ese enlace, con toda seguridad, no se dimensionó para eso, así que sus propios usuarios también se quedan sin capacidad.

Nótese que BGP funcionó exactamente como se le pidió. No hubo ninguna falla ni ningún ataque: es una falta de política. El protocolo no sabe qué es un proveedor. Esta misma situación, cuando ocurre en la Internet real, se llama route leak. Volveremos a verla la próxima semana.

Caminos valle-libre

Dibujemos cada camino con el proveedor arriba y el cliente abajo. El de r2 a r4 es el de arriba a la derecha:

Cuatro caminos dibujados con el proveedor arriba. r1 r2 r5 r6 r3 sube, sube, cruza una vez entre peers y baja: es valle-libre. r2 r1 r4 baja a r1 y vuelve a subir: es un valle, y no es valle-libre. r3 r6 r4 r1 sube una vez y baja dos: es valle-libre. r4 r6 r5 r2 sube, cruza una vez y baja: es valle-libreCuatro caminos dibujados con el proveedor arriba. r1 r2 r5 r6 r3 sube, sube, cruza una vez entre peers y baja: es valle-libre. r2 r1 r4 baja a r1 y vuelve a subir: es un valle, y no es valle-libre. r3 r6 r4 r1 sube una vez y baja dos: es valle-libre. r4 r6 r5 r2 sube, cruza una vez y baja: es valle-libre
Los cuatro caminos de la tabla de abajo. Tres son una montaña, y uno, el de r2 a r4, es un valle.

El tráfico baja a un cliente para volver a subir. A eso se le llama un valle, y las reglas de exportación existen para impedirlo. Formalmente, un camino de sistemas autónomos es valle-libre (valley-free) si se puede dividir en tres partes, en este orden:

  1. Cero o más enlaces de cliente a proveedor (subida).
  2. A lo sumo un enlace de peers.
  3. Cero o más enlaces de proveedor a cliente (bajada).

Todo camino permitido es una montaña: sube, quizás cruza una vez en la cima y baja. Los caminos prohibidos son los que tienen un valle (bajan y vuelven a subir), los que cruzan dos enlaces de peers, y los que suben después de un enlace de peers.

Las reglas de exportación garantizan esa forma. Si un AS recibe una ruta de un peer o proveedor (la ruta ya “bajó” o “cruzó”, vista desde el que anuncia), solo la manda a clientes, y por lo tanto el anuncio sigue bajando.

El archivo spvp.py tiene una función corta, is_valley_free, que aplica esta definición a un AS_PATH sabiendo las relaciones de los seis AS. Las pruebas la aplican a las tablas reales:

Camino ¿Valle-libre? Por qué
r1 r2 r5 r6 r3 Sí Sube, sube, cruza una vez, baja
r2 r1 r4 No Baja de r2 a r1, y vuelve a subir a r4
r3 r6 r4 r1 Sí Sube una vez y baja dos veces
r4 r6 r5 r2 Sí Sube, cruza una vez, baja

Por qué estas reglas dan estabilidad

BGP no tiene un punto único que decida. Cada AS reacciona a lo que hacen los otros. ¿Quién garantiza que todas esas decisiones lleguen a un estado estable, en vez de cambiar para siempre?

Hay un resultado famoso de Gao y Rexford (2001). Si se cumplen tres condiciones, la red siempre converge a un estado estable, sin importar el orden en que los AS tomen sus decisiones:

  1. No hay ciclos de proveedores. Si a es proveedor de b y b de c, entonces c no es proveedor de a. El grafo de cliente a proveedor es acíclico.
  2. Importación. Cada AS prefiere rutas de clientes antes que de peers y proveedores.
  3. Exportación. Se cumple la tabla de la sección anterior.

Vale la pena sorprenderse: ninguna de las tres pide coordinación global. Cada operador las cumple porque le conviene económicamente, y la estabilidad de toda Internet sale como consecuencia.

Para ver que no es algo automático, spvp.py simula un vector de caminos en miniatura. En cada turno, cada AS mira lo que ofrecen sus vecinos, descarta los caminos que ya lo contienen y se queda con el que más le gusta. Se detiene si en una vuelta completa nadie cambia, o si el estado se repite. El primer ejemplo tiene tres AS y un destino 0, que es cliente de los tres. Hay un ciclo de proveedores: 1 es proveedor de 2, 2 de 3, y 3 de 1. Cumple las reglas 2 y 3: las rutas que cada AS prefiere vienen de clientes, y la regla 2 deja libre el orden entre clientes. Cada uno prefiere pasar por su cliente del anillo antes que llegar directo.

python3 spvp.py
Anillo con un ciclo de proveedores:
  vuelta 1:  1 0   2 0   3 1 0
  vuelta 2:  1 2 0   2 3 1 0   3 1 2 0
  vuelta 3:  1 0   2 0   3 1 0
  repite un estado ya visto: en este orden no termina nunca

Anillo sin ciclo de proveedores:
  vuelta 1:  1 0   2 0   3 0
  vuelta 2:  1 2 0   2 3 0   3 0
  vuelta 3:  1 3 0   2 3 0   3 0
  vuelta 4:  1 3 0   2 3 0   3 0
  estable

Seis AS con las reglas de Gao y Rexford (camino de cada uno hacia 64603):
  64601: 64604 64606 64603
  64602: 64605 64606 64603
  64603: (origen)
  64604: 64606 64603
  64605: 64606 64603
  64606: 64603
  con 50 órdenes de activación al azar: 1 resultado distinto

Cada columna es el camino que usa un AS: 1, 2 y 3. Sigan el primer ejemplo. En la vuelta 1, 3 pasa por 1. En la vuelta 2, 1 quiere pasar por 2, y 2 por 3, y 3 por 1: cada uno está persiguiendo al siguiente. Pero cuando el camino de un vecino ya contiene al que pregunta, no lo puede usar y debe volver atrás. Los tres dan vueltas y nunca descansan. Una configuración de esta forma se conoce como bad gadget, por el trabajo de Griffin, Shepherd y Wilfong.

Al invertir un solo enlace del ciclo (1 pasa a ser proveedor de 3), las mismas preferencias se estabilizan en pocas vueltas. Y los seis AS de nuestro laboratorio, con las reglas completas, llegan al mismo resultado hacia 64603 con cada uno de los 50 órdenes al azar. Lo último es solo una comprobación en este ejemplo, no una demostración. La demostración está en el artículo de Gao y Rexford.

Dos advertencias para quedarse con la idea correcta:

  • Es una garantía condicional. Basta que un AS no cumpla para que se pierda. BGP no verifica nada: la próxima semana veremos qué ocurre.
  • Estable no significa bueno. El resultado puede ser un camino largo, lento o caro para alguien. Las reglas aseguran que el sistema se detenga, no que se detenga en el mejor lugar.

Idea clave. Las reglas de importación y exportación no son solo una forma de ahorrar. Es lo que evita que BGP oscile, y que las rutas de Internet cambien sin parar.

Políticas en FRRouting

Pasemos a la herramienta. En FRRouting, una política de BGP se escribe con tres piezas.

Un route-map es un programa corto que se aplica a cada ruta, en una dirección de una sesión. Se compone de entradas numeradas, y cada una tiene una acción, permit o deny, sus condiciones match y sus cambios set:

route-map NOMBRE permit 10
 match <condición>
 set <cambio>
route-map NOMBRE permit 20
 match <otra condición>

Se evalúa de esta forma:

  1. Se recorren las entradas por número, de menor a mayor.
  2. Una entrada sin match aplica a todas las rutas. Si hay varios match deben cumplirse todos.
  3. En la primera entrada que aplica: si es permit, se hacen los set y la ruta pasa; si es deny, se bota.
  4. Si ninguna aplica, la ruta se bota. Un route-map termina con un deny implícito.

Una prefix-list es una lista de prefijos con la que un match puede preguntar “¿es este prefijo?”. Una comunidad es una etiqueta de 32 bits, que se escribe AS:valor, y sirve para recordar algo acerca de la ruta. Con bgp community-list se le pone un nombre a un conjunto de comunidades para poder hacer match con ellas.

El route-map se aplica a un vecino, con una dirección:

router bgp 65300
 address-family ipv4 unicast
  neighbor 100.64.130.130 route-map FROM_Q in

in es lo que entra desde ese vecino, antes de la elección del mejor camino: es la política de importación. out es lo que se le va a anunciar: es la exportación. Un vecino tiene a lo sumo un route-map por dirección.

Un ejemplo, pieza por pieza

Para aprender cada pieza por separado, usamos la tercera topología, en poli/. Tiene un AS mediano, m, con tres vecinos. Va a ser un ejemplo: no vamos a escribir aquí todas las reglas. Eso es el laboratorio.

      p (65310) ---- q (65320)        q también es cliente de p
        |  proveedor  /  peer
        |            /
        +--- m (65300)
              |  cliente
             c (65330)

Prefijos: m, 100.64.130.0/24; p, 100.64.131.0/24; q, 100.64.132.0/24; c, 100.64.133.0/24. Al inicio no hay políticas:

make up-poli
docker exec clab-w06-poli-m vtysh -c 'show bgp ipv4'
     Network          Next Hop            Metric LocPrf Weight Path
 *>  100.64.130.0/24  0.0.0.0                  0         32768 i
 *>  100.64.131.0/24  100.64.131.129           0             0 65310 i
 *                    100.64.130.130                         0 65320 65310 i
 *>  100.64.132.0/24  100.64.130.130           0             0 65320 i
 *                    100.64.131.129                         0 65310 65320 i
 *>  100.64.133.0/24  100.64.130.134           0             0 65330 i

Displayed 4 routes and 6 total paths

Hacia 100.64.131.0/24, m va directo a su proveedor p, porque el camino es más corto. Pero el camino por su peer q le saldría gratis.

Paso 1, local-preference. Este es el archivo poli/step1_localpref.conf:

! Paso 1, en m: lo que llega de q vale más que el valor por defecto (100).
route-map FROM_Q permit 10
 set local-preference 150
router bgp 65300
 address-family ipv4 unicast
  neighbor 100.64.130.130 route-map FROM_Q in
 exit-address-family

La configuración se puede cargar en un router que ya está corriendo. vtysh -f lee un archivo que esté dentro del nodo, así que primero se copia:

docker cp poli/step1_localpref.conf clab-w06-poli-m:/tmp/s.conf
docker exec clab-w06-poli-m vtysh -f /tmp/s.conf
docker exec clab-w06-poli-m vtysh -c 'show bgp ipv4 100.64.131.0/24'
BGP routing table entry for 100.64.131.0/24, version 7
Paths: (2 available, best #1, table default)
  Advertised to non peer-group peers:
  100.64.130.130 100.64.130.134 100.64.131.129
  65320 65310
    100.64.130.130 from 100.64.130.130 (100.64.132.1)
      Origin IGP, localpref 150, valid, external, best (Local Pref)
      Last update: Mon Nov  2 07:49:42 2026
  65310
    100.64.131.129 from 100.64.131.129 (100.64.131.1)
      Origin IGP, metric 0, valid, external
      Last update: Mon Nov  2 07:49:14 2026

Un camino de dos AS le gana a uno de un AS, y el router lo explica: best (Local Pref). LOCAL_PREF no sale del AS. Desde c, que es otro AS, este es el camino que m anuncia, sin rastro de la preferencia:

BGP routing table entry for 100.64.131.0/24, version 11
Paths: (1 available, best #1, table default)
  Advertised to non peer-group peers:
  100.64.130.133
  65300 65320 65310
    100.64.130.133 from 100.64.130.133 (100.64.130.1)
      Origin IGP, valid, external, best (First path received)
      Last update: Mon Nov  2 07:49:37 2026

En la práctica. Mientras un route-map recién cargado se aplica a lo que ya está en la tabla, pueden ver por unos segundos la letra S (stale) en vez de * en show bgp ipv4: FRRouting le pidió al vecino que le vuelva a mandar sus rutas. Espérense un momento. Si un cambio no parece tener efecto, clear bgp ipv4 * soft pide reprocesar todo sin tumbar las sesiones.

Paso 2, comunidades. Queremos recordar de dónde vino una ruta. Una vez en la tabla, el AS_PATH no dice qué tipo de vecino era: 65330 es solo un número. La forma habitual es poner una etiqueta al entrar, y leerla al salir:

! Paso 2, en m: lo que llega de c se marca con una comunidad.
route-map FROM_C permit 10
 set community 65300:30
router bgp 65300
 address-family ipv4 unicast
  neighbor 100.64.130.134 route-map FROM_C in
 exit-address-family
BGP routing table entry for 100.64.133.0/24, version 9
Paths: (1 available, best #1, table default)
  Advertised to non peer-group peers:
  100.64.130.130 100.64.130.134 100.64.131.129
  65330
    100.64.130.134 from 100.64.130.134 (100.64.133.1)
      Origin IGP, metric 0, valid, external, best (First path received)
      Community: 65300:30
      Last update: Mon Nov  2 07:49:55 2026

El valor 30 no significa nada para BGP: el significado lo pone el operador. Y a diferencia de LOCAL_PREF, una comunidad sí viaja a otros AS. Este es p, que recibió la ruta con la etiqueta:

  65300 65330
    100.64.131.130 from 100.64.131.130 (100.64.130.1)
      Origin IGP, valid, external, best (AS Path)
      Community: 65300:30
      Last update: Mon Nov  2 07:49:50 2026

Por eso conviene que set community, sin más opciones, reemplace las que traía la ruta: un vecino no debería poder meterse en la lógica interna de otro AS mandando una comunidad con su número. Para agregar sin borrar existe la palabra additive.

Paso 3, exportación. Ahora usamos la etiqueta. Hacia su proveedor, m solo debe mandar su prefijo y lo de su cliente:

! Paso 3, en m: hacia p salen el prefijo propio y lo marcado en el paso 2.
ip prefix-list MINE seq 5 permit 100.64.130.0/24
bgp community-list standard TAGGED_C permit 65300:30
route-map TO_P permit 10
 match ip address prefix-list MINE
route-map TO_P permit 20
 match community TAGGED_C
router bgp 65300
 address-family ipv4 unicast
  neighbor 100.64.131.129 route-map TO_P out
 exit-address-family

Dos entradas, cada una con un permit, y todo lo demás cae en el deny implícito. Antes de esto, m le anunciaba a p hasta la ruta de su peer q. Después:

docker exec clab-w06-poli-m vtysh -c 'show bgp ipv4 neighbors 100.64.131.129 advertised-routes'
     Network          Next Hop            Metric LocPrf Weight Path
 *>  100.64.130.0/24  0.0.0.0                  0         32768 i
 *>  100.64.133.0/24  100.64.130.134           0             0 65330 i

Total number of prefixes 2

Y desde p, ya no existe el camino a q que pasaba por m:

     Network          Next Hop            Metric LocPrf Weight Path
 *>  100.64.130.0/24  100.64.131.130           0             0 65300 i
 *                    100.64.131.134                         0 65320 65300 i
 *>  100.64.131.0/24  0.0.0.0                  0         32768 i
 *>  100.64.132.0/24  100.64.131.134           0             0 65320 i
 *>  100.64.133.0/24  100.64.131.130                         0 65300 65330 i
 *                    100.64.131.134                         0 65320 65300 65330 i

Displayed 4 routes and 6 total paths

Para ver cuántas veces se usó cada entrada, sirve show route-map TO_P. Y show bgp ipv4 community 65300:30 lista las rutas que tienen esa etiqueta.

¿Por qué una comunidad, y no una prefix-list con los prefijos de c? Porque una lista hay que mantenerla a mano en cada router, y cuando el cliente tiene su propio cliente se queda corta. La comunidad se pone una vez, en el borde donde se conoce la relación, y sirve en todas las sesiones de salida.

Error común. Olvidar el deny implícito. Un route-map que no deja pasar nada deja la sesión arriba y no anuncia nada, sin ningún error. También se bota todo si el nombre está mal escrito. Lo probamos en m, con un nombre que no existe:

The route-map 'TYPO_NAME' does not exist.

Neighbor        V         AS   MsgRcvd   MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd   PfxSnt Desc
100.64.130.130  4      65320        26        32        9    0    0 00:01:09            2        0 N/A
100.64.130.134  4      65330        35        37        9    0    0 00:00:49            1        4 N/A
100.64.131.129  4      65310        12        18        9    0    0 00:01:09            2        2 N/A

PfxSnt en 0 para 100.64.130.130. Si una sesión está en Established y el vecino no recibe nada, miren primero sus route-map y sus show bgp ipv4 neighbors ... advertised-routes.

Lo que debe pasar con las políticas puestas

Ahora les toca a ustedes. El paso 4 del laboratorio es escribir el conjunto completo de políticas para los seis AS, en lab/r1.conf a lab/r6.conf, con lo que acabamos de ver. Cada AS marca cada ruta según su origen, le da su preferencia y filtra lo que exporta. Aquí no está la configuración, pero sí está lo que deben observar cuando funcione, para que puedan comprobarlo. Como todos los AS comparten el mismo esquema, el trabajo está en entenderlo para uno y aplicarlo a los otros.

El AS chico ya no le anuncia nada ajeno a sus proveedores:

docker exec clab-w06-ases-r1 vtysh -c 'show bgp ipv4 neighbors 100.64.2.129 advertised-routes'
     Network          Next Hop            Metric LocPrf Weight Path
 *>  100.64.1.0/24    0.0.0.0                  0         32768 i

Total number of prefixes 1

Y el caso del tránsito gratis se resolvió. El camino de r2 a r4 ahora pasa por arriba, y es valle-libre:

traceroute to 100.64.4.1 (100.64.4.1) from 100.64.2.1, 30 hops max, 46 byte packets
 1  100.64.5.133  0.007 ms
 2  100.64.5.130  0.002 ms
 3  100.64.4.1  0.002 ms
Animación del tránsito gratis sobre los seis AS. Sin políticas, r1 anuncia a r2 sus seis prefijos, entre ellos 100.64.4.0/24, que aprendió de r4. Por eso, el tráfico de r2 hacia r4 baja a r1 y sube a r4, con traceroute 100.64.2.130 y 100.64.4.1, y r1 paga los dos enlaces. Con las políticas puestas, r1 solo anuncia su prefijo, y el tráfico va por r5, r6 y r4, con traceroute 100.64.5.133, 100.64.5.130 y 100.64.4.1: r2 le paga a r5, r4 le paga a r6, y entre peers no hay pagoAnimación del tránsito gratis sobre los seis AS. Sin políticas, r1 anuncia a r2 sus seis prefijos, entre ellos 100.64.4.0/24, que aprendió de r4. Por eso, el tráfico de r2 hacia r4 baja a r1 y sube a r4, con traceroute 100.64.2.130 y 100.64.4.1, y r1 paga los dos enlaces. Con las políticas puestas, r1 solo anuncia su prefijo, y el tráfico va por r5, r6 y r4, con traceroute 100.64.5.133, 100.64.5.130 y 100.64.4.1: r2 le paga a r5, r4 le paga a r6, y entre peers no hay pago
El mismo destino, antes y después de las políticas. El camino nuevo es más largo, pero cada enlace lo paga quien corresponde.

Es más largo. A la red en su conjunto le toma un salto más, y es lo correcto: ahora el que paga es quien debe pagar. Veamos el criterio de importación en r6, que conoce 100.64.1.0/24 de dos formas. Esta tabla viene de una solución con valores 300, 200 y 100. Los valores de ustedes pueden ser otros:

BGP routing table entry for 100.64.1.0/24, version 15
Paths: (2 available, best #1, table default)
  Advertised to non peer-group peers:
  100.64.5.129 100.64.6.130 100.64.6.134
  64604 64601
    100.64.6.130 from 100.64.6.130 (100.64.4.1)
      Origin IGP, localpref 300, valid, external, best (Local Pref)
      Community: 64606:100
      Last update: Mon Nov  2 07:47:54 2026
  64605 64602 64601
    100.64.5.129 from 100.64.5.129 (100.64.5.1)
      Origin IGP, localpref 200, valid, external
      Community: 64606:200
      Last update: Mon Nov  2 07:47:53 2026

Ganó por Local Pref y no por el largo: el camino de cliente habría ganado aunque fuera más largo. test_lab.py hace una comprobación más: los mejores caminos de los seis routers hacia los seis prefijos deben coincidir con lo que predice spvp.py con las reglas de Gao y Rexford, y todos deben ser valle-libres.

Preferir un proveedor

El paso 5 es para r1, el AS con dos proveedores. Con las políticas puestas, los dos proveedores valen lo mismo, y r1 llega a h3 por el más corto:

traceroute to 100.64.3.10 (100.64.3.10), 30 hops max, 46 byte packets
 1  100.64.1.1  0.004 ms
 2  100.64.4.129  0.002 ms
 3  100.64.6.129  0.002 ms
 4  100.64.6.134  0.001 ms
 5  100.64.3.10  0.002 ms

Supongamos que el contrato con r2 es más barato. r1 debería preferirlo siempre que pueda, aunque el camino sea más largo. Con un LOCAL_PREF mayor en lo que entra desde r2:

BGP routing table entry for 100.64.3.0/24, version 27
Paths: (2 available, best #1, table default)
  Not advertised to any peer
  64602 64605 64606 64603
    100.64.2.129 from 100.64.2.129 (100.64.2.1)
      Origin IGP, localpref 120, valid, external, best (Local Pref)
      Community: 64601:300
      Last update: Mon Nov  2 07:48:01 2026
  64604 64606 64603
    100.64.4.129 from 100.64.4.129 (100.64.4.1)
      Origin IGP, localpref 100, valid, external
      Community: 64601:300
      Last update: Mon Nov  2 07:47:52 2026
traceroute to 100.64.3.10 (100.64.3.10), 30 hops max, 46 byte packets
 1  100.64.1.1  0.005 ms
 2  100.64.2.129  0.003 ms
 3  100.64.5.133  0.002 ms
 4  100.64.6.129  0.002 ms
 5  100.64.6.134  0.001 ms
 6  100.64.3.10  0.005 ms

Un salto más, y por el proveedor que r1 quería. Ahora miren el traceroute de vuelta, desde h3:

traceroute to 100.64.1.10 (100.64.1.10), 30 hops max, 46 byte packets
 1  100.64.3.1  0.006 ms
 2  100.64.6.133  0.002 ms
 3  100.64.6.130  0.002 ms
 4  100.64.2.130  0.001 ms
 5  100.64.1.10  0.003 ms

Atención: el salto 4 es 100.64.2.130, una dirección del enlace r1–r2. Aun así, ese paquete no llegó por r2. Vino de r4 (100.64.6.130 es la dirección de r4) y entró a r1 por la otra interfaz. Es que r1 responde al ICMP con una dirección suya, y no necesariamente con la de la interfaz por la que entró el paquete: la elige según por dónde va a salir la respuesta, que ahora es hacia r2. Y r2 no estuvo en el camino de ida de ese traceroute. Lo que dice el AS_PATH en r6 y lo que muestra el salto 3 coinciden: entró por r4.

Idea clave. LOCAL_PREF controla por dónde sale el tráfico de mi AS, y nada más. Por dónde entra lo decide el que manda, con sus propias preferencias. Un AS tiene un control total de su salida, y solo puede hacer sugerencias para su entrada: un MED hacia un vecino, anuncios de prefijos más específicos, o repetir su número en el AS_PATH para alargar el camino que no quiere (AS path prepending, ejercicio 8).

Si se cae el enlace con r2, se retiran las rutas y el tráfico pasa solo al otro proveedor, sin que nadie toque nada:

docker exec clab-w06-ases-r1 ip link set eth2 down
docker exec clab-w06-ases-h1 traceroute -n -w 1 -q 1 100.64.3.10
traceroute to 100.64.3.10 (100.64.3.10), 30 hops max, 46 byte packets
 1  100.64.1.1  0.004 ms
 2  100.64.4.129  0.001 ms
 3  100.64.6.129  0.004 ms
 4  100.64.6.134  0.002 ms
 5  100.64.3.10  0.002 ms

Y al volver el enlace, el tráfico vuelve a r2.

Anycast

Hasta ahora, un prefijo tiene un solo owner. Nada en BGP impide que dos AS anuncien el mismo prefijo. De hecho, si uno lo hace sin permiso es un hijack, y lo veremos la próxima semana. Si lo hacen de común acuerdo, es una técnica muy útil.

Anycast es asignar la misma dirección IP a varios servidores en lugares distintos, y dejar que el routing lleve cada paquete a uno de ellos, normalmente el más cercano según BGP. El cliente no se entera: ve una sola dirección. Se usa mucho en:

  • DNS. Los servidores raíz usan anycast: cada letra (a a m) es una dirección, y detrás hay muchas instancias en todo el mundo.
  • CDN. Un usuario llega a la instancia cercana, sin pasar por una redirección de DNS.
  • Defensa contra DoS. Un ataque distribuido se reparte entre las instancias, en lugar de caer todo en un solo lugar.

El script ases/anycast.sh prende una instancia en un router: le agrega la dirección 100.64.200.1 a su loopback, levanta un pequeño servicio que responde con el nombre del router y anuncia 100.64.200.0/24. Lo prendemos en r2 y en r6, sin políticas:

ases/anycast.sh r2 64602 on
ases/anycast.sh r6 64606 on
docker exec clab-w06-ases-h1 sh -c 'nc -w 2 100.64.200.1 5300 </dev/null'
docker exec clab-w06-ases-h3 sh -c 'nc -w 2 100.64.200.1 5300 </dev/null'
r2
r6

Misma dirección, dos respuestas. h1 está junto a r2, y h3 está junto a r6. ¿Y r5, que queda a la misma distancia de los dos?

BGP routing table entry for 100.64.200.0/24, version 11
Paths: (2 available, best #1, table default)
  Advertised to non peer-group peers:
  100.64.5.130 100.64.5.134
  64602
    100.64.5.134 from 100.64.5.134 (100.64.2.1)
      Origin IGP, metric 0, valid, external, best (Older Path)
      Last update: Mon Nov  2 07:47:38 2026
  64606
    100.64.5.130 from 100.64.5.130 (100.64.6.1)
      Origin IGP, metric 0, valid, external
      Last update: Mon Nov  2 07:47:38 2026

Decide un desempate, el más antiguo: los dos caminos son iguales en todo lo que importa. “Cercano” significa cercano para BGP, con todos los criterios y políticas de antes. Puede no ser cercano en kilómetros ni en milisegundos.

Si se apaga una instancia, su ruta se retira y sus clientes pasan solos a la otra:

ases/anycast.sh r2 64602 off
docker exec clab-w06-ases-h1 sh -c 'nc -w 2 100.64.200.1 5300 </dev/null'
r6

Error común. Creer que anycast sirve igual para todo. Si durante una conexión TCP cambia la ruta, los paquetes siguientes llegan a otra instancia, que no conoce esa conexión y la corta. Por eso se popularizó primero en DNS sobre UDP, donde una consulta es un solo paquete. En CDN funciona bien porque en la práctica las rutas cambian poco durante una conexión corta, pero no es una garantía.

Cómo llega una organización a Internet

Armemos todas las piezas con un caso. Una empresa nueva en Lima quiere publicar un servicio web y no depender de un solo proveedor. ¿Qué necesita?

  1. Direcciones. Un bloque de direcciones públicas. Hay dos caminos: pedirlas a su proveedor (son del proveedor, y hay que devolverlas si se cambia de proveedor), o solicitar un bloque propio al registro regional, que para América Latina es LACNIC. En IPv4, los bloques nuevos son muy difíciles de conseguir y a menudo se compran a otros.
  2. Un número de AS. Sirve si la empresa tendrá políticas propias, como dos proveedores. También lo asigna el registro. Si tiene un solo proveedor, por lo general no hace falta: el proveedor anuncia sus direcciones dentro de su propio agregado.
  3. Conexión con proveedores. Contrata uno o más, y abre una sesión eBGP con cada uno. Aquí aplica lo que hicimos con r1: anunciar solo lo propio, y nunca dar transit entre proveedores. Los proveedores, a su vez, filtran lo que aceptan de ese cliente.
  4. Red interna. OSPF dentro, iBGP entre los routers de borde si hay más de uno, y NAT o direcciones públicas según lo que se vaya a publicar. Es el P1 de ustedes.
  5. DNS. Tener direcciones no es tener un nombre. La empresa registra su dominio, y el registrador deja en los servidores del dominio superior un registro NS que apunta a sus servidores de nombres, junto con sus direcciones. En esos servidores de nombres, un registro A apunta al servidor web. Veremos DNS en detalle más adelante en el curso.

En Kurose y Ross esto es la sección 5.4.6: ninguna pieza es nueva. Pero notar cómo se enlazan es útil. Sin DNS no te encuentran. Sin BGP, aunque te encuentren no te alcanzan. Sin OSPF, el paquete no atraviesa tu propia red. Y sin direcciones no hay nada que anunciar.

El laboratorio de la semana y make test

Todo se hace en code/week-06/, dentro del contenedor del curso.

code/week-06/
  ases/ases.clab.yml     los seis AS, sin políticas; base del laboratorio
  ases/anycast.sh        prende o apaga una instancia anycast
  ibgp/ibgp.clab.yml     un AS con cuatro routers, OSPF e iBGP
  ibgp/nhs_b1.conf ...   next-hop-self en los bordes; med_x.conf para MED
  poli/poli.clab.yml     el ejemplo de route-map, local-preference y comunidades
  poli/step1...conf      los tres pasos del ejemplo
  spvp.py                simulador de vector de caminos y comprobación de valle-libre
  lab/                   sus respuestas: r1.conf ... r6.conf y prefer.conf

Paso 1, una sesión. make up-ases. Con show bgp summary, sigan una sesión hasta Established. Apáguenla con neighbor ... shutdown, empiecen a capturar y vuelvan a prenderla. Encuentren en la captura el OPEN y un UPDATE, como en la Sesión A. Copien el archivo con docker cp y ábranlo en Wireshark, con el filtro bgp. No suban los .pcap al repositorio: se generan.

Paso 2, leer un AS_PATH. Desde r5, lean la ruta a 100.64.3.0/24 con show bgp ipv4. ¿Cuántos AS cruza? ¿Quién la originó? ¿Por dónde saldría el paquete?

Paso 3, tránsito gratis. Sin tocar nada, encuentren el AS que da transit gratis a sus dos proveedores. Muestren el AS_PATH y el traceroute que lo prueban, y expliquen quién paga cada enlace.

Paso 4, políticas. Completen lab/r1.conf a lab/r6.conf. Cada archivo trae el AS, sus vecinos y su relación con cada uno. Con route-map, marquen cada ruta con una comunidad según su origen, ordenen las preferencias con local-preference y filtren lo que sale. Carguen todo y comprueben lo que describe la sección anterior:

make policies
docker exec clab-w06-ases-r2 vtysh -c 'show bgp ipv4'

Paso 5, preferir un proveedor. Completen lab/prefer.conf para que r1 prefiera a r2. Un vecino admite un solo route-map de entrada, así que deben seguir marcando la ruta. Cárguenlo con make prefer, y compruébenlo con traceroute desde h1.

Paso 6, los proyectos. Entreguen P1 y lean el enunciado de P2.

En la práctica. P2 les pide algo parecido en otra escala: su AS tiene varios routers, otros vecinos y reglas adicionales. Lo que hagan en lab/ no se puede copiar tal cual, pero sí les va a servir la forma de razonar.

Cuando terminen un archivo de lab/, borren su línea TODO. Las pruebas que dependen de esos archivos se saltan, con un mensaje, hasta que estén todos.

make test levanta las tres topologías, una tras otra, y comprueba lo que dice este capítulo:

make test     # dentro del contenedor; tarda poco más de un minuto
test_every_session_is_established (test_ases.A_Sessions.test_every_session_is_established) ... ok
test_each_router_goes_to_its_closest_exit (test_ibgp.B_HotPotato.test_each_router_goes_to_its_closest_exit) ... ok
setUpModule (test_lab) ... skipped 'falta completar lab/r1.conf'
test_local_pref_beats_a_shorter_as_path (test_poli.B_LocalPref.test_local_pref_beats_a_shorter_as_path) ... ok
test_provider_cycle_with_free_ranking_never_settles (test_spvp.Convergence.test_provider_cycle_with_free_ranking_never_settles) ... ok
...
----------------------------------------------------------------------
Ran 49 tests in 65.683s

OK (skipped=1)

Eso es lo que verán mientras lab/ siga con su TODO. Cuando lo completen, se agregan las pruebas de test_lab.py. Esas pruebas miran comportamientos, no sus valores: local-preference y comunidades pueden tener otros números. Al terminar, pase lo que pase, make test destruye sus topologías. Si levantan algo a mano, make down lo limpia. Para reiniciar desde cero, destruyan y vuelvan a levantar: las políticas cargadas no se guardan en los frr.conf.

Resumen

  • Un sistema autónomo es una red bajo una misma administración y una misma política de routing. Dentro de un AS manda la eficiencia. Entre AS, manda la política.
  • BGP es un protocolo de vector de caminos: cada AS anuncia prefijos con un AS_PATH, le agrega su número al reenviar y descarta lo que ya lo contiene. No hay mapa global.
  • Una sesión es una conexión TCP al puerto 179, con cuatro mensajes: OPEN, UPDATE, KEEPALIVE y NOTIFICATION. Los anuncios valen hasta que se retiran o cae la sesión.
  • eBGP es entre AS distintos, e iBGP dentro del mismo. iBGP no reenvía a iBGP (por eso se usa malla completa o route reflectors) y no cambia el NEXT_HOP si no se pide con next-hop-self. OSPF sigue siendo el que lleva hasta los routers de borde.
  • Para elegir: LOCAL_PREF, largo de AS_PATH, ORIGIN, MED, eBGP antes que iBGP, costo IGP y desempates. BGP no mide retardo. Hot potato es salir por la salida más cercana.
  • Cliente, proveedor y peer responden a quién le paga a quién. Importación: preferir cliente, luego peer, luego proveedor. Exportación: rutas de clientes y propias a todos; las de peers y proveedores, solo a clientes.
  • Si se cumplen esas reglas, y no hay ciclos de proveedores, los caminos son valle-libres y BGP converge a un estado estable. Es una garantía condicional, no una propiedad del protocolo.
  • En FRRouting, una política es un route-map aplicado con in u out, con match, set y un deny implícito al final. local-preference ordena la salida; las comunidades recuerdan de dónde vino una ruta; prefix-list nombra prefijos.
  • Anycast es anunciar el mismo prefijo desde varios lugares. “Cercano” significa cercano para BGP.
  • Para aparecer en Internet hacen falta direcciones, a menudo un número de AS, proveedores, una red interna y DNS.

Ejercicios

  1. Sin correr nada, predigan el AS_PATH que tiene r5 hacia 100.64.4.0/24, en la red sin políticas y con políticas. Si cambia, expliquen por qué. Comprueben.
  2. Respondan según las reglas: un AS recibe dos rutas al mismo prefijo, una de un proveedor con AS_PATH de largo 2 y otra de un cliente con AS_PATH de largo 5. ¿Cuál debería preferir, y qué configuración lo hace posible? ¿Y a quién puede anunciar cada una?
  3. En una captura de una sesión, un router tiene un hold time de 180 s y el otro propone 90 s. Busquen en la RFC 4271 qué valor usan. ¿Cada cuánto debería mandarse un KEEPALIVE? Prueben a cambiarlo con neighbor ... timers 30 90 y confírmenlo en show bgp neighbors.
  4. En ibgp/, sin cargar next-hop-self, agreguen los enlaces de borde a OSPF. ¿Qué cambia en show bgp ipv4 de b2? ¿Qué desventaja tendría esta solución en un AS con cientos de vecinos?
  5. Dibujen un camino que no sea valle-libre y que tenga un enlace de peers. Expliquen, enlace por enlace, qué AS está perdiendo dinero. Comprueben su respuesta con spvp.is_valley_free.
  6. Expliquen la diferencia entre hot potato y cold potato. En la topología ibgp, si x y 65100 tienen dos conexiones y ambos usan hot potato, ¿es simétrico el tráfico entre un host detrás de b2 y uno detrás de x? Dibujen las dos direcciones.
  7. Escriban en spvp.py una red de cuatro AS que tenga un ciclo de proveedores y que aun así converja. ¿Contradice lo que dice este capítulo? Expliquen la diferencia entre “garantiza que converge” y “si no se cumple, no converge”.
  8. Con las políticas puestas, hagan que r1 prefiera que el tráfico le entre por r4, repitiendo su número en el AS_PATH hacia r2 con set as-path prepend 64601 64601. Comprueben desde h3 y desde r5 qué cambia y qué no. ¿Por qué r2 puede seguir usando el enlace directo con r1?
  9. Con las políticas puestas, quiten en r1 solo el route-map de salida hacia r4 (no neighbor 100.64.4.129 route-map ... out). Antes de mirar, predigan qué camino elegirán r4 y r6 hacia 100.64.5.0/24, recordando qué local-preference le dan a un cliente. Comprueben con show bgp ipv4 y con traceroute desde r6. ¿Qué AS paga de más? Comparen con la definición de route leak, y expliquen por qué la regla de importación empeora la situación en este caso.
  10. Una organización tiene 100.64.200.0/24 en anycast en tres ciudades y usa TCP. Expliquen qué le pasa a una descarga larga si una falla cambia el mejor camino de un usuario a otra ciudad. Propongan una forma de reducir ese riesgo y digan qué pierde con ella.
  11. Un compañero aplica en su AS este route-map de exportación hacia un proveedor: route-map OUT deny 10, con match community FROM_PEER, y nada más. Dice que así bloquea las rutas de peers y deja pasar el resto. ¿Qué anuncia en realidad? Corríjanlo. Comprueben con advertised-routes.
  12. Más difícil. Lean el route-map de su r2 del laboratorio. Supongan que r1 empieza a anunciarle 100.64.5.0/24, el prefijo de su proveedor r5, por error o a propósito. ¿Cuál ruta elige r2? ¿Por dónde va el tráfico de r2 hacia r5? ¿Qué regla habría que agregar para impedirlo? (Es el tema de la próxima semana.)