Прозрачное проксирование с помощью netfilter, iproute2, ipchains и squid

Этот раздел написал Рэм Нарул (Ram Narula), из «Internet for Education» (Таиланд).

Прозрачное проксирование — это обычное перенаправление серверу squid трафика, отправляемого на порт 80 (web).

Существует 3 общеизвестных способа такого перенаправления:

Шлюз.
Вы можете настроить шлюз таким образом, что он будет перенапрвлять все пакеты, адресованные на порт 80, сереверу squid

НО

Это увеличит нагрузку на шлюз. Кроме того, некоторые коммерческие роутеры не поддерживают такую возможность.

Layer 4 switch
Свичи выполняют такое перенаправление без особых проблем.

НО

Стоимость этого оборудования очень высока и может быть сопоставима с ценой связки «обычный роутер» + «Linux-сервер»

Использовать кэш-сервер в качестве шлюза.
Вы можете отправить ВЕСЬ трафик через кэш-сервер.

НО

Это довольно рисковано, поскольку squid довольно значительно нагружает CPU, что может привести к снижению производительности сети. Кроме того, squid может «рухнуть» и тогда никто из сети не сможет выйти в Интернет.

Мы предлагаем 4-й вариант:
Linux+NetFilter.
Эта методика предполагает установку меток на пакеты, с портом назначения равным числу 80, и дальнейшая маршрутизация помеченных пакетов, с помощью iproute2, на squid.

|—————-|
| Реализация |
|—————-|

Используемые адреса
10.0.0.1 naret (NetFilter)
10.0.0.2 silom (Squid)
10.0.0.3 donmuang (Router, соединенный с Интернет)
10.0.0.4 kaosarn (некий сервер в сети)
10.0.0.5 RAS
10.0.0.0/24 main network
10.0.0.0/19 total network

|—————|
|Структура сети |
|—————|

Internet
|
donmuang
|
————hub/switch———-
| | | |
naret silom kaosarn RAS etc.

Прежде всего — весь трафик должен идти через naret, для этого на всех компьютерах пропишем его в качестве шлюза по-умолчанию. Исключение составляет silom, для которого шлюз по-умолчанию — donmuang (в противном случае web-трафик зациклится).
(на всех компьютерах в моей сети был прописан шлюз по-умолчанию — 10.0.0.1, который ранее принадлежал donmuang, поэтому я изменил IP-адрес у donmuang на 10.0.0.3, а серверу naret присвоил адрес 10.0.0.1)

Silom
——
-настройка squid и ipchains

Настройте прокси-сервер squid на silom. Убедитесь, что он поддерживает прозрачное проксирование. Обычно прокси-серверу, для приема запросов от пользователей, назначают порт 3128, поэтому весь трафик, отправляемый на порт 80 будет перенаправлен на порт 3128. С помощью ipchains это делают следующие правила:
silom# ipchains -N allow1
silom# ipchains -A allow1 -p TCP -s 10.0.0.0/19 -d 0/0 80 -j REDIRECT 3128
silom# ipchains -I input -j allow1

iptables:
silom# iptables -t nat -A PREROUTING -i eth0 -p tcp —dport 80 -j REDIRECT —to-port 3128

За информацией по настройке сервера squid, обращайтесь на http://squid.nlanr.net/.
Убедитесь, что на этом сервере разрешен форвардинг, и заданный по умолчанию шлюз для него — donmuang (НЕ naret!).

Naret
——
-настройка iptables и iproute2
-запрет ICMP-сообщений о перенаправлении (если необходимо)

Пометить пакеты, с портом назначения 80, числовой меткой 2.

naret# iptables -A PREROUTING -i eth0 -t mangle -p tcp —dport 80 \
-j MARK —set-mark 2

Настроить маршрутизацию так, чтобы помеченные пакеты отправлялись на silom

naret# echo 202 www.out >> /etc/iproute2/rt_tables
naret# ip rule add fwmark 2 table www.out
naret# ip route add default via 10.0.0.2 dev eth0 table www.out
naret# ip route flush cache

Если donmuang и naret находятся в одной подсети, то naret не должен выдавать ICMP-сообщения о перенаправлении. Запрет можно наложить так:
naret# echo 0 > /proc/sys/net/ipv4/conf/all/send_redirects
naret# echo 0 > /proc/sys/net/ipv4/conf/default/send_redirects
naret# echo 0 > /proc/sys/net/ipv4/conf/eth0/send_redirects

На этом настройку можно считать завершенной. Проверим конфигурацию

Для naret:

naret# iptables -t mangle -L
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
MARK tcp — anywhere anywhere tcp dpt:www MARK set 0x2

Chain OUTPUT (policy ACCEPT)
target prot opt source destination

naret# ip rule ls
0: from all lookup local
32765: from all fwmark 2 lookup www.out
32766: from all lookup main
32767: from all lookup default

naret# ip route list table www.out
default via 203.114.224.8 dev eth0

naret# ip route
10.0.0.1 dev eth0 scope link
10.0.0.0/24 dev eth0 proto kernel scope link src 10.0.0.1
127.0.0.0/8 dev lo scope link
default via 10.0.0.3 dev eth0

