Blame view

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