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