Начиная с версии 7.0, во FreeBSD появились множественные таблицы маршрутизации, или Forward Information Base. Возможно, кому-то они кажутся излишеством, однако, с учетом того, что софт-роутеры на FreeBSD во многом превосходят аппаратные а-ля Cisco (для сомневающихся - попробуйте в самую топовую 7600 циску впихнуть 3-4 BGP Full View, чтоб она не загнулась), постройка таких маршрутизаторов не теряет актуальности. Но это все лирика, перейдем к делу. Итак, где могут пригодиться FIB? Исходя из определения, там, где надо часть трафика пускать не по основным каналам, да и вообще, везде, где надо более гибкое управление сетевым трафиком. FreeBSD предлагает для этого мощные и гибкие средства. В частности, это утилита setfib(8). Она проста в лучших традициях Unix Way и вызовается командой
setfib [-F] fib utility [argument ...]
(мне больше нравится просто setfib <номер таблицы маршрутизации> <нужная программа с параметрами>) позволяет запустить нужную программу с той либо другой таблицей маршрутизации. Таким образом, например, мы можем пустить трафик Apache по одному интернет-каналу, а ftp-демон - по другому. Однако, остается вопрос, что делать с транзитным трафиком в случае, если наша FreeBSD-система является маршрутизатором. Тут также все просто: в штатном фаерволе ipfw(8) есть команда setfib.
В моем случае, надо было на маршрутизаторе, отвечающем за взаимодействие с другими провайдерами, направить VOIP-трафик из сети, выделенной VOIP-провайдером на его софт-свитч. В классическом случае для этого надо было бы использовать Policy-Based Routing (PBR), писать правила fwd в фаерволе, однако все решилось просто:
# /usr/sbin/setfib 1 /sbin/route add 10.80.4.6 10.80.4.17 # /sbin/ipfw add 1000 setfib 1 ip from 10.80.16.0/22 to 10.80.4.17
где 10.80.4.17 - голосовой шлюз VOIP-провайдера, а 10.80.16.0/22 - сеть, выделенная им для предоставления IP-телефонии нашим клиентам. Аналогично решается задача классического PBR - для одного провайдера воздаем одну таблицу маршрутизации, для другого - другую, потом нужным пакетом указываем, по которой из них идти.
Теперь нюансы. Для того, чтобы включить поддержку множественных таблиц маршрутизации, в ядро надо добавить опцию
options ROUTETABLES=2
где 2 - желаемое количество таблиц маршрутизации. Если используется несколько таблиц, для носновной таблицы (номер 0) необходимо задать default route, иначе пакеты побегут по default route из других таблиц.