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

Freebsd и Kernel Space Nat Высокие задержки после запуска цепочек NAT ( ipfw )

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

До недавнего момента стоял Gentoo, без SMP ( rshaper не умеет с SMP работать ). Решили перейти на freebsd + firewall_nat + pipes ( tables ).

Всё отлично, НО: как только загружаются цепочки ната - задержки во вне и у клиентов и на самих натах вырастают до 100-120мс и очень сильно падает пропускная способность интерфейсов.

Обе машины одинаковые, вот конфиг:

FreeBSD gw1 7.3-RELEASE FreeBSD 7.3-RELEASE #1: Thu Oct 14 23:11:23 MSD 2010     root@gw1:/usr/obj/usr/src/sys/GW1  i386

lspci
00:00.0 Host bridge: Intel Corporation 5000P Chipset Memory Controller Hub (rev b1)
00:02.0 PCI bridge: Intel Corporation 5000 Series Chipset PCI Express x8 Port 2-3 (rev b1)
00:03.0 PCI bridge: Intel Corporation 5000 Series Chipset PCI Express x4 Port 3 (rev b1)
00:04.0 PCI bridge: Intel Corporation 5000 Series Chipset PCI Express x8 Port 4-5 (rev b1)
00:05.0 PCI bridge: Intel Corporation 5000 Series Chipset PCI Express x4 Port 5 (rev b1)
00:06.0 PCI bridge: Intel Corporation 5000 Series Chipset PCI Express x8 Port 6-7 (rev b1)
00:07.0 PCI bridge: Intel Corporation 5000 Series Chipset PCI Express x4 Port 7 (rev b1)
00:08.0 System peripheral: Intel Corporation 5000 Series Chipset DMA Engine (rev b1)
00:10.0 Host bridge: Intel Corporation 5000 Series Chipset FSB Registers (rev b1)
00:10.1 Host bridge: Intel Corporation 5000 Series Chipset FSB Registers (rev b1)
00:10.2 Host bridge: Intel Corporation 5000 Series Chipset FSB Registers (rev b1)
00:11.0 Host bridge: Intel Corporation 5000 Series Chipset Reserved Registers (rev b1)
00:13.0 Host bridge: Intel Corporation 5000 Series Chipset Reserved Registers (rev b1)
00:15.0 Host bridge: Intel Corporation 5000 Series Chipset FBD Registers (rev b1)
00:16.0 Host bridge: Intel Corporation 5000 Series Chipset FBD Registers (rev b1)
00:1e.0 PCI bridge: Intel Corporation 82801 PCI Bridge (rev d9)
00:1f.0 ISA bridge: Intel Corporation 631xESB/632xESB/3100 Chipset LPC Interface Controller (rev 09)
00:1f.1 IDE interface: Intel Corporation 631xESB/632xESB IDE Controller (rev 09)
00:1f.2 RAID bus controller: Intel Corporation 631xESB/632xESB SATA RAID Controller (rev 09)
00:1f.3 SMBus: Intel Corporation 631xESB/632xESB/3100 Chipset SMBus Controller (rev 09)
01:00.0 PCI bridge: Intel Corporation 6311ESB/6321ESB PCI Express Upstream Port (rev 01)
01:00.3 PCI bridge: Intel Corporation 6311ESB/6321ESB PCI Express to PCI-X Bridge (rev 01)
02:00.0 PCI bridge: Intel Corporation 6311ESB/6321ESB PCI Express Downstream Port E1 (rev 01)
02:01.0 PCI bridge: Intel Corporation 6311ESB/6321ESB PCI Express Downstream Port E2 (rev 01)
02:02.0 PCI bridge: Intel Corporation 6311ESB/6321ESB PCI Express Downstream Port E3 (rev 01)
05:00.0 Ethernet controller: Intel Corporation 80003ES2LAN Gigabit Ethernet Controller (Copper) (rev 01)
05:00.1 Ethernet controller: Intel Corporation 80003ES2LAN Gigabit Ethernet Controller (Copper) (rev 01)
0a:00.0 Ethernet controller: Intel Corporation 82576 Gigabit Network Connection (rev 01)
0a:00.1 Ethernet controller: Intel Corporation 82576 Gigabit Network Connection (rev 01)
0c:0c.0 VGA compatible controller: ATI Technologies Inc ES1000 (rev 02)

