# Route Tables and Longest-Prefix Match — Cloud Networking: VPCs, Subnets & Peering

Source: https://www.skillbyai.com/en/cloud-networking/cn-route-tables

> Read a route table, predict which route a packet uses and understand the implicit local route.

## How a VPC decides where a packet goes

Every subnet is associated with exactly one **route table**; a route table can serve many subnets. Each route has a **destination** CIDR and a **target**, such as `local`, an internet gateway (`igw-...`), a NAT gateway (`nat-...`), a peering connection (`pcx-...`) or a transit gateway (`tgw-...`). Every VPC route table contains a **local route** for the VPC's own CIDR, which lets all subnets in the VPC reach each other; you cannot delete it. When several routes match a destination, the VPC picks the **most specific** one, meaning the longest prefix. So with routes for `10.1.0.0/16` and `10.1.5.0/24`, traffic to `10.1.5.9` follows the `/24`. The default route `0.0.0.0/0` matches everything, so it is used only when nothing more specific does. Routing decides the *path*; it does not allow or deny traffic. Firewalls (security groups and network ACLs) make that decision separately.

## Tracing a route lookup

This toy lookup mirrors the VPC router: collect every matching route, then keep the one with the longest prefix.

```python
import ipaddress

routes = [
    ("10.0.0.0/16", "local"),
    ("10.1.0.0/16", "pcx-peer"),
    ("10.1.5.0/24", "tgw-attach"),
    ("0.0.0.0/0", "nat-gw"),
]

def lookup(dst):
    ip = ipaddress.ip_address(dst)
    matches = [(ipaddress.ip_network(c), t) for c, t in routes if ip in ipaddress.ip_network(c)]
    best = max(matches, key=lambda m: m[0].prefixlen)
    return best[1]

print(lookup("10.0.3.9"))
print(lookup("10.1.5.9"))
print(lookup("142.250.1.1"))
```

- Line 3: The table has a local route, a peering route, a more specific transit gateway route inside the peering range, and a default route.
- Line 16: First lookup: 10.0.3.9. Only the local /16 and the default /0 contain it.
- Line 13: The longest prefix wins, so /16 beats /0 and the packet stays inside the VPC.
- Line 17: 10.1.5.9 matches the peering /16, the transit /24 and the default route. Three candidates.
- Line 13: /24 is the most specific, so the packet goes to the transit gateway, not the peer.
- Line 18: A public address matches only the default route, so it leaves through the NAT gateway.

## The same lookup, run for real

Running the snippet confirms the trace.

```python
import ipaddress

routes = [
    ("10.0.0.0/16", "local"),
    ("10.1.0.0/16", "pcx-peer"),
    ("10.1.5.0/24", "tgw-attach"),
    ("0.0.0.0/0", "nat-gw"),
]

def lookup(dst):
    ip = ipaddress.ip_address(dst)
    matches = [(ipaddress.ip_network(c), t) for c, t in routes if ip in ipaddress.ip_network(c)]
    best = max(matches, key=lambda m: m[0].prefixlen)
    return best[1]

print(lookup("10.0.3.9"))
print(lookup("10.1.5.9"))
print(lookup("142.250.1.1"))
```

Output:

```
local
tgw-attach
nat-gw
```

## Routes are one-way

A route in VPC A towards VPC B does nothing for the reply. The return path needs its own route in B's route table. 'It works one way only' is almost always a missing return route.

**Quiz:** A route table has 10.0.0.0/16 -> local, 10.2.0.0/16 -> pcx-1, 10.2.4.0/22 -> tgw-1 and 0.0.0.0/0 -> igw. Where does traffic to 10.2.6.4 go?

- [ ] pcx-1
- [x] tgw-1
- [ ] igw
- [ ] local

*Answer:* tgw-1. 10.2.4.0/22 covers 10.2.4.0 to 10.2.7.255, so both pcx-1 (/16) and tgw-1 (/22) match. The longer prefix, /22, wins.
