Linux Advanced Routing & Traffic Control HOWTO

Перевод: © Иван Песин,
Андрей Киселёв,
LinuxFocus

Bert Hubert, bert.hubert@netherlabs.nl,
Thomas Graf, tgraf@suug.ch,
Gregory Maxwell,
Remco van Mook, remco@virtu.nl,
Martijn van Oosterhout, kleptog@cupid.suninternet.com,
Paul B Schroeder, paulsch@us.ibm.com,
Jasper Spaans, jasper@spaans.ds9a.nl, Pedro Larroy, piotr@member.fsf.org

Оригинальную версию документа вы найдете по адресу lartc.org.

Практическое руководство по применению iproute2 (и в меньшей степени netfilter) для управления трафиком.

Содержание


1. Посвящение.
2. Введение.
2.1. Ограничения и лицензионное соглашение
2.2. Предварительные сведения
2.3. Что может предложить вам Linux
2.4. Дополнительные замечания
2.5. Доступ к CVS и передача обновлений
2.6. Список рассылки
2.7. Структура документа.
3. Введение в iproute2
3.1. Почему iproute2?
3.2. Краткий обзор iproute2
3.3. Необходимые условия
3.4. Текущая конфигурация
3.4.1. Просмотр списка сетевых интерфейсов с помощью утилиты ip
3.4.2. Просмотр списка IP-адресов с помощью утилиты ip
3.4.3. Просмотр списка маршрутов с помощью утилиты ip
3.5. ARP
4. Правила - база политик маршрутизации
4.1. Простая маршрутизация по источнику.
4.2. Маршрутизация через несколько каналов/провайдеров.
4.2.1. Раздельный доступ
4.2.2. Распределение нагрузки.
5. GRE и другие тоннели.
5.1. Несколько общих замечаний о тоннелях:
5.2. Тоннелирование IP в IP.
5.3. GRE тоннели.
5.3.1. Тоннелирование IPv4.
5.3.2. Тоннелирование IPv6.
5.4. Тоннели неядерного уровня.
6. Тоннелирование IPv6 при помощьи Cisco и/или 6bone.
6.1. Тоннелирование IPv6.
7. IPSEC: безопасная передача данных протоколами IP через Интернет
7.1. Пример ручного конфигурирования безопасного соединения между двумя хостами.
7.2. Пример автоматического конфигурирования безопасного соединения между двумя хостами.
7.2.1. Теория.
7.2.2. Пример.
7.2.3. Автоматизация с использованием сертификатов X.509
7.2.4. Как сохранить настройки туннеля в безопасности.
7.3. Туннели IPSEC
7.4. Другое программное обеспечение для работы с IPSEC
7.5. Взаимодействие с другими операционными системами через IPSEC.
7.5.1. Windows.
7.5.2. Check Point VPN-1 NG
8. Маршрутизация групповых сообщений.

9. Дисциплины обработки очередей для управления пропускной способностью
9.1. Понятие очереди и дисциплины обработки
9.2. Простые бесклассовые дисцплины обработки очереди.
9.2.1. pfifo_fast
9.2.2. Token Bucket Filter
9.2.3. Stochastic Fairness Queueing.
9.3. Какие типы дисциплин нужно использовать.
9.4. Терминология
9.5. Классовые дисциплины обработки очередей.
9.5.1. Порядок движения пакетов внутри полноклассовых дисциплин и классов.
9.5.2. Элементы дисциплины: корень, дескриптор, родительские элементы и элементы одного уровня.
9.5.3. Дисциплина PRIO.
9.5.4. Дисциплина CBQ.
9.5.5. Hierarchical Token Bucket
9.6. Классификация пакетов с помощью фильтров.
9.6.1. Ряд простых примеров фильтрации.
9.6.2. Наиболее употребимые способы фильтрации.
9.7. Intermediate queueing device.
9.7.1. Пример конфигурирования.
10. Распределение нагрузки по нескольким интерфейсам.
10.1. Предостережение.
10.2. Другие возможности.
11. Netfilter и iproute -- маркировка пакетов.
12. Расширенная фильтрация.
12.1. Классификатор u32.
12.1.1. Селектор U32.
12.1.2. Селекторы общего назначения.
12.1.3. Селекторы специального назначения.
12.2. Классификатор route.
12.3. Фильтры-ограничители трафика.
12.3.1. Способы ограничения.
12.3.2. Действия в случае превышения ограничения.
12.3.3. Примеры.
12.4. Хеш-фильтры.
12.5. Фильтрация трафика IPv6.
12.5.1. Почему не работают tc-фильтры в IPv6?
12.5.2. Маркировка пакетов IPv6 средствами ip6tables.
12.5.3. Использование селектора u32 для пакетов IPv6.
13. Параметры настройки сети в ядре.
13.1. Reverse Path Filtering.
13.2. Малоизвестные настройки.
13.2.1. Параметры настройки IPv4.
13.2.2. Параметры настройки устройств.
13.2.3. Параметры сетевых политик.
13.2.4. Параметры маршрутизации.
14. Специализированные дисциплины управления очередями.
14.1. bfifo/pfifo
14.1.1. Параметры и порядок использования.
14.2. Алгоритм Кларка-Шенкера-Чанга.
14.3. DSMARK.
14.3.1. Введение.
14.3.2. Что такое Dsmark и с чем его "едят"?
14.3.3. Основные принципы.
14.3.4. Как работать с Dsmark.
14.3.5. Как работает SCH_DSMARK.
14.3.6. Фильтр TC_INDEX.
14.4. Ingress qdisc.
14.4.1. Параметры и порядок использования.
14.5. Random Early Detection (RED)
14.6. Generic Random Early Detection.
14.7. Эмуляция VC/ATM.
14.8. Weighted Round Robin (WRR).
15. Решебник.
15.1. Запуск нескольких сайтов с различными SLA.
15.2. Защита от SYN flood.
15.3. Ограничение пропускной способности для ICMP-пакетов, с целью предотвращения dDoS атак.
15.4. Управление приоритетами для трафика различных типов.
15.5. Прозрачное проксирование с помощью netfilter, iproute2, ipchains и squid.
15.5.1. Схема движения пакетов после настройки.
15.6. Решение проблемы с Path MTU Discovery путем настройки MTU.
15.6.1. Решение
15.7. Решение проблемы с Path MTU Discovery путем настройки MSS.
15.8. Формирователь трафика: Низкая задержка, максимальная производительность.
15.8.1. Почему все так сложно?
15.8.2. Формирователь трафика на базе CBQ.
15.8.3. Формирователь трафика на базе HTB.
15.9. Ограничение скорости для отдельного хоста или подсети.
15.10. Пример подключения локальной сети к Интернет через NAT, с организацией QoS.
15.10.1. Начнем с оптимизации пропускной способности.
15.10.2. Классификация пакетов.
15.10.3. Дополнительная оптимизация
15.10.4. Выполнение настроек во время загрузки системы.
16. Построение мостов и псевдо-мостов с Proxy ARP.
16.1. Бриджинг и iptables.
16.2. Бриджинг и шейпинг.
16.3. Псевдо-мосты с проксированием ARP.
16.3.1. ARP и проксирование ARP
16.3.2. Реализация
17. Динамическая маршрутизация -- OSPF и BGP.
17.1. Настройка OSPF в Zebra
17.1.1. Предварительные условия.
17.1.2. Конфигурирование.
17.1.3. Запуск Zebra
17.2. Настройка BGP4 с помощью Zebra.
17.2.1. Конфигурация сети (пример).
17.2.2. Конфигурирование (пример).
17.2.3. Проверка конфигурации.
18. Прочие возможности.
19. Рекомендуемая литература.
20. Благодарности.

