FastNetMon

Monday, 20 April 2015

How to measure DPDK application performance?

Really brilliant idea! Found it here: http://www.net.in.tum.de/fileadmin/bibtex/publications/papers/MoonGen_draft2.pdf

Quote:

Measuring the CPU load caused by a DPDK-based application is difficult because DPDK recommends a busy-wait loop, i.e. the CPU load is always 100% for a typical application. MoonGen and other DPDKbased generators like Pktgen-DPDK are no exception to this. The bottleneck for packet transmission is usually not the CPU but the line rate of the network, so just measuring the achieved rate provides no insight. We therefore decrease the clock frequency of our CPU such that the processing power becomes the bottleneck. The performance can then be quantified as CPU cycles per packet. The same approach was used by Rizzo to evaluate the performance of netmap.


Использование DPDK на Debian 8 Jessie вместе с драйвером ixgbe (Intel 82599)

Использование DPDK на Debian 8 Jessie вместе с драйвером ixgbe (Intel 82599).

Собираем:
cd /usr/src
wget http://dpdk.org/browse/dpdk/snapshot/dpdk-16.04.tar.gz
tar -xf dpdk-16.04.tar.gz
cd dpdk-16.04/
make config T=x86_64-native-linuxapp-gcc
make
Загружаем uio:
modprobe uio_pci_generic

Проверяем, какие сетевые мы видим:
tools/dpdk_nic_bind.py --status
tools/dpdk_nic_bind.py --status
Network devices using DPDK-compatible driver
============================================
<none>
Network devices using kernel driver
===================================
0000:02:00.0 'I350 Gigabit Network Connection' if=eth0 drv=igb unused=uio_pci_generic *Active*
0000:02:00.1 'I350 Gigabit Network Connection' if=eth1 drv=igb unused=uio_pci_generic
0000:02:00.2 'I350 Gigabit Network Connection' if=eth2 drv=igb unused=uio_pci_generic
0000:02:00.3 'I350 Gigabit Network Connection' if=eth3 drv=igb unused=uio_pci_generic
0000:0a:00.0 '82599ES 10-Gigabit SFI/SFP+ Network Connection' if=eth4 drv=ixgbe unused=uio_pci_generic
0000:0a:00.1 '82599ES 10-Gigabit SFI/SFP+ Network Connection' if=eth5 drv=ixgbe unused=uio_pci_generic
0000:0d:00.0 '82599ES 10-Gigabit SFI/SFP+ Network Connection' if=eth6 drv=ixgbe unused=uio_pci_generic
0000:0d:00.1 '82599ES 10-Gigabit SFI/SFP+ Network Connection' if=eth7 drv=ixgbe unused=uio_pci_generic 

Отключаем сетевые (в моем случае eth4/eth6), с которыми будем работать от драйвера из Linux ядра для работы с DPDK:

./tools/dpdk_nic_bind.py --bind=uio_pci_generic  0a:00.0
./tools/dpdk_nic_bind.py --bind=uio_pci_generic 0d:00.0

Убеждаемся, что все подцепилось:
tools/dpdk_nic_bind.py --status
Network devices using DPDK-compatible driver
============================================
0000:0a:00.0 '82599ES 10-Gigabit SFI/SFP+ Network Connection' drv=uio_pci_generic unused=
0000:0d:00.0 '82599ES 10-Gigabit SFI/SFP+ Network Connection' drv=uio_pci_generic unused=
Network devices using kernel driver
===================================
0000:02:00.0 'I350 Gigabit Network Connection' if=eth0 drv=igb unused=uio_pci_generic *Active*
0000:02:00.1 'I350 Gigabit Network Connection' if=eth1 drv=igb unused=uio_pci_generic
0000:02:00.2 'I350 Gigabit Network Connection' if=eth2 drv=igb unused=uio_pci_generic
0000:02:00.3 'I350 Gigabit Network Connection' if=eth3 drv=igb unused=uio_pci_generic
0000:0a:00.1 '82599ES 10-Gigabit SFI/SFP+ Network Connection' if=eth5 drv=ixgbe unused=uio_pci_generic
0000:0d:00.1 '82599ES 10-Gigabit SFI/SFP+ Network Connection' if=eth7 drv=ixgbe unused=uio_pci_generic
Other network devices
=====================
<none>

Теперь нужно настроить HugeTLB, смотрим, в какие точки оно у нас смонтировано:
cat /proc/mounts |grep tlb

И размонтируем!

После этого монтируем вновь:
mkdir -p /mnt/huge
mount -t hugetlbfs nodev /mnt/huge
echo 64 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages
Собираем пример форвардера:

cd examples
apt-get install -y libvirt-dev
export RTE_TARGET=x86_64-native-linuxapp-gcc
export RTE_SDK=/usr/src/dpdk-16.04
make
Если получаем ошибку "/usr/src/dpdk-16.04/mk/internal/rte.extvars.mk:57: *** Cannot find .config in /usr/src/dpdk-16.04/x86_64-native-linuxapp-gcc.  Останов.", то нужно внести фикс:

В файле:
vim /usr/src/dpdk-16.04/mk/internal/rte.extvars.mk

Фиксим:
-RTE_SDK_BIN := $(RTE_SDK)/$(RTE_TARGET)
+RTE_SDK_BIN := $(RTE_SDK)/build

Итак, у нас CPU E5-2407 0 @ 2.20GHz у него 3 канала памяти (-n 3) и 4 ядра (-l 0-3).

Запускаем (можно указать --pci-whitelist 0a:00.0 --pci-whitelist 0d:00.0 чтобы работать только с этими портами):
./l2fwd/l2fwd/x86_64-native-linuxapp-gcc/app/l2fwd -l 0-3 -n 3  -- -p 3

-p 3 - это битовая маска портов, с которыми мы работаем (3 = 11 в бинарной кодировке, оба порта).

Обращаю внимание, что на целевой стороне нужно включить promisc режим, ибо пакеты летят с левым MAC:
11:47:35.261390 90:e2:ba:4a:d8:e8 > 02:00:00:00:00:01, ethertype IPv4 (0x0800), length 60: 128.0.71.57.9926 > 10.20.20.100.80: UDP, length 18
11:47:35.261391 90:e2:ba:4a:d8:e8 > 02:00:00:00:00:01, ethertype IPv4 (0x0800), length 60: 128.0.71.56.14204 > 10.20.20.100.80: UDP, length 18
11:47:35.261392 90:e2:ba:4a:d8:e8 > 02:00:00:00:00:01, ethertype IPv4 (0x0800), length 60: 128.0.71.57.6523 > 10.20.20.100.80: UDP, length 18
11:47:35.261394 90:e2:ba:4a:d8:e8 > 02:00:00:00:00:01, ethertype IPv4 (0x0800), length 60: 128.0.71.56.51110 > 10.20.20.100.80: UDP, length 18
11:47:35.261394 90:e2:ba:4a:d8:e8 > 02:00:00:00:00:01, ethertype IPv4 (0x0800), length 60: 128.0.71.57.12424 > 10.20.20.100.80: UDP, length 18

