# 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_lengthlen - 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` требует ровно эту схему в двух функциях: ```c++ // сумма в дополнительном коде по 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` (арифметика подсетей).
Проверь себя 1. Кадр Ethernet с VLAN-тегом занимает 18 байт заголовка вместо 14. Откуда взялись эти лишние 4 байта и что конкретно в них закодировано?
ОтветVLAN-тег 802.1Q: 2 байта TPID (фиксированное значение 0x8100) + 2 байта TCI, где TCI = PCP (3 бита приоритета) + DEI (1 бит) + VID (12 бит номер VLAN, диапазон 1–4094 реально используемых значений).
2. Почему PMTUD зависит от ICMP, и что происходит, если файрвол на пути блокирует ICMP целиком?
ОтветPMTUD узнаёт об узком месте по ICMP Destination Unreachable с кодом «fragmentation needed and DF set» от промежуточного маршрутизатора; если ICMP заблокирован, отправитель никогда не получит этот сигнал и будет слать пакеты, которые молча теряются на узком месте — классическая причина «маленькие пакеты проходят, большие зависают» через VPN/туннель.
3. При проверке контрольной суммы IPv4-заголовка сумма всех 16-битных слов (включая само поле суммы) даёт 0xFFFF. Почему именно это число, а не 0?
ОтветПоле контрольной суммы — это инверсия суммы остальных слов; сумма числа и его инверсии в дополнительном коде всегда даёт все единицы (0xFFFF), это математическое свойство one's complement, а не произвольный выбор.
4. Подсеть `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 служебных).
5. Почему `/31` — единственная маска (кроме /32) с `host_count`, который не считается по формуле `2^(32-prefix) - 2`?
ОтветRFC 3021: на линке точка-точка из всего двух адресов резервировать отдельно сеть и broadcast бессмысленно — оба адреса используют как хостовые, поэтому `host_count = 2`, а не `2^1 - 2 = 0`.
6. Коммутатор получил кадр с 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