cat /etc/sysctl.conf
#security.bsd.see_other_uids=0
net.inet.ip.forwarding=1
net.inet.ip.fastforwarding=1
net.inet.ip.fw.one_pass=0
net.inet.ip.dummynet.io_fast=1
net.inet.icmp.icmplim=1024
net.inet.ip.fw.dyn_buckets=2048
net.inet.ip.dummynet.hash_size=1024

 

Нат запускается скриптом ( связка с Трафик-Инспектор сервер - остаточное явление - доживает дни до перехода на UTM) - строки запуска на 1 абонента такие:

# общие
exec("ipfw -f flush");
exec("ipfw -f pipe flush");
exec("ipfw -f queue flush");
exec("ipfw nat 65000 config ip 109.197.112.2 log");
exec("ipfw pipe 1 config bw 8192Kbit/s mask dst-ip 0xffffffff");
exec("ipfw add pipe 1 ip from table\(101\) to any out");
exec("ipfw add pipe 1 ip from any to table\(101\)");
# ........
# сам юзер:
exec("ipfw add $user_id nat 65000 ip from $user_ip/32 to any");
exec("ipfw add $user_id nat 65000 ip from any to $real_ip");
и в трубу:
exec("ipfw table 101 add $user_ip");

 

После этого, скрипт работает в бесконечном цикле, отлавливает по in_array кто вошёл, кто вышел и добавляет или удаляет цепочки ната и мемберов из групп пайпов. Никакого дублирования нет точно, проверял много раз - всё чётко. НО: вырастают безумно таймы и падает производительность интерфейсов.

 

Вот ещё некоторые данные:

last pid:  9419;  load averages:  1.84,  1.86,  1.58                                                                                                                                                                 up 0+00:42:17  15:32:59
78 processes:  7 running, 52 sleeping, 19 waiting
CPU 0: 31.6% user,  0.0% nice,  0.4% system,  0.0% interrupt, 68.0% idle
CPU 1:  0.4% user,  0.0% nice,  0.4% system,  0.0% interrupt, 99.2% idle
CPU 2:  0.4% user,  0.0% nice, 67.3% system,  0.0% interrupt, 32.3% idle
CPU 3:  0.0% user,  0.0% nice, 99.6% system,  0.0% interrupt,  0.4% idle
Mem: 14M Active, 9016K Inact, 97M Wired, 44K Cache, 11M Buf, 3382M Free
Swap: 8192M Total, 8192M Free

  PID USERNAME  THR PRI NICE   SIZE    RES STATE   C   TIME   WCPU COMMAND
   13 root        1 171 ki31     0K     8K CPU1    1  39:41 100.00% idle: cpu1
   27 root        1 -68    -     0K     8K CPU3    3  30:54 100.00% em1 taskq
   14 root        1 171 ki31     0K     8K RUN     0  36:32 91.06% idle: cpu0
   26 root        1 -68    -     0K     8K CPU2    2  22:44 70.46% em0 taskq
   12 root        1 171 ki31     0K     8K RUN     2  18:38 33.98% idle: cpu2
1068 root        1 100    0 12116K  7060K select  0   7:10 17.48% php

 

 vmstat -i
interrupt                          total       rate
irq1: atkbd0                           4          0
irq20: atapci1                      8111          3
cpu0: timer                      4984635       1971
irq256: em0                      5471836       2164
irq257: em1                      1848173        731
cpu1: timer                      4984449       1971
cpu3: timer                      5017736       1984
cpu2: timer                      5017735       1984
Total                           27332679      10811

 

gw0# ping ya.ru
PING ya.ru (87.250.251.3): 56 data bytes
64 bytes from 87.250.251.3: icmp_seq=0 ttl=58 time=103.548 ms
64 bytes from 87.250.251.3: icmp_seq=1 ttl=58 time=93.891 ms
64 bytes from 87.250.251.3: icmp_seq=2 ttl=58 time=90.336 ms
64 bytes from 87.250.251.3: icmp_seq=3 ttl=58 time=109.123 ms
64 bytes from 87.250.251.3: icmp_seq=4 ttl=58 time=103.121 ms

 

