root/net/atm/mpoa_caches.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. in_cache_get
  2. in_cache_get_with_mask
  3. in_cache_get_by_vcc
  4. in_cache_add_entry
  5. cache_hit
  6. in_cache_put
  7. in_cache_remove_entry
  8. clear_count_and_expired
  9. check_resolving_entries
  10. refresh_entries
  11. in_destroy_cache
  12. eg_cache_get_by_cache_id
  13. eg_cache_get_by_tag
  14. eg_cache_get_by_vcc
  15. eg_cache_get_by_src_ip
  16. eg_cache_put
  17. eg_cache_remove_entry
  18. eg_cache_add_entry
  19. update_eg_cache_entry
  20. clear_expired
  21. eg_destroy_cache
  22. atm_mpoa_init_cache

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

/* [<][>][^][v][top][bottom][index][help] */