Jump to content
Калькуляторы

Тюнинг Linux под NAT

Есть у меня сервер, на котором крутится контроллер UniFi с БД MySQL, сетевые сервисы (DHCP, DNS) и который раздает интернет пользователям UniFi.

Раньше это был сервер на ксеоне под 64-разрядной FreeBSD 8.2, для NAT использовался pf. Особо не тюнинговался, разве что размеры буферов чуть увеличил.

Сейчас временно (пока будет готовиться сервер) сервис перенесен на обычный ПК c i7 под 64-разрядным Debian 7, основная причина переноса — отсутствие под FreeBSD клиента Oracle (мне нужно работать с СУБД Oracle). Набор софта идентичный, только для NAT используется iptables.

И по итогам примерно недели заметил следующее.

1. Время от времени на сервер находят небольшие периоды задумчивости, когда он в течении 2-3 секунд сильно тормозит. На интернет-доступе сказывается не очень заметно, но при подключении по SSH заметно. С чем связано — непонятно, на запущенном htop каких-то всплесков активности не замечаю.

2. По производительности компьютеры вроде бы сопоставимы (E5620 2.4GHz и i7-4770 3.4GHz), ПК даже производительнее. Однако при одинаковой нагрузке (30 точек доступа, около сотни клиентов) на ПК Unifi более тормозной, информация с точек на контроллере обновляется медленнее.

3. Но самое главное, NAT работает как-то странно. На pf все работало как часы. На iptables время от времени становятся недоступными определенные порты и хосты. Если запустить следующий скрипт (заново настраивающий iptables), то все начинает работать на следующие несколько часов:

#!/bin/sh

