summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Kozlov <xeb@mail.ru>2011-01-05 02:07:15 +0300
committerDmitry Kozlov <xeb@mail.ru>2011-01-05 02:07:15 +0300
commit2a05ce54544185f34016b1a9e46afda9d0af980e (patch)
treec048887255771beef98defd9a2822289d575b5e7
parentcdd91cd6a6a7bd00dcf9a0ba78ea76e01ce33655 (diff)
downloadaccel-ppp-2a05ce54544185f34016b1a9e46afda9d0af980e.tar.gz
accel-ppp-2a05ce54544185f34016b1a9e46afda9d0af980e.zip
shaper_tbf: implemented time ranges
-rw-r--r--README55
-rw-r--r--accel-pptpd/extra/shaper_tbf.c464
-rw-r--r--accel-pptpd/triton/timer.c2
3 files changed, 431 insertions, 90 deletions
diff --git a/README b/README
index 17b95b1f..107e773d 100644
--- a/README
+++ b/README
@@ -61,6 +61,61 @@ Configuration
-------------
read man accel-pptp.conf
+Built-in shaper
+--------------
+accel-pptp supports tbf based shaper manager.
+To enable it uncomment shaper_tbf in [modules] section.
+It accepts radius attrbutes in various formats: rate, down-rate/up-rate and cisco-like. Values have to be in kilobits except cisco-like.
+For example:
+Filter-Id=1000 (means 1000Kbit both up-stream and down-stream rate)
+Filter-Id=2000/3000 (means 2000Kbit down-stream rate and 3000Kbit up-stream rate)
+To change radius attribute which containes rate information use 'attr' option, for example:
+[tbf]
+attr=My-Custom-Rate-Attribute
+of course this attribute have to be in radius dictionary.
+To specify different attributes for down-stream and up-stream rates use 'attr-down' and 'attr-up' options, for example:
+[tbf]
+attr-down=PPPD-Downstream-Speed
+attr-up=PPPD-Upstream-Speed
+
+If you want to use cisco-like format configure accel-pptp as following:
+[tbf]
+vendor=Cisco
+attr=Cisco-AVPair
+and send two attributes:
+Cisco-AVPair=lcp:interface-config#1=rate-limit input 2000000 8000 8000 conform-action transmit exceed-action drop (which means 2000Kbit up-stream rate and 8Kb burst)
+Cisco-AVPair=lcp:interface-config#1=rate-limit output 2000000 8000 8000 conform-action transmit exceed-action drop (which means 2000Kbit down-stream rate and 8Kb burst)
+
+Advanced shaper using
+---------------------
+1. Burst configuration.
+If you not using cisco-format then burst calculates from rate and specified burst factors.
+To specify burst factors use 'down-burst-factor' and 'up-burst-factor' options, for example:
+[tbf]
+down-burst-factor=1.0
+up-burst-factor=10.0
+which means that burst for tbf qdisc will be calculated as down-stream rate multiply to 1.0 and burst for policer will be calculated as up-stream rate multiply to 10.0.
+
+2. Time ranges.
+You can specify time ranges to authomatic rate reconfiguration.
+To specify time ranges use following sample configuration:
+[tbf]
+time-range=1,1:00-3:00
+time-range=2,3:00-5:00
+time-range=3,5:00-7:00
+first number is time range identifier.
+To specify time range specific rates use following format of radius attributes: range-id,rate, range-id,down-rate/up-rate or cisco-like, for example:
+Filter-Id=1000
+Filter-Id=1,2000
+Filter-Id=2,3000
+Filter-Id=3,4000
+which means: set 1000Kbit by default, set 2000Kbit in time range 1, set 3000Kbit in time range 2, set 4000Kbit in time range 3.
+You have to pass multiple Filter-Id attributes to utilize this functionality.
+Or cisco-like:
+Cisco-AVPair=lcp:interface-config#1=rate-limit output access-group 1 1000000 8000 8000 conform-action transmit exceed-action drop
+Cisco-AVPair=lcp:interface-config#1=rate-limit input access-group 1 1000000 8000 8000 conform-action transmit exceed-action drop
+ans so on...
+
Warning !!!
-----------
diff --git a/accel-pptpd/extra/shaper_tbf.c b/accel-pptpd/extra/shaper_tbf.c
index bed43e2f..99610dd7 100644
--- a/accel-pptpd/extra/shaper_tbf.c
+++ b/accel-pptpd/extra/shaper_tbf.c
@@ -52,21 +52,49 @@ static LIST_HEAD(shaper_list);
static double tick_in_usec = 1;
static double clock_factor = 1;
+struct time_range_pd_t;
struct shaper_pd_t
{
struct list_head entry;
struct ppp_t *ppp;
struct ppp_pd_t pd;
+ int temp_down_speed;
+ int temp_up_speed;
+ int down_speed;
+ int up_speed;
+ struct list_head tr_list;
+ struct time_range_pd_t *cur_tr;
+};
+
+struct time_range_pd_t
+{
+ struct list_head entry;
+ int id;
int down_speed;
int down_burst;
int up_speed;
int up_burst;
- int temp_down_speed;
- int temp_up_speed;
+};
+
+struct time_range_t
+{
+ struct list_head entry;
+ int id;
+ struct triton_timer_t begin;
+ struct triton_timer_t end;
};
static void *pd_key;
+static LIST_HEAD(time_range_list);
+static int time_range_id;
+
+static void shaper_ctx_close(struct triton_context_t *);
+static struct triton_context_t shaper_ctx = {
+ .close = shaper_ctx_close,
+ .before_switch = log_switch,
+};
+
static unsigned tc_time2tick(unsigned time)
{
return time*tick_in_usec;
@@ -413,6 +441,7 @@ static struct shaper_pd_t *find_pd(struct ppp_t *ppp, int create)
spd->ppp = ppp;
list_add_tail(&spd->pd.entry, &ppp->pd_list);
spd->pd.key = &pd_key;
+ INIT_LIST_HEAD(&spd->tr_list);
pthread_rwlock_wrlock(&shaper_lock);
list_add_tail(&spd->entry, &shaper_list);
@@ -511,13 +540,31 @@ out_err:
return -1;
}
-static void parse_string(const char *str, int dir, int *speed, int *burst)
+static void parse_string(const char *str, int dir, int *speed, int *burst, int *tr_id)
{
char *endptr;
long int val;
unsigned int n1, n2, n3;
- if (strstr(str, "lcp:interface-config#1=rate-limit output") == str) {
+ if (strstr(str, "lcp:interface-config#1=rate-limit output access-group") == str) {
+ if (dir == ATTR_DOWN) {
+ val = sscanf(str, "lcp:interface-config#1=rate-limit output access-group %i %u %u %u conform-action transmit exceed-action drop", tr_id, &n1, &n2, &n3);
+ if (val == 4) {
+ *speed = n1/1000;
+ *burst = n2;
+ }
+ }
+ return;
+ } else if (strstr(str, "lcp:interface-config#1=rate-limit input access-group") == str) {
+ if (dir == ATTR_UP) {
+ val = sscanf(str, "lcp:interface-config#1=rate-limit input access-group %i %u %u %u conform-action transmit exceed-action drop", tr_id, &n1, &n2, &n3);
+ if (val == 4) {
+ *speed = n1/1000;
+ *burst = n2;
+ }
+ }
+ return;
+ } else if (strstr(str, "lcp:interface-config#1=rate-limit output") == str) {
if (dir == ATTR_DOWN) {
val = sscanf(str, "lcp:interface-config#1=rate-limit output %u %u %u conform-action transmit exceed-action drop", &n1, &n2, &n3);
if (val == 3) {
@@ -526,8 +573,7 @@ static void parse_string(const char *str, int dir, int *speed, int *burst)
}
}
return;
- }
- else if (strstr(str, "lcp:interface-config#1=rate-limit input") == str) {
+ } else if (strstr(str, "lcp:interface-config#1=rate-limit input") == str) {
if (dir == ATTR_UP) {
val = sscanf(str, "lcp:interface-config#1=rate-limit input %u %u %u conform-action transmit exceed-action drop", &n1, &n2, &n3);
if (val == 3) {
@@ -539,9 +585,18 @@ static void parse_string(const char *str, int dir, int *speed, int *burst)
}
val = strtol(str, &endptr, 10);
- if (*endptr == 0)
+ if (*endptr == 0) {
*speed = val;
- else {
+ return;
+ }
+ if (*endptr == ',') {
+ *tr_id = val;
+ val = strtol(endptr + 1, &endptr, 10);
+ }
+ if (*endptr == 0) {
+ *speed = val;
+ return;
+ } else {
if (*endptr == '/' || *endptr == '\\' || *endptr == ':') {
if (dir == ATTR_DOWN)
*speed = val;
@@ -552,50 +607,111 @@ static void parse_string(const char *str, int dir, int *speed, int *burst)
}
#ifdef RADIUS
-static void parse_attr(struct rad_attr_t *attr, int dir, int *speed, int *burst)
+static void parse_attr(struct rad_attr_t *attr, int dir, int *speed, int *burst, int *tr_id)
{
if (attr->attr->type == ATTR_TYPE_STRING)
- parse_string(attr->val.string, dir, speed, burst);
+ parse_string(attr->val.string, dir, speed, burst, tr_id);
else if (attr->attr->type == ATTR_TYPE_INTEGER)
*speed = attr->val.integer;
}
-static void ev_radius_access_accept(struct ev_radius_t *ev)
+static struct time_range_pd_t *get_tr_pd(struct shaper_pd_t *pd, int id)
{
- struct rad_attr_t *attr;
- int down_speed = 0, down_burst = 0;
- int up_speed = 0, up_burst = 0;
- struct shaper_pd_t *pd = find_pd(ev->ppp, 1);
+ struct time_range_pd_t *tr_pd;
+
+ list_for_each_entry(tr_pd, &pd->tr_list, entry) {
+ if (tr_pd->id == id)
+ return tr_pd;
+ }
- if (!pd)
- return;
+ tr_pd = _malloc(sizeof(*tr_pd));
+ memset(tr_pd, 0, sizeof(*tr_pd));
+ tr_pd->id = id;
+
+ if (id == time_range_id)
+ pd->cur_tr = tr_pd;
+
+ list_add_tail(&tr_pd->entry, &pd->tr_list);
+
+ return tr_pd;
+}
+
+static void clear_tr_pd(struct shaper_pd_t *pd)
+{
+ struct time_range_pd_t *tr_pd;
- list_for_each_entry(attr, &ev->reply->attrs, entry) {
+ while (!list_empty(&pd->tr_list)) {
+ tr_pd = list_entry(pd->tr_list.next, typeof(*tr_pd), entry);
+ list_del(&tr_pd->entry);
+ _free(tr_pd);
+ }
+}
+
+static void check_radius_attrs(struct shaper_pd_t *pd, struct rad_packet_t *pack)
+{
+ struct rad_attr_t *attr;
+ int down_speed, down_burst;
+ int up_speed, up_burst;
+ int tr_id;
+ struct time_range_pd_t *tr_pd;
+
+ list_for_each_entry(attr, &pack->attrs, entry) {
if (attr->vendor && attr->vendor->id != conf_vendor)
continue;
if (!attr->vendor && conf_vendor)
continue;
+ if (attr->attr->id != conf_attr_down && attr->attr->id != conf_attr_up)
+ continue;
+ tr_id = 0;
+ down_speed = 0;
+ down_burst = 0;
+ up_speed = 0;
+ up_burst = 0;
if (attr->attr->id == conf_attr_down)
- parse_attr(attr, ATTR_DOWN, &down_speed, &down_burst);
+ parse_attr(attr, ATTR_DOWN, &down_speed, &down_burst, &tr_id);
if (attr->attr->id == conf_attr_up)
- parse_attr(attr, ATTR_UP, &up_speed, &up_burst);
+ parse_attr(attr, ATTR_UP, &up_speed, &up_burst, &tr_id);
+ tr_pd = get_tr_pd(pd, tr_id);
+ if (down_speed)
+ tr_pd->down_speed = down_speed;
+ if (down_burst)
+ tr_pd->down_burst = down_burst;
+ if (up_speed)
+ tr_pd->up_speed = up_speed;
+ if (up_burst)
+ tr_pd->up_burst = up_burst;
}
+}
- pd->down_speed = down_speed;
- pd->down_burst = down_burst;
- pd->up_speed = up_speed;
- pd->up_burst = up_burst;
+static void ev_radius_access_accept(struct ev_radius_t *ev)
+{
+ int down_speed, down_burst;
+ int up_speed, up_burst;
+ struct shaper_pd_t *pd = find_pd(ev->ppp, 1);
- if (temp_down_speed) {
+ if (!pd)
+ return;
+
+ check_radius_attrs(pd, ev->reply);
+
+ if (temp_down_speed || temp_up_speed) {
pd->temp_down_speed = temp_down_speed;
pd->temp_up_speed = temp_up_speed;
+ pd->down_speed = temp_down_speed;
+ pd->up_speed = temp_up_speed;
down_speed = temp_down_speed;
- down_burst = 0;
- }
-
- if (temp_up_speed) {
up_speed = temp_up_speed;
+ down_burst = 0;
up_burst = 0;
+ } else {
+ if (!pd->cur_tr)
+ return;
+ pd->down_speed = pd->cur_tr->down_speed;
+ pd->up_speed = pd->cur_tr->up_speed;
+ down_speed = pd->cur_tr->down_speed;
+ up_speed = pd->cur_tr->up_speed;
+ down_burst = pd->cur_tr->down_burst;
+ up_burst = pd->cur_tr->up_speed;
}
if (down_speed > 0 && up_speed > 0) {
@@ -608,48 +724,46 @@ static void ev_radius_access_accept(struct ev_radius_t *ev)
static void ev_radius_coa(struct ev_radius_t *ev)
{
- struct rad_attr_t *attr;
- int down_speed = 0, down_burst = 0;
- int up_speed = 0, up_burst = 0;
- struct shaper_pd_t *pd = find_pd(ev->ppp, 1);
+ struct shaper_pd_t *pd = find_pd(ev->ppp, 0);
if (!pd) {
ev->res = -1;
return;
}
-
- list_for_each_entry(attr, &ev->request->attrs, entry) {
- if (attr->vendor && attr->vendor->id != conf_vendor)
- continue;
- if (!attr->vendor && conf_vendor)
- continue;
- if (attr->attr->id == conf_attr_down)
- parse_attr(attr, ATTR_DOWN, &down_speed, &down_burst);
- if (attr->attr->id == conf_attr_up)
- parse_attr(attr, ATTR_UP, &up_speed, &up_burst);
- }
- if (pd->down_speed != down_speed || pd->up_speed != up_speed || pd->down_burst != down_burst || pd->up_burst != up_burst) {
- pd->down_speed = down_speed;
- pd->down_burst = down_burst;
- pd->up_speed = up_speed;
- pd->up_burst = up_burst;
+ clear_tr_pd(pd);
+ check_radius_attrs(pd, ev->request);
+
+ if (pd->temp_down_speed || pd->temp_up_speed)
+ return;
+
+ if (!pd->cur_tr) {
+ if (pd->down_speed || pd->up_speed) {
+ pd->down_speed = 0;
+ pd->up_speed = 0;
+ if (conf_verbose)
+ log_ppp_info2("tbf: removed shaper\n");
+ remove_shaper(ev->ppp->ifname);
+ }
+ return;
+ }
- if (temp_down_speed || temp_up_speed)
- return;
+ if (pd->down_speed != pd->cur_tr->down_speed || pd->up_speed != pd->cur_tr->up_speed) {
+ pd->down_speed = pd->cur_tr->down_speed;
+ pd->up_speed = pd->cur_tr->up_speed;
if (remove_shaper(ev->ppp->ifname)) {
ev->res = -1;
return;
}
- if (down_speed > 0 || up_speed > 0) {
- if (install_shaper(ev->ppp->ifname, down_speed, down_burst, up_speed, up_burst)) {
+ if (pd->down_speed > 0 || pd->up_speed > 0) {
+ if (install_shaper(ev->ppp->ifname, pd->cur_tr->down_speed, pd->cur_tr->down_burst, pd->cur_tr->up_speed, pd->cur_tr->up_burst)) {
ev->res= -1;
return;
} else {
if (conf_verbose)
- log_ppp_info2("tbf: changed shaper %i/%i (Kbit)\n", down_speed, up_speed);
+ log_ppp_info2("tbf: changed shaper %i/%i (Kbit)\n", pd->down_speed, pd->up_speed);
}
} else {
if (conf_verbose)
@@ -664,12 +778,13 @@ static void ev_shaper(struct ev_shaper_t *ev)
struct shaper_pd_t *pd = find_pd(ev->ppp, 1);
int down_speed = 0, down_burst = 0;
int up_speed = 0, up_burst = 0;
+ int tr_id;
if (!pd)
return;
- parse_string(ev->val, ATTR_DOWN, &down_speed, &down_burst);
- parse_string(ev->val, ATTR_UP, &up_speed, &up_burst);
+ parse_string(ev->val, ATTR_DOWN, &down_speed, &down_burst, &tr_id);
+ parse_string(ev->val, ATTR_UP, &up_speed, &up_burst, &tr_id);
if (down_speed > 0 && up_speed > 0) {
pd->down_speed = down_speed;
@@ -686,6 +801,7 @@ static void ev_ctrl_finished(struct ppp_t *ppp)
struct shaper_pd_t *pd = find_pd(ppp, 0);
if (pd) {
+ clear_tr_pd(pd);
pthread_rwlock_wrlock(&shaper_lock);
list_del(&pd->entry);
pthread_rwlock_unlock(&shaper_lock);
@@ -708,7 +824,7 @@ static void shaper_change(struct shaper_pd_t *pd)
if (pd->temp_down_speed && pd->temp_up_speed)
install_shaper(pd->ppp->ifname, pd->temp_down_speed, 0, pd->temp_up_speed, 0);
else if (pd->down_speed && pd->up_speed)
- install_shaper(pd->ppp->ifname, pd->down_speed, pd->down_burst, pd->up_speed, pd->up_burst);
+ install_shaper(pd->ppp->ifname, pd->cur_tr->down_speed, pd->cur_tr->down_burst, pd->cur_tr->up_speed, pd->cur_tr->up_burst);
}
static int shaper_change_exec(const char *cmd, char * const *f, int f_cnt, void *cli)
@@ -716,12 +832,13 @@ static int shaper_change_exec(const char *cmd, char * const *f, int f_cnt, void
struct shaper_pd_t *pd;
int down_speed = 0, up_speed = 0, down_burst = 0, up_burst = 0;
int all = 0, temp = 0, found = 0;
+ int tr_id;
if (f_cnt < 4)
return CLI_CMD_SYNTAX;
- parse_string(f[3], ATTR_DOWN, &down_speed, &down_burst);
- parse_string(f[3], ATTR_UP, &up_speed, &up_burst);
+ parse_string(f[3], ATTR_DOWN, &down_speed, &down_burst, &tr_id);
+ parse_string(f[3], ATTR_UP, &up_speed, &up_burst, &tr_id);
if (down_speed == 0 || up_speed == 0)
return CLI_CMD_INVAL;
@@ -750,10 +867,12 @@ static int shaper_change_exec(const char *cmd, char * const *f, int f_cnt, void
} else {
pd->temp_down_speed = 0;
pd->temp_up_speed = 0;
- pd->down_speed = down_speed;
- pd->down_burst = down_burst;
- pd->up_speed = up_speed;
- pd->up_burst = up_burst;
+ if (!pd->cur_tr)
+ pd->cur_tr = get_tr_pd(pd, 0);
+ pd->cur_tr->down_speed = down_speed;
+ pd->cur_tr->down_burst = down_burst;
+ pd->cur_tr->up_speed = up_speed;
+ pd->cur_tr->up_burst = up_burst;
}
triton_context_call(pd->ppp->ctrl->ctx, (triton_event_func)shaper_change, pd);
if (!all) {
@@ -780,8 +899,8 @@ static void shaper_restore(struct shaper_pd_t *pd)
{
remove_shaper(pd->ppp->ifname);
- if (pd->down_speed && pd->up_speed)
- install_shaper(pd->ppp->ifname, pd->down_speed, pd->down_burst, pd->up_speed, pd->up_burst);
+ if (pd->cur_tr)
+ install_shaper(pd->ppp->ifname, pd->cur_tr->down_speed, pd->cur_tr->down_burst, pd->cur_tr->up_speed, pd->cur_tr->up_burst);
}
static int shaper_restore_exec(const char *cmd, char * const *f, int f_cnt, void *cli)
@@ -833,39 +952,166 @@ static void print_rate(const struct ppp_t *ppp, char *buf)
*buf = 0;
}
-static int clock_init(void)
+static void shaper_ctx_close(struct triton_context_t *ctx)
{
- FILE *fp;
- uint32_t clock_res;
- uint32_t t2us;
- uint32_t us2t;
+ struct time_range_t *r;
+
+ while (!list_empty(&time_range_list)) {
+ r = list_entry(time_range_list.next, typeof(*r), entry);
+ list_del(&r->entry);
+ if (r->begin.tpd)
+ triton_timer_del(&r->begin);
+ if (r->end.tpd)
+ triton_timer_del(&r->end);
+ _free(r);
+ }
- fp = fopen("/proc/net/psched", "r");
+ triton_context_unregister(ctx);
+}
- if (!fp) {
- log_emerg("tbf: failed to open /proc/net/psched: %s\n", strerror(errno));
- return -1;
+static void update_shaper_tr(struct shaper_pd_t *pd)
+{
+ struct time_range_pd_t *tr;
+
+ list_for_each_entry(tr, &pd->tr_list, entry) {
+ if (tr->id != time_range_id)
+ continue;
+ pd->cur_tr = tr;
+ break;
}
- if (fscanf(fp, "%08x%08x%08x", &t2us, &us2t, &clock_res) != 3) {
- log_emerg("tbf: failed to parse /proc/net/psched\n");
- fclose(fp);
- return -1;
+ if (pd->temp_down_speed || pd->temp_up_speed)
+ return;
+
+ if (pd->down_speed || pd->up_speed) {
+ if (pd->cur_tr && pd->down_speed == pd->cur_tr->down_speed && pd->up_speed == pd->cur_tr->up_speed)
+ return;
+ remove_shaper(pd->ppp->ifname);
}
+
+ if (pd->cur_tr && (pd->cur_tr->down_speed || pd->cur_tr->up_speed)) {
+ pd->down_speed = pd->cur_tr->down_speed;
+ pd->up_speed = pd->cur_tr->up_speed;
+ if (!install_shaper(pd->ppp->ifname, pd->cur_tr->down_speed, pd->cur_tr->down_burst, pd->cur_tr->up_speed, pd->cur_tr->up_burst)) {
+ if (conf_verbose)
+ log_ppp_info2("tbf: changed shaper %i/%i (Kbit)\n", pd->cur_tr->down_speed, pd->cur_tr->up_speed);
+ }
+ } else
+ if (conf_verbose)
+ log_ppp_info2("tbf: removed shaper\n");
+
+}
- fclose(fp);
+static void time_range_begin_timer(struct triton_timer_t *t)
+{
+ struct time_range_t *tr = container_of(t, typeof(*tr), begin);
+ struct shaper_pd_t *pd;
- /* compatibility hack: for old iproute binaries (ignoring
- * the kernel clock resolution) the kernel advertises a
- * tick multiplier of 1000 in case of nano-second resolution,
- * which really is 1. */
- if (clock_res == 1000000000)
- t2us = us2t;
+ time_range_id = tr->id;
- clock_factor = (double)clock_res / TIME_UNITS_PER_SEC;
- tick_in_usec = (double)t2us / us2t * clock_factor;
+ log_debug("tbf: time_range_begin_timer: id=%i\n", time_range_id);
- return 0;
+ pthread_rwlock_rdlock(&shaper_lock);
+ list_for_each_entry(pd, &shaper_list, entry)
+ triton_context_call(pd->ppp->ctrl->ctx, (triton_event_func)update_shaper_tr, pd);
+ pthread_rwlock_unlock(&shaper_lock);
+}
+
+static void time_range_end_timer(struct triton_timer_t *t)
+{
+ struct shaper_pd_t *pd;
+
+ time_range_id = 0;
+
+ log_debug("tbf: time_range_end_timer\n");
+
+ pthread_rwlock_rdlock(&shaper_lock);
+ list_for_each_entry(pd, &shaper_list, entry)
+ triton_context_call(pd->ppp->ctrl->ctx, (triton_event_func)update_shaper_tr, pd);
+ pthread_rwlock_unlock(&shaper_lock);
+}
+
+static struct time_range_t *parse_range(const char *val)
+{
+ char *endptr;
+ int id;
+ time_t t;
+ struct tm begin_tm, end_tm;
+ struct time_range_t *r;
+
+ id = strtol(val, &endptr, 10);
+ if (*endptr != ',')
+ return NULL;
+ if (id <= 0)
+ return NULL;
+
+ time(&t);
+ localtime_r(&t, &begin_tm);
+ begin_tm.tm_sec = 1;
+ end_tm = begin_tm;
+ end_tm.tm_sec = 0;
+
+ endptr = strptime(endptr + 1, "%H:%M", &begin_tm);
+ if (*endptr != '-')
+ return NULL;
+
+ endptr = strptime(endptr + 1, "%H:%M", &end_tm);
+ if (*endptr)
+ return NULL;
+
+ r = _malloc(sizeof(*r));
+ memset(r, 0, sizeof(*r));
+
+ r->id = id;
+ r->begin.expire_tv.tv_sec = mktime(&begin_tm);
+ r->begin.period = 24 * 60 * 60 * 1000;
+ r->begin.expire = time_range_begin_timer;
+ r->end.expire_tv.tv_sec = mktime(&end_tm);
+ r->end.period = 24 * 60 * 60 * 1000;
+ r->end.expire = time_range_end_timer;
+
+ return r;
+}
+
+static void load_time_ranges(void)
+{
+ struct conf_sect_t *s = conf_get_section("tbf");
+ struct conf_option_t *opt;
+ struct time_range_t *r;
+ time_t ts;
+
+ if (!s)
+ return;
+
+ time(&ts);
+
+ while (!list_empty(&time_range_list)) {
+ r = list_entry(time_range_list.next, typeof(*r), entry);
+ list_del(&r->entry);
+ if (r->begin.tpd)
+ triton_timer_del(&r->begin);
+ if (r->end.tpd)
+ triton_timer_del(&r->end);
+ _free(r);
+ }
+
+ list_for_each_entry(opt, &s->items, entry) {
+ if (strcmp(opt->name, "time-range"))
+ continue;
+ r = parse_range(opt->val);
+ if (r) {
+ list_add_tail(&r->entry, &time_range_list);
+ if (ts >= r->begin.expire_tv.tv_sec && ts <= r->end.expire_tv.tv_sec)
+ time_range_begin_timer(&r->begin);
+ if (r->begin.expire_tv.tv_sec < ts)
+ r->begin.expire_tv.tv_sec += 24 * 60 * 60;
+ if (r->end.expire_tv.tv_sec < ts)
+ r->end.expire_tv.tv_sec += 24 * 60 * 60;
+ triton_timer_add(&shaper_ctx, &r->begin, 1);
+ triton_timer_add(&shaper_ctx, &r->end, 1);
+ } else
+ log_emerg("tbf: failed to parse time-range '%s'\n", opt->val);
+ }
}
#ifdef RADIUS
@@ -905,7 +1151,7 @@ static int parse_vendor_opt(const char *opt)
}
#endif
-void load_config(void)
+static void load_config(void)
{
const char *opt;
@@ -959,6 +1205,43 @@ void load_config(void)
opt = conf_get_opt("tbf", "verbose");
if (opt && atoi(opt) > 0)
conf_verbose = 1;
+
+ triton_context_call(&shaper_ctx, (triton_event_func)load_time_ranges, NULL);
+}
+
+static int clock_init(void)
+{
+ FILE *fp;
+ uint32_t clock_res;
+ uint32_t t2us;
+ uint32_t us2t;
+
+ fp = fopen("/proc/net/psched", "r");
+
+ if (!fp) {
+ log_emerg("tbf: failed to open /proc/net/psched: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (fscanf(fp, "%08x%08x%08x", &t2us, &us2t, &clock_res) != 3) {
+ log_emerg("tbf: failed to parse /proc/net/psched\n");
+ fclose(fp);
+ return -1;
+ }
+
+ fclose(fp);
+
+ /* compatibility hack: for old iproute binaries (ignoring
+ * the kernel clock resolution) the kernel advertises a
+ * tick multiplier of 1000 in case of nano-second resolution,
+ * which really is 1. */
+ if (clock_res == 1000000000)
+ t2us = us2t;
+
+ clock_factor = (double)clock_res / TIME_UNITS_PER_SEC;
+ tick_in_usec = (double)t2us / us2t * clock_factor;
+
+ return 0;
}
static void __init init(void)
@@ -966,6 +1249,9 @@ static void __init init(void)
if (clock_init())
return;
+ triton_context_register(&shaper_ctx, NULL);
+ triton_context_wakeup(&shaper_ctx);
+
load_config();
#ifdef RADIUS
diff --git a/accel-pptpd/triton/timer.c b/accel-pptpd/triton/timer.c
index fbb3c57d..e419e938 100644
--- a/accel-pptpd/triton/timer.c
+++ b/accel-pptpd/triton/timer.c
@@ -135,7 +135,7 @@ int __export triton_timer_add(struct triton_context_t *ctx, struct triton_timer_
t->ctx = (struct _triton_context_t *)ctx->tpd;
else
t->ctx = (struct _triton_context_t *)default_ctx.tpd;
- t->fd = timerfd_create(CLOCK_MONOTONIC, 0);
+ t->fd = timerfd_create(abs_time ? CLOCK_REALTIME : CLOCK_MONOTONIC, 0);
if (t->fd < 0) {
triton_log_error("timer:timerfd_create: %s", strerror(errno));
mempool_free(t);