📄 tc_cbq.c
字号:
/* * tc_cbq.c * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * */#include <stddef.h>#include <sys/types.h>#include <linux/types.h>#include "rsvp_daemon.h"#include "rapi_lib.h" /* Define flowspec formats */#include "rsvp_specs.h" /* Flowspec descriptor format */#include "rsvp_TCif.h" /* Adaptation interface */extern double pow(double x, double y);extern double exp(double x);#include "libnetlink.h"#include "tc_linux.h"struct cbq_class{ struct cbq_class *next; Chandle classid; Chandle parent; struct tc_cbq_lssopt lss; struct tc_cbq_wrropt wrr; struct tc_ratespec rate;};struct cbq_qdisc{ rsvp_qdisc_t *qi; struct cbq_class lll; struct cbq_class is_g; struct cbq_class *is_cl;};unsigned tc_cbq_calc_maxidle(unsigned bndw, unsigned rate, unsigned avpkt, int ewma_log, unsigned maxburst){ double maxidle; double g = 1.0 - 1.0/(1<<ewma_log); double xmt = (double)avpkt/bndw; maxidle = xmt*(1-g); if (bndw != rate && maxburst) { double vxmt = (double)avpkt/rate - xmt; vxmt *= (pow(g, -(double)maxburst) - 1); if (vxmt > maxidle) maxidle = vxmt; } return tc_core_usec2tick(maxidle*(1<<ewma_log)*1000000);}unsigned tc_cbq_calc_offtime(unsigned bndw, unsigned rate, unsigned avpkt, int ewma_log, unsigned minburst){ double g = 1.0 - 1.0/(1<<ewma_log); double offtime = (double)avpkt/rate - (double)avpkt/bndw; if (minburst == 0) return 0; if (minburst == 1) offtime *= pow(g, -(double)minburst) - 1; else offtime *= 1 + (pow(g, -(double)(minburst-1)) - 1)/(1-g); return tc_core_usec2tick(offtime*1000000);}static intstore_classinfo(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg){ struct tcmsg *t = NLMSG_DATA(n); struct rtattr *tb[TCA_MAX+1]; struct rtattr *rta[TCA_CBQ_MAX+1]; rsvp_qdisc_t *qi = arg; struct cbq_qdisc *cbq = qi->data; struct cbq_class *cl = NULL; if (n->nlmsg_type != RTM_NEWTCLASS) return 0; if (n->nlmsg_len < NLMSG_LENGTH(sizeof(t))) return -1; if (qi->link->ifl_index != t->tcm_ifindex) return 0; if (TC_H_MAJ(t->tcm_parent^qi->handle) && t->tcm_parent != TC_H_ROOT) return 0; if (t->tcm_handle == TC_H_MAKE(qi->handle, 0)) { cl = &cbq->lll; } else if (t->tcm_handle == TC_H_MAKE(qi->handle, 0x7FFE)) { cl = &cbq->is_g; } parse_rtattr(tb, TCA_MAX, TCA_RTA(t), TCA_PAYLOAD(n)); if (tb[TCA_OPTIONS]) parse_rtattr(rta, TCA_CBQ_MAX, RTA_DATA(tb[TCA_OPTIONS]), RTA_PAYLOAD(tb[TCA_OPTIONS])); if (rta[TCA_CBQ_LSSOPT] == NULL || rta[TCA_CBQ_WRROPT] == NULL || rta[TCA_CBQ_RATE] == NULL) return 0; if (cl == NULL) { if ((cl = malloc(sizeof(*cl))) == NULL) return -1; memset(cl, 0, sizeof(*cl)); } cl->classid = t->tcm_handle; cl->parent = t->tcm_parent; memcpy(&cl->lss, RTA_DATA(rta[TCA_CBQ_LSSOPT]), sizeof(cl->lss)); memcpy(&cl->wrr, RTA_DATA(rta[TCA_CBQ_WRROPT]), sizeof(cl->wrr)); memcpy(&cl->rate, RTA_DATA(rta[TCA_CBQ_RATE]), sizeof(cl->rate)); if (cl != &cbq->lll && cl != &cbq->is_g) { if (cl->wrr.priority != 1) { free(cl); return 0; } cl->next = cbq->lll.next; cbq->lll.next = cl; } return 0;}static int cbq_alloc(rsvp_qdisc_t *qi, struct tcmsg *tcm, struct rtattr **rta){ struct rtattr *tb[TCA_CBQ_MAX+1]; struct cbq_qdisc *cbq; if (rta[TCA_OPTIONS] == NULL) return -1; cbq = malloc(sizeof(*cbq)); if (cbq == NULL) return -1; memset(cbq, 0, sizeof(struct cbq_qdisc)); cbq->qi = qi; qi->data = cbq; parse_rtattr(tb, TCA_CBQ_MAX, RTA_DATA(rta[TCA_OPTIONS]), RTA_PAYLOAD(rta[TCA_OPTIONS])); cbq->lll.classid = tcm->tcm_handle; if (tb[TCA_CBQ_LSSOPT]) memcpy(&cbq->lll.lss, RTA_DATA(tb[TCA_CBQ_LSSOPT]), sizeof(cbq->lll.lss)); if (tb[TCA_CBQ_WRROPT]) memcpy(&cbq->lll.wrr, RTA_DATA(tb[TCA_CBQ_WRROPT]), sizeof(cbq->lll.wrr)); if (tb[TCA_CBQ_RATE]) memcpy(&cbq->lll.rate, RTA_DATA(tb[TCA_CBQ_RATE]), sizeof(cbq->lll.rate)); return 0;}static void cbq_free(rsvp_qdisc_t *qi){ struct cbq_qdisc *cbq = qi->data; struct cbq_class *cl; qi->data = NULL; while ((cl = cbq->lll.next) != NULL) { cbq->lll.next = cl->next; free(cl); } free(cbq);}static void cbq_free_class(rsvp_qdisc_t *qi, struct cbq_class *cl){ struct cbq_qdisc *cbq = qi->data; struct cbq_class **clp; for (clp = &cbq->lll.next; *clp; clp = &(*clp)->next) { if (cl == *clp) { *clp = cl->next; free(cl); return; } }}static void cbq_kill_classes(rsvp_qdisc_t *qi){ int level; struct cbq_qdisc *cbq = qi->data; struct cbq_class *cl, **clp; for (level = 0; level <= TC_CBQ_MAXLEVEL; level++) { clp = &cbq->lll.next; while ((cl = *clp) != NULL) { if (cl->lss.level <= level && tc_kill_class(qi->link->ifl_index, cl->classid) == 0) { *clp = cl->next; free(cl); continue; } clp = &cl->next; } }}static void cbq_clear(rsvp_qdisc_t *qi){ struct cbq_qdisc *cbq = qi->data; if (cbq->lll.classid) tc_kill_filters(qi, cbq->lll.classid); cbq_kill_classes(qi);}static int cbq_start(rsvp_qdisc_t *qi){ struct cbq_qdisc *cbq = qi->data; struct cbq_class *cl; if (cbq->lll.rate.rate == 0) { log(LOG_ERR, 0, "CBQ@%s: no all-link class\n", qi->link->ifl_name); return -1; } if (cbq->is_g.rate.rate == 0) { log(LOG_ERR, 0, "CBQ@%s: no reserved class\n", qi->link->ifl_name); return -1; } qi->link->ifl_path_bw = cbq->lll.rate.rate; tc_init_filters(qi, cbq->lll.classid); /* These parameters must be settable via config file! */ qi->ai.epsilon = 1e-6; qi->ai.g_max = 15; qi->ai.cl_max = 256; qi->ai.mem_max = 1024*1024; qi->ai.interval = 1; qi->ai.time_const = 8; qi->laddend = 0; qi->lmtu = cbq->lll.wrr.allot; qi->wfactor = (float)cbq->is_g.rate.rate/cbq->is_g.wrr.weight; qi->llhead = qi->lmtu - qi->link->ifl_path_mtu; /* Account for ping-pong buffers. Dmaing cards need TX queue len-1 instead of 1 (f.e. 15 for tulip) */ qi->lmaxlatency = (double)qi->lmtu/cbq->lll.rate.rate; if (qi->link->ifl_min_latency == 0) qi->link->ifl_min_latency = 1000000*(double)cbq->lll.rate.mpu/cbq->lll.rate.rate; /* Calculate some values */ qi->ai.ewma_const = exp(-(float)qi->ai.interval/qi->ai.time_const); qi->ai.bw_max = cbq->is_g.rate.rate; qi->D = qi->lmaxlatency + 2*(double)qi->lmtu*qi->ai.g_max/cbq->lll.rate.rate; qi->C = (double)qi->lmtu*cbq->is_g.rate.rate/cbq->lll.rate.rate; for (cl = cbq->lll.next; cl; cl = cl->next) { qi->ai.g_max--; qi->ai.bw_max -= cl->rate.rate; log(LOG_ERR, 0, "CBQ@%s: stale class %08x eated %dbps\n", qi->link->ifl_name, cl->classid, cl->rate.rate); } if (qi->ai.g_max <= 0 || qi->ai.bw_max <= 0) { log(LOG_ERR, 0, "CBQ@%s: no capacities for reservations.\n", qi->link->ifl_name); return -1; } /* OK. Machine is ready to fly! */ return 0;}static int cbq_init(rsvp_qdisc_t *qi){ struct tcmsg t; memset(&t, 0, sizeof(t)); t.tcm_parent = qi->handle; t.tcm_ifindex = qi->link->ifl_index; if (rtnl_dump_request(&tc_nl, RTM_GETTCLASS, &t, sizeof(t)) < 0) { log(LOG_ERR, errno, "cannot send dump request"); return -1; } if (rtnl_dump_filter(&tc_nl, store_classinfo, qi) < 0) { log(LOG_ERR, errno, "dump terminated\n"); cbq_clear(qi); return -1; } /* Clear old CBQ state */ cbq_clear(qi); /* Start CBQ */ if (cbq_start(qi)) { cbq_clear(qi); return -1; } return 0;}int cbq_sync_cl(rsvp_qdisc_t *qi){ struct cbq_qdisc *cbq = qi->data; struct cbq_class *cl = cbq->is_cl; struct tc_estimator est; struct tc_cbq_police pol; __u32 rtab[256]; char buf[4096]; struct rtattr *rta = (void*)buf; if (qi->ai.cl_num == 0) { qi->ai.cl_cur_rate = qi->ai.cl_rate; if (cl == NULL) return 0; log(LOG_DEBUG, 0, "kill class %08x\n", cl->classid); if (tc_kill_class(qi->link->ifl_index, cl->classid) == 0) { cbq->is_cl = NULL; cbq_free_class(qi, cl); return 0; } log(LOG_ERR, 0, "kill class %08x: not deleted\n", cl->classid);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -