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

Использование ipset

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

Первая мысль — блокировать в iptables. Мысль это безусловна верная, но при большом количестве правил, это будет создавать излишнюю нагрузку на CPU. Так например линейный список из 1000 правил убьет производительность роутера под нуль.

Каким образом можно увеличить производительность данной схемы ?

Выход был найден – ipset.

Установка ipset для CentOS i386 занимает 1 минуту:

Подключаем CentALT:

rpm -ihv http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-4.noarch.rpm
rpm -ihv http://centos.alt.ru/repository/centos/5/i386/centalt-release-5-3.noarch.rpm

Устанавливаем нужные пакеты:

yum install ipset kmod-ipset

Обновляем iptables — пересобран штатный для CentOS iptables, только добавлен модуль SET.

yum update iptables

Создаем файл /etc/ipset.conf в который будем писать ip которым запрещен доступ следующего содержания

#!/bin/bash

# Создаем новую цепочку правил
ipset -N access iphash
# добавляем список доступа
ipset -A access 192.168.0.2
ipset -A access 192.168.0.3
ipset -A access 192.168.0.4

добавляем в автоматический запуск в файл /etc/rc.d/rc.local
добавляем последней строку
/bin/bash /etc/ipset.conf

Затем добавляем в /etc/sysconfig/iptables единственную строку которая закроет доступ всем ip адресам из выше приведенного списка

-A FORWARD -m set --set access src -j DROP

перегружаем правила iptables

service iptables restart

Все.

Переход от блокировки в iptables на блокировку в ipset снизил нагрузку на систему более чем в 2 раза при количестве правил >1000, сетевой трафик проходящий через роутер в районе 100 kpps.

Подобным образом можно успешно защищаться от простейших DDOS атак.

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

Ограничение количества сессий с одного IP-адреса

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

На самом деле, я нашел всего два модуля для iptables, которые помогут мне помочь в решении данной задачи. Это модуль connlimit и модуль recent.

connlimit может работать только с tcp протоколом, и может ограничивать количество установленных tcp сессий для каждого клиента достаточно простым правилом, например пример приведенный ниже ограничит количество TCP сессий от каждого клиента из сети 172.16.0.0/12 в 200.


-A FORWARD -s 172.16.0.0/12 -p tcp --syn -m connlimit --connlimit-above 200 -j DROP

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

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

Например присвоим всем сетевыем пакетам с состоянием NEW (новое соединение), проходящие через сетевой интерфейс eth0 нашего роутера имя SYNF.

-A FORWARD -i eth0 -m state --state NEW -m recent --set --name SYNF --rsource

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

-A FORWARD -i eth0 -m state --state NEW -m recent --update --seconds 10 --hitcount 10 --rttl --name SYNF --rsource -j DROP

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

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

Сетевой адаптер Intel ServerAdapter 1000 ET Quad Port PCIe в CentOS 5

Купили такую железку Intel ServerAdapter 1000 ET Quad Port PCIe .

Смонтировали в сервер. Задача заставить данный адаптер работать в CentOS 5, и распределить сетевую нагрузку по нескольким очередям.

Загружаемся:

Информация в dmesg


Intel(R) Gigabit Ethernet Network Driver - version 1.3.16-k2
Copyright (c) 2007-2009 Intel Corporation.
ACPI: PCI Interrupt 0000:09:00.0[A] -> GSI 17 (level, low) -> IRQ 169
PCI: Setting latency timer of device 0000:09:00.0 to 64
EDAC MC0: Giving out device to i5000_edac.c I5000: DEV 0000:00:10.0
intel_rng: FWH not detected
ACPI: PCI Interrupt 0000:00:1f.3[B] -> GSI 20 (level, low) -> IRQ 162
igb 0000:09:00.0: Intel(R) Gigabit Ethernet Network Connection
igb 0000:09:00.0: eth2: (PCIe:2.5Gb/s:Width x4) 00:1b:21:3e:ae:28
igb 0000:09:00.0: eth2: PBA No: e64750-002
igb 0000:09:00.0: Using MSI-X interrupts. 4 rx queue(s), 1 tx queue(s)
ACPI: PCI Interrupt 0000:09:00.1[B] -> GSI 18 (level, low) -> IRQ 106
PCI: Setting latency timer of device 0000:09:00.1 to 64
igb 0000:09:00.1: Intel(R) Gigabit Ethernet Network Connection
igb 0000:09:00.1: eth2: (PCIe:2.5Gb/s:Width x4) 00:1b:21:3e:ae:29
igb 0000:09:00.1: eth2: PBA No: e64750-002
igb 0000:09:00.1: Using MSI-X interrupts. 4 rx queue(s), 1 tx queue(s)
ACPI: PCI Interrupt 0000:0a:00.0[A] -> GSI 19 (level, low) -> IRQ 218
PCI: Setting latency timer of device 0000:0a:00.0 to 64
igb 0000:0a:00.0: Intel(R) Gigabit Ethernet Network Connection
igb 0000:0a:00.0: eth3: (PCIe:2.5Gb/s:Width x4) 00:1b:21:3e:ae:2c
igb 0000:0a:00.0: eth3: PBA No: e64750-002
igb 0000:0a:00.0: Using MSI-X interrupts. 4 rx queue(s), 1 tx queue(s)
ACPI: PCI Interrupt 0000:0a:00.1[B] -> GSI 16 (level, low) -> IRQ 177
PCI: Setting latency timer of device 0000:0a:00.1 to 64
igb 0000:0a:00.1: Intel(R) Gigabit Ethernet Network Connection
igb 0000:0a:00.1: eth2: (PCIe:2.5Gb/s:Width x4) 00:1b:21:3e:ae:2d
igb 0000:0a:00.1: eth2: PBA No: e64750-002
igb 0000:0a:00.1: Using MSI-X interrupts. 4 rx queue(s), 1 tx queue(s)

