Перейти до вмісту

Маршрутизація в одному вузлі

Ви ставите Linux-машину між двома мережами, вмикаєте на ній усе, що треба, і хости по обидва боки бачать її, але не бачать одне одного. Або сервер має два мережевих підключення, і відповіді на запити, що прийшли через друге, чомусь вертаються через перше й губляться. Або ping відповідає з одного інтерфейсу й мовчить з іншого. Усі ці історії розв’язуються однаково: подивитися, яке рішення про маршрут ухвалило ядро, і зрозуміти чому.

Маршрутизація в мережевому курсі має два масштаби. Цей модуль про один вузол: що він робить із кожним пакетом, коли той надходить чи виходить. Як маршрути потрапляють у таблицю від сусідніх маршрутизаторів, розглядає модуль 8.

Передумови. Префікси й підмережі, TTL, ICMP — модуль 6. Таблиця сусідів і ARP — модуль 5. Простори імен мережі — модуль 17 курсу «Операційні системи».

Рішення про наступний стрибок

Section titled “Рішення про наступний стрибок”

Вузол, що має надіслати пакет, відповідає на єдине питання: кому саме передати його далі (наступний стрибок, next hop) і через який інтерфейс. Відповідь на нього дає таблиця маршрутів (routing table): список записів «адреси такого-то префікса досяжні так-то».

Далі все залежить від того, де адресат.

  • Адресат у тій самій мережі, що й один з інтерфейсів, тобто безпосередньо досяжний. Тоді вузол питає ARP про MAC-адресу самого адресата й шле кадр йому напряму.
  • Адресат деінде. Тоді вузол бере MAC-адресу шлюзу (gateway), тобто сусіднього маршрутизатора, а адресу IP у пакеті лишає справжню. Кадр іде до шлюзу, а пакет усередині — до адресата. На наступному вузлі те саме рішення приймається заново.

Шлюз у записі мусить сам бути безпосередньо досяжним, бо його MAC-адресу теж треба дізнатися через ARP, і ядро перевіряє це під час додавання маршруту.

Запис складається з префікса й того, що з ним робити:

10.1.0.0/24 via 10.0.1.1 dev ha proto static metric 100

Тут 10.1.0.0/24 — префікс, via 10.0.1.1 — шлюз (наступний стрибок), dev ha — інтерфейс, metric — «ціна». Якщо via немає, адресат безпосередньо досяжний через dev. Додаткові поля (proto, scope, src) повідомляють, хто додав запис і яку адресу відправника ядро підставить.

Деякі записи з’являються самі. Коли ви призначаєте інтерфейсу адресу 10.0.1.2/24, ядро додає в таблицю маршрут до всієї підмережі:

10.0.1.0/24 dev ha proto kernel scope link src 10.0.1.2

proto kernel означає, що його створило ядро. Без такого запису вузол не знав би, що сусіди з підмережі досяжні напряму.

Шлюз має бути досяжним. Якщо спробувати додати маршрут через адресу, якої немає в жодній підмережі інтерфейсів вузла, ядро відмовить: Error: Nexthop has invalid gateway. Обійти це можна ключем onlink, який каже «вважай, що шлюз у цій ланці, без перевірки», але навмисне користуються цим рідко.

Записи в таблиці накладаються: адреса 198.51.100.7 водночас належить 198.51.100.0/25, 198.51.100.0/24 і 0.0.0.0/0 (типовому маршруту, усьому інтернету). Усі маршрутизатори обирають за одним правилом: за найдовшим префіксом, тобто за найвужчим записом, який містить адресу.

Три маршрути накладаються. Типовий 0.0.0.0/0 охоплює все, 198.51.100.0/24 охоплює останній октет від 0 до 255, 198.51.100.0/25 лише від 0 до 127. Адреса 198.51.100.7 потрапляє в усі три й іде за найвужчим, /25. Адреса 198.51.100.200 потрапляє лише в /24 і типовий, тож іде за /24.0.0.0.0/0 (типовий)через 10.0.1.1198.51.100.0/24через 10.0.3.1198.51.100.0/25через 10.0.1.1.7.2000128255останній октет 198.51.100.x
Три маршрути, що накладаються. Адреса .7 потрапляє в усі три й іде за найвужчим, /25. Адреса .200 потрапляє лише в /24 і типовий, тож іде за /24. Це ті самі маршрути, що в розділі «Як це насправді в Linux».