На микротике:
[admin@MikroTik] > ping ya.ru
77.88.21.3 64 byte ping: ttl=62 time=4 ms
77.88.21.3 64 byte ping: ttl=62 time=4 ms
77.88.21.3 64 byte ping: ttl=62 time=4 ms
77.88.21.3 64 byte ping: ttl=62 time=4 ms
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 4/4.0/4 ms

 

Думаю проблема в этом:

top -SP
CPU0    0 551:36 100.00% em1 taskq

 

Кто сталкивался - ткните носом. Не хочется экспериментировать с natd, говорят что кернел нат быстрее, думаю проблема в настройках sysctl ..... Буду благодарен за помощь.

Edited by Mozhay

Share this post


Link to post
Share on other sites

Вместо 2*count($user_ip) правил:

exec("ipfw add $user_id nat 65000 ip from $user_ip/32 to any");

exec("ipfw add $user_id nat 65000 ip from any to $real_ip");

сделать где-то сверху

exec("ipfw add nat 65000 ip from table 101 to any");
exec("ipfw add nat 65000 ip from any to $real_ip");

Edited by Latik

Share this post


Link to post
Share on other sites

Я правильно понял, что такая нагрузка из-за большого ( более 1200 ) пар цепочек ната ?

Т.е. я по анологии с трубой пихаю юзеров в таблицу?

exec("ipfw -f flush");
exec("ipfw -f pipe flush");
exec("ipfw -f queue flush");
exec("ipfw disable one_pass");
exec("ipfw nat 65000 config ip 109.197.112.2 log");
# труба
exec("ipfw pipe 81 config bw 8192Kbit/s mask dst-ip 0xffffffff");
exec("ipfw add pipe 81 ip from table\(108\) to any out");
exec("ipfw add pipe 81 ip from any to table\(108\)");
# нат
exec("ipfw add nat 65000 ip from table 108 to any");
exec("ipfw add nat 65000 ip from any to 109.197.112.2");

# типичный пользователь - добавление
exec("ipfw table 108 add $user_ip");
# типичный пользователь - удаление
exec("ipfw table 108 delete $user_ip");

Получается таблица одна и на нат и на трубу?

Share this post


Link to post
Share on other sites
Я правильно понял, что такая нагрузка из-за большого ( более 1200 ) пар цепочек ната ?
Наверняка.

Пакет не должен пробегать больше сотни правил.

Смотрите "tablearg" в man ipfw.

В идеале NAT лучше унести на Linux, а на FreeBSD оставить только шейперы.

Share this post


Link to post
Share on other sites
До недавнего момента стоял Gentoo, без SMP ( rshaper не умеет с SMP работать ). Решили перейти на freebsd + firewall_nat + pipes ( tables ).

NAT лучше реализовать на отдельной машине (на пограничном маршрутизаторе), иначе будут проблемы с классификацией трафика по IP, а сам шейпер можно сделать мостом. Кроме того, все нормальные люди делают шейпинг на Linux с помощью фильтров u32 или flow.

Edited by photon

Share this post


Link to post
Share on other sites
До недавнего момента стоял Gentoo, без SMP ( rshaper не умеет с SMP работать ). Решили перейти на freebsd + firewall_nat + pipes ( tables ).
NAT лучше реализовать на отдельной машине (на пограничном маршрутизаторе), иначе будут проблемы с классификацией трафика по IP, а сам шейпер можно сделать мостом. Кроме того, все нормальные люди делают шейпинг на Linux с помощью фильтров u32 или flow.

С таблицами на нат стало приемлемо ( по 700-750 юзеров на каждый из 2х натов в пике):

   35 root        1 -68    -     0K     8K -       0 775:37 31.93% em1 taskq
   34 root        1 -68    -     0K     8K -       3 551:22 18.46% em0 taskq

 

Огромное спасибо всем)

 

