2 /* ============================================================= */
3 /* === Prometheus QoS - you can "steal fire" from your ISP === */
4 /* === "fair-per-IP" quality of service (QoS) utility === */
5 /* === requires Linux 2.4.x or 2.6.x with HTB support === */
6 /* === Copyright(C) 2005-2007 Michael Polak (xChaos) === */
7 /* === Credits: CZFree.Net, Martin Devera, Netdave, Aquarius === */
8 /* ============================================================= */
10 /* Modified: xChaos, 20070502
12 Prometheus QoS is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation; either version 2.1 of
15 the License, or (at your option) any later version.
17 Prometheus QoS is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with the Linux kernel source code; if not, write to
24 Michael Polak, Svojsikova 7, 169 00 Praha 6 Czech Republic */
27 #define MAX_GUARANTED_KBPS 2048
32 const char *version
="0.7.1";
34 /* ======= Help screen is hopefuly self-documenting part of code :-) ======= */
38 puts("Command line switches:\n\
40 -?, --help this help screen\n\
41 -v, --version show version number of this utility and exit\n\
42 -c filename force alternative /etc/prometheus.conf filename\n\
43 -h filename force alternative /etc/hosts filename (overrides hosts keyword)\n\
44 -f just flush iptables and tc classes and exit (stop shaping)\n\
45 -9 emergency iptables flush (do not read data transfer statistics)\n\
46 -p just generate preview of data transfer statistics and exit\n\
47 -n no delay (overrides qos-free-delay keyword)\n\
48 -d dry run (preview tc and iptables commands on stdout)\n\
52 /* === Configuraration file values defaults - stored in global variables ==== */
54 int dry_run
=0; /* preview - use puts() instead of system() */
55 char *config
="/etc/prometheus.conf"; /* main configuration file */
56 char *hosts
="/etc/hosts"; /* line bandwidth definition file */
57 char *tc
="/sbin/tc"; /* requires tc with HTB support */
58 char *iptables
="/sbin/iptables"; /* requires iptables utility */
59 char *html
="/var/www/traffic.html"; /* hall of fame filename */
60 char *preview
="/var/www/preview.html"; /* hall of fame preview */
61 char *cmdlog
="/var/log/prometheus"; /* command log filename */
62 char *credit
="/var/run/prometheus.credit"; /* credit log file */
63 int enable_credit
=1; /* enable credit file */
64 int use_credit
=0; /* use credit file (if enabled)*/
65 char *log_dir
="/var/www/html/logs/"; /* log directory pathname */
66 char *log_url
="logs/"; /* log directory URL prefix */
67 char *title
="Hall of Fame - Greatest Suckers"; /* hall of fame title */
68 int hall_of_fame
=1; /* enable hall of fame */
69 char *lan
="eth0"; /* LAN interface */
70 char *lan_medium
="100Mbit"; /* 10Mbit/100Mbit ethernet */
71 char *wan
="eth1"; /* WAN/ISP interface */
72 char *wan_medium
="100Mbit"; /* 10Mbit/100Mbit ethernet */
73 char *qos_leaf
="sfq perturb 5"; /* leaf discipline */
74 char *qos_free_zone
=NULL
; /* QoS free zone */
75 int qos_proxy
=1; /* include proxy port to QoS */
76 int include_upload
=1; /* upload+download=total traffic */
77 char *proxy_ip
="192.168.1.1/32"; /* our IP with proxy port */
78 int proxy_port
=3128; /* proxy port number */
79 int line
=1024; /* WAN/ISP download in kbps */
80 int up
=1024; /* WAN/ISP upload in kbps */
81 int free_min
=32; /* minimum guaranted bandwidth for all undefined hosts */
82 int free_max
=64; /* maximum allowed bandwidth for all undefined hosts */
83 int qos_free_delay
=0; /* seconds to sleep before applying new QoS rules */
84 int digital_divide
=2; /* controls digital divide weirdness ratio, 1...3 */
85 int max_nesting
=3; /* maximum nesting of HTB clases, built-in maximum seems to be 4 */
86 int burst
=8; /* HTB burst (in kbits) */
87 int magic_priorities
=8; /* number of priority levels (soft shaping) */
88 int magic_treshold
=8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */
91 /* not yet implemented:
92 int fixed_packets=0; maximum number of pps per IP address (not class!)
93 int packet_limit=5; maximum number of pps to htn CEIL, not rate !!!
97 char *kwd
="via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */
99 const idxtable_treshold1
=24; /* this is no longer configurable */
100 const idxtable_treshold2
=12; /* this is no longer configurable */
101 const idxtable_bitmask1
=3; /* this is no longer configurable */
102 const idxtable_bitmask2
=3; /* this is no longer configurable */
105 /* not yet implemented:
106 -s start shaping! (keep data transfer statistics - but apply shaping)\n\
107 -r just reload configuration (...and keep data transfer statistics)\n\
110 /* ==== This is C<<1 stuff - learn C<<1 first! http://cll1.arachne.cz ==== */
123 unsigned long long direct
;
124 unsigned long long proxy
;
125 unsigned long long upload
;
126 unsigned long long traffic
;
127 unsigned long long credit
;
128 unsigned long pktsup
;
129 unsigned long pktsdown
;
130 struct Keyword
*keyword
;
132 } *ips
=NULL
, *ip
, *sharedip
;
140 } *groups
=NULL
, *group
;
146 struct Index
*parent
;
150 } *idxs
=NULL
, *idx
, *metaindex
;
156 int asymetry_ratio
; /* ratio for ADSL-like upload */
157 int asymetry_fixed
; /* fixed treshold for ADSL-like upload */
158 int data_limit
; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
159 int prio_limit
; /* soft shaping (qos): reduce HTB prio if max*prio_limit MB exceeded */
160 long fixed_limit
; /* fixed data limit for setting lower HTB ceil */
161 long fixed_prio
; /* fixed data lmit for setting lower HTB prio */
162 int reserve_min
; /* bonus for nominal HTB rate bandwidth (in kbps) */
163 int reserve_max
; /* malus for nominal HTB ceil (in kbps) */
164 // int divide_max; /* relative malus: new_ceil=rate+(old_ceil-rate)/divide_max */
165 // int htb_ceil_bonus_divide; /* relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide */
166 int default_prio
; /* default HTB priority for this keyword */
171 } *keyword
,*defaultkeyword
=NULL
,*keywords
=NULL
;
173 /* Damned, this must be object oriented! This looks almost like constructor ;-) */
183 ip
->mark
=ip
->min
=ip
->max
=ip
->desired
=ip
->credit
=0;
184 ip
->upload
=ip
->proxy
=ip
->direct
=ip
->traffic
=0;
185 ip
->pktsup
=ip
->pktsdown
=0;
186 ip
->keyword
=keywords
;
190 /* ====== Iptables indexes are used to reduce complexity to log8(N) ===== */
192 char *very_ugly_ipv4_code(char *inip
,int bitmask
,int format_as_chainname
)
194 /* warning: this function was debugged only for bitmask values 20,24,28 !!!*/
196 char *ip
,*outip
,*outptr
,*fmt
;
199 /* debug printf("(%s,%d) -> ",ip,bitmask); */
201 if(ip
&& *ip
&& bitmask
>=0 && bitmask
<=32)
202 string(outip
,strlen(ip
)+10); /*fuck unicode? assertion: 10>strlen("_%d_%d") */
204 /* should never exit here */
211 if(dot
<(bitmask
/8-1))
213 if(format_as_chainname
)
222 char *cutdot
=strchr(ip
+1,'.'); /*for bitmask<24*/
223 if(cutdot
)*cutdot
='\0';
224 if(format_as_chainname
)
229 n
=atoi(ip
+1)-atoi(ip
+1)%(1<<(8-bitmask
%8));
233 /*debug printf("%d/%d => [_%d_%d]\n",atoi(ip+1),bitmask,n,bitmask); */
234 sprintf(outptr
,fmt
,n
,bitmask
);
235 if(!format_as_chainname
) while(bitmask
<24)
240 /* debug printf("[%s]\n",outip); */
251 /*should never exit here*/
256 char *hash_id(char *ip
,int bitmask
)
257 { return very_ugly_ipv4_code(ip
,bitmask
,1); }
259 char *subnet_id(char *ip
,int bitmask
)
260 { return very_ugly_ipv4_code(ip
,bitmask
,0); }
262 /* ================= Let's parse configuration file here =================== */
264 void reject_config_and_exit(char *filename
)
266 printf("Configuration file %s rejected - abnormal exit.",filename
);
270 void get_config(char *config_filename
)
272 printf("Configured keywords: ");
273 parse(config_filename
)
275 option("keyword",kwd
);
280 create(keyword
,Keyword
);
282 keyword
->asymetry_ratio
=1; /* ratio for ADSL-like upload */
283 keyword
->asymetry_fixed
=0; /* fixed treshold for ADSL-like upload */
284 keyword
->data_limit
=8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
285 keyword
->prio_limit
=4; /* soft shaping (qos): reduce HTB prio if max*prio_limit MB exceeded */
286 keyword
->fixed_limit
=0; /* fixed data limit for setting lower HTB ceil */
287 keyword
->fixed_prio
=0; /* fixed data limit for setting lower HTB prio */
288 keyword
->reserve_min
=8; /* bonus for nominal HTB rate bandwidth (in kbps) */
289 keyword
->reserve_max
=0; /* malus for nominal HTB ceil (in kbps) */
291 keyword->divide_max=0; relative malus: new_ceil=rate+(old_ceil-rate)/divide_max
292 keyword->htb_ceil_bonus_divide=0; relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide
294 keyword
->default_prio
=1;
295 keyword
->html_color
="000000";
298 push(keyword
,keywords
);
299 if(!defaultkeyword
) defaultkeyword
=keyword
;
304 else every(keyword
,keywords
)
306 int l
=strlen(keyword
->key
);
309 if(!strncmp(keyword
->key
,_
,l
) && strlen(_
)>l
+2)
311 char *tmptr
=_
; /* <---- l+1 ----> */
312 _
+=l
+1; /* via-prometheus-asymetry-ratio, etc. */
313 ioption("asymetry-ratio",keyword
->asymetry_ratio
);
314 ioption("asymetry-treshold",keyword
->asymetry_fixed
);
315 ioption("magic-relative-limit",keyword
->data_limit
);
316 ioption("magic-relative-prio",keyword
->prio_limit
);
317 loption("magic-fixed-limit",keyword
->fixed_limit
);
318 loption("magic-fixed-prio",keyword
->fixed_prio
);
319 ioption("htb-default-prio",keyword
->default_prio
);
320 ioption("htb-rate-bonus",keyword
->reserve_min
);
321 ioption("htb-ceil-malus",keyword
->reserve_max
);
323 ioption("htb-ceil-divide",keyword->divide_max);
324 ioption("htb-ceil-bonus-divide",keyword->htb_ceil_bonus_divide);
326 option("html-color",keyword
->html_color
);
329 if(keyword
->data_limit
|| keyword
->fixed_limit
||
330 keyword
->prio_limit
|| keyword
->fixed_prio
)
338 option("iptables",iptables
);
339 option("hosts",hosts
);
340 option("lan-interface",lan
);
341 option("wan-interface",wan
);
342 option("lan-medium",lan_medium
);
343 option("wan-medium",wan_medium
);
344 ioption("wan-download",line
);
345 ioption("wan-upload",up
);
346 ioption("hall-of-fame-enable",hall_of_fame
);
347 option("hall-of-fame-title",title
);
348 option("hall-of-fame-filename",html
);
349 option("hall-of-fame-preview",preview
);
350 option("log-filename",cmdlog
);
351 option("credit-filename",credit
);
352 ioption("credit-enable",enable_credit
);
353 option("log-traffic-directory",log_dir
);
354 option("log-traffic-url-path",log_url
);
355 option("qos-free-zone",qos_free_zone
);
356 ioption("qos-free-delay",qos_free_delay
);
357 ioption("qos-proxy-enable",qos_proxy
);
358 option("qos-proxy-ip",proxy_ip
);
359 option("htb-leaf-discipline",qos_leaf
);
360 ioption("qos-proxy-port",proxy_port
);
361 ioption("free-rate",free_min
);
362 ioption("free-ceil",free_max
);
363 ioption("htb-burst",burst
);
364 ioption("htb-nesting-limit",max_nesting
);
365 ioption("magic-include-upload",include_upload
);
366 ioption("magic-priorities",magic_priorities
);
367 ioption("magic-treshold",magic_treshold
);
368 /* not yet implemented:
369 ioption("magic-fixed-packets",fixed_packets);
370 ioption("magic-relative-packets",packet_limit);
375 perror(config_filename
);
376 puts("Warning - using built-in defaults instead ...");
381 /* are supplied values meaningful ?*/
384 puts("Illegal value of wan bandwidth: 0 kbps.");
385 reject_config_and_exit(config_filename
);
389 /* ===================== traffic analyser - uses iptables ================ */
391 void get_traffic_statistics(void)
396 textfile(Pipe
,str
) *line
,*lines
=NULL
;
400 sprintf(cmd
,"%s -L -v -x -n -t mangle",iptables
);
412 int col
, accept
=0,proxyflag
=0,valid
=1,setchainname
=0,commonflag
=0;
413 unsigned long long traffic
=0;
414 unsigned long pkts
=0;
415 char *ipaddr
=NULL
,*ptr
;
417 /* debug puts(line->str); */
418 valid_columns(ptr
,line
->str
,' ',col
)
419 if(valid
) switch(col
)
421 case 1: if(eq(ptr
,"Chain"))
423 else if(eq(ptr
,"pkts"))
426 sscanf(ptr
,"%lu",&pkts
);
428 case 2: if(setchainname
)
430 if(!strncmp(ptr
,"post_",5) || eq(ptr
,"POSTROUTING"))
433 if(!strncmp(ptr
,"forw_",5) || eq(ptr
,"FORWARD"))
436 if(eq(ptr
,"post_common") || eq(ptr
,"forw_common"))
440 sscanf(ptr
,"%Lu",&traffic
); traffic
+=(1<<19); traffic
>>=20;
442 case 3: if(strncmp(ptr
,"post_",5) && strncmp(ptr
,"forw_",5) || commonflag
)
443 accept
=eq(ptr
,"MARK");
445 case 8: if(downloadflag
)
447 if(strstr(proxy_ip
,ptr
))proxyflag
=1;
452 case 9: if(downloadflag
)ipaddr
=ptr
;break;
455 if(accept
&& traffic
>0 && ipaddr
)
457 if(proxyflag
)printf("(proxy) ");
458 else if(!downloadflag
) printf("(upload) ");
459 printf("IP %s: %Lu M (%ld pkts)\n", ipaddr
, traffic
, pkts
);
460 find(ip
,ips
,eq(ip
->addr
,ipaddr
));
465 if(eq(ip
->addr
,"0.0.0.0/0"))
467 ip
->name
="(unregistered)";
469 ip
->max
=ip
->desired
=free_max
;
478 ip
->traffic
+=traffic
;
479 ip
->direct
=ip
->traffic
-ip
->upload
-ip
->proxy
;
487 ip
->traffic
+=traffic
;
489 if(traffic
>ip
->traffic
)
499 /* ========== This function executes, logs OR ALSO prints command ========== */
501 void safe_run(char *cmd
)
503 if(dry_run
) printf("\n=>%s\n",cmd
); else system(cmd
);
504 if(log_file
) fprintf(log_file
,"%s\n",cmd
);
507 /* == This function strips extra characters after IP address and stores it = */
509 void parse_ip(char *str
)
511 char *ptr
=str
,*ipaddr
=NULL
,*ipname
=NULL
;;
513 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
519 while(*ptr
&& (*ptr
==' ' || *ptr
==9))
522 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
526 find(ip
,ips
,eq(ip
->addr
,ipaddr
)); else TheIP();
531 char *parse_datafile_line(char *str
)
533 char *ptr
=strchr(str
,' ');
545 /*-----------------------------------------------------------------*/
546 /* Are you looking for int main (int argc, char **argv) ? :-)) */
547 /*-----------------------------------------------------------------*/
555 int class_count
=0,ip_count
=0;
559 int just_preview
=0; /* preview - generate just stats */
560 char *chain_forward
, *chain_postrouting
;
564 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
565 Version %s - Copyright (C)2005-2007 Michael Polak (xChaos)\n\
566 Credits: CZFree.Net, Martin Devera, Netdave, Aquarius\n\n",version
);
568 /*----- Boring... we have to check command line options first: ----*/
572 argument("-c") { nextargument(config
); }
573 argument("-h") { nextargument(althosts
);}
574 argument("-d") { dry_run
=1; }
575 argument("-f") { just_flush
=1; }
576 argument("-9") { just_flush
=9; }
577 argument("-p") { just_preview
=1; }
578 argument("-n") { nodelay
=1; }
579 argument("-?") { help(); exit(0); }
580 argument("--help") { help(); exit(0); }
581 argument("-v") { exit(0); }
582 argument("--version") { exit(0); }
586 puts("*** THIS IS JUST DRY RUN ! ***\n");
588 date(d
); /* this is typical cll1.h macro */
590 /*-----------------------------------------------------------------*/
591 printf("Parsing configuration file %s ...\n", config
);
592 /*-----------------------------------------------------------------*/
595 if(althosts
) hosts
=althosts
;
599 /*-----------------------------------------------------------------*/
600 puts("Parsing iptables verbose output ...");
601 /*-----------------------------------------------------------------*/
602 get_traffic_statistics();
605 /*-----------------------------------------------------------------*/
606 printf("Parsing class defintion file %s ...\n", hosts
);
607 /*-----------------------------------------------------------------*/
612 if(*str
<'0' || *str
>'9')
615 //Does this IP share QoS class with some other ?
616 substring
=strstr(str
,"sharing-");
619 substring
+=8; //"sharing-"
622 ip
->sharing
=substring
;
623 ip
->keyword
=defaultkeyword
; /* settings for default keyword */
624 while(*substring
&& *substring
!='\n')
630 //Do we have to create new QoS class for this IP ?
632 find(keyword
,keywords
,(substring
=strstr(str
,keyword
->key
)))
638 ip
->prio
=keyword
->default_prio
;
639 substring
+=strlen(keyword
->key
)+1;
641 while(*ptr
&& *ptr
!='-')
646 ip
->max
=ip
->desired
=atoi(ptr
+1);
648 ip
->min
=atoi(substring
);
651 puts("Illegal value of minimum bandwidth: 0 kbps.");
652 reject_config_and_exit(hosts
);
657 ip
->max
=ip
->min
+ip
->keyword
->reserve_min
;
661 ip
->max
-=ip
->keyword
->reserve_max
;
664 if(ip->keyword->divide_max>1)
665 ip->max=ip->min+(ip->max-ip->min)/ip->keyword->divide_max;
666 if(ip->keyword->htb_ceil_bonus_divide>0)
667 ip->max+=ip->max/ip->keyword->htb_ceil_bonus_divide;
672 ip
->mark
=MAX_GUARANTED_KBPS
+1+class_count
++;
674 find(group
,groups
,group
->min
==ip
->min
)
677 group
->desired
+=ip
->min
;
684 if(group
->min
<8) group
->min
=8;
685 /* Warning - this is maybe because of primitive tc namespace, can be fixed */
686 /* it is because class IDs are derived from min. bandwidth. - xCh */
687 if(group
->min
>MAX_GUARANTED_KBPS
) group
->min
=MAX_GUARANTED_KBPS
;
690 group
->desired
=ip
->min
;
691 insert(group
,groups
,desc_order_by
,min
);
703 /*-----------------------------------------------------------------*/
704 /* cll1.h - let's allocate brand new character buffer... */
705 /*-----------------------------------------------------------------*/
708 /*-----------------------------------------------------------------*/
709 puts("Resolving shared connections ...");
710 /*-----------------------------------------------------------------*/
711 search(ip
,ips
,ip
->sharing
)
713 search(sharedip
,ips
,eq(sharedip
->name
,ip
->sharing
))
715 sharedip
->traffic
+=ip
->traffic
;
717 ip
->mark
=sharedip
->mark
;
721 printf("Unresolved shared connection: %s %s sharing-%s\n",ip
->addr
,ip
->name
,ip
->sharing
);
724 if(enable_credit
&& just_flush
<9)
726 /*-----------------------------------------------------------------*/
727 printf("Parsing credit file %s ...\n", credit
);
728 /*-----------------------------------------------------------------*/
731 ptr
=parse_datafile_line(_
);
734 find(ip
,ips
,eq(ip
->addr
,_
))
735 sscanf(ptr
,"%Lu",&(ip
->credit
));
743 /*-----------------------------------------------------------------*/
744 puts("Initializing iptables and tc classes ...");
745 /*-----------------------------------------------------------------*/
747 log_file
=fopen(cmdlog
,"w");
749 sprintf(str
,"%s -t mangle -F INPUT",iptables
);
752 sprintf(str
,"%s -t mangle -F OUTPUT",iptables
);
755 sprintf(str
,"%s -t mangle -F PREROUTING",iptables
);
758 sprintf(str
,"%s -t mangle -F POSTROUTING",iptables
);
761 sprintf(str
,"%s -t mangle -F FORWARD",iptables
);
764 sprintf(str
,"%s -t mangle -Z INPUT",iptables
);
767 sprintf(str
,"%s -t mangle -Z OUTPUT",iptables
);
770 sprintf(str
,"%s -t mangle -Z PREROUTING",iptables
);
773 sprintf(str
,"%s -t mangle -Z POSTROUTING",iptables
);
776 sprintf(str
,"%s -t mangle -Z FORWARD",iptables
);
779 sprintf(str
,"%s -t mangle -X",iptables
);
782 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,lan
);
785 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,wan
);
788 if(qos_free_zone
&& *qos_free_zone
!='0')
792 sprintf(str
,"%s -t mangle -A FORWARD -d %s -o %s -j ACCEPT",iptables
, qos_free_zone
, wan
);
797 sprintf(str
,"%s -t mangle -N post_noproxy 2>/dev/null",iptables
);
799 sprintf(str
,"%s -t mangle -F post_noproxy",iptables
);
801 sprintf(str
,"%s -t mangle -A POSTROUTING -p ! tcp -o %s -j post_noproxy",iptables
, lan
);
803 sprintf(str
,"%s -t mangle -A POSTROUTING -s ! %s -o %s -j post_noproxy",iptables
, proxy_ip
, lan
);
805 sprintf(str
,"%s -t mangle -A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy",iptables
, proxy_ip
, proxy_port
, lan
);
808 chain
="post_noproxy";
813 sprintf(str
,"%s -t mangle -A %s -s %s -o %s -j ACCEPT",iptables
, chain
, qos_free_zone
, lan
);
817 if(ip_count
>idxtable_treshold1
&& !just_flush
)
819 int idxcount
=0, bitmask
=32-idxtable_bitmask1
; /* default net mask: 255.255.255.240 */
820 char *subnet
, *ptr
, *buf
;
821 /*-----------------------------------------------------------------*/
822 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count
);
823 /*-----------------------------------------------------------------*/
825 sprintf(str
,"%s -t mangle -N post_common 2>/dev/null",iptables
);
827 sprintf(str
,"%s -t mangle -F post_common",iptables
);
829 sprintf(str
,"%s -t mangle -N forw_common 2>/dev/null",iptables
);
831 sprintf(str
,"%s -t mangle -F forw_common",iptables
);
834 search(ip
,ips
,ip
->addr
&& *(ip
->addr
) && !eq(ip
->addr
,"0.0.0.0/0"))
836 buf
=hash_id(ip
->addr
,bitmask
);
837 find(idx
,idxs
,eq(idx
->id
,buf
))
844 idx
->bitmask
=bitmask
;
852 /* brutal perfomance optimalization */
853 while(idxcount
>idxtable_treshold2
&& bitmask
>2*idxtable_bitmask2
)
855 bitmask
-=idxtable_bitmask2
;
857 search(idx
,idxs
,idx
->parent
==NULL
)
859 buf
=hash_id(idx
->addr
,bitmask
);
860 find(metaindex
,idxs
,eq(metaindex
->id
,buf
))
861 metaindex
->children
++;
864 create(metaindex
,Index
);
865 metaindex
->addr
=idx
->addr
;
867 metaindex
->bitmask
=bitmask
;
868 metaindex
->parent
=NULL
;
869 metaindex
->children
=0;
871 push(metaindex
,idxs
);
873 idx
->parent
=metaindex
;
877 /* this should slightly optimize throughout ... */
878 sort(idx
,idxs
,desc_order_by
,children
);
879 sort(idx
,idxs
,order_by
,bitmask
);
884 subnet
=subnet_id(idx
->addr
,idx
->bitmask
);
885 printf("%d: %s/%d\n",++i
,subnet
,idx
->bitmask
);
887 sprintf(str
,"%s -t mangle -N post_%s 2>/dev/null",iptables
, idx
->id
);
890 sprintf(str
,"%s -t mangle -F post_%s",iptables
, idx
->id
);
893 sprintf(str
,"%s -t mangle -N forw_%s 2>/dev/null",iptables
, idx
->id
);
896 sprintf(str
,"%s -t mangle -F forw_%s",iptables
, idx
->id
);
901 string(buf
,strlen(idx
->parent
->id
)+6);
902 sprintf(buf
,"post_%s",idx
->parent
->id
);
907 sprintf(str
,"%s -t mangle -A %s -d %s/%d -o %s -j post_%s",iptables
, buf
, subnet
, idx
->bitmask
, lan
, idx
->id
);
910 sprintf(str
,"%s -t mangle -A %s -d %s/%d -o %s -j post_common",iptables
, buf
, subnet
, idx
->bitmask
, lan
);
915 string(buf
,strlen(idx
->parent
->id
)+6);
916 sprintf(buf
,"forw_%s",idx
->parent
->id
);
921 sprintf(str
,"%s -t mangle -A %s -s %s/%d -o %s -j forw_%s",iptables
, buf
, subnet
, idx
->bitmask
, wan
, idx
->id
);
924 sprintf(str
,"%s -t mangle -A %s -s %s/%d -o %s -j forw_common",iptables
, buf
, subnet
, idx
->bitmask
, wan
);
927 printf("Total indexed iptables chains created: %d\n", i
);
929 sprintf(str
,"%s -t mangle -A FORWARD -o %s -j forw_common",iptables
, wan
);
932 sprintf(str
,"%s -t mangle -A POSTROUTING -o %s -j post_common",iptables
, lan
);
940 puts("Just flushed iptables and tc classes - now exiting ...");
946 if(!dry_run
&& !nodelay
&& qos_free_delay
)
948 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay
);
949 sleep(qos_free_delay
);
952 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q 1 default 2",tc
,lan
);
955 sprintf(str
,"%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio 0",tc
,lan
,lan_medium
,lan_medium
,burst
);
958 sprintf(str
,"%s class add dev %s parent 1:2 classid 1:1 htb rate %dkbit ceil %dkbit burst %dk prio 0",tc
,lan
,line
,line
,burst
);
961 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q 1 default 2",tc
,wan
);
964 sprintf(str
,"%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio 0",tc
,wan
,wan_medium
,wan_medium
,burst
);
967 sprintf(str
,"%s class add dev %s parent 1:2 classid 1:1 htb rate %dkbit ceil %dkbit burst %dk prio 0",tc
,wan
,up
,up
,burst
);
971 /*-----------------------------------------------------------------*/
972 puts("Locating suckers and generating root classes ...");
973 /*-----------------------------------------------------------------*/
974 sort(ip
,ips
,desc_order_by
,traffic
);
977 /*-----------------------------------------------------------------*/
978 /* sub-scope - local variables */
983 FILE *credit_file
=NULL
;
985 if(!just_preview
&& !dry_run
&& enable_credit
) credit_file
=fopen(credit
,"w");
992 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio 1",
993 tc
, lan
, parent
, group
->min
, rate
, max
, burst
);
997 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %ldkbit ceil %ldkbit burst %dk prio 1",
998 tc
, wan
, parent
, group
->min
, (long)(rate
*up
/line
), (long)(max
*up
/line
), burst
);
1002 if(group_count
++<max_nesting
) parent
=group
->min
;
1004 rate
-=digital_divide
*group
->min
;
1005 if(rate
<group
->min
)rate
=group
->min
;
1007 /*shaping of aggresive downloaders, with credit file support */
1010 int group_rate
=group
->min
, priority_sequence
=magic_priorities
+1;
1012 search(ip
, ips
, ip
->min
==group
->min
&& ip
->max
>ip
->min
)
1014 if(ip
->keyword
->data_limit
>0 &&
1015 ip
->traffic
>ip
->credit
+
1016 (ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))
1019 if(group_rate
<ip
->max
) ip
->max
=group_rate
;
1020 group_rate
+=magic_treshold
;
1021 ip
->prio
=magic_priorities
+2;
1022 if(ip
->prio
<3) ip
->prio
=3;
1026 if(ip
->traffic
>ip
->credit
+
1027 (ip
->min
*ip
->keyword
->prio_limit
+(ip
->keyword
->fixed_prio
<<20)) &&
1030 ip
->prio
=priority_sequence
--;
1031 if(ip
->prio
<2) ip
->prio
=2;
1036 unsigned long long lcredit
=0;
1037 if((ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))>ip
->traffic
)
1038 lcredit
=(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))-ip
->traffic
;
1039 fprintf(credit_file
,"%s %Lu\n",ip
->addr
,lcredit
);
1046 if(credit_file
)fclose(credit_file
);
1051 f
=fopen(preview
,"w");
1054 else if(!dry_run
&& !just_flush
)
1056 /*-----------------------------------------------------------------*/
1057 printf("Writing data transfer database ...\n");
1058 /*-----------------------------------------------------------------*/
1059 f
=fopen("/var/run/prometheus.previous","w");
1062 search(ip
,ips
,ip
->traffic
|| ip
->direct
|| ip
->proxy
||ip
->upload
)
1063 fprintf(f
,"%s %Lu %Lu %Lu %Lu\n",ip
->addr
,ip
->traffic
,ip
->direct
,ip
->proxy
,ip
->upload
);
1077 /*-----------------------------------------------------------------*/
1078 printf("Sorting data and generating statistics page %s ...\n",ptr
);
1079 /*-----------------------------------------------------------------*/
1081 fputs("<table border>\n<tr><th align=\"right\">#</th><th align=\"right\">group</th><th align=\"right\">IPs</th><th align=\"right\">requested</th>\n",f
);
1082 fprintf(f
,"<th colspan=\"%d\">data limits</th>\n",keywordcount
);
1087 printf("%d k group: %d bandwidth requested: %d k\n",group
->min
,group
->count
,group
->desired
);
1089 fprintf(f
,"<tr><td align=\"right\">%d</td><td align=\"right\">%d k</td>",count
,group
->min
);
1090 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d k</td>",group
->count
,group
->desired
);
1092 every(keyword
,keywords
)
1093 fprintf(f
,"<td align=\"right\"><font color=\"#%s\">%d M</font></td>",keyword
->html_color
,group
->min
*keyword
->data_limit
);
1096 total
+=group
->count
;
1100 printf("Total groups: %d Total bandwidth requested: %d k\nAGGREGATION: 1/%d\n",count
,i
,i
/line
);
1102 fprintf(f
,"<tr><th colspan=\"2\" align=\"left\">Line %d k</td>",line
);
1103 fprintf(f
,"<th align=\"right\">%d</td><th align=\"right\">%d k</td>",total
,i
);
1105 every(keyword
,keywords
)
1106 fprintf(f
,"<th align=\"right\">%d IPs</th>",keyword
->ip_count
);
1108 fprintf(f
,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n",(int)(0.5+i
/line
));
1109 fprintf(f
,"<th colspan=\"%d\">%d traffic classes</th></tr>\n",keywordcount
,total
);
1111 fputs("</table>\n",f
);
1113 else if(!dry_run
&& !just_flush
)
1119 unsigned long long total
=0, total_direct
=0, total_proxy
=0, total_upload
=0, tmp_sum
=0;
1120 int active_classes
=0;
1123 struct Sum
{unsigned long long l
; int i
; list(Sum
);} *sum
,*sums
=NULL
;
1130 fprintf(f
,"<p><table border>\n<tr><th colspan=\"%d\">%s",colspan
,title
);
1131 fprintf(f
," (%s)</th></tr>\n", d
);
1132 fputs("<tr><td align=\"right\">#</td><td>hostname</td>\
1133 <td align=\"right\">credit</td>\
1134 <td align=\"right\">limit</td>\
1135 <td align=\"right\">total</td>\
1136 <td align=\"right\">direct</td>\n",f
);
1138 fputs("<td align=\"right\">proxy</td>\n",f
);
1139 fputs("<td align=\"right\">upload</td>\
1140 <td align=\"right\">minimum</td>\
1141 <td align=\"right\">desired</td>\
1142 <td align=\"right\">maximum</td>\
1143 <td>prio</td></tr>\n",f
);
1147 char *f1
="", *f2
="";
1148 if(ip
->max
<ip
->desired
)
1150 f1
="<font color=\"red\">";
1155 f1
="<font color=\"brown\">";
1160 printf("%03d. %-22s %10Lu (%d/%d)\n",i
,ip
->name
, ip
->traffic
, ip
->min
, ip
->max
);
1162 fprintf(f
,"<tr><td align=\"right\"><a name=\"%s\"></a>%d</td><td><a href=\"%s%s.log\">%s</a></td><td align=\"right\">%Lu M</td>\n",
1163 ip
->name
, i
, log_url
, ip
->name
, ip
->name
, ip
->credit
);
1164 fprintf(f
,"<td align=\"right\"><font color=\"#%s\">%Lu M</font></td>",ip
->keyword
->html_color
,ip
->credit
+(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20)));
1165 fprintf(f
,"<td align=\"right\">%s%Lu M%s</td><td align=\"right\">%Lu M</td>\n", f1
, ip
->traffic
, f2
, ip
->direct
);
1167 fprintf(f
,"<td align=\"right\">%Lu M</td>\n", ip
->proxy
);
1168 fprintf(f
,"<td align=\"right\">%Lu M</td>\n", ip
->upload
);
1169 fprintf(f
,"<td align=\"right\">%d k</td><td align=\"right\">%d k</td><td align=\"right\">%s%d k%s</td><td>%s%d%s</td></tr>\n",ip
->min
,ip
->desired
,f1
,ip
->max
,f2
,f1
,ip
->prio
,f2
);
1171 total_direct
+=ip
->direct
;
1172 total_proxy
+=ip
->proxy
;
1173 total_upload
+=ip
->upload
;
1177 tmp_sum
+=ip
->traffic
;
1180 sum
->i
=active_classes
;
1181 insert(sum
,sums
,order_by
,i
);
1188 sprintf(str
,"%s%s.log",log_dir
,ip
->name
);
1189 iplog
=fopen(str
,"a");
1192 fprintf(iplog
,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%s",time(NULL
),ip
->name
,ip
->traffic
, ip
->direct
, ip
->proxy
, ip
->upload
,d
);
1198 fprintf(f
,"<tr><th colspan=\"4 \"align=\"left\">SUMMARY:</td>");
1199 fprintf(f
,"<th align=\"right\">%Lu M</th>\
1200 <th align=\"right\">%Lu M</th>\n", total
, total_direct
);
1202 fprintf(f
,"<th align=\"right\">%Lu M</th>\n", total_proxy
);
1203 fprintf(f
,"<th align=\"right\">%Lu M</th>", total_upload
);
1204 fputs("<td colspan=\"4\"></td></th>\n</table>\n",f
);
1206 if(active_classes
>10)
1208 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"4\">Enterprise Research and Planning (ERP)</th></tr>\n",f
);
1209 fputs("<tr><td colspan=\"2\">Active Classes</td><td colspan=\"2\">Data transfers</td></tr>\n",f
);
1210 find (sum
,sums
,sum
->l
>=total
/4)
1211 fprintf(f
,"<tr><td>Top %d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%d %%</td></tr>\n",sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total
);
1212 find (sum
,sums
,sum
->i
==10)
1213 fprintf(f
,"<tr><td>Top 10</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%d %%</td></tr>\n",(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total
);
1214 find (sum
,sums
,sum
->l
>=total
/2)
1215 fprintf(f
,"<tr><td>Top %d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%d %%</td></tr>\n",sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total
);
1216 find (sum
,sums
,sum
->i
>=(active_classes
+3)/4)
1217 fprintf(f
,"<tr><td>Top %d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%d %%</td></tr>\n",sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total
);
1218 find (sum
,sums
,sum
->i
>=(active_classes
+1)/2)
1219 fprintf(f
,"<tr><td>Top %d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%d %%</td></tr>\n",sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total
);
1220 fprintf(f
,"<tr><th align=\"left\">All %d</th><th align=\"right\">100 %%</th><th align=\"right\">%Lu M</th><th align=\"right\">100 %%</th></tr>\n",active_classes
,total
);
1221 fputs("</table>\n",f
);
1223 fprintf(f
,"<small>Statistics generated by Prometheus QoS version %s<br>GPL+Copyright(C)2005 Michael Polak, <a href=\"http://www.arachne.cz/\">Arachne Labs</a></small>\n",version
);
1229 puts("Statistics preview generated (-p switch) - now exiting ...");
1233 /*-----------------------------------------------------------------*/
1234 puts("Generating iptables and tc classes ...");
1235 /*-----------------------------------------------------------------*/
1238 printf("%-22s %-15s mark\n","name","ip");
1239 search(ip
,ips
,ip
->mark
>0)
1245 duplicate(ip
->addr
,buf
);
1246 buf
=hash_id(ip
->addr
,32-idxtable_bitmask1
);
1248 string(chain_forward
,6+strlen(buf
));
1249 strcpy(chain_forward
,"forw_");
1250 strcat(chain_forward
,buf
);
1252 string(chain_postrouting
,6+strlen(buf
));
1253 strcpy(chain_postrouting
,"post_");
1254 strcat(chain_postrouting
,buf
);
1260 chain_forward
="FORWARD";
1261 chain_postrouting
="POSTROUTING";
1264 printf("%-22s %-16s %04d ", ip
->name
, ip
->addr
, ip
->mark
);
1266 /* -------------------------------------------------------- mark download */
1268 sprintf(str
,"%s -t mangle -A %s -d %s/32 -o %s -j MARK --set-mark %d",iptables
,chain_postrouting
,ip
->addr
,lan
,ip
->mark
);
1269 /* -m limit --limit 1/s */
1274 sprintf(str
,"%s -t mangle -A %s -s %s -p tcp --sport %d -d %s/32 -o %s -j MARK --set-mark %d",iptables
,chain_postrouting
,proxy_ip
,proxy_port
,ip
->addr
,lan
,ip
->mark
);
1278 sprintf(str
,"%s -t mangle -A %s -d %s/32 -o %s -j ACCEPT",iptables
,chain_postrouting
,ip
->addr
,lan
);
1281 /* -------------------------------------------------------- mark upload */
1283 sprintf(str
,"%s -t mangle -A %s -s %s/32 -o %s -j MARK --set-mark %d",iptables
,chain_forward
,ip
->addr
,wan
,ip
->mark
);
1286 sprintf(str
,"%s -t mangle -A %s -s %s/32 -o %s -j ACCEPT",iptables
,chain_forward
,ip
->addr
,wan
);
1291 /* -------------------------------------------------------- download class */
1292 printf("(down: %dk-%dk ", ip
->min
, ip
->max
);
1294 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d", tc
, lan
, ip
->min
, ip
->mark
,ip
->min
,ip
->max
, burst
, ip
->prio
);
1297 sprintf(str
,"%s qdisc add dev %s parent 1:%d handle %d %s", tc
, lan
, ip
->mark
, ip
->mark
, qos_leaf
);
1300 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc
, lan
, ip
->mark
, ip
->mark
);
1303 /* -------------------------------------------------------- upload class */
1304 printf("up: %dk-%dk)\n", (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1305 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
));
1307 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1308 tc
, wan
, ip
->min
, ip
->mark
,
1309 (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1310 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
), burst
, ip
->prio
);
1313 sprintf(str
,"%s qdisc add dev %s parent 1:%d handle %d %s",tc
, wan
, ip
->mark
, ip
->mark
, qos_leaf
);
1316 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",tc
, wan
, ip
->mark
, ip
->mark
);
1320 printf("(sharing %s)\n", ip
->sharing
);
1327 chain_forward
="forw_common";
1328 chain_postrouting
="post_common";
1332 chain_forward
="FORWARD";
1333 chain_postrouting
="POSTROUTING";
1336 /* -------------------------------------------------------- mark download */
1340 sprintf(str
,"%s -t mangle -A %s -s %s -p tcp --sport %d -o %s -j MARK --set-mark 3",iptables
,chain_postrouting
,proxy_ip
,proxy_port
,lan
);
1342 sprintf(str
,"%s -t mangle -A %s -s %s -p tcp --sport %d -o %s -j ACCEPT",iptables
,chain_postrouting
,proxy_ip
,proxy_port
,lan
);
1345 sprintf(str
,"%s -t mangle -A %s -o %s -j MARK --set-mark 3",iptables
,chain_postrouting
,lan
);
1347 sprintf(str
,"%s -t mangle -A %s -o %s -j ACCEPT",iptables
,chain_postrouting
,lan
);
1350 /* -------------------------------------------------------- mark upload */
1351 sprintf(str
,"%s -t mangle -A %s -o %s -j MARK --set-mark 3",iptables
,chain_forward
,wan
);
1353 sprintf(str
,"%s -t mangle -A %s -o %s -j ACCEPT",iptables
,chain_forward
,wan
);
1356 printf("Total IP count: %d\n", i
);
1358 /* ---------------------------------------- tc - free bandwith shared class */
1359 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio 2",tc
,lan
,parent
,free_min
,free_max
,burst
);
1362 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio 2",tc
,wan
,parent
,free_min
,free_max
,burst
);
1366 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,lan
,qos_leaf
);
1369 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,wan
,qos_leaf
);
1372 /* tc handle 1 fw flowid */
1373 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,lan
);
1376 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,wan
);
1379 if(log_file
) fclose(log_file
);
1382 /* that's all folks, thank you for reading it all the way up to this point ;-) */
1383 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
This page took 1.344923 seconds and 5 git commands to generate.