2 * Connection oriented routing
3 * Copyright (C) 2007-2010 Michael Blizek
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 static spinlock_t conn_credits_lock
;
25 /* credit_lock must be held while calling this */
26 int refresh_credits_state(struct neighbor
*nb
)
28 long jiffies_tmp
= jiffies
;
30 __s64 creditrate
= 1000 * ((__s64
)(nb
->creditrate_initial
+
31 nb
->creditrate_earning
- nb
->creditrate_spending
));
33 __s64 crediterrorrate
= 1000 * ((__s64
)(nb
->creditrate_spending
-
34 nb
->creditrate_spending_expected
)) -
36 * tolerance is 50% of creditsrate_initial + 2.5% of
37 * both spending+earning
39 500 * ((__s64
)(nb
->creditrate_initial
)) -
40 25 * ((__s64
)(nb
->creditrate_spending_expected
)) -
41 25 * ((__s64
)(nb
->creditrate_earning
));
43 __s64 debitrate
= 1000 * ((__s64
)(nb
->debitrate_initial
+
44 nb
->debitrate_initial_adj
+ nb
->debitrate_earning
-
45 nb
->debitrate_spending
));
48 __s64 credits_adj
= (jiffies_tmp
- nb
->jiffies_credit_update
) *
49 creditrate
+ nb
->credits_fract
;
51 __s64 creditsd_adj
= (jiffies_tmp
- nb
->jiffies_credit_update
) *
52 crediterrorrate
+ nb
->credits_diff_fract
;
54 __s64 debits_adj
= (jiffies_tmp
- nb
->jiffies_credit_update
) *
55 debitrate
+ nb
->debits_fract
;
58 nb
->jiffies_credit_update
= jiffies_tmp
;
61 if (unlikely(credits_adj
< 0 && (nb
->credits
< -(credits_adj
/HZ
)))) {
63 nb
->credits_fract
= 0;
65 nb
->credits
+= credits_adj
/ HZ
;
66 nb
->credits_fract
= credits_adj
% HZ
;
69 if (unlikely(creditsd_adj
< 0 && (nb
->credits_diff
<
70 -(creditsd_adj
/HZ
)))) {
72 nb
->credits_diff_fract
= 0;
74 nb
->credits_diff
+= creditsd_adj
/ HZ
;
75 nb
->credits_diff_fract
= creditsd_adj
% HZ
;
78 if (unlikely(debits_adj
< 0 && (nb
->debits
< -(debits_adj
/HZ
)))) {
84 nb
->debits
+= debits_adj
/ HZ
;
85 nb
->debits_fract
= debits_adj
% HZ
;
91 void check_credit_state(struct neighbor
*nb
)
96 struct list_head
*currlh
;
99 spin_lock_irqsave( &(nb
->credits_lock
), iflags
);
100 refresh_credits_state(nb
);
101 resetconns
= (nb
->debits
== 0 && ((
102 (__s64
) nb
->debitrate_initial_adj
+
103 (__s64
) nb
->debitrate_earning
-
104 (__s64
) nb
->debitrate_spending
) < 0));
105 spin_unlock_irqrestore( &(nb
->credits_lock
), iflags
);
107 if (likely(resetconns
== 0)) {
108 if (unlikely(sendcredits
))
115 mutex_lock(&(nb
->conn_list_lock
));
116 BUG_ON(list_empty(&(nb
->snd_conn_list
)) && nb
->num_send_conns
!= 0);
117 currlh
= nb
->snd_conn_list
.next
;
119 while (currlh
!= &(nb
->snd_conn_list
)) {
121 struct conn
*sconn
= container_of(currlh
, struct conn
,
123 struct conn
*rconn
= sconn
->reversedir
;
125 mutex_lock(&(rconn
->rcv_lock
));
126 BUG_ON(sconn
->targettype
!= TARGET_OUT
);
127 BUG_ON(rconn
->sourcetype
!= SOURCE_IN
);
129 spin_lock_irqsave(&conn_credits_lock
, iflags
);
130 if (rconn
->targettype
== TARGET_UNCONNECTED
||
131 (rconn
->targettype
== TARGET_SOCK
&&
132 rconn
->target
.sock
.credituser
!= 0))
135 ispaying
= (sconn
->recp_crate
> rconn
->sender_crate
);
136 spin_unlock_irqrestore(&conn_credits_lock
, iflags
);
138 mutex_unlock(&(rconn
->rcv_lock
));
142 * reset_conn must not be called with conn_list_lock
145 mutex_unlock(&(nb
->conn_list_lock
));
149 currlh
= currlh
->next
;
155 int debit_adj_needed(struct neighbor
*nb
)
158 unsigned long iflags
;
160 spin_lock_irqsave( &(nb
->credits_lock
), iflags
);
162 refresh_credits_state(nb
);
164 expected_adj
= nb
->creditrate_initial
- nb
->credits_diff
/10000;
165 if (unlikely((expected_adj
< 0 || nb
->debitrate_initial_adj
< 0) &&
166 ( (expected_adj
* 2 < nb
->debitrate_initial_adj
) ||
167 (expected_adj
> nb
->debitrate_initial_adj
* 2) ))) {
168 nb
->debitrate_initial_adj
= (nb
->debitrate_initial_adj
* 15 +
173 spin_unlock_irqrestore( &(nb
->credits_lock
), iflags
);
178 void set_credits(struct neighbor
*nb
, __u64 credits
, __s32 creditrate_initial
,
179 __u32 creditrate_earning
, __u32 creditrate_spending
)
181 unsigned long iflags
;
183 spin_lock_irqsave( &(nb
->credits_lock
), iflags
);
185 refresh_credits_state(nb
);
187 if (nb
->credits_diff
+ nb
->credits
< credits
)
188 nb
->credits_diff
= 0;
190 nb
->credits_diff
+= nb
->credits
- credits
;
191 nb
->credits
= credits
;
192 nb
->creditrate_initial
= creditrate_initial
;
193 nb
->creditrate_earning
= creditrate_earning
;
194 nb
->creditrate_spending
= creditrate_spending
;
196 spin_unlock_irqrestore( &(nb
->credits_lock
), iflags
);
199 void set_debitrate_initial(struct neighbor
*nb
, __u32 debitrate
)
201 unsigned long iflags
;
203 spin_lock_irqsave( &(nb
->credits_lock
), iflags
);
205 refresh_credits_state(nb
);
206 nb
->debitrate_initial
= debitrate
;
208 spin_unlock_irqrestore( &(nb
->credits_lock
), iflags
);
213 static __u32
credit_exchange_in(struct neighbor
*nb
, __u32 crate_in_raw
)
215 unsigned long iflags
;
217 spin_lock_irqsave( &(nb
->credits_lock
), iflags
);
218 if (unlikely(nb
->debits
== 0))
221 ret
= multiply_div(nb
->credits
, crate_in_raw
, nb
->debits
);
222 spin_unlock_irqrestore( &(nb
->credits_lock
), iflags
);
224 if ((ret
>> 32) != 0)
229 static void refresh_conn_crates(struct conn
*conn
)
231 if (conn
->sourcetype
== SOURCE_NONE
) {
232 conn
->sender_crate
= conn
->reversedir
->recp_crate
;
233 } else if (conn
->sourcetype
== SOURCE_IN
) {
234 conn
->sender_crate
= credit_exchange_in(conn
->source
.in
.nb
,
235 conn
->source
.in
.crate_in_raw
);
236 } else if (conn
->sourcetype
== SOURCE_SOCK
) {
237 BUG_ON(conn
->reversedir
->target
.sock
.credituser
== 1 &&
238 conn
->targettype
== TARGET_SOCK
&&
239 conn
->reversedir
->recp_crate
!= 0);
242 if ((conn
->source
.sock
.crate
+ conn
->reversedir
->recp_crate
) <
243 conn
->reversedir
->recp_crate
|| (
244 conn
->reversedir
->recp_crate
+
245 conn
->source
.sock
.crate
) > MAX_CREDITRATE_SOCK
)
246 conn
->sender_crate
= MAX_CREDITRATE_SOCK
;
248 conn
->sender_crate
= conn
->reversedir
->recp_crate
+
249 conn
->source
.sock
.crate
;
254 if (conn
->targettype
== TARGET_UNCONNECTED
) {
255 conn
->recp_crate
= conn
->sender_crate
;
256 conn
->reversedir
->sender_crate
= conn
->recp_crate
;
257 } else if ((conn
->targettype
== TARGET_SOCK
&&
258 conn
->target
.sock
.credituser
== 0)) {
259 conn
->recp_crate
= conn
->sender_crate
;
260 conn
->reversedir
->sender_crate
= conn
->recp_crate
+
261 conn
->reversedir
->source
.sock
.crate
;
265 static void _refresh_conn_credits(struct conn
*conn
)
267 long jiffies_tmp
= jiffies
;
269 __u32 scrate
= conn
->sender_crate
;
270 __u32 rcrate
= conn
->recp_crate
;
274 refresh_conn_crates(conn
);
276 refresh_conn_crates(conn
);
278 /* 500 and not 1000 here: 1000 * (*_crate + *rate)/2 = 500 * ... */
279 diff
= 500 * ((__s64
) conn
->sender_crate
+ (__s64
) scrate
-
280 (__s64
) conn
->recp_crate
- (__s64
) rcrate
) * (
281 jiffies_tmp
- conn
->jiffies_credit_update
) +
284 conn
->credits
+= diff
/ HZ
;
285 conn
->credits_fract
= diff
% HZ
;
287 conn
->jiffies_credit_update
= jiffies_tmp
;
291 * locked for access to credits + source.* + target.*
292 * lock both sides, if either source or target is not out/in
294 static __u32
credits_lock_conn(struct conn
*conn
)
297 mutex_lock(&(conn
->rcv_lock
));
298 if (conn
->sourcetype
!= SOURCE_IN
) {
299 mutex_unlock(&(conn
->rcv_lock
));
301 mutex_lock(&(conn
->reversedir
->rcv_lock
));
302 mutex_lock(&(conn
->rcv_lock
));
305 } else if (conn
->targettype
!= TARGET_OUT
) {
306 mutex_lock(&(conn
->reversedir
->rcv_lock
));
313 static void credits_unlock_conn(struct conn
*conn
, __u32 hints
)
315 if ((hints
& 1) != 0)
316 mutex_unlock(&(conn
->rcv_lock
));
317 if ((hints
& 2) != 0)
318 mutex_unlock(&(conn
->reversedir
->rcv_lock
));
319 if ((hints
& 4) != 0)
320 mutex_unlock(&(conn
->rcv_lock
));
323 void refresh_conn_credits(struct conn
*conn
)
325 unsigned long iflags
;
326 __u32 unlockhints
= credits_lock_conn(conn
);
328 if (unlikely(conn
->targettype
== TARGET_SOCK
&&
329 conn
->reversedir
->targettype
== TARGET_SOCK
&&
330 conn
->target
.sock
.credituser
== 0 &&
331 conn
->reversedir
->target
.sock
.credituser
== 0))
333 spin_lock_irqsave(&conn_credits_lock
, iflags
);
335 _refresh_conn_credits(conn
);
336 refresh_conn_crates(conn
);
338 spin_unlock_irqrestore(&conn_credits_lock
, iflags
);
340 credits_unlock_conn(conn
, unlockhints
);
343 void set_conn_in_crate(struct conn
*rconn
, __u32 crate_in
)
345 unsigned long iflags
;
347 __u32 unlockhints
= credits_lock_conn(rconn
);
348 spin_lock_irqsave(&conn_credits_lock
, iflags
);
350 BUG_ON(rconn
->sourcetype
!= SOURCE_IN
);
351 _refresh_conn_credits(rconn
);
352 rconn
->source
.in
.crate_in_raw
= crate_in
;
353 refresh_conn_crates(rconn
);
355 spin_unlock_irqrestore(&conn_credits_lock
, iflags
);
356 credits_unlock_conn(rconn
, unlockhints
);
359 int __init
cor_credits_init(void)
361 spin_lock_init(&conn_credits_lock
);