|——-|
|-КОНЕЦ-|
|——-|

15.5.1. Схема движения пакетов после настройки.

|——————————————|
| Схема движения пакетов |
|——————————————|

ИНТЕРНЕТ
/\
||
\/
———————donmuang————————
/\ /\ ||
|| || ||
|| \/ ||
naret silom ||
*destination port 80 ================>(cache) ||
/\ || ||
|| \/ \/
\\===================================kaosarn, RAS, и пр.

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

Для web/http трафика:

kaosarn http request->naret->silom->donmuang->internet
http replies from Internet->donmuang->silom->kaosarn

Для прочего трафика:
kaosarn outgoing data->naret->donmuang->internet
incoming data from Internet->donmuang->kaosarn

http://docstore.mik.ua/manuals/ru/LARTC/x2540.html

Решение проблемы с Path MTU Discovery путем настройки MTU/MSS

Общеизвестно, что скорость передачи данных возрастает с увеличением размера пакета. Это вполне естественно, ведь для каждого пакета в потоке принимается решение о выборе маршрута. К примеру, файл, размером в 1 мегабайт, будет передан быстрее, если он будет разбит на 700 пакетов (при максимальном размере пакета), а не на 4000.

Однако, не все сегменты Интернет могут передавать пакеты, с максимальной полезной нагрузкой в 1460 байт. Поэтому необходимо найти такой размер, который будет максимально возможным для заданного маршрута.

Процесс поиска такого размера называется ‘Path MTU Discovery’ (Поиск Максимального Размера Пакета для выбранного Пути), где MTU означает ‘Maximum Transfer Unit’ (Максимальный Размер Блока передачи данных).

Когда на маршрутизатор поступает пакет, который не может быть передан по выбранному маршруту целиком (без фрагментации) И у него установлен флаг «Don’t Fragment» (Не фрагментировать), то в ответ отправляется ICMP-сообщение о том, что пакет был сброшен из-за невозможности «протолкнуть» его по выбранному маршруту. Компьютер, выполнивший посылку, начинает последовательно уменьшать размер пакетов до тех пор, пока они не смогут быть переданы по выбранному маршруту.

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

В результате таких действий процесс поиска оптимального размера пакета работает все хуже и хуже, а на некоторых маршрутизаторах вообще не работает, что в свою очередь порождает сеансы TCP/IP с весьма странным поведением, которые «умирают» спустя некоторое время.

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

15.6.1. Решение

Если вы столкнетесь с подобной проблемой, то можно посоветовать отключить ‘Path MTU Discovery’ и установить MTU вручную. Koos van den Hout пишет:

У меня возникла следующая проблема: для арендованного мною канала, работающего через ppp, на скорости 33.6К, я установил величину MTU/MRU, равную 296. Это дает мне достаточно приемлемое время отклика.

Со моей стороны установлен роутер (с маскарадингом), работающий под управлением Linux.

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

После этого возникла масса проблем с авторизацией в irc. В процессе длительных поисков я установил, что само соединение проходит и даже показывается системой как ‘connected’, но я не получал motd от irc (motd — от англ. Message of The Day, которое демонстрируется после успешной авторизации, прим. перев.). Кроме того, помятуя о проблеме, связанной с MTU, я определил, что проблема исчезала только в том случае, когда MTU устанавливался равным 296. А так как серверы irc блокируют весь трафик, который напрямую не связан с их работой, то в числе блокируемых оказался и ICMP.

Мне удалось убедить администратора WEB-сервера в истинных причинах возникновения проблем, но администратор IRC-сервера отказался устранять их.

Таким образом, передо мной встала необходимость уменьшить MTU для внешнего трафика и оставить нормальное значение для локального.

Решение:

ip route add default via 10.0.0.1 mtu 296

(10.0.0.1 — шлюз по-умолчанию, внутренний адрес маршрутизатора с маскарадингом)
Вообще, можно запретить ‘PMTU Discovery’ путем настройки специфических маршрутов. Например, если проблемы наблюдаются только с определенной подсетью, то это должно помочь:

ip route add 195.96.96.0/24 via 10.0.0.1 mtu 1000

Как уже говорилось выше, Path MTU Discovery не работает в Интернет должным образом. Если вам известны факты существования сегментов в вашей сети, где размер MTU ограничен, то вы уже не можете полагаться на безотказную работу Path MTU Discovery.

Однако, помимо MTU, есть еще один способ ограничения размера пакета — это, так называемый MSS (Maximum Segment Size — Максимальный Размер Сегмента). MSS — это поле в заголовке TCP-пакета SYN.

С недавних пор, ядра Linux и некоторые драйверы PPPoE, стали поддерживать такую особенность, как ‘clamp the MSS’ (ограничение размера MSS).

В этом есть свои плюсы и минусы. С одной стороны, устанавливая MSS, вы недвусмысленно извещаете удаленную сторону о том, что размер пакета не должен превышать заданную величину. Причем для этого не требуется передачи ICMP-сообщений.

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

Чтобы иметь возможность манипулировать размером сегмента, у вас должны быть установлены iptables, не ниже 1.2.1a и ядро Linux, не ниже 2.4.3. Основная команда iptables:

# iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

Она рассчитает правильный MSS для вашего соединения. Если вы достаточно уверены в себе и в своих знаниях, можете попробовать нечто подобное:

# iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 128

Это правило устанавливает MSS равным 128. Очень полезно, если вы наблюдаете разрывы при передаче голосовых данных, когда поток небольших пакетов VoIP прерывается «огромными» http-пакетами.

Ограничение скорости для отдельного хоста или подсети

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

Эти три строки сделают все что вам нужно:

tc qdisc add dev $DEV root handle 1: cbq avpkt 1000 bandwidth 10mbit

tc class add dev $DEV parent 1: classid 1:1 cbq rate 512kbit \
allot 1500 prio 5 bounded isolated

tc filter add dev $DEV parent 1: protocol ip prio 16 u32 \
match ip dst 195.96.96.97 flowid 1:1

Первая строка — назначает базовую дисциплину на заданный интерфейс и сообщает ядру, что пропускная способность интерфейса составляет 10 Мбит/сек. Если вы установите неверное значение, то особого вреда не будет, однако, всегда стремитесь устанавливать верные значения, это повысит точность вычислений.

Вторая строка создает класс с полосой пропускания 512 Кбит/сек. Подробное описание CBQ содержит раздел Дисциплины обработки очередей для управления пропускной способностью.

Последняя строка говорит о том, какой трафик должен формироваться классом, определенным выше. Трафик, не подпадающий под заданное в фильтре условие, НЕ ОГРАНИЧИВАЕТСЯ! Более сложные примеры назначения условий (подсети, порт отправителя, порт адресата), вы найдете в разделе Наиболее употребимые способы фильтрации.

Если вы внесли какие-либо изменения в сценарий и желаете перезапустить его — предварительно запустите команду tc qdisc del dev $DEV root, чтобы очистить существующую конфигурацию.

Сценарий может быть немного улучшен, за счет добавления в конец дополнительной строки tc qdisc add dev $DEV parent 1:1 sfq perturb 10. За подробным описанием обращайтесь к разделу Stochastic Fairness Queueing.

Bonding производительность

Задача – протестировать суммарную пропускную полосу получаемую при помощи бондинга (bonding — объединение нескольких физических интерфейсов в один логический, с расширенной по сравнению с любым из составных интерфейсов полосой пропускания) двух гигабитных сетевых интерфейсов.

Тестирование производилось с помощью двух серверов в каждом из которых было по два гигабитных сетевых интерфейса (Broadcom Corporation NetXtreme II BCM5708 Gigabit Ethernet), физически сетевые платы серверов были соединены между собой с помощью двух кросоверных пачкордов.

ОС: CentOS 5.3.

Для начала протестируем максимальную скорость передачи данных по каждому интерфейсу в отдельности при помощи двух утилит iperf и netperf.
iperf показал результаты 949-968 Mbits/sec
netperf показал результаты от 865.64 до 956.35 10^6bits/sec

Теперь настроим bonding на обоих серверах и повторим тесты производительности.

Подгружаем модуль бондинга, для этого в файлы /etc/modprobe.conf на обоих серверах внесем следующие строки:

alias bond0 bonding
options bond0 miimon=100 mode=0

Настройки сетевых интерфейсов на первом сервере.
cat ifcfg-eth0

# Broadcom Corporation NetXtreme II BCM5708 Gigabit Ethernet
DEVICE=eth0
ONBOOT=yes
BOOTPROTO=none
USERCTL=no
MASTER=bond0
SLAVE=yes
HWADDR=00:21:5E:3F:E5:A0

Второй адаптер
cat ifcfg-eth1

# Broadcom Corporation NetXtreme II BCM5708 Gigabit Ethernet
DEVICE=eth1
ONBOOT=yes
BOOTPROTO=none
USERCTL=no
MASTER=bond0
SLAVE=yes
HWADDR=00:21:5E:3F:E5:A2

Настраиваем сетевые параметры интерфейса бондинга
cat ifcfg-bond0

DEVICE=bond0
IPADDR=192.168.10.1
NETMASK=255.255.255.0
NETWORK=192.168.10.0
BROADCAST=192.168.10.255
ONBOOT=yes
BOOTPROTO=none
USERCTL=no

Перезагрузимся, для того, чтобы изменения вступили в силу.

Теперь аналогичным образом настроим сеть на сервере 2, соответственно назначив интерфейсу bond0 ip адрес 192.168.10.2 .

Теперь внимательно посмотрим, что же нам выдаст команда
cat /proc/net/bonding/bond0

Ethernet Channel Bonding Driver: v3.2.4 (January 28, 2008)

Bonding Mode: load balancing (round-robin)
MII Status: up
MII Polling Interval (ms): 100
Up Delay (ms): 0
Down Delay (ms): 0

Slave Interface: eth0
MII Status: up
Link Failure Count: 1
Permanent HW addr: 00:21:5e:3f:eb:7c

Slave Interface: eth1
MII Status: up
Link Failure Count: 1
Permanent HW addr: 00:21:5e:3f:eb:7e

