summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortruckman <truckman@FreeBSD.org>2017-05-25 17:22:13 +0000
committerLuiz Souza <luiz@netgate.com>2017-07-15 11:23:59 -0500
commitee69a0676ef262c886f221f160b183eb0a74a0b2 (patch)
tree091d1fe2e54f846ecd8eb3816052dfacbeb3f673
parent01facd89e40b6782676548c86b5e08b1d829a24c (diff)
downloadFreeBSD-src-ee69a0676ef262c886f221f160b183eb0a74a0b2.zip
FreeBSD-src-ee69a0676ef262c886f221f160b183eb0a74a0b2.tar.gz
MFC r318511
The result of right shifting a negative signed value is implementation defined. On machines without arithmetic shift instructions, zero bits may be shifted in from the left, giving a large positive result instead of the desired divide-by power-of-2. Fix this by operating on the absolute value and compensating for the possible negation later. Reverse the order of the underflow/overflow tests and the exponential decay calculation to avoid the possibility of an erroneous overflow detection if p is a sufficiently small non-negative value. Also check for negative values of prob before doing the exponential decay to avoid another instance of of right shifting a negative value. Tested by: Rasool Al-Saadi <ralsaadi@swin.edu.au> (cherry picked from commit 61ad262512e302f69f713f8f13a6fff42dd917c7)
-rw-r--r--sys/netpfil/ipfw/dn_aqm_pie.c59
-rw-r--r--sys/netpfil/ipfw/dn_sched_fq_pie.c59
2 files changed, 76 insertions, 42 deletions
diff --git a/sys/netpfil/ipfw/dn_aqm_pie.c b/sys/netpfil/ipfw/dn_aqm_pie.c
index 85062e2..8259d08 100644
--- a/sys/netpfil/ipfw/dn_aqm_pie.c
+++ b/sys/netpfil/ipfw/dn_aqm_pie.c
@@ -206,6 +206,7 @@ calculate_drop_prob(void *x)
int64_t p, prob, oldprob;
struct dn_aqm_pie_parms *pprms;
struct pie_status *pst = (struct pie_status *) x;
+ int p_isneg;
pprms = pst->parms;
prob = pst->drop_prob;
@@ -221,6 +222,12 @@ calculate_drop_prob(void *x)
((int64_t)pst->current_qdelay - (int64_t)pprms->qdelay_ref);
p +=(int64_t) pprms->beta *
((int64_t)pst->current_qdelay - (int64_t)pst->qdelay_old);
+
+ /* take absolute value so right shift result is well defined */
+ p_isneg = p < 0;
+ if (p_isneg) {
+ p = -p;
+ }
/* We PIE_MAX_PROB shift by 12-bits to increase the division precision */
p *= (PIE_MAX_PROB << 12) / AQM_TIME_1S;
@@ -243,37 +250,47 @@ calculate_drop_prob(void *x)
oldprob = prob;
- /* Cap Drop adjustment */
- if ((pprms->flags & PIE_CAPDROP_ENABLED) && prob >= PIE_MAX_PROB / 10
- && p > PIE_MAX_PROB / 50 )
- p = PIE_MAX_PROB / 50;
+ if (p_isneg) {
+ prob = prob - p;
- prob = prob + p;
-
- /* decay the drop probability exponentially */
- if (pst->current_qdelay == 0 && pst->qdelay_old == 0)
- /* 0.98 ~= 1- 1/64 */
- prob = prob - (prob >> 6);
+ /* check for multiplication underflow */
+ if (prob > oldprob) {
+ prob= 0;
+ D("underflow");
+ }
+ } else {
+ /* Cap Drop adjustment */
+ if ((pprms->flags & PIE_CAPDROP_ENABLED) &&
+ prob >= PIE_MAX_PROB / 10 &&
+ p > PIE_MAX_PROB / 50 ) {
+ p = PIE_MAX_PROB / 50;
+ }
+ prob = prob + p;
- /* check for multiplication overflow/underflow */
- if (p>0) {
+ /* check for multiplication overflow */
if (prob<oldprob) {
D("overflow");
prob= PIE_MAX_PROB;
}
}
- else
- if (prob>oldprob) {
- prob= 0;
- D("underflow");
- }
- /* make drop probability between 0 and PIE_MAX_PROB*/
- if (prob < 0)
+ /*
+ * decay the drop probability exponentially
+ * and restrict it to range 0 to PIE_MAX_PROB
+ */
+ if (prob < 0) {
prob = 0;
- else if (prob > PIE_MAX_PROB)
- prob = PIE_MAX_PROB;
+ } else {
+ if (pst->current_qdelay == 0 && pst->qdelay_old == 0) {
+ /* 0.98 ~= 1- 1/64 */
+ prob = prob - (prob >> 6);
+ }
+
+ if (prob > PIE_MAX_PROB) {
+ prob = PIE_MAX_PROB;
+ }
+ }
pst->drop_prob = prob;
diff --git a/sys/netpfil/ipfw/dn_sched_fq_pie.c b/sys/netpfil/ipfw/dn_sched_fq_pie.c
index bfcd6c5..2ba16ab 100644
--- a/sys/netpfil/ipfw/dn_sched_fq_pie.c
+++ b/sys/netpfil/ipfw/dn_sched_fq_pie.c
@@ -377,6 +377,7 @@ fq_calculate_drop_prob(void *x)
struct dn_aqm_pie_parms *pprms;
int64_t p, prob, oldprob;
aqm_time_t now;
+ int p_isneg;
now = AQM_UNOW;
pprms = pst->parms;
@@ -393,6 +394,12 @@ fq_calculate_drop_prob(void *x)
((int64_t)pst->current_qdelay - (int64_t)pprms->qdelay_ref);
p +=(int64_t) pprms->beta *
((int64_t)pst->current_qdelay - (int64_t)pst->qdelay_old);
+
+ /* take absolute value so right shift result is well defined */
+ p_isneg = p < 0;
+ if (p_isneg) {
+ p = -p;
+ }
/* We PIE_MAX_PROB shift by 12-bits to increase the division precision */
p *= (PIE_MAX_PROB << 12) / AQM_TIME_1S;
@@ -415,37 +422,47 @@ fq_calculate_drop_prob(void *x)
oldprob = prob;
- /* Cap Drop adjustment */
- if ((pprms->flags & PIE_CAPDROP_ENABLED) && prob >= PIE_MAX_PROB / 10
- && p > PIE_MAX_PROB / 50 )
- p = PIE_MAX_PROB / 50;
+ if (p_isneg) {
+ prob = prob - p;
- prob = prob + p;
-
- /* decay the drop probability exponentially */
- if (pst->current_qdelay == 0 && pst->qdelay_old == 0)
- /* 0.98 ~= 1- 1/64 */
- prob = prob - (prob >> 6);
+ /* check for multiplication underflow */
+ if (prob > oldprob) {
+ prob= 0;
+ D("underflow");
+ }
+ } else {
+ /* Cap Drop adjustment */
+ if ((pprms->flags & PIE_CAPDROP_ENABLED) &&
+ prob >= PIE_MAX_PROB / 10 &&
+ p > PIE_MAX_PROB / 50 ) {
+ p = PIE_MAX_PROB / 50;
+ }
+ prob = prob + p;
- /* check for multiplication over/under flow */
- if (p>0) {
+ /* check for multiplication overflow */
if (prob<oldprob) {
D("overflow");
prob= PIE_MAX_PROB;
}
}
- else
- if (prob>oldprob) {
- prob= 0;
- D("underflow");
- }
- /* make drop probability between 0 and PIE_MAX_PROB*/
- if (prob < 0)
+ /*
+ * decay the drop probability exponentially
+ * and restrict it to range 0 to PIE_MAX_PROB
+ */
+ if (prob < 0) {
prob = 0;
- else if (prob > PIE_MAX_PROB)
- prob = PIE_MAX_PROB;
+ } else {
+ if (pst->current_qdelay == 0 && pst->qdelay_old == 0) {
+ /* 0.98 ~= 1- 1/64 */
+ prob = prob - (prob >> 6);
+ }
+
+ if (prob > PIE_MAX_PROB) {
+ prob = PIE_MAX_PROB;
+ }
+ }
pst->drop_prob = prob;
OpenPOWER on IntegriCloud