Включаем режим прослушки вот так:
ifconfig eth1 promisc 

Итак, нагрузка:
33624 root      20   0  378800   3716   3356 R 200.0  0.0  30:04.50 l2fwd                                            
%Cpu(s): 50.0 us,  0.0 sy,  0.0 ni, 50.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st


Показания с PCM просто потрясающие - все операции идут через кэш процессора:
Time elapsed: 998 ms
Called sleep function for 1000 ms
---------------------------------------|
--             Socket 0              --|
---------------------------------------|
---------------------------------------|
---------------------------------------|
--   Memory Performance Monitoring   --|
---------------------------------------|
--  Mem Ch 0: Reads (MB/s):    0.26  --|
--            Writes(MB/s):   18.52  --|
--  Mem Ch 1: Reads (MB/s):    0.10  --|
--            Writes(MB/s):   17.11  --|
-- NODE0 Mem Read (MB/s):      0.36  --|
-- NODE0 Mem Write (MB/s) :   35.64  --|
-- NODE0 P. Write (T/s) :      3107  --|
-- NODE0 Memory (MB/s):    36.00     --|
---------------------------------------||---------------------------------------
--                   System Read Throughput(MB/s):      0.36                  --
--                  System Write Throughput(MB/s):     35.64                  --
--                 System Memory Throughput(MB/s):     36.00                  --
---------------------------------------||---------------------------------------

В случае netmap цифры ужасающие:
---------------------------------------|
--             Socket 0              --|
---------------------------------------|
---------------------------------------|
---------------------------------------|
--   Memory Performance Monitoring   --|
---------------------------------------|
--  Mem Ch 0: Reads (MB/s): 1162.53  --|
--            Writes(MB/s):  726.09  --|
--  Mem Ch 1: Reads (MB/s):    0.01  --|
--            Writes(MB/s):    0.00  --|
-- NODE0 Mem Read (MB/s):   1162.53  --|
-- NODE0 Mem Write (MB/s) :  726.09  --|
-- NODE0 P. Write (T/s) :      3575  --|
-- NODE0 Memory (MB/s):  1888.63     --|
---------------------------------------||---------------------------------------
--                   System Read Throughput(MB/s):   1162.53                  --
--                  System Write Throughput(MB/s):    726.09                  --
--                 System Memory Throughput(MB/s):   1888.63                  --
---------------------------------------||---------------------------------------

Запуск тест testpmd:
./x86_64-native-linuxapp-gcc/build/app/test-pmd/testpmd -l 0-3 -n 3  -- --interactive --total-num-mbufs=2048
Вот огромный гайд по тулзе testpmd: http://www.intel.com/content/dam/www/public/us/en/documents/guides/intel-dpdk-testpmd-application-user-guide.pdf

Генерация до 14.6 MPPS на одном логическом ядре силами MoonGen и DPDK

Итак, для начала Вам нужно собрать и установить DPDK: 2.0.0 версии или старше.

Вытягиваем код и стаскиваем зависимости (LuaJIT):
cd /usr/src
git clone https://github.com/emmericp/MoonGen.git
cd MoonGen/
# Update dependencies
git submodule update --init
Указываем путь к свеже установленному DPDK:
export RTE_TARGET=x86_64-native-linuxapp-gcc
export RTE_SDK=/usr/src/dpdk-16.04
Собираем:
./build.sh
Смотрим номера портов (этот блок выдается при запуске MoonGen без параметров):
Found 7 usable ports:
   Ports 0: D8:9D:67:64:4A:71 (unknown NIC (PCI ID 8086:1521))
   Ports 1: D8:9D:67:64:4A:72 (unknown NIC (PCI ID 8086:1521))
   Ports 2: D8:9D:67:64:4A:73 (unknown NIC (PCI ID 8086:1521))
   Ports 3: 90:E2:BA:4A:D8:DC (82599EB 10-Gigabit SFI/SFP+ Network Connection)
   Ports 4: 90:E2:BA:4A:D8:DD (82599EB 10-Gigabit SFI/SFP+ Network Connection)
   Ports 5: 90:E2:BA:4A:D8:E8 (82599EB 10-Gigabit SFI/SFP+ Network Connection)
   Ports 6: 90:E2:BA:4A:D8:E9 (82599EB 10-Gigabit SFI/SFP+ Network Connection)

Запускаем генерацию SYN флуда (5 - порт из списка выше, 10.0.0.1 - стартовый порт для генерации src, 10000 - скорость):
build/MoonGen examples/l3-tcp-syn-flood.lua 5 10.0.0.1 16000000 10000
В итоге после инициализации получаем отличный флуд:
[Device: id=0] Sent 845365678 packets, current rate 14.83 Mpps, 7594.27 MBit/s, 9967.48 MBit/s wire rate.
[Device: id=0] Sent 860193837 packets, current rate 14.83 Mpps, 7592.01 MBit/s, 9964.52 MBit/s wire rate.
[Device: id=0] Sent 875025963 packets, current rate 14.83 Mpps, 7594.04 MBit/s, 9967.17 MBit/s wire rate.
[Device: id=0] Sent 889854138 packets, current rate 14.83 Mpps, 7591.99 MBit/s, 9964.49 MBit/s wire rate.
[Device: id=0] Sent 904685096 packets, current rate 14.83 Mpps, 7593.43 MBit/s, 9966.37 MBit/s wire rate.
[Device: id=0] Sent 919514890 packets, current rate 14.83 Mpps, 7592.84 MBit/s, 9965.60 MBit/s wire rate.

