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 | ||
21454aaa | 97 | dprintk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %pI4\n", &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){ | |
21454aaa HH |
153 | dprintk("mpoa: (%s) mpoa_caches.c: threshold exceeded for ip %pI4, sending MPOA res req\n", |
154 | mpc->dev->name, &entry->ctrl_info.in_dst_ip); | |
1da177e4 LT |
155 | entry->entry_state = INGRESS_RESOLVING; |
156 | msg.type = SND_MPOA_RES_RQST; | |
157 | memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN ); | |
158 | msg.content.in_info = entry->ctrl_info; | |
159 | qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); | |
160 | if (qos != NULL) msg.qos = qos->qos; | |
161 | msg_to_mpoad( &msg, mpc); | |
162 | do_gettimeofday(&(entry->reply_wait)); | |
163 | } | |
164 | ||
165 | return CLOSED; | |
166 | } | |
167 | ||
168 | static void in_cache_put(in_cache_entry *entry) | |
169 | { | |
170 | if (atomic_dec_and_test(&entry->use)) { | |
171 | memset(entry, 0, sizeof(in_cache_entry)); | |
172 | kfree(entry); | |
173 | } | |
174 | ||
175 | return; | |
176 | } | |
177 | ||
178 | /* | |
179 | * This should be called with write lock on | |
180 | */ | |
181 | static void in_cache_remove_entry(in_cache_entry *entry, | |
182 | struct mpoa_client *client) | |
183 | { | |
184 | struct atm_vcc *vcc; | |
185 | struct k_message msg; | |
1da177e4 LT |
186 | |
187 | vcc = entry->shortcut; | |
21454aaa HH |
188 | dprintk("mpoa: mpoa_caches.c: removing an ingress entry, ip = %pI4\n", |
189 | &entry->ctrl_info.in_dst_ip); | |
1da177e4 LT |
190 | |
191 | if (entry->prev != NULL) | |
192 | entry->prev->next = entry->next; | |
193 | else | |
194 | client->in_cache = entry->next; | |
195 | if (entry->next != NULL) | |
196 | entry->next->prev = entry->prev; | |
197 | client->in_ops->put(entry); | |
198 | if(client->in_cache == NULL && client->eg_cache == NULL){ | |
199 | msg.type = STOP_KEEP_ALIVE_SM; | |
200 | msg_to_mpoad(&msg,client); | |
201 | } | |
202 | ||
203 | /* Check if the egress side still uses this VCC */ | |
204 | if (vcc != NULL) { | |
205 | eg_cache_entry *eg_entry = client->eg_ops->get_by_vcc(vcc, client); | |
206 | if (eg_entry != NULL) { | |
207 | client->eg_ops->put(eg_entry); | |
208 | return; | |
209 | } | |
210 | vcc_release_async(vcc, -EPIPE); | |
211 | } | |
212 | ||
213 | return; | |
214 | } | |
215 | ||
216 | ||
217 | /* Call this every MPC-p2 seconds... Not exactly correct solution, | |
218 | but an easy one... */ | |
219 | static void clear_count_and_expired(struct mpoa_client *client) | |
220 | { | |
1da177e4 LT |
221 | in_cache_entry *entry, *next_entry; |
222 | struct timeval now; | |
223 | ||
224 | do_gettimeofday(&now); | |
225 | ||
226 | write_lock_bh(&client->ingress_lock); | |
227 | entry = client->in_cache; | |
228 | while(entry != NULL){ | |
229 | entry->count=0; | |
230 | next_entry = entry->next; | |
231 | if((now.tv_sec - entry->tv.tv_sec) | |
232 | > entry->ctrl_info.holding_time){ | |
21454aaa HH |
233 | dprintk("mpoa: mpoa_caches.c: holding time expired, ip = %pI4\n", |
234 | &entry->ctrl_info.in_dst_ip); | |
1da177e4 LT |
235 | client->in_ops->remove_entry(entry, client); |
236 | } | |
237 | entry = next_entry; | |
238 | } | |
239 | write_unlock_bh(&client->ingress_lock); | |
240 | ||
241 | return; | |
242 | } | |
243 | ||
244 | /* Call this every MPC-p4 seconds. */ | |
245 | static void check_resolving_entries(struct mpoa_client *client) | |
246 | { | |
247 | ||
248 | struct atm_mpoa_qos *qos; | |
249 | in_cache_entry *entry; | |
250 | struct timeval now; | |
251 | struct k_message msg; | |
252 | ||
253 | do_gettimeofday( &now ); | |
254 | ||
255 | read_lock_bh(&client->ingress_lock); | |
256 | entry = client->in_cache; | |
257 | while( entry != NULL ){ | |
258 | if(entry->entry_state == INGRESS_RESOLVING){ | |
259 | if(now.tv_sec - entry->hold_down.tv_sec < client->parameters.mpc_p6){ | |
260 | entry = entry->next; /* Entry in hold down */ | |
261 | continue; | |
262 | } | |
263 | if( (now.tv_sec - entry->reply_wait.tv_sec) > | |
264 | entry->retry_time ){ | |
265 | entry->retry_time = MPC_C1*( entry->retry_time ); | |
266 | if(entry->retry_time > client->parameters.mpc_p5){ | |
267 | /* Retry time maximum exceeded, put entry in hold down. */ | |
268 | do_gettimeofday(&(entry->hold_down)); | |
269 | entry->retry_time = client->parameters.mpc_p4; | |
270 | entry = entry->next; | |
271 | continue; | |
272 | } | |
273 | /* Ask daemon to send a resolution request. */ | |
274 | memset(&(entry->hold_down),0,sizeof(struct timeval)); | |
275 | msg.type = SND_MPOA_RES_RTRY; | |
276 | memcpy(msg.MPS_ctrl, client->mps_ctrl_addr, ATM_ESA_LEN); | |
277 | msg.content.in_info = entry->ctrl_info; | |
278 | qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); | |
279 | if (qos != NULL) msg.qos = qos->qos; | |
280 | msg_to_mpoad(&msg, client); | |
281 | do_gettimeofday(&(entry->reply_wait)); | |
282 | } | |
283 | } | |
284 | entry = entry->next; | |
285 | } | |
286 | read_unlock_bh(&client->ingress_lock); | |
287 | } | |
288 | ||
289 | /* Call this every MPC-p5 seconds. */ | |
290 | static void refresh_entries(struct mpoa_client *client) | |
291 | { | |
292 | struct timeval now; | |
293 | struct in_cache_entry *entry = client->in_cache; | |
294 | ||
295 | ddprintk("mpoa: mpoa_caches.c: refresh_entries\n"); | |
296 | do_gettimeofday(&now); | |
297 | ||
298 | read_lock_bh(&client->ingress_lock); | |
299 | while( entry != NULL ){ | |
300 | if( entry->entry_state == INGRESS_RESOLVED ){ | |
301 | if(!(entry->refresh_time)) | |
302 | entry->refresh_time = (2*(entry->ctrl_info.holding_time))/3; | |
303 | if( (now.tv_sec - entry->reply_wait.tv_sec) > entry->refresh_time ){ | |
304 | dprintk("mpoa: mpoa_caches.c: refreshing an entry.\n"); | |
305 | entry->entry_state = INGRESS_REFRESHING; | |
306 | ||
307 | } | |
308 | } | |
309 | entry = entry->next; | |
310 | } | |
311 | read_unlock_bh(&client->ingress_lock); | |
312 | } | |
313 | ||
314 | static void in_destroy_cache(struct mpoa_client *mpc) | |
315 | { | |
316 | write_lock_irq(&mpc->ingress_lock); | |
317 | while(mpc->in_cache != NULL) | |
318 | mpc->in_ops->remove_entry(mpc->in_cache, mpc); | |
319 | write_unlock_irq(&mpc->ingress_lock); | |
320 | ||
321 | return; | |
322 | } | |
323 | ||
30d492da | 324 | static eg_cache_entry *eg_cache_get_by_cache_id(__be32 cache_id, struct mpoa_client *mpc) |
1da177e4 LT |
325 | { |
326 | eg_cache_entry *entry; | |
327 | ||
328 | read_lock_irq(&mpc->egress_lock); | |
329 | entry = mpc->eg_cache; | |
330 | while(entry != NULL){ | |
331 | if(entry->ctrl_info.cache_id == cache_id){ | |
332 | atomic_inc(&entry->use); | |
333 | read_unlock_irq(&mpc->egress_lock); | |
334 | return entry; | |
335 | } | |
336 | entry = entry->next; | |
337 | } | |
338 | read_unlock_irq(&mpc->egress_lock); | |
339 | ||
340 | return NULL; | |
341 | } | |
342 | ||
343 | /* This can be called from any context since it saves CPU flags */ | |
30d492da | 344 | static eg_cache_entry *eg_cache_get_by_tag(__be32 tag, struct mpoa_client *mpc) |
1da177e4 LT |
345 | { |
346 | unsigned long flags; | |
347 | eg_cache_entry *entry; | |
348 | ||
349 | read_lock_irqsave(&mpc->egress_lock, flags); | |
350 | entry = mpc->eg_cache; | |
351 | while (entry != NULL){ | |
352 | if (entry->ctrl_info.tag == tag) { | |
353 | atomic_inc(&entry->use); | |
354 | read_unlock_irqrestore(&mpc->egress_lock, flags); | |
355 | return entry; | |
356 | } | |
357 | entry = entry->next; | |
358 | } | |
359 | read_unlock_irqrestore(&mpc->egress_lock, flags); | |
360 | ||
361 | return NULL; | |
362 | } | |
363 | ||
364 | /* This can be called from any context since it saves CPU flags */ | |
365 | static eg_cache_entry *eg_cache_get_by_vcc(struct atm_vcc *vcc, struct mpoa_client *mpc) | |
366 | { | |
367 | unsigned long flags; | |
368 | eg_cache_entry *entry; | |
369 | ||
370 | read_lock_irqsave(&mpc->egress_lock, flags); | |
371 | entry = mpc->eg_cache; | |
372 | while (entry != NULL){ | |
373 | if (entry->shortcut == vcc) { | |
374 | atomic_inc(&entry->use); | |
f7d57453 | 375 | read_unlock_irqrestore(&mpc->egress_lock, flags); |
1da177e4 LT |
376 | return entry; |
377 | } | |
378 | entry = entry->next; | |
379 | } | |
380 | read_unlock_irqrestore(&mpc->egress_lock, flags); | |
381 | ||
382 | return NULL; | |
383 | } | |
384 | ||
30d492da | 385 | static eg_cache_entry *eg_cache_get_by_src_ip(__be32 ipaddr, struct mpoa_client *mpc) |
1da177e4 LT |
386 | { |
387 | eg_cache_entry *entry; | |
388 | ||
389 | read_lock_irq(&mpc->egress_lock); | |
390 | entry = mpc->eg_cache; | |
391 | while(entry != NULL){ | |
392 | if(entry->latest_ip_addr == ipaddr) { | |
393 | atomic_inc(&entry->use); | |
f7d57453 | 394 | read_unlock_irq(&mpc->egress_lock); |
1da177e4 LT |
395 | return entry; |
396 | } | |
397 | entry = entry->next; | |
398 | } | |
399 | read_unlock_irq(&mpc->egress_lock); | |
400 | ||
401 | return NULL; | |
402 | } | |
403 | ||
404 | static void eg_cache_put(eg_cache_entry *entry) | |
405 | { | |
406 | if (atomic_dec_and_test(&entry->use)) { | |
407 | memset(entry, 0, sizeof(eg_cache_entry)); | |
408 | kfree(entry); | |
409 | } | |
410 | ||
411 | return; | |
412 | } | |
413 | ||
414 | /* | |
415 | * This should be called with write lock on | |
416 | */ | |
417 | static void eg_cache_remove_entry(eg_cache_entry *entry, | |
418 | struct mpoa_client *client) | |
419 | { | |
420 | struct atm_vcc *vcc; | |
421 | struct k_message msg; | |
422 | ||
423 | vcc = entry->shortcut; | |
424 | dprintk("mpoa: mpoa_caches.c: removing an egress entry.\n"); | |
425 | if (entry->prev != NULL) | |
426 | entry->prev->next = entry->next; | |
427 | else | |
428 | client->eg_cache = entry->next; | |
429 | if (entry->next != NULL) | |
430 | entry->next->prev = entry->prev; | |
431 | client->eg_ops->put(entry); | |
432 | if(client->in_cache == NULL && client->eg_cache == NULL){ | |
433 | msg.type = STOP_KEEP_ALIVE_SM; | |
434 | msg_to_mpoad(&msg,client); | |
435 | } | |
436 | ||
437 | /* Check if the ingress side still uses this VCC */ | |
438 | if (vcc != NULL) { | |
439 | in_cache_entry *in_entry = client->in_ops->get_by_vcc(vcc, client); | |
440 | if (in_entry != NULL) { | |
441 | client->in_ops->put(in_entry); | |
442 | return; | |
443 | } | |
444 | vcc_release_async(vcc, -EPIPE); | |
445 | } | |
446 | ||
447 | return; | |
448 | } | |
449 | ||
450 | static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, struct mpoa_client *client) | |
451 | { | |
2afe37cd | 452 | eg_cache_entry *entry = kzalloc(sizeof(eg_cache_entry), GFP_KERNEL); |
1da177e4 LT |
453 | |
454 | if (entry == NULL) { | |
455 | printk("mpoa: mpoa_caches.c: new_eg_cache_entry: out of memory\n"); | |
456 | return NULL; | |
457 | } | |
458 | ||
21454aaa HH |
459 | dprintk("mpoa: mpoa_caches.c: adding an egress entry, ip = %pI4, this should be our IP\n", |
460 | &msg->content.eg_info.eg_dst_ip); | |
1da177e4 LT |
461 | |
462 | atomic_set(&entry->use, 1); | |
463 | dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry: about to lock\n"); | |
464 | write_lock_irq(&client->egress_lock); | |
465 | entry->next = client->eg_cache; | |
466 | entry->prev = NULL; | |
467 | if (client->eg_cache != NULL) | |
468 | client->eg_cache->prev = entry; | |
469 | client->eg_cache = entry; | |
470 | ||
471 | memcpy(entry->MPS_ctrl_ATM_addr, client->mps_ctrl_addr, ATM_ESA_LEN); | |
472 | entry->ctrl_info = msg->content.eg_info; | |
473 | do_gettimeofday(&(entry->tv)); | |
474 | entry->entry_state = EGRESS_RESOLVED; | |
475 | dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry cache_id %lu\n", ntohl(entry->ctrl_info.cache_id)); | |
21454aaa HH |
476 | dprintk("mpoa: mpoa_caches.c: mps_ip = %pI4\n", |
477 | &entry->ctrl_info.mps_ip); | |
1da177e4 LT |
478 | atomic_inc(&entry->use); |
479 | ||
480 | write_unlock_irq(&client->egress_lock); | |
481 | dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry: unlocked\n"); | |
482 | ||
483 | return entry; | |
484 | } | |
485 | ||
486 | static void update_eg_cache_entry(eg_cache_entry * entry, uint16_t holding_time) | |
487 | { | |
488 | do_gettimeofday(&(entry->tv)); | |
489 | entry->entry_state = EGRESS_RESOLVED; | |
490 | entry->ctrl_info.holding_time = holding_time; | |
491 | ||
492 | return; | |
493 | } | |
494 | ||
495 | static void clear_expired(struct mpoa_client *client) | |
496 | { | |
497 | eg_cache_entry *entry, *next_entry; | |
498 | struct timeval now; | |
499 | struct k_message msg; | |
500 | ||
501 | do_gettimeofday(&now); | |
502 | ||
503 | write_lock_irq(&client->egress_lock); | |
504 | entry = client->eg_cache; | |
505 | while(entry != NULL){ | |
506 | next_entry = entry->next; | |
507 | if((now.tv_sec - entry->tv.tv_sec) | |
508 | > entry->ctrl_info.holding_time){ | |
509 | msg.type = SND_EGRESS_PURGE; | |
510 | msg.content.eg_info = entry->ctrl_info; | |
511 | dprintk("mpoa: mpoa_caches.c: egress_cache: holding time expired, cache_id = %lu.\n",ntohl(entry->ctrl_info.cache_id)); | |
512 | msg_to_mpoad(&msg, client); | |
513 | client->eg_ops->remove_entry(entry, client); | |
514 | } | |
515 | entry = next_entry; | |
516 | } | |
517 | write_unlock_irq(&client->egress_lock); | |
518 | ||
519 | return; | |
520 | } | |
521 | ||
522 | static void eg_destroy_cache(struct mpoa_client *mpc) | |
523 | { | |
524 | write_lock_irq(&mpc->egress_lock); | |
525 | while(mpc->eg_cache != NULL) | |
526 | mpc->eg_ops->remove_entry(mpc->eg_cache, mpc); | |
527 | write_unlock_irq(&mpc->egress_lock); | |
528 | ||
529 | return; | |
530 | } | |
531 | ||
532 | ||
533 | ||
534 | static struct in_cache_ops ingress_ops = { | |
535 | in_cache_add_entry, /* add_entry */ | |
536 | in_cache_get, /* get */ | |
537 | in_cache_get_with_mask, /* get_with_mask */ | |
538 | in_cache_get_by_vcc, /* get_by_vcc */ | |
539 | in_cache_put, /* put */ | |
540 | in_cache_remove_entry, /* remove_entry */ | |
541 | cache_hit, /* cache_hit */ | |
542 | clear_count_and_expired, /* clear_count */ | |
543 | check_resolving_entries, /* check_resolving */ | |
544 | refresh_entries, /* refresh */ | |
545 | in_destroy_cache /* destroy_cache */ | |
546 | }; | |
547 | ||
548 | static struct eg_cache_ops egress_ops = { | |
549 | eg_cache_add_entry, /* add_entry */ | |
550 | eg_cache_get_by_cache_id, /* get_by_cache_id */ | |
551 | eg_cache_get_by_tag, /* get_by_tag */ | |
552 | eg_cache_get_by_vcc, /* get_by_vcc */ | |
553 | eg_cache_get_by_src_ip, /* get_by_src_ip */ | |
554 | eg_cache_put, /* put */ | |
555 | eg_cache_remove_entry, /* remove_entry */ | |
556 | update_eg_cache_entry, /* update */ | |
557 | clear_expired, /* clear_expired */ | |
558 | eg_destroy_cache /* destroy_cache */ | |
559 | }; | |
560 | ||
561 | ||
562 | void atm_mpoa_init_cache(struct mpoa_client *mpc) | |
563 | { | |
564 | mpc->in_ops = &ingress_ops; | |
565 | mpc->eg_ops = &egress_ops; | |
566 | ||
567 | return; | |
568 | } |