Вужчий запис точніше описує адресу, широкі створюють «фон». Так можна задати загальне правило й поряд виняток; весь інтернет тримається на типовому маршруті плюс уточненнях. Довжина префікса важливіша за все інше, зокрема й за метрику.

Типовим маршрутом (default route) називають запис 0.0.0.0/0, префікс довжини нуль. Йому підходить будь-яка адреса, тож він програє всім конкретнішим і вступає в дію лише тоді, коли більше нічого не підійшло.

Якщо два записи мають однаковий префікс, за довжиною не розрізнити. Тоді вирішує метрика: менша перемагає. Другий запис — резервний:

203.0.113.0/24 via 10.0.1.1 dev ha metric 100
203.0.113.0/24 via 10.0.3.1 dev hc metric 200

Поки інтерфейс ha живий, пакети йдуть через 10.0.1.1. Якщо він упаде, ядро викине з таблиці всі маршрути через нього, і працюватиме другий запис. Зворотна сторона: коли ha повернеться, маршрути через нього самі не з’являться. Їх мав би повернути той, хто їх додав (мережевий менеджер, демон маршрутизації або ваш скрипт).

Маршрут не обов’язково кудись веде. Спеціальні типи кажуть ядру, що робити з пакетами до цього префікса:

  • blackhole: мовчки відкинути;
  • unreachable: відкинути, а для пересланих пакетів відповісти відправнику ICMP «host unreachable»;
  • prohibit: відкинути, а для пересланих пакетів відповісти ICMP «administratively prohibited».

Ними користуються, щоб не пускати трафік до певної мережі, не завантажуючи файрвол, або щоб пакети не «витікали» за типовим маршрутом. Програма, що відправляє пакети на такі адреси, отримує різні помилки: для blackhole — Invalid argument, для unreachable — No route to host, для prohibit — Permission denied.

Вузол як маршрутизатор

Section titled “Вузол як маршрутизатор”

Звичайний хост відкидає пакети, адресовані не йому. Щоб Linux працював маршрутизатором, треба ввімкнути пересилання:

Terminal window
sysctl -w net.ipv4.ip_forward=1

З вимкненим пересиланням вузол приймає пакет, бачить, що адреса призначення не його, і викидає, записуючи в лічильник IpInAddrErrors. Коли «клієнти бачать маршрутизатор, але не бачать одне одного», найчастіше забули ip_forward.

Далі для пакета, що пересилається, відбувається таке:

  1. Пакет надходить на інтерфейс, ядро перевіряє, чи адреса призначення не належить самому вузлу (шукає в таблиці local). Якщо належить, пакет доставляється локальним процесам і далі не їде.

  2. Інакше ядро шукає маршрут за адресою призначення й обирає найдовший префікс.

  3. TTL зменшується на одиницю. Якщо вийшов нуль, пакет відкидається, а відправнику йде ICMP time exceeded (саме на цьому тримається traceroute).

  4. Якщо розмір більший за MTU вихідного інтерфейсу: фрагментація або ICMP «frag needed» залежно від біта DF (модуль 6).

  5. Ядро знаходить (через ARP, якщо потрібно) MAC-адресу наступного стрибка, будує новий кадр і відправляє.

Зауважте: кадр за цей час замінився цілком, а пакет у звичайному разі зазнав лише двох змін: TTL і контрольна сума заголовка.

Перевірка зворотного шляху

Section titled “Перевірка зворотного шляху”

Пакет надійшов на інтерфейс із певною адресою відправника. Ядро може перевірити, чи справді відповідь на цю адресу пішла б через той самий інтерфейс. Це перевірка зворотного шляху (reverse path filtering, rp_filter). Вона відкидає пакети з підмінених адрес, але ламає асиметричну маршрутизацію, коли запит приходить одним шляхом, а відповідь піде іншим. Значення параметра:

  • 0 — вимкнено;
  • 1 — строго: відповідь мусить піти тим самим інтерфейсом, яким надійшов пакет;
  • 2 — вільно: достатньо, щоб до відправника існував будь-який маршрут.

Діє більше з двох значень: net.ipv4.conf.all.rp_filter та значення самого інтерфейсу. Якщо пакети «зникають» на вузлі з кількома інтерфейсами, першим підозрюйте rp_filter і дивіться лічильник IPReversePathFilter у nstat.