[Device: id=0] Sent 934345896 packets, current rate 14.83 Mpps, 7593.42 MBit/s, 9966.37 MBit/s wire rate.
Со стороны получателя это выглядит вот так:
10.224.21.215.1025 > 192.168.1.1.1024: Flags [S], cksum 0xc562 (correct), seq 1:21, win 10, length 2015:01:27.116876 IP (tos 0x0, ttl 64, id 0, offset 0, flags [none], proto TCP (6), length 60)    
10.223.153.106.1025 > 192.168.1.1.1024: Flags [S], cksum 0x41d0 (correct), seq 1:21, win 10, length 2015:01:27.116877 IP (tos 0x0, ttl 64, id 0, offset 0, flags [none], proto TCP (6), length 60)    
10.224.21.216.1025 > 192.168.1.1.1024: Flags [S], cksum 0xc561 (correct), seq 1:21, win 10, length 2015:01:27.116877 IP (tos 0x0, ttl 64, id 0, offset 0, flags [none], proto TCP (6), length 60)    
10.223.153.117.1025 > 192.168.1.1.1024: Flags [S], cksum 0x41c5 (correct), seq 1:21, win 10, length 2015:01:27.116878 IP (tos 0x0, ttl 64, id 0, offset 0, flags [none], proto TCP (6), length 60)    
10.224.21.230.1025 > 192.168.1.1.1024: Flags [S], cksum 0xc553 (correct), seq 1:21, win 10, length 2015:01:27.116878 IP (tos 0x0, ttl 64, id 0, offset 0, flags [none], proto TCP (6), length 60)    
10.223.153.122.1025 > 192.168.1.1.1024: Flags [S], cksum 0x41c0 (correct), seq 1:21, win 10, length 2015:01:27.116879 IP (tos 0x0, ttl 64, id 0, offset 0, flags [none], proto TCP (6), length 60)    
10.224.21.233.1025 > 192.168.1.1.1024: Flags [S], cksum 0xc550 (correct), seq 1:21, win 10, length 2015:01:27.116879 IP (tos 0x0, ttl 64, id 0, offset 0, flags [none], proto TCP (6), length 60)    
10.223.153.129.1025 > 192.168.1.1.1024: Flags [S], cksum 0x41b9 (correct), seq 1:21, win 10, length 2015:01:27.116880 IP (tos 0x0, ttl 64, id 0, offset 0, flags [none], proto TCP (6), length 60)    
10.224.21.246.1025 > 192.168.1.1.1024: Flags [S], cksum 0xc543 (correct), seq 1:21, win 10, length 2015:01:27.116880 IP (tos 0x0, ttl 64, id 0, offset 0, flags [none], proto TCP (6), length 60)   
10.223.153.142.1025 > 192.168.1.1.1024: Flags [S], cksum 0x41ac (correct), seq 1:21, win 10, length 2015:01:27.116881 IP (tos 0x0, ttl 64, id 0, offset 0, flags [none], proto TCP (6), length 60)    
10.224.21.249.1025 > 192.168.1.1.1024: Flags [S], cksum 0xc540 (correct), seq 1:21, win 10, length 2015:01:27.116882 IP (tos 0x0, ttl 64, id 0, offset 0, flags [none], proto TCP (6), length 60)    
10.223.153.145.1025 > 192.168.1.1.1024: Flags [S], cksum 0x41a9 (correct), seq 1:21, win 10, length 20
Тесты проводились на железе  Intel(R) Core(TM) i7 CPU 950  @ 3.07GHz. На более слабом чипе Intel(R) Xeon(R) CPU E5-2407 0 @ 2.20GHz удалось достичь лишь 12.75 MPPS просто потому что чип медленный.

Content of /etc/rc.local for auto start:
echo 64 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages
/usr/src/MoonGen/bind-interfaces.sh

Friday, 17 April 2015

Сборка модуля netmap на Debian 7/8 с сетевой Intel 82599 с использование драйверов SourceForge

Если Вас устраивают обычные драйверы из дистрибутива, используйте вот эту инструкцию, она намного проще: http://www.stableit.ru/2015/03/netmap-ixgbe.html

Проект netmap не блещет понятной информацией, но я постараюсь упростить Вам немного жизнь.

Вам можно взять пропатченную мною версию драйвера, прошу, в спец репо (там лежит самая новая на 2е марта 2015го года версия драйвера ixgbe с Sourceforge): https://github.com/pavel-odintsov/ixgbe-linux-netmap  Эта версия отлично работает как с ядром 3.2 (Wheezy), так и с ядром 3.16 (Jessie).

Для работ нам нужно будет  установить довольно фундаментальных тулзы:
apt-get install -y make git gcc

Для начала создадим фейковую иерархию повторяющую структуру попок ядра Linux и положим в нее уже пропатченный драйвер ixgbe c Sourceforge:
cd /usr/src
git clone https://github.com/pavel-odintsov/ixgbe-linux-netmap.git
После этого приступаем к сборке модуля netmap вместе с драйвером ixgbe (почему мы собираемся из ветки next потому что стабильная имеет крайне критичные баги):
# Debian 7
apt-get install -y linux-headers-3.2.0-4-amd64
# Debian 8
apt-get install -y linux-headers-3.16.0-4-amd64
cd /usr/src
git clone https://github.com/luigirizzo/netmap.git
cd netmap/LINUX/
Накладывем патч sed'ом:
sed -i 's/#define ixgbe_driver_name netmap_ixgbe_driver_name/\/\/\0/' ixgbe_netmap_linux.h
sed -i 's/^char ixgbe_driver_name\[\]/\/\/\0/' ixgbe_netmap_linux.h
Создаем override конфиг:
vim ixgbe-override
Следующим содержимым:
ixgbe-dst := ixgbe
ixgbe-patch := #(leave empty)
ixgbe-src := /usr/src/ixgbe-linux-netmap/ixgbe-3.23.2.1/src/
Также можно заменить ixgbe-3.23.2.1 на ixgbe-4.1.5, чтобы использовать обновленную версию драйвера.