Протестируем производительность с помошью утилиты iperf в один tcp поток.

На первом сервере запускаем iperf -s .
На втором сервере запускаем iperf -c 192.168.10.2

По 10 проходам получаем такие результаты:

Тест 1 1.88 Gbits/sec
Тест 2 1.87 Gbits/sec
Тест 3 1.88 Gbits/sec
Тест 4 1.87 Gbits/sec
Тест 5 1.88 Gbits/sec
Тест 6 1.88 Gbits/sec
Тест 7 1.88 Gbits/sec
Тест 8 1.88 Gbits/sec
Тест 9 1.88 Gbits/sec
Тест 10 1.88 Gbits/sec

Cо стороны первого сервера вывод данных от iperf выглядит так:

Client connecting to 192.168.10.2, TCP port 5001
TCP window size: 16.0 KByte (default)
------------------------------------------------------------
[ 3] local 192.168.10.1 port 39151 connected with 192.168.10.2 port 5001
[ ID] Interval Transfer Bandwidth
[ 3] 0.0-10.0 sec 2.19 GBytes 1.88 Gbits/sec

Протестируем производительность с помошью утилиты iperf в 100 tcp потоков.

На первом сервере запускаем iperf -s .
На втором сервере запускаем iperf -c 192.168.10.2 -P 100

По результатам 10 тестов получаем такие результаты:
iperf на первом и втором сервере после запуска выдавал разные результаты, поэтому я привожу оба результата.

Тест 1 1.83 1.88 Gbits/sec
Тест 2 1.84 1.89 Gbits/sec
Тест 3 1.44 1.88 Gbits/sec
Тест 4 1.85 1.87 Gbits/sec
Тест 5 1.87 1.88 Gbits/sec
Тест 6 1.76 1.88 Gbits/sec
Тест 7 1.84 1.87 Gbits/sec
Тест 8 1.83 1.85 Gbits/sec
Тест 9 1.87 1.89 Gbits/sec
Тест 10 1.83 1.84 Gbits/sec

Тестируем производительность с помошью netperf
На первом сервере запускаем netserver -p 10000 -n 4
На втором сервере запускаем netperf -p 10000 -H 192.168.10.2 -l 30

После 10 проходов получаем такие результаты (10^6bits/sec):

Тест 1 1206.99
Тест 2 1710.40
Тест 3 1878.43
Тест 4 1857.45
Тест 5 1874.43
Тест 6 1878.10
Тест 7 1862.14
Тест 8 1876.81
Тест 9 1876.41
Тест 10 1876.15

Со стороны второго сервера вывод данных после тестирования выглядят так:

TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.10.2 (192.168.10.2) port 0 AF_INET
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec

87380 16384 16384 30.01 1878.43

Вывод: При использовании bonding для двух гигабитных сетевых адаптеров имеет смысл и его использование увеличивает пропускную способность сети в 2 раза.

http://centos.alt.ru/?p=12

Количество соединений с сервером

Посмотреть сколько в данный момент с сервером установленно соединений и в каком они состоянии можно просто выполнив :

netstat -an|awk '/tcp/ {print $6}'|sort|uniq -c

Вывод будет выглядеть примерно следующим образом

83 ESTABLISHED
9 FIN_WAIT1
93 FIN_WAIT2
9 LAST_ACK
6 LISTEN
7 SYN_RECV
817 TIME_WAIT

SMP-affinity

Не многие знают, что они могут значительно повысить производительность сетевой подсистемы Linux на мультипроцессорных или многоядерных системах за счёт распределения системных прерываний от сетевых адаптеров на различные процессоры/ядра.

Дело в том, что при интенсивной сетевой нагрузке сетевые платы вызывают слишком много системных прерываний (Вы можете посмотреть нагрузку на процессоры Вашего сервера создаваемую обработкой системных прерываний с помощью утилиты top – параметр si), что влечёт за собой потерю пакетов проходящих на/через сетевые интерфейсы.

Допустим, что у Вас в системе есть два процессора и два сетевых адаптера, сделаем так, чтобы системные прерывания от eth0 обрабатывались первым процессором, а прерывания от второго сетевого адаптера eth1 обрабатывались вторым процессором.

Проверим как обрабатываются прерывания от сетевых адаптеров в данный момент: cat /proc/interrupts

           CPU0       CPU1
  0: 1025359421 1011223877    IO-APIC-edge  timer
  1:          7     443237    IO-APIC-edge  i8042
  6:          3          2    IO-APIC-edge  floppy
  7:          0          0    IO-APIC-edge  parport0
  8:          0   18718112    IO-APIC-edge  rtc
  9:          1          0    IO-APIC-level  acpi
 12:   11950434        756    IO-APIC-edge  i8042
90:      790345          0    IO-APIC-level  eth0
169:         69   10339595    IO-APIC-level  uhci_hcd:usb5, HDA Intel, i915@pci:0000:00:02.0
177:          79073095  0     IO-APIC-level  eth1
209:          0          0    IO-APIC-level  uhci_hcd:usb4
217:     212348          1    IO-APIC-level  ehci_hcd:usb1, uhci_hcd:usb2
225:   24498064       3245    IO-APIC-level  uhci_hcd:usb3, libata
NMI:          0          0
LOC: 2036559271 2036559270
ERR:          0
MIS:          0

