Ilya Evseev Posted January 30, 2010 Posted January 30, 2010 Утилита для генерации правил массового шейпинга. Модули для биллинга (UTM4, UTM5, ...) и для шлюза (FreeBSD+ipfw+Dummynet). Брать/читать - здесь: http://sources.homelink.ru/shaping/ В том виде, в котором выложены, не тестировались (тот вид, в котором они фактически используются, для выкладывания решительно не подходит), поэтому могут быть ошибки, но вряд ли серьёзные. Вставить ник Quote
Denis Samsonov Posted January 31, 2010 Posted January 31, 2010 (edited) Выкладываю свой вариант :) подходит для утм5, а вообще можно к любому биллингу и любому шейперу прикрутить #!/usr/local/bin/php <?php #скрипт генерации правил шейперов. должен запускаться по крону include ("/netup/wkbill/config.php"); ###функции ######################################################правила для IPFW #создание файла для ipfw function ipfw_create_file($ipfw_commands_file) { $file=fopen($ipfw_commands_file,"w+"); fwrite($file, "#!/bin/sh\n"); fwrite($file, "fwcmd=\"/sbin/ipfw -q\"\n"); fclose($file); } #создание пайпа dummynet function ipfw_create_pipe($ipfw_commands_file,$pipe_id,$in_speed,$out_speed,$tariff_id,$tariff_name) { $file=fopen($ipfw_commands_file,"a+"); fwrite($file,"#Tariff ID: $tariff_id Name: $tariff_name\n"); fwrite($file,"\${fwcmd} pipe $pipe_id config mask dst-ip 0xffffffff bw ".$in_speed."Kbit/s\n"); $pipe_id=$pipe_id+1000; fwrite($file,"\${fwcmd} pipe $pipe_id config mask src-ip 0xffffffff bw ".$out_speed."Kbit/s\n"); fclose($file); } function ipfw_table_add($ipfw_commands_file,$ip,$pipe) { $file=fopen($ipfw_commands_file,"a+"); fwrite($file,"\${fwcmd} table 1 add $ip $pipe\n"); $pipe=$pipe+1000; fwrite($file,"\${fwcmd} table 2 add $ip $pipe\n"); fclose($file); } function ipfw_table_del($ipfw_commands_file,$ip) { $file=fopen($ipfw_commands_file,"a+"); fwrite($file,"\${fwcmd} table 1 delete $ip\n"); fwrite($file,"\${fwcmd} table 2 delete $ip\n"); fclose($file); } #################################################основной скрипт $utm5dblink = mysql_connect($utm5dbhost , $utm5dbuser, $utm5dbpass)or die ("Возникла ошибка при подключении к базе данных\n"); //подключаемся к базе mysql_select_db($utm5dbname) or die ("Возникла ошибка при выборе базы данных\n"); #узнаем текущий час $cur_hour=date("H:i:s"); $current_time=strtotime(now); #создаем файл в который будем писать комманды для шейперов ipfw_create_file($ipfw_commands_file); #запрос на получение существующих правил для тарифов $query = mysql_query("SELECT * FROM tariffs, wk_shaper_rules WHERE wk_shaper_rules.tariff_id = tariffs.id AND tariffs.is_deleted=0") or die("не удается получить список правил для тарифов"); $numresults = mysql_num_rows($query); for ($i=0; $i <$numresults; $i++){ $row=mysql_fetch_array($query); $id=$row[0]; //id пользователя $tariff_id=iconv("cp1251", "KOI8-R", $row['tariff_id']); //ID тарифа $comment = iconv("cp1251", "UTF-8", $comment); $tariff_name=$row['name']; //Название тарифа $day_mode_start=$row['day_mode_start']; //начало дневного режима $day_mode_end=$row['day_mode_end']; //конец дневного режима $day_in_speed=$row['day_in_speed']; //входящая скорость дневного режима $day_out_speed=$row['day_out_speed']; //исходящая скорость дневного режима $night_mode_start=$row['night_mode_start']; //начало ночного режима $night_mode_end=$row['night_mode_end']; //конец дневного режима $night_in_speed=$row['night_in_speed']; //входящая скорость ночного режима $night_out_speed=$row['night_out_speed']; //исходящая скорость ночного режима $boost_in_speed=$row['boost_in_speed']; //входящая скорость n2o boost $boost_out_speed=$row['boost_out_speed']; //исходящая скорость n2o boost $night_boost_in_speed=$row['night_boost_in_speed']; //входящая скорость n2o boost ночь $night_boost_out_speed=$row['night_boost_out_speed']; //исходящая скорость n2o boost ночь #создаем правила шейпинга ночного режима if ($cur_hour>=$night_mode_start AND $cur_hour<=$night_mode_end) { ipfw_create_pipe($ipfw_commands_file,$tariff_id,$night_in_speed,$night_out_speed,$tariff_id,$tariff_name); } #в остальном случае создаем стандартные правила шейпинга else { ipfw_create_pipe($ipfw_commands_file,$tariff_id,$day_in_speed,$day_out_speed,$tariff_id,$tariff_name); } #если на тарифе есть услуга N2O Boost то создаем отдельные правила if ($boost_in_speed>0 AND $boost_out_speed>0) { $boost_id=$tariff_id+2000; #n2o boost ночной режим if ($cur_hour>=$night_mode_start AND $cur_hour<=$night_mode_end) { ipfw_create_pipe($ipfw_commands_file,$boost_id,$night_boost_in_speed,$night_boost_out_speed,$tariff_id,$tariff_name); } #в остальном случае стандартные правила для n2o boost else { ipfw_create_pipe($ipfw_commands_file,$boost_id,$boost_in_speed,$boost_out_speed,$tariff_id,$tariff_name); } } } #пишем комманды на удаление/добавление правил в созданные пайпы $query = mysql_query ("SELECT sl.account_id, INET_NTOA(ip & 4294967295) AS ip, tsl.tariff_id, ac.int_status FROM ip_groups ig, iptraffic_service_links il, service_links sl, tariffs_services_link tsl, accounts ac WHERE ig.is_deleted =0 AND il.is_deleted =0 AND sl.is_deleted =0 AND ig.ip_group_id = il.ip_group_id AND sl.id = il.id AND sl.service_id = tsl.service_id AND ac.id = sl.account_id AND ig.ip_type =1") or die("Запрос к бд на получение правил доступа не прошел"); $numresults = mysql_num_rows($query); for ($i=0; $i <$numresults; $i++){ $row=mysql_fetch_array($query); $tariff_id_out=0; $id = $row[0]; //ID пользователя $ip=$row['ip']; //IP адрес $tariff_id=$row['tariff_id']; //ID тарифа $tariff_id_out=$tariff_id+1000; $int_status=$row['int_status']; //статус интернета (1 - включен 0 - выключен) #проверяем. сменился ли тариф с предыдущего запуска или нет. если изменился то сначала удаляем старые правила $c_query = mysql_query("SELECT id FROM wk_shaper_rules_cache WHERE ip='$ip' AND tariff_id='$tariff_id'") or die("не удалось проверить правила с предыдущего запуска"); if (mysql_num_rows($c_query)==0) { print("У пользователя $id сменился тарифф\n"); ipfw_table_del($ipfw_commands_file,$ip); mysql_query("DELETE FROM wk_shaper_rules_cache WHERE ip='$ip'") or die("не удается удалить старую запись из кеша"); mysql_query("INSERT INTO wk_shaper_rules_cache (ip, tariff_id) VALUES ('$ip', '$tariff_id')"); } #если интернет включен то даем разрешающее правило if ($int_status==1) { #сначала проверяем услугу N2O Boost #проверяем не требуется ли подключить услугу $n2o_query = mysql_query ("SELECT * FROM wk_service_n2o_boost WHERE boost_start_time<=$current_time AND boost_end_time>=$current_time AND ip_addr='$ip'") or die("не удается провертить подключение услуги N2O Boost"); if (mysql_num_rows($n2o_query)!=0) { $n2o_row=mysql_fetch_array($n2o_query); if ($n2o_row['status']==0) { mysql_query("UPDATE wk_service_n2o_boost SET status=1 WHERE id=$n2o_row[0]"); ipfw_table_del($ipfw_commands_file,$ip); } $boost_id=$tariff_id+2000; ipfw_table_add($ipfw_commands_file,$ip,$boost_id); } #проверяем не требуется ли отключить услугу $n2o_query = mysql_query("SELECT * FROM wk_service_n2o_boost WHERE boost_end_time<=$current_time AND status=1 AND ip_addr='$ip'") or die ("Запрос не прошел"); if (mysql_num_rows($n2o_query)!=0) { $n2o_row=mysql_fetch_array($n2o_query); if ($n2o_row['status']==1) { mysql_query("UPDATE wk_service_n2o_boost SET status=0 WHERE id=$n2o_row[0]"); ipfw_table_del($ipfw_commands_file,$ip); } ipfw_table_add($ipfw_commands_file,$ip,$tariff_id); } #если допуслуг нету то просто разрешаем доступ в интернет else { ipfw_table_add($ipfw_commands_file,$ip,$tariff_id); } } #если интернет выключен то даем команду на удаление из таблиц if ($int_status==0) { ipfw_table_del($ipfw_commands_file,$ip); } } mysql_close($utm5dblink); ?> все данные по тарифам храняться и скоростям и форсажу храняться в таблицах wk_shaper_rules CREATE TABLE IF NOT EXISTS `wk_shaper_rules` ( `id` int(11) NOT NULL auto_increment, `tariff_id` int(11) NOT NULL, `day_in_speed` int(11) NOT NULL, `day_out_speed` int(11) NOT NULL, `night_mode_start` time NOT NULL, `night_mode_end` time NOT NULL, `night_in_speed` int(11) NOT NULL, `night_out_speed` int(11) NOT NULL, `boost_in_speed` int(11) NOT NULL, `boost_out_speed` int(11) NOT NULL, `night_boost_in_speed` int(11) NOT NULL default '0', `night_boost_out_speed` int(11) NOT NULL default '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=koi8r; таблица wk_service_n2o_boost CREATE TABLE IF NOT EXISTS `wk_service_n2o_boost` ( `id` int(11) NOT NULL auto_increment, `account_id` int(11) NOT NULL, `boost_id` int(11) NOT NULL, `boost_start_time` int(11) NOT NULL, `boost_end_time` int(11) NOT NULL, `tariff_id` int(11) NOT NULL, `status` int(11) NOT NULL default '0', `ip_addr` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=koi8r; и для отслеживания изменившихся тарифных планов у пользователей мы еще держим кеш в таблице wk_shaper_rules_cache CREATE TABLE IF NOT EXISTS `wk_shaper_rules_cache` ( `id` int(11) NOT NULL auto_increment, `ip` varchar(255) NOT NULL, `tariff_id` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=koi8r; скрипт запускается на сервере с биллнгом по крону #Правила шейпера */5 * * * * /netup/wkbill/shaper_rules.php 2>&1 на каждом из маршрутизаторов раз в 3 минуты по крону пускается другой скрипт (который скачивает файл по ftp и запускает его), get_shaper_rules.sh #!/bin/sh #скрипт для скачивания правил шейпирования с маршрутизатора и их применения ftp_login="xxxxx" ftp_passw="xxxx" /usr/bin/fetch -o /usr/local/wkt_scripts/ipfw_commands ftp://$ftp_login:$ftp_passw@195.93.xxx.xxx/ipfw_commands /bin/sh /usr/local/wkt_scripts/ipfw_commands ко всему этому прикручивается вебморда для управления скоростями и временем, код не дам а покажу только скриншот :) можете сделать подобное или написать мне в приват если интересно :) чуть позже выложу статейку по настройке маршрутизатора под FreeBSD 7.2 + пример использования tablearg Edited January 31, 2010 by Denis Samsonov Вставить ник Quote
Denis Samsonov Posted January 31, 2010 Posted January 31, 2010 собственно статейка с примером по tablearg http://denjs.habrahabr.ru/blog/82656/ Опубликуйте в статьях на сайте кто может или кому интересно :) Вставить ник Quote
Dyr Posted February 9, 2010 Posted February 9, 2010 Мы не стали заморачиваться с вводом дополнительных boost-параметров, просто сделали по крону замену файлов с шаблонами скоростей: # Night tariffs 59 23 * * * root /bin/ln -sf /root/utmscripts/utm2shaper.night /root/utmscripts/utm2shaper.utm # Day tariffs 59 13 * * * root /bin/ln -sf /root/utmscripts/utm2shaper.day /root/utmscripts/utm2shaper.utm Это существенно проще. ;) Вставить ник Quote
Ilya Evseev Posted February 10, 2010 Author Posted February 10, 2010 Мы не стали заморачиваться с вводом дополнительных boost-параметров, просто сделали по крону замену файлов с шаблонами скоростей:Смотри в shapers_generate, как правильно. Без крона, без дублирования общих строк,все отличия рядом и, если потребуется, с раздельными периодами для разных тарифов. Fullspeed - не замена ночному режиму, а дополнение к нему. Вставить ник Quote
Dyr Posted February 10, 2010 Posted February 10, 2010 (edited) Смотрю. Ты ещё и delay для пайпов задаёшь?? ИМХО, извращение. Лучше уж [для низкоскоростных тарифов] задавать параметры queue и burst. У нас неплохие результаты показывает такое сочетание: my $speed_in = int($actual_limit*1.1); my $speed_out = $speed_in; my $queue_size = int($speed_in / 8); my $burst_size = int($speed_in * 1.5 / 8); # http://www.cisco.com/en/US/docs/ios/12_2/qos/configuration/guide/qcfpolsh.html # normal burst = configured rate * (1 byte)/(8 bits) * 1.5 seconds # extended burst = 2 * normal burst P.S. downloaded ".($total_bytes/1000000)." Mbytes" : "" Скажем нет маркетологически-метрологическим мегабайтам! Даёшь 1 048 576 байт в мегабайте! :) Edited February 10, 2010 by Dyr Вставить ник Quote
Ilya Evseev Posted February 12, 2010 Author Posted February 12, 2010 Смотрю.Ты ещё и delay для пайпов задаёшь?? ИМХО, извращение. Это настраиваемый параметр, который по умолчанию не используется.Оставлен исключительно для экспериментов с delay -1ms. downloaded ".($total_bytes/1000000)." Mbytes" : "" Скажем нет маркетологически-метрологическим мегабайтам! Даёшь 1 048 576 байт в мегабайте! :) Это комментарий для проверки "на всякий случай". Вставить ник Quote
Dyr Posted February 15, 2010 Posted February 15, 2010 Это настраиваемый параметр, который по умолчанию не используется.Оставлен исключительно для экспериментов с delay -1ms. Тогда на всякий случай предупрежу - "delay -1ms" на 8.0 практически моментально приводит к перезагрузке, так что если будешь переходить на восьмёрку, экспериментировать с ним не советую ;) Вставить ник Quote
st_re Posted February 15, 2010 Posted February 15, 2010 downloaded ".($total_bytes/1000000)." Mbytes" : "" Скажем нет маркетологически-метрологическим мегабайтам! Даёшь 1 048 576 байт в мегабайте! :) Если заглянуть унутрь dumminet, то можно заметить, что в килобайте у нее 1000 байт, а в мегабайте 1000 кил. Тоже самое про биты. Хорошо что хоть в байте 8 бит. (при задании скоростей в командной строчке они приводятся к байт/сек. При выводе обратно к К и М). 1000 там в исходниках. Вставить ник Quote
Dyr Posted February 16, 2010 Posted February 16, 2010 (edited) st_re, увы, я не знаю С, но всё же - где это там? В /usr/src/sys/netinet/ip_dummynet.c чётко видно, что 1024: # grep -w 1000 /usr/src/sys/netinet/ip_dummynet.* ip_dummynet.c: p->delay = (p->delay * hz) / 1000; ip_dummynet.c: pipe_bp->delay = (pipe_bp->delay * 1000) / hz; ip_dummynet.h: * If we limit to max 1000 flows and a max weight of 100, then ip_dummynet.h: * XXX With this scaling, max 1000 flows, max weight 100, 1Gbit/s, the # grep -w 1024 /usr/src/sys/netinet/ip_dummynet.* ip_dummynet.c:static long pipe_byte_limit = 1024 * 1024; ip_dummynet.c: x->qsize = 1024 * 1024; # grep -w 1024 /usr/src/sbin/ipfw/dummynet.c sprintf(qs, "%d KB", l / 1024); p.fs.qsize *= 1024; p.fs.min_th *= 1024; p.fs.max_th *= 1024; limit = 1024*1024; Правда, есть ещё и такое: # grep -w 1000 /usr/src/sbin/ipfw/dummynet.c else if (b >= 1000) sprintf(buf, "%7.3f Kbit/s", b/1000); p.bandwidth *= 1000; Edited February 16, 2010 by Dyr Вставить ник Quote
Dyr Posted February 16, 2010 Posted February 16, 2010 Похоже, действительно в десятичных единицах считает. Ото ж блин, а... if (*end == 'K' || *end == 'k') { end++; p.bandwidth *= 1000; } else if (*end == 'M') { end++; p.bandwidth *= 1000000; } И что за извращение такое, выпендриться и строго соответствовать букве вместо общепринятого обозначения. Идиётизм. Вставить ник Quote
st_re Posted February 16, 2010 Posted February 16, 2010 uname -a FreeBSD xxx.xxx.ru 7.3-PRERELEASE FreeBSD 7.3-PRERELEASE #0: Fri Feb 12 20:13:07 MSK 2010 root@xxx.xxx.ru:/usr/obj/usr/src/sys/xxx amd64 /usr/src/sbin/ipfw/dummynet.c /* * Print rate (or clocking interface) */ if (p->if_name[0] != '\0') sprintf(buf, "%s", p->if_name); else if (b == 0) sprintf(buf, "unlimited"); else if (b >= 1000000) sprintf(buf, "%7.3f Mbit/s", b/1000000); else if (b >= 1000) sprintf(buf, "%7.3f Kbit/s", b/1000); else sprintf(buf, "%7.3f bit/s ", b); Если в 8 они поправили, то могет быть. Насколько лет назад я пытался накатать sendpr... но потом себе биллинг поправил, чтобы всегда в бит/с писал. Вставить ник Quote
Giga-Byte Posted February 16, 2010 Posted February 16, 2010 И что за извращение такое, выпендриться и строго соответствовать букве вместо общепринятого обозначения. Идиётизм. это вы про что? общеприниятое всмысле "bit/s" ? Вставить ник Quote
st_re Posted February 16, 2010 Posted February 16, 2010 Кстати, хозяйке на заметку.Задание в конфиге mbyte/s приведет к очень интересному для многих фифекту... Как и mBite. Бит от байта оно отличает строго по высоте буквы B. если нижний регистр - биты, верхний - байты. Что там дальше за буквы - пофиг. Вставить ник Quote
Dyr Posted February 16, 2010 Posted February 16, 2010 И что за извращение такое, выпендриться и строго соответствовать букве вместо общепринятого обозначения. Идиётизм.это вы про что? общеприниятое всмысле "bit/s" ? Это я про то, что вместо общепринятых, хоть и строго говоря, неправильных приравниваний СИшных приставок кило- и мега- как 1024 и 1024^2 разработчики dummynet решили пойти своим путём и написать всё строго "по бумажке", где кило это 1000 а мега это 1000^2. Кстати, хозяйке на заметку.Задание в конфиге mbyte/s приведет к очень интересному для многих фифекту... Как и mBite. Бит от байта оно отличает строго по высоте буквы B. если нижний регистр - биты, верхний - байты. Что там дальше за буквы - пофиг.Прэлестно, просто прэлестно. Сегодня не успею, а вот завтра постараюсь отправить соотсветствующее письмецо разработчикам. Вставить ник Quote
littlesavage Posted February 16, 2010 Posted February 16, 2010 (edited) Dyr, AFAIK, в телекоме редко кто информацию меряет в двоичных мегабитах. Неудобно. Собственно, разрабочики стандарта Fast Ethernet свои 100Mbit/s сделали десятичными. С двоичными обозначеними только проблем больше будет. Сможешь с ходу сказать, сколько нужно довичных мегабит, чтобы сэмулировать 100Mbit/s интерфейс? Edited February 16, 2010 by littlesavage Вставить ник Quote
Dyr Posted February 17, 2010 Posted February 17, 2010 (edited) Да не сказал бы. Просто если на скорость ещё не очень обращают внимание, то трафик как раз считают обычно в двоичных приставках. Собственно, разрабочики стандарта Fast Ethernet свои 100Mbit/s сделали десятичными.Кстати, тоже пытался найти сходу упоминание о битовой скорости для данного стандарта и не нашёл. :) Edited February 17, 2010 by Dyr Вставить ник Quote
photon Posted February 17, 2010 Posted February 17, 2010 (edited) Для двоичных префиксов определены следующие стандартные обозначения: http://en.wikipedia.org/wiki/Binary_prefix...andard_prefixes http://physics.nist.gov/cuu/Units/binary.html Kibit = 1024 bit, Mibit = 1024*1024 bit и т.д. В линуксовом tc они используются и там такой путаницы не возникает. Edited February 17, 2010 by photon Вставить ник Quote
littlesavage Posted February 17, 2010 Posted February 17, 2010 Dyr, на вики в таблице сравнения скоростей тоже десятичные приставки используются: http://en.wikipedia.org/wiki/List_of_device_bandwidths Вставить ник Quote
Dyr Posted February 17, 2010 Posted February 17, 2010 Уговорили :) Но с тем, что байты меряются с двоичными приставками (и в том же dummynet тоже, кстати), согласны? ;) Вставить ник Quote
Mechanic Posted February 23, 2010 Posted February 23, 2010 собственно статейка с примером по tablearghttp://denjs.habrahabr.ru/blog/82656/ Опубликуйте в статьях на сайте кто может или кому интересно :) а сколько kpps бегает через шейпер ? и сколько интерфейсов в онлайне ? у меня похожая конфигурация, но , что то нет нормальных показателей по производительности, может дел в железе ?! мать intel dq35joe + core2duo 3Ghz Вставить ник Quote
Dyr Posted February 24, 2010 Posted February 24, 2010 Комменты к статье, кстати, жгут. Советы заменить pf nat на ng_nat хороши ровно до тех пор, пока не вспоминаешь, что pf умеет натить на диапазон адресов. Вставить ник Quote
reddog Posted April 11, 2010 Posted April 11, 2010 Ilya Evseev, ограничение скорости на более чем один ip на пользователя не делается я так понимаю? То есть если к абоненту в сервисной связке привязано с десяток ip'шников то ограничение будет только у одного - первого? Вставить ник Quote
Ilya Evseev Posted April 12, 2010 Author Posted April 12, 2010 Ilya Evseev, ограничение скорости на более чем один ip на пользователя не делается я так понимаю? То есть если к абоненту в сервисной связке привязано с десяток ip'шников то ограничение будет только у одного - первого?Для UTM5 не проверялось.Для UTM4 каждый IP получит отдельный пайп. Вставить ник Quote
Sergey_Taurus Posted May 21, 2010 Posted May 21, 2010 (edited) У меня вопрос по шейперам на FreeBSD, если можно. Почитал Ваши,Ivan Rostovikov и Denis Samsonov, примеры и появилось несколько вопросов. 1) Как правильно реализовать алгоритм переброса абонента из одной полосы в другую? Скорее всего перемещением его в другую ipfw table, но как лучше: занулением всех таблиц и раскладкой юзеров по новым заново или вычислением текущего состония ipfw tables, сравнением с новым нужным состоянием и генераций новых ipfw table N add и ipfw table N delete листингов, которые будут делать изменения. Если, по каким-то причинам, нужно делать полный ipfw table N flush и заполнять их заново, я так понимаю что сервер выкинет всех из пайпов\очередей и на момент (1,2-10 секунд, минута и т.п.) и пропустит их на wirespeed (что в принципе не сильная проблема). Вопрос: отдадутся ли оставшиеся пакеты (если были) в существующих очередях\пайпах юзерам при сбросе\переключении таблиц. Не будет ли потерь пакетов в этот момент? 2) Как я понял, в обоих примерах пайпы создаются динамически, через определенный промежуток времени конфигурация пайпов\очередей грохается и пересоздается заново в зависимости от текущих тарифов\ночного времени и прочего. Вопрос: насколько "плохо" становится серверу при пересоздании большого количества пайпов (ведь с масками типа 0xffffffff отдельный пайп, вернее 2 по одному на вход и выход, создается для каждого адреса)? Теряются ли пакеты при сбросе конфигурации пайпов (ipfw pipe flush, ipfw queue flush) и насколько это ощущает абонент? Коллеги, мне нужно понять правильный алгоритм действий (или возможные варианты) в плане динамики изменения пайпов\ipfw таблиц, а потом уже реализовать его не проблема для связки с нашим билингом. Заранее спасибо за ответы. Edited May 21, 2010 by Sergey_Taurus Вставить ник Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.