Уважаемые господа, Столкнулся с проблемой, на решение которой расчитывал потратить два часа, а борюсь уже третий день. Хочется узнать Ваше мнение насчет возможности ее решения. Заранее прошу прощения за пространность изложения.
Началось всё с того, что мне (для моих совершенно не относящихся к вопросу задач) понадобилось сделать тестовый стенд, который бы представлял собой одну машину с двумя виртуальными сетевыми интерфейсами, соединенными между собой виртуальным коммутатором или мостом. Для определенности, пусть первый интерфейс имеет адрес 192.168.0.1, а второй 192.168.0.2. При этом мне бы хотелось, чтобы пакеты, отправляемые на IP-адрес 192.168.0.2 проделывали путь "интерфейс 1 -> виртуальный коммутатор -> интерфейс 2", и, соответственно, наоборот.
задача эта разбилась на две подзадачи:
1. Создать набор виртуальных устройств
2. Решить проблему маршрутизации
С первой задачей я справился довольно быстро, воспользовавшись пакетом vde (http://vde.sourceforge.net). Наверное, можно было бы воспользоваться и bridge-utils (я попробовал и тот, и другой, vde мне показался проще). В итоге вырисовался следующий алгоритм:
В первой консоли (запускаем первый коммутатор и сетевой интерфейс):
# vde_switch -s /tmp/switch1 -tap tap1
Во второй консоли (запускаем второй коммутатор и сетевой интерфейс):
# vde_switch -s /tmp/switch2 -tap tap2
В третьей консоли (uplink):
# dpipe vde_plug /tmp/switch1 = vde_plug /tmp/switch2
Поднял сетевые интерфейсы:
# ifconfig tap1 192.168.0.1 up
# ifconfig tap2 192.168.0.2 up
Проверка показывает, что все выглядит нормально (отправляем пакет "в никуда", на обоих интерфейсах наблюдаем безответные arp-запросы)
# ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
From 192.168.0.1 icmp_seq=1 Destination Host Unreachable
From 192.168.0.1 icmp_seq=2 Destination Host Unreachable
# tcpdump -n -i tap1
10:22:31.616312 arp who-has 192.168.0.3 tell 192.168.0.1
# tcpdump -n -i tap2
10:22:40.967846 arp who-has 192.168.0.3 tell 192.168.0.1
Проблемы начались при настройке маршрутизации:
Первое, что меня удивило - отсутствие на сетевых интерфейсах пакетов, отправляемых на IP-адреса 192.168.0.1 и 192.168.0.2. По моим представлениям, согласно
# route -n | grep 192.168
192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 tap1
192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 tap2
пакет на все адреса подсети 192.168.0.0/24 должен отправляться через tap1. Однако, несмотря на исправно отправляющий и получающий пакеты "ping 192.168.0.1", "tcpdump -n -i tap1" упорно молчал. "ping -I tap1 192.168.0.1" тоже не привел к желаемому результату. Пакеты неожиданно для меня обнаружились на интерфейсе с именем "lo".
Следующей моей попыткой стало явное указание маршрута к 192.168.0.2:
# route add -host 192.168.0.2 dev tap1
Не помогло и это - пакеты продолжали ходить через loopback
Оставалось сделать неутешительный вывод: для ip-адресов, которые указаны в качестве адресов даннрого хоста, система плюет на таблицу маршрутизации и отправляет пакеты через loopback.
Более детальное изучение этого вопроса показало, что для полного понимания того, что происходит, нужно пользоваться не "обрезанным вариантом" route, а более продвинутым "ip route".
Оказалось, что таблиц маршрутизации в linux'е не одна, а несколько, и мешавшие мне записи находились в таблице с именем local.
# ip route show table local | grep 192.168
broadcast 192.168.0.255 dev tap1 proto kernel scope link src 192.168.0.1
broadcast 192.168.0.255 dev tap2 proto kernel scope link src 192.168.0.2
local 192.168.0.1 dev tap1 proto kernel scope host src 192.168.0.1 <--------- вот эти записи все портят?
broadcast 192.168.0.0 dev tap1 proto kernel scope link src 192.168.0.1
broadcast 192.168.0.0 dev tap2 proto kernel scope link src 192.168.0.2
local 192.168.0.2 dev tap2 proto kernel scope host src 192.168.0.2 <--------- вот эти записи все портят?
Тогда я попробовал немного их изменить:
# ip route del local 192.168.0.2 dev tap2 proto kernel scope host src 192.168.0.2
# ip route add unicast 192.168.0.2 dev tap1 via 192.168.0.1
Пакеты на хост 192.168.0.2 стали ходить через tap1. Однако, видимо из-за отсутствия записи local для 192.168.0.2, система этот адрес "не признавала" и не отвечала на запросы. Более того, интерфейс tap2 вообще отказался функционировать, приводя примерно к таким результатам:
# ping -I tap2 192.168.0.3
connect: Invalid argument
Никакие сотрясания бубна из разряда "добавить запись local после записи unicast" и т.п. не помогли.
Итак, пришлось признать следующие факты:
1. Когда в таблице маршрутизации есть запись local, система использует ее и благополучно отправляет все пакеты для локальных ip-адресов через loopback.
2. Когда в таблице маршрутизации нет записи local, система вообще считает, что такого ip-адреса ни на одном сетевом интерфейсе нет
Ни один из этих вариантов мне, естественно, не подошел, а результаты эти, наверное, предсказуемы (и даже тривиальны) для тех, кто знаком с этим вопросом больше, чем я.
В общем, в связи с этим возникает вопрос: возможно ли вообще каким-либо способом реализовать схему, которую я предложил в самом начале? Конечно, нечто похожее можно сделать и с помощью виртуальных машин, однако делать этого мне бы очень не хотелось из-за слабых ресурсов компьютера, да и вообще, работать за двумя машинами вместо одной - это не слишком удобно.