На первый взгляд все замечательно адаптер определился и работает, но смутили надписи 4 rx queue(s), 1 tx queue(s) на каждом из портов. Все дело в том, что у данного адаптера по 8 rx (прием) очередей на каждый порт.

Проверим версию драйвера

modinfo igb


filename: /lib/modules/2.6.18-164.6.1.el5PAE/kernel/drivers/net/igb/igb.ko
version: 1.3.16-k2
license: GPL
description: Intel(R) Gigabit Ethernet Network Driver
author: Intel Corporation,
srcversion: 78555F0A019E05BADBD95AA
alias: pci:v00008086d000010D6sv*sd*bc*sc*i*
alias: pci:v00008086d000010A9sv*sd*bc*sc*i*
alias: pci:v00008086d000010A7sv*sd*bc*sc*i*
alias: pci:v00008086d000010E8sv*sd*bc*sc*i*
alias: pci:v00008086d000010E7sv*sd*bc*sc*i*
alias: pci:v00008086d000010E6sv*sd*bc*sc*i*
alias: pci:v00008086d0000150Asv*sd*bc*sc*i*
alias: pci:v00008086d000010C9sv*sd*bc*sc*i*
depends: 8021q
vermagic: 2.6.18-164.6.1.1.el5PAE SMP mod_unload 686 REGPARM 4KSTACKS gcc-4.1
parm: max_vfs:Maximum number of virtual functions to allocate per physical function (uint)
module_sig: 883f3504af3fe359a79aca2e69819291121b4409f6ecc47545455cf3b51a9aa99f40859e7bd7931a09f76b4b34dde9013eed67638dee172193713aff51f

Очень напрягает практически полное отсутствие секции parm, т.е. драйвер не знает практически никаких параметров.

Поднимем один порт например eth2 и посмотрим как обстоят дела в /proc/interrupts
cat /proc/interrupts|grep eth2

           CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7
122:          0          0          0          0          0          0          0          0       PCI-MSI-X  eth2-tx-0
130:        182          0          0          0          0          0          0          0       PCI-MSI-X  eth2-rx-0
138:        182          0          0          0          0          0          0          0       PCI-MSI-X  eth2-rx-1
146:        182          0          0          0          0          0          0          0       PCI-MSI-X  eth2-rx-2
154:        182          0          0          0          0          0          0          0       PCI-MSI-X  eth2-rx-3
162:          2          0          0          0          0          0          0          0       PCI-MSI-X  eth2

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

modprobe igb IntMode=3,3,3,3 RSS=8,8,8,8


FATAL: Error inserting igb (/lib/modules/2.6.18-164.6.1.1.el5PAE/kernel/drivers/net/igb/igb.ko): Unknown symbol in module, or unknown parameter (see dmesg)

в dmesg

igb: Unknown parameter `IntMode'
igb: Unknown parameter `RSS'

опс, драйвер не знает таких параметров 🙁

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

Устанавливаем:

rpm -ihv http://elrepo.org/linux/elrepo/el5/i386/RPMS/kmod-igb-PAE-2.0.6-1.el5.elrepo.i686.rpm

Загружается http://elrepo.org/linux/elrepo/el5/i386/RPMS/kmod-igb-PAE-2.0.6-1.el5.elrepo.i686.rpm
предупреждение: /var/tmp/rpm-xfer.cvXEF5: Заголовок V3 DSA signature: NOKEY, key ID baadae52
Подготовка...     ########################################### [100%]
   1:kmod-igb-PAE           ########################################### [100%]
Creating the symbolic links. This may take some time ...
Done.


modinfo igb