Політика маршрутизації: кілька таблиць

Section titled “Політика маршрутизації: кілька таблиць”

Досі все вирішувала одна таблиця й лише адреса призначення. Але трапляються задачі, де вибір має залежати від чогось іншого. Сервер має два підключення до різних провайдерів. Запит надійшов із адреси першого провайдера, тож відповідь треба відправити через нього, а типовий маршрут веде до другого. Без додаткових засобів відповідь піде не туди, і провайдер її відкине.

Linux розв’язує це політикою маршрутизації. Таблиць маршрутів може бути багато (кожна має номер; main — 254, local — 255, default — 253), а правила (ip rule) вирішують, яку таблицю переглядати. Кожне правило має пріоритет і умову (адреса відправника, призначення, мітка пакета fwmark, вхідний інтерфейс), а також таблицю. Ядро проходить правила за зростанням пріоритету; перша таблиця, що дала маршрут, вирішує.

Вибір маршруту через ip rule. Правила переглядаються за зростанням пріоритету: 0 — таблиця local, 1000 — пакети з адресою відправника 10.0.3.2 у таблицю 100, 32766 — таблиця main, 32767 — таблиця default. Перша таблиця, що дала маршрут, вирішує; інакше перехід до наступного правила.пакет0from alllocalсвої адреси, broadcast1000from 10.0.3.2100свій набір маршрутів32766from allmainзвичайні маршрути32767from alldefaultзазвичай порожнянемає збігу або маршруту: даліпріоритет: 0 → 32767
Типові правила (0, 32766, 32767) і одне додане нами з пріоритетом 1000. Якщо таблиця не має підходящого маршруту, пошук переходить до наступного правила.

Для відповіді через потрібного провайдера кожне його підключення отримує власну таблицю з власним типовим маршрутом, а правило «якщо відправник — моя адреса в цій мережі, дивись у відповідну таблицю» вмикає її. Це маршрутизація за адресою відправника (source-based routing). Не плутайте її зі старою опцією IP source routing, у якій маршрут задавав сам пакет: ту опцію давно всюди вимикають.

ECMP: кілька рівноцінних шляхів

Section titled “ECMP: кілька рівноцінних шляхів”

Інколи до префікса ведуть кілька однаково добрих шляхів. Замість того щоб тримати один у резерві, можна навантажувати їх усі: ECMP (equal-cost multipath). У таблиці такий запис має кілька наступних стрибків із вагами.

Складніше з розподілом пакетів. Якщо розкидати їх по черзі, пакети одного з’єднання потраплять у різні шляхи з різною затримкою й прийдуть у переплутаному порядку, а TCP сприймає це як втрату (модуль 11). Пакети одного потоку мають завжди йти одним шляхом, а різні потоки — різними. Для цього ядро обчислює хеш від полів пакета й обирає за ним наступний стрибок. Які поля брати, задає net.ipv4.fib_multipath_hash_policy: 0 — лише адреси відправника й призначення (усі з’єднання між двома хостами підуть одним шляхом), 1 — ще й порти (різні з’єднання між тими самими хостами розтечуться).

VRF: окремі таблиці для цілих мереж

Section titled “VRF: окремі таблиці для цілих мереж”

VRF (virtual routing and forwarding) дає змогу мати на одному вузлі кілька незалежних екземплярів маршрутизації. Інтерфейси приписують до VRF, і кожна VRF має власну таблицю, так що адреси різних клієнтів можуть збігатися, не заважаючи одна одній. Так роблять провайдери, коли обслуговують клієнтів із перетинними приватними адресами. У Linux VRF зроблено як пристрій, пов’язаний із таблицею, а інтерфейси додаються до нього як підлеглі. Подібної ізоляції добивається й простір імен мережі, який ми вже використовуємо, але VRF легша: процеси лишаються в тому самому просторі, а розділені лише маршрути.

Будуємо: хост h із двома підключеннями, ha до r1 (10.0.1.0/24) і hc до r2 (10.0.3.0/24). Далі r1 і r2 ведуть до вузла x, який має ще адресу 198.51.100.7. Топологію будує цей скрипт (в кінці модуля не забудьте прибрати простори імен):