Глава 1. Посвящение

Посвящается большому количеству людей. Перечислим лишь некоторых из них:

  • Rusty Rassel
  • Алексею Н. Кузнецову
  • Отличным ребятам из Google
  • Сотрудникам из Casema Internet

Глава 2. Введение

Добро пожаловать, уважаемый читатель!

Этот документ расскажет вам -- как повысить эффективность управления трафиком в системах, построеных на базе Linux 2.2/2.4. Многие из вас даже не подозревают, что уже работают с инструментальными средствами, которые позволяют делать весьма интересные вещи. Широко известные команды, такие как route и ifconfig - фактически являются довольно тонкой оберткой вокруг очень мощной инфраструктуры iproute2.

Я надеюсь, что это HOWTO станет столь же востребованным как и документация к netfilter от Rusty Rassel.

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

Если вас интересуют лишь простейшие приемы управления трафиком, то прежде, чем вы начнете "блуждать" по этому HOWTO, загляните в главу "Прочие возможности" и прочитайте раздел, посвященный CBQ.init.

2.1. Ограничения и лицензионное соглашение

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

Короче говоря, если ваша магистраль STM-64 была взломана и по ней стала распространяться порнография вашим самым уважаемым клиентам - это не наша вина. Уж простите.

Держателями авторских прав на этот документ являются: Bert Hubert, Gregory Maxwell, Martijn van Oosterhout, Remco van Mook, Paul B. Schroeder и другие. Этот материал может распространяться только на условиях Open Publication License, v1.0 или более поздней (самую последнюю версию текста лицензии вы найдете по адресу www.opencontent.org/openpub/).

Допускается свободное копирование и распространение (в том числе и продажа) этого документа в любом виде. Настоятельно просим о всех, вносимых вами изменениях (а так же ваши комментарии), сообщать руководителю проекта.

Если вы опубликовали твердую копию этого HOWTO, просим вас передать авторам документа несколько экземпляров в "ознакомительных целях" :-)

2.2. Предварительные сведения

Как следует из заголовка - это "Advanced" HOWTO, т.е. рассчитано на подготовленного читателя. Хоть мы и не имеем дело с космической техникой, но некоторая база знаний вам все же потребуется.

Ниже приводится пара ссылок на документы, в которых содержится основная, необходимая вам информация:

Rusty Russell: networking-concepts-HOWTO

Очень хорошее введение. Рассказывает - что такое сети и как они взаимодействуют между собой.

Linux Networking-HOWTO (ранее называлось Net-3 HOWTO)

Отличное руководство, очень подробное. После его прочтения вы самостоятельно сможете подключиться к Internet. Как правило, в большинстве дистрибутивов, располагается в /usr/doc/HOWTO/NET3-4-HOWTO.txt, но так же доступно и в Интернет, по адресу http://www.linuxports.com/howto/networking (русский перевод: http://www.linux.opennet.ru/docs/HOWTO-RU/NET-3-HOWTO.html).

2.3. Что может предложить вам Linux

Вот далеко неполный список из того, что может предложить вам операционная система Linux:

  • Управлять пропускной способностью НА отдельных компьютерах.
  • Управлять пропускной способностью К отдельным компьютерам.
  • Поможет "раздать" пропускную способность по-справедливости.
  • Защитить вашу сеть от DoS-атак.
  • Предотвратить нападения из вашей сети на серверы в Интернет.
  • Распараллелить несколько серверов, с целью равномерного распределения нагрузки.
  • Ограничить доступ к вашим компьютерам.
  • Ограничить доступ ваших пользователей к другим узлам сети.
  • Выполнять маршрутизацию на основе UID (да!), MAC-адресов, исходящих IP-адресов, номеров портов, типа обслуживания, времени суток и содержимого.

