3cc2662a6cf648d097091004d514a87c424d857c
[svn/Prometheus-QoS/.git] / prometheus.c
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-2008 Michael Polak (xChaos) */
6 /* iptables-restore support Copyright(C) 2007-2008 ludva */
7 /* Credit: CZFree.Net,Martin Devera,Netdave,Aquarius,Gandalf */
8 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
9
10 /* Modified by: xChaos, 20110428
11 ludva, 20080415
12
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.
17
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.
22
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
26
27 GNU General Public License is located in file COPYING */
28
29 #define STRLEN 256
30 #define FIRSTGROUPID 1024
31 #define FIRSTIPCLASS 2048
32 #undef DEBUG
33
34 #include "cll1-0.6.2.h"
35
36 const char *version = "0.8.3";
37
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. */
42
43 const char *stats_html_signature = "<small>Statistics generated by Prometheus QoS version %s<br>GPL+Copyright(C)2005-2011 Michael Polak, <a href=\"http://www.arachne.cz/\">Arachne Labs</a></small>\n";
44
45 /* ======= All path names are defined here (for RPM patch) ======= */
46
47 char *tc = "/sbin/tc"; /* requires tc with HTB support */
48 char *iptables = "/sbin/iptables"; /* requires iptables utility */
49 char *iptablessave = "/sbin/iptables-save"; /* not yet required */
50 char *iptablesrestore = "/sbin/iptables-restore"; /* requires iptables-restore */
51 const char *ls = "/bin/ls"; /* this is not user configurable :-) */
52
53 char *config = "/etc/prometheus/prometheus.conf"; /* main configuration file */
54 char *hosts = "/etc/prometheus/hosts"; /* per-IP bandwidth definition file */
55
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 *html = "/var/www/traffic.html"; /* hall of fame filename */
59 char *preview = "/var/www/preview.html"; /* hall of fame preview */
60 char *cmdlog = "/var/log/prometheuslog"; /* command log filename */
61 char *log_dir = "/var/www/logs/"; /* log directory pathname, ended with slash */
62 char *log_url = "logs/"; /* log directory relative URI prefix (partial URL) */
63 char *html_log_dir = "/var/www/logs/html/";
64
65 /* ======= Help screen is hopefuly self-documenting part of code :-) ======= */
66
67 void help(void)
68 {
69 puts("Command line switches:\n\
70 \n\
71 -?, --help this help screen\n\
72 -v, --version show Version number of this utility and exit\n\
73 -c filename force alternative /etc/prometheus.Conf filename\n\
74 -h filename force alternative /etc/Hosts filename (overrides hosts keyword)\n\
75 -f just Flush iptables and tc classes and exit (stop shaping)\n\
76 -9 emergency iptables flush (do not read data transfer statistics)\n\
77 -p just generate Preview of data transfer statistics and exit\n\
78 -d Dry run (preview tc and iptables commands on stdout)\n\
79 -r Run (reset all statistics and start shaping)\n\
80 -n run Now (start shaping without delay - overrides qos-free-delay keyword)\n\
81 -l Mmm YYYY generate HTML summary of traffic Logs (Mmm=Jan-Dec or Year, YYYY=year)\n\
82 -m generate HTML summary of traffic logs for yesterday's Month\n\
83 -y generate HTML summary of traffic logs for yesterday's Year\n");
84 /* not yet implemented:
85 -s start shaping! (keep data transfer statistics - but apply shaping)\n\
86 */
87 }
88
89 /* === Configuraration file values defaults - stored in global variables ==== */
90
91 int filter_type = 1; /*1 mark, 2 classify*/
92 char *mark = "MARK";
93 char *mark_iptables = "MARK --set-mark ";
94 int dry_run = 0; /* preview - use puts() instead of system() */
95 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]";
96 FILE *iptables_file = NULL;
97 int enable_credit = 1; /* enable credit file */
98 int use_credit = 0; /* use credit file (if enabled)*/
99 char *title = "Hall of Fame - Greatest Suckers"; /* hall of fame title */
100 int hall_of_fame = 1; /* enable hall of fame */
101 char *lan = "eth0"; /* LAN interface */
102 char *lan_medium = "100Mbit"; /* 10Mbit/100Mbit ethernet */
103 char *wan = "eth1"; /* WAN/ISP interface */
104 char *wan_medium = "100Mbit"; /* 10Mbit/100Mbit ethernet */
105 char *qos_leaf = "sfq perturb 5"; /* leaf discipline */
106 char *qos_free_zone = NULL; /* QoS free zone */
107 int qos_proxy = 1; /* include proxy port to QoS */
108 int found_lmsid = 0; /* show links to users in LMS information system */
109 int include_upload = 1; /* upload+download=total traffic */
110 char *proxy_ip = "192.168.1.1/32"; /* our IP with proxy port */
111 int proxy_port = 3128; /* proxy port number */
112 long long int line = 1024; /* WAN/ISP download in kbps */
113 long long int up = 1024; /* WAN/ISP upload in kbps */
114 int free_min = 32; /* minimum guaranted bandwidth for all undefined hosts */
115 int free_max = 64; /* maximum allowed bandwidth for all undefined hosts */
116 int qos_free_delay = 0; /* seconds to sleep before applying new QoS rules */
117 int digital_divide = 2; /* controls digital divide weirdness ratio, 1...3 */
118 int max_nesting = 3; /* maximum nesting of HTB clases, built-in maximum seems to be 4 */
119 int htb_r2q = 256; /* should work for leaf values 512 kbps to 8 Mbps */
120 int burst = 8; /* HTB burst (in kbits) */
121 int burst_main = 64;
122 int burst_group = 32;
123 int magic_treshold = 8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */
124 int keywordcount = 0;
125 /* not yet implemented:
126 int fixed_packets = 0; maximum number of pps per IP address (not class!)
127 int packet_limit = 5; maximum number of pps to htn CEIL, not rate !!!
128 */
129 FILE *log_file = NULL;
130 char *kwd = "via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */
131
132 const int highest_priority = 0; /* highest HTB priority (HTB built-in value is 0) */
133 const int lowest_priority = 7; /* lowest HTB priority (HTB built-in value is 7) */
134 const int idxtable_treshold1 = 24; /* this is no longer configurable */
135 const int idxtable_treshold2 = 12; /* this is no longer configurable */
136 const int idxtable_bitmask1 = 3; /* this is no longer configurable */
137 const int idxtable_bitmask2 = 3; /* this is no longer configurable */
138
139 /* ==== This is C<<1 stuff - learn C<<1 first! https://dev.arachne.cz/svn/cll1h ==== */
140
141 struct IP
142 {
143 char *addr;
144 char *name;
145 char *sharing;
146 int min;
147 int desired;
148 int max;
149 int mark;
150 int prio;
151 int fixedprio;
152 int group;
153 int lmsid;
154 unsigned long long direct;
155 unsigned long long proxy;
156 unsigned long long upload;
157 unsigned long long traffic;
158 unsigned long long credit;
159 unsigned long pktsup;
160 unsigned long pktsdown;
161 struct Keyword *keyword;
162 list(IP);
163 } *ips=NULL, *ip, *sharedip;
164
165 struct Group
166 {
167 int min;
168 int count;
169 int desired;
170 int id;
171 list(Group);
172 } *groups=NULL, *group;
173
174 struct Index
175 {
176 char *addr;
177 char *id;
178 struct Index *parent;
179 int bitmask;
180 int children;
181 list(Index);
182 } *idxs=NULL, *idx, *metaindex;
183
184 struct Keyword
185 {
186 char *key;
187
188 int asymetry_ratio; /* ratio for ADSL-like upload */
189 int asymetry_fixed; /* fixed treshold for ADSL-like upload */
190 int data_limit; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
191 int data_prio; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
192 long fixed_limit; /* fixed data limit for setting lower HTB ceil */
193 long fixed_prio; /* fixed data lmit for setting lower HTB prio */
194 int reserve_min; /* bonus for nominal HTB rate bandwidth (in kbps) */
195 int reserve_max; /* malus for nominal HTB ceil (in kbps) */
196 // int divide_max; /* relative malus: new_ceil=rate+(old_ceil-rate)/divide_max */
197 // int htb_ceil_bonus_divide; /* relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide */
198 int default_prio; /* default HTB priority for this keyword */
199 char *html_color;
200 int ip_count;
201 char *leaf_discipline;
202
203 list(Keyword);
204 } *keyword,*defaultkeyword=NULL,*keywords=NULL;
205
206 /* Damned, this must be object oriented! This looks almost like constructor ;-) */
207
208 void TheIP(void)
209 {
210 create(ip,IP);
211 ip->name = "";
212 ip->addr = "";
213 ip->sharing = NULL;
214 ip->prio = highest_priority+1;
215 ip->lmsid = -1;
216 ip->fixedprio = \
217 ip->mark = \
218 ip->min = \
219 ip->max = \
220 ip->desired = \
221 ip->credit = \
222 ip->upload = \
223 ip->proxy = \
224 ip->direct = \
225 ip->traffic = \
226 ip->pktsup = \
227 ip->pktsdown = 0;
228 ip->keyword = keywords;
229 push(ip,ips);
230 }
231
232 /* ====== iptables indexes are used to reduce complexity to log8(N) ===== */
233
234 char *very_ugly_ipv4_code(char *inip,int bitmask,int format_as_chainname)
235 {
236 /* warning: this function was debugged only for bitmask values 20,24,28 !!!*/
237 int dot=0,n;
238 char *ip,*outip,*outptr,*fmt;
239
240 duplicate(inip,ip);
241 /* debug printf("(%s,%d) -> ",ip,bitmask); */
242
243 if(ip && *ip && bitmask>=0 && bitmask<=32)
244 {
245 string(outip,strlen(ip)+10); /*fuck unicode? assertion: 10>strlen("_%d_%d") */
246 }
247 else
248 {
249 /* should never exit here */
250 return "undefined";
251 }
252 outptr=outip;
253 while(ip && *ip)
254 {
255 if(*ip=='.')
256 {
257 if(dot<(bitmask/8-1))
258 {
259 if(format_as_chainname)
260 {
261 *outptr='_';
262 }
263 else
264 {
265 *outptr='.';
266 }
267 outptr++;
268 dot++;
269 }
270 else
271 {
272 char *cutdot=strchr(ip+1,'.'); /*for bitmask<24*/
273 if(cutdot)*cutdot='\0';
274 if(format_as_chainname)
275 fmt="_%d_%d";
276 else
277 fmt=".%d";
278 if(bitmask%8)
279 n=atoi(ip+1)-atoi(ip+1)%(1<<(8-bitmask%8));
280 else
281 n=0;
282
283 /*debug printf("%d/%d => [_%d_%d]\n",atoi(ip+1),bitmask,n,bitmask); */
284 sprintf(outptr,fmt,n,bitmask);
285 if(!format_as_chainname) while(bitmask<24)
286 {
287 strcat(outip,".0");
288 bitmask+=8;
289 }
290 /* debug printf("[%s]\n",outip); */
291 return outip;
292 }
293 }
294 else
295 {
296 *outptr=*ip;
297 outptr++;
298 }
299 ip++;
300 }
301 /*should never exit here*/
302 *outptr='\0';
303 return outip;
304 }
305
306 char *hash_id(char *ip,int bitmask)
307 {
308 return very_ugly_ipv4_code(ip,bitmask,1);
309 }
310
311 char *subnet_id(char *ip,int bitmask)
312 {
313 return very_ugly_ipv4_code(ip,bitmask,0);
314 }
315
316 /* ================= Let's parse configuration file here =================== */
317
318 void reject_config_and_exit(char *filename)
319 {
320 printf("Configuration file %s rejected - abnormal exit.",filename);
321 exit(-1);
322 }
323
324 void get_config(char *config_filename)
325 {
326 char *cnf="mark";
327
328 printf("Configured keywords: ");
329 parse(config_filename)
330 {
331 option("keyword",kwd);
332 if(kwd)
333 {
334 printf("%s ",kwd);
335
336 create(keyword,Keyword);
337 keyword->key=kwd;
338 keyword->asymetry_ratio=1; /* ratio for ADSL-like upload */
339 keyword->asymetry_fixed=0; /* fixed treshold for ADSL-like upload */
340 keyword->data_limit=8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
341 keyword->data_prio=4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
342 keyword->fixed_limit=0; /* fixed data limit for setting lower HTB ceil */
343 keyword->fixed_prio=0; /* fixed data limit for setting lower HTB prio */
344 keyword->reserve_min=8; /* bonus for nominal HTB rate bandwidth (in kbps) */
345 keyword->reserve_max=0; /* malus for nominal HTB ceil (in kbps) */
346 keyword->default_prio=highest_priority+1;
347 keyword->html_color="000000";
348 keyword->ip_count=0;
349 keyword->leaf_discipline="";
350
351 push(keyword,keywords);
352 if(!defaultkeyword) defaultkeyword=keyword;
353 keywordcount++;
354
355 kwd=NULL;
356 }
357 else
358 {
359 for_each(keyword,keywords)
360 {
361 int l=strlen(keyword->key);
362
363 if(!strncmp(keyword->key,_,l) && strlen(_)>l+2)
364 {
365 char *tmptr=_; /* <---- l+1 ----> */
366 _+=l+1; /* via-prometheus-asymetry-ratio, etc. */
367 ioption("asymetry-ratio",keyword->asymetry_ratio);
368 ioption("asymetry-treshold",keyword->asymetry_fixed);
369 ioption("magic-relative-limit",keyword->data_limit);
370 ioption("magic-relative-prio",keyword->data_prio);
371 loption("magic-fixed-limit",keyword->fixed_limit);
372 loption("magic-fixed-prio",keyword->fixed_prio);
373 ioption("htb-default-prio",keyword->default_prio);
374 ioption("htb-rate-bonus",keyword->reserve_min);
375 ioption("htb-ceil-malus",keyword->reserve_max);
376 option("leaf-discipline",keyword->leaf_discipline);
377 option("html-color",keyword->html_color);
378 _=tmptr;
379
380 if(keyword->data_limit || keyword->fixed_limit ||
381 keyword->data_prio || keyword->fixed_prio)
382 {
383 use_credit=1;
384 }
385 }
386 }
387 }
388
389 option("tc",tc);
390 option("iptables",iptables);
391 option("iptables-save",iptablessave); /* new */
392 option("iptables-restore",iptablesrestore); /* new */
393 option("iptables-file",iptablesfile); /* new */
394 option("hosts",hosts);
395 option("lan-interface",lan);
396 option("wan-interface",wan);
397 option("lan-medium",lan_medium);
398 option("wan-medium",wan_medium);
399 lloption("wan-download",line);
400 lloption("wan-upload",up);
401 ioption("hall-of-fame-enable",hall_of_fame);
402 option("hall-of-fame-title",title);
403 option("hall-of-fame-filename",html);
404 option("hall-of-fame-preview",preview);
405 option("log-filename",cmdlog);
406 option("credit-filename",credit);
407 ioption("credit-enable",enable_credit);
408 option("log-traffic-directory",log_dir);
409 option("log-traffic-html-directory",html_log_dir);
410 option("log-traffic-url-path",log_url);
411 option("qos-free-zone",qos_free_zone);
412 ioption("qos-free-delay",qos_free_delay);
413 ioption("qos-proxy-enable",qos_proxy);
414 option("qos-proxy-ip",proxy_ip);
415 option("htb-leaf-discipline",qos_leaf);
416 ioption("qos-proxy-port",proxy_port);
417 ioption("free-rate",free_min);
418 ioption("free-ceil",free_max);
419 ioption("htb-burst",burst);
420 ioption("htb-burst-main",burst_main);
421 ioption("htb-burst-group",burst_group);
422 ioption("htb-nesting-limit",max_nesting);
423 ioption("htb-r2q",htb_r2q);
424 ioption("magic-include-upload",include_upload);
425 ioption("magic-treshold",magic_treshold);
426 option("filter-type", cnf);
427
428 /* not yet implemented:
429 ioption("magic-fixed-packets",fixed_packets);
430 ioption("magic-relative-packets",packet_limit);
431 */
432 }
433 fail
434 {
435 perror(config_filename);
436 puts("Warning - using built-in defaults instead ...");
437 }
438 done;
439 printf("\n");
440
441 /*leaf discipline for keywords*/
442 for_each(keyword,keywords)
443 {
444 if (!strcmpi(keyword->leaf_discipline, ""))
445 {
446 keyword->leaf_discipline = qos_leaf;
447 }
448 }
449
450 if (strcmpi(cnf, "mark"))
451 {
452 filter_type = 2;
453 mark = "CLASSIFY";
454 mark_iptables = "CLASSIFY --set-class 1:";
455 }
456 else
457 {
458 filter_type = 1;
459 mark = "MARK";
460 mark_iptables = "MARK --set-mark ";
461 }
462
463 /* are supplied values meaningful ?*/
464 if(line<=0 || up<=0)
465 {
466 puts("Illegal value of LAN or WAN bandwidth: 0 kbps.");
467 reject_config_and_exit(config_filename);
468 }
469 }
470
471 /* ===================== traffic analyser - uses iptables ================ */
472
473 void get_traffic_statistics(void)
474 {
475 char *str,*cmd;
476 int downloadflag=0;
477
478 textfile(Pipe,str) *line,*lines=NULL;
479 string(str,STRLEN);
480 string(cmd,STRLEN);
481
482 sprintf(cmd,"%s -L -v -x -n -t mangle",iptables);
483 shell(cmd);
484 input(str,STRLEN)
485 {
486 create(line,Pipe);
487 line->str=str;
488 string(str,STRLEN);
489 append(line,lines);
490 }
491
492 for_each(line,lines)
493 {
494 int col, accept=0,proxyflag=0,valid=1,setchainname=0,commonflag=0;
495 unsigned long long traffic=0;
496 unsigned long pkts=0;
497 char *ipaddr=NULL,*ptr;
498
499 /* debug puts(line->str); */
500 valid_columns(ptr,line->str,' ',col)
501 if(valid) switch(col)
502 {
503 case 1: if(eq(ptr,"Chain"))
504 setchainname=1;
505 else if(eq(ptr,"pkts"))
506 valid=0;
507 else
508 sscanf(ptr,"%lu",&pkts);
509 break;
510 case 2: if(setchainname)
511 {
512 if(!strncmp(ptr,"post_",5) || eq(ptr,"POSTROUTING"))
513 downloadflag=1;
514 else
515 if(!strncmp(ptr,"forw_",5) || eq(ptr,"FORWARD"))
516 downloadflag=0;
517
518 if(eq(ptr,"post_common") || eq(ptr,"forw_common"))
519 commonflag=1;
520 }
521 else
522 sscanf(ptr,"%Lu",&traffic); traffic+=(1<<19); traffic>>=20;
523 break;
524 case 3: if((strncmp(ptr,"post_",5) && strncmp(ptr,"forw_",5)) || commonflag)
525 accept=eq(ptr,mark);
526 /*if (filter_type==1) accept=eq(ptr,"MARK"); else accept=eq(ptr,"CLASSIFY");*/
527 break;
528 case 8: if(downloadflag)
529 {
530 if(strstr(proxy_ip,ptr))proxyflag=1;
531 }
532 else
533 ipaddr=ptr;
534 break;
535 case 9: if(downloadflag)ipaddr=ptr;break;
536 }
537
538 if(accept && traffic>0 && ipaddr)
539 {
540 if(proxyflag)
541 {
542 printf("(proxy) ");
543 }
544 else if(!downloadflag)
545 {
546 printf("(upload) ");
547 }
548 printf("IP %s: %Lu M (%ld pkts)\n", ipaddr, traffic, pkts);
549
550 if_exists(ip,ips,eq(ip->addr,ipaddr));
551 else
552 {
553 TheIP();
554 ip->addr=ipaddr;
555 if(eq(ip->addr,"0.0.0.0/0"))
556 {
557 ip->name="(unregistered)";
558 ip->min=free_min;
559 ip->max=ip->desired=free_max;
560 }
561 }
562
563 if(downloadflag)
564 {
565 if(proxyflag)
566 {
567 ip->proxy=traffic;
568 }
569 else
570 {
571 ip->traffic+=traffic;
572 }
573 ip->direct=ip->traffic-ip->upload-ip->proxy;
574 ip->pktsdown=pkts;
575 }
576 else
577 {
578 ip->upload=traffic;
579 ip->pktsup=pkts;
580 if(include_upload)
581 {
582 ip->traffic+=traffic;
583 }
584 else
585 {
586 if(traffic>ip->traffic)
587 {
588 ip->traffic=traffic;
589 }
590 }
591 }
592 }
593 }
594
595 free(cmd);
596 }
597
598 /* ========== This function executes, logs OR ALSO prints command ========== */
599
600 void safe_run(char *cmd)
601 {
602 if(dry_run)
603 {
604 printf("\n=>%s\n",cmd);
605 }
606 else
607 {
608 system(cmd);
609 }
610 if(log_file)
611 {
612 fprintf(log_file,"%s\n",cmd);
613 }
614 }
615
616 void save_line(char *line)
617 {
618 fprintf(iptables_file,"%s\n",line);
619 }
620
621 void run_restore(void)
622 {
623 char *restor, *str;
624 string(restor,STRLEN);
625
626 /*-----------------------------------------------------------------*/
627 printf("Running %s <%s ...\n",iptablesrestore,iptablesfile);
628 /*-----------------------------------------------------------------*/
629
630 save_line("COMMIT");
631 fclose(iptables_file);
632 if(dry_run)
633 {
634 parse(iptablesfile)
635 {
636 printf("%s\n",_);
637 }
638 done;
639 }
640
641 sprintf(restor,"%s <%s",iptablesrestore, iptablesfile);
642 safe_run(restor);
643
644 free(restor);
645 }
646
647 /* == This function strips extra characters after IP address and stores it = */
648
649 void parse_ip(char *str)
650 {
651 char *ptr,*ipaddr=NULL,*ipname=NULL,*lmsid=NULL;
652
653 ptr=strchr(str,'{');
654 if(ptr)
655 {
656 lmsid=++ptr;
657 while(*ptr && *ptr!='}')
658 {
659 ptr++;
660 }
661 *ptr=0;
662 }
663
664 ptr=str;
665 while(*ptr && *ptr!=' ' && *ptr!=9)
666 {
667 ptr++;
668 }
669
670 *ptr=0;
671 ipaddr=str;
672 ptr++;
673 while(*ptr && (*ptr==' ' || *ptr==9))
674 {
675 ptr++;
676 }
677 ipname=ptr;
678 while(*ptr && *ptr!=' ' && *ptr!=9)
679 {
680 ptr++;
681 }
682 *ptr=0;
683
684 if_exists(ip,ips,eq(ip->addr,ipaddr));
685 else
686 {
687 TheIP();
688 }
689 ip->addr=ipaddr;
690 ip->name=ipname;
691 if(lmsid)
692 {
693 ip->lmsid=atoi(lmsid);
694 found_lmsid=1;
695 }
696 }
697
698 char *parse_datafile_line(char *str)
699 {
700 char *ptr=strchr(str,' ');
701
702 if(ptr)
703 {
704 *ptr=0;
705 ptr++;
706 return ptr;
707 }
708 else
709 {
710 return NULL;
711 }
712 }
713
714 struct IpLog
715 {
716 char *name;
717 long traffic;
718 long guaranted;
719 int i;
720 int lmsid;
721 long l;
722 list(IpLog);
723 } *iplog,*iplogs;
724
725 void parse_ip_log(int argc, char **argv)
726 {
727 char *month, *year, *str, *name="(undefined)", *ptr, *ptr2, *filename;
728 long traffic=0l, traffic_month, total=0, guaranted;
729 int col, col2, y_ok, m_ok, accept_month, i=1, any_month=0, lmsid;
730 char mstr[4], ystr[5];
731 FILE *f;
732 string(str,STRLEN);
733 string(filename,STRLEN);
734
735 if(argv[1][1]=='l') /* -l */
736 {
737 if(argc<4)
738 {
739 puts("Missing parameter(s)!\nUsage: prometheus -l Mmm YYYY (Mmm=Jan-Dec or Year, YYYY=year)");
740 exit(-1);
741 }
742 else
743 {
744 month=argv[2];
745 if(eq(month,"Year")) any_month=1;
746 year=argv[3];
747 }
748 }
749 else
750 {
751 time_t t = time(NULL) - 3600*24 ; /* yesterday's timestamp*/
752 struct tm *timep = localtime(&t);
753
754 if(argv[1][1]=='m') /* -m yestarday - month */
755 {
756 strftime(mstr, 4, "%b", timep);
757 month=mstr;
758 strftime(ystr, 5, "%Y", timep);
759 year=ystr;
760 }
761 else /* -y yesterday - year */
762 {
763 month="Year";
764 any_month=1;
765 strftime(ystr, 5, "%Y", timep);
766 year=ystr;
767 }
768 }
769 printf("Analysing traffic for %s %s ...\n",month,year);
770
771 /* sorry... next release of C<<1 header file will include for_path_files(name,path) { } macro */
772 sprintf(str,"%s %s/",ls,log_dir);
773 shell(str);
774 input(str,STRLEN)
775 {
776 if(strstr(str,".log"))
777 {
778 ptr=strrchr(str,'\n');
779 if(ptr) *ptr='\0';
780 sprintf(filename,"%s/%s",log_dir,str);
781 printf("Parsing %s ...",filename);
782 accept_month=0;
783 traffic_month=0;
784 guaranted=0;
785 lmsid=-1;
786 parse(filename)
787 {
788 y_ok=m_ok=0;
789 valid_columns(ptr,_,'\t',col) switch(col)
790 {
791 case 2: name = ptr;break;
792 case 3: traffic = atol(ptr);break;
793 /* column number - was 7, now 11...*/
794 case 7:
795 case 8:
796 case 9:
797 case 10:
798 case 11: if (isalpha(*ptr)) /* character, not numeric string = date, just one*/
799 {
800 valid_columns(ptr2,ptr,' ',col2) switch(col2)
801 {
802 case 2: if(any_month || eq(ptr2,month)) m_ok = 1; break;
803 case 5: if(eq(ptr2,year)) y_ok = 1; break;
804 }
805 }
806 else
807 {
808 if(col == 7) guaranted = atol(ptr);
809 if(col == 10) lmsid = atoi(ptr);
810 }
811 }
812
813 if(y_ok && m_ok)
814 {
815 traffic_month += traffic;
816 accept_month = 1;
817 }
818 }
819 done;
820
821 if(accept_month)
822 {
823 create(iplog,IpLog);
824 iplog->name = name;
825 iplog->guaranted = guaranted;
826 iplog->traffic = traffic_month;
827 iplog->lmsid = lmsid;
828 insert(iplog,iplogs,desc_order_by,traffic);
829 printf(" %ld MB\n",iplog->traffic);
830 }
831 else
832 {
833 puts(" no records.");
834 }
835 }
836 }
837 sprintf(str,"%s/%s-%s.html",html_log_dir,year,month);
838 printf("Writing %s ...",str);
839 f=fopen(str,"w");
840 if(f)
841 {
842 fprintf(f,"<table border><tr><th colspan=\"2\">%s %s</th><th colspan=\"2\">Data transfers</th><th align=\"right\">Min.speed</th></tr>\n ",month,year);
843
844 for_each(iplog,iplogs)
845 {
846 if(iplog->traffic)
847 {
848 fprintf(f,"<tr><td align=\"right\">%d</td><th align=\"left\">%s</td><td align=\"right\">%ld M</td><th align=\"right\">%ld G</th><td align=\"right\">%ld kbps</th></tr>\n",
849 i++, iplog->name, iplog->traffic, iplog->traffic>>10, iplog->guaranted);
850 total+=iplog->traffic>>10;
851 iplog->i=i;
852 iplog->l=total;
853 }
854 }
855 fprintf(f,"<tr><th colspan=\"3\" align=\"left\">Total:</th><th align=\"right\">%ld GB</th><th align=\"right\">%Ld kbps</th></tr>\n", total, line);
856 fputs("</table>\n", f);
857
858 if(i>10)
859 {
860 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"5\">Enterprise Research and Planning (ERP)</th></tr>\n",f);
861 fputs("<tr><td>Analytic category</td>\n",f);
862 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr>\n",f);
863
864 if_exists(iplog,iplogs,iplog->l>=total/4)
865 {
866 fprintf(f,"<tr><td>Top 25%% of traffic</td>\n");
867 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
868 }
869
870 if_exists(iplog,iplogs,iplog->i==10)
871 {
872 fprintf(f,"<tr><td>Top 10 downloaders</td>\n");
873 fprintf(f,"<th align=\"right\">10</th><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
874 }
875
876 if_exists(iplog,iplogs,iplog->l>=total/2)
877 {
878 fprintf(f,"<tr><td>Top 50%% of traffic</td>\n");
879 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><th align=\"right\">%d %%</th></tr>\n",iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
880 }
881
882 if_exists(iplog,iplogs,iplog->l>=4*total/5)
883 {
884 fprintf(f,"<tr><td>Top 80%% of traffic</td>\n");
885 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><th align=\"right\">%d %%</th></tr>\n",iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
886 }
887
888 if_exists (iplog,iplogs,iplog->i>=i/5)
889 {
890 fprintf(f,"<tr><td>Top 20%% downloaders</td>\n");
891 fprintf(f,"<td align=\"right\">%d</td><th align=\"right\">%d %%</th><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
892 }
893
894 if_exists(iplog,iplogs,iplog->i>=i/4)
895 {
896 fprintf(f,"<tr><td>Top 25%% downloaders</td>\n");
897 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
898 }
899
900 if_exists(iplog,iplogs,iplog->i>=i/2)
901 {
902 fprintf(f,"<tr><td>Top 50%% downloaders</td>\n");
903 fprintf(f,"<td align=\"right\">%d</td><th align=\"right\">%d %%</th><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
904 }
905
906 if_exists(iplog,iplogs,iplog->i>=4*i/5)
907 {
908 fprintf(f,"<tr><td>Top 80%% downloaders</td>\n");
909 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
910 }
911
912 fprintf(f,"<tr><td>All users, all traffic</td>\n");
913 fprintf(f,"<th align=\"right\">%d</th><th align=\"right\">100 %%</th><th align=\"right\">%ld G</th><th align=\"right\">100 %%</th></tr>\n",i-1,total);
914 fputs("</table>\n", f);
915 }
916
917 fprintf(f, stats_html_signature, version);
918 fclose(f);
919 puts(" done.");
920 }
921 }
922
923 /*-----------------------------------------------------------------*/
924 /* Are you looking for int main(int argc, char **argv) ? :-)) */
925 /*-----------------------------------------------------------------*/
926
927 program
928 {
929 int i=0;
930 FILE *f=NULL;
931 char *str, *ptr, *d;
932 char *substring;
933 int class_count=0,ip_count=0;
934 int parent=1;
935 int just_flush=FALSE;
936 int nodelay=FALSE;
937 int just_preview=FALSE; /* preview - generate just stats */
938 int just_logs=FALSE; /* just parse logs */
939 int run=FALSE;
940
941 char *chain_forward, *chain_postrouting;
942 char *althosts=NULL;
943
944 printf("\n\
945 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
946 Version %s - Copyright (C)2005-2011 Michael Polak (xChaos)\n\
947 iptables-restore & burst tunning & classify modification by Ludva\n\
948 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version);
949
950 /*----- Boring... we have to check command line options first: ----*/
951
952 arguments
953 {
954 argument("-c") { nextargument(config); }
955 argument("-h") { nextargument(althosts);}
956 argument("-d") { run=TRUE; dry_run=TRUE; }
957 argument("-f") { run=TRUE; just_flush=TRUE; }
958 argument("-9") { run=TRUE; just_flush=9; }
959 argument("-p") { run=TRUE; just_preview=TRUE; }
960 argument("-r") { run=TRUE; }
961 argument("-n") { run=TRUE; nodelay=TRUE; }
962 argument("-l") { just_logs=TRUE; }
963 argument("-m") { just_logs=TRUE; }
964 argument("-y") { just_logs=TRUE; }
965 argument("-?") { help(); exit(0); }
966 argument("--help") { help(); exit(0); }
967 argument("-v") { exit(0); }
968 argument("--version") { exit(0); }
969 }
970
971 if(dry_run)
972 {
973 puts("*** THIS IS JUST DRY RUN ! ***\n");
974 }
975
976 date(d); /* this is typical cll1.h macro - prints current date */
977
978 /*-----------------------------------------------------------------*/
979 printf("Parsing configuration file %s ...\n", config);
980 /*-----------------------------------------------------------------*/
981 get_config(config);
982
983 if(just_logs)
984 {
985 parse_ip_log(argc,argv);
986 exit(0);
987 }
988 else if(not run)
989 {
990 help();
991 exit(0);
992 }
993
994 if(althosts)
995 {
996 hosts=althosts;
997 }
998
999 if(just_flush<9)
1000 {
1001 /*-----------------------------------------------------------------*/
1002 puts("Parsing iptables verbose output ...");
1003 /*-----------------------------------------------------------------*/
1004 get_traffic_statistics();
1005 }
1006
1007 /*-----------------------------------------------------------------*/
1008 printf("Parsing class defintion file %s ...\n", hosts);
1009 /*-----------------------------------------------------------------*/
1010 int groupidx = FIRSTGROUPID;
1011 parse(hosts)
1012 {
1013 str=_;
1014
1015 if(*str<'0' || *str>'9')
1016 {
1017 /* any line starting with non-number is comment ...*/
1018 continue;
1019 }
1020
1021 //Does this IP share QoS class with some other ?
1022 substring=strstr(str,"sharing-");
1023 if(substring)
1024 {
1025 substring+=8; //"sharing-"
1026 parse_ip(str);
1027 ip_count++;
1028 ip->sharing=substring;
1029 ip->keyword=defaultkeyword; /* settings for default keyword */
1030 while(*substring && *substring!='\n')
1031 {
1032 substring++;
1033 }
1034 *substring=0;
1035 }
1036 else
1037 {
1038 //Do we have to create new QoS class for this IP ?
1039
1040 if_exists(keyword,keywords,(substring=strstr(str,keyword->key)))
1041 {
1042 parse_ip(str);
1043 ip_count++;
1044 ip->keyword=keyword;
1045 keyword->ip_count++;
1046 ip->prio=keyword->default_prio;
1047 substring+=strlen(keyword->key)+1;
1048 ptr=substring;
1049 while(*ptr && *ptr!='-')
1050 {
1051 ptr++;
1052 }
1053 if(*ptr=='-')
1054 {
1055 *ptr=0;
1056 ip->max=ip->desired=atoi(ptr+1);
1057 }
1058 ip->min=atoi(substring);
1059 if(ip->min<=0)
1060 {
1061 printf(" %s: Illegal value of minimum bandwidth 0 kbps, using %d kbps\n",str,free_min);
1062 ip->min=free_min;
1063 }
1064 if(ip->max<=ip->min)
1065 {
1066 ip->fixedprio=1;
1067 ip->max=ip->min+ip->keyword->reserve_min;
1068 }
1069 else
1070 {
1071 ip->max-=ip->keyword->reserve_max;
1072 if(ip->max<ip->min)
1073 {
1074 ip->max=ip->min;
1075 }
1076 }
1077 ip->mark=FIRSTIPCLASS+1+class_count++;
1078
1079 if_exists(group,groups,group->min==ip->min)
1080 {
1081 group->count++;
1082 group->desired+=ip->min;
1083 ip->group = group->id;
1084 }
1085 else
1086 {
1087 create(group,Group);
1088 group->min=ip->min;
1089 group->id = groupidx++;
1090 ip->group = group->id;
1091
1092 if(group->min<8) group->min=8;
1093 /* Warning - this is maybe because of primitive tc namespace, can be fixed */
1094 /* it is because class IDs are derived from min. bandwidth. - xCh */
1095 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;
1096
1097 group->count=1;
1098 group->desired=ip->min;
1099 insert(group,groups,desc_order_by,min);
1100 }
1101 }//endif keyword-
1102 }//endif sharing-
1103 }
1104 fail
1105 {
1106 perror(hosts);
1107 exit(-1);
1108 }
1109 done;
1110
1111 /*-----------------------------------------------------------------*/
1112 /* cll1.h - let's allocate brand new character buffer... */
1113 /*-----------------------------------------------------------------*/
1114 string(str,STRLEN);
1115
1116 /*-----------------------------------------------------------------*/
1117 puts("Resolving shared connections ...");
1118 /*-----------------------------------------------------------------*/
1119 for_selected(ip,ips,ip->sharing)
1120 {
1121 for_selected(sharedip,ips,eq(sharedip->name,ip->sharing))
1122 {
1123 sharedip->traffic+=ip->traffic;
1124 ip->traffic=0;
1125 ip->mark=sharedip->mark;
1126 ip->lmsid=sharedip->lmsid;
1127 break;
1128 }
1129 if(!sharedip)
1130 {
1131 printf("Unresolved shared connection: %s %s sharing-%s\n",ip->addr,ip->name,ip->sharing);
1132 }
1133 }
1134
1135 if(enable_credit && just_flush<9)
1136 {
1137 /*-----------------------------------------------------------------*/
1138 printf("Parsing credit file %s ...\n", credit);
1139 /*-----------------------------------------------------------------*/
1140 parse(credit)
1141 {
1142 ptr=parse_datafile_line(_);
1143 if(ptr)
1144 {
1145 if_exists(ip,ips,eq(ip->addr,_))
1146 {
1147 sscanf(ptr,"%Lu",&(ip->credit));
1148 }
1149 }
1150 }
1151 done;
1152 }
1153
1154 if(!just_preview)
1155 {
1156 /*-----------------------------------------------------------------*/
1157 puts("Initializing iptables and tc classes ...");
1158 /*-----------------------------------------------------------------*/
1159
1160 iptables_file=fopen(iptablesfile,"w");
1161 if (iptables_file == NULL)
1162 {
1163 puts("Cannot open iptablesfile!");
1164 exit(-1);
1165 }
1166
1167 log_file=fopen(cmdlog,"w");
1168 if (log_file == NULL)
1169 {
1170 puts("Cannot open logfile!");
1171 exit(-1);
1172 }
1173
1174 save_line(iptablespreamble);
1175 run_restore();
1176
1177 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,lan);
1178 safe_run(str);
1179
1180 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,wan);
1181 safe_run(str);
1182
1183 iptables_file=fopen(iptablesfile,"w");
1184 save_line(iptablespreamble);
1185
1186 if(qos_free_zone && *qos_free_zone!='0')
1187 {
1188 char *chain;
1189
1190 sprintf(str,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone, wan);
1191 save_line(str);
1192
1193 if(qos_proxy)
1194 {
1195 save_line(":post_noproxy - [0:0]");
1196 sprintf(str,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan);
1197 save_line(str);
1198 sprintf(str,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip, lan);
1199 save_line(str);
1200 sprintf(str,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip, proxy_port, lan);
1201 save_line(str);
1202
1203 chain="post_noproxy";
1204 }
1205 else
1206 {
1207 chain="POSTROUTING";
1208 }
1209
1210 sprintf(str,"-A %s -s %s -o %s -j ACCEPT", chain, qos_free_zone, lan);
1211 save_line(str);
1212 }
1213
1214 if(ip_count>idxtable_treshold1 && !just_flush)
1215 {
1216 int idxcount=0, bitmask=32-idxtable_bitmask1; /* default net mask: 255.255.255.240 */
1217 char *subnet, *buf;
1218 /*-----------------------------------------------------------------*/
1219 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count);
1220 /*-----------------------------------------------------------------*/
1221
1222 save_line(":post_common - [0:0]");
1223 save_line(":forw_common - [0:0]");
1224
1225 for_selected(ip,ips,ip->addr && *(ip->addr) && !eq(ip->addr,"0.0.0.0/0"))
1226 {
1227 buf=hash_id(ip->addr,bitmask);
1228 if_exists(idx,idxs,eq(idx->id,buf))
1229 {
1230 idx->children++;
1231 }
1232 else
1233 {
1234 create(idx,Index);
1235 idx->addr=ip->addr;
1236 idx->id=buf;
1237 idx->bitmask=bitmask;
1238 idx->parent=NULL;
1239 idx->children=0;
1240 idxcount++;
1241 push(idx,idxs);
1242 }
1243 }
1244
1245 /* brutal perfomance optimalization */
1246 while(idxcount>idxtable_treshold2 && bitmask>2*idxtable_bitmask2)
1247 {
1248 bitmask-=idxtable_bitmask2;
1249 idxcount=0;
1250
1251 for_selected(idx,idxs,idx->parent==NULL)
1252 {
1253 buf=hash_id(idx->addr,bitmask);
1254 if_exists(metaindex,idxs,eq(metaindex->id,buf))
1255 {
1256 metaindex->children++;
1257 }
1258 else
1259 {
1260 create(metaindex,Index);
1261 metaindex->addr=idx->addr;
1262 metaindex->id=buf;
1263 metaindex->bitmask=bitmask;
1264 metaindex->parent=NULL;
1265 metaindex->children=0;
1266 idxcount++;
1267 push(metaindex,idxs);
1268 }
1269 idx->parent=metaindex;
1270 }
1271 }
1272
1273 /* this should slightly optimize throughout ... */
1274 sort(idx,idxs,desc_order_by,children);
1275 sort(idx,idxs,order_by,bitmask);
1276
1277 i=0;
1278 for_each(idx,idxs)
1279 {
1280 subnet=subnet_id(idx->addr,idx->bitmask);
1281 printf("%d: %s/%d\n",++i,subnet,idx->bitmask);
1282
1283 sprintf(str,":post_%s - [0:0]", idx->id);
1284 save_line(str);
1285
1286 sprintf(str,":forw_%s - [0:0]", idx->id);
1287 save_line(str);
1288
1289 if(idx->parent)
1290 {
1291 string(buf,strlen(idx->parent->id)+6);
1292 sprintf(buf,"post_%s",idx->parent->id);
1293 }
1294 else
1295 {
1296 buf="POSTROUTING";
1297 }
1298
1299 sprintf(str,"-A %s -d %s/%d -o %s -j post_%s", buf, subnet, idx->bitmask, lan, idx->id);
1300 save_line(str);
1301
1302 sprintf(str,"-A %s -d %s/%d -o %s -j post_common", buf, subnet, idx->bitmask, lan);
1303 save_line(str);
1304
1305 if(idx->parent)
1306 {
1307 string(buf,strlen(idx->parent->id)+6);
1308 sprintf(buf,"forw_%s",idx->parent->id);
1309 }
1310 else
1311 {
1312 buf="FORWARD";
1313 }
1314
1315 sprintf(str,"-A %s -s %s/%d -o %s -j forw_%s", buf, subnet, idx->bitmask, wan, idx->id);
1316 save_line(str);
1317
1318 sprintf(str,"-A %s -s %s/%d -o %s -j forw_common", buf, subnet, idx->bitmask, wan);
1319 save_line(str);
1320 }
1321 printf("Total indexed iptables chains created: %d\n", i);
1322
1323 sprintf(str,"-A FORWARD -o %s -j forw_common", wan);
1324 save_line(str);
1325
1326 sprintf(str,"-A POSTROUTING -o %s -j post_common", lan);
1327 save_line(str);
1328 }
1329
1330 }
1331
1332 if(just_flush)
1333 {
1334 fclose(iptables_file);
1335 if (log_file) fclose(log_file);
1336 puts("Just flushed iptables and tc classes - now exiting ...");
1337 exit(0);
1338 }
1339
1340 if(!just_preview)
1341 {
1342 if(!dry_run && !nodelay && qos_free_delay)
1343 {
1344 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay);
1345 sleep(qos_free_delay);
1346 }
1347
1348 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,lan,htb_r2q);
1349 safe_run(str);
1350
1351 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1352 tc,lan,lan_medium,lan_medium,burst_main,highest_priority);
1353 safe_run(str);
1354
1355 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1356 tc,lan,line,line,burst_main,highest_priority);
1357 safe_run(str);
1358
1359 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,wan,htb_r2q);
1360 safe_run(str);
1361
1362 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1363 tc,wan,wan_medium,wan_medium,burst_main,highest_priority);
1364 safe_run(str);
1365
1366 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1367 tc,wan,up,up,burst_main,highest_priority);
1368 safe_run(str);
1369 }
1370
1371 /*-----------------------------------------------------------------*/
1372 puts("Locating heavy downloaders and generating root classes ...");
1373 /*-----------------------------------------------------------------*/
1374 sort(ip,ips,desc_order_by,traffic);
1375
1376 /*-----------------------------------------------------------------*/
1377 /* sub-scope - local variables */
1378 {
1379 long long int rate=line;
1380 long long int max=line;
1381 int group_count=0;
1382 FILE *credit_file=NULL;
1383
1384 if(!just_preview && !dry_run && enable_credit)
1385 {
1386 credit_file=fopen(credit,"w");
1387 }
1388
1389 for_each(group,groups)
1390 {
1391 if(!just_preview)
1392 {
1393 //download
1394 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",
1395 tc, lan, parent, group->id, rate, max, burst_group, highest_priority+1, group->desired);
1396 safe_run(str);
1397
1398 //upload
1399 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",
1400 tc, wan, parent, group->id, rate*up/line, max*up/line, burst_group, highest_priority+1, group->desired);
1401 safe_run(str);
1402 }
1403
1404 if(group_count++<max_nesting)
1405 {
1406 parent=group->id;
1407 }
1408
1409 rate-=digital_divide*group->min;
1410 if(rate<group->min)
1411 {
1412 rate=group->min;
1413 }
1414
1415 /*shaping of aggresive downloaders, with credit file support */
1416 if(use_credit)
1417 {
1418 int group_rate=group->min, priority_sequence=lowest_priority;
1419
1420 for_selected(ip, ips, ip->min==group->min && ip->max>ip->min)
1421 {
1422 if( ip->keyword->data_limit && !ip->fixedprio &&
1423 ip->traffic>ip->credit+
1424 (ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20)) )
1425 {
1426 if(group_rate<ip->max)
1427 {
1428 ip->max=group_rate;
1429 }
1430 group_rate+=magic_treshold;
1431 ip->prio=lowest_priority;
1432 if(ip->prio<highest_priority+2)
1433 {
1434 ip->prio=highest_priority+2;
1435 }
1436 }
1437 else
1438 {
1439 if( ip->keyword->data_prio && !ip->fixedprio &&
1440 ip->traffic>ip->credit+
1441 (ip->min*ip->keyword->data_prio+(ip->keyword->fixed_prio<<20)) )
1442 {
1443 ip->prio=priority_sequence--;
1444 if(ip->prio<highest_priority+1)
1445 {
1446 ip->prio=highest_priority+1;
1447 }
1448 }
1449
1450 if(credit_file)
1451 {
1452 unsigned long long lcredit=0;
1453
1454 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic)
1455 {
1456 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;
1457 }
1458 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);
1459 }
1460 }
1461 }
1462
1463 }
1464 }
1465 if(credit_file)
1466 {
1467 fclose(credit_file);
1468 }
1469 }
1470
1471 if(just_preview)
1472 {
1473 f=fopen(preview,"w");
1474 ptr=preview;
1475 }
1476 else if(!dry_run && !just_flush)
1477 {
1478 /*-----------------------------------------------------------------*/
1479 printf("Writing data transfer database ...\n");
1480 /*-----------------------------------------------------------------*/
1481 f=fopen("/var/run/prometheus.previous","w");
1482 if(f)
1483 {
1484 for_selected(ip,ips,ip->traffic || ip->direct || ip->proxy ||ip->upload)
1485 fprintf(f,"%s %Lu %Lu %Lu %Lu\n",ip->addr,ip->traffic,ip->direct,ip->proxy,ip->upload);
1486 fclose(f);
1487 }
1488
1489 f=fopen(html,"w");
1490 ptr=html;
1491 }
1492
1493 if(f)
1494 {
1495 int total=0;
1496 int count=1;
1497 i=0;
1498
1499 /*-----------------------------------------------------------------*/
1500 printf("Sorting data and generating statistics page %s ...\n",ptr);
1501 /*-----------------------------------------------------------------*/
1502
1503 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);
1504 fprintf(f,"<th colspan=\"%d\">data limits</th>\n",keywordcount);
1505 fputs("</tr>\n",f);
1506
1507 for_each(group,groups)
1508 {
1509 #ifdef DEBUG
1510 printf("%d k group: %d bandwidth requested: %d k\n",group->min,group->count,group->desired);
1511 #endif
1512 fprintf(f,"<tr><td align=\"right\">%d</td><td align=\"right\">%d k</td>",count,group->min);
1513 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d k</td>",group->count,group->desired);
1514
1515 for_each(keyword,keywords)
1516 {
1517 fprintf(f,"<td align=\"right\"><font color=\"#%s\">%d M</font></td>",keyword->html_color,group->min*keyword->data_limit);
1518 }
1519 i+=group->desired;
1520 total+=group->count;
1521 count++;
1522 }
1523 #ifdef DEBUG
1524 printf("Total groups: %d Total bandwidth requested: %d k\nAGGREGATION: 1/%d\n",count,i,i/line);
1525 #endif
1526 fprintf(f,"<tr><th colspan=\"2\" align=\"left\">Line %Ld k</td>",line);
1527 fprintf(f,"<th align=\"right\">%d</td><th align=\"right\">%d k</td>",total,i);
1528
1529 for_each(keyword,keywords)
1530 {
1531 fprintf(f,"<th align=\"right\">%d IPs</th>",keyword->ip_count);
1532 }
1533 fprintf(f,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n",(int)(0.5+i/line));
1534 fprintf(f,"<th colspan=\"%d\">%d traffic classes</th></tr>\n",keywordcount,total);
1535
1536 fputs("</table>\n",f);
1537 }
1538 else if(!dry_run && !just_flush)
1539 perror(html);
1540
1541 i=1;
1542 if(f)
1543 {
1544 unsigned long long total=0, total_direct=0, total_proxy=0, total_upload=0, tmp_sum=0;
1545 int active_classes=0;
1546 int colspan;
1547 FILE *iplog;
1548 struct Sum {unsigned long long l; int i; list(Sum);} *sum,*sums=NULL;
1549
1550 colspan=11;
1551 if(qos_proxy)
1552 {
1553 colspan++;
1554 }
1555 if(found_lmsid)
1556 {
1557 colspan++;
1558 }
1559
1560 fprintf(f,"<p><table border>\n<tr><th colspan=\"%d\">%s",colspan,title);
1561 fprintf(f," (%s)</th></tr>\n", d);
1562 fputs("<tr><td align=\"right\">#</td><td>hostname</td>",f);
1563 if(found_lmsid)
1564 {
1565 fputs("<td align=\"right\">lms</td>\n",f);
1566 }
1567 fputs("<td align=\"right\">credit</td>\
1568 <td align=\"right\">limit</td>\
1569 <td align=\"right\">total</td>\
1570 <td align=\"right\">direct</td>\n",f);
1571 if(qos_proxy)
1572 {
1573 fputs("<td align=\"right\">proxy</td>\n",f);
1574 }
1575 fputs("<td align=\"right\">upload</td>\
1576 <td align=\"right\">minimum</td>\
1577 <td align=\"right\">desired</td>\
1578 <td align=\"right\">maximum</td>\
1579 <td>prio</td></tr>\n",f);
1580
1581 for_each(ip,ips)
1582 {
1583 char *f1="", *f2="";
1584 if(ip->max<ip->desired)
1585 {
1586 f1="<font color=\"red\">";
1587 f2="</font>";
1588 }
1589 else if(ip->prio>highest_priority+1)
1590 {
1591 f1="<font color=\"brown\">";
1592 f2="</font>";
1593 }
1594
1595 #ifdef DEBUG
1596 printf("%03d. %-22s %10Lu (%d/%d)\n",i ,ip->name, ip->traffic, ip->min, ip->max);
1597 #endif
1598 fprintf(f,"<tr><td align=\"right\"><a name=\"%s\"></a>%d</td><td><a href=\"%s%s.log\">%s</a></td>\n", ip->name, i, log_url, ip->name, ip->name);
1599 if(found_lmsid)
1600 {
1601 fputs("<td align=\"right\">",f);
1602 if(ip->lmsid > 0)
1603 {
1604 /*base URL will be configurable soon ... */
1605 fprintf(f,"<a href=\"https://hermes.spoje.net/?m=customerinfo&amp;id=%d\">%04d</a>\n", ip->lmsid, ip->lmsid);
1606 }
1607 else if(ip->lmsid == 0)
1608 {
1609 fputs("------",f);
1610 }
1611 fputs("</td>\n",f);
1612 }
1613 fprintf(f,"<td align=\"right\">%Lu M</td>\n", ip->credit);
1614 fprintf(f,"<td align=\"right\"><font color=\"#%s\">%Lu M</font></td>",
1615 ip->keyword->html_color, ip->credit+(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20)));
1616 fprintf(f,"<td align=\"right\">%s%Lu M%s</td><td align=\"right\">%Lu M</td>\n", f1, ip->traffic, f2, ip->direct);
1617 if(qos_proxy)
1618 {
1619 fprintf(f,"<td align=\"right\">%Lu M</td>\n", ip->proxy);
1620 }
1621 fprintf(f,"<td align=\"right\">%Lu M</td>\n", ip->upload);
1622 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",
1623 ip->min,ip->desired,f1,ip->max,f2,f1,ip->prio,f2);
1624 total+=ip->traffic;
1625 total_direct+=ip->direct;
1626 total_proxy+=ip->proxy;
1627 total_upload+=ip->upload;
1628 if(ip->traffic>0)
1629 {
1630 active_classes++;
1631 tmp_sum+=ip->traffic;
1632 create(sum,Sum);
1633 sum->l=tmp_sum;
1634 sum->i=active_classes;
1635 insert(sum,sums,order_by,i);
1636 }
1637
1638 i++;
1639
1640 if(!just_preview)
1641 {
1642 sprintf(str,"%s/%s.log",log_dir,ip->name);
1643 iplog=fopen(str,"a");
1644 if(iplog)
1645 {
1646 fprintf(iplog,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%d\t%d\t%d\t%d\t%s",
1647 time(NULL),ip->name,ip->traffic,ip->direct,ip->proxy,ip->upload,ip->min,ip->max,ip->desired,ip->lmsid,d); /* d = date*/
1648 fclose(iplog);
1649 }
1650 }
1651
1652 }
1653 fprintf(f,"<tr><th colspan=\"%d\" align=\"left\">SUMMARY:</td>",colspan-7);
1654 fprintf(f,"<th align=\"right\">%Lu M</th>\
1655 <th align=\"right\">%Lu M</th>\n", total, total_direct);
1656 if(qos_proxy)
1657 {
1658 fprintf(f,"<th align=\"right\">%Lu M</th>\n", total_proxy);
1659 }
1660 fprintf(f,"<th align=\"right\">%Lu M</th>", total_upload);
1661 fputs("<td colspan=\"4\"></td></th>\n</table>\n",f);
1662
1663 if(active_classes>10)
1664 {
1665 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"5\">Enterprise Research and Planning (ERP)</th></tr>\n",f);
1666 fputs("<tr><td>Analytic category</td>\n",f);
1667 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr>\n",f);
1668
1669 if_exists(sum,sums,sum->l>=total/4)
1670 {
1671 fprintf(f,"<tr><td>Top 25%% of traffic</td>\n");
1672 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total);
1673 }
1674
1675 if_exists(sum,sums,sum->i==10)
1676 {
1677 fprintf(f,"<tr><td>Top 10 downloaders</td>\n");
1678 fprintf(f,"<th align=\"right\">10</th><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total);
1679 }
1680
1681 if_exists(sum,sums,sum->l>=total/2)
1682 {
1683 fprintf(f,"<tr><td>Top 50%% of traffic</td>\n");
1684 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><th align=\"right\">%Ld %%</th></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total);
1685 }
1686
1687 if_exists(sum,sums,sum->l>=4*total/5)
1688 {
1689 fprintf(f,"<tr><td>Top 80%% of traffic</td>\n");
1690 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><th align=\"right\">%Ld %%</th></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total);
1691 }
1692
1693 if_exists (sum,sums,sum->i>=(active_classes+1)/5)
1694 {
1695 fprintf(f,"<tr><td>Top 20%% downloaders</td>\n");
1696 fprintf(f,"<td align=\"right\">%d</td><th align=\"right\">%d %%</th><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total);
1697 }
1698
1699 if_exists(sum,sums,sum->i>=(active_classes+1)/4)
1700 {
1701 fprintf(f,"<tr><td>Top 25%% downloaders</td>\n");
1702 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total);
1703 }
1704
1705 if_exists(sum,sums,sum->i>=(active_classes+1)/2)
1706 {
1707 fprintf(f,"<tr><td>Top 50%% downloaders</td>\n");
1708 fprintf(f,"<td align=\"right\">%d</td><th align=\"right\">%d %%</th><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total);
1709 }
1710
1711 if_exists(sum,sums,sum->i>=4*(active_classes+1)/5)
1712 {
1713 fprintf(f,"<tr><td>Top 80%% downloaders</td>\n");
1714 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total);
1715 }
1716
1717 fprintf(f,"<tr><td>All users, all traffic</td>\n");
1718 fprintf(f,"<th align=\"right\">%d</th><th align=\"right\">100 %%</th><th align=\"right\">%Lu M</th><th align=\"right\">100 %%</th></tr>\n",active_classes,total);
1719 fputs("</table>\n", f);
1720 }
1721 fprintf(f, stats_html_signature, version);
1722 fclose(f);
1723 }
1724
1725 if(just_preview)
1726 {
1727 puts("Statistics preview generated (-p switch) - now exiting ...");
1728 exit(0);
1729 }
1730
1731 /*-----------------------------------------------------------------*/
1732 puts("Generating iptables and tc classes ...");
1733 /*-----------------------------------------------------------------*/
1734
1735 i=0;
1736 printf("%-22s %-15s mark\n","name","ip");
1737
1738 for_selected(ip,ips,ip->mark>0)
1739 {
1740
1741 if(idxs)
1742 {
1743 char *buf;
1744 duplicate(ip->addr,buf);
1745 buf=hash_id(ip->addr,32-idxtable_bitmask1);
1746
1747 string(chain_forward,6+strlen(buf));
1748 strcpy(chain_forward,"forw_");
1749 strcat(chain_forward,buf);
1750
1751 string(chain_postrouting,6+strlen(buf));
1752 strcpy(chain_postrouting,"post_");
1753 strcat(chain_postrouting,buf);
1754
1755 free(buf);
1756 }
1757 else
1758 {
1759 chain_forward="FORWARD";
1760 chain_postrouting="POSTROUTING";
1761 }
1762
1763 printf("%-22s %-16s %04d ", ip->name, ip->addr, ip->mark);
1764
1765 /* -------------------------------------------------------- mark download */
1766
1767 sprintf(str,"-A %s -d %s/32 -o %s -j %s%d",chain_postrouting,ip->addr,lan,mark_iptables,ip->mark);
1768 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/
1769 /* -m limit --limit 1/s */
1770 save_line(str);
1771
1772 if(qos_proxy)
1773 {
1774 sprintf(str,"-A %s -s %s -p tcp --sport %d -d %s/32 -o %s -j %s%d",chain_postrouting,proxy_ip,proxy_port,ip->addr,lan,mark_iptables,ip->mark);
1775 /*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);*/
1776 save_line(str);
1777 }
1778
1779 sprintf(str,"-A %s -d %s/32 -o %s -j ACCEPT",chain_postrouting,ip->addr,lan);
1780 save_line(str);
1781
1782 /* -------------------------------------------------------- mark upload */
1783 sprintf(str,"-A %s -s %s/32 -o %s -j %s%d",chain_forward,ip->addr,wan,mark_iptables,ip->mark);
1784 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/
1785 save_line(str);
1786
1787 sprintf(str,"-A %s -s %s/32 -o %s -j ACCEPT",chain_forward,ip->addr,wan);
1788 save_line(str);
1789
1790 if(ip->min)
1791 {
1792 /* -------------------------------------------------------- download class */
1793 printf("(down: %dk-%dk ", ip->min, ip->max);
1794
1795 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->group, ip->mark,ip->min,ip->max, burst, ip->prio);
1796 safe_run(str);
1797
1798 if (strcmpi(ip->keyword->leaf_discipline, "none"))
1799 {
1800 sprintf(str,"%s qdisc add dev %s parent 1:%d handle %d %s", tc, lan, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/
1801 safe_run(str);
1802 }
1803 if (filter_type == 1)
1804 {
1805 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc, lan, ip->mark, ip->mark);
1806 safe_run(str);
1807 }
1808
1809 /* -------------------------------------------------------- upload class */
1810 printf("up: %dk-%dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1811 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));
1812
1813 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1814 tc, wan, ip->group, ip->mark,
1815 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1816 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);
1817 safe_run(str);
1818
1819 if (strcmpi(ip->keyword->leaf_discipline, "none"))
1820 {
1821 sprintf(str,"%s qdisc add dev %s parent 1:%d handle %d %s",tc, wan, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/
1822 safe_run(str);
1823 }
1824 if (filter_type == 1)
1825 {
1826 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",tc, wan, ip->mark, ip->mark);
1827 safe_run(str);
1828 }
1829 }
1830 else
1831 printf("(sharing %s)\n", ip->sharing);
1832 i++;
1833 }
1834
1835 if(idxs)
1836 {
1837 chain_forward = "forw_common";
1838 chain_postrouting = "post_common";
1839 }
1840 else
1841 {
1842 chain_forward = "FORWARD";
1843 chain_postrouting = "POSTROUTING";
1844 }
1845 /* -------------------------------- classify or reject free download */
1846 {
1847 char *final_chain = "DROP"; /* REJECT would be better, but it is impossible in mangle */
1848 if(free_min) final_chain = "ACCEPT";
1849 if(qos_proxy)
1850 {
1851 if(free_min)
1852 {
1853 sprintf(str,"-A %s -s %s -p tcp --sport %d -o %s -j %s%d",chain_postrouting,proxy_ip,proxy_port,lan,mark_iptables,3);
1854 save_line(str);
1855 }
1856 sprintf(str,"-A %s -s %s -p tcp --sport %d -o %s -j %s",chain_postrouting,proxy_ip,proxy_port,lan,final_chain);
1857 save_line(str);
1858 }
1859 if(free_min)
1860 {
1861 sprintf(str,"-A %s -o %s -j %s%d",chain_postrouting,lan,mark_iptables,3);
1862 save_line(str);
1863 }
1864 sprintf(str,"-A %s -o %s -j %s",chain_postrouting,lan,final_chain);
1865 save_line(str);
1866 /* ------------------------------- classify or reject free upload */
1867 if(free_min)
1868 {
1869 sprintf(str,"-A %s -o %s -j %s%d",chain_forward,wan,mark_iptables,3);
1870 save_line(str);
1871 }
1872 sprintf(str,"-A %s -o %s -j %s",chain_forward,wan,final_chain);
1873 save_line(str);
1874 }
1875
1876 if(free_min) /* allocate free bandwith if it is not zero... */
1877 {
1878 /*-----------------------------------------------------------------*/
1879 puts("Generating free bandwith classes ...");
1880 /*-----------------------------------------------------------------*/
1881 sprintf(str, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1882 tc,lan,parent,free_min,free_max,burst,lowest_priority);
1883 safe_run(str);
1884 sprintf(str, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1885 tc,wan,parent,free_min,free_max,burst,lowest_priority);
1886 safe_run(str);
1887 /* tc SFQ */
1888 if (strcmpi(qos_leaf, "none"))
1889 {
1890 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc,lan,qos_leaf);
1891 safe_run(str);
1892
1893 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc,wan,qos_leaf);
1894 safe_run(str);
1895 }
1896 /* tc handle 1 fw flowid */
1897 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc,lan);
1898 safe_run(str);
1899
1900 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc,wan);
1901 safe_run(str);
1902 }
1903 printf("Total IP count: %d\n", i);
1904 run_restore();
1905 if (log_file) fclose(log_file);
1906 return 0;
1907 /* that's all folks, thank you for reading it all the way up to this point ;-) */
1908 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
1909 }
This page took 1.096089 seconds and 4 git commands to generate.