как мы можем видеть в приведённом примере первый сетевого адаптер «висит» на IRQ 90, а второй на IRQ 177. Причём явно видно что прерывания как от первого, так и второго сетевого адаптера обрабатываются первым процессором в системе.

Исправим данную ситуацию, для этого нам необходимо записать число “2″ в файл /proc/irq/177/smp_affinity

echo "2" >/proc/irq/177/smp_affinity

после этого посмотрим как изменилась ситуация:

cat /proc/interrupts
           CPU0       CPU1
  0: 1025359421 1011223877    IO-APIC-edge  timer
  1:          7     443237    IO-APIC-edge  i8042
  6:          3          2    IO-APIC-edge  floppy
  7:          0          0    IO-APIC-edge  parport0
  8:          0   18718112    IO-APIC-edge  rtc
  9:          1          0    IO-APIC-level  acpi
 12:   11950434        756    IO-APIC-edge  i8042
90:      790345          0    IO-APIC-level  eth0
169:         69   10339595    IO-APIC-level  uhci_hcd:usb5, HDA Intel, i915@pci:0000:00:02.0
177:   79073095    3672362    IO-APIC-level  eth1
209:          0          0    IO-APIC-level  uhci_hcd:usb4
217:     212348          1    IO-APIC-level  ehci_hcd:usb1, uhci_hcd:usb2
225:   24498064       3245    IO-APIC-level  uhci_hcd:usb3, libata
NMI:          0          0
LOC: 2036559271 2036559270
ERR:          0
MIS:          0

как видим счётчик прерываний для eth1 на CPU0 не изменился, но появились цифры ниже CPU1 т.е. обработка прерываний от второго сетевого адаптера eth1 обрабатывается вторым процессором в системе.

Небольшое объяснение насчёт того, что же значит цифра 2 !
Linux каждому cpu в системе ставит в соответствие некую цифру обозначающую данный процессор в системе. Ниже приведена таблица для 4-х процессорной системы

            двоичный    шестнадцатеричный
    CPU 0    0001         1
    CPU 1    0010         2
    CPU 2    0100         4
    CPU 3    1000         8

т.е. если бы у нас в вышеприведённом примере было не 2 а четыре процессора и мы бы хотели обрабатывать прерывания от eth1 на третьем процессоре CPU2, то нам для этого пришлось бы вместо 2 записать цифру 4 в файл /proc/irq/177/smp_affinity .

Любознательный читатель может спросить, что же было бы если бы мы записали в данный файл число которого нет в приведённой таблице, например echo “3″ >/proc/irq/177/smp_affinity. Ответ прост прерывания от eth1 обрабатывались бы первым и вторым процессором т.к.

           двоичный     шестнадцатеричный
    CPU 0    0001         1
  + CPU 2    0010         2
    -----------------------
             0011         3

Стоит особо отметить, нет смысла обрабатывать системные прерывания от одного сетевого адаптера на нескольких процессорах/ядрах т.к. суммарно system interrupts от данного адаптера никогда не превысит 100%, т.е. максимум, что Вы сможете получить это 50% загрузки на одном процессоре/ядре и 50% на другом.

Дополнение: у компании Intel существуют чипсеты 82575 и 82576 сетевые карты на базе которых имеют несколько очередей каждая из которых может обрабатываться отдельным ядром/процессором.

Выглядит это следующим образом

cat /proc/interrupts
           CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7
  0:   72718527   72693470   72701000   72694778   72698856   72705975   72697612   72709066    IO-APIC-edge  timer
  1:          0          1          0          0          0          0          1          0    IO-APIC-edge  i8042
  6:          0          0          2          0          0          0          1          0    IO-APIC-edge  floppy
  8:          0          0          0          0          0          1          0          0    IO-APIC-edge  rtc
  9:          0          0          0          0          0          0          0          1   IO-APIC-level  acpi
 14:     143672     144923     144966     146156     144955     144426     144156     144955    IO-APIC-edge  ata_piix
 15:     892735     915776     908202     913235     910358     903767     912399     900143    IO-APIC-edge  ide1
 58:          0          0          0          0          0          0          0          0   IO-APIC-level  uhci_hcd:usb3
 66:         64          0          0 2259148530          0          0          0          0       PCI-MSI-X  eth0-tx0
 74: 2992330737          0          0          0          0          0          0          0       PCI-MSI-X  eth0-rx0
 82:       4197 3028991669          0          0          0          0          0          0       PCI-MSI-X  eth0-rx1
 90:       4091          0 3008220806          0          0          0          0          0       PCI-MSI-X  eth0-rx2
 98:       4092          0          0 2999334745          0          0          0          0       PCI-MSI-X  eth0-rx3