И наконец-то собираемся:
./configure  --override=ixgbe-override --drivers=ixgbe
make
Выгружаем текущий драйвер ixgbe (обычно он идет из поставки ядра) - будьте внимательны, не выгрузите драйвер той сетевой по которой находитесь на машине:
rmmod ixgbe
Загружаем (последовательность важна):
insmod /usr/src/netmap/LINUX/netmap.ko
insmod /usr/src/netmap/LINUX/ixgbe/ixgbe.ko
Убеждаемся, что netmap поднялся:
ls -al /dev/netmap
crw------- 1 root root 10, 59 Oct 29 03:51 /dev/netmap
Кроме этого, вот так выглядит dmesg, если все подцепилось успешно:
[153334.585563] 291.669424 [3083] netmap_init               run mknod /dev/netmap c 10 59 # error 0
[153334.585631] netmap: loaded module
[153334.855803] Intel(R) 10 Gigabit PCI Express Network Driver - version 3.23.2.1
[153334.855853] Copyright (c) 1999-2014 Intel Corporation.
[153334.856074] ixgbe 0000:0a:00.0: setting latency timer to 64
[153334.856209] ixgbe: 0000:0a:00.0: ixgbe_check_options: FCoE Offload feature enabled
[153335.015669] ixgbe 0000:0a:00.0: irq 74 for MSI/MSI-X
[153335.015681] ixgbe 0000:0a:00.0: irq 75 for MSI/MSI-X
[153335.015690] ixgbe 0000:0a:00.0: irq 76 for MSI/MSI-X
[153335.015699] ixgbe 0000:0a:00.0: irq 77 for MSI/MSI-X
[153335.015708] ixgbe 0000:0a:00.0: irq 78 for MSI/MSI-X
[153335.017961] ixgbe 0000:0a:00.0: PCI Express bandwidth of 32GT/s available
[153335.017987] ixgbe 0000:0a:00.0: (Speed:5.0GT/s, Width: x8, Encoding Loss:20%)
[153335.018104] ixgbe 0000:0a:00.0: eth4: MAC: 2, PHY: 9, SFP+: 3, PBA No: E68793-006
[153335.018141] ixgbe 0000:0a:00.0: 90:e2:ba:4a:d8:dc
[153335.018164] ixgbe 0000:0a:00.0: eth4: Enabled Features: RxQ: 4 TxQ: 4 FdirHash DCA RSC
[153335.019351] ixgbe 0000:0a:00.0: eth4: Intel(R) 10 Gigabit Network Connection
[153335.019380] 292.103764 [2720] netmap_attach             success for eth4 tx 4/512 rx 4/512 queues/slots
[153335.019536] ixgbe 0000:0a:00.1: setting latency timer to 64
[153335.019669] ixgbe: 0000:0a:00.1: ixgbe_check_options: FCoE Offload feature enabled
[153336.166573] ixgbe 0000:0a:00.1: irq 89 for MSI/MSI-X
[153336.166584] ixgbe 0000:0a:00.1: irq 90 for MSI/MSI-X
[153336.166593] ixgbe 0000:0a:00.1: irq 91 for MSI/MSI-X
[153336.166602] ixgbe 0000:0a:00.1: irq 92 for MSI/MSI-X
[153336.166611] ixgbe 0000:0a:00.1: irq 93 for MSI/MSI-X
[153336.168899] ixgbe 0000:0a:00.1: PCI Express bandwidth of 32GT/s available
[153336.168927] ixgbe 0000:0a:00.1: (Speed:5.0GT/s, Width: x8, Encoding Loss:20%)
[153336.169044] ixgbe 0000:0a:00.1: eth5: MAC: 2, PHY: 1, PBA No: E68793-006
[153336.169069] ixgbe 0000:0a:00.1: 90:e2:ba:4a:d8:dd
[153336.169092] ixgbe 0000:0a:00.1: eth5: Enabled Features: RxQ: 4 TxQ: 4 FdirHash DCA RSC
[153336.170307] ixgbe 0000:0a:00.1: eth5: Intel(R) 10 Gigabit Network Connection
[153336.170338] 293.256101 [2720] netmap_attach             success for eth5 tx 4/512 rx 4/512 queues/slots
[153336.170491] ixgbe 0000:0d:00.0: setting latency timer to 64
[153336.170624] ixgbe: 0000:0d:00.0: ixgbe_check_options: FCoE Offload feature enabled
[153336.330127] ixgbe 0000:0d:00.0: irq 94 for MSI/MSI-X
[153336.330138] ixgbe 0000:0d:00.0: irq 95 for MSI/MSI-X
[153336.330147] ixgbe 0000:0d:00.0: irq 96 for MSI/MSI-X
[153336.330156] ixgbe 0000:0d:00.0: irq 97 for MSI/MSI-X
[153336.330165] ixgbe 0000:0d:00.0: irq 98 for MSI/MSI-X
[153336.332445] ixgbe 0000:0d:00.0: PCI Express bandwidth of 32GT/s available
[153336.332474] ixgbe 0000:0d:00.0: (Speed:5.0GT/s, Width: x8, Encoding Loss:20%)
[153336.332591] ixgbe 0000:0d:00.0: eth6: MAC: 2, PHY: 9, SFP+: 3, PBA No: E68793-006
[153336.332628] ixgbe 0000:0d:00.0: 90:e2:ba:4a:d8:e8
[153336.332651] ixgbe 0000:0d:00.0: eth6: Enabled Features: RxQ: 4 TxQ: 4 FdirHash DCA RSC
[153336.333845] ixgbe 0000:0d:00.0: eth6: Intel(R) 10 Gigabit Network Connection
[153336.333875] 293.419834 [2720] netmap_attach             success for eth6 tx 4/512 rx 4/512 queues/slots
[153336.334038] ixgbe 0000:0d:00.1: setting latency timer to 64
[153336.334174] ixgbe: 0000:0d:00.1: ixgbe_check_options: FCoE Offload feature enabled
[153337.477010] ixgbe 0000:0d:00.1: irq 99 for MSI/MSI-X
[153337.477021] ixgbe 0000:0d:00.1: irq 100 for MSI/MSI-X
[153337.477030] ixgbe 0000:0d:00.1: irq 101 for MSI/MSI-X
[153337.477039] ixgbe 0000:0d:00.1: irq 102 for MSI/MSI-X
[153337.477048] ixgbe 0000:0d:00.1: irq 103 for MSI/MSI-X
[153337.479378] ixgbe 0000:0d:00.1: PCI Express bandwidth of 32GT/s available
[153337.479406] ixgbe 0000:0d:00.1: (Speed:5.0GT/s, Width: x8, Encoding Loss:20%)
[153337.479523] ixgbe 0000:0d:00.1: eth7: MAC: 2, PHY: 1, PBA No: E68793-006
[153337.479548] ixgbe 0000:0d:00.1: 90:e2:ba:4a:d8:e9
[153337.479570] ixgbe 0000:0d:00.1: eth7: Enabled Features: RxQ: 4 TxQ: 4 FdirHash DCA RSC
[153337.480771] ixgbe 0000:0d:00.1: eth7: Intel(R) 10 Gigabit Network Connection
[153337.480800] 294.568133 [2720] netmap_attach             success for eth7 tx 4/512 rx 4/512 queues/slots


После этого в случае мирроринга трафика включаем передатчики и активируем режим прослушки:
ifconfig eth3 up
ifconfig eth4 up
ifconfig eth3 promisc
ifconfig eth4 promisc

Собираем примеры:
cd /usr/src/netmap/examples
make
Пробуем послушать трафик:
./pkt-gen -i eth3 -f rx
После этого радуемся пришедшему трафику:
./pkt-gen -i eth3 -f rx
680.697796 main [1624] interface is eth3
680.698022 extract_ip_range [275] range is 10.0.0.1:0 to 10.0.0.1:0
680.698032 extract_ip_range [275] range is 10.1.0.1:0 to 10.1.0.1:0
680.979194 main [1807] mapped 334980KB at 0x7f25d7fd4000
Receiving from netmap:eth3: 8 queues, 1 threads and 1 cpus.
680.979231 main [1887] Wait 2 secs for phy reset
682.979291 main [1889] Ready...
682.979330 nm_open [457] overriding ifname eth3 ringid 0x0 flags 0x1
683.980349 main_thread [1421] 137263 pps (137391 pkts in 1000935 usec)
684.981295 main_thread [1421] 124018 pps (124135 pkts in 1000945 usec)
685.259717 main_thread [1421] 120051 pps (33425 pkts in 278423 usec)

Wednesday, 15 April 2015

Реализация TFO TCP Fast Open на примере ядра Linux 3.19

В данной статьей я кратко постараюсь объяснить, как устроен внутри Linux ядра механизм TCP Fast Open позволяющий обойтись без 3 этапного установления соединения.

