College Online
0%

Enlace de Dados

Modulo 5 · Aula 1 ~20 min de leitura Nivel: Intermediario

Video da aula estara disponivel em breve

A camada de enlace

A camada de enlace é responsável pela transferência de dados entre nós adjacentes (diretamente conectados). Enquanto a camada de rede (IP) lida com roteamento entre redes diferentes, a camada de enlace lida com a comunicação dentro de um único segmento de rede.

Suas responsabilidades principais são: enquadramento (framing) — delimitar onde um quadro começa e termina; controle de acesso ao meio (MAC) — decidir quem pode transmitir quando; detecção de erros — verificar se o quadro chegou íntegro; e endereçamento local — identificar dispositivos no mesmo segmento.

Ethernet e quadros (frames)

Diagrama
Quadro Ethernet:

+-----------+----------+------+---------+---------+-----+
| Preambulo | SFD      | Dest | Source  | Type    | ... |
| 7 bytes   | 1 byte   | MAC  | MAC     | 2 bytes |     |
|           |          |6 bytes|6 bytes |         |     |
+-----------+----------+------+---------+---------+-----+
                                                    |
+---------------------------------------------------+---+----+
|              Payload (46-1500 bytes)                   | FCS|
|              (pacote IP encapsulado)                   |4 B |
+--------------------------------------------------------+----+

MAC address: 48 bits, notacao hexadecimal
  Exemplo: AA:BB:CC:DD:EE:FF
  Primeiros 3 octetos: OUI (fabricante)
  Ultimos 3 octetos: ID unico do dispositivo

FCS (Frame Check Sequence): CRC-32 para detecção de erros

Tamanho total do quadro Ethernet:
  Mínimo: 64 bytes (46 payload + 18 overhead)
  Máximo: 1518 bytes (1500 payload + 18 overhead)
  Jumbo frames: até 9000 bytes de payload (datacenters)

Detecção de erros: CRC-32

O campo FCS (Frame Check Sequence) usa CRC-32 (Cyclic Redundancy Check) para detectar erros de transmissão. O transmissor calcula o CRC sobre todo o quadro e anexa o resultado. O receptor recalcula e compara — se diferente, o quadro é descartado silenciosamente.

Python
import binascii

# Simulação de CRC-32 na camada de enlace
def compute_fcs(frame_bytes):
    """Calcula o FCS (CRC-32) de um quadro Ethernet."""
    crc = binascii.crc32(frame_bytes) & 0xFFFFFFFF
    return crc

def verify_frame(frame_bytes, expected_fcs):
    """Verifica integridade do quadro."""
    computed = compute_fcs(frame_bytes)
    if computed == expected_fcs:
        print("Quadro íntegro — CRC OK")
        return True
    else:
        print(f"ERRO: CRC esperado {expected_fcs:#x}, calculado {computed:#x}")
        print("Quadro descartado (bit flip durante transmissão)")
        return False

# Simulando envio e recebimento
dados = b"Hello Ethernet"
fcs = compute_fcs(dados)
print(f"FCS calculado: {fcs:#010x}")
verify_frame(dados, fcs)             # OK
verify_frame(dados + b"X", fcs)      # ERRO — dados corrompidos

MAC addresses

MAC (Media Access Control) addresses sao enderecos fisicos de 48 bits, atribuidos pelo fabricante e (em teoria) unicos globalmente. Diferente de enderecos IP (logicos, mutaveis), MACs sao fisicos e geralmente fixos.

Python
import uuid
import subprocess

# Obter MAC address do host
mac = ':'.join([f'{(uuid.getnode() >> i) & 0xff:02x}'
               for i in range(0, 48, 8)][::-1])
print(f"MAC address: {mac}")

# Ver tabela ARP (mapeamento IP -> MAC)
result = subprocess.run(["arp", "-a"], capture_output=True, text=True)
print(result.stdout)

Controle de acesso ao meio (MAC)

Quando múltiplos dispositivos compartilham o mesmo meio físico (como um segmento de rede sem fio ou um hub Ethernet antigo), é necessário um protocolo para evitar colisões — duas transmissões simultâneas que se corrompem mutuamente.

Diagrama
Protocolos de acesso ao meio:

1. CSMA/CD (Carrier Sense Multiple Access / Collision Detection)
   Usado pelo Ethernet clássico (half-duplex)

   Algoritmo:
     1. Escuta o meio (carrier sense)
     2. Se livre → transmite
     3. Se ocupado → espera
     4. Se colisão detectada durante transmissão:
        a. Para de transmitir
        b. Envia jam signal (32 bits)
        c. Espera tempo aleatório (exponential backoff)
        d. Tenta novamente

   Exponential backoff:
     Após n colisões, espera K × 512 bit-times
     onde K é aleatório em [0, 2^n - 1]
     Máximo: n = 10 → K em [0, 1023]
     Após 16 colisões: desiste (frame descartado)

