1 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2 /* Prometheus QoS - you can "steal fire" from your ISP */
3 /* "fair-per-IP" quality of service (QoS) utility */
4 /* requires Linux 2.4.x or 2.6.x with HTB support */
5 /* Copyright(C) 2005-2012 Michael Polak, Arachne Labs */
6 /* iptables-restore support Copyright(C) 2007-2008 ludva */
7 /* Credit: CZFree.Net,Martin Devera,Netdave,Aquarius,Gandalf */
8 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
10 /* Modified by: xChaos, 20120610
13 Prometheus QoS is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2.1 of
16 the License, or (at your option) any later version.
18 Prometheus QoS is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with Prometheus Qos; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 GNU General Public License is located in file COPYING */
30 #define FIRSTGROUPID 1024
31 #define FIRSTIPCLASS 2048
34 #include "cll1-0.6.2.h"
36 const char *version
= "0.8.3-f";
38 /* Version numbers: 0.8.3 is development releases ("beta"), 0.8.4 will be "stable" */
39 /* Debian(RPM) package versions/patchlevels: 0.7.9-2, 0.8.0-1, 0.8.0-2, etc. */
40 /* C source code development versions ("beta"): 0.7.9-a, 0.8.1-b, etc. */
41 /* C source code release versions: 0.8.0, 0.8.2, 0.8.4, etc. */
43 const char *stats_html_signature
= "<span class=\"small\">Statistics generated by Prometheus QoS version %s<br />GPL+Copyright(C)2005-2012 Michael Polak, <a target=\"_blank\" href=\"http://www.arachne.cz/\">Arachne Labs</a></span>\n";
45 /* ======= All path names are defined here (for RPM patch) ======= */
47 const char *tc
= "/sbin/tc"; /* requires tc with HTB support */
48 const char *iptables
= "/sbin/iptables"; /* requires iptables utility */
49 const char *iptablessave
= "/sbin/iptables-save"; /* not yet required */
50 const char *iptablesrestore
= "/sbin/iptables-restore"; /* requires iptables-restore */
51 const char *ls
= "/bin/ls"; /* this is not user configurable :-) */
53 char *config
= "/etc/prometheus/prometheus.conf"; /* main configuration file */
54 char *hosts
= "/etc/prometheus/hosts"; /* per-IP bandwidth definition file */
56 char *iptablesfile
= "/var/spool/prometheus.iptables"; /* temporary file for iptables-restore*/
57 char *credit
= "/var/lib/misc/prometheus.credit"; /* credit log file */
58 char *classmap
= "/var/lib/misc/prometheus.classes"; /* credit log file */
59 char *html
= "/var/www/traffic.html"; /* hall of fame - html version */
60 char *preview
= "/var/www/preview.html"; /* hall of fame preview */
61 char *json
= "/var/www/logs/traffic.json"; /* hall of fame - json version */
62 char *cmdlog
= "/var/log/prometheuslog"; /* command log filename */
63 char *log_dir
= "/var/www/logs/"; /* log directory pathname, ended with slash */
64 char *log_url
= "/logs/"; /* log directory relative URI prefix (partial URL) */
65 char *html_log_dir
= "/var/www/logs/html/";
67 char *jquery_url
= "http://code.jquery.com/jquery-latest.js";
68 char *lms_url
= "/lms/?m=customerinfo&id=";
69 int use_jquery_popups
= 1;
70 int row_odd_even
= 0; /*<tr class="odd/even"> */
73 const char *tr_odd_even(void)
75 row_odd_even
= 1 - row_odd_even
;
78 return "<tr class=\"even\">\n";
82 return "<tr class=\"odd\">\n";
86 /* ======= Help screen is hopefuly self-documenting part of code :-) ======= */
90 puts("Command line switches:\n\
92 -d Dry run (preview tc and iptables commands on stdout)\n\
93 -r Run (reset all statistics and start shaping - daily usage)\n\
94 -p just generate Preview of data transfer statistics and exit (after -r)\n\
95 -s start Shaping FUP limits (keeps data transfer stat like -p) (after -r)\n\
96 -n run Now (like -r delay - overrides qos-free-delay keyword, after boot)\n\
97 -f just Flush iptables and tc classes and exit (stop shaping, no QiS)\n\
98 -9 emergency iptables flush (like -f, but dumps data transfer statistics)\n\
100 -c filename force alternative /etc/prometheus/prometheus.conf filename\n\
101 -h filename force alternative /etc/hosts filename (overrides hosts keyword)\n\
102 -l Mmm YYYY generate HTML summary of Logged traffic (Mmm=Jan-Dec) (and exit)\n\
103 -m generate HTML summary of traffic for yesterday's Month (and exit)\n\
104 -y generate HTML summary of traffic for yesterday's Year (and exit)\n\
105 -? --help show this help scree (and exit)\n\
106 -v --version show Version number of this utility (and exit)\n");
109 /* === Configuraration file values defaults - stored in global variables ==== */
111 int filter_type
= 1; /*1 mark, 2 classify*/
113 char *mark_iptables
= "MARK --set-mark ";
114 int dry_run
= 0; /* preview - use puts() instead of system() */
115 char *iptablespreamble
= "*mangle\n:PREROUTING ACCEPT [0:0]\n:POSTROUTING ACCEPT [0:0]\n:INPUT ACCEPT [0:0]\n:OUTPUT ACCEPT [0:0]\n:FORWARD ACCEPT [0:0]";
116 FILE *iptables_file
= NULL
;
117 int enable_credit
= 1; /* enable credit file */
118 int use_credit
= 0; /* use credit file (if enabled)*/
119 char *title
= "Hall of Fame - Greatest Suckers"; /* hall of fame title */
120 int hall_of_fame
= 1; /* enable hall of fame */
121 char *lan
= "eth0"; /* LAN interface */
122 char *lan_medium
= "100Mbit"; /* 10Mbit/100Mbit ethernet */
123 char *wan
= "eth1"; /* WAN/ISP interface */
124 char *wan_medium
= "100Mbit"; /* 10Mbit/100Mbit ethernet */
125 char *qos_leaf
= "sfq perturb 5"; /* leaf discipline */
126 char *qos_free_zone
= NULL
; /* QoS free zone */
127 int qos_proxy
= 1; /* include proxy port to QoS */
128 int found_lmsid
= 0; /* show links to users in LMS information system */
129 int include_upload
= 1; /* upload+download=total traffic */
130 char *proxy_ip
= "192.168.1.1/32"; /* our IP with proxy port */
131 int proxy_port
= 3128; /* proxy port number */
132 long long int line
= 1024; /* WAN/ISP download in kbps */
133 long long int up
= 1024; /* WAN/ISP upload in kbps */
134 int free_min
= 32; /* minimum guaranted bandwidth for all undefined hosts */
135 int free_max
= 64; /* maximum allowed bandwidth for all undefined hosts */
136 int qos_free_delay
= 0; /* seconds to sleep before applying new QoS rules */
137 int digital_divide
= 2; /* controls digital divide weirdness ratio, 1...3 */
138 int max_nesting
= 3; /* maximum nesting of HTB clases, built-in maximum seems to be 4 */
139 int htb_r2q
= 256; /* should work for leaf values 512 kbps to 8 Mbps */
140 int burst
= 8; /* HTB burst (in kbits) */
142 int burst_group
= 32;
143 int magic_treshold
= 8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */
144 int keywordcount
= 0;
145 /* not yet implemented:
146 int fixed_packets = 0; maximum number of pps per IP address (not class!)
147 int packet_limit = 5; maximum number of pps to htn CEIL, not rate !!!
149 FILE *log_file
= NULL
;
150 char *kwd
= "via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */
152 const int highest_priority
= 0; /* highest HTB priority (HTB built-in value is 0) */
153 const int lowest_priority
= 7; /* lowest HTB priority (HTB built-in value is 7) */
154 const int idxtable_treshold1
= 24; /* this is no longer configurable */
155 const int idxtable_treshold2
= 12; /* this is no longer configurable */
156 const int idxtable_bitmask1
= 3; /* this is no longer configurable */
157 const int idxtable_bitmask2
= 3; /* this is no longer configurable */
159 /* ==== This is C<<1 stuff - learn C<<1 first! https://dev.arachne.cz/svn/cll1h ==== */
174 unsigned long long direct
;
175 unsigned long long proxy
;
176 unsigned long long upload
;
177 unsigned long long traffic
;
178 unsigned long long credit
;
179 unsigned long pktsup
;
180 unsigned long pktsdown
;
181 struct Keyword
*keyword
;
183 } *ips
=NULL
, *ip
, *sharedip
;
192 } *groups
=NULL
, *group
;
198 struct Index
*parent
;
202 } *idxs
=NULL
, *idx
, *metaindex
;
208 int asymetry_ratio
; /* ratio for ADSL-like upload */
209 int asymetry_fixed
; /* fixed treshold for ADSL-like upload */
210 int data_limit
; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
211 int data_prio
; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
212 long fixed_limit
; /* fixed data limit for setting lower HTB ceil */
213 long fixed_prio
; /* fixed data lmit for setting lower HTB prio */
214 int reserve_min
; /* bonus for nominal HTB rate bandwidth (in kbps) */
215 int reserve_max
; /* malus for nominal HTB ceil (in kbps) */
216 // int divide_max; /* relative malus: new_ceil=rate+(old_ceil-rate)/divide_max */
217 // int htb_ceil_bonus_divide; /* relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide */
218 int default_prio
; /* default HTB priority for this keyword */
221 char *leaf_discipline
;
224 } *keyword
,*defaultkeyword
=NULL
,*keywords
=NULL
;
226 /* Damned, this must be object oriented! This looks almost like constructor ;-) */
234 ip
->prio
= highest_priority
+1;
248 ip
->keyword
= keywords
;
252 /* ====== iptables indexes are used to reduce complexity to log8(N) ===== */
254 char *very_ugly_ipv4_code(char *inip
,int bitmask
,int format_as_chainname
)
256 /* warning: this function was debugged only for bitmask values 20,24,28 !!!*/
258 char *ip
,*outip
,*outptr
,*fmt
;
261 /* debug printf("(%s,%d) -> ",ip,bitmask); */
263 if(ip
&& *ip
&& bitmask
>=0 && bitmask
<=32)
265 string(outip
,strlen(ip
)+10); /*fuck unicode? assertion: 10>strlen("_%d_%d") */
269 /* should never exit here */
277 if(dot
<(bitmask
/8-1))
279 if(format_as_chainname
)
292 char *cutdot
=strchr(ip
+1,'.'); /*for bitmask<24*/
298 if(format_as_chainname
)
309 n
= atoi(ip
+1)-atoi(ip
+1)%(1<<(8-bitmask
%8));
316 /*debug printf("%d/%d => [_%d_%d]\n",atoi(ip+1),bitmask,n,bitmask); */
317 sprintf(outptr
,fmt
,n
,bitmask
);
318 if(!format_as_chainname
)
326 /* debug printf("[%s]\n",outip); */
337 /*should never exit here*/
342 char *hash_id(char *ip
,int bitmask
)
344 return very_ugly_ipv4_code(ip
,bitmask
,1);
347 char *subnet_id(char *ip
,int bitmask
)
349 return very_ugly_ipv4_code(ip
,bitmask
,0);
352 /* ================= Let's parse configuration file here =================== */
354 void reject_config_and_exit(char *filename
)
356 printf("Configuration file %s rejected - abnormal exit.",filename
);
360 void get_config(char *config_filename
)
364 printf("Configured keywords: ");
365 parse(config_filename
)
367 option("keyword",kwd
);
372 create(keyword
,Keyword
);
374 keyword
->asymetry_ratio
=1; /* ratio for ADSL-like upload */
375 keyword
->asymetry_fixed
=0; /* fixed treshold for ADSL-like upload */
376 keyword
->data_limit
=8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
377 keyword
->data_prio
=4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
378 keyword
->fixed_limit
=0; /* fixed data limit for setting lower HTB ceil */
379 keyword
->fixed_prio
=0; /* fixed data limit for setting lower HTB prio */
380 keyword
->reserve_min
=8; /* bonus for nominal HTB rate bandwidth (in kbps) */
381 keyword
->reserve_max
=0; /* malus for nominal HTB ceil (in kbps) */
382 keyword
->default_prio
=highest_priority
+1;
383 keyword
->html_color
="000000";
385 keyword
->leaf_discipline
="";
387 push(keyword
,keywords
);
388 if(!defaultkeyword
) defaultkeyword
=keyword
;
395 for_each(keyword
,keywords
)
397 int l
=strlen(keyword
->key
);
399 if(!strncmp(keyword
->key
,_
,l
) && strlen(_
)>l
+2)
401 char *tmptr
=_
; /* <---- l+1 ----> */
402 _
+=l
+1; /* via-prometheus-asymetry-ratio, etc. */
403 ioption("asymetry-ratio",keyword
->asymetry_ratio
);
404 ioption("asymetry-treshold",keyword
->asymetry_fixed
);
405 ioption("magic-relative-limit",keyword
->data_limit
);
406 ioption("magic-relative-prio",keyword
->data_prio
);
407 loption("magic-fixed-limit",keyword
->fixed_limit
);
408 loption("magic-fixed-prio",keyword
->fixed_prio
);
409 ioption("htb-default-prio",keyword
->default_prio
);
410 ioption("htb-rate-bonus",keyword
->reserve_min
);
411 ioption("htb-ceil-malus",keyword
->reserve_max
);
412 option("leaf-discipline",keyword
->leaf_discipline
);
413 option("html-color",keyword
->html_color
);
416 if(keyword
->data_limit
|| keyword
->fixed_limit
||
417 keyword
->data_prio
|| keyword
->fixed_prio
)
426 option("iptables",iptables
);
427 option("iptables-save",iptablessave
); /* new */
428 option("iptables-restore",iptablesrestore
); /* new */
429 option("iptables-in-filename",iptablesfile
); /* new */
430 option("hosts",hosts
);
431 option("lan-interface",lan
);
432 option("wan-interface",wan
);
433 option("lan-medium",lan_medium
);
434 option("wan-medium",wan_medium
);
435 lloption("wan-download",line
);
436 lloption("wan-upload",up
);
437 ioption("hall-of-fame-enable",hall_of_fame
);
438 option("hall-of-fame-title",title
);
439 option("hall-of-fame-filename",html
);
440 option("json-filename",json
);
441 option("hall-of-fame-preview",preview
);
442 option("log-filename",cmdlog
);
443 option("credit-filename",credit
);
444 option("classmap-filename",classmap
);
445 ioption("credit-enable",enable_credit
);
446 option("log-traffic-directory",log_dir
);
447 option("log-traffic-html-directory",html_log_dir
);
448 option("log-traffic-url-path",log_url
);
449 option("jquery-url",jquery_url
);
450 option("lms-url",lms_url
);
451 ioption("use-jquery-popups",use_jquery_popups
);
452 option("qos-free-zone",qos_free_zone
);
453 ioption("qos-free-delay",qos_free_delay
);
454 ioption("qos-proxy-enable",qos_proxy
);
455 option("qos-proxy-ip",proxy_ip
);
456 option("htb-leaf-discipline",qos_leaf
);
457 ioption("qos-proxy-port",proxy_port
);
458 ioption("free-rate",free_min
);
459 ioption("free-ceil",free_max
);
460 ioption("htb-burst",burst
);
461 ioption("htb-burst-main",burst_main
);
462 ioption("htb-burst-group",burst_group
);
463 ioption("htb-nesting-limit",max_nesting
);
464 ioption("htb-r2q",htb_r2q
);
465 ioption("magic-include-upload",include_upload
);
466 ioption("magic-treshold",magic_treshold
);
467 option("filter-type", cnf
);
468 /* not yet implemented:
469 ioption("magic-fixed-packets",fixed_packets);
470 ioption("magic-relative-packets",packet_limit);
475 perror(config_filename
);
476 puts("Warning - using built-in defaults instead ...");
478 done
; /* ugly macro end */
481 /* leaf discipline for keywords */
482 for_each(keyword
,keywords
)
484 if(!strcmpi(keyword
->leaf_discipline
, ""))
486 keyword
->leaf_discipline
= qos_leaf
;
490 if(strcmpi(cnf
, "mark"))
494 mark_iptables
= "CLASSIFY --set-class 1:";
500 mark_iptables
= "MARK --set-mark ";
503 /* are supplied values meaningful ?*/
506 puts("Illegal value of LAN or WAN bandwidth: 0 kbps.");
507 reject_config_and_exit(config_filename
);
511 /* ===================== traffic analyser - uses iptables ================ */
513 void get_traffic_statistics(void)
518 textfile(Pipe
,str
) *line
,*lines
=NULL
;
522 sprintf(cmd
,"%s -L -v -x -n -t mangle",iptables
);
534 int col
, accept
=0,proxyflag
=0,valid
=1,setchainname
=0,commonflag
=0;
535 unsigned long long traffic
=0;
536 unsigned long pkts
=0;
537 char *ipaddr
=NULL
,*ptr
;
539 /* debug puts(line->str); */
540 valid_columns(ptr
,line
->str
,' ',col
)
541 if(valid
) switch(col
)
543 case 1: if(eq(ptr
,"Chain"))
547 else if(eq(ptr
,"pkts"))
553 sscanf(ptr
,"%lu",&pkts
);
556 case 2: if(setchainname
)
558 if(!strncmp(ptr
,"post_",5) || eq(ptr
,"POSTROUTING"))
564 if(!strncmp(ptr
,"forw_",5) || eq(ptr
,"FORWARD"))
569 if(eq(ptr
,"post_common") || eq(ptr
,"forw_common"))
576 sscanf(ptr
,"%Lu",&traffic
);
581 case 3: if((strncmp(ptr
,"post_",5) && strncmp(ptr
,"forw_",5)) || commonflag
)
585 /*if(filter_type==1) accept=eq(ptr,"MARK"); else accept=eq(ptr,"CLASSIFY");*/
587 case 8: if(downloadflag
)
589 if(strstr(proxy_ip
,ptr
))
599 case 9: if(downloadflag
)ipaddr
=ptr
;break;
602 if(accept
&& traffic
>0 && ipaddr
)
608 else if(!downloadflag
)
612 printf("IP %s: %Lu MB (%ld pkts)\n", ipaddr
, traffic
, pkts
);
614 if_exists(ip
,ips
,eq(ip
->addr
,ipaddr
));
619 if(eq(ip
->addr
,"0.0.0.0/0"))
621 ip
->name
="(unregistered)";
623 ip
->max
=ip
->desired
=free_max
;
635 ip
->traffic
+=traffic
;
637 ip
->direct
=ip
->traffic
-ip
->upload
-ip
->proxy
;
646 ip
->traffic
+=traffic
;
650 if(traffic
>ip
->traffic
)
661 /* ========== This function executes, logs OR ALSO prints command ========== */
663 void safe_run(char *cmd
)
667 printf("\n=>%s\n",cmd
);
675 fprintf(log_file
,"%s\n",cmd
);
679 void save_line(char *line
)
681 fprintf(iptables_file
,"%s\n",line
);
684 void run_restore(void)
687 string(restor
,STRLEN
);
689 /*-----------------------------------------------------------------*/
690 printf("Running %s <%s ...\n", iptablesrestore
, iptablesfile
);
691 /*-----------------------------------------------------------------*/
694 fclose(iptables_file
);
701 done
; /* ugly macro end */
704 sprintf(restor
,"%s <%s",iptablesrestore
, iptablesfile
);
710 /* == This function strips extra characters after IP address and stores it = */
712 void parse_ip(char *str
)
714 char *ptr
,*ipaddr
=NULL
,*ipname
=NULL
,*lmsid
=NULL
;
720 while(*ptr
&& *ptr
!='}')
728 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
736 while(*ptr
&& (*ptr
==' ' || *ptr
==9))
741 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
747 if_exists(ip
,ips
,eq(ip
->addr
,ipaddr
));
756 ip
->lmsid
=atoi(lmsid
);
761 char *parse_datafile_line(char *str
)
763 char *ptr
=strchr(str
,' ');
788 void parse_ip_log(int argc
, char **argv
)
790 char *month
, *year
, *str
, *name
="(undefined)", *ptr
, *ptr2
, *filename
;
791 long traffic
=0l, traffic_month
, total
=0, guaranted
;
792 int col
, col2
, y_ok
, m_ok
, accept_month
, i
=1, any_month
=0, lmsid
;
793 char mstr
[4], ystr
[5];
796 string(filename
,STRLEN
);
798 if(argv
[1][1]=='l') /* -l */
802 puts("Missing parameter(s)!\nUsage: prometheus -l Mmm YYYY (Mmm=Jan-Dec or Year, YYYY=year)");
808 if(eq(month
,"Year")) any_month
=1;
814 time_t t
= time(NULL
) - 3600*24 ; /* yesterday's timestamp*/
815 struct tm
*timep
= localtime(&t
);
817 if(argv
[1][1]=='m') /* -m yestarday - month */
819 strftime(mstr
, 4, "%b", timep
);
821 strftime(ystr
, 5, "%Y", timep
);
824 else /* -y yesterday - year */
828 strftime(ystr
, 5, "%Y", timep
);
832 printf("Analysing traffic for %s %s ...\n",month
,year
);
834 /* sorry... next release of C<<1 header file will include for_path_files(name,path) { } macro */
835 sprintf(str
,"%s %s/",ls
,log_dir
);
839 if(strstr(str
,".log"))
841 ptr
=strrchr(str
,'\n');
843 sprintf(filename
,"%s/%s",log_dir
,str
);
844 printf("Parsing %s ...",filename
);
852 valid_columns(ptr
,_
,'\t',col
) switch(col
)
854 case 2: name
= ptr
;break;
855 case 3: traffic
= atol(ptr
);break;
856 /* column number - was 7, now 11...*/
861 case 11: if(isalpha(*ptr
)) /* character, not numeric string = date, just one*/
863 valid_columns(ptr2
,ptr
,' ',col2
) switch(col2
)
865 case 2: if(any_month
|| eq(ptr2
,month
)) m_ok
= 1; break;
866 case 5: if(eq(ptr2
,year
)) y_ok
= 1; break;
871 if(col
== 7) guaranted
= atol(ptr
);
872 if(col
== 10) lmsid
= atoi(ptr
);
878 traffic_month
+= traffic
;
882 done
; /* ugly macro end */
888 iplog
->guaranted
= guaranted
;
889 iplog
->traffic
= traffic_month
;
890 iplog
->lmsid
= lmsid
;
891 insert(iplog
,iplogs
,desc_order_by
,traffic
);
892 printf(" %ld MB\n",iplog
->traffic
);
896 puts(" no records.");
900 sprintf(str
,"%s/%s-%s.html",html_log_dir
,year
,month
);
901 printf("Writing %s ... ",str
);
905 fprintf(f
, "<table class=\"decorated last\"><thead>\n\
906 <tr><th colspan=\"2\">%s %s</th>\n\
907 <th style=\"text-align: right\">lms</th>\n\
908 <th colspan=\"2\">Data transfers</th>\n\
909 <th style=\"text-align: right\">Min.speed</th>\n\
910 </tr></thead><tbody>\n ",
914 for_each(iplog
, iplogs
)
918 fprintf(f
, "%s<td style=\"text-align: right\">%d</td>\n\
919 <td style=\"text-align: left\"><a class=\"blue\" target=\"_blank\" href=\"%s%s.log\">%s</td>\n\
920 <td style=\"text-align: right\">",
921 tr_odd_even(), i
++, log_url
, iplog
->name
, iplog
->name
);
924 /*base URL will be configurable soon ... */
925 fprintf(f
, "<a class=\"blue\" target=\"_blank\" href=\"%s%d\">%04d</a>\n", lms_url
, iplog
->lmsid
, iplog
->lmsid
);
927 else if(iplog
->lmsid
== 0)
931 fprintf(f
, "<td style=\"text-align: right\">%ld MB</td>\n\
932 <td style=\"text-align: right\"><strong>%ld GB</strong></td>\n\
933 <td style=\"text-align: right\">%ld kb/s</th></tr>\n",
934 iplog
->traffic
, iplog
->traffic
>>10, iplog
->guaranted
);
935 total
+=iplog
->traffic
>>10;
940 fprintf(f
,"</tbody><thead><tr>\
941 <th colspan=\"3\" style=\"text-align: left\">Total:</th>\
942 <th colspan=\"2\" style=\"text-align: right\"><strong>%ld GB</strong></th>\
943 <th style=\"text-align: right\"><strong>%Ld kb/s</strong></th></tr>\n", total
, line
);
944 fputs("</thead></table>\n", f
);
949 fputs("<a name=\"erp\"></a><p><table class=\"decorated last\">\n\
950 <caption>Enterprise Resource Planning (ERP)</caption>\n\
952 <th>Analytic category</th>\n\
953 <th colspan=\"2\" style=\"text-align: center\">Active Classes</th>\n\
954 <th colspan=\"2\" style=\"text-align: center\">Data transfers</th>\n\
955 </tr></thead><tbody>\n",f
);
957 if_exists(iplog
,iplogs
,iplog
->l
>=total
/4)
959 fprintf(f
,"%s<td>Top 25%% of traffic</td>\n", tr_odd_even());
960 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
961 <td style=\"text-align: right\">%d %%</td>\n\
962 <td style=\"text-align: right\">%ld GB</td>\n\
963 <td style=\"text-align: right\">%d %%</td></tr>\n",
964 iplog
->i
, (100*iplog
->i
+50)/i
, iplog
->l
, (int)((100*iplog
->l
+50)/total
));
967 if_exists(iplog
,iplogs
,iplog
->i
==10)
969 fprintf(f
,"%s<td>Top 10 downloaders</td>\n", tr_odd_even());
970 fprintf(f
,"<td style=\"text-align: right\"><strong>10</strong></td>\n\
971 <td style=\"text-align: right\">%d %%</td>\n\
972 <td style=\"text-align: right\">%ld GB</td>\n\
973 <td style=\"text-align: right\">%d %%</td></tr>\n",
974 (100*iplog
->i
+50)/i
, iplog
->l
, (int)((100*iplog
->l
+50)/total
));
977 if_exists(iplog
,iplogs
,iplog
->l
>=total
/2)
979 fprintf(f
,"%s<td>Top 50%% of traffic</td>\n", tr_odd_even());
980 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
981 <td style=\"text-align: right\">%d %%</td>\n\
982 <td style=\"text-align: right\">%ld GB</td>\n\
983 <td style=\"text-align: right\"><strong>%d %%</strong></td></tr>\n",
984 iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
987 if_exists(iplog
,iplogs
,iplog
->l
>=4*total
/5)
989 fprintf(f
,"%s<td>Top 80%% of traffic</td>\n",tr_odd_even());
990 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
991 <td style=\"text-align: right\">%d %%</td>\n\
992 <td style=\"text-align: right\">%ld GB</td>\n\
993 <td style=\"text-align: right\"><strong>%d %%</strong></td></tr>\n",
994 iplog
->i
, (100*iplog
->i
+50)/i
, iplog
->l
, (int)((100*iplog
->l
+50)/total
));
997 if_exists (iplog
,iplogs
,iplog
->i
>=i
/5)
999 fprintf(f
,"%s<td>Top 20%% downloaders</td>\n",tr_odd_even());
1000 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1001 <td style=\"text-align: right\"><strong>%d %%</strong></td>\n\
1002 <td style=\"text-align: right\">%ld GB</td>\n\
1003 <td style=\"text-align: right\">%d %%</td></tr>\n",
1004 iplog
->i
, (100*iplog
->i
+50)/i
, iplog
->l
, (int)((100*iplog
->l
+50)/total
));
1007 if_exists(iplog
,iplogs
,iplog
->i
>=i
/4)
1009 fprintf(f
,"%s<td>Top 25%% downloaders</td>\n", tr_odd_even());
1010 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1011 <td style=\"text-align: right\">%d %%</td>\n\
1012 <td style=\"text-align: right\">%ld GB</td>\n\
1013 <td style=\"text-align: right\">%d %%</td></tr>\n",
1014 iplog
->i
, (100*iplog
->i
+50)/i
, iplog
->l
, (int)((100*iplog
->l
+50)/total
));
1017 if_exists(iplog
,iplogs
,iplog
->i
>=i
/2)
1019 fprintf(f
,"%s<td>Top 50%% downloaders</td>\n",tr_odd_even());
1020 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1021 <td style=\"text-align: right\"><strong>%d %%</strong></td>\n\
1022 <td style=\"text-align: right\">%ld GB</td>\n\
1023 <td style=\"text-align: right\">%d %%</td></tr>\n",
1024 iplog
->i
, (100*iplog
->i
+50)/i
, iplog
->l
, (int)((100*iplog
->l
+50)/total
));
1027 if_exists(iplog
,iplogs
,iplog
->i
>=4*i
/5)
1029 fprintf(f
,"%s<td>Top 80%% downloaders</td>\n",tr_odd_even());
1030 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1031 <td style=\"text-align: right\">%d %%</td>\n\
1032 <td style=\"text-align: right\">%ld GB</td>\n\
1033 <td style=\"text-align: right\">%d %%</td></tr>\n",
1034 iplog
->i
, (100*iplog
->i
+50)/i
, iplog
->l
, (int)((100*iplog
->l
+50)/total
));
1037 fprintf(f
,"</tbody><thead><tr><th><a class=\"blue\" target=\"_blank\" href=\"%sERP.log\">All users, all traffic</a></th>\n", log_url
);
1038 fprintf(f
,"<th style=\"text-align: right\">%d</th>\n\
1039 <th style=\"text-align: right\">100 %%</th>\n\
1040 <th style=\"text-align: right\">%ld GB</th>\n\
1041 <th style=\"text-align: right\">100 %%</th></tr>\n",i
-1,total
);
1042 fputs("</thead></table>\n", f
);
1045 fprintf(f
, stats_html_signature
, version
);
1055 void append_log(struct IP
*self
) /*using global variables*/
1060 date(d
); /* this is typical cll1.h macro - prints current date */
1062 sprintf(str
,"%s/%s.log", log_dir
, self
->name
);
1066 fprintf(f
,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%d\t%d\t%d\t%d\t%s",
1067 time(NULL
), self
->name
, self
->traffic
, self
->direct
, self
->proxy
,
1068 self
->upload
, self
->min
, self
->max
, self
->desired
, self
->lmsid
, d
); /* d = date*/
1078 /*-----------------------------------------------------------------*/
1079 /* Are you looking for int main(int argc, char **argv) ? :-)) */
1080 /*-----------------------------------------------------------------*/
1084 int i
=0; /* just plain old Fortran style integer :-) */
1085 FILE *f
=NULL
; /* everything is just stream of bytes... */
1086 char *str
, *ptr
, *d
; /* LET A$=B$ :-) */
1088 int class_count
=0,ip_count
=0;
1090 int just_flush
=FALSE
; /* deactivates all previous actions */
1092 int just_preview
=FALSE
; /* preview - generate just stats */
1093 int start_shaping
=FALSE
; /* apply FUP - requires classmap file */
1094 int just_logs
=FALSE
; /* just parse logs */
1098 char *chain_forward
, *chain_postrouting
;
1099 char *althosts
=NULL
;
1102 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
1103 Version %s - Copyright (C)2005-2012 Michael Polak, Arachne Labs\n\
1104 iptables-restore & burst tunning & classify modification by Ludva\n\
1105 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version
);
1107 /*----- Boring... we have to check command line options first: ----*/
1110 argument("-c") { nextargument(config
); }
1111 argument("-h") { nextargument(althosts
);}
1112 argument("-d") { run
=TRUE
; dry_run
=TRUE
; }
1113 argument("-f") { run
=TRUE
; just_flush
=TRUE
; }
1114 argument("-9") { run
=TRUE
; just_flush
=9; }
1115 argument("-p") { run
=TRUE
; just_preview
=TRUE
; }
1116 argument("-s") { run
=TRUE
; just_preview
=TRUE
; start_shaping
=TRUE
; }
1117 argument("-r") { run
=TRUE
; }
1118 argument("-n") { run
=TRUE
; nodelay
=TRUE
; }
1119 argument("-l") { just_logs
=TRUE
; }
1120 argument("-m") { just_logs
=TRUE
; }
1121 argument("-y") { just_logs
=TRUE
; }
1122 argument("-?") { help(); exit(0); }
1123 argument("--help") { help(); exit(0); }
1124 argument("-v") { exit(0); }
1125 argument("--version") { exit(0); }
1130 puts("*** THIS IS JUST DRY RUN ! ***\n");
1133 date(d
); /* this is typical cll1.h macro - prints current date */
1135 /*-----------------------------------------------------------------*/
1136 printf("Parsing configuration file %s ...\n", config
);
1137 /*-----------------------------------------------------------------*/
1142 parse_ip_log(argc
,argv
);
1158 /*-----------------------------------------------------------------*/
1159 puts("Parsing iptables verbose output ...");
1160 /*-----------------------------------------------------------------*/
1161 get_traffic_statistics();
1164 /*-----------------------------------------------------------------*/
1165 printf("Parsing class defintion file %s ...\n", hosts
);
1166 /*-----------------------------------------------------------------*/
1167 int groupidx
= FIRSTGROUPID
;
1172 if(*str
<'0' || *str
>'9')
1174 /* any line starting with non-number is comment ...*/
1178 //Does this IP share QoS class with some other ?
1179 substring
=strstr(str
,"sharing-");
1182 substring
+=8; //"sharing-"
1185 ip
->sharing
=substring
;
1186 ip
->keyword
=defaultkeyword
; /* settings for default keyword */
1187 while(*substring
&& *substring
!='\n')
1195 //Do we have to create new QoS class for this IP ?
1197 if_exists(keyword
,keywords
,(substring
=strstr(str
,keyword
->key
)))
1201 ip
->keyword
=keyword
;
1202 keyword
->ip_count
++;
1203 ip
->prio
=keyword
->default_prio
;
1204 substring
+=strlen(keyword
->key
)+1;
1206 while(*ptr
&& *ptr
!='-')
1213 ip
->max
= ip
->desired
=atoi(ptr
+1);
1215 ip
->min
= atoi(substring
);
1218 printf(" %s: Illegal value of minimum bandwidth 0 kbps, using %d kb/s\n",
1222 if(ip
->max
<= ip
->min
)
1225 ip
->max
= ip
->min
+ip
->keyword
->reserve_min
;
1229 ip
->max
-= ip
->keyword
->reserve_max
;
1235 ip
->mark
=FIRSTIPCLASS
+1+class_count
++;
1237 if_exists(group
,groups
,group
->min
==ip
->min
)
1240 group
->desired
+= ip
->min
;
1241 ip
->group
= group
->id
;
1245 create(group
,Group
);
1246 group
->min
= ip
->min
;
1247 group
->id
= groupidx
++;
1248 ip
->group
= group
->id
;
1250 if(group
->min
<8) group
->min
=8;
1251 /* Warning - this is maybe because of primitive tc namespace, can be fixed */
1252 /* it is because class IDs are derived from min. bandwidth. - xCh */
1253 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;
1256 group
->desired
=ip
->min
;
1257 insert(group
,groups
,desc_order_by
,min
);
1267 done
; /* ugly macro end */
1269 /*-----------------------------------------------------------------*/
1270 /* cll1.h - let's allocate brand new character buffer... */
1271 /*-----------------------------------------------------------------*/
1274 /*-----------------------------------------------------------------*/
1275 puts("Resolving shared connections ...");
1276 /*-----------------------------------------------------------------*/
1277 for_each(ip
,ips
) if(ip
->sharing
)
1279 for_each(sharedip
,ips
) if(eq(sharedip
->name
,ip
->sharing
))
1281 sharedip
->traffic
+=ip
->traffic
;
1283 ip
->mark
=sharedip
->mark
;
1284 ip
->lmsid
=sharedip
->lmsid
;
1289 printf("Unresolved shared connection: %s %s sharing-%s\n",
1290 ip
->addr
, ip
->name
, ip
->sharing
);
1294 if(enable_credit
&& just_flush
<9)
1296 /*-----------------------------------------------------------------*/
1297 printf("Parsing credit file %s ...\n", credit
);
1298 /*-----------------------------------------------------------------*/
1301 ptr
=parse_datafile_line(_
);
1304 if_exists(ip
,ips
,eq(ip
->addr
,_
))
1306 sscanf(ptr
,"%Lu",&(ip
->credit
));
1310 done
; /* ugly macro end */
1315 /*-----------------------------------------------------------------*/
1316 puts("Initializing iptables and tc classes ...");
1317 /*-----------------------------------------------------------------*/
1319 iptables_file
=fopen(iptablesfile
,"w");
1320 if(iptables_file
== NULL
)
1322 puts("Cannot open iptablesfile!");
1326 log_file
=fopen(cmdlog
,"w");
1327 if(log_file
== NULL
)
1329 puts("Cannot open logfile!");
1333 save_line(iptablespreamble
);
1336 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,lan
);
1339 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,wan
);
1342 iptables_file
=fopen(iptablesfile
,"w");
1343 save_line(iptablespreamble
);
1345 if(qos_free_zone
&& *qos_free_zone
!='0')
1349 sprintf(str
,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone
, wan
);
1354 save_line(":post_noproxy - [0:0]");
1355 sprintf(str
,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan
);
1357 sprintf(str
,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip
, lan
);
1359 sprintf(str
,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip
, proxy_port
, lan
);
1362 chain
="post_noproxy";
1366 chain
="POSTROUTING";
1369 sprintf(str
,"-A %s -s %s -o %s -j ACCEPT", chain
, qos_free_zone
, lan
);
1373 if(ip_count
>idxtable_treshold1
&& !just_flush
)
1375 int idxcount
=0, bitmask
=32-idxtable_bitmask1
; /* default net mask: 255.255.255.240 */
1377 /*-----------------------------------------------------------------*/
1378 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count
);
1379 /*-----------------------------------------------------------------*/
1381 save_line(":post_common - [0:0]");
1382 save_line(":forw_common - [0:0]");
1384 for_each(ip
,ips
) if(ip
->addr
&& *(ip
->addr
) && !eq(ip
->addr
,"0.0.0.0/0"))
1386 buf
=hash_id(ip
->addr
,bitmask
);
1387 if_exists(idx
,idxs
,eq(idx
->id
,buf
))
1396 idx
->bitmask
=bitmask
;
1404 /* brutal perfomance optimalization */
1405 while(idxcount
>idxtable_treshold2
&& bitmask
>2*idxtable_bitmask2
)
1407 bitmask
-=idxtable_bitmask2
;
1410 for_each(idx
,idxs
) if(idx
->parent
== NULL
)
1412 buf
=hash_id(idx
->addr
,bitmask
);
1413 if_exists(metaindex
,idxs
,eq(metaindex
->id
,buf
))
1415 metaindex
->children
++;
1419 create(metaindex
,Index
);
1420 metaindex
->addr
=idx
->addr
;
1422 metaindex
->bitmask
=bitmask
;
1423 metaindex
->parent
=NULL
;
1424 metaindex
->children
=0;
1426 push(metaindex
,idxs
);
1428 idx
->parent
=metaindex
;
1432 /* this should slightly optimize throughout ... */
1433 sort(idx
,idxs
,desc_order_by
,children
);
1434 sort(idx
,idxs
,order_by
,bitmask
);
1439 subnet
=subnet_id(idx
->addr
,idx
->bitmask
);
1440 printf("%d: %s/%d\n",
1441 ++i
, subnet
, idx
->bitmask
);
1443 sprintf(str
,":post_%s - [0:0]", idx
->id
);
1446 sprintf(str
,":forw_%s - [0:0]", idx
->id
);
1451 string(buf
,strlen(idx
->parent
->id
)+6);
1452 sprintf(buf
,"post_%s",idx
->parent
->id
);
1459 sprintf(str
,"-A %s -d %s/%d -o %s -j post_%s", buf
, subnet
, idx
->bitmask
, lan
, idx
->id
);
1462 sprintf(str
,"-A %s -d %s/%d -o %s -j post_common", buf
, subnet
, idx
->bitmask
, lan
);
1467 string(buf
,strlen(idx
->parent
->id
)+6);
1468 sprintf(buf
,"forw_%s",idx
->parent
->id
);
1475 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_%s", buf
, subnet
, idx
->bitmask
, wan
, idx
->id
);
1478 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_common", buf
, subnet
, idx
->bitmask
, wan
);
1481 printf("Total indexed iptables chains created: %d\n", i
);
1483 sprintf(str
,"-A FORWARD -o %s -j forw_common", wan
);
1486 sprintf(str
,"-A POSTROUTING -o %s -j post_common", lan
);
1494 fclose(iptables_file
);
1499 puts("Just flushed iptables and tc classes - now exiting ...");
1505 if(!dry_run
&& !nodelay
&& qos_free_delay
)
1507 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay
);
1508 sleep(qos_free_delay
);
1511 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",
1515 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1516 tc
,lan
,lan_medium
,lan_medium
,burst_main
,highest_priority
);
1519 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1520 tc
,lan
,line
,line
,burst_main
,highest_priority
);
1523 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc
,wan
,htb_r2q
);
1526 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1527 tc
,wan
,wan_medium
,wan_medium
,burst_main
,highest_priority
);
1530 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1531 tc
,wan
,up
,up
,burst_main
,highest_priority
);
1535 /*-----------------------------------------------------------------*/
1536 puts("Locating heavy downloaders and generating root classes ...");
1537 /*-----------------------------------------------------------------*/
1538 sort(ip
,ips
,desc_order_by
,traffic
);
1540 /*-----------------------------------------------------------------*/
1541 /* sub-scope - local variables */
1543 long long int rate
= line
;
1544 long long int max
= line
;
1545 int group_count
= 0;
1546 FILE *credit_file
= NULL
;
1548 if(!just_preview
&& !dry_run
&& enable_credit
)
1550 credit_file
= fopen(credit
,"w");
1553 for_each(group
,groups
)
1558 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d #down desired %d",
1559 tc
, lan
, parent
, group
->id
, rate
, max
, burst_group
, highest_priority
+1, group
->desired
);
1563 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d #up desired %d",
1564 tc
, wan
, parent
, group
->id
, rate
*up
/line
, max
*up
/line
, burst_group
, highest_priority
+1, group
->desired
);
1568 if(group_count
++ < max_nesting
)
1573 rate
-= digital_divide
*group
->min
;
1574 if(rate
< group
->min
)
1579 /*shaping of aggresive downloaders, with credit file support */
1582 int group_rate
= group
->min
, priority_sequence
= lowest_priority
;
1584 for_each(ip
, ips
) if(ip
->min
== group
->min
&& ip
->max
> ip
->min
)
1586 if( ip
->keyword
->data_limit
&& !ip
->fixedprio
1587 && ( ip
->traffic
>ip
->credit
1588 + (ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))) )
1590 if(group_rate
<ip
->max
)
1594 group_rate
+=magic_treshold
;
1595 ip
->prio
=lowest_priority
;
1596 if(ip
->prio
<highest_priority
+2)
1598 ip
->prio
=highest_priority
+2;
1603 if( ip
->keyword
->data_prio
1605 && ( ip
->traffic
>ip
->credit
1606 + (ip
->min
*ip
->keyword
->data_prio
+(ip
->keyword
->fixed_prio
<<20))) )
1608 ip
->prio
=priority_sequence
--;
1609 if(ip
->prio
<highest_priority
+1)
1611 ip
->prio
=highest_priority
+1;
1617 unsigned long long lcredit
=0;
1619 if((ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))>ip
->traffic
)
1621 lcredit
=(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))-ip
->traffic
;
1623 fprintf(credit_file
,"%s %Lu\n",ip
->addr
,lcredit
);
1631 fclose(credit_file
);
1639 printf("Reading %s and applying Fair Use Policy rules ... \n", classmap
);
1647 if_exists(ip
,ips
,eq(ip
->addr
,_
))
1650 if(ip
->max
< ip
->desired
) /* apply FUP limit immediately.... */
1652 printf("Applying limit for %-22s %-16s %04d ", ip
->name
, ip
->addr
, ip
->mark
);
1653 printf("(down: %dk-%dk ", ip
->min
, ip
->max
);
1654 sprintf(str
, "%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1655 tc
, lan
, ip
->group
, ip
->mark
,ip
->min
,ip
->max
, burst
, ip
->prio
);
1657 printf("up: %dk-%dk)\n", (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1658 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
));
1659 sprintf(str
,"%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1660 tc
, wan
, ip
->group
, ip
->mark
,
1661 (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1662 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
), burst
, ip
->prio
);
1671 puts("Warning - classmap file not fund, just generating preview ...");
1672 start_shaping
=FALSE
;
1674 done
; /* ugly macro end */
1676 f
=fopen(preview
,"w");
1679 else if(!dry_run
&& !just_flush
)
1681 /*-----------------------------------------------------------------*/
1682 printf("Writing daily statistics %s ... ", json
);
1683 /*-----------------------------------------------------------------*/
1692 && (ip
->traffic
|| ip
->direct
|| ip
->proxy
|| ip
->upload
))
1698 fprintf(f
, " \"%s\":{ \"lms\": %d, \"ip\":\"%s\", \"total\":%Lu, \"down\":%Lu, \"proxy\":%Lu, \"up\":%Lu }",
1699 ip
->name
, ip
->lmsid
, ip
->addr
, ip
->traffic
, ip
->direct
, ip
->proxy
, ip
->upload
);
1720 /*-----------------------------------------------------------------*/
1721 printf("Sorting data and generating statistics page %s ...\n", ptr
);
1722 /*-----------------------------------------------------------------*/
1724 if(use_jquery_popups
)
1726 fprintf(f
,"<script type=\"text/javascript\" src=\"%s\"></script>\n", jquery_url
);
1728 fputs("<table class=\"decorated last\">\n\
1729 <caption>Bandwidth classes</caption>\n\
1731 <th style=\"text-align: right\">#</th>\n\
1732 <th style=\"text-align: right\">group</th>\n\
1733 <th style=\"text-align: right\">IPs</th>\n\
1734 <th style=\"text-align: right\">requested</th>\n",f
);
1735 fprintf(f
,"<th colspan=\"%d\">data limits</th>\n", keywordcount
);
1736 fputs("</tr></thead><tbody>\n",f
);
1739 for_each(group
, groups
)
1742 printf("%d kb/s group: %d bandwidth requested: %d kb/s\n",group
->min
,group
->count
,group
->desired
);
1744 fprintf(f
, "%s<td style=\"text-align: right\">%d</td><td style=\"text-align: right\">%d kb/s</td>",
1745 tr_odd_even(), count
, group
->min
);
1746 fprintf(f
, "<td style=\"text-align: right\">%d</td><td style=\"text-align: right\">%d kb/s</td>",
1747 group
->count
, group
->desired
);
1749 for_each(keyword
, keywords
) if(keyword
->ip_count
)
1751 fprintf(f
,"<td style=\"text-align: right\"><span style=\"color:#%s\">%d MB</span></td>",
1752 keyword
->html_color
, group
->min
*keyword
->data_limit
);
1754 i
+= group
->desired
;
1755 total
+= group
->count
;
1759 printf("Total groups: %d Total bandwidth requested: %d kb/s\nAGGREGATION: 1/%d\n",
1762 fprintf(f
,"</tr></tbody>\n\
1764 <th colspan=\"2\" style=\"text-align: left\">Line %Ld kb/s</td>",line
);
1765 fprintf(f
,"<th style=\"text-align: right\">%d</td><th style=\"text-align: right\">%d kb/s</td>",total
,i
);
1767 for_each(keyword
, keywords
) if(keyword
->ip_count
)
1769 fprintf(f
,"<th style=\"text-align: right\">%d IPs</th>",keyword
->ip_count
);
1771 fprintf(f
,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n", (int)(0.5+i
/line
));
1772 fprintf(f
,"<th colspan=\"%d\">%d traffic classes</th></tr>\n", keywordcount
, total
);
1774 fputs("</thead></table>\n",f
);
1776 else if(!dry_run
&& !just_flush
)
1784 unsigned long long total_traffic
=0, total_direct
=0, total_proxy
=0, total_upload
=0, tmp_sum
=0;
1785 int active_classes
=0;
1787 struct Sum
{unsigned long long l
; int i
; list(Sum
);} *sum
,*sums
=NULL
;
1788 int limit_count
=0, prio_count
=0;
1796 fprintf(f
,"<p><table class=\"decorated last\">\n<caption>%s",title
);
1797 fprintf(f
," (%s)</caption>\n", d
);
1798 fputs("<thead><tr>\n<th colspan=\"3\"> </th>\n",f
);
1799 fputs("<th style=\"text-align: right\">credit</th>\n\
1800 <th style=\"text-align: right\">FUP</th>\n\
1801 <th style=\"text-align: right\">total</th>\n\
1802 <th style=\"text-align: right\">down</th>\n",f
);
1805 fputs("<th style=\"text-align: right\">proxy</th>\n",f
);
1807 fputs("<th style=\"text-align: right\">up</th>\n\
1808 <th style=\"text-align: right\">min</th>\n\
1809 <th style=\"text-align: right\">max</th>\n\
1810 <th style=\"text-align: right\">limit</th>\n\
1813 <th style=\"text-align: right\">#</th>\n\
1814 <th>hostname [+sharing]</th>\n\
1815 <th style=\"text-align: right\">LMS</th>\n\
1816 <th style=\"text-align: right\">MB</th>\n\
1817 <th style=\"text-align: right\">MB</th>\n\
1818 <th style=\"text-align: right\">MB</th>\n\
1819 <th style=\"text-align: right\">MB</th>\n\
1820 <th style=\"text-align: right\">MB</th>\n\
1821 <th style=\"text-align: right\">kb/s</th>\n\
1822 <th style=\"text-align: right\">kb/s</th>\n\
1823 <th style=\"text-align: right\">kb/s</th>\n\
1825 </tr></thead><tbody>\n",f
);
1828 for_each(ip
,ips
) if(!use_jquery_popups
|| !ip
->sharing
)
1830 char *f1
="", *f2
="";
1833 if(ip
->max
< ip
->desired
)
1835 f1
="<span style=\"color:red\">";
1839 else if(ip
->prio
> highest_priority
+1)
1841 f1
="<span style=\"color:brown\">";
1847 printf("%03d. %-22s %10Lu (%d/%d)\n",i
,ip
->name
, ip
->traffic
, ip
->min
, ip
->max
);
1849 /* hostnames -------------------------------------- */
1850 fprintf(f
,"%s<td style=\"text-align: right\"><a name=\"%s\"></a>%d</td><td><a class=\"blue\" target=\"_blank\" href=\"%s%s.log\">%s</a>\n",
1851 tr_odd_even(), ip
->name
, i
, log_url
, ip
->name
, ip
->name
);
1853 if(use_jquery_popups
)
1855 fprintf(f
,"<span id=\"sharing_%d\" style=\"display:none\">",i
);
1857 for_each(sharedip
, ips
) if(eq(ip
->name
, sharedip
->sharing
))
1859 fprintf(f
,"<br /><a class=\"blue\" target=\"_blank\" href=\"%s%s.log\">%s</a>\n", log_url
, sharedip
->name
, sharedip
->name
);
1862 fputs("</span>\n",f
);
1865 fprintf(f
,"<span>[<a class=\"blue\" href=\"#\" onClick=\"$(this).parent().hide();$(\'#sharing_%d\').show();$(\'#download_%d\').show();$(\'#upload_%d\').show();return(false);\" style=\"cursor: pointer;\">+%d</a>]</span>",
1866 i
, i
, i
, popup_button
);
1870 /* ----------------------------------------------- */
1874 fputs("<td style=\"text-align: right\">",f
);
1877 fprintf(f
,"<a class=\"blue\" target=\"_blank\" href=\"%s%d\">%04d</a>\n", lms_url
, ip
->lmsid
, ip
->lmsid
);
1879 else if(ip
->lmsid
== 0)
1885 fprintf(f
,"<td style=\"text-align: right\">%Lu</td>\n", ip
->credit
);
1886 fprintf(f
,"<td style=\"text-align: right\"><span style=\"color:#%s\">%Lu</span></td>",
1887 ip
->keyword
->html_color
,
1888 ip
->credit
+(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20)));
1889 fprintf(f
,"<td style=\"text-align: right\">%s%Lu%s", f1
, ip
->traffic
, f2
);
1891 /* download --------------------------------------- */
1892 fprintf(f
,"</td><td style=\"text-align: right\">%Lu", ip
->direct
);
1893 if(use_jquery_popups
)
1895 fprintf(f
,"<span id=\"download_%d\" style=\"display:none\">",i
);
1896 for_each(sharedip
, ips
) if(eq(ip
->name
, sharedip
->sharing
))
1898 fprintf(f
,"<br />%Lu", sharedip
->direct
);
1900 fputs("</span>\n",f
);
1903 /* ----------------------------------------------- */
1907 fprintf(f
,"<td style=\"text-align: right\">%Lu</td>\n", ip
->proxy
);
1909 /* upload ---------------------------------------- */
1910 fprintf(f
,"<td style=\"text-align: right\">%Lu", ip
->upload
);
1911 if(use_jquery_popups
)
1913 fprintf(f
,"<span id=\"upload_%d\" style=\"display:none\">",i
);
1914 for_each(sharedip
,ips
) if(eq(ip
->name
, sharedip
->sharing
))
1916 fprintf(f
,"<br />%Lu", sharedip
->upload
);
1918 fputs("</span>\n",f
);
1921 /* ----------------------------------------------- */
1923 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1924 <td style=\"text-align: right\">%d</td>\n\
1925 <td style=\"text-align: right\">%s%d%s</td>\n\
1926 <td>%s%d%s</td></tr>\n",
1927 ip
->min
, ip
->desired
,
1931 total_traffic
+=ip
->traffic
;
1932 total_direct
+=ip
->direct
;
1933 total_proxy
+=ip
->proxy
;
1934 total_upload
+=ip
->upload
;
1938 tmp_sum
+=ip
->traffic
;
1941 sum
->i
=active_classes
;
1942 insert(sum
,sums
,order_by
,i
);
1948 for_each(sharedip
,ips
) if(eq(ip
->name
, sharedip
->sharing
))
1950 append_log(sharedip
);
1954 fprintf(f
,"</tbody><thead><tr>\n\
1955 <th colspan=\"%d\" style=\"text-align: left\">%d CLASSES</th>", colspan
-7, i
);
1956 fprintf(f
,"<th style=\"text-align: right\">%Lu</th><th style=\"text-align: right\">%Lu</th>\n", total_traffic
, total_direct
);
1959 fprintf(f
,"<th style=\"text-align: right\">%Lu</th>\n", total_proxy
);
1961 fprintf(f
,"<th style=\"text-align: right\">%Lu</th>", total_upload
);
1962 fprintf(f
,"<th colspan=\"4\"><span style=\"color:red\">LIMIT %dx</span> <span style=\"color:brown\">LOW-PRIO %dx</span></th></tr>\n</thead></table>\n",limit_count
,prio_count
);
1965 if(active_classes
>10)
1967 int top20_count
=0,top20_perc1
=0;
1968 long long top20_perc2
=0;
1969 unsigned long long top20_sum
=0l;
1971 fputs("<a name=\"erp\"></a><p><table class=\"decorated last\"><caption>Enterprise Resource Planning (ERP)</caption>\n",f
);
1972 fputs("<thead><tr>\n\
1973 <th>Analytic category</th>\n\
1974 <th colspan=\"2\" style=\"text-align: center\">Active Classes</th>\n\
1975 <th colspan=\"2\" style=\"text-align: center\">Data transfers</th>\n\
1976 </tr></thead><tbody>\n",f
);
1978 if_exists(sum
,sums
,sum
->l
>=total_traffic
/4)
1980 fprintf(f
,"%s<td>Top 25%% of traffic</td>\n", tr_odd_even());
1981 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1982 <td style=\"text-align: right\">%d %%</td>\n\
1983 <td style=\"text-align: right\">%Lu MB</td>\n\
1984 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1985 sum
->i
, (100*sum
->i
+50)/active_classes
, sum
->l
, (100*sum
->l
+50)/total_traffic
);
1988 if_exists(sum
,sums
,sum
->i
==10)
1990 fprintf(f
,"%s<td>Top 10 downloaders</td>\n", tr_odd_even());
1991 fprintf(f
,"<td style=\"text-align: right\"><strong>10</strong></td>\n\
1992 <td style=\"text-align: right\">%d %%</td>\n\
1993 <td style=\"text-align: right\">%Lu MB</td>\n\
1994 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1995 (100*sum
->i
+50)/active_classes
, sum
->l
, (100*sum
->l
+50)/total_traffic
);
1998 if_exists(sum
,sums
,sum
->l
>=total_traffic
/2)
2000 fprintf(f
,"%s<td>Top 50%% of traffic</td>\n", tr_odd_even());
2001 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
2002 <td style=\"text-align: right\">%d %%</td>\n\
2003 <td style=\"text-align: right\">%Lu MB</td>\n\
2004 <td style=\"text-align: right\"><strong>%Ld %%</strong></td></tr>\n",
2005 sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
2008 if_exists(sum
,sums
,sum
->l
>=4*total_traffic
/5)
2010 fprintf(f
,"%s<td>Top 80%% of traffic</td>\n", tr_odd_even());
2011 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
2012 <td style=\"text-align: right\">%d %%</td>\n\
2013 <td style=\"text-align: right\">%Lu MB</td>\n\
2014 <td style=\"text-align: right\"><strong>%Ld %%</strong></td></tr>\n",
2015 sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
2018 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/5)
2020 fprintf(f
,"%s<td>Top 20%% downloaders</td>\n", tr_odd_even());
2022 top20_perc1
=(100*sum
->i
+50)/active_classes
;
2024 top20_perc2
=(100*sum
->l
+50)/total_traffic
;
2025 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
2026 <td style=\"text-align: right\"><strong>%d %%</strong></td>\n\
2027 <td style=\"text-align: right\">%Lu MB</td>\n\
2028 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
2029 top20_count
,top20_perc1
,top20_sum
,top20_perc2
);
2032 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/4)
2034 fprintf(f
,"%s<td>Top 25%% downloaders</td>\n", tr_odd_even());
2035 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
2036 <td style=\"text-align: right\">%d %%</td>\n\
2037 <td style=\"text-align: right\">%Lu MB</td>\n\
2038 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
2039 sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
2042 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/2)
2044 fprintf(f
,"%s<td>Top 50%% downloaders</td>\n", tr_odd_even());
2045 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
2046 <td style=\"text-align: right\"><strong>%d %%</strong></td>\n\
2047 <td style=\"text-align: right\">%Lu MB</td>\n\
2048 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
2049 sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
2052 if_exists(sum
,sums
,sum
->i
>=4*(active_classes
+1)/5)
2054 fprintf(f
,"%s<td>Top 80%% downloaders</td>\n", tr_odd_even());
2055 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
2056 <td style=\"text-align: right\">%d %%</td>\n\
2057 <td style=\"text-align: right\">%Lu MB</td>\n\
2058 <td style=\"text-align: right\">%Ld %%</td></tr></tbody>\n",
2059 sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
2062 fprintf(f
,"<thead><tr><th><a class=\"blue\" target=\"_blank\" href=\"%sERP.log\">All users, all traffic</a></th>\n", log_url
);
2063 fprintf(f
,"<th style=\"text-align: right\">%d</th>\n\
2064 <th style=\"text-align: right\">100 %%</th>\n\
2065 <th style=\"text-align: right\">%Lu MB</th>\n\
2066 <th style=\"text-align: right\">100 %%</th></tr>\n",active_classes
,total_traffic
);
2067 fputs("</thead></table>\n", f
);
2069 /* write basic ERP data to log directory */
2073 sprintf(str
,"%s/ERP.log",log_dir
);
2074 iplog
=fopen(str
,"a");
2077 fprintf(iplog
,"%ld\t%d\t%d %%\t%Lu M\t%Ld %%\tACTIVE %d\tTRAFFIC %Lu M\tCLASSES %d\tFUP-LIMIT %d\tLOW-PRIO %d\t%s",
2078 time(NULL
), top20_count
, top20_perc1
, top20_sum
, top20_perc2
,
2079 active_classes
, total_traffic
, i
, limit_count
, prio_count
, d
); /* d = date*/
2089 fprintf(f
, stats_html_signature
, version
);
2100 printf("Statistics preview generated (-%c switch) - now exiting ...\n", swchar
);
2106 printf("%-22s %-15s mark\n","name","ip");
2109 printf("Writing %s ... ", classmap
);
2110 f
= fopen(classmap
, "w");
2116 /*-----------------------------------------------------------------*/
2117 puts("Generating iptables and tc classes ... ");
2118 /*-----------------------------------------------------------------*/
2120 for_each(ip
, ips
) if(ip
->mark
> 0)
2125 duplicate(ip
->addr
,buf
);
2126 buf
=hash_id(ip
->addr
,32-idxtable_bitmask1
);
2128 string(chain_forward
,6+strlen(buf
));
2129 strcpy(chain_forward
,"forw_");
2130 strcat(chain_forward
,buf
);
2132 string(chain_postrouting
,6+strlen(buf
));
2133 strcpy(chain_postrouting
,"post_");
2134 strcat(chain_postrouting
,buf
);
2140 chain_forward
="FORWARD";
2141 chain_postrouting
="POSTROUTING";
2145 printf("%-22s %-16s %04d ", ip
->name
, ip
->addr
, ip
->mark
);
2148 /* -------------------------------------------------------- mark download */
2150 sprintf(str
, "-A %s -d %s/32 -o %s -j %s%d",
2151 chain_postrouting
, ip
->addr
, lan
, mark_iptables
, ip
->mark
);
2152 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/
2153 /* -m limit --limit 1/s */
2158 sprintf(str
, "-A %s -s %s -p tcp --sport %d -d %s/32 -o %s -j %s%d",
2159 chain_postrouting
, proxy_ip
, proxy_port
, ip
->addr
, lan
, mark_iptables
, ip
->mark
);
2160 /*sprintf(str,"-A %s -s %s -p tcp --sport %d -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,proxy_ip,proxy_port,ip->addr,lan,ip->mark);*/
2164 sprintf(str
, "-A %s -d %s/32 -o %s -j ACCEPT",
2165 chain_postrouting
, ip
->addr
, lan
);
2168 /* -------------------------------------------------------- mark upload */
2169 sprintf(str
, "-A %s -s %s/32 -o %s -j %s%d",
2170 chain_forward
, ip
->addr
, wan
, mark_iptables
, ip
->mark
);
2171 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/
2174 sprintf(str
, "-A %s -s %s/32 -o %s -j ACCEPT",
2175 chain_forward
, ip
->addr
, wan
);
2180 /* -------------------------------------------------------- download class */
2182 printf("(down: %dk-%dk ", ip
->min
, ip
->max
);
2185 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
2186 tc
, lan
, ip
->group
, ip
->mark
,ip
->min
,ip
->max
, burst
, ip
->prio
);
2189 if(strcmpi(ip
->keyword
->leaf_discipline
, "none"))
2191 sprintf(str
, "%s qdisc add dev %s parent 1:%d handle %d %s",
2192 tc
, lan
, ip
->mark
, ip
->mark
, ip
->keyword
->leaf_discipline
); /*qos_leaf*/
2196 if(filter_type
== 1)
2198 sprintf(str
, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",
2199 tc
, lan
, ip
->mark
, ip
->mark
);
2203 /* -------------------------------------------------------- upload class */
2205 printf("up: %dk-%dk)\n", (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
2206 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
));
2209 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
2210 tc
, wan
, ip
->group
, ip
->mark
,
2211 (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
2212 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
), burst
, ip
->prio
);
2215 if(strcmpi(ip
->keyword
->leaf_discipline
, "none"))
2217 sprintf(str
, "%s qdisc add dev %s parent 1:%d handle %d %s",
2218 tc
, wan
, ip
->mark
, ip
->mark
, ip
->keyword
->leaf_discipline
); /*qos_leaf*/
2222 if(filter_type
== 1)
2224 sprintf(str
, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",
2225 tc
, wan
, ip
->mark
, ip
->mark
);
2231 fprintf(f
, "%s %d\n", ip
->addr
, ip
->mark
);
2237 printf("(sharing %s)\n", ip
->sharing
);
2250 chain_forward
= "forw_common";
2251 chain_postrouting
= "post_common";
2255 chain_forward
= "FORWARD";
2256 chain_postrouting
= "POSTROUTING";
2258 /* -------------------------------- classify or reject free download */
2260 char *final_chain
= "DROP"; /* REJECT would be better, but it is impossible in mangle */
2263 final_chain
= "ACCEPT";
2269 sprintf(str
,"-A %s -s %s -p tcp --sport %d -o %s -j %s%d",
2270 chain_postrouting
,proxy_ip
,proxy_port
,lan
,mark_iptables
,3);
2273 sprintf(str
,"-A %s -s %s -p tcp --sport %d -o %s -j %s",
2274 chain_postrouting
,proxy_ip
,proxy_port
,lan
,final_chain
);
2279 sprintf(str
,"-A %s -o %s -j %s%d", chain_postrouting
, lan
, mark_iptables
, 3);
2282 sprintf(str
,"-A %s -o %s -j %s", chain_postrouting
, lan
, final_chain
);
2284 /* ------------------------------- classify or reject free upload */
2287 sprintf(str
,"-A %s -o %s -j %s%d", chain_forward
, wan
, mark_iptables
, 3);
2290 sprintf(str
,"-A %s -o %s -j %s", chain_forward
, wan
, final_chain
);
2294 if(free_min
) /* allocate free bandwith if it is not zero... */
2296 /*-----------------------------------------------------------------*/
2297 puts("Generating free bandwith classes ...");
2298 /*-----------------------------------------------------------------*/
2299 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
2300 tc
, lan
, parent
, free_min
, free_max
,burst
, lowest_priority
);
2302 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
2303 tc
, wan
, parent
, free_min
, free_max
, burst
, lowest_priority
);
2306 if(strcmpi(qos_leaf
, "none"))
2308 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s", tc
, lan
, qos_leaf
);
2311 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s", tc
, wan
, qos_leaf
);
2314 /* tc handle 1 fw flowid */
2315 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3", tc
, lan
);
2318 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3", tc
, wan
);
2321 printf("Total IP count: %d\n", i
);
2328 /* that's all folks, thank you for reading it all the way up to this point ;-) */
2329 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
This page took 1.929908 seconds and 4 git commands to generate.