Line data Source code
1 : /*
2 : * Copyright (c) 2017 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "gmpx_basic_types.h"
6 : #include "gmp.h"
7 : #include "gmp_intf.h"
8 : #include "gmpx_environment.h"
9 : #include "gmp_map.h"
10 :
11 : static inline gmp_proto
12 4016 : mc_af_to_gmp_proto (const mc_af mcaf)
13 : {
14 4016 : switch (mcaf) {
15 4016 : case MCAST_AF_IPV4:
16 4016 : return GMP_PROTO_IGMP;
17 0 : case MCAST_AF_IPV6:
18 0 : return GMP_PROTO_MLD;
19 0 : default:
20 0 : assert(FALSE);
21 : }
22 : return GMP_PROTO_IGMP; /* Statement added to avoid compiler warnings. */
23 : }
24 :
25 : /* Statics... */
26 :
27 : static boolean initialized = FALSE;
28 : static block_t gmpx_timer_block;
29 : static task_timer_root *gmpx_timer_roots[GMP_NUM_TIMER_GROUPS][GMP_NUM_PROTOS];
30 :
31 :
32 : /*
33 : * gmpx_smear_timer_group
34 : *
35 : * Smear the timers for a protocol and group.
36 : */
37 : void
38 0 : gmpx_smear_timer_group (gmp_proto proto, gmp_timer_group group)
39 : {
40 : /* Smear the timers. */
41 :
42 0 : task_timer_smear_auto_parent_timers(gmpx_timer_roots[group][proto]);
43 0 : }
44 :
45 :
46 : /*
47 : * gmpx_destroy_timer
48 : *
49 : * Get rid of a timer.
50 : */
51 : void
52 4141 : gmpx_destroy_timer (gmpx_timer *timer)
53 : {
54 4141 : if (!timer)
55 125 : return;
56 :
57 : /* Free the rpd timer. */
58 :
59 4016 : task_timer_delete(timer->gmpxt_timer);
60 :
61 : /* Free the block. */
62 :
63 4016 : task_block_free(gmpx_timer_block, timer);
64 : }
65 :
66 :
67 : /*
68 : * gmpx_start_timer
69 : *
70 : * Start a timer.
71 : */
72 : void
73 3131 : gmpx_start_timer (gmpx_timer *timer, uint32_t ivl, uint32_t jitter_pct)
74 : {
75 : utime_t long_ivl;
76 :
77 : /* Convert the timer interval to a utime_t. */
78 :
79 3131 : long_ivl.ut_sec = ivl / MSECS_PER_SEC;
80 3131 : long_ivl.ut_usec = (ivl % MSECS_PER_SEC) * USECS_PER_MSEC;
81 :
82 : /* Start the timer. */
83 :
84 3131 : task_timer_uset_alt_root_auto_parent_oneshot(
85 3131 : gmpx_timer_roots[timer->gmpxt_group][timer->gmpxt_proto],
86 : timer->gmpxt_timer, &long_ivl, jitter_pct);
87 3131 : }
88 :
89 :
90 : /*
91 : * gmpx_timer_expiry
92 : *
93 : * Handle a timer expiry.
94 : */
95 : static void
96 1094 : gmpx_timer_expiry (task_timer *rpd_timer, time_t tm UNUSED)
97 : {
98 : gmpx_timer *timer;
99 :
100 : /* Stop the timer and then call the caller's callback. */
101 :
102 1094 : task_timer_reset(rpd_timer);
103 1094 : timer = task_timer_data(rpd_timer);
104 :
105 1094 : if (timer->gmpxt_callback)
106 1094 : (*timer->gmpxt_callback)(timer, timer->gmpxt_context);
107 1094 : }
108 :
109 :
110 : /*
111 : * gmpx_create_grouped_timer
112 : *
113 : * Create a timer as part of a group.
114 : *
115 : * Returns a pointer to a timer, or NULL if out of memory.
116 : */
117 : gmpx_timer *
118 4016 : gmpx_create_grouped_timer (gmp_timer_group group, void *inst_context,
119 : const char *name, gmpx_timer_callback callback,
120 : void *timer_context)
121 : {
122 : gmpx_timer *timer;
123 : mc_af af;
124 : mgm_global_data *gd;
125 : gmp_timer_group group_num;
126 : gmp_proto proto;
127 :
128 4016 : gd = inst_context;
129 4016 : af = gd->mgm_gd_af;
130 :
131 : /* If we haven't initialized, do so now. */
132 :
133 4016 : if (!initialized) {
134 125 : gmpx_timer_block = task_block_init(sizeof(gmpx_timer), "GMP timer");
135 375 : for (proto = 0; proto < GMP_NUM_PROTOS; proto++) {
136 750 : for (group_num = 0; group_num < GMP_NUM_TIMER_GROUPS;
137 500 : group_num++) {
138 500 : gmpx_timer_roots[group_num][proto] =
139 500 : task_timer_get_auto_parent_root();
140 : }
141 : }
142 125 : initialized = TRUE;
143 : }
144 :
145 : /* Allocate the timer block. */
146 :
147 4016 : timer = task_block_alloc(gmpx_timer_block);
148 4016 : if (timer) {
149 :
150 : /* Got one. Initialize the block. */
151 :
152 4016 : timer->gmpxt_timer =
153 4016 : task_timer_create_idle_leaf(gd->tp, name, 0, NULL,
154 : gmpx_timer_expiry, timer);
155 4016 : timer->gmpxt_context = timer_context;
156 4016 : timer->gmpxt_callback = callback;
157 4016 : timer->gmpxt_group = group;
158 4016 : timer->gmpxt_proto = mc_af_to_gmp_proto(af);
159 : }
160 :
161 4016 : return timer;
162 : }
163 :
164 :
165 : /*
166 : * gmpx_create_timer
167 : *
168 : * Create a timer.
169 : *
170 : * Returns a pointer to a timer, or NULL if out of memory.
171 : */
172 : gmpx_timer *
173 2308 : gmpx_create_timer (void *inst_context, const char *name,
174 : gmpx_timer_callback callback, void *timer_context)
175 : {
176 2308 : return gmpx_create_grouped_timer(GMP_TIMER_GROUP_DEFAULT, inst_context,
177 : name, callback, timer_context);
178 : }
179 :
180 :
181 : /*
182 : * gmpx_timer_time_remaining
183 : *
184 : * Returns the time remaining before expiration of a timer, in millseconds.
185 : */
186 : uint32_t
187 191 : gmpx_timer_time_remaining (gmpx_timer *timer)
188 : {
189 : utime_t time_left_usec;
190 : uint32_t time_left_msec;
191 :
192 191 : if (!timer)
193 0 : return 0;
194 :
195 : /* Get the remaining time. */
196 :
197 191 : task_timer_utime_left(timer->gmpxt_timer, &time_left_usec);
198 191 : time_left_msec = ((time_left_usec.ut_sec * MSECS_PER_SEC) +
199 191 : (time_left_usec.ut_usec / USECS_PER_MSEC));
200 :
201 191 : return time_left_msec;
202 : }
203 :
204 :
205 : /*
206 : * gmpx_timer_running
207 : *
208 : * Returns TRUE if the timer is running, or FALSE if it is not.
209 : */
210 : boolean
211 757 : gmpx_timer_running (gmpx_timer *timer)
212 : {
213 757 : if (!timer)
214 0 : return FALSE;
215 :
216 757 : return task_timer_running(timer->gmpxt_timer);
217 : }
218 :
219 :
220 : /*
221 : * gmpx_stop_timer
222 : *
223 : * Stop a timer.
224 : */
225 : void
226 125 : gmpx_stop_timer (gmpx_timer *timer)
227 : {
228 125 : if (!timer)
229 0 : return;
230 :
231 125 : task_timer_reset(timer->gmpxt_timer);
232 : }
233 :
|