Суть его сводится к тому, что если и клиент и сервер имеют поддержку TFO, о которой сообщают за счет специального флага в TCP пакете (а также сопровождающего его TFO Cookie - секретного ключа), который получают при установке обычного 3-х этапного соединения, то второе и последующие соединения с тем же сервером они могут осуществлять сразу высылая данные в SYN пакете, а не осуществляя повторную установку соединения. Авторизация что этот пакет является легитимным осуществляется за счет проверки TFO Cookie (который ранее был получен от сервера).

Во-первых! Чтобы активировать поддержку и клиентского и серверного TFO на обоих машинах для теста нужно сделать следующее:
sysctl -w net.ipv4.tcp_fastopen=3

Если не задано обратное, то генерация ключей для TFO cookie осуществляется автоматически.

Если же требуется задать ключ вручную, можно использовать спец переменную ядра:
cat /proc/sys/net/ipv4/tcp_fastopen_key
00000000-00000000-00000000-00000000

Обработчик записи в эту переменную (функция proc_tcp_fastopen_key, файл net/ipv4/sysctl_net_ipv4.c) вызывает функцию tcp_fastopen_reset_cipher с параметрами - переданный ключ и его длина. По дефалту генерируется рандомный ключ посредством функции net_get_random_once. После этого создается контекст для шифрования с данным ключем посредством aes алгоритма. Контекст сохраняется в переменной tcp_fastopen_ctx.

Генерация куки для IPv4.

Тут все просто, собирается массив из 4х 32 битных чисел. Два - src и dst IP адреса для данного соединения, два числа еще - нули. После этого все это дело шифруется aes.

Генерация куки для IPv6.

А вот тут немного магии (зовется она CBC MAC: http://en.wikipedia.org/wiki/CBC-MAC). Сначала шифруется IP адрес источника (уже без паддинга нулями - 4 32 битных целых числе). После этого мы берем результат шифрования (4 32 битных числа) и xor-им с соответствующими 32 битными частями целевого IP адреса. После этого результата еще раз шифруем токеном и получаем итоговую cookie.

Кроме этого, судя по тексту из патча:

A simple cookie scheme together with capping the number of outstanding TFO requests (still in TCP_SYN_RECV state) to a limit per listener forms the main line of defense against spoofed SYN
attacks.

Число, которое передается как параметр для listen сокета посредством функции setsockopt(sockfd, SOL_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen)) используется, чтобы защититься от флуда TFO SYN'ами и перейти на обычный механизм установки соединения.

К сожалению, в процессе тестов мною было убито ядро 3.16, проблема оказалась апстримной и я очень надеюсь, что скоро будет решена :)

В Debian Jessie 8 пред релизной версии сломана поддержка TCP Fast Open сокетов

Вот такая хреновая тема :( Подробнее вот тут: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=782515

Баг апстримный: http://thread.gmane.org/gmane.linux.network/359588

Машину не валит, но сокеты лочит, так что уже назначен уровень Local DoS и можно ждать скорого фикса :)

Ура ура! Баг исправлен! Ждем ребилда ядра :) Следить удобно тут: https://packages.debian.org/sid/linux-image-3.16.0-4-amd64

Ура ура ура! Баг исправлен и доступен в стабильном репо свежего Debian Jessie! Все обновляемся! :)

Sunday, 29 March 2015

Стабильность работы netmap-ipfw на Linux

Тест выполнялся почти 3е суток, нагрузка со стороны генератора флуда была около 6MPPS, рандомного udp флуда.
ps aux|grep kipfwroot     19036 72.1  0.0 676328  2728 pts/2    R    Mar26 2731:56 ./kipfw netmap:eth4-0 netmap:eth6-0root     19037 68.9  0.0 676328  2728 pts/2    R    Mar26 2610:52 ./kipfw netmap:eth4-1 netmap:eth6-1root     19038 69.7  0.0 676328  2728 pts/2    S    Mar26 2640:07 ./kipfw netmap:eth4-2 netmap:eth6-2root     19039 68.9  0.0 676328  2992 pts/2    S    Mar26 2610:41 ./kipfw netmap:eth4-3 netmap:eth6-3root     21088  0.0  0.0   7768   852 pts/1    S+   11:17   0:00 grep kipfw
Нагрузка на машине была почти предельная:
  [||||||||||||||||||||||||||||||||||||||||||         72.7%]     Tasks: 35, 55 thr, 47 kthr; 2 running  [|||||||||||||||||||||||||||||||||||||||            69.1%]     Load average: 2.15 2.60 2.69   [|||||||||||||||||||||||||||||||||||||||||          71.4%]     Uptime: 12 days, 11:33:08  [||||||||||||||||||||||||||||||||||||||||           68.2%]  Mem[|||||||                                     1332/32207MB]  Swp[                                                0/8190MB]

Но ничего не упало и паразитный трафик не прошел! :)

Wednesday, 18 March 2015

Контроль за состоянием php-fpm силами monit на Debian

Вот так:
check process php5-fpm with pidfile /var/run/php5-fpm.pid
  start program = "/etc/init.d/php5-fpm start"
  stop program  = "/etc/init.d/php5-fpm stop"
  if failed unixsocket /var/run/php5-fpm.sock  then restart
  if 3 restarts within 5 cycles then timeout

Tuesday, 17 March 2015

Фильтрация трафика силами сетевой карты

Очень редко при защите от DDoS кто-либо освещает эту тему и совершенно неоправданно.

Итак, как? Начнем с того, что у Вас должна быть приличная 10GE сетевая карточка (например, Intel XL710 или же Intel 82599 - я буду проводить тесты на нем). Сразу хочу оговориться, что драйверы для сетевой карты нужно брать НЕ из дистрибутива (они очень малофункциональны), а из проекта ixgbe на Sourceforge.

Во-вторых, нужен механизм управления этим всем делом. Обычно, это делается силами ethtool.

Приступим!

Для начала нам нужно сконфигурировать сетевую и ее драйвер:
vim /etc/modprobe.d/ixgbe.conf
И добиваем к существующим там такой параметр (он нужен чтобы выделить 32 тысячи ):
FdirPballoc=3,3,3,3
После этого драйвер нужно передернуть и поднять ифейсы заново:
rmmod ixgbe
modprobe ixgbe
ifconfig 11.22.33.44. eth4
Что же мы сделали? Мы включили функциональность фильтрации сетевой. Почему именно 3?