Terminal window
for n in h r1 r2 x; do sudo ip netns add $n; sudo ip netns exec $n ip link set lo up; done
L() { sudo ip link add $2 type veth peer name $4; sudo ip link set $2 netns $1; sudo ip link set $4 netns $3; }
L h ha r1 rb; L h hc r2 rd; L r1 re x xf; L r2 rg x xi
a() { sudo ip netns exec $1 ip addr add $2 dev $3; sudo ip netns exec $1 ip link set $3 up; }
a h 10.0.1.2/24 ha; a r1 10.0.1.1/24 rb; a h 10.0.3.2/24 hc; a r2 10.0.3.1/24 rd
a r1 10.1.0.1/24 re; a x 10.1.0.2/24 xf; a r2 10.2.0.1/24 rg; a x 10.2.0.2/24 xi
sudo ip netns exec x ip addr add 198.51.100.7/32 dev lo

Без жодних маршрутів на h є лише ті, що створило ядро:

Terminal window
sudo ip netns exec h ip route
10.0.1.0/24 dev ha proto kernel scope link src 10.0.1.2
10.0.3.0/24 dev hc proto kernel scope link src 10.0.3.2

Найдовший префікс наживо

Section titled “Найдовший префікс наживо”

Додамо типовий маршрут і два, що накладаються, а тоді спитаємо ядро, за яким воно піде. Для цього є ip route get: вона нічого не відправляє, а показує рішення.

Terminal window
sudo ip netns exec h ip route add default via 10.0.1.1
sudo ip netns exec h ip route add 198.51.100.0/24 via 10.0.3.1
sudo ip netns exec h ip route add 198.51.100.0/25 via 10.0.1.1
for d in 10.0.1.50 198.51.100.7 198.51.100.200 8.8.8.8; do
sudo ip netns exec h ip route get $d
done
10.0.1.50 dev ha src 10.0.1.2 uid 0
198.51.100.7 via 10.0.1.1 dev ha src 10.0.1.2 uid 0
198.51.100.200 via 10.0.3.1 dev hc src 10.0.3.2 uid 0
8.8.8.8 via 10.0.1.1 dev ha src 10.0.1.2 uid 0

Перший — безпосередньо досяжний (via немає). Другий вибрав /25, а третій, що лежить в іншій половині, лише /24. Останній підійшов тільки під типовий. Зверніть увагу на src: разом з інтерфейсом ядро обирає й адресу відправника, яку підставить у пакет (для hc це 10.0.3.2). Власні адреси вузла живуть в окремій таблиці local (ip route show table local): ip route get 10.0.1.2 відповідає local 10.0.1.2 dev lo.

h уже відправляє все невідоме через r1 (типовий маршрут). Щоб відповіді вузла x могли повернутися, потрібен зворотний маршрут, і тоді перевіримо, що дає ip_forward:

Terminal window
sudo ip netns exec x ip route add 10.0.1.0/24 via 10.1.0.1
Terminal window
sudo ip netns exec h ping -c1 -W1 10.1.0.2
sudo ip netns exec r1 sysctl -w net.ipv4.ip_forward=1
sudo ip netns exec h ping -c1 -W1 10.1.0.2
sudo ip netns exec r1 nstat -az IpInAddrErrors IpForwDatagrams
1 packets transmitted, 0 received, 100% packet loss, time 0ms
net.ipv4.ip_forward = 1
1 packets transmitted, 1 received, 0% packet loss, time 0ms
IpInAddrErrors 1 0.0
IpForwDatagrams 2 0.0

Перший пінг пропав, і IpInAddrErrors на r1 показує, куди: пакет на чужу адресу відкинуто. Після вмикання пересилання лічильник IpForwDatagrams росте (2 — запит і відповідь).

Тепер rp_filter. Для цього досліду r2 теж має пересилати (sudo ip netns exec r2 sysctl -w net.ipv4.ip_forward=1), а x потрібен маршрут до 10.0.3.0/24 через r2 (sudo ip netns exec x ip route add 10.0.3.0/24 via 10.2.0.1). Зробимо відправку несиметричною: на r1 маршрут до 10.0.3.0/24 ведемо не назад через rb, а через x (ip route replace 10.0.3.0/24 via 10.1.0.2 dev re), а h відправляє пінг із адреси 10.0.3.2 через ha:

