Уважаемые господа,Столкнулся с проблемой, на решение которой расчитывал потратить два часа, а борюсь уже третий день. Хочется узнать Ваше мнение насчет возможности ее решения. Заранее прошу прощения за пространность изложения.
Началось всё с того, что мне (для моих совершенно не относящихся к вопросу задач) понадобилось сделать тестовый стенд, который бы представлял собой одну машину с двумя виртуальными сетевыми интерфейсами, соединенными между собой виртуальным коммутатором или мостом. Для определенности, пусть первый интерфейс имеет адрес 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-адреса ни на одном сетевом интерфейсе нетНи один из этих вариантов мне, естественно, не подошел, а результаты эти, наверное, предсказуемы (и даже тривиальны) для тех, кто знаком с этим вопросом больше, чем я.
В общем, в связи с этим возникает вопрос: возможно ли вообще каким-либо способом реализовать схему, которую я предложил в самом начале? Конечно, нечто похожее можно сделать и с помощью виртуальных машин, однако делать этого мне бы очень не хотелось из-за слабых ресурсов компьютера, да и вообще, работать за двумя машинами вместо одной - это не слишком удобно.
Разницу между маршрутизацией и коммутацией понимаем?
>Разницу между маршрутизацией и коммутацией понимаем?Не понимаю, при чем здесь это. Как раз коммутация прошла без проблем, а за выбор сетевого интерфейса отвечают таблицы маршрутизации.
А Вы разрешили маршрутизацию пакетов между интерфейсами на уровне ядра ?
>А Вы разрешили маршрутизацию пакетов между интерфейсами на уровне ядра ?Да, если Вы про /proc/sys/net/ipv4/ip_forward, то в нем единичка. Никаких дополнительных ограничений на файрволе тоже нет.
>В общем, в связи с этим возникает вопрос: возможно ли вообще каким-либо
>способом реализовать схему, которую я предложил в самом начале?
можно. более того, я вас поздравляю - 90% этого очень нелегкого пути вы уже прошли сами.
я добавлю вам парочку наставлений, и с оными вы легко разберетесь, ибо способный судя по тому, что написали, итак:
постулат 1) запись local может существовать в любой таблице, не только в таблице local. для принятия пакета как "своего" необходимо лишь чтобы именно она оказалась "выбраным маршрутом" для этого пакета (не важно, сколько других записей с таким же dest/mask существует)
постулат 2) анализировать можно не только dest. у вас есть RPDB где можно анализировать и src address, и fwmark если src недостаточно окажется. а тут уже можно дать волю фантазии.------
для lab environment сойдет такое сооружение. но надо помнить, что при опускании/поднятии интерфейсов записи в таблице local появятся снова и вся "весч" сломается. вообще я бы не стал пускать в продакшн любую конфигурацию, для достижения которой пришлось менять/удалять маршруты с "proto kernel".\^P^/