106:          2          0          0          0          0          0          0          0       PCI-MSI-X  eth0
114:          7          0          0          0          0          0          0 2265679966       PCI-MSI-X  eth1-tx0
122:          1          0          0          0 3906833163          0          0          0       PCI-MSI-X  eth1-rx0
130:          1          0          0          0          0 3957703625          0          0       PCI-MSI-X  eth1-rx1
138:          1          0          0          0          0          0 3918250115          0       PCI-MSI-X  eth1-rx2
146:          1          0          0          0          0          0          0 3928688764       PCI-MSI-X  eth1-rx3
154:          2          0          0          0          0          0          0          0       PCI-MSI-X  eth1
169:          0          0          0          0          0          0          0          0   IO-APIC-level  uhci_hcd:usb5
177:          1          0          0          0          1          1          1          1   IO-APIC-level  uhci_hcd:usb4, aic94xx
185:          0          0          0          0          0          0          0          0   IO-APIC-level  ehci_hcd:usb1, uhci_hcd:usb2
NMI:          0          0          0          0          0          0          0          0
LOC:  581643579  581643516  581643609  581643411  581643494  581643475  581643531  581643008
ERR:          0
MIS:          0

За данную информацию спасибо Marian Ivasiuk

Подробнее прочитать о SMP-Affinity можно по этому адресу http://www.cs.uwaterloo.ca/~brecht/servers/apic/SMP-affinity.txt
http://centos.alt.ru/?p=26

Iptables производительность

Низкая производительность роутера может быть связанна с некорректными настройками iptables.

Первое, что Вам необходимо сделать если на роутере нет NAT — отключить connection tracking делается это в таблице nat цепочка PREROUTING.

*raw
-A PREROUTING -j NOTRACK
COMMIT

Имейте ввиду, что если у Вас используются правила iptables с использованием модуля match, то Вам придется отказаться от их использования, также у Вас перестанут работать правила использующие conntrack таблицу.

Следующее проверить какие правила iptables отрабатываются чаще всего, и поставить их первыми. Посмотреть какие правила срабатывают чаще всего можно так:

iptables -L -n -v

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

Пример:
Допустим есть сеть домового провайдера. Количество клиентов порядка 10000. При блокировании клиента он блокируется в правилах iptables. На текущий момент заблокированно 2000 клиентов, т. е. в iptables 2000 правил для пакетного фильтра типа:

-A FORWARD -s 192.168.0.1 -j DROP
-A FORWARD -s 192.168.0.2 -j DROP
-A FORWARD -s 192.168.0.3 -j DROP
--/ И так дальше/--
-A FORWARD -s 192.168.1.1 -j DROP
-A FORWARD -s 192.168.1.2 -j DROP
-A FORWARD -s 192.168.1.3 -j DROP
--/ И так дальше/--
-A FORWARD -s 192.168.2.1 -j DROP
-A FORWARD -s 192.168.2.2 -j DROP
-A FORWARD -s 192.168.2.3 -j DROP
--/ И так дальше/--
-A FORWARD -s 192.168.7.1 -j DROP
-A FORWARD -s 192.168.7.2 -j DROP
-A FORWARD -s 192.168.7.254 -j DROP
# Всех остальных пропускаем
-A FORWARD -j ACCEPT

т.е. для того чтобы проверить пропустить или заблокировать пакеты от машины 192.168.8.254 будет произведено 2000 проверок в правилах iptables . ЭТО УЖАСНО. При интенсивном сетевом обмене ни о какой производительности речи быть не может.

Перепишем данные правила следующим образом:

-A FORWARD -s 192.168.0.0/24 -j NET-00
-A FORWARD -s 192.168.1.0/24 -j NET-01
-A FORWARD -s 192.168.2.0/24 -j NET-02
-A FORWARD -s 192.168.3.0/24 -j NET-03
-A FORWARD -s 192.168.4.0/24 -j NET-04
-A FORWARD -s 192.168.5.0/24 -j NET-05
-A FORWARD -s 192.168.6.0/24 -j NET-06
-A FORWARD -s 192.168.7.0/24 -j NET-07
//
-A NET-00 -s 192.168.0.1 -j DROP
-A NET-00 -s 192.168.0.2 -j DROP
-A NET-00 -s 192.168.0.3 -j DROP
--/ И так дальше/--
-A NET-01 -s 192.168.1.1 -j DROP
-A NET-01 -s 192.168.1.2 -j DROP
-A NET-01 -s 192.168.1.3 -j DROP
--/ И так дальше/--
-A NET-07 -s 192.168.7.1 -j DROP
-A NET-07 -s 192.168.7.2 -j DROP
-A NET-07 -s 192.168.7.3 -j DROP
-A FORWARD -j ACCEPT

В наших новых правилах для аналогичной проверки необходимо 255 проверок, итак немного модифицировав правила для iptables мы сократили количество проверок в пакетном фильтре в 4 раза.

Еще одним способом избавиться от узкого места в iptables – использовать ipset.

http://centos.alt.ru/?p=32

NAT производительность

Решил выяснить сколько трафика сможет занатить один Linux сервер, какая нагрузка будет при этом на CPU.

Выяснилось, что при одном и том, же сетевом трафике, но разном количестве пакетов нагрузка на CPU будет разная, что совершенно логично.

Приведу тестовые данные:

