У вас два аплинка, и ip -6 route show выводит один и тот же следующий переход на обоих: default via fe80::1 dev uplink0 и default via fe80::1 dev uplink1. Это не конфликт дублирующегося адреса, и копирование голого следующего перехода fe80::1 в таблицу политики не сообщает ядру, какой канал вы имели в виду. Настоящий вопрос уже, чем подсказывает симптом: нужен ли второй таблице один канал или оба, и что сохраняет эти маршруты живыми после перезагрузки. Три условия, проверяемые по порядку, решают большую часть.

Один и тот же fe80::1 — это два разных соседа

Адреса, локальные для канала, ограничены одним каналом, поэтому fe80::1 — не один адрес, напечатанный дважды; это два соседа, которые случайно делят суффикс. Индекс зоны — это способ хоста сказать, какой именно он имеет в виду, поэтому fe80::1%uplink0 и fe80::1%uplink1 для ядра разные пункты назначения, и этот суффикс никогда не уходит на удалённый маршрутизатор. RFC 4007 описывает стоящую за этим модель зон, и именно поэтому таблица политики должна нести устройство при каждом локальном следующем переходе.

Генератор конфигурации VPN, который копирует числовой идентификатор зоны с одного хоста в шаблон, обращается с локальным контекстом так, будто он часть адреса, и записанный им файл неверен на каждой машине с другими именами или индексами интерфейсов. Таблица политики и не сливает два канала в один: маршрутизируемый VPN передаёт пакеты между сетями, но не переносит локальную идентичность удалённого соседа Ethernet через туннель, поэтому локальный трафик остаётся на своём канале.

Уберите устройство, и маршрут станет незаписываемым. ip -6 route add default via fe80::1 table 200 не может разрешить шлюз, и iproute2 отвергает это с Error: Nexthop has invalid gateway. ошибкой. Добавьте dev uplink0 и команда удастся, потому что именно устройство привязывает следующий переход к одному из этих двух соседей. Чего устройство сказать не может — правильный ли uplink0 канал для этой таблицы, а маршрут, скопированный с другого хоста, приносит с собой имена интерфейсов того хоста, и настоящие ошибки берутся именно отсюда.

Условие первое: один канал или два в таблице

Начните с того, для чего нужен второй аплинк. Если оба канала несут один и тот же трафик и один из них резервный, альтернативная таблица должна содержать оба шлюза с разными метриками: одни и те же пункты назначения, один предпочтительный путь, один очевидный второй выбор. Если аплинки существуют потому, что разный трафик должен выходить через разных провайдеров, или потому, что это раздельный туннель, в котором часть трафика обходит VPN, а остальное остаётся внутри, эти два канала вовсе не принадлежат одной таблице. Они принадлежат двум таблицам, выбираемым правилом, и правило выбирает таблицу, а не туннель: обходящий трафик помечается до маршрутизации, и именно метка отправляет его во вторую таблицу.

Во втором случае правило решает, когда обращаться к таблице, а маршрут решает, куда пакет пойдёт после этого:

ip -6 rule add fwmark 0x2 table 201
ip -6 route add default via fe80::1 dev uplink1 metric 100 table 201
ip -6 route add 2001:db8:100::/48 dev uplink1 metric 100 table 201
ip -6 route show table 201

Ни один объект не заменяет другой, и таблица только с маршрутом по умолчанию всё равно может не разрешить свой шлюз. Если добавление отвергнуто или маршрут есть, но непригоден, поместите подключённый префикс этого интерфейса в ту же таблицу или отметьте переход как onlink , когда этот префикс маршрутизируется в другом месте. В блоке выше 2001:db8:100::/48 обозначает именно тот подключённый префикс на uplink1, а не произвольный пункт назначения. Правило fwmark лишь потребляет метку, которую должен установить кто-то другой, — правило nftables или iptables на пути пересылки либо SO_MARK в сокете, поэтому скопированный блок без источника метки ничего не сопоставляет.

Условие второе: метрики не обнаруживают мёртвого провайдера

Метрика — это предпочтение среди существующих маршрутов, а не проверка работоспособности. Когда оператор пропадает, ядро удаляет маршруты на этом устройстве, и второй маршрут по умолчанию берёт верх. Когда кабель остаётся включённым, а провайдер за ним умирает, в таблице ничего не меняется: предпочтительный маршрут установлен, сосед доступен на уровне 2, и пакеты уходят в чёрную дыру. Если это различие важно для вашей схемы, отказоустойчивость должна исходить от чего-то, что зондирует путь и удаляет маршрут, — будь то демон маршрутизации или маленький скрипт, удаляющий и заново устанавливающий запись.

Проверьте выбор после построения таблицы и проверьте так, как его увидит ядро. ip -6 route get 2001:db8:100::1 выводит маршрут, который был бы использован, включая устройство и выбранный адрес источника, и он соблюдает правила политики. Адрес источника, принадлежащий не тому аплинку, обычно означает, что правило совпало раньше, чем вы ожидали.

Условие третье: решите, кому принадлежит сохранность

Маршрут, добавленный через ip -6 route add , живёт до перезагрузки или до того, как что-то его сбросит. Маршрут по умолчанию, полученный из объявлений маршрутизатора, несёт время жизни и может быть отозван маршрутизатором, тогда как добавленный вручную по умолчанию никогда не истекает сам. Смешивание обоих в одной таблице — это путь, которым устаревший постоянный маршрут начинает перевешивать свежий объявленный, спустя долгое время после того, как описанный им аплинк перестал существовать.

Выберите одного владельца на таблицу. Если сетевой менеджер или демон маршрутизации уже управляет интерфейсом, опишите маршрут политики там и не трогайте ядро. Если вы делаете это скриптом, сделайте его идемпотентным и сразу напишите снос, потому что он понадобится при первом неудачном изменении:

ip -6 route flush table 201
ip -6 rule del fwmark 0x2 table 201

На маршрутизаторе, который пересылает трафик других хостов, прежде чем винить таблицу, проверьте net.ipv6.conf.all.forwarding . Если пересылка выключена, пакеты, адресованные другой сети, отбрасываются, как бы ни была правильна таблица 201.

Запишите проект, чтобы следующий человек мог его проверить

Инвентарь, который хранит только fe80::1 , выбрасывает поля, которые важны. Записывайте пункт назначения, следующий переход, устройство, таблицу и метрику вместе, а также откуда взялся каждый маршрут: объявленный, созданный менеджером или статический. Когда кто-то позже спросит, действительно ли второй аплинк несёт трафик, эта запись ответит без догадок.

Прежде чем объявить таблицу готовой, подтвердите соседа через ip -6 neigh show dev uplink0 , перечитайте ip -6 rule show на предмет случайностей порядка и проверьте трафиком, соответствующим правилу, а не ping, который берёт маршрут по умолчанию. Затем намеренно отключите один аплинк и посмотрите, на какой маршрут ядро отступит; ответ должен совпасть с записанным.

Похожие статьи