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 *
new_esi_portal(uint32_t uid,in6_addr_t * ip6,uint32_t port,uint32_t esip)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
free_esi_portal(esi_portal_t * p)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 *
ev_new(uint32_t uid,uchar_t * eid,uint32_t len)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
cb_portal_uids(void * p1,void * p2)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
cb_esi_portal(void * p1,void * p2)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 *
extract_esi_portal(uint32_t uid,uint32_t * intval)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
ev_add(ev_t * ev,int init)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
sigalrm(int sig)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
esi_load(uint32_t uid,uchar_t * eid,uint32_t len)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
verify_esi_portal()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
esi_add(uint32_t uid,uchar_t * eid,uint32_t len)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
esi_remove(uint32_t uid)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
esi_remove_obj(const isns_obj_t * obj,int pending)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
get_stopwatch(int flag)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
ev_intval(void * p)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
ev_match(void * p,uint32_t uid)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
ev_remove(void * p,uint32_t portal_uid,int flag,int pending)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
ev_free(void * p)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
evf_init(void * p)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
evf_again(void * p)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
evf_wakeup(void * p)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
evf_rem(void * p)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
evf_rem_pending(void * p)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
evf_zero(void * p)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
evl_append(void * p)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
evl_strip(void * p)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
evl_remove(uint32_t id1,uint32_t id2,int pending)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
idle(uint32_t t)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
ev_ex(ev_t * ev)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 *
esi_proc(void * arg)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
esi_ping(int so,isns_pdu_t * pdu,size_t pl)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 *
esi_monitor(void * arg)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
portal_dies(uint32_t uid)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
reg_expiring(void * p)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