Roteamento
Video da aula estara disponivel em breve
O que e roteamento?
Roteamento é o processo de determinar o caminho que um pacote deve seguir da origem ao destino, atravessando múltiplos roteadores. Cada roteador mantém uma tabela de roteamento que indica, para cada destino, qual é o próximo salto (next hop). É importante distinguir: forwarding (plano de dados) é a ação de mover um pacote de uma interface de entrada para uma de saída; routing (plano de controle) é o processo de construir a tabela que determina para onde o forwarding envia.
Tabelas de roteamento
Exemplo de tabela de roteamento:
Destino Mascara Next Hop Interface
────────────── ────────────── ──────────── ─────────
192.168.1.0 255.255.255.0 diretamente eth0
10.0.0.0 255.0.0.0 192.168.1.1 eth0
0.0.0.0 0.0.0.0 192.168.1.254 eth0 (default)
Algoritmo de forwarding:
1. Recebe pacote com IP destino
2. Procura o "longest prefix match" na tabela
3. Encaminha para o next hop correspondente
4. Se nenhuma entrada corresponde: usa default route (0.0.0.0/0)
Algoritmos de roteamento
Link-state (estado de enlace)
Cada roteador conhece a topologia completa da rede. Usa o algoritmo de Dijkstra para calcular o caminho mais curto para todos os destinos.
import heapq
def dijkstra(graph, start):
"""Algoritmo de Dijkstra para shortest path."""
distances = {node: float('inf') for node in graph}
distances[start] = 0
previous = {node: None for node in graph}
pq = [(0, start)]
while pq:
current_dist, current = heapq.heappop(pq)
if current_dist > distances[current]:
continue
for neighbor, weight in graph[current].items():
distance = current_dist + weight
if distance < distances[neighbor]:
distances[neighbor] = distance
previous[neighbor] = current
heapq.heappush(pq, (distance, neighbor))
return distances, previous
# Topologia de rede (grafo ponderado)
network = {
"R1": {"R2": 1, "R3": 4},
"R2": {"R1": 1, "R3": 2, "R4": 6},
"R3": {"R1": 4, "R2": 2, "R4": 3},
"R4": {"R2": 6, "R3": 3},
}
dist, prev = dijkstra(network, "R1")
print("Distancias de R1:", dist)
# {'R1': 0, 'R2': 1, 'R3': 3, 'R4': 6}
Distance-vector (vetor de distâncias)
Cada roteador conhece apenas seus vizinhos diretos e as distâncias que eles anunciam. Usa o algoritmo de Bellman-Ford distribuído. Cada roteador envia sua tabela de distâncias aos vizinhos periodicamente.
import copy
def bellman_ford_distributed(topology, max_iterations=10):
"""Simulação do algoritmo distance-vector distribuído.
Cada router troca tabelas com vizinhos até convergir."""
nodes = list(topology.keys())
# Inicializa: cada node conhece distância 0 para si
tables = {n: {n: 0} for n in nodes}
for iteration in range(max_iterations):
old_tables = copy.deepcopy(tables)
for node in nodes:
for neighbor, cost in topology[node].items():
# Recebe tabela do vizinho
for dest, dist in old_tables[neighbor].items():
new_dist = cost + dist
if dest not in tables[node] or new_dist < tables[node][dest]:
tables[node][dest] = new_dist
if tables == old_tables:
print(f"Convergiu na iteração {iteration + 1}")
break
return tables
network = {
"R1": {"R2": 1, "R3": 4},
"R2": {"R1": 1, "R3": 2, "R4": 6},
"R3": {"R1": 4, "R2": 2, "R4": 3},
"R4": {"R2": 6, "R3": 3},
}
tables = bellman_ford_distributed(network)
for node, table in tables.items():
print(f"{node}: {table}")
Count-to-infinity e split horizon
O distance-vector sofre do problema count-to-infinity: quando um link falha, routers podem trocar informações desatualizadas indefinidamente, incrementando custos até infinito. Soluções:
Problema count-to-infinity:
A ---[1]--- B ---[1]--- C
Se link B-C cai, B acha que pode chegar a C via A (custo 3)
A atualiza: custo para C = 4 (via B que diz 3 + 1)
B atualiza: custo para C = 5 (via A que diz 4 + 1)
... loop infinito até atingir "infinito" (16 no RIP)
Soluções:
Split horizon: Não anunciar rota de volta para quem a ensinou
Poison reverse: Anunciar custo infinito de volta para o vizinho
Triggered update: Enviar atualização imediata quando rota muda
Hold-down timer: Ignorar atualizações por T segundos após falha
Link-state vs Distance-vector:
Link-state Distance-vector
────────────── ────────────── ──────────────
Conhecimento Topologia completa Apenas vizinhos
Algoritmo Dijkstra Bellman-Ford
Convergencia Rapida Lenta (count-to-infinity)
Mensagens Floods LSAs Envia tabela aos vizinhos
Protocolo real OSPF, IS-IS RIP, EIGRP
Escalabilidade Melhor Pior em redes grandes
Protocolos de roteamento reais
OSPF (Open Shortest Path First)
Protocolo link-state usado dentro de sistemas autonomos (intra-AS). Cada roteador envia LSAs (Link State Advertisements) para construir um mapa completo da rede.
BGP (Border Gateway Protocol)
Protocolo path-vector usado entre sistemas autônomos (inter-AS). É o protocolo que "cola" a Internet — cada AS anuncia quais prefixos IP pode alcançar. BGP é o protocolo mais crítico da Internet e utiliza políticas de roteamento (não apenas menor custo) para decidir rotas.
AS 1 (Google) AS 2 (Amazon)
┌──────────────┐ ┌──────────────┐
│ OSPF interno │ │ OSPF interno │
│ R1──R2──R3 │ │ R4──R5──R6 │
└──────┬───────┘ └──────┬───────┘
│ │
└────── BGP ──────────┘
(troca de rotas inter-AS)
BGP: "Eu (AS1) posso alcançar 172.217.0.0/16"
"Eu (AS2) posso alcançar 54.239.0.0/16"
BGP path attributes (o que determina a melhor rota):
1. LOCAL_PREF Preferência local (maior = melhor)
2. AS_PATH Lista de ASes no caminho (menor = melhor)
3. NEXT_HOP Próximo roteador BGP
4. MED Multi-Exit Discriminator (sugestão do vizinho)
Diferença crucial: OSPF minimiza custo (shortest path)
BGP aplica POLÍTICAS (business relationships)
- Customer → Provider (paga, recebe trânsito)
- Peer → Peer (troca gratuita de tráfego)
- Provider → Customer (oferece trânsito)
Longest prefix match em detalhes
O algoritmo longest prefix match é fundamental para o forwarding IP. Quando um roteador tem múltiplas entradas que correspondem ao destino, ele escolhe a mais específica (maior prefixo):
import ipaddress
def longest_prefix_match(dest_ip, routing_table):
"""Implementa longest prefix match para forwarding IP."""
dest = ipaddress.ip_address(dest_ip)
best_match = None
best_prefix_len = -1
for network_str, next_hop in routing_table:
network = ipaddress.ip_network(network_str)
if dest in network and network.prefixlen > best_prefix_len:
best_match = next_hop
best_prefix_len = network.prefixlen
return best_match, best_prefix_len
# Tabela de roteamento
table = [
("10.0.0.0/8", "R1"), # Rota genérica
("10.1.0.0/16", "R2"), # Mais específica
("10.1.1.0/24", "R3"), # Mais específica ainda
("0.0.0.0/0", "default"), # Default route
]
# Teste: 10.1.1.50 corresponde a /8, /16 e /24 — qual ganha?
hop, prefix = longest_prefix_match("10.1.1.50", table)
print(f"10.1.1.50 → {hop} (prefix /{prefix})") # R3 (/24 — mais longo)
hop, prefix = longest_prefix_match("10.2.0.1", table)
print(f"10.2.0.1 → {hop} (prefix /{prefix})") # R1 (/8)
hop, prefix = longest_prefix_match("8.8.8.8", table)
print(f"8.8.8.8 → {hop} (prefix /{prefix})") # default (/0)
No harness.os
# Tabela de roteamento harness.os: concern -> agent
# Funciona como uma routing table onde "destino" e o concern
routing_table = {
"governance": {"agent": "governance-agent", "priority": 1},
"security": {"agent": "security-agent", "priority": 1},
"causal": {"agent": "build-agent", "priority": 2},
"relational": {"agent": "knowledge-agent", "priority": 2},
"metacognitive": {"agent": "meta-agent", "priority": 3},
"*": {"agent": "general-agent", "priority": 99}, # default route
}
def route_request(concern: str) -> str:
"""Roteia um request para o agente correto baseado no concern."""
if concern in routing_table:
return routing_table[concern]["agent"]
return routing_table["*"]["agent"] # default route
print(route_request("governance")) # governance-agent
print(route_request("unknown")) # general-agent (default)
Resumo
- Roteamento (plano de controle) constrói tabelas; forwarding (plano de dados) move pacotes
- Tabelas de roteamento: destino para next hop, resolvido via longest prefix match
- Link-state (Dijkstra): conhece toda a topologia, converge rápido (OSPF, IS-IS)
- Distance-vector (Bellman-Ford): só conhece vizinhos, converge devagar, sujeito a count-to-infinity (RIP)
- OSPF: intra-AS (dentro de uma rede); BGP: inter-AS (entre redes), baseado em políticas
- BGP usa path attributes (LOCAL_PREF, AS_PATH, MED) para decisão de rota, não apenas custo
Homework
Exercício 1: Construa uma routing table para harness.os que mapeia concerns para agentes especializados.
- Liste todos os 5 concerns e o agente responsável por cada um
- Adicione uma default route para concerns desconhecidos
- Implemente longest-prefix match: se concern é "security.mcp", match "security"
- Adicione métricas (latência, custo) e escolha a melhor rota
Exercício 2: Implemente o algoritmo de Dijkstra para uma rede com 6 roteadores. Desenhe a topologia, atribua pesos aos links, e calcule a árvore de caminhos mínimos a partir de cada roteador.
Exercício 3: Simule o problema count-to-infinity com 3 roteadores em linha (A-B-C). Remova o link B-C e mostre quantas iterações o distance-vector precisa para convergir. Implemente split horizon e compare.
Exercício 4: Pesquise um incidente real de BGP hijacking (ex: Pakistan YouTube 2008, ou Cloudflare 2019). Explique: o que aconteceu, por que BGP permitiu, e como poderia ser prevenido (RPKI).
Verifique seu entendimento
Qual algoritmo e usado pelo protocolo OSPF para calcular o caminho mais curto?
Verifique seu entendimento
Um roteador tem estas entradas na tabela: 10.0.0.0/8 → R1, 10.1.0.0/16 → R2, 10.1.1.0/24 → R3. Para qual next hop vai um pacote destinado a 10.1.1.50?
Verifique seu entendimento
Qual é a principal diferença entre OSPF e BGP?