На сегодняшний день эти дополнительные возможности не получили широкого распространения. На то есть ряд причин: хотя имеющаяся документация достаточно подробна, она почти не содержит практических рекомендаций. А вопросы управления трафиком вообще не освещены.

2.4. Дополнительные замечания

Есть несколько замечаний, относительно этого документа, которые хотелось бы особо отметить. По большей части этот документ был написан мною, но мне не хотелось бы, чтобы это положение вещей оставалось таким и дальше. Я являюсь убежденным сторонником идей Open Source и потому призываю вас вносить свои изменения, исправления, дополнения и пр. Не стесняйтесь сообщать мне о допущеных ошибках, опечатках или устаревшей информации. Если мой английский кажется вам несколько корявым - не забывайте, что я не являюсь носителем этого языка. Не бойтесь присылать мне ваши замечания и предложения.

Если вы уверены в том, что уровень вашей квалификации позволяет вам оказать поддержку тому или иному разделу документа или вы в состоянии написать и поддерживать новые разделы - добро пожаловать! Это HOWTO доступно через CVS, в формате SGML. Я буду только рад, если число соавторов увеличится.

В поиске слабо освещенных тем вам помогут примечания "FIXME". Желаете внести исправления - всегда пожалуйста! Везде, где вы встретите слово "FIXME", знайте, что вы вступаете на неизведанную территорию. Я не берусь утверждать, что в других местах нет ошибок, но здесь вам следует быть особенно осторожными. Если вы смогли подтвердить правильность того или иного предположения, пожалуйста, сообщите нам, чтобы мы могли удалить примечание "FIXME".

2.5. Доступ к CVS и передача обновлений

Канонический адрес этого документа: http://www.ds9a.nl/lartc.

Сейчас у нас открыт анонимный доступ к CVS из любой точки мира. Сделано это с целью предоставить вам возможность всегда иметь самую последнюю версию HOWTO и присылать свои исправления без особых затруднений.

Кроме того, это дает возможность авторам работать с исходным текстом документа независимо друг от друга.
$ export CVSROOT=:pserver:anon@outpost.ds9a.nl:/var/cvsroot
$ cvs login
CVS password: [введите 'cvs' (без кавычек)]
$ cvs co 2.4routing
cvs server: Updating 2.4routing
U 2.4routing/lartc.db

Если вы внесли какие либо изменения, просто дайте команду cvs -z3 diff -uBb, а полученый вывод отправьте по адресу: <howto@ds9a.nl>, это облегчит нам внесение ваших исправлений. Изменения должны вноситься в файл с расширением .db, все остальные файлы генерируются на его основе.

Предоставляемый Makefile, облегчит вам преобразование документа в форматы postscript, dvi, pdf, html и простой текст. Вам может потребоваться установить у себя docbook, docbook-utils, ghostscript и tetex, чтобы иметь возможность преобразования документа во все вышеперечисленные форматы.

Не тратьте ваши силы на файл 2.4routing.sgml -- это устаревшая версия! Свежая версия находится в файле lartc.db.

2.6. Список рассылки

Поток писем к авторам документа увеличивается все больше и больше. Поэтому было решено запустить список рассылки, в котором люди могли бы поговорить друг с другом о проблемах маршрутизации и управлении трафиком. Вы можете подписаться на рассылку по адресу: http://mailman.ds9a.nl/mailman/listinfo/lartc.

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

2.7. Структура документа

В самом начале находятся разделы, представляющие наибольший интерес, но, к сожалению, менее точные и менее полные.

Маршрутизация и фильтрация - суть разные понятия. Фильтрация достаточно хорошо описана в HOWTO от Rusty Rassel, которые вы найдете по адресу http://netfilter.samba.org/unreliable-guides/.

Наше внимание главным образом будет сконцентрировано на связке netfilter - iproute2.

Глава 3. Введение в iproute2

3.1. Почему iproute2?

Большинство дистрибутивов Linux, как и большинство ОС UNIX, в настоящее время используют довольно древние утилиты arp, ifconfig и route. Пока что эти инструменты работают достаточно адекватно, но иногда, на ядрах Linux версии 2.2 и выше, они могут вести себя довольно неожиданно.

Сетевая подсистема, в ядрах 2.2 и выше, была полностью переписана. Новый сетевой код дал увеличение производительности и более высокие эксплуатационные характеристики, что делает Linux еще более привлекательным на рынке операционных систем.

Фактически, реализация сетевой подсистемы в Linux, выполняющая классификацию, маршрутизацию и фильтрацию, оказалась даже более полной, чем в специализированных маршрутизаторах, межсетевых экранах и других устройствах управления трафиком.

По мере появления новых разработок, они "наслаивались" поверх существующих реализаций в существующих операционных системах. Это постоянное наслаивание привело к тому, что код, решающий задачи управления сетевым трафиком, временами проявлял весьма странное поведение.

Эта, заново переписанная, реализация сетевой подсистемы позволила достичь таких характеристик, которые раньше были просто недоступны.

3.2. Краткий обзор iproute2

Linux обладает довольно сложной системой управления пропускной способностью, названной Traffic Control (Управление Трафиком). Она поддерживает различные методы классификации, деления по приоритетам, совместного использования, и ограничения как входящего, так и исходящего трафика.

Мы начнем обсуждение проблемы с краткого обзора iproute2 и ее возможностей.

3.3. Необходимые условия

Вам следует установить необходимый инструментарий - набор утилит командной строки. Этот пакет называется iproute, по крайней мере в Red Hat и Debian. Если в вашем дистрибутиве его нет, то пакет можно скачать по адресу: ftp://ftp.inr.ac.ru/ip-routing/iproute2-2.2.4-now-ss991023.tar.gz.

