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 memset(entry, 0, sizeof(in_cache_entry)); 184 kfree(entry); 185 } 186 } 187 188 /* 189 * This should be called with write lock on 190 */ 191 static void in_cache_remove_entry(in_cache_entry *entry, 192 struct mpoa_client *client) 193 { 194 struct atm_vcc *vcc; 195 struct k_message msg; 196 197 vcc = entry->shortcut; 198 dprintk("removing an ingress entry, ip = %pI4\n", 199 &entry->ctrl_info.in_dst_ip); 200 201 if (entry->prev != NULL) 202 entry->prev->next = entry->next; 203 else 204 client->in_cache = entry->next; 205 if (entry->next != NULL) 206 entry->next->prev = entry->prev; 207 client->in_ops->put(entry); 208 if (client->in_cache == NULL && client->eg_cache == NULL) { 209 msg.type = STOP_KEEP_ALIVE_SM; 210 msg_to_mpoad(&msg, client); 211 } 212 213 /* Check if the egress side still uses this VCC */ 214 if (vcc != NULL) { 215 eg_cache_entry *eg_entry = client->eg_ops->get_by_vcc(vcc, 216 client); 217 if (eg_entry != NULL) { 218 client->eg_ops->put(eg_entry); 219 return; 220 } 221 vcc_release_async(vcc, -EPIPE); 222 } 223 } 224 225 /* Call this every MPC-p2 seconds... Not exactly correct solution, 226 but an easy one... */ 227 static void clear_count_and_expired(struct mpoa_client *client) 228 { 229 in_cache_entry *entry, *next_entry; 230 time64_t now; 231 232 now = ktime_get_seconds(); 233 234 write_lock_bh(&client->ingress_lock); 235 entry = client->in_cache; 236 while (entry != NULL) { 237 entry->count = 0; 238 next_entry = entry->next; 239 if ((now - entry->time) > entry->ctrl_info.holding_time) { 240 dprintk("holding time expired, ip = %pI4\n", 241 &entry->ctrl_info.in_dst_ip); 242 client->in_ops->remove_entry(entry, client); 243 } 244 entry = next_entry; 245 } 246 write_unlock_bh(&client->ingress_lock); 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 time64_t now; 256 struct k_message msg; 257 258 now = ktime_get_seconds(); 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 265 if ((now - entry->hold_down) 266 < client->parameters.mpc_p6) { 267 entry = entry->next; /* Entry in hold down */ 268 continue; 269 } 270 if ((now - entry->reply_wait) > 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 entry->hold_down = ktime_get_seconds(); 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(time64_t)); 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 entry->reply_wait = ktime_get_seconds(); 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 time64_t now; 303 struct in_cache_entry *entry = client->in_cache; 304 305 ddprintk("refresh_entries\n"); 306 now = ktime_get_seconds(); 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 - entry->reply_wait) > 314 entry->refresh_time) { 315 dprintk("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 333 static eg_cache_entry *eg_cache_get_by_cache_id(__be32 cache_id, 334 struct mpoa_client *mpc) 335 { 336 eg_cache_entry *entry; 337 338 read_lock_irq(&mpc->egress_lock); 339 entry = mpc->eg_cache; 340 while (entry != NULL) { 341 if (entry->ctrl_info.cache_id == cache_id) { 342 refcount_inc(&entry->use); 343 read_unlock_irq(&mpc->egress_lock); 344 return entry; 345 } 346 entry = entry->next; 347 } 348 read_unlock_irq(&mpc->egress_lock); 349 350 return NULL; 351 } 352 353 /* This can be called from any context since it saves CPU flags */ 354 static eg_cache_entry *eg_cache_get_by_tag(__be32 tag, struct mpoa_client *mpc) 355 { 356 unsigned long flags; 357 eg_cache_entry *entry; 358 359 read_lock_irqsave(&mpc->egress_lock, flags); 360 entry = mpc->eg_cache; 361 while (entry != NULL) { 362 if (entry->ctrl_info.tag == tag) { 363 refcount_inc(&entry->use); 364 read_unlock_irqrestore(&mpc->egress_lock, flags); 365 return entry; 366 } 367 entry = entry->next; 368 } 369 read_unlock_irqrestore(&mpc->egress_lock, flags); 370 371 return NULL; 372 } 373 374 /* This can be called from any context since it saves CPU flags */ 375 static eg_cache_entry *eg_cache_get_by_vcc(struct atm_vcc *vcc, 376 struct mpoa_client *mpc) 377 { 378 unsigned long flags; 379 eg_cache_entry *entry; 380 381 read_lock_irqsave(&mpc->egress_lock, flags); 382 entry = mpc->eg_cache; 383 while (entry != NULL) { 384 if (entry->shortcut == vcc) { 385 refcount_inc(&entry->use); 386 read_unlock_irqrestore(&mpc->egress_lock, flags); 387 return entry; 388 } 389 entry = entry->next; 390 } 391 read_unlock_irqrestore(&mpc->egress_lock, flags); 392 393 return NULL; 394 } 395 396 static eg_cache_entry *eg_cache_get_by_src_ip(__be32 ipaddr, 397 struct mpoa_client *mpc) 398 { 399 eg_cache_entry *entry; 400 401 read_lock_irq(&mpc->egress_lock); 402 entry = mpc->eg_cache; 403 while (entry != NULL) { 404 if (entry->latest_ip_addr == ipaddr) { 405 refcount_inc(&entry->use); 406 read_unlock_irq(&mpc->egress_lock); 407 return entry; 408 } 409 entry = entry->next; 410 } 411 read_unlock_irq(&mpc->egress_lock); 412 413 return NULL; 414 } 415 416 static void eg_cache_put(eg_cache_entry *entry) 417 { 418 if (refcount_dec_and_test(&entry->use)) { 419 memset(entry, 0, sizeof(eg_cache_entry)); 420 kfree(entry); 421 } 422 } 423 424 /* 425 * This should be called with write lock on 426 */ 427 static void eg_cache_remove_entry(eg_cache_entry *entry, 428 struct mpoa_client *client) 429 { 430 struct atm_vcc *vcc; 431 struct k_message msg; 432 433 vcc = entry->shortcut; 434 dprintk("removing an egress entry.\n"); 435 if (entry->prev != NULL) 436 entry->prev->next = entry->next; 437 else 438 client->eg_cache = entry->next; 439 if (entry->next != NULL) 440 entry->next->prev = entry->prev; 441 client->eg_ops->put(entry); 442 if (client->in_cache == NULL && client->eg_cache == NULL) { 443 msg.type = STOP_KEEP_ALIVE_SM; 444 msg_to_mpoad(&msg, client); 445 } 446 447 /* Check if the ingress side still uses this VCC */ 448 if (vcc != NULL) { 449 in_cache_entry *in_entry = client->in_ops->get_by_vcc(vcc, client); 450 if (in_entry != NULL) { 451 client->in_ops->put(in_entry); 452 return; 453 } 454 vcc_release_async(vcc, -EPIPE); 455 } 456 } 457 458 static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, 459 struct mpoa_client *client) 460 { 461 eg_cache_entry *entry = kzalloc(sizeof(eg_cache_entry), GFP_KERNEL); 462 463 if (entry == NULL) { 464 pr_info("out of memory\n"); 465 return NULL; 466 } 467 468 dprintk("adding an egress entry, ip = %pI4, this should be our IP\n", 469 &msg->content.eg_info.eg_dst_ip); 470 471 refcount_set(&entry->use, 1); 472 dprintk("new_eg_cache_entry: about to lock\n"); 473 write_lock_irq(&client->egress_lock); 474 entry->next = client->eg_cache; 475 entry->prev = NULL; 476 if (client->eg_cache != NULL) 477 client->eg_cache->prev = entry; 478 client->eg_cache = entry; 479 480 memcpy(entry->MPS_ctrl_ATM_addr, client->mps_ctrl_addr, ATM_ESA_LEN); 481 entry->ctrl_info = msg->content.eg_info; 482 entry->time = ktime_get_seconds(); 483 entry->entry_state = EGRESS_RESOLVED; 484 dprintk("new_eg_cache_entry cache_id %u\n", 485 ntohl(entry->ctrl_info.cache_id)); 486 dprintk("mps_ip = %pI4\n", &entry->ctrl_info.mps_ip); 487 refcount_inc(&entry->use); 488 489 write_unlock_irq(&client->egress_lock); 490 dprintk("new_eg_cache_entry: unlocked\n"); 491 492 return entry; 493 } 494 495 static void update_eg_cache_entry(eg_cache_entry *entry, uint16_t holding_time) 496 { 497 entry->time = ktime_get_seconds(); 498 entry->entry_state = EGRESS_RESOLVED; 499 entry->ctrl_info.holding_time = holding_time; 500 } 501 502 static void clear_expired(struct mpoa_client *client) 503 { 504 eg_cache_entry *entry, *next_entry; 505 time64_t now; 506 struct k_message msg; 507 508 now = ktime_get_seconds(); 509 510 write_lock_irq(&client->egress_lock); 511 entry = client->eg_cache; 512 while (entry != NULL) { 513 next_entry = entry->next; 514 if ((now - entry->time) > entry->ctrl_info.holding_time) { 515 msg.type = SND_EGRESS_PURGE; 516 msg.content.eg_info = entry->ctrl_info; 517 dprintk("egress_cache: holding time expired, cache_id = %u.\n", 518 ntohl(entry->ctrl_info.cache_id)); 519 msg_to_mpoad(&msg, client); 520 client->eg_ops->remove_entry(entry, client); 521 } 522 entry = next_entry; 523 } 524 write_unlock_irq(&client->egress_lock); 525 } 526 527 static void eg_destroy_cache(struct mpoa_client *mpc) 528 { 529 write_lock_irq(&mpc->egress_lock); 530 while (mpc->eg_cache != NULL) 531 mpc->eg_ops->remove_entry(mpc->eg_cache, mpc); 532 write_unlock_irq(&mpc->egress_lock); 533 } 534 535 536 static const struct in_cache_ops ingress_ops = { 537 .add_entry = in_cache_add_entry, 538 .get = in_cache_get, 539 .get_with_mask = in_cache_get_with_mask, 540 .get_by_vcc = in_cache_get_by_vcc, 541 .put = in_cache_put, 542 .remove_entry = in_cache_remove_entry, 543 .cache_hit = cache_hit, 544 .clear_count = clear_count_and_expired, 545 .check_resolving = check_resolving_entries, 546 .refresh = refresh_entries, 547 .destroy_cache = in_destroy_cache 548 }; 549 550 static const struct eg_cache_ops egress_ops = { 551 .add_entry = eg_cache_add_entry, 552 .get_by_cache_id = eg_cache_get_by_cache_id, 553 .get_by_tag = eg_cache_get_by_tag, 554 .get_by_vcc = eg_cache_get_by_vcc, 555 .get_by_src_ip = eg_cache_get_by_src_ip, 556 .put = eg_cache_put, 557 .remove_entry = eg_cache_remove_entry, 558 .update = update_eg_cache_entry, 559 .clear_expired = clear_expired, 560 .destroy_cache = eg_destroy_cache 561 }; 562 563 void atm_mpoa_init_cache(struct mpoa_client *mpc) 564 { 565 mpc->in_ops = &ingress_ops; 566 mpc->eg_ops = &egress_ops; 567 } 568