Динамическая маршрутизация в FreeBSD, BIRD

FreeBSD
Рано или поздно в сети с несколькими маршрутизаторами возникает потребность в динамической маршрутизации. Что такое динамическая маршрутизация, и зачем она нужна — рассказывать не буду, ибо это основы о которых можно почитать и в Интернет, эта тема будет о программном обеспечении для обеспечения динамический маршрутизации.
Одной из самой из известных программ для обеспечения динамической маршрутизации безусловно является знаменитая quagga. cisco-style (фу мля, убогость то какая) интерфейс консоли, поддержка RIP, OSPF, BGP, ISIS,… Да, продукт известен. Но он имеет ряд своих недостатков, например:
— не поддерживает множественные таблицы маршрутизации (пародия вида table — это просто издевательство);
— под столь мной любимой FreeBSD есть ряд серьезных косяков. Например с версии 0.99.16 разломан протокол OSPF. При наличии в системе нескольких таблиц маршрутизации — квага просматривает все, из-за чего возникают неприятные косяки с ее прямым назначением;
— единственный способ из рантайма управлять квагой — это пользоваться ее консолью;
— практически отсутствующее API для разработчиков.
Под Linux она конечно работает получше, но все равно отсутствует поддержка множественных таблиц маршрутизации…

Итак, поговорим мы сегодня о таком проекте, как BIRD.
И сразу же анонс продукта с главной страницы проекта:
What do we support:
- Both IPv4 and IPv6 (use --enable-ipv6 when configuring)
- Multiple routing tables
- BGP
- RIP
- OSPF
- Static routes
- Inter-table protocol
- Command-line interface (using the `birdc' client; to get some help, just press `?')
- Soft reconfiguration -- no online commands for changing the configuration in very limited ways, just edit the configuration file and issue a `configure' command or send SIGHUP and BIRD will start using the new configuration, possibly restarting protocols affected by the configuration changes
Powerful language for route filtering

Недурно — «Multiple routing tables», «Inter-table protocol»?

Сразу лирическое отступление, в FreeBSD множественные таблицы маршрутизации появились с версии 7.1 аж в 2008 году, что очень поздно. Для примера, в Linux они появились аж в 1999 году. К сожалению BIRD не умеет работать с таблицами маршрутизации FreeBSD, в связи с чем пришлось его немного допиливать. Допилилось легко. Код легко читаем и прекрасно рассмотрен API.
Таким образом, мы имеем BIRD с поддержкой множественных таблиц маршрутизации в FreeBSD.

Теперь поговорим немного об такой возможности BIRD как «Inter-table protocol». Что же это такое? В BIRD существует понятие «таблица маршрутизации», нет, это не таблица маршрутизации системы, это внутренняя таблица BIRD в которой хранятся маршруты каким либо способом доставленные в BIRD. А доставить их можно так: статическое объявление маршрутов, импорт из таблицы маршрутизации системы, маршруты приехавшие по OSPF/BFP/RIP/…
Все эти маршруты живут внутри таблицы BIRD, которая и называется «таблицей маршрутизации».
Как можно объявить таблицу? Легко:
table fib0;
table fib2;

Это создаст внутри BIRD две таблицы маршрутизации, «fib0» и «fib2».

Но пустые таблицы нам мало интересны, заполним их статическими маршрутами. Делается это очень легко (это примеры рабочего файла конфигурации):
protocol static {
    table fib0;
    route 10.0.0.0/8 via 10.2.2.1;
    route 193.33.62.0/23 via 10.2.2.1;
    route 91.202.20.0/22 via 10.2.2.1;
    route 93.186.96.0/20 via "ng0";
    route 193.203.60.0/22 via "ng0";
    route 78.132.128.0/17 via "ng0";
    route 213.135.128.0/19 via "ng0";
    route 82.179.144.0/20 via "ng0";
    route 195.19.96.0/19 via "ng0";
}

protocol static {
    table fib2;
    route 0.0.0.0/0 via 192.168.130.2;
}

Как видно, мы населили таблицы определенными маршрутами. Причем видно, что шлюз можно задавать как IP-адрес, а можно и как интерфейс (в случае с «ng0»). Так же ничего не мешает указывать default-маршруты.

Итак, мы заселили наши таблички маршрутами. Резонный вопрос: а как из этих табличек маршруты объединить с тем, что есть в системе? Для этого существует протокол kernel, пример:
protocol kernel {
    table fib0;
    scan time 20;
    import none;
    export all;
    kernel table 0;
}

protocol kernel {
    table fib2;
    scan time 20;
    import none;
    export all;
    kernel table 2;
}

Здесь мы привязываем fib0 к системной таблице маршрутизации 0 (это таблица по умолчанию для FreeBSD) и fib2 к системной таблице 2.
import — говорит, что мы будем импортировать из системной таблицы 0 в fib0 (в данном случае — ничего импортировать не будем), а export — указывает, что мы будем записывать из fib0 в системную таблицу маршрутизации 0 (в этом примере — мы будем записывать весь fib2 в системную таблицу маршрутизации).
Для fib2 все аналогично. Думаю здесь больше вопросов никаких не должно возникнуть.
scan time — как часто мы будем синхронизировать эти таблицы. 20 секунд. Что означает эти 20 секунд? Дело в том, что возможна ситуация когда BIRD не смог получить событие от системы об изменении системной таблицы маршрутизации. Для избежания такой ситуации таблица перечитывается раз в 20 секунд. Да, это можно отключить.

Теперь поговорим о «Inter-table protocol», что это такое, и зачем оно собственно нужно.
Пока мы остановились на том — что к системной таблице маршрутизации 0 привязывается fib0, а к таблице 2 — fib2. А вдруг нам потребуется отдать часть маршрутов из fib0 в fib2? это операция повлечет за собой не только передачу маршрутов из fib0 в fib2, но и как следствие попадание маршрутов из fib0 в системную таблицу маршрутизации 2. Достигается это так же легко, протокол pipe, пример:
protocol pipe {
    table fib2;
    peer table fib0;
    export none;
    import all;
}

Таблица fib2 подключается к fib0, при этом она ничего не экспортирует в fib0, зато импортирует из fib0 все маршруты. Такой вот хитрый протокол.

Но все это было бы скучно и решалось спокойно и без BIRD, если бы не одно «но». Но существует два соседних маршрутизатора, с которыми мы обмениваемся маршрутами :) С соседями мы общаемся с помощью BGP. Пример:
protocol bgp {
    table fib0;
    local as 64602;
    neighbor 192.168.135.2 as 64603;
    export filter rfc1918_reject;
    import filter rfc1918_reject;
}

protocol bgp {
    table fib0;
    local as 64602;
    neighbor 192.168.135.10 as 64604;
    export filter rfc1918_reject;
    import filter rfc1918_reject;
}

Итак, что это значит все? Наша AS имеет номер 64602, соседи 64603 и 64604. На каждого соседа объявляется свой протокол bgp. Каждый из этих протоколов привязан к таблице fib0 — т.е. из все маршруты пришедшие/отправленные по bgp будут записывать/отправляться в/из fib0. Думаю с этим вопросов нет. Итого, у нас таблица fib0 уже содержит как статические маршруты так и bgp.
Так же в параметрах export/import появилось изменение — filter rfc1918_reject. Как пишутся фильтры — рассмотрим ниже, пока скажу — что это фильтр запрещает экспорт/импорт маршрутов из сетей, объявленных в RFC1918 (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16).

Пример фильтра для написанного выше:
# reject rfc1918 filter
filter rfc1918_reject  {
    if net ~ [ 10.0.0.0/8+, 172.16.0.0/12+, 192.168.0.0/16+ ] then reject;
    else accept;
}

Для написания фильтров и функций в BIRD используется свой язык описания. Синтаксис можно посмотреть в официальной документации. В данном случае, если маршрут принадлежит одной из подсетей, объявленных в квадратных скобках — то он будет отвергаться. 10.0.0.0/8+ — означает, что любой маршрут принадлежащий 10.0.0.0/8 и так же субсетям этой сети будет отвергаться.

Ну и теперь приведу полный пример файл конфигурации:
log syslog { debug, trace, info, remote, warning, error, auth, fatal, bug };
log stderr all;

# Override router ID
router id 0.0.0.10;

# Define another routing table
table fib0;
table fib2;

# reject rfc1918 filter
filter rfc1918_reject  {
    if net ~ [ 10.0.0.0/8+, 172.16.0.0/12+, 192.168.0.0/16+ ] then reject;
    else accept;
}

# Turn on global debugging of all protocols
debug protocols all;

protocol kernel {
    table fib0;
    scan time 20;
    import none;
    export all;
    kernel table 0;
}

protocol kernel {
    table fib2;
    scan time 20;
    import none;
    export all;
    kernel table 2;
}

protocol static {
    table fib0;
    route 10.0.0.0/8 via 10.2.2.1;
    route 193.33.62.0/23 via 10.2.2.1;
    route 91.202.20.0/22 via 10.2.2.1;
    route 93.186.96.0/20 via "ng0";
    route 193.203.60.0/22 via "ng0";
    route 78.132.128.0/17 via "ng0";
    route 213.135.128.0/19 via "ng0";
    route 82.179.144.0/20 via "ng0";
    route 195.19.96.0/19 via "ng0";
}

protocol static {
    table fib2;
    route 0.0.0.0/0 via 192.168.130.2;
}

protocol pipe {
    table fib2;
    peer table fib0;
    export none;
    import all;
}

protocol bgp {
    table fib0;
    local as 64602;
    neighbor 192.168.135.6 as 64601;
    export filter rfc1918_reject;
    import filter rfc1918_reject;
}

protocol bgp {
    table fib0;
    local as 64602;
    neighbor 192.168.135.2 as 64603;
    export filter rfc1918_reject;
    import filter rfc1918_reject;
}

protocol bgp {
    table fib0;
    local as 64602;
    neighbor 192.168.135.10 as 64604;
    export filter rfc1918_reject;
    import filter rfc1918_reject;
}

# This pseudo-protocol watches all interface up/down events.
protocol device {
        scan time 10;           # Scan interfaces every 10 seconds
}


Все кусочки были рассмотрены выше, только подытожу — что делает такой конфиг:
1. Создаются две таблицы маршутизации BIRD (fib0 и fib2);
2. Таблицы из п.1 привязываются к системным таблицам маршрутизации 0 и 2 соответственно;
3. Разрешается подкачка маршрутов из fib0 в fib2;
4. Таблица fib0 так же заселяется маршрутами, попавшими по bgp.

В итоге — в двух системных таблицах маршрутизации находятся общие маршруты :)

PS: Ну и на последок — что творится на текущий момент в BIRD:

mira# uname
FreeBSD
mira# birdc show protocols all
BIRD 1.2.5 ready.
name     proto    table    state  since       info
kernel1  Kernel   fib0     up     22:01
  Preference:     10
  Input filter:   REJECT
  Output filter:  ACCEPT
  Routes:         0 imported, 13 exported, 0 preferred
  Route change stats:     received   rejected   filtered    ignored   accepted
    Import updates:              0          0          0          0          0
    Import withdraws:            0          0        ---          0          0
    Export updates:             16          0          0        ---         16
    Export withdraws:            2        ---        ---        ---          2

kernel2  Kernel   fib2     up     22:01
  Preference:     10
  Input filter:   REJECT
  Output filter:  ACCEPT
  Routes:         0 imported, 14 exported, 0 preferred
  Route change stats:     received   rejected   filtered    ignored   accepted
    Import updates:              0          0          0          0          0
    Import withdraws:            0          0        ---          0          0
    Export updates:             17          0          0        ---         17
    Export withdraws:            2        ---        ---        ---          2

static1  Static   fib0     up     22:01
  Preference:     200
  Input filter:   ACCEPT
  Output filter:  REJECT
  Routes:         9 imported, 0 exported, 18 preferred
  Route change stats:     received   rejected   filtered    ignored   accepted
    Import updates:              9          0          0          0          9
    Import withdraws:            0          0        ---          0          0
    Export updates:              0          0          0        ---          0
    Export withdraws:            0        ---        ---        ---          0

static2  Static   fib2     up     22:01
  Preference:     200
  Input filter:   ACCEPT
  Output filter:  REJECT
  Routes:         1 imported, 0 exported, 1 preferred
  Route change stats:     received   rejected   filtered    ignored   accepted
    Import updates:              1          0          0          0          1
    Import withdraws:            0          0        ---          0          0
    Export updates:              0          0          0        ---          0
    Export withdraws:            0        ---        ---        ---          0

pipe1    Pipe     fib2     up     22:01       => fib0
  Preference:     70
  Input filter:   ACCEPT
  Output filter:  REJECT
  Routes:         16 imported, 0 exported
  Route change stats:     received   rejected   filtered    ignored   accepted
    Import updates:             28          0          0          9         19
    Import withdraws:            3          0        ---          0          3
    Export updates:             20         19          1          0          0
    Export withdraws:            3          0        ---          0          0

bgp1     BGP      fib0     up     22:01       Established
  Preference:     100
  Input filter:   rfc1918_reject
  Output filter:  rfc1918_reject
  Routes:         5 imported, 9 exported, 6 preferred
  Route change stats:     received   rejected   filtered    ignored   accepted
    Import updates:              5          0          0          0          5
    Import withdraws:            0          0        ---          0          0
    Export updates:             16          3          1        ---         12
    Export withdraws:            2        ---        ---        ---          3
  BGP state:          Established
    Session:          external AS4
    Neighbor AS:      64601
    Neighbor ID:      192.168.135.6
    Neighbor address: 192.168.135.6
    Nexthop address:  192.168.135.6
    Source address:   192.168.135.5
    Neighbor caps:    refresh AS4
    Hold timer:       102/180
    Keepalive timer:  10/60

bgp2     BGP      fib0     up     22:01       Established
  Preference:     100
  Input filter:   rfc1918_reject
  Output filter:  rfc1918_reject
  Routes:         2 imported, 11 exported, 2 preferred
  Route change stats:     received   rejected   filtered    ignored   accepted
    Import updates:              5          0          0          0          5
    Import withdraws:            3          0        ---          0          3
    Export updates:             16          4          1        ---         11
    Export withdraws:            2        ---        ---        ---          0
  BGP state:          Established
    Session:          external AS4
    Neighbor AS:      64603
    Neighbor ID:      0.0.0.50
    Neighbor address: 192.168.135.2
    Nexthop address:  192.168.135.2
    Source address:   192.168.135.1
    Neighbor caps:    refresh AS4
    Hold timer:       87/180
    Keepalive timer:  45/60

bgp3     BGP      fib0     start  22:01       Idle          BGP Error: Bad BGP identifier
  Preference:     100
  Input filter:   rfc1918_reject
  Output filter:  rfc1918_reject
  Routes:         0 imported, 0 exported, 0 preferred
  Route change stats:     received   rejected   filtered    ignored   accepted
    Import updates:              0          0          0          0          0
    Import withdraws:            0          0        ---          0          0
    Export updates:              0          0          0        ---          0
    Export withdraws:            0        ---        ---        ---          0
  BGP state:          Idle
    Error wait:       43/60
    Last error:       BGP Error: Bad BGP identifier

device1  Device   master   up     22:01
  Preference:     240
  Input filter:   ACCEPT
  Output filter:  REJECT
  Routes:         0 imported, 0 exported, 0 preferred
  Route change stats:     received   rejected   filtered    ignored   accepted
    Import updates:              0          0          0          0          0
    Import withdraws:            0          0        ---          0          0
    Export updates:              0          0          0        ---          0
    Export withdraws:            0        ---        ---        ---          0

1 комментарий

avatar
Чем же тебе cisco стиль не угодил? Очень удобный имхо стиль :)
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.