Можете попробовать взять самую последнюю версию.

Отдельные утилиты пакета требуют, чтобы в ядре были разрешены некоторые опции. Следует отметить, что все дистрибутивы Red Hat, до версии 6.2 включительно, поставляются с ядром, в котором по-умолчанию большинство необходимых опций отключено.

В Red Hat 7.2 такое положение вещей исправлено.

Кроме того, в ядре должна быть включена поддержка netlink, этого требует iproute2.

3.4. Текущая конфигурация

Для вас может оказаться сюрпризом, но iproute2 уже сконфигурирована! Существующие команды ifconfig и route уже используют расширенные системные вызовы, но главным образом с настройками, заданным по-умолчанию.

Утилита ip является основной в пакете. Попробуем с ее помощью исследовать имеющиеся в системе сетевые интерфейсы.

[ahu@home ahu]$ ip link list
1: lo: <LOOPBACK,UP> mtu 3924 qdisc noqueue 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: dummy: <BROADCAST,NOARP> mtu 1500 qdisc noop 
    link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
3: eth0: <BROADCAST,MULTICAST,PROMISC,UP> mtu 1400 qdisc pfifo_fast qlen 100
    link/ether 48:54:e8:2a:47:16 brd ff:ff:ff:ff:ff:ff
4: eth1: <BROADCAST,MULTICAST,PROMISC,UP> mtu 1500 qdisc pfifo_fast qlen 100
    link/ether 00:e0:4c:39:24:78 brd ff:ff:ff:ff:ff:ff
3764: ppp0: <POINTOPOINT,MULTICAST,NOARP,UP> mtu 1492 qdisc pfifo_fast qlen 10
    link/ppp

Здесь приведен результат работы команды ip link list на моем домашнем маршрутизаторе ( с "поднятым" NAT), у вас он может несколько отличаться. Я поясню часть того, что вы видите, но не все, а только то, что нас интересует в данный момент.

Первым в списке находится локальный (loopback) интерфейс. В принципе, при крнфигурировании ядра, можно отключить поддержку этого интерфейса, но я бы не советовал этого делать. Размер максимального блока передачи данных (MTU - Maximum Transfer Unit) для этого интерфейса составляет 3924 октета, и для него отсутствует очередь, поскольку он не соответствует никакому физическому устройству и существует только в "воображении" ядра.

Я пропущу фиктивный (dummy) интерфейс, так как он может отсутствовать на вашем компьютере. Дальше у меня идут два физических сетевых интерфейса, один - со стороны модема, другой - обслуживает мою домашнюю локальную сеть. И наконец последним в списке стоит интерфейс ppp0.

Обратите внимание на отсутствие IP-адресов в листинге. iproute отделяет понятие "интерфейса" от понятия "IP-адреса". При назначении нескольких IP-адресов одному интерфейсу (IP-алиасинг), понятие IP-адреса становится достаточно расплывчатым.

Зато показываются MAC-адреса - аппаратные идентификаторы сетевых интерфейсов.

3.4.2. Просмотр списка IP-адресов с помощью утилиты ip

[ahu@home ahu]$ ip address show        
1: lo: <LOOPBACK,UP> mtu 3924 qdisc noqueue 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 brd 127.255.255.255 scope host lo
2: dummy: <BROADCAST,NOARP> mtu 1500 qdisc noop 
    link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
3: eth0: <BROADCAST,MULTICAST,PROMISC,UP> mtu 1400 qdisc pfifo_fast qlen 100
    link/ether 48:54:e8:2a:47:16 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.1/8 brd 10.255.255.255 scope global eth0
4: eth1: <BROADCAST,MULTICAST,PROMISC,UP> mtu 1500 qdisc pfifo_fast qlen 100
    link/ether 00:e0:4c:39:24:78 brd ff:ff:ff:ff:ff:ff
3764: ppp0: <POINTOPOINT,MULTICAST,NOARP,UP> mtu 1492 qdisc pfifo_fast qlen 10
    link/ppp 
    inet 212.64.94.251 peer 212.64.94.1/32 scope global ppp0

Этот листинг содержит более подробную информацию. Здесь показаны все IP-адреса, и каким интерфейсам они принадлежат. Здесь "inet" соответствует термину "Internet (IPv4)". Существует целый ряд типов сетевых адресов, но нас они пока не интересуют.

Взглянем поближе на интерфейс eth0. Из листинга видно, что ему назначен адрес "inet" - 10.0.0.1/8, где "/8" определяет число бит, соответствующих адресу сети. Таким образом, для адресации хостов в сети у нас остается 32 - 8 = 24 бита, что соответствует адресу сети - 10.0.0.0 и маске сети - 255.0.0.0.

Это говорит о том, что любой хост в этой сети, например 10.250.3.13, будет непосредственно доступен через наш интерфейс с IP-адресом 10.0.0.1.

Для ppp0 применима та же концепция, хотя числа в IP-адресе отличаются. Ему присвоен адрес - 212.64.94.251, без маски сети. Это означает, что он обслуживает соединение типа "точка-точка" (point-to-point), и что каждый адрес, за исключением 212.64.94.251, является удаленным. Но и это еще не все. Для этого интерфейса указывается адрес другого конца соединения - 212.64.94.1. Здесь число "/32" говорит о том, что это конкретный IP-адрес и он не содержит адреса сети.

Очень важно, чтобы вы поняли суть этой концепции. Если у вас возникают какие либо затруднения, обращайтесь к документации, упомянутой в начале этого HOWTO.

Вы наверняка обратили внимание на слово "qdisc". Оно обозначает дисциплину обработки очереди (Queueing Discipline). Позднее мы коснемся этой темы подробнее.

3.4.3. Просмотр списка маршрутов с помощью утилиты ip