filename:       /lib/modules/2.6.18-164.6.1.1.el5PAE/weak-updates/igb/igb.ko
version:        2.0.6
license:        GPL
description:    Intel(R) Gigabit Ethernet Network Driver
author:         Intel Corporation, 
srcversion:     AD1D1A409C0E0945FADD6A2
alias:          pci:v00008086d000010D6sv*sd*bc*sc*i*
alias:          pci:v00008086d000010A9sv*sd*bc*sc*i*
alias:          pci:v00008086d000010A7sv*sd*bc*sc*i*
alias:          pci:v00008086d000010E8sv*sd*bc*sc*i*
alias:          pci:v00008086d0000150Dsv*sd*bc*sc*i*
alias:          pci:v00008086d000010E7sv*sd*bc*sc*i*
alias:          pci:v00008086d000010E6sv*sd*bc*sc*i*
alias:          pci:v00008086d00001518sv*sd*bc*sc*i*
alias:          pci:v00008086d0000150Asv*sd*bc*sc*i*
alias:          pci:v00008086d000010C9sv*sd*bc*sc*i*
depends:
vermagic:       2.6.18-8.el5PAE SMP mod_unload 686 REGPARM 4KSTACKS gcc-4.1
parm:           InterruptThrottleRate:Interrupt Throttling Rate (array of int)
parm:           IntMode:Interrupt Mode (array of int)
parm:           LLIPort:Low Latency Interrupt TCP Port (array of int)
parm:           LLIPush:Low Latency Interrupt on TCP Push flag (array of int)
parm:           LLISize:Low Latency Interrupt on Packet Size (array of int)
parm:           RSS:RSS - multiqueue receive count (array of int)
parm:           VMDQ:VMDQ - VMDq multiqueue receive (array of int)
parm:           QueuePairs:QueuePairs - TX/RX queue pairs for interrupt handling (array of int)
parm:           debug:Debug level (0=none, ..., 16=all) (int)

Подгружаем драйвер с нужными параметрами

modprobe igb IntMode=3,3,3,3 RSS=8,8,8,8

Проверяем

cat /proc/interrupts |grep eth2

 51:          6          0          0          0          0          0          0          0       PCI-MSI-X  eth2
 52:          5          0          0          0          0          0          0          0       PCI-MSI-X  eth2-TxRx-0
 53:         34          0          0          0          0          0          0          0       PCI-MSI-X  eth2-rx-1
 54:          8          0          0          0          0          0          0          0       PCI-MSI-X  eth2-rx-2
 59:          8          0          0          0          0          0          0          0       PCI-MSI-X  eth2-rx-3
 60:          8          0          0          0          0          0          0          0       PCI-MSI-X  eth2-rx-4
 61:         34          0          0          0          0          0          0          0       PCI-MSI-X  eth2-rx-5
 62:          8          0          0          0          0          0          0          0       PCI-MSI-X  eth2-rx-6
 67:          5          0          0          0          0          0          0          0       PCI-MSI-X  eth2-rx-7

Теперь на каждый порт мы имеем по 8 очередей.

Победа.

Попытаемся заNAT-ить несколько сот мегабит трафика при штатном драйвере igb и проверим нагрузку на систему.

Для сравнения вспомним данный обзор, в котором процессоры умирали от si (system interrupts) при трафике в 400 мегабит.

«Дунем» через наш адаптер 400 мегабит входящего трафика, исходящий окажется в пределах 300 мегабит.


vnstat -i eth0 -tr

609740 packets sampled in 5 seconds
Traffic average for eth0

      rx       45864.72 kB/s          61261 packets/s
      tx       29906.86 kB/s          60686 packets/s

Посмотрим количество conntrack соединений

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

net.ipv4.netfilter.ip_conntrack_count = 272495

Посмотрим нагрузку на ядра

top

Cpu0  :  0.0%us,  0.0%sy,  0.0%ni, 68.4%id,  0.0%wa,  0.7%hi, 30.9%si,  0.0%st
Cpu1  :  0.0%us,  0.0%sy,  0.0%ni, 65.6%id,  0.0%wa,  3.3%hi, 31.1%si,  0.0%st
Cpu2  :  0.0%us,  0.0%sy,  0.0%ni, 66.7%id,  0.0%wa,  0.3%hi, 33.0%si,  0.0%st
Cpu3  :  0.0%us,  0.0%sy,  0.0%ni, 69.7%id,  0.0%wa,  0.3%hi, 30.0%si,  0.0%st
Cpu4  :  0.3%us,  0.0%sy,  0.0%ni, 65.1%id,  0.0%wa,  0.7%hi, 33.9%si,  0.0%st
Cpu5  :  0.0%us,  0.0%sy,  0.0%ni, 63.8%id,  0.0%wa,  0.7%hi, 35.5%si,  0.0%st
Cpu6  :  0.0%us,  0.0%sy,  0.0%ni, 64.7%id,  0.0%wa,  3.0%hi, 32.3%si,  0.0%st
Cpu7  :  0.0%us,  0.0%sy,  0.0%ni, 63.7%id,  0.0%wa,  0.7%hi, 35.7%si,  0.0%st
Mem:   4147676k total,   340000k used,  3807676k free,    40524k buffers
Swap:  1052248k total,        0k used,  1052248k free,   123408k cached

Как видим средняя нагрузка на CPU от system interrupts в районе 33% т.е. сервер будет в состоянии занатить 1 гигабит трафика.

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