Terminal window
sudo ip netns exec h ping -c1 -W1 -I 10.0.3.2 10.1.0.2 # rp_filter = 0
sudo ip netns exec r1 sysctl -w net.ipv4.conf.all.rp_filter=1 net.ipv4.conf.rb.rp_filter=1
sudo ip netns exec h ping -c1 -W1 -I 10.0.3.2 10.1.0.2 # строго
sudo ip netns exec r1 nstat -az TcpExtIPReversePathFilter
sudo ip netns exec r1 sysctl -w net.ipv4.conf.all.rp_filter=2 net.ipv4.conf.rb.rp_filter=2
sudo ip netns exec h ping -c1 -W1 -I 10.0.3.2 10.1.0.2 # вільно
1 packets transmitted, 1 received, 0% packet loss, time 0ms
1 packets transmitted, 0 received, 100% packet loss, time 0ms
TcpExtIPReversePathFilter 1 0.0
1 packets transmitted, 1 received, 0% packet loss, time 0ms

Зі строгим режимом пакет відкинуто: відповідь на 10.0.3.2 пішла б не через rb, а з вільним (2) достатньо, що маршрут до відправника існує взагалі. Лічильник IPReversePathFilter каже, що пакет загинув саме тут. У вашій системі може стояти 1 або 2: саме ядро типово ставить 0, але дистрибутиви зазвичай вмикають перевірку через sysctl.d.

Terminal window
sudo ip netns exec h ip route add 203.0.113.0/24 via 10.0.1.1 metric 100
sudo ip netns exec h ip route add 203.0.113.0/24 via 10.0.3.1 metric 200
sudo ip netns exec h ip route get 203.0.113.5
sudo ip netns exec h ip link set ha down
sudo ip netns exec h ip route show 203.0.113.0/24
sudo ip netns exec h ip link set ha up
sudo ip netns exec h ip route show 203.0.113.0/24
203.0.113.5 via 10.0.1.1 dev ha src 10.0.1.2 uid 0
203.0.113.0/24 via 10.0.3.1 dev hc metric 200
203.0.113.0/24 via 10.0.3.1 dev hc metric 200

Поки ha живий, вигравав менший metric 100. Після падіння лишився лише резервний, і після повернення ha запис із метрикою 100 не повернувся. Так само додаються ip route add blackhole 192.0.2.0/24, unreachable … і prohibit ….

Terminal window
sudo ip netns exec h ip route add default via 10.0.3.1 dev hc table 100
sudo ip netns exec h ip rule add from 10.0.3.2 lookup 100 priority 1000
sudo ip netns exec h ip rule show
sudo ip netns exec h ip route get 8.8.8.8 from 10.0.3.2
sudo ip netns exec h ip route get 8.8.8.8 from 10.0.1.2
0: from all lookup local
1000: from 10.0.3.2 lookup 100
32766: from all lookup main
32767: from all lookup default
8.8.8.8 from 10.0.3.2 via 10.0.3.1 dev hc table 100 uid 0
8.8.8.8 from 10.0.1.2 via 10.0.1.1 dev ha uid 0

Без правила обидві адреси пішли б однаково, за типовим маршрутом таблиці main. Рядок table 100 у виводі показує, де знайшовся маршрут. Коли відповіді йдуть «не туди», починайте з ip route get … from ….

Terminal window
sudo ip netns exec h ip route del default
sudo ip netns exec h ip route add default nexthop via 10.0.1.1 dev ha weight 1 nexthop via 10.0.3.1 dev hc weight 1
sudo ip netns exec h ip route show default
for p in 1000 1001 1002; do
sudo ip netns exec h ip route get 8.8.8.8 ipproto tcp sport $p dport 80 | head -1
done
default
nexthop via 10.0.1.1 dev ha weight 1
nexthop via 10.0.3.1 dev hc weight 1
8.8.8.8 via 10.0.3.1 dev hc src 10.0.3.2 uid 0
8.8.8.8 via 10.0.3.1 dev hc src 10.0.3.2 uid 0
8.8.8.8 via 10.0.3.1 dev hc src 10.0.3.2 uid 0

За типовою політикою 0 хеш бере лише адреси, тож усі порти дають один шлях. Зі значенням 1:

Terminal window
sudo ip netns exec h sysctl -w net.ipv4.fib_multipath_hash_policy=1