Итак, мы теперь знаем, как можно отыскать адреса 10.x.y.z, и как обратиться к адресу 212.64.94.1. Однако этого недостаточно, поскольку нам необходимо иметь возможность общения с внешним миром. Интернет доступен нам через ppp-соединение, которое объявляет, что хост с адресом 212.64.94.1, готов передать наши пакеты во внешний мир и вернуть результаты обратно.

[ahu@home ahu]$ ip route show
212.64.94.1 dev ppp0  proto kernel  scope link  src 212.64.94.251 
10.0.0.0/8 dev eth0  proto kernel  scope link  src 10.0.0.1 
127.0.0.0/8 dev lo  scope link 
default via 212.64.94.1 dev ppp0

Этот листинг достаточно "прозрачен". Первые 3 строки сообщают сведения, которые нами уже обсуждались выше. Последняя строка говорит о том, что внешний мир доступен через 212.64.94.1 - шлюз, заданный по-умолчанию. То что это шлюз, видно благодаря наличию слова "via" (в переводе с англ. - "через"). Этот шлюз (с адресом 212.64.94.1) готов перенаправлять наши пакеты в Интернет и возвращать обратно результаты наших запросов.

Для примера, более "старая" утилита route, дает такой результат на моей машине:

[ahu@home ahu]$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
212.64.94.1     0.0.0.0         255.255.255.255 UH    0      0        0 ppp0
10.0.0.0        0.0.0.0         255.0.0.0       U     0      0        0 eth0
127.0.0.0       0.0.0.0         255.0.0.0       U     0      0        0 lo
0.0.0.0         212.64.94.1     0.0.0.0         UG    0      0        0 ppp0 

3.5. ARP

ARP - Address Resolution Protocol (Протокол Определения Адреса) описан в RFC 826. Он используется для определения ethernet-адреса по IP-адресу. Машины в Интернет более известны под именами, которые преобразуются в IP-адреса, благодаря чему узел сети, скажем с именем foo.com, имеет возможность связаться с другой машиной, например с именем bar.net. Но в ethernet-сетях для адресации используется не IP-адрес, а ethernet-адрес и здесь на сцену выходит протокол ARP.

Рассмотрим простой пример. Предположим, что имеется сеть из нескольких компьютеров. В ней находятся компьютеры foo, с адресом 10.0.0.1 и foo, с адресом 10.0.0.2. Пусть foo хочет послать пакет ICMP Echo Request (ping) компьютеру bar, чтобы проверить - работает ли он, но увы, foo не знает ethernet-адрес компьютера bar. Таким образом, прежде чем ping-ануть bar, foo должен отослать ARP-запрос. Этот запрос очень похож на то, что обычно кричит человек, пытаясь отыскать в толпе своего товарища: "Bar (10.0.0.2)! Ты где?". В результате все машины в сети услышат "крик" foo, но только bar (10.0.0.2) откликнется на него, послав обратно ARP-ответ, который можно трактовать как: "Foo (10.0.0.1)! Я - здесь! Мой адрес 00:60:94:E9:08:12.". После этой "переклички" foo будет знать ethernet-адрес компьютера bar и сможет связаться с ним, пока опять не "забудет" (в кэше ARP) адрес компьютера bar (обычно записи в ARP-кэше удаляются через 15 минут).

Содержимое ARP-кэша можно просмотреть так:

[root@espa041 /home/src/iputils]# ip neigh show
9.3.76.42 dev eth0 lladdr 00:60:08:3f:e9:f9 nud reachable
9.3.76.1 dev eth0 lladdr 00:06:29:21:73:c8 nud reachable

Как видите, мой компьютер espa041 (9.3.76.41) "знает", как найти компьютер espagate (9.3.76.1). А теперь добавим еще один адрес в наш кэш:

[root@espa041 /home/paulsch/.gnome-desktop]# ping -c 1 espa043
PING espa043.austin.ibm.com (9.3.76.43) from 9.3.76.41 : 56(84) bytes of data.
64 bytes from 9.3.76.43: icmp_seq=0 ttl=255 time=0.9 ms

--- espa043.austin.ibm.com ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.9/0.9/0.9 ms

[root@espa041 /home/src/iputils]# ip neigh show
9.3.76.43 dev eth0 lladdr 00:06:29:21:80:20 nud reachable
9.3.76.42 dev eth0 lladdr 00:60:08:3f:e9:f9 nud reachable
9.3.76.1 dev eth0 lladdr 00:06:29:21:73:c8 nud reachable

В результате попытки взаимодействия компьютера espa041 с espa043, ethernet-адрес последнего был добавлен в кэш. По истечении некоторого тайм аута (если между этими двумя компьютерами больше не было передано ни одного пакета), espa041 "забудет" адрес компьютера espa043 и для того чтобы что-то сообщить ему, опять потребуется послать ARP-запрос.

Удалим адрес компьютера espa043 из кэша:

[root@espa041 /home/src/iputils]# ip neigh delete 9.3.76.43 dev eth0
[root@espa041 /home/src/iputils]# ip neigh show
9.3.76.43 dev eth0  nud failed
9.3.76.42 dev eth0 lladdr 00:60:08:3f:e9:f9 nud reachable
9.3.76.1 dev eth0 lladdr 00:06:29:21:73:c8 nud stale 

Теперь espa041 "забыл" адрес компьютера espa043. Если espa041 опять "захочет" что-то сообщить espa043, он будет вынужден вновь послать ARP-запрос. В этом листинге также видно, что в записи для espagate (9.3.76.1), состояние reachable (доступно) изменилось на stale (устарело). Это означает, что ethernet-адрес все еще является допустимым, но он должен быть подтвержден при первой же попытке обмена.


