1 #include <linux/types.h>
2 #include <linux/atmmpc.h>
3 #include <linux/time.h>
5 #include "mpoa_caches.h"
9 * mpoa_caches.c: Implementation of ingress and egress cache
14 #define dprintk(format, args...) \
15 printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */
17 #define dprintk(format, args...) \
19 printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\
24 #define ddprintk(format, args...) \
25 printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */
27 #define ddprintk(format, args...) \
29 printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\
33 static in_cache_entry
*in_cache_get(__be32 dst_ip
,
34 struct mpoa_client
*client
)
36 in_cache_entry
*entry
;
38 read_lock_bh(&client
->ingress_lock
);
39 entry
= client
->in_cache
;
40 while (entry
!= NULL
) {
41 if (entry
->ctrl_info
.in_dst_ip
== dst_ip
) {
42 atomic_inc(&entry
->use
);
43 read_unlock_bh(&client
->ingress_lock
);
48 read_unlock_bh(&client
->ingress_lock
);
53 static in_cache_entry
*in_cache_get_with_mask(__be32 dst_ip
,
54 struct mpoa_client
*client
,
57 in_cache_entry
*entry
;
59 read_lock_bh(&client
->ingress_lock
);
60 entry
= client
->in_cache
;
61 while (entry
!= NULL
) {
62 if ((entry
->ctrl_info
.in_dst_ip
& mask
) == (dst_ip
& mask
)) {
63 atomic_inc(&entry
->use
);
64 read_unlock_bh(&client
->ingress_lock
);
69 read_unlock_bh(&client
->ingress_lock
);
75 static in_cache_entry
*in_cache_get_by_vcc(struct atm_vcc
*vcc
,
76 struct mpoa_client
*client
)
78 in_cache_entry
*entry
;
80 read_lock_bh(&client
->ingress_lock
);
81 entry
= client
->in_cache
;
82 while (entry
!= NULL
) {
83 if (entry
->shortcut
== vcc
) {
84 atomic_inc(&entry
->use
);
85 read_unlock_bh(&client
->ingress_lock
);
90 read_unlock_bh(&client
->ingress_lock
);
95 static in_cache_entry
*in_cache_add_entry(__be32 dst_ip
,
96 struct mpoa_client
*client
)
98 in_cache_entry
*entry
= kzalloc(sizeof(in_cache_entry
), GFP_KERNEL
);
101 pr_info("mpoa: mpoa_caches.c: new_in_cache_entry: out of memory\n");
105 dprintk("adding an ingress entry, ip = %pI4\n", &dst_ip
);
107 atomic_set(&entry
->use
, 1);
108 dprintk("new_in_cache_entry: about to lock\n");
109 write_lock_bh(&client
->ingress_lock
);
110 entry
->next
= client
->in_cache
;
112 if (client
->in_cache
!= NULL
)
113 client
->in_cache
->prev
= entry
;
114 client
->in_cache
= entry
;
116 memcpy(entry
->MPS_ctrl_ATM_addr
, client
->mps_ctrl_addr
, ATM_ESA_LEN
);
117 entry
->ctrl_info
.in_dst_ip
= dst_ip
;
118 do_gettimeofday(&(entry
->tv
));
119 entry
->retry_time
= client
->parameters
.mpc_p4
;
121 entry
->entry_state
= INGRESS_INVALID
;
122 entry
->ctrl_info
.holding_time
= HOLDING_TIME_DEFAULT
;
123 atomic_inc(&entry
->use
);
125 write_unlock_bh(&client
->ingress_lock
);
126 dprintk("new_in_cache_entry: unlocked\n");
131 static int cache_hit(in_cache_entry
*entry
, struct mpoa_client
*mpc
)
133 struct atm_mpoa_qos
*qos
;
134 struct k_message msg
;
137 if (entry
->entry_state
== INGRESS_RESOLVED
&& entry
->shortcut
!= NULL
)
140 if (entry
->entry_state
== INGRESS_REFRESHING
) {
141 if (entry
->count
> mpc
->parameters
.mpc_p1
) {
142 msg
.type
= SND_MPOA_RES_RQST
;
143 msg
.content
.in_info
= entry
->ctrl_info
;
144 memcpy(msg
.MPS_ctrl
, mpc
->mps_ctrl_addr
, ATM_ESA_LEN
);
145 qos
= atm_mpoa_search_qos(entry
->ctrl_info
.in_dst_ip
);
148 msg_to_mpoad(&msg
, mpc
);
149 do_gettimeofday(&(entry
->reply_wait
));
150 entry
->entry_state
= INGRESS_RESOLVING
;
152 if (entry
->shortcut
!= NULL
)
157 if (entry
->entry_state
== INGRESS_RESOLVING
&& entry
->shortcut
!= NULL
)
160 if (entry
->count
> mpc
->parameters
.mpc_p1
&&
161 entry
->entry_state
== INGRESS_INVALID
) {
162 dprintk("(%s) threshold exceeded for ip %pI4, sending MPOA res req\n",
163 mpc
->dev
->name
, &entry
->ctrl_info
.in_dst_ip
);
164 entry
->entry_state
= INGRESS_RESOLVING
;
165 msg
.type
= SND_MPOA_RES_RQST
;
166 memcpy(msg
.MPS_ctrl
, mpc
->mps_ctrl_addr
, ATM_ESA_LEN
);
167 msg
.content
.in_info
= entry
->ctrl_info
;
168 qos
= atm_mpoa_search_qos(entry
->ctrl_info
.in_dst_ip
);
171 msg_to_mpoad(&msg
, mpc
);
172 do_gettimeofday(&(entry
->reply_wait
));
178 static void in_cache_put(in_cache_entry
*entry
)
180 if (atomic_dec_and_test(&entry
->use
)) {
181 memset(entry
, 0, sizeof(in_cache_entry
));
189 * This should be called with write lock on
191 static void in_cache_remove_entry(in_cache_entry
*entry
,
192 struct mpoa_client
*client
)
195 struct k_message msg
;
197 vcc
= entry
->shortcut
;
198 dprintk("removing an ingress entry, ip = %pI4\n",
199 &entry
->ctrl_info
.in_dst_ip
);
201 if (entry
->prev
!= NULL
)
202 entry
->prev
->next
= entry
->next
;
204 client
->in_cache
= entry
->next
;
205 if (entry
->next
!= NULL
)
206 entry
->next
->prev
= entry
->prev
;
207 client
->in_ops
->put(entry
);
208 if (client
->in_cache
== NULL
&& client
->eg_cache
== NULL
) {
209 msg
.type
= STOP_KEEP_ALIVE_SM
;
210 msg_to_mpoad(&msg
, client
);
213 /* Check if the egress side still uses this VCC */
215 eg_cache_entry
*eg_entry
= client
->eg_ops
->get_by_vcc(vcc
,
217 if (eg_entry
!= NULL
) {
218 client
->eg_ops
->put(eg_entry
);
221 vcc_release_async(vcc
, -EPIPE
);
227 /* Call this every MPC-p2 seconds... Not exactly correct solution,
228 but an easy one... */
229 static void clear_count_and_expired(struct mpoa_client
*client
)
231 in_cache_entry
*entry
, *next_entry
;
234 do_gettimeofday(&now
);
236 write_lock_bh(&client
->ingress_lock
);
237 entry
= client
->in_cache
;
238 while (entry
!= NULL
) {
240 next_entry
= entry
->next
;
241 if ((now
.tv_sec
- entry
->tv
.tv_sec
)
242 > entry
->ctrl_info
.holding_time
) {
243 dprintk("holding time expired, ip = %pI4\n",
244 &entry
->ctrl_info
.in_dst_ip
);
245 client
->in_ops
->remove_entry(entry
, client
);
249 write_unlock_bh(&client
->ingress_lock
);
254 /* Call this every MPC-p4 seconds. */
255 static void check_resolving_entries(struct mpoa_client
*client
)
258 struct atm_mpoa_qos
*qos
;
259 in_cache_entry
*entry
;
261 struct k_message msg
;
263 do_gettimeofday(&now
);
265 read_lock_bh(&client
->ingress_lock
);
266 entry
= client
->in_cache
;
267 while (entry
!= NULL
) {
268 if (entry
->entry_state
== INGRESS_RESOLVING
) {
269 if ((now
.tv_sec
- entry
->hold_down
.tv_sec
) <
270 client
->parameters
.mpc_p6
) {
271 entry
= entry
->next
; /* Entry in hold down */
274 if ((now
.tv_sec
- entry
->reply_wait
.tv_sec
) >
276 entry
->retry_time
= MPC_C1
* (entry
->retry_time
);
278 * Retry time maximum exceeded,
279 * put entry in hold down.
281 if (entry
->retry_time
> client
->parameters
.mpc_p5
) {
282 do_gettimeofday(&(entry
->hold_down
));
283 entry
->retry_time
= client
->parameters
.mpc_p4
;
287 /* Ask daemon to send a resolution request. */
288 memset(&(entry
->hold_down
), 0, sizeof(struct timeval
));
289 msg
.type
= SND_MPOA_RES_RTRY
;
290 memcpy(msg
.MPS_ctrl
, client
->mps_ctrl_addr
, ATM_ESA_LEN
);
291 msg
.content
.in_info
= entry
->ctrl_info
;
292 qos
= atm_mpoa_search_qos(entry
->ctrl_info
.in_dst_ip
);
295 msg_to_mpoad(&msg
, client
);
296 do_gettimeofday(&(entry
->reply_wait
));
301 read_unlock_bh(&client
->ingress_lock
);
304 /* Call this every MPC-p5 seconds. */
305 static void refresh_entries(struct mpoa_client
*client
)
308 struct in_cache_entry
*entry
= client
->in_cache
;
310 ddprintk("refresh_entries\n");
311 do_gettimeofday(&now
);
313 read_lock_bh(&client
->ingress_lock
);
314 while (entry
!= NULL
) {
315 if (entry
->entry_state
== INGRESS_RESOLVED
) {
316 if (!(entry
->refresh_time
))
317 entry
->refresh_time
= (2 * (entry
->ctrl_info
.holding_time
))/3;
318 if ((now
.tv_sec
- entry
->reply_wait
.tv_sec
) >
319 entry
->refresh_time
) {
320 dprintk("refreshing an entry.\n");
321 entry
->entry_state
= INGRESS_REFRESHING
;
327 read_unlock_bh(&client
->ingress_lock
);
330 static void in_destroy_cache(struct mpoa_client
*mpc
)
332 write_lock_irq(&mpc
->ingress_lock
);
333 while (mpc
->in_cache
!= NULL
)
334 mpc
->in_ops
->remove_entry(mpc
->in_cache
, mpc
);
335 write_unlock_irq(&mpc
->ingress_lock
);
340 static eg_cache_entry
*eg_cache_get_by_cache_id(__be32 cache_id
,
341 struct mpoa_client
*mpc
)
343 eg_cache_entry
*entry
;
345 read_lock_irq(&mpc
->egress_lock
);
346 entry
= mpc
->eg_cache
;
347 while (entry
!= NULL
) {
348 if (entry
->ctrl_info
.cache_id
== cache_id
) {
349 atomic_inc(&entry
->use
);
350 read_unlock_irq(&mpc
->egress_lock
);
355 read_unlock_irq(&mpc
->egress_lock
);
360 /* This can be called from any context since it saves CPU flags */
361 static eg_cache_entry
*eg_cache_get_by_tag(__be32 tag
, struct mpoa_client
*mpc
)
364 eg_cache_entry
*entry
;
366 read_lock_irqsave(&mpc
->egress_lock
, flags
);
367 entry
= mpc
->eg_cache
;
368 while (entry
!= NULL
) {
369 if (entry
->ctrl_info
.tag
== tag
) {
370 atomic_inc(&entry
->use
);
371 read_unlock_irqrestore(&mpc
->egress_lock
, flags
);
376 read_unlock_irqrestore(&mpc
->egress_lock
, flags
);
381 /* This can be called from any context since it saves CPU flags */
382 static eg_cache_entry
*eg_cache_get_by_vcc(struct atm_vcc
*vcc
,
383 struct mpoa_client
*mpc
)
386 eg_cache_entry
*entry
;
388 read_lock_irqsave(&mpc
->egress_lock
, flags
);
389 entry
= mpc
->eg_cache
;
390 while (entry
!= NULL
) {
391 if (entry
->shortcut
== vcc
) {
392 atomic_inc(&entry
->use
);
393 read_unlock_irqrestore(&mpc
->egress_lock
, flags
);
398 read_unlock_irqrestore(&mpc
->egress_lock
, flags
);
403 static eg_cache_entry
*eg_cache_get_by_src_ip(__be32 ipaddr
,
404 struct mpoa_client
*mpc
)
406 eg_cache_entry
*entry
;
408 read_lock_irq(&mpc
->egress_lock
);
409 entry
= mpc
->eg_cache
;
410 while (entry
!= NULL
) {
411 if (entry
->latest_ip_addr
== ipaddr
) {
412 atomic_inc(&entry
->use
);
413 read_unlock_irq(&mpc
->egress_lock
);
418 read_unlock_irq(&mpc
->egress_lock
);
423 static void eg_cache_put(eg_cache_entry
*entry
)
425 if (atomic_dec_and_test(&entry
->use
)) {
426 memset(entry
, 0, sizeof(eg_cache_entry
));
434 * This should be called with write lock on
436 static void eg_cache_remove_entry(eg_cache_entry
*entry
,
437 struct mpoa_client
*client
)
440 struct k_message msg
;
442 vcc
= entry
->shortcut
;
443 dprintk("removing an egress entry.\n");
444 if (entry
->prev
!= NULL
)
445 entry
->prev
->next
= entry
->next
;
447 client
->eg_cache
= entry
->next
;
448 if (entry
->next
!= NULL
)
449 entry
->next
->prev
= entry
->prev
;
450 client
->eg_ops
->put(entry
);
451 if (client
->in_cache
== NULL
&& client
->eg_cache
== NULL
) {
452 msg
.type
= STOP_KEEP_ALIVE_SM
;
453 msg_to_mpoad(&msg
, client
);
456 /* Check if the ingress side still uses this VCC */
458 in_cache_entry
*in_entry
= client
->in_ops
->get_by_vcc(vcc
, client
);
459 if (in_entry
!= NULL
) {
460 client
->in_ops
->put(in_entry
);
463 vcc_release_async(vcc
, -EPIPE
);
469 static eg_cache_entry
*eg_cache_add_entry(struct k_message
*msg
,
470 struct mpoa_client
*client
)
472 eg_cache_entry
*entry
= kzalloc(sizeof(eg_cache_entry
), GFP_KERNEL
);
475 pr_info("out of memory\n");
479 dprintk("adding an egress entry, ip = %pI4, this should be our IP\n",
480 &msg
->content
.eg_info
.eg_dst_ip
);
482 atomic_set(&entry
->use
, 1);
483 dprintk("new_eg_cache_entry: about to lock\n");
484 write_lock_irq(&client
->egress_lock
);
485 entry
->next
= client
->eg_cache
;
487 if (client
->eg_cache
!= NULL
)
488 client
->eg_cache
->prev
= entry
;
489 client
->eg_cache
= entry
;
491 memcpy(entry
->MPS_ctrl_ATM_addr
, client
->mps_ctrl_addr
, ATM_ESA_LEN
);
492 entry
->ctrl_info
= msg
->content
.eg_info
;
493 do_gettimeofday(&(entry
->tv
));
494 entry
->entry_state
= EGRESS_RESOLVED
;
495 dprintk("new_eg_cache_entry cache_id %u\n",
496 ntohl(entry
->ctrl_info
.cache_id
));
497 dprintk("mps_ip = %pI4\n", &entry
->ctrl_info
.mps_ip
);
498 atomic_inc(&entry
->use
);
500 write_unlock_irq(&client
->egress_lock
);
501 dprintk("new_eg_cache_entry: unlocked\n");
506 static void update_eg_cache_entry(eg_cache_entry
*entry
, uint16_t holding_time
)
508 do_gettimeofday(&(entry
->tv
));
509 entry
->entry_state
= EGRESS_RESOLVED
;
510 entry
->ctrl_info
.holding_time
= holding_time
;
515 static void clear_expired(struct mpoa_client
*client
)
517 eg_cache_entry
*entry
, *next_entry
;
519 struct k_message msg
;
521 do_gettimeofday(&now
);
523 write_lock_irq(&client
->egress_lock
);
524 entry
= client
->eg_cache
;
525 while (entry
!= NULL
) {
526 next_entry
= entry
->next
;
527 if ((now
.tv_sec
- entry
->tv
.tv_sec
)
528 > entry
->ctrl_info
.holding_time
) {
529 msg
.type
= SND_EGRESS_PURGE
;
530 msg
.content
.eg_info
= entry
->ctrl_info
;
531 dprintk("egress_cache: holding time expired, cache_id = %u.\n",
532 ntohl(entry
->ctrl_info
.cache_id
));
533 msg_to_mpoad(&msg
, client
);
534 client
->eg_ops
->remove_entry(entry
, client
);
538 write_unlock_irq(&client
->egress_lock
);
543 static void eg_destroy_cache(struct mpoa_client
*mpc
)
545 write_lock_irq(&mpc
->egress_lock
);
546 while (mpc
->eg_cache
!= NULL
)
547 mpc
->eg_ops
->remove_entry(mpc
->eg_cache
, mpc
);
548 write_unlock_irq(&mpc
->egress_lock
);
554 static struct in_cache_ops ingress_ops
= {
555 in_cache_add_entry
, /* add_entry */
556 in_cache_get
, /* get */
557 in_cache_get_with_mask
, /* get_with_mask */
558 in_cache_get_by_vcc
, /* get_by_vcc */
559 in_cache_put
, /* put */
560 in_cache_remove_entry
, /* remove_entry */
561 cache_hit
, /* cache_hit */
562 clear_count_and_expired
, /* clear_count */
563 check_resolving_entries
, /* check_resolving */
564 refresh_entries
, /* refresh */
565 in_destroy_cache
/* destroy_cache */
568 static struct eg_cache_ops egress_ops
= {
569 eg_cache_add_entry
, /* add_entry */
570 eg_cache_get_by_cache_id
, /* get_by_cache_id */
571 eg_cache_get_by_tag
, /* get_by_tag */
572 eg_cache_get_by_vcc
, /* get_by_vcc */
573 eg_cache_get_by_src_ip
, /* get_by_src_ip */
574 eg_cache_put
, /* put */
575 eg_cache_remove_entry
, /* remove_entry */
576 update_eg_cache_entry
, /* update */
577 clear_expired
, /* clear_expired */
578 eg_destroy_cache
/* destroy_cache */
582 void atm_mpoa_init_cache(struct mpoa_client
*mpc
)
584 mpc
->in_ops
= &ingress_ops
;
585 mpc
->eg_ops
= &egress_ops
;