IPT=`which iptables`
IF_EXT=eth1.100
IF_WIFI=eth1.900
IP_EXT=`ip -o -4 addr show dev eth1.100 | sed -ne 's/.*inet \(.*\) brd.*/\1/p'`
IP_EXT=${IP_EXT%/*}
NET_WIFI="10.10.0.0/16"
NET_UNIFI="10.10.10.0/24"
FW="$IPT -t filter"
NAT="$IPT -t nat"

## Filter section
$FW -F
$FW -X
$FW -Z
$FW -P INPUT DROP
$FW -P OUTPUT ACCEPT
$FW -P FORWARD DROP

## Filter input invalid and bad packets
$FW -N INVALID
$FW -A INVALID -p tcp ! --syn -m state --state NEW -j DROP
$FW -A INVALID -p tcp --tcp-flags ALL ALL -j DROP
$FW -A INVALID -p tcp --tcp-flags ALL NONE -j DROP
$FW -A INVALID -p tcp --tcp-flags ALL SYN -m state --state ESTABLISHED -j DROP
$FW -A INVALID -p icmp --fragment -j DROP
$FW -A INVALID -m state --state INVALID -j DROP
$FW -A INVALID -d 255.255.255.255 -j DROP
$FW -A INVALID -j RETURN


## Internet services
$FW -N INTERNET
# Allow ICMP
$FW -A INTERNET -p icmp --icmp-type 0 -j ACCEPT
$FW -A INTERNET -j RETURN

## Hotspot services
$FW -N HOTSPOT
# Allow DHCP request and reply
$FW -A HOTSPOT -p udp --sport 67 --dport 68 -j ACCEPT
# Block foreign networks
$FW -A HOTSPOT ! -s $NET_WIFI -j DROP
# Allow ping reply
$FW -A HOTSPOT -p icmp --icmp-type 0  -j ACCEPT
$FW -A HOTSPOT -p icmp --icmp-type 3  -j ACCEPT
$FW -A HOTSPOT -p icmp --icmp-type 8  -j ACCEPT
$FW -A HOTSPOT -p icmp --icmp-type 11 -j ACCEPT
# Allow HTTP and HTTPS for clients
$FW -A HOTSPOT -p tcp --dport 80  -j ACCEPT
$FW -A HOTSPOT -p tcp --dport 443 -j ACCEPT
# Allow DNS queries for clients
$FW -A HOTSPOT -p tcp --dport 53  -j ACCEPT
$FW -A HOTSPOT -p udp --dport 53  -j ACCEPT
# Allow NTP queries for clients
$FW -A HOTSPOT -p udp --dport 123  -j ACCEPT
# Allow AP communications
$FW -A HOTSPOT -p tcp --dport 8080 -s $NET_UNIFI -j ACCEPT
$FW -A HOTSPOT -p tcp --dport 8443 -s $NET_UNIFI -j ACCEPT
$FW -A HOTSPOT -j RETURN

## Global rules
$FW -A INPUT -i $IF_LOOP -j ACCEPT
$FW -A INPUT -j INVALID
$FW -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Block bogons on external interface
$FW -A INPUT -i $IF_EXT    -s 10.0.0.0/8      -j DROP  # Private, class A
$FW -A INPUT -i $IF_EXT    -s 172.16.0.0/12   -j DROP  # Private, class B
$FW -A INPUT -i $IF_EXT    -s 192.168.0.0/16  -j DROP  # Private, class C
$FW -A INPUT -i $IF_EXT    -s 224.0.0.0/4     -j DROP  # Multicast, class D
$FW -A INPUT -i $IF_EXT    -s 240.0.0.0/5     -j DROP  # Reserved, class E
$FW -A INPUT -i $IF_EXT    -s 169.254.0.0/16  -j DROP  # Link-local
$FW -A INPUT -i $IF_EXT    -s 127.0.0.0/8     -j DROP  # Loopback
# Block foreign networks on internal interfaces
$FW -A INPUT -i $IF_INT  ! -s $NET_INT        -j DROP

# Main processing
$FW -A INPUT -i $IF_EXT -j INTERNET
$FW -A INPUT -i $IF_WIFI -j HOTSPOT
$FW -A INPUT -j LOG --log-prefix "INPUT DROP: "

## NAT section
$FW -A FORWARD -i $IF_WIFI -o $IF_EXT  -s $NET_WIFI ! -d $NET_INT -p icmp                   -j ACCEPT
$FW -A FORWARD -i $IF_WIFI -o $IF_EXT  -s $NET_WIFI ! -d $NET_INT -p tcp --dport 80         -j ACCEPT
$FW -A FORWARD -i $IF_WIFI -o $IF_EXT  -s $NET_WIFI ! -d $NET_INT -p tcp --dport 443        -j ACCEPT
$FW -A FORWARD -i $IF_WIFI -o $IF_EXT  -s $NET_WIFI ! -d $NET_INT -p tcp --dport 1024:49151 -j ACCEPT
$FW -A FORWARD -i $IF_WIFI -o $IF_EXT  -s $NET_WIFI ! -d $NET_INT -p udp --dport 53         -j ACCEPT
$FW -A FORWARD -i $IF_WIFI -o $IF_EXT  -s $NET_WIFI ! -d $NET_INT -p udp --dport 123        -j ACCEPT
$FW -A FORWARD -i $IF_WIFI -o $IF_EXT  -s $NET_WIFI ! -d $NET_INT -p udp --dport 1024:49151 -j ACCEPT
$FW -A FORWARD -i $IF_EXT  -o $IF_WIFI -m state --state ESTABLISHED,RELATED -j ACCEPT
$FW -A FORWARD -j LOG --log-prefix "FORWARD DROP: "
$NAT -F
$NAT -X
$NAT -Z
$NAT -A POSTROUTING -o $IF_EXT -s $NET_WIFI -p icmp --icmp-type 0 -j SNAT --to-source $IP_EXT
$NAT -A POSTROUTING -o $IF_EXT -s $NET_WIFI -p icmp --icmp-type 8 -j SNAT --to-source $IP_EXT
$NAT -A POSTROUTING -o $IF_EXT -s $NET_WIFI -p tcp                -j SNAT --to-source $IP_EXT
$NAT -A POSTROUTING -o $IF_EXT -s $NET_WIFI -p udp                -j SNAT --to-source $IP_EXT

Ошибок в правилах я не нахожу, но может просто глаз замылился.

Share this post


Link to post
Share on other sites

отсутствие под FreeBSD клиента Oracle (мне нужно работать с СУБД Oracle).

 

Вы плохо гуглили.

Install Oracle 11g Release 2 on FreeBSD 9

Share this post


Link to post
Share on other sites

1) Смотрите iotop.

3) Скорее всего, у вас забивается conntrack. Узнать можно, почитав dmesg|tail.

В конец /etc/sysctl.conf добавить:

net.ipv4.netfilter.ip_conntrack_max = 104857600
net.ipv4.netfilter.ip_conntrack_buckets = 2621440

Применить:

/sbin/sysctl -p

 

P.S.:

Пожалуйста, уберите с глаз моих этот скрипт, мне от него плакать хочется. Откройте для себя iptables-persistent.

Share this post


Link to post
Share on other sites

Вы плохо гуглили.

Да нет, гуглил я хорошо. Есть только два рабочих способа — установка клиента Oracle под эмулятором и использование JDBC. Второй способ мне не подходит, первый способ подходит только для небольших скриптов, т.к. для него хост-процесс (perl или php) тоже должен быть запущен под эмулятором.

Способ по ссылке я изучу, пока не совсем понятно, что там делается. Если используется виртуальный Linux для сборки бинарников — я это пробовал, во FreeBSD такие бинарники не работают.

 

3) Скорее всего, у вас забивается conntrack. Узнать можно, почитав dmesg|tail.

В dmesg вообще ни слова про conn.

Однако рекомендации учту, sysctl подправлю.

 

Откройте для себя iptables-persistent.

Зачем? Если только для того, чтобы сохранять правила после перезагрузки, то мне удобнее использовать скрипт, который к тому же можно подвесить на if-up.d

Share this post


Link to post
Share on other sites

Вы плохо гуглили.

Да нет, гуглил я хорошо. Есть только два рабочих способа — установка клиента Oracle под эмулятором и использование JDBC. Второй способ мне не подходит, первый способ подходит только для небольших скриптов, т.к. для него хост-процесс (perl или php) тоже должен быть запущен под эмулятором.

Способ по ссылке я изучу, пока не совсем понятно, что там делается. Если используется виртуальный Linux для сборки бинарников — я это пробовал, во FreeBSD такие бинарники не работают.

 

Вижу несколько объяснений:

1) Я не разобрался в типах эмуляторах

2) Я не умею использовать дебаггер и ldd для поиска зависимостей и библиотек для бинарных программ

3) Я хочу подружить жутко проприетарный софт, написанный командой индусов, который работает под одной версия java. Да, в мануале к этому софту черным по белому, написано в требованиях: версия Виндоус и версия джава, чтоб хоть как-то запустилось.

Share this post


Link to post
Share on other sites

Зачем? Если только для того, чтобы сохранять правила после перезагрузки, то мне удобнее использовать скрипт, который к тому же можно подвесить на if-up.d

Вообще не принципиально, но это как-то Debian way.

Share this post


Link to post
Share on other sites

1) Смотрите iotop.

Посмотрел, все ровно. Да и маловероятно это - сетевой интерфейс гигабит, диск SSD, узких мест я не вижу.

Share this post


Link to post
Share on other sites

Посмотрел, все ровно. Да и маловероятно это - сетевой интерфейс гигабит, диск SSD, узких мест я не вижу.

Ну потюньте для начала conntrack. При переполнении его таблицы такой спецэффект тоже имеет место быть.

Или попробуйте во время затыка сделать conntrack -F - должно отпустить, заодно и узнаете.

Share this post


Link to post
Share on other sites

Кстати да, в коннтраке по умолчанию всего 32-64к записей. Стоит увеличить хотя бы до 256к (на 500-1к клиентов должно хватить).

Можно еще потюнить hashsize (только не сильно усердствовать - не влезающая в кэш хэш-таблица это пожалуй похуже пары лишних операций сравнения). http://wiki.khnet.info/index.php/Conntrack_tuning - неплохой мануал.

Share this post


Link to post
Share on other sites

Странно, получаю ошибку:

setting key "net.ipv4.netfilter.ip_conntrack_buckets": No such file or directory

При этом файл /proc/sys/net/ipv4/netfilter/ip_conntrack_buckets существует, в нем значение 16384.

 

Если эти параметры указывать не в файле, а задать напрямую командой sysctl net.ipv4.netfilter.ip_conntrack_buckets=2621440, то ошибку не выдает, но и параметр не меняет.

Share this post


Link to post
Share on other sites

Если эти параметры указывать не в файле, а задать напрямую командой sysctl net.ipv4.netfilter.ip_conntrack_buckets=2621440

 

sysctl -w в линуксе требуется -w

Share this post


Link to post
Share on other sites

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

 

$ cat /etc/modprobe.d/nf_conntrack.conf

options nf_conntrack hashsize=1048576

Share this post


Link to post
Share on other sites

sysctl -w в линуксе требуется -w

Без разницы.

Если параметр назначаю непосредственно с помощью sysctl, то ошибок не выдается, но и значение не меняется (смотрю с помощью sysctl -a | grep conntrack_buckets).

Если же я создаю в /etc/sysctl.d свой conf-файл с оптимизированными параметрами, то при выполнении sysctl --system параметр net.ipv4.netfilter.ip_conntrack_buckets не загружается, выдает ошибку "sysctl: setting key "net.ipv4.netfilter.ip_conntrack_buckets": No such file or directory" (остальные параметры применяются).

Share this post


Link to post
Share on other sites

cat /etc/modprobe.d/nf_conntrack.conf

А вот этого файла у меня и нет.

Модуль же загружен:

# modinfo nf_conntrack
filename:       /lib/modules/3.14-0.bpo.1-amd64/kernel/net/netfilter/nf_conntrack.ko
license:        GPL
depends:        
intree:         Y
vermagic:       3.14-0.bpo.1-amd64 SMP mod_unload modversions 
parm:           tstamp:Enable connection tracking flow timestamping. (bool)
parm:           acct:Enable connection tracking flow accounting. (bool)
parm:           nf_conntrack_helper:Enable automatic conntrack helper assignment (default 1) (bool)
parm:           expect_hashsize:uint

Share this post


Link to post
Share on other sites

создайте этот файл. если нет папки modprobe.d, то ищите где лежат опции модулей в вашем дистрибутиве

 

модуль нужно выгрузить и загрузить заново или просто перезагрузить сервер

Share this post


Link to post
Share on other sites

О каких опциях идет речь?

nf_conntrack hashsize я пока вообще не трогаю, для начала я хочу задать net.ipv4.netfilter.ip_conntrack_buckets = 2621440.

При его указании в conf-файле для sysctl я получаю ошибку.

Share this post


Link to post
Share on other sites

Для диагностики:

ethtool -S eth0 (и другие интерфейсы) - есть ли дропы или нет

tc -s -d qdisc - тоже дропы

mpstat -P ALL - упирается ли какое-то из ядер в потолок?

Есть ли сетевки на шине PCI?

Есть ли hyperthreading? Тогда загрузка в 50% может быть на самом деле 100%. "Ненастоящие" ядра можно _ОСТОРОЖНО_ отключать, через sysfs

Есть ли на тазике шейперы? Если да - отключать offloading. Учитывая что используется ПК - там могут быть сетевки, которые при нагрузке глючат на этой части - лучше отключать в любом случае.

 

Смотреть:

sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max

net.netfilter.nf_conntrack_count = 389005

net.netfilter.nf_conntrack_max = 1000000

Сколько сейчас и сколько максимум. Заодно и можно прикинуть неодходимый hashsize.

 

grep "Hz" /proc/cpuinfo

Является ли частота номинальной или "плавает".

Еще может быть причиной syn flood, но это можно определить по приведенным выше командам "диагностики".

Share this post


Link to post
Share on other sites

изменить его можно только в момент загрузки модуля

Вроде как и в /sys можно поправить.

Ну и да, ИМХО 1М записей хеша это слишком уж дофига. Не то что в L1 - в L2 кеш не влезет. А значит - будут сильные потери производительности. 32-64к записей с головой, а то и стандартное кол-во оставить (будет чуть больше нагрузка на проц)

Share this post


Link to post
Share on other sites

1 букет это сколько байт, напомните?

8 для 32бит, 16 для 64бит (2 указателя). Что для 1М хеша превращается в 16МБ - явно вылезет из кэша в медленную RAM.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.