linux/net/atm/mpoa_caches.c
<<
>>
Prefs
   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
  25static in_cache_entry *in_cache_get(__be32 dst_ip,
  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
  45static in_cache_entry *in_cache_get_with_mask(__be32 dst_ip,
  46                                              struct mpoa_client *client,
  47                                              __be32 mask)
  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
  67static 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
  87static in_cache_entry *in_cache_add_entry(__be32 dst_ip,
  88                                          struct mpoa_client *client)
  89{
  90        in_cache_entry *entry = kzalloc(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
  97        dprintk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %u.%u.%u.%u\n", NIPQUAD(dst_ip));
  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
 123static 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){
 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));
 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
 167static 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 */
 180static 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;
 185
 186        vcc = entry->shortcut;
 187        dprintk("mpoa: mpoa_caches.c: removing an ingress entry, ip = %u.%u.%u.%u\n",NIPQUAD(entry->ctrl_info.in_dst_ip));
 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... */
 217static void clear_count_and_expired(struct mpoa_client *client)
 218{
 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){
 231                        dprintk("mpoa: mpoa_caches.c: holding time expired, ip = %u.%u.%u.%u\n", NIPQUAD(entry->ctrl_info.in_dst_ip));
 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. */
 242static 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. */
 287static 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
 311static 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
 321static eg_cache_entry *eg_cache_get_by_cache_id(__be32 cache_id, struct mpoa_client *mpc)
 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 */
 341static eg_cache_entry *eg_cache_get_by_tag(__be32 tag, struct mpoa_client *mpc)
 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 */
 362static 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);
 372                        read_unlock_irqrestore(&mpc->egress_lock, flags);
 373                        return entry;
 374                }
 375                entry = entry->next;
 376        }
 377        read_unlock_irqrestore(&mpc->egress_lock, flags);
 378
 379        return NULL;
 380}
 381
 382static eg_cache_entry *eg_cache_get_by_src_ip(__be32 ipaddr, struct mpoa_client *mpc)
 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);
 391                        read_unlock_irq(&mpc->egress_lock);
 392                        return entry;
 393                }
 394                entry = entry->next;
 395        }
 396        read_unlock_irq(&mpc->egress_lock);
 397
 398        return NULL;
 399}
 400
 401static 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 */
 414static 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
 447static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, struct mpoa_client *client)
 448{
 449        eg_cache_entry *entry = kzalloc(sizeof(eg_cache_entry), GFP_KERNEL);
 450
 451        if (entry == NULL) {
 452                printk("mpoa: mpoa_caches.c: new_eg_cache_entry: out of memory\n");
 453                return NULL;
 454        }
 455
 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));
 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));
 472        dprintk("mpoa: mpoa_caches.c: mps_ip = %u.%u.%u.%u\n",
 473                NIPQUAD(entry->ctrl_info.mps_ip));
 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
 482static 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
 491static 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
 518static 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
 530static 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
 544static 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
 558void 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}
 565