А по теории организации - у меня бордером стоит Микротик x86 ( RB1000 стоит на горячую замену с аналогичными настройками без коммутации ) - он разруливает bgp на 3 внешних канала ( временно работает только один и второй в фейл-овере ), за ним моя сетка /21 - там уже сервера и внешние интерфейсы натов ( они же шейперы ). За ними стоит ядро на DGS-3610G стекируемые по 10G, на котором ip policy на роутинг как load-balance - он сам рулит распределением на 2 ната. Какой смысл разделять шейпинг и нат? Т.е. немного не так - какая разница: 2 сервера с нат+шейпер или 1 нат и 1 шейпер?

 

Share this post


Link to post
Share on other sites
все нормальные люди делают шейпинг на Linux
Не все :)

 

Во-первых, sc не умеет динамически менять скорость по времени суток, объёму трафика и т.д.

Или уже умеет?

 

Во-вторых, sc поддерживает только одну сеть /16.

Как быть тем, у кого блоков несколько (например, два - приватные и публичные)?

 

В-третьих, sc - это невероятный монстр: 3330 строк!

Для сравнения, шейпер для freebsd+ipfw+dummynet состоит из 756 строк (разница в 4,5 раза),

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

 

Share this post


Link to post
Share on other sites
какая разница: 2 сервера с нат+шейпер или 1 нат и 1 шейпер?
У одной задачи больше шансов целиком уместиться в процессорный кэш.

Плюс уменьшаются внутренние расходы на синхронизацию.

Это в теории.

На практике - лично у меня вторая схема оказалась быстрее.

Share this post


Link to post
Share on other sites
все нормальные люди делают шейпинг на Linux
Не все :)

Не вырывайте слова из контекста. Я имею в виду, что если люди и делают шейпер на Linux, то с помощью классификаторов u32 или flow, а не какого-то устаревшего rshaper. Во FreeBSD мне самому больше нравится реализация правил шейпинга, потому что они проще.

 

Во-первых, sc не умеет динамически менять скорость по времени суток, объёму трафика и т.д.

Или уже умеет?

Поддержку множителя сделать довольно просто, а менять в зависимости от времени суток надо с помощью cron.

 

Во-вторых, sc поддерживает только одну сеть /16.

Как быть тем, у кого блоков несколько (например, два - приватные и публичные)?

Это я еще полгода назад доделал. Если использовать filter_method = u32, то поддерживается сколько угодно блоков с одинаковыми октетами, но IP-адресов все равно должно быть не больше 2^16 - 2.

 

В-третьих, sc - это невероятный монстр: 3330 строк!

Для сравнения, шейпер для freebsd+ipfw+dummynet состоит из 756 строк (разница в 4,5 раза),

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

Там еще POD для создания man-страницы в исходник встроен, который занимает половину количества строк. Во FreeBSD правила намного проще, и для нее не надо полторы тыщи строк городить. Если бы я писал для FreeBSD (что уже неоднократно делалось многими), то тоже вышло бы примерно 500-700 строк. А для Linux получилось много кода, потому что надо генерировать довольно нетривиальные хэш-фильтры, проверять правильность входных данных и т.п. В простых админских скриптах никаких проверок обычно не делается, т.к. можно положиться на используемые программы. При использовании пакетных режимов одно некорректное правило может прервать процесс загрузки правил.
Edited by photon

Share this post


Link to post
Share on other sites
Там еще POD для создания man-страницы в исходник встроен, который занимает половину количества строк.
sc.conf.pod - 335 строк.

sc - 485 из 2520.

В сумме 620 из 3330.

С одной стороны, на половину никак не тянет.

С другой стороны, если утилиту приходится сопровождать столь объёмным описанием, не есть ли это признак её чрезмерной усложнённости? ;-)

 

В любом случае, хорошо, что такой инструмент есть.

Мой Вам респект!

 

Share this post


Link to post
Share on other sites

Вообще, да. Сложновато получилось. Было бы неплохо кусок кода, генерирующий хэш-фильтры по списку подсетей, переписать на C и перекинуть в tc. Сейчас хэш-фильтрами пользоваться без прослоек абсолютно невозможно, поэтому собственно все и шейпят на FreeBSD, где более внятный язык правил.

Edited by photon

Share this post


Link to post
Share on other sites

Интересно, не пробовал ли кто-нибудь из присутствующих dummynet под Linux - Луиджи не так давно портировал ipfw и dummynet под Linux (и под Windows, кстати).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this