Итак тестовая система:
Однопроцессорный четырехядерный сервер Intel(R) Xeon(R) CPU E5405 2.00GHz
Сетевые адаптеры Broadcom NetXtreme II BCM5708 1000Base-T (B2) PCI-X 64-bit 133MHz
ОС CentOS 5.4

Правила для iptables простые /etc/sysconfig/iptables


*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT DROP [0:0]

COMMIT

*nat

-A POSTROUTING -o eth0 -s 172.16.1.0/24 -j SNAT --to 192.168.0.1
-A POSTROUTING -o eth0 -s 172.16.2.0/24 -j SNAT --to 192.168.0.2
-A POSTROUTING -o eth0 -s 172.16.3.0/24 -j SNAT --to 192.168.0.3
--//--
-A POSTROUTING -o eth0 -s 172.16.254.0/24 -j SNAT --to 192.168.0.254

COMMIT

Пропустим через сервер трафик порядка 100 мегабит:

Входящий 90-100 мбит/с
Исходящий 50-60 мбит/с

Посмотрим количество пакетов:

vnstat -tr 15 -i eth0
409452 packets sampled in 15 seconds
Traffic average for eth0

rx 11291.52 kB/s 14072 packets/s
tx 5771.39 kB/s 13223 packets/s

Нагрузка на процессоры:

Cpu0 : 0.0%us, 0.0%sy, 0.0%ni, 91.0%id, 0.0%wa, 1.7%hi, 7.3%si, 0.0%st
Cpu1 : 0.0%us, 0.0%sy, 0.0%ni, 88.3%id, 0.0%wa, 3.7%hi, 8.0%si, 0.0%st

Количество соединений:

sysctl -a | grep ip_conntrack_count
net.ipv4.netfilter.ip_conntrack_count = 65405

Как видим нагрузка на каждый из процессоров всего в районе 7-8 процентов.

Увеличим трафик проходящий через сервер трафик до 200 мбит/с посмотрим как изменится картина

Трафик на обоих сетевых интерфейсах:
Входящий 200-230 мбит/с
Исходящий 130-150 мбит/с


vnstat -tr 15 -i eth0
873819 packets sampled in 15 seconds
Traffic average for eth0

rx 22922.61 kB/s 29719 packets/s
tx 14199.36 kB/s 28535 packets/s

Нагрузка на CPU

Cpu0 : 0.0%us, 0.0%sy, 0.0%ni, 68.0%id, 0.0%wa, 2.3%hi, 29.7%si, 0.0%st
Cpu1 : 0.0%us, 0.0%sy, 0.0%ni, 60.0%id, 0.0%wa, 4.7%hi, 35.0%si, 0.0%st

Увеличим трафик проходящий через сервер трафик до 350 мбит/с посмотрим как изменится картина

Трафик на обоих сетевых интерфейсах:
Входящий 350-370 мбит/с
Исходящий 190-210 мбит/с


vnstat -tr 15 -i eth0
1475987 packets sampled in 15 seconds
Traffic average for eth0

rx 37181.86 kB/s 49891 packets/s
tx 20991.49 kB/s 48507 packets/s

Нагрузка на CPU

Cpu0 : 0.0%us, 0.0%sy, 0.0%ni, 37.9%id, 0.0%wa, 1.7%hi, 60.5%si, 0.0%st
Cpu1 : 0.0%us, 0.0%sy, 0.0%ni, 19.5%id, 0.0%wa, 5.3%hi, 75.2%si, 0.0%st

Количество сетевых соединений

sysctl -a | grep ip_conntrack_count
net.ipv4.netfilter.ip_conntrack_count = 215402

Ну вот в принципе и все, как видим, даже обычный сервер в состоянии «заNATить» порядка 400 мегабит трафика.

2 gbit/sec SPAN Cisco export Netflow :)

Встала задача писать весь транзитный трафик с Cisco 6504, меня интересуют 2 гигабитных канала на интерфейсах Gi2/1 , Gi2/2. Можно было бы писать NetFlow напрямую с Cisco 6504, но на ней осуществляется нарезка полос (User Based Rate Limit microflow policy) совместно с которым экспорт в NetFlow не работает, поэтому будем извращаться :).

Для начала выгоним SPAN (копию интересующего меня трафика с Gi2/1 , Gi2/2 ) в два гигабитных порта Gi2/4 и Gi2/5.


!
vlan 100
!
!
interface Port-channel100
switchport
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet2/4
switchport
switchport access vlan 100
switchport mode access
channel-group 100 mode on
!
interface GigabitEthernet2/5
switchport
switchport access vlan 100
switchport mode access
channel-group 100 mode on
!
monitor session 1 source interface Gi2/1 , Gi2/2
monitor session 1 destination interface Po100
!

Теперь необходимо определиться с инструментарием которым мы собираемся «ловить» поток и отдавать его в формате NetFlow.

На самом деле выбор не велик fprobe, ipcad, softflowd т. е. те вещи которые работают через pcap «умерли» сразу, попутно убив CPU сервера 🙂

Через ULOG iptables писать нельзя т. к. трафик не попадает ни в одну цепочку (ибо он не транзитный).

