Embedded HandbookПриложения
Все разделы › XII. Сети и DevOps для инженера
STM32F103, STM32F407 · уровень средний · 7 мин чтения
Открыть в интерактивном справочнике

108. Маршрутизация, VLAN, Wi-Fi и VPN

Сеть из раздела 105 кончается на шлюзе. Дальше пакет ведут маршрутизаторы: каждый смотрит в свою таблицу и отдаёт пакет следующему, уменьшая его время жизни. VLAN делит один провод на несколько сетей, Wi-Fi заменяет провод радио, а VPN прокладывает свою сеть поверх чужой. Код раздела выбирает маршрут, разбирает ответы маршрутизатора, ставит метку VLAN, считает каналы, затухание и цену туннеля. Опыт — маршрутизатор Linux между двумя сетями Docker: эхо-запросы с TTL 1 и 2, как у traceroute.

Кадры, ARP и ping — раздел 105, TCP и MSS — раздел 106.

Как это называется в документации

Оригинал Перевод
routing table таблица маршрутов
longest prefix match выбор самого длинного совпавшего префикса
default route маршрут по умолчанию
next hop следующий узел на пути
time exceeded ICMP «время жизни истекло»
destination unreachable ICMP «адресат недостижим»
VLAN tag, 802.1Q метка виртуальной сети
VLAN ID (VID), priority (PCP) номер виртуальной сети, приоритет
trunk / access port порт с метками / без меток
channel, channel width канал, ширина канала
free-space path loss (FSPL) затухание в свободном пространстве
RSSI, dBm уровень принятого сигнала, децибел к милливатту
tunnel, encapsulation туннель, упаковка пакета в пакет
MTU, MSS clamping наибольший пакет, урезание MSS под туннель

108.1 Таблица маршрутов

Маршрутизатор ищет в таблице запись, в чью сеть попадает адрес назначения; если подходят несколько — выигрывает самый длинный префикс:

int route_lookup(const route_t *t, unsigned n, uint32_t dst)
{
    int best = -1;
    for (unsigned i = 0; i < n; i++) {
        uint32_t m = t[i].len ? 0xFFFFFFFFu << (32u - t[i].len) : 0u;
        if ((dst & m) == t[i].net && (best < 0 || t[i].len > t[best].len))
            best = (int)i;
    }
    return best;
}
Сеть Шлюз Что это
0.0.0.0/0 192.168.1.1 всё остальное — маршрут по умолчанию
192.168.1.0/24 — своя сеть, напрямую
10.8.0.0/16 10.8.0.1 туннель VPN
10.8.5.0/24 192.168.1.50 через соседний маршрутизатор
10.8.5.7/32 192.168.1.60 один узел — отдельно

8.8.8.8 уходит по маршруту по умолчанию, 192.168.1.77 — напрямую, 10.8.1.2 — в туннель, 10.8.5.9 — через .50, а 10.8.5.7 — через .60: у /32 префикс длиннее всех. Без маршрута по умолчанию для 8.8.8.8 записи нет, и маршрутизатор отвечает «адресат недостижим».


108.2 Время жизни и traceroute

Опыт: эхо с TTL 1 и 2 через маршрутизатор между двумя сетями

Каждый маршрутизатор уменьшает TTL на единицу. Дошло до нуля — пакет выбрасывают, а отправителю шлют ICMP «время жизни истекло» и вкладывают начало его пакета: заголовок IP и 8 байт за ним, где у эха стоит номер. По нему отправитель узнаёт, на какой запрос пришёл ответ:

    } else if (r->type == ICMP_TIME_EXCEEDED || r->type == ICMP_UNREACHABLE) {
        const uint8_t *in = m + 8;      /* заголовок нашего пакета и 8 байт за ним */
        if (n < ihl + 8 + 20)
            return 0;
        unsigned ihl2 = (in[0] & 15u) * 4u;
        if (n < ihl + 8 + ihl2 + 8)
            return 0;
        r->orig_dst = g32(in + 16);
        r->id = g16(in + ihl2 + 4);
        r->seq = g16(in + ihl2 + 6);
    }

Опыт: сети 10.108.1.0/24 и 10.108.2.0/24, между ними контейнер с включённой пересылкой, а у сервера за ним — маршрут обратно. Код раздела собирает эхо функциями раздела 105 и отдаёт кадр MAC-адресу маршрутизатора. Эхо с TTL 1 маршрутизатор дальше не пустил и ответил сам — тип 11, код 0, от 10.108.1.2, а внутри — начало нашего пакета к 10.108.2.20 с нашим номером эха. Эхо с TTL 2 прошло, и ответ сервера пришёл с TTL 63: он начал с 64 и миновал один маршрутизатор. traceroute делает то же: TTL 1, 2, 3 …, и каждый ответ «время истекло» называет очередной узел пути.


108.3 VLAN: одна сеть — несколько сетей

Метка 802.1Q — 4 байта между адресом отправителя и типом: 0x8100, затем 3 бита приоритета, бит DEI и 12 бит номера сети:

unsigned vlan_tag(uint8_t *f, unsigned n, unsigned pcp, unsigned vid)
{
    memmove(f + 16, f + 12, n - 12);
    w16(f + 12, VLAN_TPID);
    w16(f + 14, (pcp & 7u) << 13 | (vid & 0xFFFu));   /* приоритет 3 бита, DEI, номер сети 12 бит */
    return n + 4;
}

