Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | #include <linux/types.h> |
2 | #include <linux/atmmpc.h> | |
3 | #include <linux/time.h> | |
4 | ||
5 | #include "mpoa_caches.h" | |
6 | #include "mpc.h" | |
7 | ||
8 | /* | |
9 | * mpoa_caches.c: Implementation of ingress and egress cache | |
10 | * handling functions | |
11 | */ | |
12 | ||
13 | #if 0 | |
14 | #define dprintk printk /* debug */ | |
15 | #else | |
16 | #define dprintk(format,args...) | |
17 | #endif | |
18 | ||
19 | #if 0 | |
20 | #define ddprintk printk /* more debug */ | |
21 | #else | |
22 | #define ddprintk(format,args...) | |
23 | #endif | |
24 | ||
30d492da | 25 | static in_cache_entry *in_cache_get(__be32 dst_ip, |
1da177e4 LT |
26 | struct mpoa_client *client) |
27 | { | |
28 | in_cache_entry *entry; | |
29 | ||
30 | read_lock_bh(&client->ingress_lock); | |
31 | entry = client->in_cache; | |
32 | while(entry != NULL){ | |
33 | if( entry->ctrl_info.in_dst_ip == dst_ip ){ | |
34 | atomic_inc(&entry->use); | |
35 | read_unlock_bh(&client->ingress_lock); | |
36 | return entry; | |
37 | } | |
38 | entry = entry->next; | |
39 | } | |
40 | read_unlock_bh(&client->ingress_lock); | |
41 | ||
42 | return NULL; | |
43 | } | |
44 | ||
30d492da | 45 | static in_cache_entry *in_cache_get_with_mask(__be32 dst_ip, |
1da177e4 | 46 | struct mpoa_client *client, |
30d492da | 47 | __be32 mask) |
1da177e4 LT |
48 | { |
49 | in_cache_entry *entry; | |
50 | ||
51 | read_lock_bh(&client->ingress_lock); | |
52 | entry = client->in_cache; | |
53 | while(entry != NULL){ | |
54 | if((entry->ctrl_info.in_dst_ip & mask) == (dst_ip & mask )){ | |
55 | atomic_inc(&entry->use); | |
56 | read_unlock_bh(&client->ingress_lock); | |
57 | return entry; | |
58 | } | |
59 | entry = entry->next; | |
60 | } | |
61 | read_unlock_bh(&client->ingress_lock); | |
62 | ||
63 | return NULL; | |
64 | ||
65 | } | |
66 | ||
67 | static in_cache_entry *in_cache_get_by_vcc(struct atm_vcc *vcc, | |
68 | struct mpoa_client *client ) | |
69 | { | |
70 | in_cache_entry *entry; | |
71 | ||
72 | read_lock_bh(&client->ingress_lock); | |
73 | entry = client->in_cache; | |
74 | while(entry != NULL){ | |
75 | if(entry->shortcut == vcc) { | |
76 | atomic_inc(&entry->use); | |
77 | read_unlock_bh(&client->ingress_lock); | |
78 | return entry; | |
79 | } | |
80 | entry = entry->next; | |
81 | } | |
82 | read_unlock_bh(&client->ingress_lock); | |
83 | ||
84 | return NULL; | |
85 | } | |
86 | ||
30d492da | 87 | static in_cache_entry *in_cache_add_entry(__be32 dst_ip, |
1da177e4 LT |
88 | struct mpoa_client *client) |
89 | { | |
2afe37cd | 90 | in_cache_entry *entry = kzalloc(sizeof(in_cache_entry), GFP_KERNEL); |
1da177e4 LT |
91 | |
92 | if (entry == NULL) { | |
93 | printk("mpoa: mpoa_caches.c: new_in_cache_entry: out of memory\n"); | |
94 | return NULL; | |
95 | } | |
96 | ||
b4229934 | 97 | dprintk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %u.%u.%u.%u\n", NIPQUAD(dst_ip)); |
1da177e4 LT |
98 | |
99 | atomic_set(&entry->use, 1); | |
100 | dprintk("mpoa: mpoa_caches.c: new_in_cache_entry: about to lock\n"); | |
101 | write_lock_bh(&client->ingress_lock); | |
102 | entry->next = client->in_cache; | |
103 | entry->prev = NULL; | |
104 | if (client->in_cache != NULL) | |
105 | client->in_cache->prev = entry; | |
106 | client->in_cache = entry; | |
107 | ||
108 | memcpy(entry->MPS_ctrl_ATM_addr, client->mps_ctrl_addr, ATM_ESA_LEN); | |
109 | entry->ctrl_info.in_dst_ip = dst_ip; | |
110 | do_gettimeofday(&(entry->tv)); | |
111 | entry->retry_time = client->parameters.mpc_p4; | |
112 | entry->count = 1; | |
113 | entry->entry_state = INGRESS_INVALID; | |
114 | entry->ctrl_info.holding_time = HOLDING_TIME_DEFAULT; | |
115 | atomic_inc(&entry->use); | |
116 | ||
117 | write_unlock_bh(&client->ingress_lock); | |
118 | dprintk("mpoa: mpoa_caches.c: new_in_cache_entry: unlocked\n"); | |
119 | ||
120 | return entry; | |
121 | } | |
122 | ||
123 | static int cache_hit(in_cache_entry *entry, struct mpoa_client *mpc) | |
124 | { | |
125 | struct atm_mpoa_qos *qos; | |
126 | struct k_message msg; | |
127 | ||
128 | entry->count++; | |
129 | if(entry->entry_state == INGRESS_RESOLVED && entry->shortcut != NULL) | |
130 | return OPEN; | |
131 | ||
132 | if(entry->entry_state == INGRESS_REFRESHING){ | |
133 | if(entry->count > mpc->parameters.mpc_p1){ | |
134 | msg.type = SND_MPOA_RES_RQST; | |
135 | msg.content.in_info = entry->ctrl_info; | |
136 | memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN); | |
137 | qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); | |
138 | if (qos != NULL) msg.qos = qos->qos; | |
139 | msg_to_mpoad(&msg, mpc); | |
140 | do_gettimeofday(&(entry->reply_wait)); | |
141 | entry->entry_state = INGRESS_RESOLVING; | |
142 | } | |
143 | if(entry->shortcut != NULL) | |
144 | return OPEN; | |
145 | return CLOSED; | |
146 | } | |
147 | ||
148 | if(entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL) | |
149 | return OPEN; | |
150 | ||
151 | if( entry->count > mpc->parameters.mpc_p1 && | |
152 | entry->entry_state == INGRESS_INVALID){ | |
b4229934 | 153 | dprintk("mpoa: (%s) mpoa_caches.c: threshold exceeded for ip %u.%u.%u.%u, sending MPOA res req\n", mpc->dev->name, NIPQUAD(entry->ctrl_info.in_dst_ip)); |
1da177e4 LT |
154 | entry->entry_state = INGRESS_RESOLVING; |
155 | msg.type = SND_MPOA_RES_RQST; | |
156 | memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN ); | |
157 | msg.content.in_info = entry->ctrl_info; | |
158 | qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); | |
159 | if (qos != NULL) msg.qos = qos->qos; | |
160 | msg_to_mpoad( &msg, mpc); | |
161 | do_gettimeofday(&(entry->reply_wait)); | |
162 | } | |
163 | ||
164 | return CLOSED; | |
165 | } | |
166 | ||
167 | static void in_cache_put(in_cache_entry *entry) | |
168 | { | |
169 | if (atomic_dec_and_test(&entry->use)) { | |
170 | memset(entry, 0, sizeof(in_cache_entry)); | |
171 | kfree(entry); | |
172 | } | |
173 | ||
174 | return; | |
175 | } | |
176 | ||
177 | /* | |
178 | * This should be called with write lock on | |
179 | */ | |
180 | static void in_cache_remove_entry(in_cache_entry *entry, | |
181 | struct mpoa_client *client) | |
182 | { | |
183 | struct atm_vcc *vcc; | |
184 | struct k_message msg; | |
1da177e4 LT |
185 | |
186 | vcc = entry->shortcut; | |
b4229934 | 187 | dprintk("mpoa: mpoa_caches.c: removing an ingress entry, ip = %u.%u.%u.%u\n",NIPQUAD(entry->ctrl_info.in_dst_ip)); |
1da177e4 LT |
188 | |
189 | if (entry->prev != NULL) | |
190 | entry->prev->next = entry->next; | |
191 | else | |
192 | client->in_cache = entry->next; | |
193 | if (entry->next != NULL) | |
194 | entry->next->prev = entry->prev; | |
195 | client->in_ops->put(entry); | |
196 | if(client->in_cache == NULL && client->eg_cache == NULL){ | |
197 | msg.type = STOP_KEEP_ALIVE_SM; | |
198 | msg_to_mpoad(&msg,client); | |
199 | } | |
200 | ||
201 | /* Check if the egress side still uses this VCC */ | |
202 | if (vcc != NULL) { | |
203 | eg_cache_entry *eg_entry = client->eg_ops->get_by_vcc(vcc, client); | |
204 | if (eg_entry != NULL) { | |
205 | client->eg_ops->put(eg_entry); | |
206 | return; | |
207 | } | |
208 | vcc_release_async(vcc, -EPIPE); | |
209 | } | |
210 | ||
211 | return; | |
212 | } | |
213 | ||
214 | ||
215 | /* Call this every MPC-p2 seconds... Not exactly correct solution, | |
216 | but an easy one... */ | |
217 | static void clear_count_and_expired(struct mpoa_client *client) | |
218 | { | |
1da177e4 LT |
219 | in_cache_entry *entry, *next_entry; |
220 | struct timeval now; | |
221 | ||
222 | do_gettimeofday(&now); | |
223 | ||
224 | write_lock_bh(&client->ingress_lock); | |
225 | entry = client->in_cache; | |
226 | while(entry != NULL){ | |
227 | entry->count=0; | |
228 | next_entry = entry->next; | |
229 | if((now.tv_sec - entry->tv.tv_sec) | |
230 | > entry->ctrl_info.holding_time){ | |
ff7512e1 | 231 | dprintk("mpoa: mpoa_caches.c: holding time expired, ip = %u.%u.%u.%u\n", NIPQUAD(entry->ctrl_info.in_dst_ip)); |
1da177e4 LT |
232 | client->in_ops->remove_entry(entry, client); |
233 | } | |
234 | entry = next_entry; | |
235 | } | |
236 | write_unlock_bh(&client->ingress_lock); | |
237 | ||
238 | return; | |
239 | } | |
240 | ||
241 | /* Call this every MPC-p4 seconds. */ | |
242 | static void check_resolving_entries(struct mpoa_client *client) | |
243 | { | |
244 | ||
245 | struct atm_mpoa_qos *qos; | |
246 | in_cache_entry *entry; | |
247 | struct timeval now; | |
248 | struct k_message msg; | |
249 | ||
250 | do_gettimeofday( &now ); | |
251 | ||
252 | read_lock_bh(&client->ingress_lock); | |
253 | entry = client->in_cache; | |
254 | while( entry != NULL ){ | |
255 | if(entry->entry_state == INGRESS_RESOLVING){ | |
256 | if(now.tv_sec - entry->hold_down.tv_sec < client->parameters.mpc_p6){ | |
257 | entry = entry->next; /* Entry in hold down */ | |
258 | continue; | |
259 | } | |
260 | if( (now.tv_sec - entry->reply_wait.tv_sec) > | |
261 | entry->retry_time ){ | |
262 | entry->retry_time = MPC_C1*( entry->retry_time ); | |
263 | if(entry->retry_time > client->parameters.mpc_p5){ | |
264 | /* Retry time maximum exceeded, put entry in hold down. */ | |
265 | do_gettimeofday(&(entry->hold_down)); | |
266 | entry->retry_time = client->parameters.mpc_p4; | |
267 | entry = entry->next; | |
268 | continue; | |
269 | } | |
270 | /* Ask daemon to send a resolution request. */ | |
271 | memset(&(entry->hold_down),0,sizeof(struct timeval)); | |
272 | msg.type = SND_MPOA_RES_RTRY; | |
273 | memcpy(msg.MPS_ctrl, client->mps_ctrl_addr, ATM_ESA_LEN); | |
274 | msg.content.in_info = entry->ctrl_info; | |
275 | qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); | |
276 | if (qos != NULL) msg.qos = qos->qos; | |
277 | msg_to_mpoad(&msg, client); | |
278 | do_gettimeofday(&(entry->reply_wait)); | |
279 | } | |
280 | } | |
281 | entry = entry->next; | |
282 | } | |
283 | read_unlock_bh(&client->ingress_lock); | |
284 | } | |
285 | ||
286 | /* Call this every MPC-p5 seconds. */ | |
287 | static void refresh_entries(struct mpoa_client *client) | |
288 | { | |
289 | struct timeval now; | |
290 | struct in_cache_entry *entry = client->in_cache; | |
291 | ||
292 | ddprintk("mpoa: mpoa_caches.c: refresh_entries\n"); | |
293 | do_gettimeofday(&now); | |
294 | ||
295 | read_lock_bh(&client->ingress_lock); | |
296 | while( entry != NULL ){ | |
297 | if( entry->entry_state == INGRESS_RESOLVED ){ | |
298 | if(!(entry->refresh_time)) | |
299 | entry->refresh_time = (2*(entry->ctrl_info.holding_time))/3; | |
300 | if( (now.tv_sec - entry->reply_wait.tv_sec) > entry->refresh_time ){ | |
301 | dprintk("mpoa: mpoa_caches.c: refreshing an entry.\n"); | |
302 | entry->entry_state = INGRESS_REFRESHING; | |
303 | ||
304 | } | |
305 | } | |
306 | entry = entry->next; | |
307 | } | |
308 | read_unlock_bh(&client->ingress_lock); | |
309 | } | |
310 | ||
311 | static void in_destroy_cache(struct mpoa_client *mpc) | |
312 | { | |
313 | write_lock_irq(&mpc->ingress_lock); | |
314 | while(mpc->in_cache != NULL) | |
315 | mpc->in_ops->remove_entry(mpc->in_cache, mpc); | |
316 | write_unlock_irq(&mpc->ingress_lock); | |
317 | ||
318 | return; | |
319 | } | |
320 | ||
30d492da | 321 | static eg_cache_entry *eg_cache_get_by_cache_id(__be32 cache_id, struct mpoa_client *mpc) |
1da177e4 LT |
322 | { |
323 | eg_cache_entry *entry; | |
324 | ||
325 | read_lock_irq(&mpc->egress_lock); | |
326 | entry = mpc->eg_cache; | |
327 | while(entry != NULL){ | |
328 | if(entry->ctrl_info.cache_id == cache_id){ | |
329 | atomic_inc(&entry->use); | |
330 | read_unlock_irq(&mpc->egress_lock); | |
331 | return entry; | |
332 | } | |
333 | entry = entry->next; | |
334 | } | |
335 | read_unlock_irq(&mpc->egress_lock); | |
336 | ||
337 | return NULL; | |
338 | } | |
339 | ||
340 | /* This can be called from any context since it saves CPU flags */ | |
30d492da | 341 | static eg_cache_entry *eg_cache_get_by_tag(__be32 tag, struct mpoa_client *mpc) |
1da177e4 LT |
342 | { |
343 | unsigned long flags; | |
344 | eg_cache_entry *entry; | |
345 | ||
346 | read_lock_irqsave(&mpc->egress_lock, flags); | |
347 | entry = mpc->eg_cache; | |
348 | while (entry != NULL){ | |
349 | if (entry->ctrl_info.tag == tag) { | |
350 | atomic_inc(&entry->use); | |
351 | read_unlock_irqrestore(&mpc->egress_lock, flags); | |
352 | return entry; | |
353 | } | |
354 | entry = entry->next; | |
355 | } | |
356 | read_unlock_irqrestore(&mpc->egress_lock, flags); | |
357 | ||
358 | return NULL; | |
359 | } | |
360 | ||
361 | /* This can be called from any context since it saves CPU flags */ | |
362 | static eg_cache_entry *eg_cache_get_by_vcc(struct atm_vcc *vcc, struct mpoa_client *mpc) | |
363 | { | |
364 | unsigned long flags; | |
365 | eg_cache_entry *entry; | |
366 | ||
367 | read_lock_irqsave(&mpc->egress_lock, flags); | |
368 | entry = mpc->eg_cache; | |
369 | while (entry != NULL){ | |
370 | if (entry->shortcut == vcc) { | |
371 | atomic_inc(&entry->use); | |
f7d57453 | 372 | read_unlock_irqrestore(&mpc->egress_lock, flags); |
1da177e4 LT |
373 | return entry; |
374 | } | |
375 | entry = entry->next; | |
376 | } | |
377 | read_unlock_irqrestore(&mpc->egress_lock, flags); | |
378 | ||
379 | return NULL; | |
380 | } | |
381 | ||
30d492da | 382 | static eg_cache_entry *eg_cache_get_by_src_ip(__be32 ipaddr, struct mpoa_client *mpc) |
1da177e4 LT |
383 | { |
384 | eg_cache_entry *entry; | |
385 | ||
386 | read_lock_irq(&mpc->egress_lock); | |
387 | entry = mpc->eg_cache; | |
388 | while(entry != NULL){ | |
389 | if(entry->latest_ip_addr == ipaddr) { | |
390 | atomic_inc(&entry->use); | |
f7d57453 | 391 | read_unlock_irq(&mpc->egress_lock); |
1da177e4 LT |
392 | return entry; |
393 | } | |
394 | entry = entry->next; | |
395 | } | |
396 | read_unlock_irq(&mpc->egress_lock); | |
397 | ||
398 | return NULL; | |
399 | } | |
400 | ||
401 | static void eg_cache_put(eg_cache_entry *entry) | |
402 | { | |
403 | if (atomic_dec_and_test(&entry->use)) { | |
404 | memset(entry, 0, sizeof(eg_cache_entry)); | |
405 | kfree(entry); | |
406 | } | |
407 | ||
408 | return; | |
409 | } | |
410 | ||
411 | /* | |
412 | * This should be called with write lock on | |
413 | */ | |
414 | static void eg_cache_remove_entry(eg_cache_entry *entry, | |
415 | struct mpoa_client *client) | |
416 | { | |
417 | struct atm_vcc *vcc; | |
418 | struct k_message msg; | |
419 | ||
420 | vcc = entry->shortcut; | |
421 | dprintk("mpoa: mpoa_caches.c: removing an egress entry.\n"); | |
422 | if (entry->prev != NULL) | |
423 | entry->prev->next = entry->next; | |
424 | else | |
425 | client->eg_cache = entry->next; | |
426 | if (entry->next != NULL) | |
427 | entry->next->prev = entry->prev; | |
428 | client->eg_ops->put(entry); | |
429 | if(client->in_cache == NULL && client->eg_cache == NULL){ | |
430 | msg.type = STOP_KEEP_ALIVE_SM; | |
431 | msg_to_mpoad(&msg,client); | |
432 | } | |
433 | ||
434 | /* Check if the ingress side still uses this VCC */ | |
435 | if (vcc != NULL) { | |
436 | in_cache_entry *in_entry = client->in_ops->get_by_vcc(vcc, client); | |
437 | if (in_entry != NULL) { | |
438 | client->in_ops->put(in_entry); | |
439 | return; | |
440 | } | |
441 | vcc_release_async(vcc, -EPIPE); | |
442 | } | |
443 | ||
444 | return; | |
445 | } | |
446 | ||
447 | static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, struct mpoa_client *client) | |
448 | { | |
2afe37cd | 449 | eg_cache_entry *entry = kzalloc(sizeof(eg_cache_entry), GFP_KERNEL); |
1da177e4 LT |
450 | |
451 | if (entry == NULL) { | |
452 | printk("mpoa: mpoa_caches.c: new_eg_cache_entry: out of memory\n"); | |
453 | return NULL; | |
454 | } | |
455 | ||
ff7512e1 | 456 | dprintk("mpoa: mpoa_caches.c: adding an egress entry, ip = %u.%u.%u.%u, this should be our IP\n", NIPQUAD(msg->content.eg_info.eg_dst_ip)); |
1da177e4 LT |
457 | |
458 | atomic_set(&entry->use, 1); | |
459 | dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry: about to lock\n"); | |
460 | write_lock_irq(&client->egress_lock); | |
461 | entry->next = client->eg_cache; | |
462 | entry->prev = NULL; | |
463 | if (client->eg_cache != NULL) | |
464 | client->eg_cache->prev = entry; | |
465 | client->eg_cache = entry; | |
466 | ||
467 | memcpy(entry->MPS_ctrl_ATM_addr, client->mps_ctrl_addr, ATM_ESA_LEN); | |
468 | entry->ctrl_info = msg->content.eg_info; | |
469 | do_gettimeofday(&(entry->tv)); | |
470 | entry->entry_state = EGRESS_RESOLVED; | |
471 | dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry cache_id %lu\n", ntohl(entry->ctrl_info.cache_id)); | |
ff7512e1 AV |
472 | dprintk("mpoa: mpoa_caches.c: mps_ip = %u.%u.%u.%u\n", |
473 | NIPQUAD(entry->ctrl_info.mps_ip)); | |
1da177e4 LT |
474 | atomic_inc(&entry->use); |
475 | ||
476 | write_unlock_irq(&client->egress_lock); | |
477 | dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry: unlocked\n"); | |
478 | ||
479 | return entry; | |
480 | } | |
481 | ||
482 | static void update_eg_cache_entry(eg_cache_entry * entry, uint16_t holding_time) | |
483 | { | |
484 | do_gettimeofday(&(entry->tv)); | |
485 | entry->entry_state = EGRESS_RESOLVED; | |
486 | entry->ctrl_info.holding_time = holding_time; | |
487 | ||
488 | return; | |
489 | } | |
490 | ||
491 | static void clear_expired(struct mpoa_client *client) | |
492 | { | |
493 | eg_cache_entry *entry, *next_entry; | |
494 | struct timeval now; | |
495 | struct k_message msg; | |
496 | ||
497 | do_gettimeofday(&now); | |
498 | ||
499 | write_lock_irq(&client->egress_lock); | |
500 | entry = client->eg_cache; | |
501 | while(entry != NULL){ | |
502 | next_entry = entry->next; | |
503 | if((now.tv_sec - entry->tv.tv_sec) | |
504 | > entry->ctrl_info.holding_time){ | |
505 | msg.type = SND_EGRESS_PURGE; | |
506 | msg.content.eg_info = entry->ctrl_info; | |
507 | dprintk("mpoa: mpoa_caches.c: egress_cache: holding time expired, cache_id = %lu.\n",ntohl(entry->ctrl_info.cache_id)); | |
508 | msg_to_mpoad(&msg, client); | |
509 | client->eg_ops->remove_entry(entry, client); | |
510 | } | |
511 | entry = next_entry; | |
512 | } | |
513 | write_unlock_irq(&client->egress_lock); | |
514 | ||
515 | return; | |
516 | } | |
517 | ||
518 | static void eg_destroy_cache(struct mpoa_client *mpc) | |
519 | { | |
520 | write_lock_irq(&mpc->egress_lock); | |
521 | while(mpc->eg_cache != NULL) | |
522 | mpc->eg_ops->remove_entry(mpc->eg_cache, mpc); | |
523 | write_unlock_irq(&mpc->egress_lock); | |
524 | ||
525 | return; | |
526 | } | |
527 | ||
528 | ||
529 | ||
530 | static struct in_cache_ops ingress_ops = { | |
531 | in_cache_add_entry, /* add_entry */ | |
532 | in_cache_get, /* get */ | |
533 | in_cache_get_with_mask, /* get_with_mask */ | |
534 | in_cache_get_by_vcc, /* get_by_vcc */ | |
535 | in_cache_put, /* put */ | |
536 | in_cache_remove_entry, /* remove_entry */ | |
537 | cache_hit, /* cache_hit */ | |
538 | clear_count_and_expired, /* clear_count */ | |
539 | check_resolving_entries, /* check_resolving */ | |
540 | refresh_entries, /* refresh */ | |
541 | in_destroy_cache /* destroy_cache */ | |
542 | }; | |
543 | ||
544 | static struct eg_cache_ops egress_ops = { | |
545 | eg_cache_add_entry, /* add_entry */ | |
546 | eg_cache_get_by_cache_id, /* get_by_cache_id */ | |
547 | eg_cache_get_by_tag, /* get_by_tag */ | |
548 | eg_cache_get_by_vcc, /* get_by_vcc */ | |
549 | eg_cache_get_by_src_ip, /* get_by_src_ip */ | |
550 | eg_cache_put, /* put */ | |
551 | eg_cache_remove_entry, /* remove_entry */ | |
552 | update_eg_cache_entry, /* update */ | |
553 | clear_expired, /* clear_expired */ | |
554 | eg_destroy_cache /* destroy_cache */ | |
555 | }; | |
556 | ||
557 | ||
558 | void atm_mpoa_init_cache(struct mpoa_client *mpc) | |
559 | { | |
560 | mpc->in_ops = &ingress_ops; | |
561 | mpc->eg_ops = &egress_ops; | |
562 | ||
563 | return; | |
564 | } |