48 KiB
D4, часть 2. L2/L3: Ethernet, IP, подсети (урок)
Это не проверка, а урок: сначала разбираем механизм, потом решаешь tasks/04_ipv4 и
tasks/13_subnet. Тема дня — то, что физически лежит в байтах пакета от момента, когда
приложение вызвало send, до момента, когда кадр ушёл в провод.
1. Модель OSI и модель TCP/IP
OSI — эталонная модель из семи независимых уровней: физический, канальный, сетевой, транспортный, сеансовый, представления, прикладной. Каждый уровень решает свою задачу и разговаривает только с соседними уровнями через фиксированный интерфейс, не зная деталей их реализации — физическую среду можно сменить с меди на оптику, ничего не трогая в IP и TCP, потому что канальный уровень скрывает эту деталь от сетевого. На практике верхние три уровня (сеансовый, представления, прикладной) отдельно не реализуют — приложение само решает вопросы сессии и кодирования данных.
TCP/IP — практическая четырёхуровневая модель, которой реально пользуется стек Linux: канальный, интернет, транспортный, прикладной. Соответствие: канальный уровень TCP/IP = L1+L2 OSI (доставка кадра внутри сегмента), интернет-уровень = L3 OSI (IP, маршрутизация между сетями), транспортный = L4 OSI (TCP/UDP, порты), прикладной уровень TCP/IP поглощает сразу L5–L7 OSI. Сокет создаётся на транспортном уровне — отдельного программного «уровня сессии» в реальном стеке не существует.
Факты для карточек
- base | Сколько уровней в модели OSI? — 7
- base | Сколько уровней в модели TCP/IP? — 4
- core | Какие три уровня OSI объединяет прикладной уровень TCP/IP? — сеансовый, представления, прикладной
- core | На каком уровне создаётся сокет? — транспортном (L4 OSI / транспортный TCP/IP)
Почему дальше: раз данные проходят через уровни сверху вниз при отправке, нужно понять, что физически происходит с байтами на каждом уровне — это инкапсуляция.
2. Инкапсуляция: во что заворачиваются данные
Каждый нижний уровень оборачивает данные верхнего уровня в свой заголовок (а канальный — ещё и в трейлер) при передаче:
данные приложения
→ сегмент TCP (заголовок 20 байт)
→ пакет IP (заголовок 20 байт)
→ кадр Ethernet (заголовок 14 байт + трейлер FCS 4 байта)
На приёмной стороне процесс идёт в обратном порядке: каждый уровень снимает свой заголовок и
передаёт содержимое выше, ориентируясь на поле типа протокола (EtherType в Ethernet-кадре
говорит, что внутри IP; поле protocol в IP-заголовке говорит, что внутри TCP/UDP/ICMP).
Так устроено потому, что каждый уровень должен работать независимо от содержимого —
коммутатору не нужно знать про TCP, чтобы передать кадр дальше, ему хватает MAC-адреса в
заголовке L2. В дампе tcpdump эта вложенность видна буквально как последовательность байт:
Ethernet, затем IP, затем TCP, затем данные.
Факты для карточек
- base | Размер заголовка TCP-сегмента (без опций)? — 20 байт
- base | Размер заголовка IP-пакета (без опций)? — 20 байт
- base | Размер заголовка Ethernet-кадра и трейлера FCS? — 14 байт заголовок + 4 байта FCS
- core | По какому полю верхний уровень при приёме узнаёт, что лежит внутри нижнего? — по полю типа протокола (EtherType в Ethernet,
protocolв IP)
Почему дальше: раз данные заворачиваются в Ethernet-кадр последними перед проводом, логично разобрать этот заголовок по байтам первым.
3. Ethernet и MAC-адрес
Ethernet-заголовок — 14 байт: 6 байт MAC-адрес получателя, 6 байт MAC-адрес отправителя, 2 байта EtherType (тип содержимого кадра — например, IPv4 или ARP). После полезной нагрузки кадр завершается 4-байтовым трейлером FCS (frame check sequence) — контрольной суммой для проверки целостности при приёме; трейлер частью заголовка не считается. Фиксированная и компактная структура нужна для того, чтобы коммутатор мог разобрать заголовок на аппаратной скорости без анализа содержимого выше — все поля имеют строго фиксированную длину и позицию.
MAC-адрес — 48-битный (6-байтный) физический адрес интерфейса, действующий только внутри одного сегмента (широковещательного домена). Первые 3 байта (OUI) назначаются производителю оборудования организацией IEEE, оставшиеся 3 байта производитель присваивает конкретному интерфейсу. Когда пакет покидает сегмент через маршрутизатор, MAC-адрес получателя в заголовке меняется на MAC следующего узла на пути, а IP-адрес остаётся прежним — L2 отвечает за доставку «из рук в руки» внутри сегмента, L3 — за доставку через множество сегментов.
Факты для карточек
- base | Длина Ethernet-заголовка? — 14 байт
- base | Длина трейлера FCS? — 4 байта
- base | Длина MAC-адреса в битах и байтах? — 48 бит, 6 байт
- core | Из скольки байт состоит OUI в MAC-адресе и кто его назначает? — 3 байта, назначает IEEE производителю
- core | Что меняется в заголовках при переходе пакета через маршрутизатор — MAC или IP получателя? — MAC-адрес получателя, IP остаётся прежним
Почему дальше: чтобы отправить кадр внутри сегмента, нужен MAC получателя, а известен обычно только его IP — протокол, который их связывает, это ARP.
4. ARP: разрешение IP в MAC
ARP (Address Resolution Protocol) по известному IP-адресу узла в локальном сегменте находит его MAC-адрес. Механизм: отправитель рассылает широковещательный (broadcast) кадр «кто владеет IP X, сообщите свой MAC»; получают его все узлы сегмента, но отвечает только владелец адреса — уже адресным unicast-пакетом со своим MAC. Полученную пару IP-MAC отправитель кладёт в локальный ARP-кэш (таблицу), чтобы не повторять broadcast на каждый пакет — именно поэтому первый пакет к новому соседу в сети чуть медленнее последующих, он ждёт ARP-ответа.
Gratuitous ARP — ARP-запрос или ответ, который узел рассылает не в ответ на чужой запрос, а сам, без повода, про собственный IP-адрес (запрашивает MAC для своего же IP). Назначение — объявить остальным узлам сегмента свою пару IP-MAC заранее (обновить их кэши до первого реального обмена) или обнаружить конфликт IP-адресов: если кто-то в сегменте уже отвечает за тот же IP, это сразу видно. Используется при старте интерфейса и при переключении на резервный узел (failover), чтобы соседи сразу обновили устаревшую запись в ARP-кэше на MAC нового узла.
Если ARP не проходит (узел выключен, неверная подсеть, фильтрация), это видно в tcpdump как
повторяющиеся «who has X» без ответа, а приложение получит таймаут соединения без объяснения
причины.
Факты для карточек
- base | Как рассылается ARP-запрос — broadcast или unicast? — broadcast
- base | Как отправляется ARP-ответ? — unicast, от владельца адреса
- core | Зачем нужен ARP-кэш? — не повторять broadcast-запрос для каждого исходящего пакета к уже известному узлу
- core | Что такое gratuitous ARP и для чего он нужен? — незапрошенный ARP про собственный IP; обновление чужих кэшей заранее и обнаружение конфликта адресов
Почему дальше: ARP работает внутри одного L2-сегмента. Если в сети настроены виртуальные сегменты поверх одной физической — VLAN, — это меняет сам Ethernet-заголовок.
5. VLAN 802.1Q
VLAN (Virtual LAN) по стандарту 802.1Q делит один физический сегмент на несколько логически изолированных широковещательных доменов — кадры из разных VLAN не видят широковещательный трафик друг друга, хотя идут по одному кабелю и через один коммутатор. Механизм — тег из 4 дополнительных байт, вставляемый в Ethernet-заголовок между MAC-адресом отправителя и полем EtherType:
- TPID (Tag Protocol Identifier) — 2 байта, фиксированное значение 0x8100, сигнализирует коммутатору, что дальше идёт VLAN-тег, а не обычный EtherType;
- TCI (Tag Control Information) — 2 байта, из них: PCP (Priority Code Point, 3 бита) — приоритет кадра для QoS, DEI (Drop Eligible Indicator, 1 бит) — кандидат на отбрасывание первым при перегрузке, VID (VLAN ID, 12 бит) — номер VLAN, диапазон 0–4095 (0 и 4095 зарезервированы, реально используется 1–4094).
Из-за тега заголовок Ethernet-кадра с VLAN вырастает с 14 до 18 байт. Если это не
учесть при расчёте MTU или максимального размера кадра, получится ошибка ровно на 4 байта —
типично ловится сравнением дампа tcpdump с ожидаемой длиной.
Факты для карточек
- base | Сколько байт добавляет VLAN-тег 802.1Q к Ethernet-заголовку? — 4 байта (14 → 18)
- base | Значение поля TPID для VLAN-тега? — 0x8100
- core | Из каких трёх полей состоит TCI и сколько бит занимает VID? — PCP (3 бита), DEI (1 бит), VID (12 бит)
- core | Диапазон реально используемых VLAN ID? — 1–4094 (0 и 4095 зарезервированы)
Почему дальше: заголовок Ethernet ограничивает не только формат, но и максимальный размер полезной нагрузки в одном кадре — MTU.
6. MTU и фрагментация
MTU (Maximum Transmission Unit) — максимальный размер полезной нагрузки, который канальный уровень передаёт в одном кадре; для стандартного Ethernet это 1500 байт. Если IP-пакет крупнее MTU исходящего интерфейса, происходит одно из двух:
- фрагментация — пакет режется на несколько IP-пакетов меньшего размера, каждый со своим IP-заголовком, собираются они уже на узле-получателе;
- если в заголовке выставлен флаг DF (Don't Fragment) — узел на пути отбрасывает пакет и отправляет источнику ICMP-сообщение о необходимости фрагментации (см. раздел про ICMP).
Ограничение в 1500 байт исторически идёт из спецификации Ethernet и балансирует накладные расходы заголовка против задержки и вероятности ошибки на длинном кадре: чем крупнее кадр, тем дороже обходится его повторная передача при ошибке. Фрагментация — дорогая операция: она нагружает маршрутизаторы на пути и делает передачу уязвимой к потере одного фрагмента, из- за которого теряется весь исходный пакет целиком. Поэтому современные стеки заранее подбирают размер пакета под MTU всего пути — механизм PMTUD (Path MTU Discovery), разобранный дальше вместе с ICMP.
Факты для карточек
- base | Значение MTU для стандартного Ethernet? — 1500 байт
- core | Что происходит с IP-пакетом крупнее MTU, если флаг DF не выставлен? — фрагментируется на несколько IP-пакетов меньшего размера
- core | Что происходит, если пакет крупнее MTU и выставлен флаг DF? — пакет отбрасывается, отправителю летит ICMP о необходимости фрагментации
- deep | Почему фрагментация считается дорогой операцией? — нагружает маршрутизаторы на пути, и потеря одного фрагмента роняет весь исходный пакет
Почему дальше: и флаг DF, и размер, и адреса — это конкретные поля одной структуры, IP-заголовка. Разберём его целиком по байтам.
7. IPv4-заголовок по полям
IPv4-заголовок — минимум 20 байт (без опций), опции могут увеличить его до 60 байт. Поля в порядке следования:
| Поле | Размер | Смысл |
|---|---|---|
| Version | 4 бита | версия протокола, для IPv4 всегда 4 |
| IHL | 4 бита | длина заголовка в 32-битных словах (минимум 5 → 20 байт) |
| TOS (Type of Service) | 8 бит | приоритет/качество обслуживания пакета |
| Total Length | 16 бит | общая длина пакета (заголовок + данные), байты |
| Identification | 16 бит | идентификатор для сборки фрагментов одного исходного пакета |
| Flags | 3 бита | бит DF (не фрагментировать), бит MF (есть ещё фрагменты) |
| Fragment Offset | 13 бит | смещение этого фрагмента в исходном пакете |
| TTL | 8 бит | время жизни пакета в хопах |
| Protocol | 8 бит | протокол следующего уровня: 6 = TCP, 17 = UDP, 1 = ICMP |
| Header Checksum | 16 бит | контрольная сумма заголовка (не данных) |
| Source / Destination IP | по 32 бита | адреса отправителя и получателя |
Это ровно поля структуры Ipv4Header из tasks/04_ipv4. Задача требует парсить их из сырого
буфера побайтово (через сдвиги и маски), а не приведением указателя reinterpret_cast — на
невыровненных адресах и при другом порядке байт это UB. Обязательные проверки при разборе:
буфер короче 20 байт, version != 4, ihl < 5, ihl*4 > len, total_length < ihl*4 или
total_length > len — пакет с любым из этих условий отбрасывается как некорректный, ещё до
попытки читать поля выше заголовка.
Факты для карточек
- base | Минимальный размер IPv4-заголовка? — 20 байт
- base | Значение поля Protocol для TCP / UDP / ICMP? — 6 / 17 / 1
- core | Сколько бит занимает поле IHL и что оно означает? — 4 бита, длина заголовка в 32-битных словах
- core | Какие условия делают IPv4-пакет некорректным при разборе (по
tasks/04_ipv4)? — буфер <20 байт, version≠4, ihl<5, ihl·4>len, total_length<ihl·4 или >len - deep | Почему в
tasks/04_ipv4запрещёнreinterpret_castна буфер? — невыровненный адрес и другой порядок байт на проводе дают UB при чтении полей как структуры напрямую
Почему дальше: одно из полей заголовка — TTL — существует специально для защиты от зацикленной маршрутизации, и с ним напрямую связан отдельный протокол ошибок, ICMP.
8. TTL и ICMP Time Exceeded: как работает traceroute
TTL (Time To Live) уменьшается на единицу на каждом маршрутизаторе, через который проходит пакет. Это сделано специально: чтобы зацикленный по ошибке маршрут не гонял пакет по сети бесконечно. Когда TTL достигает нуля, пакет отбрасывается, а отправителю отправляется ICMP Time Exceeded (тип 11).
Именно на этом механизме построен traceroute: он последовательно отправляет пакеты с TTL 1, 2, 3, ... Пакет с TTL 1 гарантированно "умирает" на первом же маршрутизаторе — тот шлёт ICMP Time Exceeded с собственным адресом, это и есть первая строка вывода traceroute. Пакет с TTL 2 доходит до второго маршрутизатора и умирает там, и так далее, пока пакет не дойдёт до конечного получателя. Так по цепочке ICMP-ответов восстанавливается список всех промежуточных маршрутизаторов на пути, без какого-либо специального протокола обнаружения маршрута — только манипуляция TTL и стандартный побочный эффект его истечения.
Факты для карточек
- base | На сколько уменьшается TTL на каждом маршрутизаторе? — на 1
- base | Какой ICMP-тип отправляется при обнулении TTL? — Time Exceeded, тип 11
- core | Как traceroute находит промежуточные маршрутизаторы, не имея отдельного протокола обнаружения пути? — последовательно шлёт пакеты с TTL=1,2,3..., каждый умирает на очередном хопе и присылает ICMP Time Exceeded с адресом этого хопа
Почему дальше: Time Exceeded — лишь один из типов ICMP-сообщений. Остальные закрывают другие сценарии ошибок доставки и обнаружения MTU пути.
9. ICMP: echo, destination unreachable, PMTUD
ICMP (Internet Control Message Protocol) — протокол сетевого уровня для диагностических сообщений; у него нет портов, он не переносит пользовательские данные приложений. Ключевые типы:
- Echo Request / Echo Reply (тип 8 / тип 0) — основа команды
ping; - Time Exceeded (тип 11) — TTL обнулился (раздел выше, основа traceroute);
- Destination Unreachable (тип 3) — пакет физически не может быть доставлен; код внутри этого типа уточняет причину, в частности код "fragmentation needed and DF set" — посылается, когда пакет крупнее MTU промежуточного линка, а флаг DF запрещает фрагментацию.
Именно код "fragmentation needed" лежит в основе PMTUD (Path MTU Discovery): отправитель шлёт пакеты с выставленным DF, начиная с MTU своего интерфейса; если по пути встречается линк с меньшим MTU, тот роутер отбрасывает пакет и присылает ICMP Destination Unreachable с этим кодом (в современных реализациях — вместе со значением MTU узкого места); отправитель уменьшает размер пакета и повторяет попытку. Так стек заранее подбирает размер, не полагаясь на фрагментацию по пути.
ICMP существует отдельно от TCP/UDP потому, что диагностика нужна на уровне, где ещё нет
понятия соединения или порта — маршрутизатор должен уметь сообщить об ошибке доставки, даже не
зная, что за протокол был внутри. Именно поэтому ping и traceroute работают даже к узлу,
на котором не открыт ни один сервис поверх TCP/UDP. Если ICMP заблокирован файрволом
(частая практика), ping не пройдёт, хотя TCP-соединение на конкретный порт может работать
нормально — это видно, если сравнить ping host и curl host с разным результатом.
Факты для карточек
- base | Номера типов Echo Request и Echo Reply? — 8 и 0
- base | Тип ICMP-сообщения Destination Unreachable? — тип 3
- core | Какой код Destination Unreachable запускает PMTUD? — "fragmentation needed and DF set"
- core | Почему ICMP не имеет портов? — диагностика работает на сетевом уровне, где ещё нет понятия транспортного соединения
- deep | Почему
pingможет не проходить, аcurlна тот же хост — работать? — ICMP заблокирован файрволом отдельно от TCP-порта, это два разных уровня фильтрации
Ловушки
- Судить о доступности хоста только по
ping→ файрвол может глушить ICMP, не трогая реальный TCP-сервис — вывод «хост недоступен» будет ложным. - Не учитывать PMTUD при жёстко заданном MTU в туннеле (VPN, GRE) → пакеты с DF молча теряются на узком месте, если ICMP-ответы блокируются по пути — проявляется как «маленькие пакеты проходят, большие — зависают».
Почему дальше: контрольная сумма заголовка из раздела про IPv4-поля устроена нетривиально — разберём отдельно, как она считается и почему покрывает только заголовок.
10. Контрольная сумма IPv4-заголовка
Алгоритм — сумма в дополнительном коде (one's complement) по 16-битным словам заголовка,
затем инверсия результата (побитовое НЕ) — это и есть значение, которое пишут в поле
header_checksum. При сложении в дополнительном коде перенос из старшего бита не отбрасывается,
а прибавляется обратно к младшему биту суммы (end-around carry).
tasks/04_ipv4 требует ровно эту схему в двух функциях:
// сумма в дополнительном коде по len байтам, затем инверсия — значение для записи в поле
// (вызывается на буфере, где поле контрольной суммы уже обнулено)
uint16_t compute_checksum(const uint8_t* buf, size_t len);
// true, если контрольная сумма заголовка верна: сумма в дополнительном коде по ihl*4 байтам
// заголовка (вместе с полем контрольной суммы) равна 0xFFFF; нагрузка не участвует
bool checksum_valid(const uint8_t* buf, size_t len);
Асимметрия проверки и вычисления не случайна: при вычислении поле суммы ещё не заполнено (обнулено), поэтому оно не участвует своим значением; при проверке поле уже содержит записанную сумму, и если она верна, повторное суммирование всех 16-битных слов заголовка (включая это поле) в дополнительном коде обязано дать все единицы — 0xFFFF. Это свойство дополнительного кода: сумма X и инверсии X всегда даёт все единицы.
Почему сумма считается только по заголовку, а не по всему пакету с данными: заголовок
меняется на каждом хопе — как минимум TTL уменьшается на 1 на каждом маршрутизаторе, а значит
контрольную сумму заголовка пришлось бы пересчитывать на каждом хопе заново. Пересчитывать её
ещё и по всей полезной нагрузке на каждом маршрутизаторе было бы избыточно дорого и не нужно:
целостность самих данных уже проверяется отдельно контрольными суммами более высокого уровня
(TCP/UDP-заголовок содержит свою контрольную сумму, покрывающую данные) и трейлером FCS на
канальном уровне. Если контрольная сумма заголовка не сходится, пакет молча отбрасывается —
ошибка ловится счётчиками ошибок интерфейса или отсутствием ожидаемого ответа в tcpdump.
Факты для карточек
- base | Алгоритм контрольной суммы IPv4-заголовка? — сумма в дополнительном коде по 16-битным словам, затем инверсия
- core | Какое значение должна давать сумма при проверке валидности (с учётом поля суммы)? — 0xFFFF
- core | Почему контрольная сумма покрывает только заголовок, а не данные? — заголовок (минимум TTL) меняется на каждом хопе и пересчитывается заново; целостность данных проверяют TCP/UDP-checksum и FCS канального уровня
- deep | Что такое end-around carry в one's complement сложении? — перенос из старшего бита не отбрасывается, а прибавляется обратно к младшему биту суммы
Ловушки
- Считать контрольную сумму по буферу с уже заполненным полем
header_checksumвместо обнулённого → результатcompute_checksumокажется неверным, потому что старое значение поля участвует в сумме. - Включить в сумму данные после заголовка (payload) → сумма не сойдётся ни у отправителя, ни
при проверке — контрольная сумма IPv4 считается строго по
ihl*4байтам, не по всей длине пакета.
Почему дальше: сами IP-адреса в заголовке не существуют сами по себе — узел должен понимать, какая их часть определяет сеть, а какая — конкретный хост. Это маска и подсеть.
11. Маски, подсети и CIDR
Маска подсети делит 32-битный IPv4-адрес на две части: номер сети и номер узла внутри неё —
это определяет, какие адреса «свои» для локальной доставки внутри сегмента, а какие требуют
выхода через шлюз. Запись /N (CIDR, Classless Inter-Domain Routing) — это и есть длина
префикса сети в битах вместо устаревшей классовой адресации (A/B/C), что позволяет выделять
подсети произвольного размера, а не только фиксированных 8/16/24 бит.
Широковещательный адрес подсети — адрес, где все биты хостовой части выставлены в 1; он зарезервирован для рассылки всем узлам сегмента и не выдаётся конкретному устройству. Первый адрес подсети (все хостовые биты — 0) зарезервирован как адрес самой сети.
Число доступных хостов по маске (для обычных подсетей — минус 2 служебных адреса, сеть и broadcast):
| Маска | Хостовых бит | Всего адресов | Доступно хостам |
|---|---|---|---|
| /24 | 8 | 256 | 254 |
| /26 | 6 | 64 | 62 |
| /30 | 2 | 4 | 2 |
| /31 | 1 | 2 | 2 (RFC 3021, оба адреса — хосты, без сети/broadcast) |
| /32 | 0 | 1 | 1 (сеть = broadcast = сам адрес) |
/31 и /32 — исключения из общего правила «минус 2»: /31 (RFC 3021) используется на
линках точка-точка между двумя маршрутизаторами, где резервировать сеть и broadcast из
всего двух адресов расточительно — оба адреса становятся хостовыми; /32 — адрес единственного
узла, маршрут на конкретный хост.
По tasks/13_subnet: для prefix <= 30 — host_count = 2^(32-prefix) - 2, first_host = network + 1, last_host = broadcast - 1. Эталонный пример: 10.0.1.130/26 → сеть
10.0.1.128, broadcast 10.0.1.191, диапазон хостов 129..190. Обратная задача —
prefix_for_hosts(h): найти самую узкую (наибольший prefix) подсеть, вмещающую h
хостов — считается как 32 - ceil(log2(h+2)) за O(1), без перебора. Примеры: 62 → /26,
63 → /25, 254 → /24, 1 → /30 (/31 и /32 в подборе не участвуют — они не для
произвольного числа хостов, а под конкретные сценарии линка и одиночного адреса).
Факты для карточек
- base | Сколько хостов доступно в подсети /24? — 254
- base | Сколько хостов доступно в подсети /26? — 62
- base | Сколько хостов доступно в подсети /30? — 2
- core | Чем /31 отличается от остальных масок по числу служебных адресов? — оба адреса хостовые (RFC 3021), нет отдельного сетевого/broadcast адреса
- core | Что означает запись
/Nв CIDR? — длина префикса сети в битах вместо классовой адресации A/B/C - deep | Формула подбора самой узкой подсети под h хостов за O(1)? —
32 - ceil(log2(h+2))
Ловушки
- Забыть исключить /31 и /32 из общего расчёта
2^(32-prefix) - 2→ для /31 формула даст 0 хостов вместо верных 2, для /32 — отрицательное число. - Спутать адрес сети (все хостовые биты 0) с первым доступным хостом (
network + 1) → off-by-one в диапазоне выдаваемых адресов.
Почему дальше: маска определяет, доставлять ли пакет напрямую внутри сегмента или через устройство более высокого уровня. Логично развести устройства L1/L2/L3 по тому, что каждое из них реально делает с кадром/пакетом.
12. Хаб, коммутатор, маршрутизатор; таблица MAC-адресов (FDB)
Три устройства работают на разных уровнях и с разным объёмом понимания трафика:
- Хаб (L1) — просто повторитель: любой бит, пришедший на один порт, электрически копируется на все остальные порты без какого-либо разбора кадра. Все порты хаба — один общий домен коллизий; трафик одной пары узлов виден всем остальным. Практически вытеснен коммутаторами.
- Коммутатор (L2) — разбирает Ethernet-заголовок и пересылает кадр только на порт, где находится MAC-адрес получателя, а не на все порты сразу. Каждый порт — отдельный домен коллизий, но все порты (без VLAN) остаются одним широковещательным доменом.
- Маршрутизатор (L3) — разбирает IP-заголовок и пересылает пакет между разными подсетями по таблице маршрутов, уменьшая TTL на 1 на каждом пересланном пакете. Разделяет широковещательные домены — broadcast из одной подсети не проходит через маршрутизатор в другую.
Коммутатор знает, на какой порт слать кадр, благодаря таблице MAC-адресов (FDB, Forwarding Database, также называют CAM-таблицей) — по сути хеш-таблице, где ключ — MAC-адрес, значение — номер порта. Заполняется она самообучением: коммутатор смотрит source MAC каждого входящего кадра и запоминает пару (MAC, порт, на который кадр пришёл) — так через обычный трафик таблица заполняется без отдельного протокола объявления адресов. Если адреса получателя нет в таблице (адрес ещё не встречался как источник), коммутатор пересылает кадр на все порты, кроме входного (flooding) — точно так же, как хаб, но только для этого одного кадра, пока адрес не станет известен.
Записи в FDB не хранятся вечно — у каждой запись есть aging: таймер, который сбрасывается при каждом новом кадре с этим source MAC, и если запись не обновлялась дольше таймаута (типичное значение в реализациях — 300 секунд, 5 минут), она удаляется из таблицы. Это нужно, чтобы таблица не разрасталась записями отключённых или перемещённых на другой порт устройств — переключить сетевой кабель с одного порта на другой без aging означало бы, что коммутатор продолжал бы слать кадры на старый, уже неверный порт.
Факты для карточек
- base | На каком уровне работает хаб / коммутатор / маршрутизатор? — L1 / L2 / L3
- base | Что такое FDB коммутатора по структуре данных? — хеш-таблица MAC-адрес → порт
- core | Как коммутатор заполняет FDB без отдельного протокола объявления? — самообучением по source MAC каждого входящего кадра
- core | Что делает коммутатор с кадром, чей MAC получателя не найден в FDB? — рассылает на все порты кроме входного (flooding)
- core | Зачем нужен aging записей FDB? — удалять устаревшие пары MAC-порт, если устройство отключилось или переехало на другой порт
- deep | Что разделяет маршрутизатор, чего не делает коммутатор? — широковещательные домены (домены коллизий разделяет уже коммутатор)
Ловушки
- Ожидать, что коммутатор ограничивает broadcast-трафик → он передаёт broadcast-кадры на все порты одного широковещательного домена так же, как хаб; ограничивает его только маршрутизатор (или разбиение на VLAN).
- Перепутать основание пересылки: коммутатор решает по MAC (L2), маршрутизатор — по IP (L3) → попытка «настроить маршрутизацию на коммутаторе» без функции L3 физически невозможна.
Ссылки на задачи этого дня: tasks/04_ipv4 (разбор IPv4-заголовка и контрольная сумма),
tasks/13_subnet (арифметика подсетей).
Проверь себя
-
Кадр Ethernet с VLAN-тегом занимает 18 байт заголовка вместо 14. Откуда взялись эти лишние 4 байта и что конкретно в них закодировано?
Ответ
VLAN-тег 802.1Q: 2 байта TPID (фиксированное значение 0x8100) + 2 байта TCI, где TCI = PCP (3 бита приоритета) + DEI (1 бит) + VID (12 бит номер VLAN, диапазон 1–4094 реально используемых значений). -
Почему PMTUD зависит от ICMP, и что происходит, если файрвол на пути блокирует ICMP целиком?
Ответ
PMTUD узнаёт об узком месте по ICMP Destination Unreachable с кодом «fragmentation needed and DF set» от промежуточного маршрутизатора; если ICMP заблокирован, отправитель никогда не получит этот сигнал и будет слать пакеты, которые молча теряются на узком месте — классическая причина «маленькие пакеты проходят, большие зависают» через VPN/туннель. -
При проверке контрольной суммы IPv4-заголовка сумма всех 16-битных слов (включая само поле суммы) даёт 0xFFFF. Почему именно это число, а не 0?
Ответ
Поле контрольной суммы — это инверсия суммы остальных слов; сумма числа и его инверсии в дополнительном коде всегда даёт все единицы (0xFFFF), это математическое свойство one's complement, а не произвольный выбор. -
Подсеть
10.0.1.130/26. Назови адрес сети, broadcast и диапазон хостов, не считая заново с нуля — по правилу из этого урока.Ответ
Сеть `10.0.1.128`, broadcast `10.0.1.191`, хосты `10.0.1.129`–`10.0.1.190` (62 адреса, /26 = 64 адреса минус 2 служебных). -
Почему
/31— единственная маска (кроме /32) сhost_count, который не считается по формуле2^(32-prefix) - 2?Ответ
RFC 3021: на линке точка-точка из всего двух адресов резервировать отдельно сеть и broadcast бессмысленно — оба адреса используют как хостовые, поэтому `host_count = 2`, а не `2^1 - 2 = 0`. -
Коммутатор получил кадр с MAC получателя, которого нет в его FDB. Что он сделает и чем это временно похоже на поведение хаба?
Ответ
Разошлёт кадр на все порты, кроме входного (flooding) — как и хаб, который всегда рассылает на все порты; разница в том, что у коммутатора это разовое поведение для конкретного неизвестного адреса, а не постоянный режим работы для всего трафика.
Материалы
- RFC 791, Internet Protocol (IPv4) — https://datatracker.ietf.org/doc/html/rfc791
- RFC 826, An Ethernet Address Resolution Protocol (ARP) — https://datatracker.ietf.org/doc/html/rfc826
- RFC 792, Internet Control Message Protocol (ICMP) — https://datatracker.ietf.org/doc/html/rfc792
- RFC 4632, Classless Inter-domain Routing (CIDR) — https://datatracker.ietf.org/doc/html/rfc4632
- RFC 3021, Using 31-Bit Prefixes on IPv4 Point-to-Point Links — https://datatracker.ietf.org/doc/html/rfc3021
- man7.org,
ip(7)— https://man7.org/linux/man-pages/man7/ip.7.html