Глава 4. Правила - база политик маршрутизации

Если ваш маршрутизатор обслуживает сложную сеть, то нужно удовлетворять нужды разных людей, обслуживание которых, вероятно, должно отличаться. База политик маршрутизации позволяет реализовать это с помощью набора таблиц маршрутизации.

Если вы хотите использовать эту возможность, убедитесь что ядро собрано с поддержкой "IP: advanced router" и "IP: policy routing".

Когда ядру необходимо выбрать маршрут, оно определяет в соответствии с какой таблицей это нужно делать. По-умолчанию, определены три таблицы. Старая утилита route изменяет таблицы main и local, как и утилита ip (по-умолчанию).

Правила по-умолчанию:

[ahu@home ahu]$ ip rule list
0:	from all lookup local 
32766:	from all lookup main 
32767:	from all lookup default

В этом листинге приведены приоритеты всех правил. Мы видим, что правила применяются ко всем пакетам (from all). Мы уже видели таблицу 'main', она выводится командой ip route ls, но таблицы 'local' и 'default' для нас новые.

Если мы хотим сделать что-то интересное, то нужно задать правила, использующие разные таблицы маршрутизации. Это позволит нам переопределить общесистемную таблицу маршрутизации.

За точной семантикой происходящего в ядре, когда есть несколько подходящих правил, обратитесь к документации ip-cref Алексея Кузнецова.

4.1. Простая маршрутизация по источнику

Давайте опять рассмотрим реальный пример. У меня есть 2 (вообще-то 3, пора бы вернуть их) кабельных модема, подключенных к маршрутизатору Linux с NAT ('masquerading'). Люди с которыми я живу в одном доме, платят мне за использование Internet. Допустим одни из моих соседей ходит только на hotmail и хочет платить меньше. Мне это подходит, но при этом будет использоваться медленный канал.

Быстрое соединение имеет с моей стороны адрес 212.64.94.251, а с другой - 212.64.94.1. Медленное соединение получает динамический адрес, в данном примере это 212.64.78.148, адрес провайдера - 195.96.98.253.

Таблица local:

[ahu@home ahu]$ ip route list table local
broadcast 127.255.255.255 dev lo  proto kernel  scope link  src 127.0.0.1 
local 10.0.0.1 dev eth0  proto kernel  scope host  src 10.0.0.1 
broadcast 10.0.0.0 dev eth0  proto kernel  scope link  src 10.0.0.1 
local 212.64.94.251 dev ppp0  proto kernel  scope host  src 212.64.94.251 
broadcast 10.255.255.255 dev eth0  proto kernel  scope link  src 10.0.0.1 
broadcast 127.0.0.0 dev lo  proto kernel  scope link  src 127.0.0.1 
local 212.64.78.148 dev ppp2  proto kernel  scope host  src 212.64.78.148 
local 127.0.0.1 dev lo  proto kernel  scope host  src 127.0.0.1 
local 127.0.0.0/8 dev lo  proto kernel  scope host  src 127.0.0.1

Много очевидных вещей, но они должны быть где-то указаны. Вот здесь они и заданы. Таблица default - пустая.

Посмотрим теперь на таблицу main :

[ahu@home ahu]$ ip route list table main 
195.96.98.253 dev ppp2  proto kernel  scope link  src 212.64.78.148 
212.64.94.1 dev ppp0  proto kernel  scope link  src 212.64.94.251 
10.0.0.0/8 dev eth0  proto kernel  scope link  src 10.0.0.1 
127.0.0.0/8 dev lo  scope link 
default via 212.64.94.1 dev ppp0

Создадим новое правило для нашего гипотетического соседа, которое будет называться 'John'. Хотя мы можем работать просто с числами, намного проще и понятней если мы определим названия наших таблиц в файле /etc/iproute2/rt_tables.

# echo 200 John >> /etc/iproute2/rt_tables
# ip rule add from 10.0.0.10 table John
# ip rule ls
0:	from all lookup local 
32765:	from 10.0.0.10 lookup John
32766:	from all lookup main 
32767:	from all lookup default

Теперь нам нужно лишь сгенерировать таблицу John и очистить кэш маршрутов:

# ip route add default via 195.96.98.253 dev ppp2 table John
# ip route flush cache

Вот и все. В качестве упражнения вы можете добавить это в скрипт ip-up.

4.2. Маршрутизация через несколько каналов/провайдеров

Ниже представлена обычная конфигурация, когда локальная сеть (или даже одна машина) подключена к Internet через двух провайдеров.

                                                                 ________
                                          +------------+        /
                                          |            |       |
                            +-------------+ Провайдер 1+-------
        __                  |             |            |     /
    ___/  \_         +------+-------+     +------------+    |
  _/        \__      |     if1      |                      /
 /             \     |    Linux     |                      |
| Локальная сеть-----+ маршрутизатор|                      |     Internet
 \_           __/    |              |                      |
   \__     __/       |     if2      |                      \
      \___/          +------+-------+     +------------+    |
                            |             |            |     \
                            +-------------+ Провайдер 2+-------
                                          |            |       |
                                          +------------+        \________

В этом случае обычно возникает два вопроса.

4.2.1. Раздельный доступ

Первый вопрос заключается в том, как организовать маршрутизацию таким образом, чтобы ответы на запросы, приходящие через определенного провайдера, скажем провайдера 1, уходили через того же провайдера.

Давайте определим некоторые переменные. Пусть $IF1 будет именем первого интерфейса (if1 на рисунке), а $IF2 - именем второго. Тогда $IP1 будет IP адресом $IF1, а $IP2 - IP адресом $IF2. Далее, $P1 это IP-адрес шлюза провайдера 1, а $P2 - IP адрес шлюза провайдера 2. Наконец, $P1_NET это IP сеть, к которой принадлежит $P1, а $P2_NET - сеть, к которой принадлежит $P2.

