1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <unistd.h> 31 #include <sys/types.h> 32 #include <time.h> 33 #include <signal.h> 34 #include <poll.h> 35 36 #include "isns_server.h" 37 #include "isns_cache.h" 38 #include "isns_obj.h" 39 #include "isns_pdu.h" 40 #include "isns_func.h" 41 #include "isns_qry.h" 42 #include "isns_msgq.h" 43 #include "isns_log.h" 44 #include "isns_sched.h" 45 #include "isns_scn.h" 46 #include "isns_esi.h" 47 48 /* 49 * global variables. 50 */ 51 52 /* 53 * local variables. 54 */ 55 static ev_t *ev_list = NULL; 56 57 static uint32_t stopwatch = 0; 58 static pthread_mutex_t stw_mtx = PTHREAD_MUTEX_INITIALIZER; 59 60 static int wakeup = 0; 61 static pthread_mutex_t idl_mtx = PTHREAD_MUTEX_INITIALIZER; 62 static pthread_cond_t idl_cond = PTHREAD_COND_INITIALIZER; 63 64 /* 65 * external variables. 66 */ 67 extern const int UID_ATTR_INDEX[MAX_OBJ_TYPE_FOR_SIZE]; 68 69 extern boolean_t time_to_exit; 70 71 extern msg_queue_t *sys_q; 72 73 extern uint64_t esi_threshold; 74 75 #ifdef DEBUG 76 extern void dump_pdu1(isns_pdu_t *); 77 #endif 78 79 /* 80 * local functions. 81 */ 82 static void *esi_monitor(void *); 83 84 /* 85 * **************************************************************************** 86 * 87 * new_esi_portal: 88 * Make a new portal for ESI event. 89 * 90 * uid - the portal object UID. 91 * ip6 - the portal IPv6 format IP address. 92 * port - the portal port. 93 * esip - the ESI port. 94 * return - the new ESI portal. 95 * 96 * **************************************************************************** 97 */ 98 static esi_portal_t * 99 new_esi_portal( 100 uint32_t uid, 101 in6_addr_t *ip6, 102 uint32_t port, 103 uint32_t esip 104 ) 105 { 106 esi_portal_t *p; 107 108 p = (esi_portal_t *)malloc(sizeof (esi_portal_t)); 109 if (p != NULL) { 110 if (((int *)ip6)[0] == 0x00 && 111 ((int *)ip6)[1] == 0x00 && 112 ((uchar_t *)ip6)[8] == 0x00 && 113 ((uchar_t *)ip6)[9] == 0x00 && 114 ((uchar_t *)ip6)[10] == 0xFF && 115 ((uchar_t *)ip6)[11] == 0xFF) { 116 p->sz = sizeof (in_addr_t); 117 p->ip4 = ((uint32_t *)ip6)[3]; 118 } else { 119 p->sz = sizeof (in6_addr_t); 120 } 121 p->ip6 = ip6; 122 p->port = port; 123 p->esip = esip; 124 p->ref = uid; 125 p->so = 0; 126 p->next = NULL; 127 } 128 129 return (p); 130 } 131 132 /* 133 * **************************************************************************** 134 * 135 * free_esi_portal: 136 * Free a list of portal of one ESI event. 137 * 138 * p - the ESI portal. 139 * 140 * **************************************************************************** 141 */ 142 static void 143 free_esi_portal( 144 esi_portal_t *p 145 ) 146 { 147 esi_portal_t *n; 148 149 while (p != NULL) { 150 n = p->next; 151 free(p->ip6); 152 free(p); 153 p = n; 154 } 155 } 156 157 /* 158 * **************************************************************************** 159 * 160 * ev_new: 161 * Make a new ESI event. 162 * 163 * uid - the Entity object UID. 164 * eid - the Entity object name. 165 * len - the length of the name. 166 * return - the ESI event. 167 * 168 * **************************************************************************** 169 */ 170 static ev_t * 171 ev_new( 172 uint32_t uid, 173 uchar_t *eid, 174 uint32_t len 175 ) 176 { 177 ev_t *ev; 178 179 ev = (ev_t *)malloc(sizeof (ev_t)); 180 if (ev != NULL) { 181 if (pthread_mutex_init(&ev->mtx, NULL) != 0 || 182 (ev->eid = (uchar_t *)malloc(len)) == NULL) { 183 free(ev); 184 return (NULL); 185 } 186 ev->uid = uid; 187 (void) strcpy((char *)ev->eid, (char *)eid); 188 ev->eid_len = len; 189 /* initialization time */ 190 ev->flags = EV_FLAG_INIT; 191 } 192 193 return (ev); 194 } 195 196 /* 197 * **************************************************************************** 198 * 199 * cb_portal_uids: 200 * Callback function which makes a copy of the portal child object 201 * UIDs from a Network Entity object. 202 * 203 * p1 - the Network Entity object. 204 * p2 - the lookup control data. 205 * return - the number of portal object UIDs. 206 * 207 * **************************************************************************** 208 */ 209 static int 210 cb_portal_uids( 211 void *p1, 212 void *p2 213 ) 214 { 215 isns_obj_t *obj = (isns_obj_t *)p1; 216 lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; 217 218 isns_attr_t *attr; 219 220 uint32_t *cuidp; 221 222 uint32_t num = 0; 223 uint32_t *p = NULL; 224 225 cuidp = get_child_t(obj, OBJ_PORTAL); 226 if (cuidp != NULL) { 227 p = (uint32_t *)malloc(*cuidp * sizeof (*p)); 228 if (p != NULL) { 229 num = *cuidp ++; 230 (void) memcpy(p, cuidp, num * sizeof (*p)); 231 lcp->data[1].ptr = (uchar_t *)p; 232 } 233 } 234 235 attr = &obj->attrs[ATTR_INDEX_ENTITY(ISNS_ENTITY_REG_PERIOD_ATTR_ID)]; 236 if (attr->tag != 0 && attr->value.ui != 0) { 237 lcp->data[2].ui = attr->value.ui; 238 } else { 239 /* just one second before the end of the world */ 240 lcp->data[2].ui = INFINITY - 1; 241 } 242 243 return (num); 244 } 245 246 /* 247 * **************************************************************************** 248 * 249 * cb_esi_portal: 250 * Callback function which gets ESI port number and ESI interval 251 * from a portal object. 252 * 253 * p1 - the Portal object. 254 * p2 - the lookup control data. 255 * return - the ESI interval. 256 * 257 * **************************************************************************** 258 */ 259 static int 260 cb_esi_portal( 261 void *p1, 262 void *p2 263 ) 264 { 265 uint32_t intval = 0; 266 267 isns_obj_t *obj; 268 lookup_ctrl_t *lcp; 269 270 in6_addr_t *ip; 271 uint32_t esip; 272 273 isns_attr_t *attr; 274 275 if (cb_clone_attrs(p1, p2) == 0) { 276 obj = (isns_obj_t *)p1; 277 lcp = (lookup_ctrl_t *)p2; 278 ip = lcp->data[1].ip; 279 esip = lcp->data[2].ui; 280 if (esip != 0) { 281 attr = &obj->attrs[ATTR_INDEX_PORTAL( 282 ISNS_PORTAL_PORT_ATTR_ID)]; 283 lcp->data[0].ui = attr->value.ui; 284 attr = &obj->attrs[ATTR_INDEX_PORTAL( 285 ISNS_ESI_INTERVAL_ATTR_ID)]; 286 if (attr->tag != 0 && attr->value.ui != 0) { 287 intval = attr->value.ui; 288 } else { 289 intval = DEFAULT_ESI_INTVAL; 290 } 291 } else { 292 free(ip); 293 } 294 } 295 296 return ((int)intval); 297 } 298 299 /* 300 * **************************************************************************** 301 * 302 * extract_esi_portal: 303 * Extract a list of portal which have an ESI port for an Entity. 304 * 305 * uid - the Entity object UID. 306 * intval - the ESI interval for returnning. 307 * return - the list of portals. 308 * 309 * **************************************************************************** 310 */ 311 static esi_portal_t * 312 extract_esi_portal( 313 uint32_t uid, 314 uint32_t *intval 315 ) 316 { 317 esi_portal_t *list = NULL; 318 esi_portal_t *p; 319 320 lookup_ctrl_t lc; 321 322 uint32_t num_of_portal; 323 uint32_t *portal_uids; 324 325 uint32_t intv; 326 327 /* prepare for looking up entity object */ 328 SET_UID_LCP(&lc, OBJ_ENTITY, uid); 329 lc.data[1].ptr = NULL; 330 lc.data[2].ui = INFINITY - 1; 331 332 /* get the array of the portal uid(s) */ 333 num_of_portal = (uint32_t)cache_lookup(&lc, NULL, cb_portal_uids); 334 portal_uids = (uint32_t *)lc.data[1].ptr; 335 *intval = lc.data[2].ui; 336 337 /* prepare for looking up portal object(s) */ 338 SET_UID_LCP(&lc, OBJ_PORTAL, 0); 339 lc.id[1] = ISNS_PORTAL_IP_ADDR_ATTR_ID; 340 lc.id[2] = ISNS_ESI_PORT_ATTR_ID; 341 FOR_EACH_OBJS(portal_uids, num_of_portal, uid, { 342 if (uid != 0) { 343 lc.data[0].ui = uid; 344 intv = cache_lookup(&lc, NULL, cb_esi_portal); 345 if (intv != 0) { 346 p = new_esi_portal(uid, 347 (in6_addr_t *)lc.data[1].ip, 348 lc.data[0].ui, lc.data[2].ui); 349 if (p != NULL) { 350 p->next = list; 351 list = p; 352 if (*intval > intv) { 353 *intval = intv; 354 } 355 } 356 } 357 } 358 }); 359 360 /* free up the portal uid array */ 361 free(portal_uids); 362 363 return (list); 364 } 365 366 /* 367 * **************************************************************************** 368 * 369 * ev_add: 370 * Add an ESI event. 371 * 372 * ev - the ESI event. 373 * init - 0: initialization time, otherwise not. 374 * return - error code. 375 * 376 * **************************************************************************** 377 */ 378 static int 379 ev_add( 380 ev_t *ev, 381 int init 382 ) 383 { 384 uint32_t intval; 385 esi_portal_t *p; 386 387 double rnd; 388 uint32_t t = 0; 389 390 /* get the portal(s) which are registered for ESI monitoring */ 391 /* and the second interval for ESI or registration expiration */ 392 p = extract_esi_portal(ev->uid, &intval); 393 ev->intval = intval; 394 if (p != NULL) { 395 ev->type = EV_ESI; 396 ev->portal = p; 397 /* avoid running everything at the same time */ 398 if (init != 0) { 399 /* generate random number within range (0, 1] */ 400 rnd = (rand() + 1) / (double)(RAND_MAX + 1); 401 t = (uint32_t)(intval * rnd); 402 } 403 } else { 404 /* no portal is registered for ESI monitoring, make */ 405 /* an entry for entity registration expiration */ 406 ev->type = EV_REG_EXP; 407 ev->portal = NULL; 408 if (init != 0) { 409 t = intval; 410 } 411 } 412 413 /* schedule the event */ 414 return (el_add(ev, t, NULL)); 415 } 416 417 /* 418 * global functions. 419 */ 420 421 /* 422 * **************************************************************************** 423 * 424 * sigalrm: 425 * The signal handler for SIGALRM, the ESI proc uses the SIGALRM 426 * for waking up to perform the client status inquery. 427 * 428 * sig - the signal. 429 * 430 * **************************************************************************** 431 */ 432 /*ARGSUSED*/ 433 void 434 sigalrm( 435 int sig 436 ) 437 { 438 /* wake up the idle */ 439 (void) pthread_mutex_lock(&idl_mtx); 440 wakeup = 1; /* wake up naturally */ 441 (void) pthread_cond_signal(&idl_cond); 442 (void) pthread_mutex_unlock(&idl_mtx); 443 } 444 445 /* 446 * **************************************************************************** 447 * 448 * esi_load: 449 * Load an ESI event from data store. 450 * 451 * uid - the Entity object UID. 452 * eid - the Entity object name. 453 * len - the length of the name. 454 * return - error code. 455 * 456 * **************************************************************************** 457 */ 458 int 459 esi_load( 460 uint32_t uid, 461 uchar_t *eid, 462 uint32_t len 463 ) 464 { 465 int ec = 0; 466 467 /* make a new event */ 468 ev_t *ev = ev_new(uid, eid, len); 469 470 /* put the new event to the list */ 471 if (ev != NULL) { 472 ev->next = ev_list; 473 ev_list = ev; 474 } else { 475 ec = ISNS_RSP_INTERNAL_ERROR; 476 } 477 478 return (ec); 479 } 480 481 /* 482 * **************************************************************************** 483 * 484 * verify_esi_portal: 485 * Verify ESI port and add the ESI entries after the ESI are loaded. 486 * 487 * return - error code. 488 * 489 * **************************************************************************** 490 */ 491 int 492 verify_esi_portal( 493 ) 494 { 495 int ec = 0; 496 497 ev_t *ev; 498 499 /* add each event from the list */ 500 while (ev_list != NULL && ec == 0) { 501 ev = ev_list; 502 ev_list = ev->next; 503 ev->next = NULL; 504 ec = ev_add(ev, 1); 505 } 506 507 return (ec); 508 } 509 510 /* 511 * **************************************************************************** 512 * 513 * esi_add: 514 * Add a new ESI event when a new Entity is registered. 515 * 516 * uid - the Entity object UID. 517 * eid - the Entity object name. 518 * len - the length of the name. 519 * return - error code. 520 * 521 * **************************************************************************** 522 */ 523 int 524 esi_add( 525 uint32_t uid, 526 uchar_t *eid, 527 uint32_t len 528 ) 529 { 530 int ec = 0; 531 532 /* make a new event */ 533 ev_t *ev = ev_new(uid, eid, len); 534 535 if (ev != NULL) { 536 /* interrupt idle */ 537 ev->flags |= EV_FLAG_WAKEUP; 538 ec = ev_add(ev, 0); 539 } else { 540 ec = ISNS_RSP_INTERNAL_ERROR; 541 } 542 543 return (ec); 544 } 545 546 /* 547 * **************************************************************************** 548 * 549 * esi_remove: 550 * Remove an ESI event immediately. 551 * 552 * uid - the Entity object UID. 553 * return - always successful. 554 * 555 * **************************************************************************** 556 */ 557 int 558 esi_remove( 559 uint32_t uid 560 ) 561 { 562 (void) el_remove(uid, 0, 0); 563 564 return (0); 565 } 566 567 /* 568 * **************************************************************************** 569 * 570 * esi_remove_obj: 571 * Update an ESI event when a Entity object or a Portal object is 572 * removed from server. If the object is being removed because of 573 * ESI failure, the ESI event will be removed with a pending time, 574 * otherwise, the ESI will be removed immediately. 575 * 576 * obj - the object being removed. 577 * pending - the pending flag. 578 * return - always successful. 579 * 580 * **************************************************************************** 581 */ 582 int 583 esi_remove_obj( 584 const isns_obj_t *obj, 585 int pending 586 ) 587 { 588 uint32_t puid, uid; 589 590 switch (obj->type) { 591 case OBJ_PORTAL: 592 puid = get_parent_uid(obj); 593 uid = get_obj_uid(obj); 594 break; 595 case OBJ_ENTITY: 596 puid = get_obj_uid(obj); 597 uid = 0; 598 break; 599 default: 600 puid = 0; 601 break; 602 } 603 604 if (puid != 0) { 605 (void) el_remove(puid, uid, pending); 606 } 607 608 return (0); 609 } 610 611 /* 612 * **************************************************************************** 613 * 614 * get_stopwatch: 615 * Get the stopwatch. It might need to signal the condition to 616 * wake up the idle so the stopwatch gets updated. 617 * 618 * flag - wake up flag. 619 * return - the stopwatch. 620 * 621 * **************************************************************************** 622 */ 623 uint32_t 624 get_stopwatch( 625 int flag 626 ) 627 { 628 uint32_t t; 629 630 /* not re-schedule, wake up idle */ 631 (void) pthread_mutex_lock(&idl_mtx); 632 if (flag != 0) { 633 wakeup = 2; /* wake up manually */ 634 (void) pthread_cond_signal(&idl_cond); 635 } else { 636 wakeup = 0; /* clear previous interruption */ 637 } 638 (void) pthread_mutex_unlock(&idl_mtx); 639 640 /* get most current time */ 641 (void) pthread_mutex_lock(&stw_mtx); 642 t = stopwatch; 643 (void) pthread_mutex_unlock(&stw_mtx); 644 645 return (t); 646 } 647 648 /* 649 * **************************************************************************** 650 * 651 * ev_intval: 652 * Get the time interval of an ESI event. 653 * 654 * p - the ESI event. 655 * return - the time interval. 656 * 657 * **************************************************************************** 658 */ 659 uint32_t 660 ev_intval( 661 void *p 662 ) 663 { 664 return (((ev_t *)p)->intval); 665 } 666 667 /* 668 * **************************************************************************** 669 * 670 * ev_match: 671 * Check the ESI event maching an Entity object. 672 * 673 * p - the ESI event. 674 * uid - the Entity object UID. 675 * return - 1: match, otherwise not. 676 * 677 * **************************************************************************** 678 */ 679 int 680 ev_match( 681 void *p, 682 uint32_t uid 683 ) 684 { 685 if (((ev_t *)p)->uid == uid) { 686 return (1); 687 } else { 688 return (0); 689 } 690 } 691 692 /* 693 * **************************************************************************** 694 * 695 * ev_remove: 696 * Remove a portal or an ESI event. If all of ESI portal has been 697 * removed, the ESI event will be marked as removal pending, which 698 * will result in removing the Entity object after the pending time. 699 * 700 * p - the ESI event. 701 * portal_uid - the Portal object UID. 702 * flag - 0: the ESI is currently in use, otherwise it is scheduled. 703 * pending - flag for the ESI removal pending. 704 * return - 0: the ESI is physically removed, otherwise not. 705 * 706 * **************************************************************************** 707 */ 708 int 709 ev_remove( 710 void *p, 711 uint32_t portal_uid, 712 int flag, 713 int pending 714 ) 715 { 716 ev_t *ev = (ev_t *)p; 717 esi_portal_t **pp, *portal; 718 719 int has_portal = 0; 720 int state; 721 722 /* remove one portal only */ 723 if (portal_uid != 0) { 724 pp = &ev->portal; 725 portal = *pp; 726 while (portal != NULL) { 727 /* found the match portal */ 728 if (portal->ref == portal_uid) { 729 /* mark it as removed */ 730 portal->ref = 0; 731 if (flag != 0) { 732 /* not in use, remove it physically */ 733 *pp = portal->next; 734 portal->next = NULL; 735 free_esi_portal(portal); 736 } else { 737 pp = &portal->next; 738 } 739 } else { 740 /* one or more esi portals are available */ 741 if (portal->ref != 0) { 742 has_portal = 1; 743 } 744 pp = &portal->next; 745 } 746 portal = *pp; 747 } 748 } 749 750 /* no portal available */ 751 if (has_portal == 0) { 752 state = (pending << 1) | flag; 753 switch (state) { 754 case 0x0: 755 /* mark the event as removed */ 756 ev->flags |= EV_FLAG_REMOVE; 757 isnslog(LOG_DEBUG, "ev_remove", 758 "%s [%d] is marked as removed.", 759 ev->type == EV_ESI ? "ESI" : "REG_EXP", 760 ev->uid); 761 break; 762 case 0x1: 763 /* physically remove the event */ 764 ev_free(ev); 765 break; 766 case 0x2: 767 case 0x3: 768 /* mark the event as removal pending */ 769 isnslog(LOG_DEBUG, "ev_remove", 770 "%s [%d] is marked as removal pending.", 771 ev->type == EV_ESI ? "ESI" : "REG_EXP", 772 ev->uid); 773 ev->flags |= EV_FLAG_REM_P1; 774 has_portal = 1; 775 break; 776 default: 777 break; 778 } 779 } else { 780 isnslog(LOG_DEBUG, "ev_remove", "%s [%d] removed portal %d.", 781 ev->type == EV_ESI ? "ESI" : "REG_EXP", 782 ev->uid, portal_uid); 783 } 784 785 return (has_portal); 786 } 787 788 /* 789 * **************************************************************************** 790 * 791 * ev_free: 792 * Free an ESI event. 793 * 794 * p - the ESI event. 795 * 796 * **************************************************************************** 797 */ 798 void 799 ev_free( 800 void *p 801 ) 802 { 803 ev_t *ev = (ev_t *)p; 804 805 /* free up all of portals */ 806 free_esi_portal(ev->portal); 807 808 isnslog(LOG_DEBUG, "ev_free", 809 "%s [%d] is physically removed.", 810 ev->type == EV_ESI ? "ESI" : "REG_EXP", 811 ev->uid); 812 813 free(ev->eid); 814 815 /* free the event */ 816 free(ev); 817 } 818 819 /* 820 * **************************************************************************** 821 * 822 * evf_init: 823 * Check the initial flag of an ESI event. 824 * 825 * p - the ESI event. 826 * return - 0: not initial, otherwise yes. 827 * 828 * **************************************************************************** 829 */ 830 int 831 evf_init( 832 void *p 833 ) 834 { 835 return (((ev_t *)p)->flags & EV_FLAG_INIT); 836 } 837 838 /* 839 * **************************************************************************** 840 * 841 * evf_again: 842 * Check the again flag of an ESI event. 843 * (this flag might be eliminated and use the init flag.) 844 * 845 * p - the ESI event. 846 * return - 0: not again, otherwise yes. 847 * 848 * **************************************************************************** 849 */ 850 int 851 evf_again( 852 void *p 853 ) 854 { 855 return (((ev_t *)p)->flags & EV_FLAG_AGAIN); 856 } 857 858 /* 859 * **************************************************************************** 860 * 861 * evf_wakeup: 862 * Check the wakeup flag of an ESI event. The idle might need to 863 * wake up before the event is scheduled. 864 * 865 * p - the ESI event. 866 * return - 0: no wakeup, otherwise yes. 867 * 868 * **************************************************************************** 869 */ 870 int 871 evf_wakeup( 872 void *p 873 ) 874 { 875 return (((ev_t *)p)->flags & EV_FLAG_WAKEUP); 876 } 877 878 /* 879 * **************************************************************************** 880 * 881 * evf_rem: 882 * Check the removal flag of an ESI event. The ESI entry might be 883 * marked as removal. 884 * 885 * p - the ESI event. 886 * return - 0: not removed, otherwise yes. 887 * 888 * **************************************************************************** 889 */ 890 int 891 evf_rem( 892 void *p 893 ) 894 { 895 return (((ev_t *)p)->flags & EV_FLAG_REMOVE); 896 } 897 898 /* 899 * **************************************************************************** 900 * 901 * evf_rem_pending: 902 * Check the removal pending flag of an ESI event. The ESI entry 903 * might be marked as removal pending. If it is, we will switch the 904 * event type and change the time interval. 905 * 906 * p - the ESI event. 907 * return - 0: not removal pending, otherwise yes. 908 * 909 * **************************************************************************** 910 */ 911 int 912 evf_rem_pending( 913 void *p 914 ) 915 { 916 ev_t *ev = (ev_t *)p; 917 if ((ev->flags & EV_FLAG_REM_P) != 0) { 918 if (ev->type != EV_REG_EXP) { 919 isnslog(LOG_DEBUG, "ev_rem_pending", 920 "%s [%d] is changed to REG_EXP.", 921 ev->type == EV_ESI ? "ESI" : "REG_EXP", 922 ev->uid); 923 ev->type = EV_REG_EXP; 924 ev->intval *= 2; /* after 2 ESI interval */ 925 } 926 return (1); 927 } 928 929 return (0); 930 } 931 932 /* 933 * **************************************************************************** 934 * 935 * evf_zero: 936 * Reset the event flag. 937 * 938 * p - the ESI event. 939 * 940 * **************************************************************************** 941 */ 942 void 943 evf_zero( 944 void *p 945 ) 946 { 947 ev_t *ev = (ev_t *)p; 948 949 /* not acutally clear it, need to set again flag */ 950 /* and keep the removal pending flag */ 951 ev->flags = EV_FLAG_AGAIN | (ev->flags & EV_FLAG_REM_P); 952 } 953 954 /* 955 * **************************************************************************** 956 * 957 * evl_append: 958 * Append an ESI event to the list, the list contains all of 959 * ESI events which are being processed at present. 960 * 961 * p - the ESI event. 962 * 963 * **************************************************************************** 964 */ 965 void 966 evl_append( 967 void *p 968 ) 969 { 970 ev_t *ev; 971 972 ev = (ev_t *)p; 973 ev->next = ev_list; 974 ev_list = ev; 975 } 976 977 /* 978 * **************************************************************************** 979 * 980 * evl_strip: 981 * Strip off an ESI event from the list after the event is being 982 * processed, it will be scheduled in the scheduler. 983 * 984 * p - the ESI event. 985 * 986 * **************************************************************************** 987 */ 988 void 989 evl_strip( 990 void *p 991 ) 992 { 993 ev_t **evp = &ev_list; 994 ev_t *ev = *evp; 995 996 while (ev != NULL) { 997 if (ev == p) { 998 *evp = ev->next; 999 break; 1000 } 1001 evp = &ev->next; 1002 ev = *evp; 1003 } 1004 } 1005 1006 /* 1007 * **************************************************************************** 1008 * 1009 * evl_remove: 1010 * Remove an ESI event or a portal of an ESI event from the event list. 1011 * 1012 * id1 - the Entity object UID. 1013 * id2 - the Portal object UID. 1014 * pending - the pending flag. 1015 * return - 1: found a match event, otherwise not. 1016 * 1017 * **************************************************************************** 1018 */ 1019 int 1020 evl_remove( 1021 uint32_t id1, 1022 uint32_t id2, 1023 int pending 1024 ) 1025 { 1026 ev_t *ev = ev_list; 1027 1028 while (ev != NULL) { 1029 /* found it */ 1030 if (ev_match(ev, id1) != 0) { 1031 /* lock the event */ 1032 (void) pthread_mutex_lock(&ev->mtx); 1033 /* mark it as removed */ 1034 (void) ev_remove(ev, id2, 0, pending); 1035 /* unlock the event */ 1036 (void) pthread_mutex_unlock(&ev->mtx); 1037 /* tell caller removal is done */ 1038 return (1); 1039 } 1040 ev = ev->next; 1041 } 1042 1043 /* not found it */ 1044 return (0); 1045 } 1046 1047 #define ALARM_MAX (21427200) 1048 1049 /* 1050 * **************************************************************************** 1051 * 1052 * idle: 1053 * Idle for certain amount of time or a wakeup signal is recieved. 1054 * 1055 * t - the idle time. 1056 * return - the time that idle left. 1057 * 1058 * **************************************************************************** 1059 */ 1060 static int 1061 idle( 1062 uint32_t t 1063 ) 1064 { 1065 uint32_t t1, t2, t3 = 0; 1066 int idl_int = 0; 1067 1068 /* hold the mutex for stopwatch update */ 1069 (void) pthread_mutex_lock(&stw_mtx); 1070 1071 do { 1072 if (t > ALARM_MAX) { 1073 t1 = ALARM_MAX; 1074 } else { 1075 t1 = t; 1076 } 1077 1078 /* start alarm */ 1079 (void) alarm(t1); 1080 1081 /* hold the mutex for idle condition */ 1082 (void) pthread_mutex_lock(&idl_mtx); 1083 1084 /* wait on condition variable to wake up idle */ 1085 while (wakeup == 0) { 1086 (void) pthread_cond_wait(&idl_cond, &idl_mtx); 1087 } 1088 if (wakeup == 2) { 1089 idl_int = 1; 1090 } 1091 /* clean wakeup flag */ 1092 wakeup = 0; 1093 1094 /* release the mutex for idle condition */ 1095 (void) pthread_mutex_unlock(&idl_mtx); 1096 1097 /* stop alarm */ 1098 t2 = alarm(0); 1099 1100 /* seconds actually slept */ 1101 t3 += t1 - t2; 1102 t -= t3; 1103 } while (t > 0 && idl_int == 0); 1104 1105 /* increate the stopwatch by the actually slept time */ 1106 stopwatch += t3; 1107 1108 /* release the mutex after stopwatch is updated */ 1109 (void) pthread_mutex_unlock(&stw_mtx); 1110 1111 /* return the amount of time which is not slept */ 1112 return (t); 1113 } 1114 1115 /* 1116 * **************************************************************************** 1117 * 1118 * ev_ex: 1119 * Execute an event. To inquiry the client status or 1120 * perform registration expiration. 1121 * 1122 * ev - the event. 1123 * 1124 * **************************************************************************** 1125 */ 1126 static void 1127 ev_ex( 1128 ev_t *ev 1129 ) 1130 { 1131 pthread_t tid; 1132 1133 switch (ev->type) { 1134 case EV_ESI: 1135 if (pthread_create(&tid, NULL, 1136 esi_monitor, (void *)ev) != 0) { 1137 isnslog(LOG_DEBUG, "ev_ex", "pthread_create() failed."); 1138 /* reschedule for next occurence */ 1139 (void) el_add(ev, 0, NULL); 1140 } else { 1141 /* increase the thread ref count */ 1142 inc_thr_count(); 1143 } 1144 break; 1145 case EV_REG_EXP: 1146 (void) queue_msg_set(sys_q, REG_EXP, (void *)ev); 1147 break; 1148 default: 1149 break; 1150 } 1151 } 1152 1153 /* 1154 * **************************************************************************** 1155 * 1156 * esi_proc: 1157 * ESI thread entry, which: 1158 * 1: fetch an event from schedule, 1159 * 2: idle for some time, 1160 * 3: execute the event or re-schedule it, 1161 * 4: repeat from step 1 before server is being shutdown. 1162 * 1163 * arg - the thread argument. 1164 * 1165 * **************************************************************************** 1166 */ 1167 /*ARGSUSED*/ 1168 void * 1169 esi_proc( 1170 void *arg 1171 ) 1172 { 1173 uint32_t t, t1, pt; 1174 ev_t *ev; 1175 1176 void *evp; 1177 1178 while (time_to_exit == B_FALSE) { 1179 ev = (ev_t *)el_first(&pt); 1180 1181 /* caculate the idle time */ 1182 if (ev != NULL) { 1183 if (pt > stopwatch) { 1184 t = pt - stopwatch; 1185 } else { 1186 t = 0; 1187 } 1188 } else { 1189 t = INFINITY; 1190 } 1191 1192 do { 1193 /* block for a certain amount of time */ 1194 if (t > 0) { 1195 isnslog(LOG_DEBUG, "esi_proc", 1196 "idle for %d seconds.", t); 1197 t1 = idle(t); 1198 } else { 1199 t1 = 0; 1200 } 1201 if (t1 > 0) { 1202 isnslog(LOG_DEBUG, "esi_proc", 1203 "idle interrupted after idle for " 1204 "%d seconds.", t - t1); 1205 } 1206 if (time_to_exit != B_FALSE) { 1207 ev = NULL; /* force break */ 1208 } else if (ev != NULL) { 1209 if (t1 > 0) { 1210 /* not naturally waken up */ 1211 /* reschedule current event */ 1212 evp = NULL; 1213 (void) el_add(ev, pt, &evp); 1214 ev = (ev_t *)evp; 1215 t = t1; 1216 } else { 1217 /* excute */ 1218 isnslog(LOG_DEBUG, "esi_proc", 1219 "excute the cron job[%d].", 1220 ev->uid); 1221 ev_ex(ev); 1222 ev = NULL; 1223 } 1224 } 1225 } while (ev != NULL); 1226 } 1227 1228 return (NULL); 1229 } 1230 1231 /* 1232 * **************************************************************************** 1233 * 1234 * esi_ping: 1235 * Ping the client with the ESI retry threshold for status inquiry. 1236 * 1237 * so - the socket descriptor. 1238 * pdu - the ESI packet. 1239 * pl - the length of packet. 1240 * return - 1: status inquired, otherwise not. 1241 * 1242 * **************************************************************************** 1243 */ 1244 static int 1245 esi_ping( 1246 int so, 1247 isns_pdu_t *pdu, 1248 size_t pl 1249 ) 1250 { 1251 int try_cnt = 0; 1252 isns_pdu_t *rsp = NULL; 1253 size_t rsp_sz; 1254 1255 int alive = 0; 1256 1257 do { 1258 if (isns_send_pdu(so, pdu, pl) == 0) { 1259 if (isns_rcv_pdu(so, &rsp, &rsp_sz, 1260 ISNS_RCV_SHORT_TIMEOUT) > 0) { 1261 #ifdef DEBUG 1262 dump_pdu1(rsp); 1263 #endif 1264 alive = 1; 1265 break; 1266 } 1267 } else { 1268 /* retry after 1 second */ 1269 (void) sleep(1); 1270 } 1271 try_cnt ++; 1272 } while (try_cnt < esi_threshold); 1273 1274 if (rsp != NULL) { 1275 free(rsp); 1276 } 1277 1278 return (alive); 1279 } 1280 1281 /* 1282 * **************************************************************************** 1283 * 1284 * esi_monitor: 1285 * Child thread for client status mornitoring. 1286 * 1287 * arg - the ESI event. 1288 * 1289 * **************************************************************************** 1290 */ 1291 static void * 1292 esi_monitor( 1293 void *arg 1294 ) 1295 { 1296 ev_t *ev = (ev_t *)arg; 1297 1298 esi_portal_t *p; 1299 int so; 1300 1301 isns_pdu_t *pdu = NULL; 1302 size_t sz; 1303 size_t pl; 1304 size_t half; 1305 1306 time_t t; 1307 1308 int feedback; 1309 1310 /* lock the event for esi monitoring */ 1311 (void) pthread_mutex_lock(&ev->mtx); 1312 1313 if (evf_rem(ev) != 0) { 1314 goto mon_done; 1315 } else if (evf_rem_pending(ev) != 0) { 1316 goto mon_done; 1317 } 1318 1319 /* timestamp */ 1320 t = time(NULL); 1321 1322 /* allocate ESI PDU */ 1323 if (pdu_reset_esi(&pdu, &pl, &sz) != 0 || 1324 pdu_add_tlv(&pdu, &pl, &sz, 1325 ISNS_TIMESTAMP_ATTR_ID, 8, (void *)&t, 1) != 0 || 1326 pdu_add_tlv(&pdu, &pl, &sz, 1327 ISNS_EID_ATTR_ID, ev->eid_len, (void *)ev->eid, 0) != 0) { 1328 /* no memory, will retry later */ 1329 goto mon_done; 1330 } 1331 1332 /* set pdu head */ 1333 pdu->version = htons((uint16_t)ISNSP_VERSION); 1334 pdu->func_id = htons((uint16_t)ISNS_ESI); 1335 pdu->xid = htons(get_server_xid()); 1336 1337 /* keep the current lenght of the playload */ 1338 half = pl; 1339 1340 p = ev->portal; 1341 while (p != NULL) { 1342 if (p->ref != 0 && 1343 /* skip IPv6 portal */ 1344 p->sz != sizeof (in6_addr_t) && 1345 pdu_add_tlv(&pdu, &pl, &sz, 1346 ISNS_PORTAL_IP_ADDR_ATTR_ID, 1347 sizeof (in6_addr_t), (void *)p->ip6, 0) == 0 && 1348 pdu_add_tlv(&pdu, &pl, &sz, 1349 ISNS_PORTAL_PORT_ATTR_ID, 1350 4, (void *)p->port, 0) == 0) { 1351 /* connect once */ 1352 so = connect_to(p->sz, p->ip4, p->ip6, p->esip); 1353 if (so != -1) { 1354 feedback = esi_ping(so, pdu, pl); 1355 (void) close(so); 1356 /* p->so = so; */ 1357 } else { 1358 /* cannot connect, portal is dead */ 1359 feedback = 0; 1360 } 1361 if (feedback == 0) { 1362 isnslog(LOG_DEBUG, "esi_monitor", 1363 "ESI ping failed."); 1364 (void) queue_msg_set(sys_q, DEAD_PORTAL, 1365 (void *)p->ref); 1366 } else { 1367 goto mon_done; 1368 } 1369 } 1370 pl = half; 1371 p = p->next; 1372 } 1373 1374 mon_done: 1375 /* unlock the event after esi monitoring is done */ 1376 (void) pthread_mutex_unlock(&ev->mtx); 1377 1378 /* clean up pdu */ 1379 if (pdu != NULL) { 1380 free(pdu); 1381 } 1382 1383 /* set reschedule flags */ 1384 ev->flags |= EV_FLAG_WAKEUP; 1385 1386 /* reschedule for next occurence */ 1387 (void) el_add(ev, 0, NULL); 1388 1389 /* decrease the thread ref count */ 1390 dec_thr_count(); 1391 1392 return (NULL); 1393 } 1394 1395 /* 1396 * **************************************************************************** 1397 * 1398 * portal_dies: 1399 * Handles the dead portal that ESI detected. 1400 * 1401 * uid - the Portal object UID. 1402 * 1403 * **************************************************************************** 1404 */ 1405 void 1406 portal_dies( 1407 uint32_t uid 1408 ) 1409 { 1410 int ec = 0; 1411 1412 lookup_ctrl_t lc; 1413 1414 /* prepare the lookup control for deregistration */ 1415 SET_UID_LCP(&lc, OBJ_PORTAL, uid); 1416 1417 /* lock the cache for object deregistration */ 1418 (void) cache_lock_write(); 1419 1420 /* deregister the portal */ 1421 ec = dereg_object(&lc, 1); 1422 1423 /* unlock cache and sync with data store */ 1424 (void) cache_unlock_sync(ec); 1425 } 1426 1427 /* 1428 * **************************************************************************** 1429 * 1430 * portal_dies: 1431 * Handles the Entity registration expiration. 1432 * 1433 * p - the ESI event. 1434 * 1435 * **************************************************************************** 1436 */ 1437 void 1438 reg_expiring( 1439 void *p 1440 ) 1441 { 1442 int ec = 0; 1443 ev_t *ev = (ev_t *)p; 1444 lookup_ctrl_t lc; 1445 1446 /* prepare the lookup control for deregistration */ 1447 SET_UID_LCP(&lc, OBJ_ENTITY, ev->uid); 1448 1449 /* lock the cache for object deregistration */ 1450 (void) cache_lock_write(); 1451 1452 if (evf_rem(ev) == 0) { 1453 /* deregister the entity */ 1454 ec = dereg_object(&lc, 0); 1455 1456 /* unlock cache and sync with data store */ 1457 ec = cache_unlock_sync(ec); 1458 1459 if (ec == 0) { 1460 /* successfuk, mark ev as removed */ 1461 ev->flags |= EV_FLAG_REMOVE; 1462 } else { 1463 /* failed, retry after 3 mintues */ 1464 ev->intval = 3 * 60; 1465 isnslog(LOG_DEBUG, "reg_expiring", 1466 "dereg failed, retry after 3 mintues."); 1467 } 1468 } else { 1469 /* ev is marked as removed, no need to dereg */ 1470 (void) cache_unlock_nosync(); 1471 } 1472 1473 /* reschedule it for next occurence */ 1474 (void) el_add(ev, 0, NULL); 1475 } 1476