Назад | Перейти на главную страницу

Одинаковый IP-адрес на двух сетевых картах теряется половина трафика

У меня есть машина, подключенная к немного сломанному научному прибору, и я пытаюсь решить проблемы. Связь точка-точка, 2x25G Ethernet, никакие другие устройства не задействованы. Устройство передает данные UDP с одним потоком на интерфейс, и я могу настроить IP-адрес и MAC-адрес назначения, но исходный IP-адрес устройства одинаков для обоих интерфейсов. Используя tcpdump, я вижу, что трафик поступает на правильные интерфейсы с правильным IP-адресом назначения и MAC-адресом для обоих.

Но я могу прослушивать только один из IP-адресов и получать данные, если я слушаю на другом IP-адресе, трафика нет. Ядро явно сбрасывает трафик, и я не знаю, почему и как это отладить.

На машине работает ubuntu 18.04, IP-адреса 10.50.5.1/16 и 10.50.5.129/16, у устройства IP 10.50.1.10. Маршруты:

10.50.0.0/16 dev data0 proto kernel scope link src 10.50.5.1 
10.50.0.0/16 dev data1 proto kernel scope link src 10.50.5.129

Какие-либо предложения?

В netstat я вижу, что пакеты не отбрасываются, так куда они деваются?

Kernel Interface table
Iface      MTU    RX-OK RX-ERR RX-DRP RX-OVR    TX-OK TX-ERR TX-DRP TX-OVR Flg
data0     9600   202320      0      0 0            29      0      0      0 BMRU
data1     9600   203600      0      0 0            31      0      0      0 BMRU

У вас возникают проблемы с маршрутизацией из-за попытки достичь одного и того же пункта назначения с использованием двух разных интерфейсов и маршрутов. По умолчанию маршрутизация выполняется по месту назначения, а не по источнику. По умолчанию Linux, который использует модель слабого хоста (но Ubuntu также устанавливает фильтр обратного пути, см. ниже) выберет тот же интерфейс: тот из равных кандидатов, который появится первым в его списке. Итак, здесь оба исходных IP-адреса 10.50.5.1 и 10.50.5.129 будут использовать data0 чтобы достичь 10.50.1.10, потому что в настоящее время он является первым среди двух равных в записях маршрута.

В противном случае требуется маршрутизация на основе источника (также известная как политика маршрутизации) в Linux: укажите также, что источник используется для определения маршрута к месту назначения.

Также по аналогичным причинам в вашей текущей конфигурации: имея два IP-адреса в одной IP-сети (10.50.0.0/16), Linux будет отвечать на запросы ARP в локальной сети с любого из своих интерфейсов с любым из своих MAC-адресов. В конце концов, если это не так, как в вашей настройке с устройством, использующим постоянные записи ARP вместо выполнения запросов, обычно только один интерфейс получает весь входящий трафик (он может быть даже «неправильным»).

И последняя капля заключается в том, что даже если инструмент отправляет на правильный интерфейс с правильным IP-адресом назначения, Ubuntu по умолчанию должен иметь Строгий обратный путь включен, отбрасывая пакеты, полученные на "неправильном" интерфейсе. Вот почему вам не хватает данных: интерфейс (попробуйте современный ip -statistics link команда) получила их, но стек маршрутизации сбросил их сразу после. Чтобы убедиться в этом, просто спросите стек маршрутизации ядра, что он думает об отправке и получении IP-пакетов:

  • отправка

    # ip route get from 10.50.5.1 10.50.1.10
    10.50.1.10 from 10.50.5.1 dev data0 uid 0 
        cache 
    # ip route get from 10.50.5.129 10.50.1.10
    10.50.1.10 from 10.50.5.129 dev data0 uid 0 
        cache 
    

    Оба будут отправлены с использованием data0, игнорируя data1.

  • получение

    # ip route get from 10.50.1.10 iif data0 10.50.5.1
    local 10.50.5.1 from 10.50.1.10 dev lo table local 
        cache <local> iif data0 
    # ip route get from 10.50.1.10 iif data1 10.50.5.129
    RTNETLINK answers: Invalid cross-device link
    

    Получение на data1 запрещено строгим фильтром обратного пути.

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

Ниже я предлагаю более чистый метод.


Во-первых, чтобы избежать использования настроек ARP (и «ARP флюс» соображений), рассмотрите два интерфейса, как они используются: двухточечные IP-интерфейсы, даже если они используются на канальном уровне Ethernet. Таким образом, нет необходимости использовать целую локальную сеть / 16: достаточно маршрутов точка-точка.

# ip address flush dev data0
# ip address flush dev data1

# ip address add 10.50.5.1 peer 10.50.1.10/32 dev data0
# ip address add 10.50.5.129 peer 10.50.1.10/32 dev data1

Две приведенные выше команды в основном являются ярлыками для ip address add 10.50.5.N/32 dev dataX; ip route add 10.50.1.10/32 dev dataX.

Вы могли бы сохранить свои сетевые настройки / 16 (например: если, наконец, они привыкнут к реальному использованию LAN с фермой оборудования позади), но для этого также потребовалось бы переключить arp_filter=1 на интерфейсах, чтобы оставаться в безопасности.

Чтобы решить проблему маршрутизации на основе источника: используйте правила, указывающие на дополнительные таблицы маршрутизации, которые будут иметь частичную копию некоторых маршрутов из основной таблицы маршрутизации. Я выбираю произвольные значения 1000 и 1001 для этих таблиц маршрутизации (и использую произвольные фиксированные приоритеты правил 10000 10001, даже если они не требуются). Все в таблице 1000 не нужно (потому что она используется по умолчанию), но в любом случае она просто чище.

ip route add table 1000 10.50.1.10/32 dev data0 src 10.50.5.1
ip route add table 1001 10.50.1.10/32 dev data1 src 10.50.5.129

ip rule add pref 10000 from 10.50.5.1 lookup 1000
ip rule add pref 10001 from 10.50.5.129 lookup 1001

Основная таблица по-прежнему будет определять, какой интерфейс используется по умолчанию (возможно, data0): любой инструмент, не привязанный к конкретному IP-адресу, будет использовать его (и, следовательно, 10.50.5.1) по умолчанию, то же самое, если привязка к 10.50.5.1. Но теперь любой инструмент, привязанный к 10.50.5.129, будет правильно использовать двунаправленный трафик. data1.

# ip route get 10.50.1.10
10.50.1.10 dev data0 src 10.50.5.1 uid 0 
    cache 
# ip route get from 10.50.5.1 10.50.1.10
10.50.1.10 from 10.50.5.1 dev data0 table 1000 uid 0 
    cache 
# ip route get from 10.50.5.129 10.50.1.10
10.50.1.10 from 10.50.5.129 dev data1 table 1001 uid 0 
    cache 

а теперь поступают данные о data1 не отбрасывается фильтром обратного пути:

# ip route get from 10.50.1.10 iif data0 10.50.5.1
local 10.50.5.1 from 10.50.1.10 dev lo table local 
    cache <local> iif data0 
# ip route get from 10.50.1.10 iif data1 10.50.5.129
local 10.50.5.129 from 10.50.1.10 dev lo table local 
    cache <local> iif data1 

Примечание:

Дополнительные таблицы маршрутизации заполняются вручную, а не ядром. Если интерфейс отключен (или IP-адрес удален), а затем восстановлен (или IP-адрес добавлен обратно), соответствующая таблица 1000 или 1001 будет очищена и не будет повторно заполнена: ее нужно добавить обратно вручную ( или с помощью инструмента настройки сети, способного это сделать).