Приоритет 5, сеть 10 — это 81 00 a0 0a, а за меткой остаётся настоящий тип, 0x0806. Номеров 4096, но 0 и 4095 заняты — сетей 4094. Кадр с меткой — до 1522 байт: старое оборудование, ждущее не больше 1518, такой кадр режет. Порт коммутатора «с метками» (trunk) несёт много сетей по одному проводу, порт «без меток» (access) — одну, и метку на нём снимают.


108.4 Wi-Fi: каналы и затухание

unsigned wifi_mhz(unsigned ch)
{
    if (ch == 14)
        return 2484;                    /* особый канал, только в Японии */
    if (ch >= 1 && ch <= 13)
        return 2407 + 5 * ch;
    return 5000 + 5 * ch;               /* 5 ГГц: канал 36 — 5180 МГц */
}
Канал МГц
1 2412
6 2437
11 2462
13 2472
14 2484
36 5180

Каналы отстоят на 5 МГц, а занимают 20 МГц: соседние перекрываются. Не перекрываются 1, 6 и 11 — между ними 25 МГц. Где разрешены каналы до 13-го, для 802.11g/n берут и четыре — 1, 5, 9, 13: они отстоят ровно на 20 МГц.

Wi-Fi 2,4 ГГц: каналы через 5 МГц, а шириной 20 — не перекрываются только 1, 6 и 11

Затухание в свободном пространстве растёт с расстоянием и частотой:

float fspl_db(float d_m, float f_mhz)
{
    return 20.0f * log10f(d_m / 1000.0f) + 20.0f * log10f(f_mhz) + 32.44f;
}

На канале 6 на 1 м — 40,2 дБ, на 10 м — 60,2 дБ, на 100 м — 80,2 дБ: вдвое дальше — плюс 6,02 дБ, вдесятеро — плюс 20. На 5180 МГц те же 10 м — 66,7 дБ, на 6,55 дБ больше: 5 ГГц быстрее, но короче. Передатчик на 20 дБм в 100 м в чистом поле даст −60,2 дБм, а каждая стена отнимет ещё.


108.5 VPN: сеть поверх сети

Туннель упаковывает пакет в пакет: внутренний шифруют и отправляют внутри UDP. WireGuard добавляет 16 байт своего заголовка и 16 байт метки подлинности, а данные дополняет до кратного 16:

unsigned wg_outer(unsigned n, int ipv6, unsigned mtu)
{
    unsigned padded = (n + 15u) & ~15u;
    if (padded > mtu)
        padded = mtu;
    return (ipv6 ? 40u : 20u) + 8u + WG_HDR + padded + WG_TAG;
}

Пакет датчика в 60 байт выходит из туннеля в 124 байта — больше чем вдвое; ping из 84 байт — 156. Внутренний пакет в 1420 байт с IPv6 снаружи даёт ровно 1500, поэтому MTU туннеля — 1420; с IPv4 снаружи выходит 1480. TCP внутри туннеля должен договориться о MSS 1380, иначе полноразмерные сегменты не пролезут.

Внешний пакет WireGuard по слоям: 60 байт данных выходят из туннеля в 124, ping в 84 байта — в 156, пакет 1420 байт с IPv6 снаружи — ровно в 1500


108.6 На приборе

У MAC F407 есть регистр сравнения метки VLAN — MACVLANTR, смещение 0x1C. Совпавшую метку он только отмечает битом VLAN в состоянии дескриптора приёма и разрешает кадр длиной до 1522 байт; кадры чужих сетей всё равно ложатся в буферы, и отбрасывать их приходится программе по этому признаку. Аппаратный фильтр по метке есть у MAC новых семейств — у H7 это бит VTFE в ETH_MACPFR. Wi-Fi к STM32 обычно подключают готовым модулем на UART или SPI, и затухание из 108.4 считают для него. VPN на приборе — редкость; чаще туннель держит маршрутизатор, а прибор видит обычную сеть и живёт с MTU 1420, если пакеты идут через туннель.

_Static_assert(offsetof(ETH_TypeDef, MACVLANTR) == 0x1C, "ETH_MACVLANTR — смещение 0x1C");

108.7 Грабли

Ответ из другой сети не приходит, хотя запрос маршрутизатор пропустил. У получателя нет обратного маршрута, и ответ уходит его шлюзу по умолчанию. В опыте серверу пришлось добавить маршрут в 10.108.1.0/24 через .2.

Через VPN ходят мелкие пакеты, а большие пропадают. MTU туннеля 1420: 1500-байтный пакет в него не влезает. MTU 1420, MSS 1380.

Wi-Fi соседа на канале 3 мешает сильнее, чем на канале 1. Соседние каналы перекрываются: брать 1, 6 или 11.

Кадр с меткой VLAN не проходит. Порт без меток, или оборудование режет кадры длиннее 1518 байт.

traceroute показывает звёздочки. Маршрутизатор не обязан отвечать «время истекло» и ограничивает частоту таких ответов.


108.8 Итоги

Дальше: раздел 109 «Git для инженера: ветки, история, версии прошивки» — как не терять прошивки и помнить, из какого кода собрана каждая.

Открыть в интерактивном справочнике