Нашелся один инструмент (ipt_netflow), но для его работоспособности в схеме со Span портом пришлось пропатчить ядро (здесь патченное ядро) и пропатчить сам модуль ipt_netflowустанавливать надо ipt_netflow (модуль iptables) и kmod-netflow-promisc (модуль ядра).

SPAN потоки приходят в сетевые адаптеры eth2 и eth3 сервера соответственно.

После установки этого чуда пишем в iptables


*raw
-A PREROUTING -i eth2 -j NETFLOW
-A PREROUTING -i eth3 -j NETFLOW
COMMIT

в /etc/modprobe.conf добавляем


options ipt_NETFLOW hashsize=160000 destination="127.0.0.1:2055"

результаты таковы, что при 1-1,5 gbit/sec трафика мы получаем следующую нагрузку на CPU
top

Tasks: 117 total, 1 running, 116 sleeping, 0 stopped, 0 zombie
Cpu0 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu1 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu2 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu3 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu4 : 0.0%us, 0.0%sy, 0.0%ni, 71.3%id, 0.3%wa, 0.0%hi, 28.3%si, 0.0%st
Cpu5 : 0.0%us, 0.0%sy, 0.0%ni, 69.5%id, 0.0%wa, 0.7%hi, 29.8%si, 0.0%st
Cpu6 : 0.0%us, 0.0%sy, 0.0%ni, 71.2%id, 0.0%wa, 0.3%hi, 28.4%si, 0.0%st
Cpu7 : 0.0%us, 1.0%sy, 0.0%ni, 68.2%id, 0.0%wa, 0.3%hi, 30.4%si, 0.0%st
Mem: 4044184k total, 2566136k used, 1478048k free, 485276k buffers
Swap: 2031608k total, 132k used, 2031476k free, 1622060k cached

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
33 root 10 -5 0 0 0 S 2.7 0.0 32:41.04 events/7
1 root 15 0 10348 632 540 S 0.0 0.0 0:02.31 init
2 root RT -5 0 0 0 S 0.0 0.0 0:00.02 migration/0
3 root 34 19 0 0 0 S 0.0 0.0 0:03.06 ksoftirqd/0
4 root RT -5 0 0 0 S 0.0 0.0 0:00.00 watchdog/0
5 root RT -5 0 0 0 S 0.0 0.0 0:00.07 migration/1
6 root 34 19 0 0 0 S 0.0 0.0 0:00.04 ksoftirqd/1
7 root RT -5 0 0 0 S 0.0 0.0 0:00.00 watchdog/1
8 root RT -5 0 0 0 S 0.0 0.0 0:00.01 migration/2
9 root 34 19 0 0 0 S 0.0 0.0 0:00.03 ksoftirqd/2

cat /proc/net/stat/ipt_netflow

Flows: active 354747 (peak 540458 reached 0d16h37m ago), mem 30486K
Hash: size 160000 (mem 1250K), metric 2.7, 2.2, 1.0, 1.0. MemTraf: 121088697 pkt, 75450911 K (pdu 5, 276).
Timeout: active 1800, inactive 15. Maxflows 2000000
Rate: 1382824352 bits/sec, 298823 packets/sec; Avg 1 min: 1367908158 bps, 296724 pps; 5 min: 1361329134 bps, 296061 pps
cpu# stat: , sock: , traffic: , drop: Total stat: 38000468809 22085636328 1231067128, 0 0 0 0, sock: 41023746 0 0, 58651136 K, traffic: 23316703456, 13030478 MB, drop: 0, 0 K
cpu0 stat: 0 0 0, 0 0 0 0, sock: 0 0 0, 0 K, traffic: 0, 0 MB, drop: 0, 0 K
cpu1 stat: 0 0 0, 0 0 0 0, sock: 0 0 0, 0 K, traffic: 0, 0 MB, drop: 0, 0 K
cpu2 stat: 0 0 0, 0 0 0 0, sock: 0 0 0, 0 K, traffic: 0, 0 MB, drop: 0, 0 K
cpu3 stat: 0 0 0, 0 0 0 0, sock: 0 0 0, 0 K, traffic: 0, 0 MB, drop: 0, 0 K
cpu4 stat: 9502008868 5521585976 307793882, 0 0 0 0, sock: 0 0 0, 0 K, traffic: 5829379858, 3259408 MB, drop: 0, 0 K
cpu5 stat: 9495159604 5519723902 307727275, 0 0 0 0, sock: 0 0 0, 0 K, traffic: 5827451177, 3255443 MB, drop: 0, 0 K
cpu6 stat: 9500201467 5522411578 307754983, 0 0 0 0, sock: 0 0 0, 0 K, traffic: 5830166561, 3258689 MB, drop: 0, 0 K
cpu7 stat: 9503098870 5521914872 307790988, 0 0 0 0, sock: 41023746 0 0, 58651136 K, traffic: 5829705860, 3256938 MB, drop: 0, 0 K
sock0: 127.0.0.1:2055, sndbuf 33554432, filled 0, peak 140936; err: sndbuf reached 0, other 0

как видим трафик порядка 1.3 гбит/сек, 300 kpps 🙂

Вроде ничего не забыл.

http://centos.alt.ru/?p=367