Создадим две дополнительные таблицы маршрутизации, скажем T1 и T2. Добавим их в файл /etc/iproute2/rt_tables. Теперь можно настроить эти таблицы следующими командами:

ip route add $P1_NET dev $IF1 src $IP1 table T1
ip route add default via $P1 table T1
ip route add $P2_NET dev $IF2 src $IP2 table T2
ip route add default via $P2 table T2

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

Теперь нужно настроить главную таблицу маршрутизации. Хорошо бы маршрутизировать пакеты для сетей провайдеров через соответствующие интерфейсы. Обратите внимание на аргумент 'src', который обеспечивает правильный выбор исходного IP-адреса.

ip route add $P1_NET dev $IF1 src $IP1
ip route add $P2_NET dev $IF2 src $IP2

Теперь задаем маршрут по умолчанию:

ip route add default via $P1

Зададим правила маршрутизации. Они будут отвечать за то, какая таблица будет использоваться при маршрутизации. Вы хотите, чтобы пакет с определенным адресом источника маршрутизировался через соответствующий интерфейс:

ip rule add from $IP1 table T1
ip rule add from $IP2 table T2

Этот набор команд обеспечивает маршрутизацию ответов через интерфейс, на котором был получен запрос.

Заметка читателя Рода Роака (Rod Roark): 'если $P0_NET это локальная сеть, а $IF0 - соответствующий ей интерфейс, желательно задать следующие команды:

ip route add $P0_NET     dev $IF0 table T1
ip route add $P2_NET     dev $IF2 table T1
ip route add 127.0.0.0/8 dev lo   table T1
ip route add $P0_NET     dev $IF0 table T2
ip route add $P1_NET     dev $IF1 table T2
ip route add 127.0.0.0/8 dev lo   table T2

Итак, мы рассмотрели очень простой пример. Он будет работать для всех процессов, выполняющихся на маршрутизаторе и для локальной сети, если настроено преобразование адресов (NAT/masquerading). В противном случае, вам будет необходим диапазон IP адресов обоих провайдеров, или выполнять маскирование для одного из провайдеров. В любом случае, вы можете задать правила выбора провайдера для каждого конкретного адреса вашей локальной сети.

4.2.2. Распределение нагрузки

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

Вместо выбора одного из провайдеров в качестве маршрута по-умолчанию, вы настраиваете т.н. многолучевой (multipath) маршрут. В стандартном ядре это обеспечит балансировку нагрузки между двумя провайдерами. Делается это следующим образом (повторюсь, мы основываемся на примере из раздела Раздельный доступ):

ip route add default scope global nexthop via $P1 dev $IF1 weight 1 nexthop via $P2 dev $IF2 weight 1

Результатом команды будет попеременный выбор маршрута по-умолчанию. Вы можете изменить параметр weight, так чтобы один из провайдеров получал большую нагрузку.
Обратите внимание, что балансировка не будет идеальной, так как она основывается на маршрутах, а маршруты кэшируются. Это означает, что маршруты к часто посещаемым сайтам не будут проходить через разных провайдеров.
Если вы действительно интересуетесь этим, вам стоит посмотреть на патчи Юлиана Анастасова (Julian Anastasov), расположеные по адресу http://www.ssi.bg/~ja/#routes. Они могут вам помочь.


Глава 5. GRE и другие тоннели

В ОС Linux поддерживаются 3 типа тоннелей. Это тоннелирование IP в IP, GRE тоннелирование и тоннели не-ядерного уровня (как, например, PPTP).

5.1. Несколько общих замечаний о тоннелях:

Тоннели могут использоваться для очень необычных и интересных вещей. Также они могут усугубить ситуацию, если они сконфигурированы неправильно. Не задавайте маршрут по умолчанию через тоннель, если только вы ТОЧНО не уверены в том, что делаете :-). Далее, тоннелирование увеличивает нагрузку на систему и сеть, потому что добовляются дополнительные IP-заголовки. Обычно, это 20 байт на пакет. Таким образом, если обычный размер пакета (MTU) в сети равен 1500 байтам, то при пересылке по тоннелю, пакет может содержать только 1480 байт. Это не обязательно становится проблемой, но помните о необходимости правильной настройки фрагментации пакетов, если вы соединяете большие сети. Ах да, и конечно самый быстрый способ "прорыть" тоннель - это "рыть" с обоих сторон.

5.2. Тоннелирование IP в IP

Этот тип тоннелирования доступен в Linux уже давно. Для его работы требуются два модуля ядра: ipip.o и new_tunnel.o.

Допустим у вас есть три сети: внутренние сети A и B, и промежуточная сеть C (например, Internet).
Итак, сеть A:

сеть          10.0.1.0
маска         255.255.255.0
маршрутизатор 10.0.1.1
Адрес маршрутизатора в сети С - 172.16.17.18.
сеть B:
сеть          10.0.2.0
маска         255.255.255.0
маршрутизатор 10.0.2.1
Адрес маршрутизатора в сети С - 172.19.20.21.
Мы полагаем, что сеть C передает пакеты от A к B и наоборот.
Такой сетью может служить даже Internet. Теперь, что нам нужно сделать?
Убедитесь, что все необходимые модули загружены:
insmod ipip.o
insmod new_tunnel.o
Теперь на маршрутизаторе сети A выполните:
ifconfig tunl0 10.0.1.1 pointopoint 172.19.20.21
route add -net 10.0.2.0 netmask 255.255.255.0 dev tunl0
А на маршрутизаторе сети B:
ifconfig tunl0 10.0.2.1 pointopoint 172.16.17.18
route add -net 10.0.1.0 netmask 255.255.255.0 dev tunl0
Когда вам нужно будет "разрушить" тоннель, выполните:

