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