Ethernet і комутація
Навіщо це
Section titled “Навіщо це”Ви підключили другий комп’ютер до тієї ж коробки, що й перший, дали обом адреси з однієї підмережі, і вони одразу бачать один одного. Ніхто не налаштовував, куди йти кадрам. Коробка (комутатор) не має IP-адреси, не читає заголовків IP, а все одно доставляє кадр саме тому, кому він адресований. Потім хтось вмикає в неї ще один кабель між двома її портами, і через хвилину вся мережа офісу лягає, а індикатори на портах блимають без упину.
Обидві ситуації пояснює один рівень: канальний (link layer). Пакети IP
самі кудись поїхати не можуть, їх завжди везе кадр (frame) якоїсь
канальної технології, і найпоширеніша з них — Ethernet. Без цього рівня
незрозуміло, що насправді робить ping у локальній мережі, чому кадр
розміром 1501 байт може не дійти, і навіщо в лабораторних курсу міст
зібрано з простору імен та кількох пар veth.
Передумови. Що таке рівні й інкапсуляція — модуль 1.
Простір імен мережі і пара veth — модуль 17 курсу «Операційні системи».
Шлях кадра від мережевої карти до ядра — модуль 3.
Кадр Ethernet
Section titled “Кадр Ethernet”Ethernet розв’язує просту задачу: багато пристроїв, підключених до спільного середовища, мусять передавати один одному блоки байтів і при цьому розуміти, кому призначений блок. Для цього перед даними ставлять адресу отримувача, адресу відправника й позначку, що лежить усередині.
Поле EtherType каже, що вкладено в кадр, щоб приймач знав, якому
протоколу віддати вміст: 0x0800 — IPv4, 0x86DD — IPv6,
0x0806 — ARP, а 0x8100 означає, що далі йде тег VLAN. Значення
до 1500 у цьому місці в старому форматі IEEE 802.3 означали довжину, тому
EtherType починається з 0x0600, і одне й те ж поле однозначно читається
обома способами.
Наприкінці стоїть FCS (frame check sequence), контрольна сума CRC-32
усього кадру. Мережева карта перераховує її при прийомі й мовчки викидає
кадр, якщо сума не збіглася. Тому tcpdump зазвичай FCS не показує: до
ядра пошкоджені кадри не доходять, а для здорових карта її зрізає.
Преамбула й початковий обмежувач кадру (SFD) слугують для синхронізації
приймача. Вони передаються перед кадром, але кадром не вважаються.
Мінімальний кадр разом із FCS має 64 байти, тобто корисне навантаження не менше 46; коротші дані карта добиває нулями. Верхня межа навантаження без тега — 1500 байтів, і саме це число називається MTU.
MAC-адреса
Section titled “MAC-адреса”На канальному рівні пристрій має адресу завдовжки 48 біт. Її пишуть як шість байтів
у шістнадцятковому вигляді: 5e:4d:22:ee:23:64. Її записують у мережеву
карту виробник, а програмно вона легко змінюється.
- Перші три байти — OUI (organizationally unique identifier), який IEEE видає виробникові. За ним у базах видно, чия це карта.
- Два молодших біти першого байта мають особливе значення. Молодший біт (I/G) відрізняє одиночну адресу (0) від групової (1). Наступний біт (U/L) показує, хто призначив адресу: виробник (0) чи адміністратор або програма (1). Такі адреси називаються локально адміністрованими.
ff:ff:ff:ff:ff:ff— широкомовна адреса: кадр отримають усі пристрої сегмента. Решта групових адрес дозволяють звертатися до підмножини: IPv4-мультикаст мапиться на01:00:5e:…, IPv6 на33:33:….
Перевірити біти можна на будь-якій адресі. Перший байт 5e у двійковому
записі 01011110: молодший біт нульовий, тобто адреса одиночна, а другий
з молодших одиничний, тобто адреса локально адміністрована. Так виглядають
адреси, які Linux випадково генерує для veth. Так само вчиняють телефони, що
підставляють випадкову MAC-адресу під час підключення до Wi-Fi, щоб мережа
не бачила справжню.
Комутатор навчається сам
Section titled “Комутатор навчається сам”Найпростіше об’єднати кілька пристроїв — повторювач (hub), який кожен отриманий сигнал копіює на всі порти. Усі пристрої тоді ділять одне середовище й, коли двоє починають говорити одночасно, кадри псуються. Це колізія, і класичний Ethernet боровся з ними алгоритмом CSMA/CD: слухати канал, не починати, поки він зайнятий, а якщо колізія сталася, почекати випадковий час і повторити. Область, у якій кадри можуть зіткнутися, називається доменом колізій.
Комутатор (switch) усе це прибрав. Кожен порт у нього — окремий канал з окремою
парою проводів на кожен напрямок (повний дуплекс), і колізіям на ньому просто
нізвідки взятися. Формально кожен порт сам є доменом колізій з двома учасниками,
портом і пристроєм за ним, тож термін «домен колізій» у сучасних мережах
здебільшого історичний. Натомість лишилося поняття широкомовного домену: множини
портів, до яких дійде кадр з адресою ff:ff:ff:ff:ff:ff. Комутатор його
не розділяє.
На який порт віддати кадр, комутатору ніхто не налаштовує: він підглядає. Кожен кадр, що надходить на порт, містить адресу відправника, тож комутатор записує в таблицю MAC (у Linux вона називається FDB, forwarding database), що ця адреса знаходиться за цим портом. Для кожного кадра комутатор діє так:
-
Запам’ятати або оновити запис «адреса відправника — порт, звідки прийшов».
-
Якщо адреса призначення групова або широкомовна, розіслати кадр на всі порти, крім того, звідки він прийшов.
-
Якщо адреса призначення є в таблиці, надіслати кадр на потрібний порт (а якщо цей порт і є вхідним, кадр відкинути: адресат на тому боці так само його вже бачив).
-
Якщо адреси немає в таблиці, вчинити як зі широкомовним: розіслати на всі решту портів. Це flooding.
Запис у таблиці не вічний: якщо від адреси давно нічого не надходило, запис старіє й видаляється (в Linux за замовчуванням через 300 секунд). Переставлений на інший порт комп’ютер за кілька секунд знову навчить комутатор, а той, що відключився, з таблиці зникне.
Слабке місце цієї схеми — розмір таблиці. Апаратні комутатори тримають її в обмеженій пам’яті. Якщо засипати комутатор кадрами з тисячами вигаданих адрес відправника, таблиця переповниться, і багато моделей у такому разі починають розсилати кадри на всі порти, як повторювач. Це відома атака MAC flooding, і від неї захищають обмеженням кількості адрес на порту.
Комутатор кадр не змінює: адреси в ньому лишаються тими, що виставив відправник, скільки б комутаторів кадр не пройшов. Новий заголовок Ethernet з’являється лише тоді, коли пакет переходить з мережі в мережу через маршрутизатор (модуль 7).
Петлі й STP
Section titled “Петлі й STP”Між двома комутаторами часто навмисно кладуть два кабелі, для резервування. Широкомовний кадр вийде з першого комутатора обома кабелями, другий комутатор прийме кожну копію і розішле на всі решту портів, зокрема назад другим кабелем. У заголовку Ethernet немає нічого схожого на TTL, тож кадр більше ніколи не помре, а кількість копій зростає лавиною. За секунди канали заповнені, таблиці MAC безперервно перебудовуються, бо та сама адреса приходить то з одного порту, то з іншого. Це широкомовний шторм.
Розв’язок — протокол STP (spanning tree protocol, IEEE 802.1D). Комутатори обмінюються службовими кадрами, обирають один із себе кореневим, а решта вибирає найкоротший шлях до кореня. Надлишкові порти переводяться в стан блокування: канал підключений, але кадрів користувачів не пропускає. Якщо активний кабель відмовить, блокований порт увімкнеться. Пізніша версія RSTP робить це за секунди замість пів хвилини. Сучасні комутатори вміють і її, і кілька інших схем, і всі вони залишають у мережі дерево без циклів.
Розмір кадру й MTU
Section titled “Розмір кадру й MTU”MTU (maximum transmission unit) задає найбільше корисне навантаження, яке інтерфейс візьме в один кадр; для Ethernet це 1500 байтів. Пакет IPv4 разом із заголовком не може бути більшим за 1500, інакше він не влізе (що з ним тоді відбувається, розглядає модуль 6).
Кадри з навантаженням до 9000 байтів називаються jumbo. У них менша
частка службових даних на кожен байт корисних і менше кадрів на секунду,
а значить, менше роботи для обробника переривань. Але вмикати jumbo можна
лише всюди одночасно: усі карти й порти комутаторів широкомовного домену
мають підтримувати однаковий розмір. Комутатор, який не вміє приймати
великі кадри, викине їх мовчки, без жодного повідомлення відправнику.
Нерівний MTU в одному сегменті дає чи не найпідступнішу поломку: дрібні
пакети проходять, великі зникають, а ping і вхід через ssh працюють.
Як це насправді в Linux
Section titled “Як це насправді в Linux”Зберемо той самий комутатор, що на рисунку: три «хости» і міст. Усе в просторах імен, система не постраждає.
sudo ip netns add swfor i in 1 2 3; do sudo ip netns add h$i sudo ip link add p$i type veth peer name q$i sudo ip link set p$i netns h$i sudo ip link set q$i netns sw sudo ip netns exec h$i ip addr add 192.0.2.$i/24 dev p$i sudo ip netns exec h$i ip link set p$i up sudo ip netns exec sw ip link set q$i updonesudo ip netns exec sw ip link add br0 type bridgefor i in 1 2 3; do sudo ip netns exec sw ip link set q$i master br0; donesudo ip netns exec sw ip link set br0 upЦе комутатор: br0 — міст у ядрі, q1…q3 — його порти, а p1…p3 — карти
трьох хостів. Адреси 192.0.2.0/24 зарезервовані для документації, тож
у прикладах ними можна користуватися спокійно. Подивимося на адреси карт:
sudo ip netns exec h1 ip -br link show p1p1@if7 UP 5e:4d:22:ee:23:64 <BROADCAST,MULTICAST,UP,LOWER_UP>Ваші адреси будуть іншими, бо ядро генерує їх випадково. У кожної адреси перший байт закінчується двійковим 10: адреса одиночна й локально адміністрована.
Таблиця MAC свіжого моста порожня, крім службових записів permanent — його
власних адрес. Пінгуємо й дивимося знову:
sudo ip netns exec h1 ping -c1 192.0.2.2sudo ip netns exec sw bridge fdb show br br0 | grep -v permanent5e:4d:22:ee:23:64 dev q1 master br0ae:a4:25:33:0b:d9 dev q2 master br0Міст навчився двох адрес з двох портів: з ARP-запиту (про нього в модулі 5)
і відповіді на нього. Команда bridge -s fdb show додає час, що минув від
останнього кадра з цієї адреси; за налаштованим ageing_time запис зникає.
ip -d link show br0 виводить самі параметри (значення ageing_time 30000
вимірюється в сотих частках секунди, тобто це 300 секунд).
Тепер побачимо flooding. На h3 запускаємо tcpdump -e (-e показує заголовки
Ethernet), а на h1 підкидаємо статичний запис для неіснуючої MAC-адреси, щоб
ARP не знадобився:
sudo ip netns exec h3 tcpdump -l -n -e -i p3 &sudo ip netns exec h1 ip neigh flush allsudo ip netns exec h1 ping -c1 192.0.2.2sudo ip netns exec h1 ip neigh replace 192.0.2.99 lladdr 02:00:00:00:00:99 dev p1 nud permanentsudo ip netns exec h1 ping -c1 -W1 192.0.2.99… 5e:4d:22:ee:23:64 > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: Request who-has 192.0.2.2 tell 192.0.2.1, length 28… 5e:4d:22:ee:23:64 > 02:00:00:00:00:99, ethertype IPv4 (0x0800), length 98: 192.0.2.1 > 192.0.2.99: ICMP echo request, id 1746, seq 1, length 64Перший рядок — широкомовний ARP-запит про 192.0.2.2; він має дійти до
всіх, тож h3 його бачить. Відповідь h2 адресована одному h1, і h3 її не
бачить: міст уже знає, де h1. У другому рядку кадр адресований
02:00:00:00:00:99, якої не існує. Міст не знає, де вона, і розсилає кадр
на всі порти, тож h3 цей кадр бачить, хоч він і не для нього. Якби міст
знав адресу, h3 цього кадра не отримав би.
Перевірити MTU можна за допомогою ping із забороною фрагментації:
sudo ip netns exec h1 ip link set p1 mtu 1400sudo ip netns exec h1 ping -c1 -M do -s 1400 192.0.2.2ping: local error: message too long, mtu=1400Розмір -s — це число байтів даних ICMP, до яких додається 8 байтів заголовка
ICMP і 20 байтів заголовка IPv4. Щоб влізти в MTU 1400, значення має бути
не більшим за 1372; тоді відповідь приходить. Повернути 1500 можна тією ж
командою. Значення 9000 на veth теж приймається, а от фізична мережева карта
погодиться лише на те, що підтримує її драйвер.
Нарешті петля. Створіть другий міст і з’єднайте два мости двома парами veth,
увімкнувши STP на обох (ip link set br0 type bridge stp_state 1). Спочатку
порти проходять стани listening і learning, і через двічі по
forward_delay (у ядра типово 15 секунд, тож близько 30 секунд)
bridge link показує чотири порти, з яких один у стані blocking:
26: l1@if25: … master br0 state forwarding priority 32 cost 228: l3@if27: … master br0 state forwarding priority 32 cost 225: l2@if26: … master br0 state forwarding priority 32 cost 227: l4@if28: … master br0 state blocking priority 32 cost 2Один із чотирьох кінців двох кабелів заблоковано. Без stp_state 1 така
конструкція породжує шторм; запускати це на хості, де ви не готові
його перезавантажити, не варто.
Прибрати за собою: sudo ip netns delete h1 (і так само h2, h3, sw).
Разом з простором імен зникають і їхні інтерфейси.
Типові помилки розуміння
Section titled “Типові помилки розуміння”«Комутатор працює з IP-адресами». Звичайний комутатор рівня 2 не дивиться далі заголовка Ethernet. IP-адреси вивчають маршрутизатори; комутатор навіть не знає, чи всередині IPv4, IPv6 чи щось інше.
«У кадрі стоїть MAC-адреса кінцевого сервера, тож усі пристрої на шляху його бачать». MAC-адреси діють лише в межах одного широкомовного домену. Щойно кадр проходить маршрутизатор, той знімає заголовок Ethernet і будує новий для наступного сегмента, з іншими адресами. Через інтернет MAC-адреса вашого комп’ютера нікуди не доходить.
«Комутатор нічого не розсилає, у нього є таблиця». Розсилає кожного разу, коли адреса призначення невідома або групова. Тому нову адресу видно на всіх портах, поки комутатор її не вивчив.
«Колізії — головна проблема сучасного Ethernet». У мережі з
комутаторами й повним дуплексом колізій немає. Якщо ethtool або лічильники
показують колізії, це ознака невдалого узгодження дуплексу (один кінець
у половинному, другий у повному) або старої апаратури.
«MTU 9000 можна ввімкнути на одному кінці, решта підлаштується». Не підлаштується. Кадр, більший за те, що приймає порт, відкидається без повідомлення, і зв’язок ламається вибірково: малі пакети проходять, великі ні.
«Ethernet сам не дасть кадру ходити колом». У заголовку немає лічильника переходів, тож петля ніколи не закінчується сама. Єдиний захист — STP чи його аналоги, або відсутність надлишкових зв’язків.
Перевір себе
Лабораторна
Section titled “Лабораторна”B1. Міст і VLAN руками будується
з того самого набору команд: два хости, міст, потім VLAN. У ній flooding
і навчання треба побачити в tcpdump на власні очі.
A3. Розбір пакетів із pcap починається з розбору заголовка Ethernet вручну: шість байтів, шість байтів, EtherType. Треба прочитати кадри з файлу й щоразу точно знати, де закінчується один заголовок і починається наступний.
Джерела
Section titled “Джерела”- Kurose, Ross, Computer Networking: A Top-Down Approach, розділ про канальний рівень
- Peterson, Davie, Computer Networks: A Systems Approach, розділ про Ethernet і комутатори
- IEEE 802.3 (Ethernet), IEEE 802.1D (мости й STP), IEEE 802.1Q
man 8 bridge,man 8 ip-link,man 8 ip-netns- Документація ядра Linux:
Documentation/networking/bridge.rst