різні порти розходяться між ha та hc: у цьому запуску порти 1000, 1001, 1003, 1004 пішли через hc, а 1002 і 1005 через ha.

VRF потребує модуля ядра vrf. Якщо ip link add … type vrf відповідає Unknown device type, модуля немає (так буває в контейнерах); на ВМ з ядром дистрибутива він є:

Terminal window
sudo ip link add vrf-red type vrf table 10
sudo ip link set vrf-red up
sudo ip link set dev eth1 master vrf-red
ip route show vrf vrf-red
sudo ip vrf exec vrf-red ping 192.0.2.1

eth1 потрапляє до VRF vrf-red, усі його маршрути тепер у таблиці 10, ip route show vrf vrf-red їх показує, а ip vrf exec запускає команду з прив’язкою до цієї VRF.

Прибрати за собою: sudo ip netns delete h і так само r1, r2, x.

Типові помилки розуміння

Section titled “Типові помилки розуміння”

«Маршрут з меншою метрикою завжди виграє». Метрика порівнюється лише для записів з однаковим префіксом. Запис /25 з метрикою 1000 переможе /24 з метрикою 1: довжина префікса важливіша.

«Пакет до віддаленої мережі адресується шлюзу». Адреса призначення в пакеті лишається адресою кінцевого отримувача, шлюзу адресований лише кадр. Шлюз у записі потрібен, щоб знати, чию MAC-адресу поставити в кадр.

«Якщо ввімкнути ip_forward, вузол стане маршрутизатором». Він лише почне пересилати чужі пакети. Щоб вони дійшли, потрібні маршрути в обох напрямках на всіх вузлах шляху: на сусідах має бути маршрут туди й назад. Часто буває так: маршрут прописали, а зворотного немає, і запити доходять, а відповіді ні.

«Якщо з одного боку ping проходить, маршрут працює в обидва боки». Запит і відповідь обираються незалежно. Вони можуть іти різними шляхами (асиметрія), і rp_filter чи файрвол на одному з них мовчки викине пакет.

«У Linux одна таблиця маршрутів». Їх багато, а ip route без аргументів показує лише main. Інші (ip route show table all, ip rule) легко пропустити, і маршрути, що діють, але не видно, збивають з пантелику.

«ECMP розкидає пакети порівну». Розкидає потоки, а не пакети. Один великий потік на одному шляху не розділиться, і шляхи можуть завантажуватися нерівномірно.

Перевір себе

1. У таблиці є 0.0.0.0/0 via A metric 1, 10.0.0.0/8 via B metric 500 і 10.1.0.0/16 via C metric 900. Куди піде пакет на 10.1.2.3?
2. Два записи для 203.0.113.0/24: метрика 100 через ha і метрика 200 через hc. Інтерфейс ha впав. Що станеться?
3. Linux між двома мережами: обидва хости бачать маршрутизатор, але не одне одного, маршрути на хостах правильні. Що перевірити першим?
4. Сервер має два підключення до різних провайдерів і типовий маршрут до першого. Відповіді на запити, що прийшли через другого провайдера, не доходять. Як це виправити засобами Linux?
5. Чому ECMP обирає шлях за хешем полів потоку, а не по черзі для кожного пакета?
6. Пакет приходить на інтерфейс із адресою відправника 10.0.3.2, але відповідь на неї пішла б іншим інтерфейсом. Що зробить вузол із rp_filter=1 і rp_filter=2?

B2. Linux як маршрутизатор: три підмережі, статичні маршрути й NAT. Тут ви самі прописуєте таблицю маршрутів, вмикаєте ip_forward і перевіряєте результат за допомогою ip route get та traceroute.

B7. Налагодження зламаної мережі: серед несправностей є маршрутна; ip route get і ip rule show — перші інструменти на підозру «пакет іде не туди».

  • Kurose, Ross, Computer Networking: A Top-Down Approach, розділ про мережевий рівень і пересилання
  • Peterson, Davie, Computer Networks: A Systems Approach, розділ про маршрутизацію
  • RFC 1812 (вимоги до IPv4-маршрутизаторів)
  • man 8 ip-route, man 8 ip-rule, man 8 ip-vrf, man 8 nstat
  • Документація ядра Linux: Documentation/networking/ip-sysctl.rst (ip_forward, rp_filter, fib_multipath_hash_policy) і Documentation/networking/vrf.rst