ifconfig tunl0 down

Вот и все. Через тоннель IP в IP нельзя передавать широковещательные пакеты или пакеты IPv6. Вы можете только соединить 2 сети IPv4, которые в обычной ситуации не могли бы работать друг с другом. При нынешнем положении вещей, совместимость этого кода доходит до ядер версии 1.3. Насколько я знаю, тоннелирование Linux IP-в-IP не работает с другими операционными системами и маршрутизаторами. Очень простое решение, если оно вам подходит - используйте его, если вам нужно больше - используйте GRE.

5.3. GRE тоннели

GRE это протокол тоннелирования, который был разработан фирмой Cisco. Он может немного больше чем тоннелирование IP-в-IP. Например, вы можете пересылать широковещательную передачу и IPv6 через тоннель GRE.

В ОС Linux вам будет нужен модуль ip_gre.o.

5.3.1. Тоннелирование IPv4

Давайте сначала разберемся с тоннелированием IPv4:

Допустим у вас есть три сети: внутренние сети A и B, и промежуточная сеть C (например, Internet).
Сеть А:
сеть          10.0.1.0
маска         255.255.255.0
маршрутизатор 10.0.1.1
Адрес маршрутизатора в сети С - 172.16.17.18. Назовем эту сеть neta (крайне оригинально)
сеть          10.0.2.0
маска         255.255.255.0
маршрутизатор 10.0.2.1
Адрес маршрутизатора в сети С - 172.19.20.21. Назовем эту сеть netb Мы полагаем, что сеть C передает пакеты от A к B и наоборот. Как и почему - это нас не интересует. На маршрутизаторе сети A, вам необходимо сделать следующее:
ip tunnel add netb mode gre remote 172.19.20.21 local 172.16.17.18 ttl 255
ip link set netb up
ip addr add 10.0.1.1 dev netb
ip route add 10.0.2.0/24 dev netb

Давайте немного обсудим эти команды. В первой строке мы добавляем тоннельное устройство и присваиваем ему имя netb (имея при этом ввиду место, куда мы хотим попасть). Потом мы сообщаем, что хотим использовать протокол GRE (mode gre), удаленный адрес 172.19.20.21 (второй маршрутизатор), и адрес с которого должны отправлятся данные, предназначенные для передачи по этому тоннелю - 172.16.17.18 (это позволяет вашему маршрутизатору иместь несколько IP-адресов в сети C и оставлять возможность выбора конкретного адреса для тоннеля) и, наконец, TTL-поле пакета должно равняться 255 (ttl 255).

Вторая строка переводит устройство в активное состояние.

В третьей строке мы присваиваем созданному интерфейсу born адрес 10.0.1.1. Это нормально для небольших сетей, но когда вы становитель "шахтером" (т.е. создаете МНОГО тоннелей), возможно вам нужно будет выбрать другой диапазон адресов для тоннельных интерфейсов (в этом примере мы могли бы использовать 10.0.3.0).

В четвертой строке определяется маршрут к сети B. Обратите внимание на формат представления сетевой маски. Если вы не знакомы с такой нотацией, краткое пояснение: записываете сетевую маску в двоичной форме и считаете все "единички". Если вы не знаете как это делается, тогда просто запомните, что 255.0.0.0 это /8, 255.255.0.0 - /16, а 255.255.255.0 - /24. Да, а 255.255.254.0 выглядит как /23, если вам интересно.


Но хватит об этом, продолжим настройку маршрутизатора сети B.
ip tunnel add neta mode gre remote 172.16.17.18 local 172.19.20.21 ttl 255
ip link set neta up
ip addr add 10.0.2.1 dev neta
ip route add 10.0.1.0/24 dev neta

Когда захотите уничтожить тоннель - выполните на маршрутизаторе A:

ip link set netb down
ip tunnel del netb

Конечно, вы можете изменить netb на neta и выполить это на маршрутизаторе B.

5.3.2. Тоннелирование IPv6

За кратким описанием адресации IPv6 обратитесь к шеcтой главе: Тоннелирование IPv6 при помощьи Cisco и/или 6bone.

Продолжим с тоннелями.
Предположим у вас есть сеть IPv6 и вы хотите подключить ее к 6bone, или к другу.

Network 3ffe:406:5:1:5:a:2:1/96

Ваш адрес IPv4 это 172.16.17.18, а маршрутизатор 6bone имеет адрес 172.22.23.24.

ip tunnel add sixbone mode sit remote 172.22.23.24 local 172.16.17.18 ttl 255
ip link set sixbone up
ip addr add 3ffe:406:5:1:5:a:2:1/96 dev sixbone
ip route add 3ffe::/15 dev sixbone

Рассмотрим детальнее эти команды. В первой строке мы создали тоннельное устройство с именем sixbone. Тоннелю задан режим sit (что значит тоннелирование IPv6 в IPv4), целевой адрес и адрес источника. TTL установлен в максимальное значение, 255. Далее, мы активируем устройство. После этого задаем наш сетевой адрес и определяем маршрут для 3ffe::/15 (что есть вся сеть 6bone) через тоннель.

Тоннели GRE на сегодняшний день являются самыми предпочтительными. Это стандарт, который широко применяется за пределами сообщества Linux, а потому представляет собой Хороший выбор.

5.4. Тоннели неядерного уровня

Существует буквально масса реализаций тоннелей неядерного уровня. Наиболее известными являются, конечно, PPP и PPTP, но их много больше (некоторые проприетарные, некоторые высокозащищенные, некоторые даже не используют IP) и это определенно выходит за рамки этого документа HOWTO.

       далее