2. CSMA/CA (Collision Avoidance)
   Usado pelo Wi-Fi (802.11) — não detecta colisões no ar

   Algoritmo:
     1. Escuta o meio
     2. Se livre por DIFS → transmite
     3. Receptor envia ACK
     4. Se ACK não recebido → colisão, retransmite

   RTS/CTS (opcional): resolve "hidden terminal problem"
     A ---RTS---> AP ---CTS---> todos
     (todos sabem que A vai transmitir → esperam)

Switches vs. Hubs

Diagrama
Hub (camada 1 - fisica):
  Recebe quadro em uma porta -> replica para TODAS as outras portas
  Nao olha MAC addresses. Colisoes frequentes. Obsoleto.

  A --[frame]--> [HUB] --[frame]--> B
                   |---[frame]--> C  (C recebe mesmo sem ser destino)
                   |---[frame]--> D  (D tambem recebe)

Switch (camada 2 - enlace):
  Mantém tabela MAC (MAC -> porta). Encaminha apenas para a porta correta.
  Sem colisoes. Performance muito melhor.

  A --[frame]--> [SWITCH] --[frame]--> B  (apenas B recebe)
                   |
              Tabela MAC:
              AA:BB:CC:11 -> porta 1 (A)
              AA:BB:CC:22 -> porta 2 (B)
              AA:BB:CC:33 -> porta 3 (C)

ARP: Address Resolution Protocol

ARP resolve enderecos IP em enderecos MAC. Quando um host quer enviar um pacote para outro host na mesma rede, ele precisa saber o MAC address do destino.

Diagrama
Host A quer enviar para 192.168.1.5, mas so sabe o IP. Precisa do MAC.

1. A envia ARP Request (broadcast):
   "Quem tem o IP 192.168.1.5? Me diga seu MAC."
   Destino: FF:FF:FF:FF:FF:FF (broadcast - todos recebem)

2. Host B (192.168.1.5) responde com ARP Reply:
   "Eu sou 192.168.1.5. Meu MAC e AA:BB:CC:DD:EE:55"

3. A guarda na ARP cache: 192.168.1.5 -> AA:BB:CC:DD:EE:55

4. A encapsula o pacote IP em um frame Ethernet com:
   MAC destino: AA:BB:CC:DD:EE:55
   MAC origem:  (MAC do A)
   Tipo: 0x0800 (IPv4)
   Payload: pacote IP

Aprendizado da tabela MAC

Switches constroem sua tabela MAC automaticamente por um processo chamado self-learning: quando um quadro chega em uma porta, o switch registra o MAC de origem e a porta. Se o MAC de destino é desconhecido, o switch faz flooding — envia para todas as portas exceto a de origem.

Python
import time

class EthernetSwitch:
    """Simulação de um switch Ethernet com self-learning."""

    def __init__(self, num_ports, aging_time=300):
        self.mac_table = {}     # MAC → (porta, timestamp)
        self.num_ports = num_ports
        self.aging_time = aging_time

    def receive_frame(self, src_mac, dst_mac, in_port):
        """Processa um quadro recebido."""
        # Self-learning: registra MAC de origem
        self.mac_table[src_mac] = (in_port, time.time())

        # Forwarding: decide para onde enviar
        if dst_mac == "FF:FF:FF:FF:FF:FF":
            # Broadcast: envia para todas as portas exceto origem
            out_ports = [p for p in range(self.num_ports) if p != in_port]
            print(f"  BROADCAST → portas {out_ports}")
        elif dst_mac in self.mac_table:
            # Unicast conhecido: envia para porta específica
            out_port = self.mac_table[dst_mac][0]
            print(f"  FORWARD → porta {out_port}")
        else:
            # MAC desconhecido: flooding
            out_ports = [p for p in range(self.num_ports) if p != in_port]
            print(f"  FLOOD (MAC desconhecido) → portas {out_ports}")

sw = EthernetSwitch(4)
sw.receive_frame("AA:11", "BB:22", 0)  # Flood (BB:22 desconhecido)
sw.receive_frame("BB:22", "AA:11", 1)  # Forward porta 0 (AA:11 aprendido)

VLANs

VLANs (Virtual LANs) permitem segmentar uma rede física em múltiplas redes lógicas isoladas. Hosts em VLANs diferentes não podem se comunicar diretamente — precisam de um roteador (inter-VLAN routing).