Есть три варианта значения поля FdirPballoc и мы выбрали наибольший размер, чтобы побольше правил набить:
1 = 8k hash filters or 2k perfect filters
2 = 16k hash filters or 4k perfect filters
3 = 32k hash filters or 8k perfect filters (array of int)
Убеждаемся по dmesg, что все зацепилось:
dmesg|grep 'Flow Director'
[45847.024851] ixgbe: Flow Director packet buffer allocation set to 3
[45847.024874] ixgbe: 0000:0a:00.0: ixgbe_check_options: Flow Director will be allocated 256kB of packet buffer
Включаем поддержку ntuple фильтров на уровне сетевой:
ethtool -K eth4 ntuple on
Итак, посмотрим список наших правил - он должен быть пуст:
ethtool --show-ntuple eth4
4 RX rings available
Total 0 rules
А вот далее идет сложный синтаксис и поэтому привожу выдачу ethtool --help:
        ethtool -N|-U|--config-nfc|--config-ntuple DEVNAME    Configure Rx network flow classification options or rules
        rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|tcp6|udp6|ah6|esp6|sctp6 m|v|t|s|d|f|n|r... |
        flow-type ether|ip4|tcp4|udp4|sctp4|ah4|esp4
            [ src %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]
            [ dst %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]
            [ proto %d [m %x] ]
            [ src-ip %d.%d.%d.%d [m %d.%d.%d.%d] ]
            [ dst-ip %d.%d.%d.%d [m %d.%d.%d.%d] ]
            [ tos %d [m %x] ]
            [ l4proto %d [m %x] ]
            [ src-port %d [m %x] ]
            [ dst-port %d [m %x] ]
            [ spi %d [m %x] ]
            [ vlan-etype %x [m %x] ]
            [ vlan %x [m %x] ]
            [ user-def %x [m %x] ]
            [ action %d ]
            [ loc %d]] |
        delete %d
Итак, запустим на машину DDoS атаку вот таким паттерном:
12:45:19.050037 IP 10.10.10.100.41356 > 10.10.10.200.61598: UDP, length 18
12:45:19.050045 IP 10.10.10.100.9967 > 10.10.10.200.24210: UDP, length 18
12:45:19.050052 IP 10.10.10.100.17254 > 10.10.10.200.44345: UDP, length 18
12:45:19.050061 IP 10.10.10.100.17516 > 10.10.10.200.41543: UDP, length 18
12:45:19.050069 IP 10.10.10.100.29307 > 10.10.10.200.60769: UDP, length 18
12:45:19.050078 IP 10.10.10.100.56313 > 10.10.10.200.49897: UDP, length 18
12:45:19.050085 IP 10.10.10.100.17761 > 10.10.10.200.6767: UDP, length 18
12:45:19.050093 IP 10.10.10.100.24303 > 10.10.10.200.12295: UDP, length 18
12:45:19.050101 IP 10.10.10.100.27105 > 10.10.10.200.52313: UDP, length 18
12:45:19.050109 IP 10.10.10.100.32141 > 10.10.10.200.55003: UDP, length 18
12:45:19.050119 IP 10.10.10.100.10274 > 10.10.10.200.11494: UDP, length 18

Итог - плачевен, машина почти убита нагрузкой:
%Cpu(s):  0.0 us,  0.0 sy,  0.0 ni, 75.0 id,  0.0 wa,  0.0 hi, 75.0 si,  0.0 st

Попробуем собрать фильтр под эту атаку.
ethtool --config-ntuple eth4 flow-type udp4 src-ip 10.10.10.100 m 255.255.255.0 action -1
Как можно догадаться, -1 означает безусловный drop трафика.

Посмотрим, что у нас получилось:
ethtool --show-ntuple eth4
4 RX rings available
Total 1 rules

Filter: 8189
    Rule Type: UDP over IPv4
    Src IP addr: 0.0.0.100 mask: 255.255.255.0
    Dest IP addr: 0.0.0.0 mask: 255.255.255.255
    TOS: 0x0 mask: 0xff
    Src port: 0 mask: 0xffff
    Dest port: 0 mask: 0xffff
    VLAN EtherType: 0x0 mask: 0xffff
    VLAN: 0x0 mask: 0xffff
    User-defined: 0x0 mask: 0xffffffffffffffff
    Action: Drop
Как удалить правило? Проще простого:
ethtool --config-ntuple eth4 delete 8189
Вуаля, при той же атаке в 7mpps мы не наблюдаем нагрузки вообще:
%Cpu(s):  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
При этом убедиться, что правило flow director работает можно очень просто:
ethtool -S eth4 |grep fdir
     fdir_match: 916143392
     fdir_miss: 139427055
     fdir_overflow: 0
Вот таким образом можно сильно облегчить жизнь Linux боксу под атакой :) Но не стоит забывать, что функциональность по фильтрации довольно слабая - только IP и порты для входящего и исходящего трафика.

Но, например, таким образом можно сделать крутую защиту от UDP амплификации. И выживать пока не кончится аплинк :)

Monday, 16 March 2015

Установка exabgp - швейцарский нож для готовки BGP и flow spec

В Debian:
apt-get install -y python-pip

И ставим через pip:
pip install exabgp
 Блин, и чего с ней дальше делать :) Документация гхм...

Thursday, 12 March 2015

Установка и использование ipset на Debian 7 Wheezy

Просто бесконечно проста с учетом того, что ipset теперь идет в поставке ядра:
dpkg -S /lib/modules/3.2.0-4-amd64/kernel/net/netfilter/ipset/ip_set_list_set.ko
linux-image-3.2.0-4-amd64: /lib/modules/3.2.0-4-amd64/kernel/net/netfilter/ipset/ip_set_list_set.ko
Ставим зависимости:
apt-get install ipset 
Создаем хэш:
ipset --create blacklist iphash --hashsize 4096
Смотрим его содержимое:
ipset --list
Name: blacklist
Type: hash:ip
Header: family inet hashsize 4096 maxelem 65536
Size in memory: 65656
References: 0
Members:
Добавляем несколько IP в список блокировки:
ipset --add blacklist 41.231.136.121
ipset --add blacklist 37.236.253.170
ipset --add blacklist 37.236.239.42
Убеждаемся, что они добавлены:
ipset --list
Name: blacklist
Type: hash:ip
Header: family inet hashsize 4096 maxelem 65536
Size in memory: 65704
References: 0
Members:
41.231.136.121
37.236.253.170
37.236.239.42
Добавляем правило iptables для отсечения товарищей, кто в этом списке:
iptables -I INPUT -m set --match-set blacklist src -p TCP --destination-port 80 -j DROP
В итоге это будет выглядеть примерно так:
iptables -nvL
Chain INPUT (policy ACCEPT 2822 packets, 188K bytes)
 pkts bytes target     prot opt in     out     source               destination        
    0     0 DROP       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            match-set blacklist src tcp dpt:80

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination        

Chain OUTPUT (policy ACCEPT 1882 packets, 320K bytes)
 pkts bytes target     prot opt in     out     source               destination          

Огромное преимущество ipset в том, что он сам проверяет на наличие дубликатов (на самом деле это приятное следствие из его структуры данных - хэша) и не нужно заниматься этим самостоятельно:
ipset --add blacklist 41.176.136.101
ipset v4.2: 41.176.136.101 is already in set blacklist.

