FreeBSD — различия между версиями
Admin (обсуждение | вклад) |
Admin (обсуждение | вклад) |
||
Строка 500: | Строка 500: | ||
Оригинал статьи http://www.opennet.ru/base/dev/shell_coding.txt.html | Оригинал статьи http://www.opennet.ru/base/dev/shell_coding.txt.html | ||
+ | |||
+ | ==IPFW PIPE == | ||
+ | |||
+ | |||
+ | options DUMMYNET ;Шейпер | ||
+ | options HZ=1000 ;Частота системного таймера, (1000=1ms,100=10ms,0=NO!) | ||
+ | |||
+ | net.inet.ip.fw.one_pass: 1 ;Заставляет напрямую поток из dummynet идти в большой мир миную | ||
+ | ;последующие правилам фаирвола | ||
+ | net.inet.ip.fw.one_pass: 0 ;Заставляет идти выходящий поток из dummynet по ниже стоящим правилам | ||
+ | |||
+ | ipfw pipe NNN config bw B delay D queue Q plr P | ||
+ | |||
+ | NNN Номер полосы | ||
+ | bw Ширина полосы ;{K | M}{bit/s | Bytes/s} | ||
+ | delay Велечина задержки ;(ms) | ||
+ | queue Размер очереди ;(slots,Bytes) | ||
+ | weight Вес/приоритет очереди ;( [1..100], default =1! 1-min 100-max ) | ||
+ | pipe Канал для связи с очердью или очередями ; | ||
+ | plr Доля потеряных пакетов случайным образом ;( 0,0..1,0] 0 =100%pass, 1 =100%reject) | ||
+ | mask Группировка по маске ;(dst-ip, src-ip, dst-port, src-port, proto, all) | ||
+ | red | gred Выполняет алгоритм управления очередью RED ;(w_q/min_th/max_th/max_p) | ||
+ | ;w_q - вес очереди | ||
+ | ;min_th - минимальный порог | ||
+ | ;max_th - максимальный порог | ||
+ | ;max_p - максимальная вероятность отбрасывания пакета | ||
+ | ;w_q и max_p ( !=0..1] ) | ||
+ | ;min_th и max_th (slots,Bytes) | ||
+ | |||
+ | При использовании алгоритма Random Early Detection (RED): Если уровень перегрузки* находится между | ||
+ | порогами min_th и max_th, пакеты отбрасываются с линейно возрастающей вероятностью от 0 до max_p, | ||
+ | которая достигается при достижении второго порога (max_th). Когда перегрузка выше второго порога, | ||
+ | все пакеты отбрасываются. | ||
+ | |||
+ | При использовании алгоритма Gentle RED (GRED): Если уровень перегрузки* находится между порогами | ||
+ | min_th и max_th, пакеты отбрасываются с линейно возрастающей вероятностью от 0 до max_p. Когда уровень | ||
+ | перегрузки больше max_th, но меньше 2*max_th, то пакеты отбрасываются не все, как в случае с RED, а с | ||
+ | линейно возрастающей вероятностью от max_th до 1. Все пакеты отбрасываются только после превышения | ||
+ | значения уровня перегрузки канала 2*max_th. | ||
+ | |||
+ | Время заполнения очереди или время задержки при стандартном значении MTU (1500) определяется: | ||
+ | |||
+ | T=(MTU*byte*Q)/L (сек) | ||
+ | |||
+ | где: | ||
+ | MTU - значение MTU; | ||
+ | byte - 8 бит, чтобы перевести в биты, так как MTU в байтах | ||
+ | Q - размер очереди в слотах; | ||
+ | L - пробускная способность канала, бит/с. | ||
+ | |||
+ | Получаем что-то типа: | ||
+ | T=(1500*8*Q)/L | ||
+ | |||
+ | Далее, если мы хотим чтобы при канале шириной в 256Kbit/s задержки не привышали 100ms, | ||
+ | можем расчитать Q! | ||
+ | |||
+ | Мой канал 256Kbit/s -> 256*1024bit/s | ||
+ | PPPOE(MTU) 1500 -> 1492 | ||
+ | 100ms/1000c=0,1ms | ||
+ | |||
+ | Q=(T*L)/(MTU*byte) | ||
+ | |||
+ | Получаем, при <=100ms | ||
+ | Q=(0,1s*262144bit/s)/(1492*8)=26214,4/11936=~2,1=2слота | ||
+ | |||
+ | Получаем, при <=200ms | ||
+ | Q=(0,2s*262144bit/s)/(1492*8)=52428,8/11936=~4,3=4слота | ||
+ | |||
+ | Получаем, при <=500ms | ||
+ | Q=(0,5s*262144bit/s)/(1492*8)=131072/11936=~10,9=10слотов | ||
+ | |||
+ | Получаем, при <=1s | ||
+ | Q=(1s*262144bit/s)/(1492*8)=262144/11936=~21,9=21слот | ||
+ | |||
+ | DUMMYNET позволяет установить очередь до 100 слотов, но | ||
+ | округлем в меньшую сторону, дабы не вылазить за рамки и | ||
+ | не получать отбрасываемых пакетов. | ||
+ | |||
+ | При нашем расчёте время задержки, при <=0,1s: | ||
+ | T=(MTU*byte*Q)/L, при 0,1s; | ||
+ | T=(1492*8*2)/262144=23872/262144=0,091c | ||
+ | при 0,2s; | ||
+ | T=(1492*8*4)/262144=47744/262144=0,182c | ||
+ | при 0,5s; | ||
+ | T=(1492*8*10)/262144=119360/262144=0,455c | ||
+ | при 1s; | ||
+ | T=(1492*8*21)/262144=250656/262144=0,956c | ||
+ | |||
+ | Для алгоритма RED или GRED расчитаем нижний порог: | ||
+ | min_th=(T*L)/(MTU*byte) (слотов) | ||
+ | min_th=(0,1*262144)/(1492*8)=26214,4/11936=~2,1=2слота, как у нас уже расчитано выше. | ||
+ | |||
+ | Теперь расчитаем верхний порог: | ||
+ | max_th=(2..5)*min_th(слотов),возьмём среднее 3 | ||
+ | max_th=3*2=6слотов, верхний порог, при задержки в 0,1s | ||
+ | max_th=3*4=12слотов, верхний порог, при задержки в 0,2s | ||
+ | max_th=3*10=30слотов, верхний порог, при задержки в 0,5s | ||
+ | max_th=3*21=63слотa, верхний порог, при задержки в 1s | ||
+ | |||
+ | Далее нам нужно уровень перегрузки канала, при котором все пакеты будут отбрасываться: | ||
+ | Q=2*max_th, | ||
+ | Q=2*6=12слотов, при задержки в 0,1s | ||
+ | Q=2*12=24слотов, при задержки в 0,2s | ||
+ | Q=2*30=60слотов, при задержки в 0,5s | ||
+ | Q=2*63=126слотов, при задержки в 1s - ???Получаем лажу! DUMMYNET способен только на 100слотов | ||
+ | |||
+ | Получаем следующие правила | ||
+ | ipfw pipe 1 config bw 256Kbit/s queue 12 gred 0.002/2/6/0.1 | ||
+ | ipfw pipe 2 config bw 256Kbit/s queue 24 gred 0.002/4/12/0.1 | ||
+ | |||
+ | ipfw pipe4 config bw 256Kbit/s queue 126 gred 0.002/21/63/0.1 - ?! Но попробовать стоит ж;) | ||
+ | ############################################################# | ||
+ | ipfw: 2 <= queue size <= 100 ;Вот такая ругань получилась ))) | ||
+ | ############################################################# | ||
+ | |||
+ | И три трубы которые принял ipfw образовали: | ||
+ | ########################################################### | ||
+ | 00001: 256.000 Kbit/s 0 ms 12 sl. 0 queues (1 buckets) ;Пакеты бьються | ||
+ | GRED w_q 0.001999 min_th 2 max_th 6 max_p 0.099991 | ||
+ | 00002: 256.000 Kbit/s 0 ms 48 sl. 0 queues (1 buckets) ;Средний вариант | ||
+ | GRED w_q 0.001999 min_th 4 max_th 12 max_p 0.099991 | ||
+ | 00003: 256.000 Kbit/s 0 ms 60 sl. 0 queues (1 buckets) ;Слишком большой pipe?! | ||
+ | GRED w_q 0.001999 min_th 10 max_th 30 max_p 0.099991 | ||
+ | ########################################################### | ||
+ | |||
+ | Так же можно вполне задать очередь в KBytes не только в слотах | ||
+ | и очередь не должна привышать ширину канала, иначе будет куча | ||
+ | битых пакетов. По советам её бы уменьшить процентов на 5%-10%. | ||
+ | 256/8=32Kbytes/s, (32/100%)*5%=3,2=~4Kbytes, 32-4=28Kbytes, | ||
+ | ipfw pipe 1 config bw 256Kbit/s queue 28Kbytes | ||
+ | |||
+ | Так же окружающие советуют: | ||
+ | w_q=0.002/min_th=(queue/10)/max_th=(3*min_th)/max_p=0.1, при queue 30 слотах | ||
+ | |||
+ | Теперь к экспериментам! | ||
+ | ... из всего что я понял и усвоил, я планирую: | ||
+ | 1. создать 2 трубы pipe 1,2 и сделать честное деление канала по скорости между | ||
+ | пользователям, типа: local->GW и GW<-local | ||
+ | |||
+ | 2. создать 2 трубы и сделать 2 очереди для входящего и исходящего траффика | ||
+ | типа GW->inet и inet<-GW с алгоритмом GRED, для предотвращения перегрузок | ||
+ | |||
+ | Немного схем... ;) | ||
+ | ########################################### | ||
+ | --> in --> out | ||
+ | [-Л-К-Л-А-]-pipe1-[-c-р-е--]-pipe3-[-И-Е--] | ||
+ | [--О-А-К--]-pipe2-[--e-в-р-]-pipe4-[--Н-Т-] | ||
+ | <-- out <-- in | ||
+ | ########################################### | ||
+ | |||
+ | Результат при 256Kbit/s | ||
+ | pipe 10 config bw 256Kbit/s queue 12 0.002/2/6/0.1 ~23.29 Kbytes/sec | ||
+ | pipe 10 config bw 256Kbit/s queue 24 0.002/2/8/0.1 ~23.73 Kbytes/sec | ||
+ | pipe 10 config bw 256Kbit/s queue 24 0.002/3/12/0.1 ~26.37 Kbytes/sec | ||
+ | pipe 10 config bw 256Kbit/s queue 30 0.002/3/15/0.1 ~22.24 Kbytes/sec | ||
+ | pipe 10 config bw 256Kbit/s queue 48 0.002/8/24/0.1 ~26.66 Kbytes/sec | ||
+ | pipe 10 config bw 256Kbit/s queue 60 0.002/10/30/0.1 ~27.19 Kbytes/sec | ||
+ | pipe 10 config bw 256Kbit/s queue 100 0.002/33/50/0.1 ~22.99 Kbytes/sec | ||
+ | То что народ насоветовал ;) | ||
+ | pipe 10 config bw 256Kbit/s queue 30 0.002/3/9/0.1 ~24.46 Kbytes/sec | ||
+ | |||
+ | В итоге написал такие правила: | ||
+ | ################################################################# | ||
+ | #BANDWISH (PIPE & QUEUE) | ||
+ | |||
+ | #NO_PASS_ALL_AFTER_BANDWISH | ||
+ | sysctl net.inet.ip.fw.one_pass=0 | ||
+ | |||
+ | #FLUSH | ||
+ | ipfw -f flush | ||
+ | ipfw -f pipe flush | ||
+ | ipfw -f queue flush | ||
+ | |||
+ | #CONFIG & ADD RULES | ||
+ | ipfw add pass ip from localhost to localhost via lo0 | ||
+ | |||
+ | ipfw pipe 1 config bw 256Kbit/s | ||
+ | ipfw queue 11 config pipe 1 mask src-ip 0xffffffff | ||
+ | ipfw add queue 11 ip from 192.168.0.0/16 to any in via bfe0 | ||
+ | ipfw add pass ip from 192.168.0.0/16 to any in via bfe0 | ||
+ | |||
+ | ipfw pipe 2 config bw 256Kbit/s | ||
+ | ipfw queue 22 config pipe 2 mask dst-ip 0xffffffff | ||
+ | ipfw add queue 22 ip from any to 192.168.0.0/16 out via bfe0 | ||
+ | ipfw add pass ip from 192.168.0.0/16 to any out via bfe0 | ||
+ | |||
+ | ipfw pipe 3 config bw 256Kbit/s #queue 60 gred 0.002/10/30/0.1 | ||
+ | ipfw add pipe 3 ip from 92.255.254.17 to any out via tun0 | ||
+ | ipfw add pass ip from 92.255.254.17 to any out via tun0 | ||
+ | |||
+ | ipfw pipe 4 config bw 256Kbit/s #queue 60 gred 0.002/10/30/0.1 | ||
+ | ipfw add pipe 4 ip from any to 92.255.254.17 in via tun0 | ||
+ | ipfw add pass ip from any to 92.255.254.17 in via tun0 | ||
+ | ################################################################# | ||
+ | |||
+ | В случае чего можно расскоментировать #queue 60 gred 0.002/10/30/0.1 | ||
+ | Для сглаживания шороховатостей, но а пока я не увидел битых пакетов. | ||
+ | |||
+ | gw2# ipfw pipe show | ||
+ | ############################################################################## | ||
+ | 00001: 256.000 Kbit/s 0 ms 50 sl. 0 queues (1 buckets) droptail | ||
+ | 00002: 256.000 Kbit/s 0 ms 50 sl. 0 queues (1 buckets) droptail | ||
+ | 00003: 256.000 Kbit/s 0 ms 50 sl. 1 queues (1 buckets) droptail | ||
+ | mask: 0x00 0x00000000/0x0000 -> 0x00000000/0x0000 | ||
+ | BKT Prot ___Source IP/port____ ____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp | ||
+ | 0 udp 92.255.254.17/57095 91.144.152.3/53 5644 533762 0 0 0 | ||
+ | 00004: 256.000 Kbit/s 0 ms 50 sl. 1 queues (1 buckets) droptail | ||
+ | mask: 0x00 0x00000000/0x0000 -> 0x00000000/0x0000 | ||
+ | BKT Prot ___Source IP/port____ ____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp | ||
+ | 0 udp 91.144.152.3/53 92.255.254.17/57095 6154 7809516 0 0 0 | ||
+ | q00022: weight 1 pipe 2 50 sl. 5 queues (64 buckets) droptail | ||
+ | mask: 0x00 0x00000000/0x0000 -> 0xffffffff/0x0000 | ||
+ | BKT Prot ___Source IP/port____ ____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp | ||
+ | 23 ip 0.0.0.0/0 192.168.10.71/0 21 4136 0 0 0 | ||
+ | 27 ip 0.0.0.0/0 192.168.1.203/0 7756 8079804 0 0 0 | ||
+ | 44 ip 0.0.0.0/0 192.168.5.124/0 385 158515 0 0 0 | ||
+ | 47 ip 0.0.0.0/0 192.168.1.255/0 11 1294 0 0 0 | ||
+ | 56 ip 0.0.0.0/0 192.168.1.104/0 135 43137 0 0 0 | ||
+ | q00011: weight 1 pipe 1 50 sl. 11 queues (64 buckets) droptail | ||
+ | mask: 0x00 0xffffffff/0x0000 -> 0x00000000/0x0000 | ||
+ | BKT Prot ___Source IP/port____ ____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp | ||
+ | 4 ip 192.168.1.22/0 0.0.0.0/0 5 541 0 0 0 | ||
+ | 8 ip 192.168.1.112/0 0.0.0.0/0 4 476 0 0 0 | ||
+ | 12 ip 192.168.1.18/0 0.0.0.0/0 1 229 0 0 0 | ||
+ | 16 ip 192.168.5.124/0 0.0.0.0/0 407 30272 0 0 0 | ||
+ | 26 ip 192.168.1.25/0 0.0.0.0/0 1 229 0 0 0 | ||
+ | 38 ip 192.168.1.103/0 0.0.0.0/0 3 404 0 0 0 | ||
+ | 52 ip 192.168.1.14/0 0.0.0.0/0 1 229 0 0 0 | ||
+ | 56 ip 192.168.1.104/0 0.0.0.0/0 147 65848 0 0 0 | ||
+ | 58 ip 192.168.1.9/0 0.0.0.0/0 223 17556 0 0 0 | ||
+ | 60 ip 192.168.1.10/0 0.0.0.0/0 1 234 0 0 0 | ||
+ | 62 ip 192.168.1.203/0 0.0.0.0/0 5775 833667 0 0 0 | ||
+ | ############################################################################## | ||
+ | |||
+ | Продолжение с поправкой... с перемусоливанием выше изложенного. | ||
+ | |||
+ | http://rrv.jino-net.ru/wiki/index.php/QoS_FreeBSD | ||
+ | Для лучшего понимания что к чему... Взято по ссылке и отдельное спасибо | ||
+ | Николаю Ананину за некое объяснение непонятных мною моментов в расчётах. | ||
+ | |||
+ | И так в моём случае с каналом в 256Kbit/s: | ||
+ | QUEUE_TOTA L= MTU*QUEUE_SIZE = (1492*8)*50 = 11936*50 = 596800 бит | ||
+ | где, | ||
+ | MTU = 1492 байт * 8 = 11936 бит | ||
+ | QUEUE_SIZE = количество слотов(пакетов) или байтах (по умолчанию 50) | ||
+ | |||
+ | Время задержки получаем из | ||
+ | T = QUEUE_SIZE/BANDWIDTH = 596800/262144 = ~2,276 секунды. | ||
+ | где, | ||
+ | BANDWIDTH = 256 * 1024 = 262144 бит | ||
+ | |||
+ | НО! ~2 сек. слишком большая задержка, нам нужно хотябы 0,5 сек. | ||
+ | ~2 сек / 0,5 сек = 4 | ||
+ | Наш QUEUE_SIZE = 50 / 4 = 12,5 = ~12 слотов для задержки в 0,5 сек. | ||
+ | |||
+ | Можем даже больше. Можем расчитать gred: | ||
+ | max_th = 12/2 = 6 | ||
+ | min_th = 6/3 = 2 | ||
+ | |||
+ | Получаем правила: | ||
+ | ipfw pipe 1 config bw 256Kbit/s queue 12 | ||
+ | ipfw queue 1 config pipe 1 mask dst-ip 0xffffffff | ||
+ | ipfw add queue 1 ip from any to 192.168.0.0/16 out via bfe0 | ||
+ | ipfw add pass ip from 192.168.0.0/16 to any out via bfe0 | ||
+ | |||
+ | Или правила с gred: | ||
+ | ipfw pipe 1 config bw 256Kbit/s queue 12 gred 0.002/2/6/0.1 | ||
+ | ipfw queue 1 config pipe 1 mask dst-ip 0xffffffff | ||
+ | ipfw add queue 1 ip from any to 192.168.0.0/16 out via bfe0 | ||
+ | ipfw add pass ip from 192.168.0.0/16 to any out via bfe0 | ||
+ | |||
+ | Промежуточный вариант... плох... в нём нету pipe не умеет weight | ||
+ | ipfw pipe 1 config bw 256Kbit/s mask dst-ip 0xffffffff queue 12 gred 0.002/2/6/0.1 | ||
+ | ipfw add pipe 1 ip from any to 192.168.0.0/16 out via bfe0 | ||
+ | |||
+ | Остановился на этом. ж;) | ||
+ | ipfw pipe 1 config bw 256Kbit/s | ||
+ | ipfw queue 1 config pipe 1 weight 50 mask dst-ip 0xffffffff queue 12 gred 0.002/2/6/0.1 | ||
+ | ipfw add queue 1 ip from any to 192.168.0.0/16 out via bfe0 | ||
+ | ipfw add pass ip from any to 192.168.0.0/16 out via bfe0 | ||
+ | |||
+ | Работает как часы! | ||
+ | Всё можно глядеть чрез iftop | ||
+ | sh# iftop -i bfe0 | ||
+ | 195Kb 391Kb 586Kb 781Kb 977Kb | ||
+ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ||
+ | gw2.fortd.ru => 192.168.5.124 118Kb 128Kb 125Kb | ||
+ | gw2.fortd.ru => 192.168.5.38 127Kb 122Kb 125Kb | ||
+ | gw2.fortd.ru => blackhole.fortd.ru 0b 0b 113b | ||
+ | gw2.fortd.ru => 192.168.5.85 0b 0b 58b | ||
+ | 192.168.1.255 => 192.168.1.203 0b 0b 0b | ||
+ | 192.168.1.255 => 192.168.1.9 0b 0b 0b | ||
+ | 255.255.255.255 => 169.254.2.2 0b 0b 0b | ||
+ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ||
+ | TX: cumm: 16.7MB peak: 253Kb rates: 245Kb 250Kb 250Kb | ||
+ | RX: 953KB 13.1Kb 5.55Kb 5.91Kb 6.92Kb | ||
+ | TOTAL: 17.6MB 263Kb 251Kb 256Kb 257Kb | ||
+ | |||
+ | Наконец-то канал поделился как хотелось!!! |
Версия 11:43, 3 ноября 2015
rc.conf
Статические маршруты
static_routes="gp" route_gp="-net 192.168.128.0/22 10.1.1.1"
Алиасы на vlan
cloned_interfaces="vlan80 vlan81" ifconfig_vlan80="inet 192.168.168.10 netmask 255.255.255.0 vlan 80 vlandev em2" ifconfig_vlan80_alias0="alias 192.168.168.11 netmask 255.255.255.0" ifconfig_vlan81="inet 192.168.169.10 netmask 255.255.255.0 vlan 81 vlandev em2" ifconfig_vlan81_alias0="alias 192.168.169.11 netmask 255.255.255.0" при этом не забываем echo 'ifconfig em2 up' >> /etc/rc.local
sysctl.conf
kern.coredump=0 net.inet6.ip6.auto_linklocal=0
gmirror + GPT
Источник [[1]]
- gmirror label -v -b round-robin gm0 /dev/ad0\\
- gmirror load\\
- gpart create -s gpt mirror/gm0\\
- gpart add -t freebsd-boot -s 128k mirror/gm0\\
- gpart add -t freebsd-ufs -s 1G mirror/gm0\\
- gpart add -t freebsd-swap -s 4G -l swap mirror/gm0\\
- gpart add -t freebsd-ufs -s 1G mirror/gm0\\
- gpart add -t freebsd-ufs -s 4G mirror/gm0\\
- gpart add -t freebsd-ufs -s 20G mirror/gm0\\
- gpart bootcode -b /boot/pmbr -p /boot/gptboot -i 1 mirror/gm0\\
- newfs -L rootfs /dev/mirror/gm0p2\\
- newfs -L tmpfs /dev/mirror/gm0p4\\
- newfs -L varfs /dev/mirror/gm0p5\\
- newfs -L usrfs /dev/mirror/gm0p6\\
- mkdir /mnt/root; mkdir /mnt/var; mkdir /mnt/usr\\
- mount /dev/ufs/rootfs /mnt/root\\
- mount /dev/ufs/varfs /mnt/var\\
- mount /dev/ufs/usrfs /mnt/usr\\
Либо с нуля создаем\\
- cd /usr/src\\
- make DESTDIR=/mnt installworld distribution installkernel KERNCONF="YOUR_KERNEL_HERE"\\
Либо копируем существующую систему\\
- cd /; pax -p eme -X -rw . /mnt/root\\
- cd /var; pax -p eme -X -rw . /mnt/var\\
- cd /usr; pax -p eme -X -rw . /mnt/usr\\
- echo 'geom_mirror_load="YES"' >> /mnt/root/boot/loader.conf\\
- echo 'vfs.root.mountfrom="ufs:/dev/ufs/rootfs"' >> /mnt/root/boot/loader.conf\\
- cat > /mnt/root/etc/fstab\\
- Device Mountpoint FStype Options Dump Pass#\\
/dev/gpt/swap none swap sw 0 0\\ /dev/ufs/rootfs / ufs rw 1 1\\ /dev/ufs/usrfs /usr ufs rw 2 2\\ ^D\\
shutdown -r now
Убираем текущий загрузочный диск, делаем загрузочным созданый.
- chmod 1777 /tmp
fail2ban
test
Shell-программирование
Автор: iNo // k0dsweb gr0up Статья является собственностью команды KodsWeb (www.kodsweb.ru) -= 06.09.2006 =-
Intro...
В данной статье я вкратце опишу shell-программирование, рассмотрю простейшие примеры и прокомментирую их. Сразу оговорюсь,что эта статья не является исчерпывающим руководством по shell-программированию. Но её будет достаточно чтобы освоить его основы. Несмотря на кажущуюся простоту shell-программирования, оно является достаточно мощным инструментом администратора unix-системы.Замечу,что для полноценного администрирования unix-системы, уметь программировать на shell просто необходимо. Все примеры протестированы на системе Slackware Linux 10.2 и полностью работоспособны.
Общие положения.
Комментарии начинаются с символа #, за исключением первой строки. Первой строкой сценария является путь к интерпретатору, начинающийся с #! с помошью которого будет запущен данный скрипт. Например:
#!/bin/sh #А вот это уже комментарий
Переменные, ввод и вывод данных.
Для задания переменных используется оператор присваевания "=". Синтаксис следующий:
<переменная>=<значение>
Замечу,что в отличие от языков perl и php,между знаком "=" и остальными параметрами нельзя ставить пробел.В этом случае интерпретатор выдаст ошибку.Чтобы обратится к заданной переменной ,надо вызвать её поставив перед ней знак $.Удалить переменную можно с помощью оператора unset. Оператор Echo просто выводит строку(или переменную), идущую после него:
#!/bin/sh var=Vasya echo $var
>--------------------------------------< Vasya >--------------------------------------<
#!/bin/sh echo My name is Vasya
>--------------------------------------< My name is Vasya >--------------------------------------<
В данный пример также можно добавить одинарные или двойные кавычки, от этого результат работы программы не изменится. Но не стоит использовать обратные кавычки, т.к.эти символы используются для выполнения команд:
#!/bin/sh echo `My name is Vasya"
>--------------------------------------<
Error: My: command not found >--------------------------------------<
#!/bin/sh echo 'ls -a'
>--------------------------------------< . .. .bash_history script.sh >--------------------------------------<
Оператор read присваевает значение переменной.Вот пример,который просит ввести переменную var,считывает её а затем выводит.
#!/bin/sh echo "Input var:" read var echo "The var is $var"
>--------------------------------------< Input var: 123 The var is 123 >--------------------------------------<
Агрументы командной строки.
Как и во всех консольных программах, в shell-сценарий можно передавать аргументы из командной строки.Переменные $1..$9 соответствуют параметрам, переданным из командной строки сценарию.Переменная $0 содержит имя интерпретируемого файла.$#-содержит количество переданных аргументов. $* и $@ содержат все аргументы,но в $@ все аргументы выделены кавычками. Напишем скрипт,который выводит 2 аргумента командной строки и имя исполняемого файла.Запуск скрипта: ./script.sh 1 2
#!/bin/sh echo "Name:$0" echo "First argument:$1" echo "Second argument:$2"
>--------------------------------------<
Name:./script.sh First argument:1 Second argument:2 >--------------------------------------<
Арифметические операции.
Арифметические операции производятся с использованием оператора let. Операции:
- - умножение
/ - деление + - сложение - - вычитание % - деление с остатком
Синтаксис арифметических операций в Shell:
let <значение> <оператор> <значение>
Пример sh let:
#!/bin/sh let res=2*7 echo $res
>--------------------------------------< 14 >--------------------------------------<
Оператор test или [].
Данные операторы предназначены для выполнения сравнений двух значений. Если сравнение успешно-оператор возвращает 0,иначе 1.Код завершения последней выполненной команды хранится в специальной переменной $?.
Синтаксис оператора test:
test <значение> -опция <значение>
или
[<значение> -опция <значение>]
Пример:
#!/bin/sh var=10 [ $var -eq 8 ] echo $?
>--------------------------------------< 1 >--------------------------------------<
Ниже приведены все опции оператора test(или []):
Сравнение целых чисел:
-gt больше чем -lt меньше чем -ge больше чем либо равно -le меньше чем либо равно -eq равно -ne не равно Сравнение строк:
-z проверка на наличие пустой строки -n проверка на наличие строки-значения = равенство != неравенство str проверка на наличие строки,состоящей из нулей Логические операции:
-a И -o ИЛИ ! НЕ Проверка файлов:
-f установка факта существования файла и его регулярности -s проверка,не является-ли файл пустым -r проверка возможности считывания файла -w проверка возможности записи файла -x проверка исполняемости файла -d проверка,является-ли файл каталогом -h проверка,является-ли файл ссылкой -c проверка,является-ли файл байт-ориентированным устройством -d проверка,является-ли файл блок-ориентированным устройством Условия.
Ниже описан синтаксис всех условных операторов, с примерами.
1) if <команда> then <команда> fi
Пример условия if ... then:
#!/bin/sh if [ $1 -eq 10 ]; then echo var=10 fi
Результат работы,при переданном параметре равном 10:
>--------------------------------------< var=10 >--------------------------------------<
2) if <команда> then <команда> else <команда> fi
Пример if ... then ... else:
#!/bin/sh if [ $1 -eq 10 ]; then echo var=10 else echo var!=10 fi
Результат работы,при переданном параметре равном 10:
>--------------------------------------< var=10 >--------------------------------------<
Результат работы,при переданном параметре равном 7:
>--------------------------------------< var!=10 >--------------------------------------<
3) if <команда> then <команда> elif <команда> else <команда> fi
Пример if ... then ... elif ... else:
#!/bin/sh if [ $1 -eq 10 ]; then echo var=10 elif [ $1 -eq 9 ]; then echo var=9 else echo var!=10 and var!=9 fi
Результат работы,при переданном параметре равном 10:
>--------------------------------------< var=10 >--------------------------------------<
Результат работы,при переданном параметре равном 9:
>--------------------------------------<
var=9 >--------------------------------------<
Результат работы,при переданном параметре равном 8:
>--------------------------------------< var!=10 and var!=9 >--------------------------------------<
4) case <строка> in <шаблон>) <команды> ;; *) <команды> ;; esac
Case-конструкция позволяет выбирать один из нескольких альтернативных вариантов.
#!/bin/sh case $1 in 1) echo arg is 1 ;; 2) echo arg is 2 ;; *) echo arg is other ;; esac
Результат работы,при переданном параметре равном 1:
>--------------------------------------< arg is 1 >--------------------------------------<
Результат работы,при переданном параметре равном 2:
>--------------------------------------< arg is 2 >--------------------------------------<
Результат работы,при переданном параметре равном 10:
>--------------------------------------< arg is other >--------------------------------------<
Циклы.
1) while <условие> do <команды> done
Оператор языка shell-программирования while выполняет команды, пока условие истино. Пример:
#!/bin/sh cont=yes while [ $cont = yes ] do echo -n "continue?" read cont done
>--------------------------------------< continue? yes continue? no >--------------------------------------<
2) until <условие> do <команды> done
Оператор until выполняет команды, пока условие ложно. Пример:
#!/bin/sh cont=yes until [ $cont = no ] do echo -n "continue?" read cont done
>--------------------------------------<
continue? yes continue? no >--------------------------------------<
3) for <переменная> do <команды> done
Цикл for - выполняет команды для каждого параметра, который был передан сценарию в командной строке. Пример:
#!/bin/sh for var do echo $var done
Результат работы программы,с параметрами 1 2 3 4 5:
>--------------------------------------< 1 2 3 4 5 >--------------------------------------<
4) for <переменная> in <строка> do <команды> done Эта конструкция отличается от обычного for тем, что параметры берутся не из командной строки, а из строки после оператора in.
5) select <строка> in <перечень элементов> do <команды> done Конструкция select создаёт меню на основе элементов заданного списка, а затем выполняет для него указанную команду. Пример:
#!/bin/sh select var in 1 2 3 do case $var in 1) echo Number 1 ;; 2) echo Number 2 ;; 3) echo Number 3 ;; *) echo Other ;; esac done
>--------------------------------------<
1) 1 2) 2 3) 3 #? 3 Number 3 #? _ >--------------------------------------<
Оригинал статьи http://www.opennet.ru/base/dev/shell_coding.txt.html
IPFW PIPE
options DUMMYNET ;Шейпер options HZ=1000 ;Частота системного таймера, (1000=1ms,100=10ms,0=NO!)
net.inet.ip.fw.one_pass: 1 ;Заставляет напрямую поток из dummynet идти в большой мир миную ;последующие правилам фаирвола net.inet.ip.fw.one_pass: 0 ;Заставляет идти выходящий поток из dummynet по ниже стоящим правилам
ipfw pipe NNN config bw B delay D queue Q plr P
NNN Номер полосы bw Ширина полосы ;{K | M}{bit/s | Bytes/s} delay Велечина задержки ;(ms) queue Размер очереди ;(slots,Bytes) weight Вес/приоритет очереди ;( [1..100], default =1! 1-min 100-max ) pipe Канал для связи с очердью или очередями ; plr Доля потеряных пакетов случайным образом ;( 0,0..1,0] 0 =100%pass, 1 =100%reject) mask Группировка по маске ;(dst-ip, src-ip, dst-port, src-port, proto, all) red | gred Выполняет алгоритм управления очередью RED ;(w_q/min_th/max_th/max_p) ;w_q - вес очереди ;min_th - минимальный порог ;max_th - максимальный порог ;max_p - максимальная вероятность отбрасывания пакета ;w_q и max_p ( !=0..1] ) ;min_th и max_th (slots,Bytes)
При использовании алгоритма Random Early Detection (RED): Если уровень перегрузки* находится между порогами min_th и max_th, пакеты отбрасываются с линейно возрастающей вероятностью от 0 до max_p, которая достигается при достижении второго порога (max_th). Когда перегрузка выше второго порога, все пакеты отбрасываются.
При использовании алгоритма Gentle RED (GRED): Если уровень перегрузки* находится между порогами min_th и max_th, пакеты отбрасываются с линейно возрастающей вероятностью от 0 до max_p. Когда уровень перегрузки больше max_th, но меньше 2*max_th, то пакеты отбрасываются не все, как в случае с RED, а с линейно возрастающей вероятностью от max_th до 1. Все пакеты отбрасываются только после превышения значения уровня перегрузки канала 2*max_th.
Время заполнения очереди или время задержки при стандартном значении MTU (1500) определяется:
T=(MTU*byte*Q)/L (сек)
где: MTU - значение MTU; byte - 8 бит, чтобы перевести в биты, так как MTU в байтах Q - размер очереди в слотах; L - пробускная способность канала, бит/с.
Получаем что-то типа: T=(1500*8*Q)/L
Далее, если мы хотим чтобы при канале шириной в 256Kbit/s задержки не привышали 100ms, можем расчитать Q!
Мой канал 256Kbit/s -> 256*1024bit/s PPPOE(MTU) 1500 -> 1492 100ms/1000c=0,1ms
Q=(T*L)/(MTU*byte)
Получаем, при <=100ms Q=(0,1s*262144bit/s)/(1492*8)=26214,4/11936=~2,1=2слота
Получаем, при <=200ms Q=(0,2s*262144bit/s)/(1492*8)=52428,8/11936=~4,3=4слота
Получаем, при <=500ms Q=(0,5s*262144bit/s)/(1492*8)=131072/11936=~10,9=10слотов
Получаем, при <=1s Q=(1s*262144bit/s)/(1492*8)=262144/11936=~21,9=21слот
DUMMYNET позволяет установить очередь до 100 слотов, но округлем в меньшую сторону, дабы не вылазить за рамки и не получать отбрасываемых пакетов.
При нашем расчёте время задержки, при <=0,1s: T=(MTU*byte*Q)/L, при 0,1s; T=(1492*8*2)/262144=23872/262144=0,091c при 0,2s; T=(1492*8*4)/262144=47744/262144=0,182c при 0,5s; T=(1492*8*10)/262144=119360/262144=0,455c при 1s; T=(1492*8*21)/262144=250656/262144=0,956c
Для алгоритма RED или GRED расчитаем нижний порог: min_th=(T*L)/(MTU*byte) (слотов) min_th=(0,1*262144)/(1492*8)=26214,4/11936=~2,1=2слота, как у нас уже расчитано выше.
Теперь расчитаем верхний порог: max_th=(2..5)*min_th(слотов),возьмём среднее 3 max_th=3*2=6слотов, верхний порог, при задержки в 0,1s max_th=3*4=12слотов, верхний порог, при задержки в 0,2s max_th=3*10=30слотов, верхний порог, при задержки в 0,5s max_th=3*21=63слотa, верхний порог, при задержки в 1s
Далее нам нужно уровень перегрузки канала, при котором все пакеты будут отбрасываться: Q=2*max_th, Q=2*6=12слотов, при задержки в 0,1s Q=2*12=24слотов, при задержки в 0,2s Q=2*30=60слотов, при задержки в 0,5s Q=2*63=126слотов, при задержки в 1s - ???Получаем лажу! DUMMYNET способен только на 100слотов
Получаем следующие правила ipfw pipe 1 config bw 256Kbit/s queue 12 gred 0.002/2/6/0.1 ipfw pipe 2 config bw 256Kbit/s queue 24 gred 0.002/4/12/0.1
ipfw pipe4 config bw 256Kbit/s queue 126 gred 0.002/21/63/0.1 - ?! Но попробовать стоит ж;)
ipfw: 2 <= queue size <= 100 ;Вот такая ругань получилась )))
И три трубы которые принял ipfw образовали:
00001: 256.000 Kbit/s 0 ms 12 sl. 0 queues (1 buckets) ;Пакеты бьються
GRED w_q 0.001999 min_th 2 max_th 6 max_p 0.099991
00002: 256.000 Kbit/s 0 ms 48 sl. 0 queues (1 buckets) ;Средний вариант
GRED w_q 0.001999 min_th 4 max_th 12 max_p 0.099991
00003: 256.000 Kbit/s 0 ms 60 sl. 0 queues (1 buckets) ;Слишком большой pipe?!
GRED w_q 0.001999 min_th 10 max_th 30 max_p 0.099991
Так же можно вполне задать очередь в KBytes не только в слотах и очередь не должна привышать ширину канала, иначе будет куча битых пакетов. По советам её бы уменьшить процентов на 5%-10%. 256/8=32Kbytes/s, (32/100%)*5%=3,2=~4Kbytes, 32-4=28Kbytes, ipfw pipe 1 config bw 256Kbit/s queue 28Kbytes
Так же окружающие советуют: w_q=0.002/min_th=(queue/10)/max_th=(3*min_th)/max_p=0.1, при queue 30 слотах
Теперь к экспериментам! ... из всего что я понял и усвоил, я планирую: 1. создать 2 трубы pipe 1,2 и сделать честное деление канала по скорости между пользователям, типа: local->GW и GW<-local
2. создать 2 трубы и сделать 2 очереди для входящего и исходящего траффика типа GW->inet и inet<-GW с алгоритмом GRED, для предотвращения перегрузок
Немного схем... ;)
--> in --> out [-Л-К-Л-А-]-pipe1-[-c-р-е--]-pipe3-[-И-Е--] [--О-А-К--]-pipe2-[--e-в-р-]-pipe4-[--Н-Т-] <-- out <-- in
Результат при 256Kbit/s pipe 10 config bw 256Kbit/s queue 12 0.002/2/6/0.1 ~23.29 Kbytes/sec pipe 10 config bw 256Kbit/s queue 24 0.002/2/8/0.1 ~23.73 Kbytes/sec pipe 10 config bw 256Kbit/s queue 24 0.002/3/12/0.1 ~26.37 Kbytes/sec pipe 10 config bw 256Kbit/s queue 30 0.002/3/15/0.1 ~22.24 Kbytes/sec pipe 10 config bw 256Kbit/s queue 48 0.002/8/24/0.1 ~26.66 Kbytes/sec pipe 10 config bw 256Kbit/s queue 60 0.002/10/30/0.1 ~27.19 Kbytes/sec pipe 10 config bw 256Kbit/s queue 100 0.002/33/50/0.1 ~22.99 Kbytes/sec То что народ насоветовал ;) pipe 10 config bw 256Kbit/s queue 30 0.002/3/9/0.1 ~24.46 Kbytes/sec
В итоге написал такие правила:
- BANDWISH (PIPE & QUEUE)
- NO_PASS_ALL_AFTER_BANDWISH
sysctl net.inet.ip.fw.one_pass=0
- FLUSH
ipfw -f flush ipfw -f pipe flush ipfw -f queue flush
- CONFIG & ADD RULES
ipfw add pass ip from localhost to localhost via lo0
ipfw pipe 1 config bw 256Kbit/s ipfw queue 11 config pipe 1 mask src-ip 0xffffffff ipfw add queue 11 ip from 192.168.0.0/16 to any in via bfe0 ipfw add pass ip from 192.168.0.0/16 to any in via bfe0
ipfw pipe 2 config bw 256Kbit/s ipfw queue 22 config pipe 2 mask dst-ip 0xffffffff ipfw add queue 22 ip from any to 192.168.0.0/16 out via bfe0 ipfw add pass ip from 192.168.0.0/16 to any out via bfe0
ipfw pipe 3 config bw 256Kbit/s #queue 60 gred 0.002/10/30/0.1 ipfw add pipe 3 ip from 92.255.254.17 to any out via tun0 ipfw add pass ip from 92.255.254.17 to any out via tun0
ipfw pipe 4 config bw 256Kbit/s #queue 60 gred 0.002/10/30/0.1 ipfw add pipe 4 ip from any to 92.255.254.17 in via tun0 ipfw add pass ip from any to 92.255.254.17 in via tun0
В случае чего можно расскоментировать #queue 60 gred 0.002/10/30/0.1 Для сглаживания шороховатостей, но а пока я не увидел битых пакетов.
gw2# ipfw pipe show
00001: 256.000 Kbit/s 0 ms 50 sl. 0 queues (1 buckets) droptail 00002: 256.000 Kbit/s 0 ms 50 sl. 0 queues (1 buckets) droptail 00003: 256.000 Kbit/s 0 ms 50 sl. 1 queues (1 buckets) droptail
mask: 0x00 0x00000000/0x0000 -> 0x00000000/0x0000
BKT Prot ___Source IP/port____ ____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp
0 udp 92.255.254.17/57095 91.144.152.3/53 5644 533762 0 0 0
00004: 256.000 Kbit/s 0 ms 50 sl. 1 queues (1 buckets) droptail
mask: 0x00 0x00000000/0x0000 -> 0x00000000/0x0000
BKT Prot ___Source IP/port____ ____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp
0 udp 91.144.152.3/53 92.255.254.17/57095 6154 7809516 0 0 0
q00022: weight 1 pipe 2 50 sl. 5 queues (64 buckets) droptail
mask: 0x00 0x00000000/0x0000 -> 0xffffffff/0x0000
BKT Prot ___Source IP/port____ ____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp
23 ip 0.0.0.0/0 192.168.10.71/0 21 4136 0 0 0 27 ip 0.0.0.0/0 192.168.1.203/0 7756 8079804 0 0 0 44 ip 0.0.0.0/0 192.168.5.124/0 385 158515 0 0 0 47 ip 0.0.0.0/0 192.168.1.255/0 11 1294 0 0 0 56 ip 0.0.0.0/0 192.168.1.104/0 135 43137 0 0 0
q00011: weight 1 pipe 1 50 sl. 11 queues (64 buckets) droptail
mask: 0x00 0xffffffff/0x0000 -> 0x00000000/0x0000
BKT Prot ___Source IP/port____ ____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp
4 ip 192.168.1.22/0 0.0.0.0/0 5 541 0 0 0 8 ip 192.168.1.112/0 0.0.0.0/0 4 476 0 0 0 12 ip 192.168.1.18/0 0.0.0.0/0 1 229 0 0 0 16 ip 192.168.5.124/0 0.0.0.0/0 407 30272 0 0 0 26 ip 192.168.1.25/0 0.0.0.0/0 1 229 0 0 0 38 ip 192.168.1.103/0 0.0.0.0/0 3 404 0 0 0 52 ip 192.168.1.14/0 0.0.0.0/0 1 229 0 0 0 56 ip 192.168.1.104/0 0.0.0.0/0 147 65848 0 0 0 58 ip 192.168.1.9/0 0.0.0.0/0 223 17556 0 0 0 60 ip 192.168.1.10/0 0.0.0.0/0 1 234 0 0 0 62 ip 192.168.1.203/0 0.0.0.0/0 5775 833667 0 0 0
Продолжение с поправкой... с перемусоливанием выше изложенного.
http://rrv.jino-net.ru/wiki/index.php/QoS_FreeBSD Для лучшего понимания что к чему... Взято по ссылке и отдельное спасибо Николаю Ананину за некое объяснение непонятных мною моментов в расчётах.
И так в моём случае с каналом в 256Kbit/s: QUEUE_TOTA L= MTU*QUEUE_SIZE = (1492*8)*50 = 11936*50 = 596800 бит где, MTU = 1492 байт * 8 = 11936 бит QUEUE_SIZE = количество слотов(пакетов) или байтах (по умолчанию 50)
Время задержки получаем из T = QUEUE_SIZE/BANDWIDTH = 596800/262144 = ~2,276 секунды. где, BANDWIDTH = 256 * 1024 = 262144 бит
НО! ~2 сек. слишком большая задержка, нам нужно хотябы 0,5 сек. ~2 сек / 0,5 сек = 4 Наш QUEUE_SIZE = 50 / 4 = 12,5 = ~12 слотов для задержки в 0,5 сек.
Можем даже больше. Можем расчитать gred: max_th = 12/2 = 6 min_th = 6/3 = 2
Получаем правила: ipfw pipe 1 config bw 256Kbit/s queue 12 ipfw queue 1 config pipe 1 mask dst-ip 0xffffffff ipfw add queue 1 ip from any to 192.168.0.0/16 out via bfe0 ipfw add pass ip from 192.168.0.0/16 to any out via bfe0
Или правила с gred: ipfw pipe 1 config bw 256Kbit/s queue 12 gred 0.002/2/6/0.1 ipfw queue 1 config pipe 1 mask dst-ip 0xffffffff ipfw add queue 1 ip from any to 192.168.0.0/16 out via bfe0 ipfw add pass ip from 192.168.0.0/16 to any out via bfe0
Промежуточный вариант... плох... в нём нету pipe не умеет weight ipfw pipe 1 config bw 256Kbit/s mask dst-ip 0xffffffff queue 12 gred 0.002/2/6/0.1 ipfw add pipe 1 ip from any to 192.168.0.0/16 out via bfe0
Остановился на этом. ж;) ipfw pipe 1 config bw 256Kbit/s ipfw queue 1 config pipe 1 weight 50 mask dst-ip 0xffffffff queue 12 gred 0.002/2/6/0.1 ipfw add queue 1 ip from any to 192.168.0.0/16 out via bfe0 ipfw add pass ip from any to 192.168.0.0/16 out via bfe0
Работает как часы! Всё можно глядеть чрез iftop sh# iftop -i bfe0
195Kb 391Kb 586Kb 781Kb 977Kb
gw2.fortd.ru => 192.168.5.124 118Kb 128Kb 125Kb gw2.fortd.ru => 192.168.5.38 127Kb 122Kb 125Kb gw2.fortd.ru => blackhole.fortd.ru 0b 0b 113b gw2.fortd.ru => 192.168.5.85 0b 0b 58b 192.168.1.255 => 192.168.1.203 0b 0b 0b 192.168.1.255 => 192.168.1.9 0b 0b 0b 255.255.255.255 => 169.254.2.2 0b 0b 0b
TX: cumm: 16.7MB peak: 253Kb rates: 245Kb 250Kb 250Kb RX: 953KB 13.1Kb 5.55Kb 5.91Kb 6.92Kb TOTAL: 17.6MB 263Kb 251Kb 256Kb 257Kb
Наконец-то канал поделился как хотелось!!!