Diagrama
Sem VLAN:                        Com VLANs:
  Todos no mesmo dominio         VLAN 10 (Eng): A, B
  de broadcast                   VLAN 20 (RH):  C, D

  A, B, C, D <-> broadcast       A <-> B (VLAN 10)
  (todos veem tudo)               C <-> D (VLAN 20)
                                  A -/-> C (bloqueado, VLANs diferentes)

  802.1Q: adiciona tag de 4 bytes ao frame Ethernet
  indicando a qual VLAN o frame pertence

Tag 802.1Q inserida no quadro Ethernet:
  ┌──────┬──────┬──────┬──────────┬──────┬─────────┬─────┐
  │ Dst  │ Src  │ TPID │ PCP│DEI│ │ VID  │  Type   │ ... │
  │ MAC  │ MAC  │0x8100│ 3b │1b │ │ 12b  │         │     │
  └──────┴──────┴──────┴──────────┴──────┴─────────┴─────┘
  TPID: Tag Protocol ID (0x8100 = 802.1Q)
  PCP:  Priority Code Point (QoS)
  VID:  VLAN ID (0-4095, 12 bits → 4096 VLANs possíveis)

Trunk port vs Access port:
  Access port: pertence a UMA VLAN, sem tag
  Trunk port: carrega múltiplas VLANs, com tag 802.1Q

No harness.os

A camada de enlace parece distante do trabalho com agentes AI, mas os conceitos aparecem diretamente ao debugar cloud networking. Além disso, o self-learning do switch é um padrão que se repete no harness.os:

Diagrama
Trace completo: MCP server -> Neon Postgres

Camada 7 (Aplicacao): MCP tool call (JSON-RPC)
Camada 7 (Aplicacao): PostgreSQL wire protocol (query SQL)
Camada 4 (Transporte): TCP segmento (porta 5432)
Camada 3 (Rede):       IP pacote (IP do Fly.io -> IP do Neon)
Camada 2 (Enlace):     Ethernet frame (MAC do gateway Fly.io)
Camada 1 (Fisica):     Sinais eletricos/opticos no datacenter

Quando "a conexao com o banco falha", o problema pode estar
em QUALQUER uma dessas camadas:
  - DNS nao resolve (camada 7)
  - Firewall bloqueia porta 5432 (camada 3/4)
  - Rede do datacenter com falha (camada 2/1)
  - TLS certificate expired (entre camada 4 e 7)

Entender todas as camadas = debugar qualquer problema de rede.

Resumo

Homework

Exercício 1: Trace um pacote do MCP server (Fly.io) ao Neon Postgres por todas as camadas de rede.

  1. Comece na aplicação: qual é a mensagem MCP? Qual query SQL?
  2. Desça: TCP (porta?), IP (IPs?), Ethernet (MACs?), físico (fibra/elétrico?)
  3. Use traceroute para ver os saltos entre seu computador e Neon
  4. Use arp -a para ver o cache ARP local

Exercício 2: Implemente o algoritmo CSMA/CD em pseudocódigo. Simule 5 estações tentando transmitir simultaneamente — quantas colisões ocorrem antes de todas conseguirem transmitir? Use exponential backoff.

Exercício 3: Implemente um switch Ethernet completo em Python com self-learning, aging de entradas (remover MACs não vistos há 300 segundos), e suporte a broadcast. Teste com 4 hosts simulados.

Exercício 4: Calcule o CRC-32 manualmente (com a biblioteca binascii) para 3 quadros Ethernet diferentes. Depois, altere 1 bit em cada quadro e verifique se o CRC detecta o erro.

Verifique seu entendimento

Qual protocolo é usado para descobrir o MAC address de um host conhecendo apenas seu IP?

  • DNS
  • DHCP
  • ARP (Address Resolution Protocol)
  • ICMP

Verifique seu entendimento

No CSMA/CD, o que acontece quando uma estação detecta colisão durante a transmissão?

  • Continua transmitindo e espera o receptor pedir retransmissão
  • Para de transmitir, envia jam signal, espera tempo aleatório (exponential backoff), e tenta novamente
  • Envia o quadro inteiro e espera um ACK
  • Descarta o quadro permanentemente

Verifique seu entendimento

Qual é a diferença fundamental entre um trunk port e um access port em VLANs?

  • Trunk ports são mais rápidos que access ports
  • Trunk ports carregam tráfego de múltiplas VLANs com tags 802.1Q; access ports pertencem a uma única VLAN sem tag
  • Access ports conectam switches entre si; trunk ports conectam hosts
  • Não há diferença — são sinônimos