Удалять IP из бана нужно следующим образом:
ipset --del blacklist 41.176.136.101

Полностью очистить спсиок блокировки можно так:
ipset --flush blacklist

Использования модуля при ну очень большом числе IP показывает, что он весьма стабилен и отлично работает:
ipset  -L | wc -l
43815
Баги/фичи:  "ipset v4.2: IP/port/element is outside of the set or set is full", при достжении размера очереди 65 тысячам IP:
ipset -L |wc -l
65541
Фикс - нет фикса (http://flug.org.ua/lists/debian-russian/71086/) Как обходник можно создать кучу хэшей и пропускать трафик через них.

Еще будет полезной фича ipset save, с помощью которой можно сделать восстановление/сохранение содержимого списков при перезагрузке:
ipset save
create blacklist hash:ip family inet hashsize 4096 maxelem 65536
add blacklist 41.231.136.121
add blacklist 37.236.253.170
add blacklist 37.236.239.42

Источники: http://lmn.name/archives/331 http://daemonkeeper.net/781/mass-blocking-ip-addresses-with-ipset/


Sunday, 8 March 2015

Сброс полного содержимого BGP таблица в демоне Quagga

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

Осуществляется вот так:
vtysh -d bgpd -c "conf term" -c "dump bgp routes-mrt /var/run/bgpdata/rib.%F.%H%M 10m"
Отключается вот так:
vtysh -d bgpd -c "conf term" -c "no dump bgp routes-mrt /var/run/bgpdata/rib.%F.%H%M 10m"
Стоит отметить, что папка /var/run/bgpdata должна существовать и принадлежать пользователю quagga:quagga.

Если хотите вбить в конфиг, то это будет выглядеть вот так:
dump bgp routes-mrt /var/run/bgpdata/rib.%F.%H%M 10m
Стоит отметить, что внутри этого дампа (его размер считается как 40 мегабайт умноженное на число аплинков от которых принимается Full Table BGP).

Он в бинарном формате и чтобы конвертировать в текст понадобится спец тулза, которой конвертируем в текстовый вид (и 114 мб для 3*Full BGP превратятся сразу же в 450 мб в текстовом формате):
/opt/libbgpdump/bgpdump rib.2015-03-08.2010 -O rib.2015-03-08.2010.parsed 

За исследование и реализацию огромное спасибо Andrey Ziltsov :)

Wednesday, 4 March 2015

Использование решения на базе Linux и netmap-ipfw для суперскоростной фильтрации паразитного трафика

Последнее время стали довольно распространены высокоскоростные атаки, осуществляемые с использованием различных вариантов усиления (amplification) трафика.

Как же с ними бороться? Довольно сложно, это стоит понимать. Дешевые решения в виде ACL на 10GE свиче либо аппаратных правил на NIC (сетевой карте) - могут блокировать лишь часть паразитного трафика с очень ограниченным набором параметров - src/dst IP, src/dst port и протокол.

Более серьезные решения требуют привлечения либо высокопроизводительных роутеров (речь про роутеры класса Juniper MX 120+, и к слову, возможности фильтрации трафика у роутеров тоже весьма ограничены) либо аппаратных фаерволлов, например, от Arbor. Роутеры стоят огромных денег, но почти всегда есть в ДЦ - это плюс. А специализированное железо от Arbor стоит совершенно непомерные суммы.

Итак, наше решение софт бокс-фильтр, машина 10GE картами, кучей процессорных мощностей и Linux либо FreeBSD на борту.

Стоит понимать, что стандартными средствами того же Linux атаку в 10Mpps не отбить, в конце концов, он просто упадет, например, вот так. Во FreeBSD ситуация во многом похожая и еще более усложняющаяся (для меня) не особо хорошим пониманием этой ОС.

Поэтому в качестве решения я обратился к системам прямого доступа к сетевой карте класса netmap, PF_RING, DPDK, а именно - мы будем использовать netmap, потому что он очень быстр, не требует лицензии и под него есть портированный фаерволл ipwf.

Итак, приготовим машину на Debian 7, с сетевыми картами ixgbe с по меньшей мере двумя интефейсами. Так как машина должна подключаться в разрез между атакуемой машиной и аплинком.

Сборка довольно проста, сначала нужно собрать netmap со всеми драйверами и загрузить его.

После этого нужно установить в систему заголовочные файлы для netmap, чтобы собрать тулкит:
Стягиваем заголовки:
cd /usr/include/net
wget https://raw.githubusercontent.com/luigirizzo/netmap/master/sys/net/netmap_user.h
wget https://raw.githubusercontent.com/luigirizzo/netmap/master/sys/net/netmap.h
Собираем:
cd /usr/src
git clone https://github.com/luigirizzo/netmap-ipfw.git
cd netmap-ipfw
make
Запускаем:
./kipfw netmap:eth4 netmap:eth6
После этого можем загрузить тестовое правило в ipfw:

cd ipfw
./ipfw add 1 deny tcp from any to any 80 in
Для испытания насколько это решение хорошо в продакшене я запустил syn флуд в 7mpps с тестовой машины силами trafgen.

Метрики моей  тесты машины (а это слабый CPU E5-2407 0 @ 2.20GHz x 4) на картинке:
top - 13:33:05 up 3 min,  2 users,  load average: 0.44, 0.13, 0.05
Tasks:  78 total,   2 running,  76 sleeping,   0 stopped,   0 zombie
%Cpu(s): 10.0 us, 14.8 sy,  0.0 ni, 74.6 id,  0.0 wa,  0.0 hi,  0.7 si,  0.0 st
KiB Mem:  32980328 total,   546592 used, 32433736 free,    45320 buffers
KiB Swap:  8387580 total,        0 used,  8387580 free,    32204 cached

  PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND                                                                                 
 3105 root      20   0  660m 9060 8908 R  99.5  0.0   0:25.36 kipfw    


  1  [|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||100.0%]     Tasks: 26, 3 thr, 52 kthr; 2 running
  2  [                                                             0.0%]     Load average: 0.60 0.19 0.07
  3  [                                                             0.0%]     Uptime: 00:03:48
  4  [|                                                            0.7%]
  Mem[|||                                                   458/32207MB]
  Swp[                                                         0/8190MB]
Как можно видеть, машина прогрузилась лишь на 1/5, но одно ядро выгружено полностью (об этом отдельно).

Вполне неплохой показатель для такого слабого железа!

Теперь попробуем ту же самую задачу простого бриджинга сделать на Linux.

Ставим бридж утилс:
apt-get install -y bridge-utils
Добавляем интерфейсы в него:
brctl addbr mybridge
brctl addif mybridge eth4
brctl addif mybridge eth6
ifconfig mybridge up
И после этого вливаем те же 7mpps:
 1  [||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||99.1%]     Tasks: 25, 3 thr, 48 kthr; 2 running
  2  [|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||100.0%]     Load average: 0.47 0.23 0.15
  3  [|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||100.0%]     Uptime: 1 day, 14:24:01
  4  [||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||99.1%]
  Mem[||||                                                  497/32207MB]
  Swp[                                                         0/8190MB]


Шапка top выглядит еще более ужасающе:
top - 13:21:10 up 1 day, 14:24,  2 users,  load average: 1.57, 0.53, 0.26
Tasks:  73 total,   5 running,  68 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.0 sy,  0.0 ni,  0.4 id,  0.0 wa,  0.0 hi, 99.6 si,  0.0 st
KiB Mem:  32980328 total,   812976 used, 32167352 free,    40784 buffers
KiB Swap:  8387580 total,        0 used,  8387580 free,   263172 cached

  PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND                                                                                 
   15 root      20   0     0    0    0 R  93.5  0.0  57:08.71 ksoftirqd/2                                                                             
   10 root      20   0     0    0    0 R  90.9  0.0  39:51.09 ksoftirqd/1                                                                             
    3 root      20   0     0    0    0 R  65.8  0.0  71:59.15 ksoftirqd/0                                                                             
   19 root      20   0     0    0    0 R  64.8  0.0  59:43.95 ksoftirqd/3                                                                             
 2806 root      20   0 20520  824  548 S   1.3  0.0   0:12.81 irqbalance                                                                              
 4723 root      20   0     0    0    0 S   1.0  0.0   0:18.05 kworker/1:2                                                                             
  342 root      20   0     0    0    0 S   0.7  0.0   0:13.04 kworker/2:1                                                                             
 2866 ntp       20   0 39076 2404 1764 S   0.7  0.0   0:08.80 ntpd                                                                                    
 5163 root      20   0     0    0    0 S   0.7  0.0   0:32.55 kworker/0:1    
Как можете видеть - Linux с этой задачей не справился потому что в нем используется схема с многократным копированием пакета вместо одноразового. Кроме этого, сам по себе стек Linux довольно тяжел и плохо приспособлен к подобной нагрузке по умолчанию.

А теперь попробуем силами все того же netmap-ipfw отбить эту атаку по отпечатку. А именно используя ее снимок из tcpdump:
11:43:10.008418 IP 198.18.51.106.62978 > 10.10.10.248.http: Flags [S], seq 1137192741, win 16, length 0
11:43:10.008419 IP 198.18.51.93.34560 > 10.10.10.113.http: Flags [S], seq 4245548258, win 16, length 0
11:43:10.008419 IP 198.18.51.98.30252 > 10.10.10.89.http: Flags [S], seq 1765400726, win 16, length 0
11:43:10.008420 IP 198.18.51.144.19980 > 10.10.10.91.http: Flags [S], seq 1052340006, win 16, length 0
11:43:10.008420 IP 198.18.51.30.38034 > 10.10.10.38.http: Flags [S], seq 2198215300, win 16, length 0
11:43:10.008421 IP 198.18.51.140.60388 > 10.10.10.133.http: Flags [S], seq 2831049352, win 16, length 0

В Linux блокировка такого трафика была бы задачей нетривиальной, но тут мы можем попробовать использовать необычайно малый размер окна и отсутствие опций tcp пакета вообще (в реальной жизни это нонсенс):
./ipfw add 8 deny tcp from any to any tcpwin 16 tcpdatalen 0
Сразу убеждаемся, что в правило начал лететь трафик:
./ipfw -a list
connected to 127.0.0.1:5555
nalloc 2248 nbytes 124 ptr (nil)
00008 578904841 23156193640 deny tcp from any to any tcpwin 16 tcpdatalen 0
65535  18831554   753262160 allow ip from any to any
Нагрузка машины-фильтра при этом была в рамках разумного:
top - 13:46:15 up 16 min,  2 users,  load average: 0.87, 0.65, 0.40
Tasks:  74 total,   2 running,  72 sleeping,   0 stopped,   0 zombie
%Cpu(s): 21.8 us,  3.0 sy,  0.0 ni, 74.7 id,  0.0 wa,  0.0 hi,  0.4 si,  0.0 st
KiB Mem:  32980328 total,   547800 used, 32432528 free,    45708 buffers
KiB Swap:  8387580 total,        0 used,  8387580 free,    32824 cached

 Как я уже обращал внимание, процесс kipfw выедает одно ядро полностью и это будет (если уже не является) причиной провалов в трафике, потому что он не успевает отбрабатывать весь проходящий трафик корректно.

Что с этим делать? Нужно делать патчи для kipfw для параллельной обработки либо попробовать запустить число инстансов kipfw по числу аппаратных очередей на сетевой карте. Таким образом в самом худшем случае на каждый процессор выйдет нагрузка не более чем 14/4=3.5Mpps на ядро, что в принципе разумная цифра.

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

Если у кого есть желание присоединиться к проекту в качестве тестера или разработчика - мои контакты справа.

Monday, 2 March 2015

Сборка netmap с поддержкой ixgbe драйвера из поставки дистрибутива


Как гайд для начала рекомендую следующую статью: http://www.stableit.ru/2014/10/netmap-debian-7-wheezy-intel-82599.html

Обращаю внимание, что репо netmap переехал и новый адрес его такой: https://github.com/luigirizzo/netmap.git

Build netmap on Debian 7 Wheezy with ixgbe 10GE NIC (82599):

Get kernel sources:
cd /usr/src
apt-get source  linux-image-3.2.0-4-amd64
Стягиваем код netmap:
cd /usr/src
git clone https://github.com/luigirizzo/netmap.git
cd netmap/LINUX/
Собираем netmap и драйвер:
./configure --kernel-sources=/usr/src/linux-3.2.65 --drivers=ixgbe
make
make install

Load modules:
insmod ./netmap.ko
modprobe mdio
modprobe ptp
modprobe dca
insmod ixgbe/ixgbe.ko
Стоит обратить внимание, что данный режим работы единственный, стабильно работы которого удалось достичь на Linux.

Чтобы добиться запуска при загрузке машины нужно сделать что-то вот такое:
rmmod ixgbe
insmod /usr/src/netmap/LINUX/netmap.ko
modprobe mdio
modprobe ptp
modprobe dca
insmod /usr/src/netmap/LINUX/ixgbe/ixgbe.ko

Thursday, 12 February 2015

Установка htop на FreeBSD 10

Стандартный top на FreeBSD очень не интуитивен, поэтому воткнем же htop!

Итак, ставим:
pkg install htop

Активируем модули эмуляции Linux:
echo 'linux_load="YES"' >> /boot/loader.conf
echo 'linux_enable="YES"' >> /etc/rc.conf

Добавляем монтирование Linux proc fs в /etc/fstab:
linproc         /compat/linux/proc      linprocfs         rw 0 0

После этого перезагружаемся либо делаем:
mount linproc
И наслаждаемся видом htop!