Line data Source code
1 : /* $Id: gmpr_private.h 514187 2012-05-06 12:25:25Z ib-builder $
2 : *
3 : * gmpr_private.h - Private definitions for GMP Router support
4 : *
5 : * Dave Katz, March 2008
6 : *
7 : * Copyright (c) 2008, Juniper Networks, Inc.
8 : * All rights reserved.
9 : */
10 :
11 : #ifndef __GMPR_PRIVATE_H__
12 : #define __GMPR_PRIVATE_H__
13 :
14 : /*
15 : * This module defines the private data structures for GMP router support.
16 : * This file should only be used by the gmp_router code.
17 : */
18 :
19 :
20 : /*
21 : * Data Structure Overview
22 : *
23 : * The primary data structure is the instance. There are one or more of
24 : * these. An instance is a grouping of interfaces under a protocol (IGMP
25 : * or MLD). Multiple instances are required if both IGMP and MLD are
26 : * running. Multiple instances within a protocol can be used by clients
27 : * if desired (this is likely to be useful only if there are different
28 : * clients for some interfaces and they have significantly different needs.)
29 : *
30 : * An interface structure is created for each interface. The same structure
31 : * is used for both the input (protocol) and output (data forwarding) roles.
32 : * For generic IGMP, the same interface acts as input and output, but if
33 : * OIF mapping is taking place, the protocol may run on one interface and
34 : * the data delivered on another. The interface is bound to an instance.
35 : *
36 : * The group state is kept in several forms. The input state on an interface
37 : * corresponds to the aggregation of all host state on an interface. This
38 : * is built according to the protocol spec.
39 : *
40 : * Output state is kept on the output interface. This corresponds to
41 : * the forwarding state being built for the interface. In generic
42 : * IGMP this is semantically identical to the input state, but if OIF
43 : * mapping is used it will differ, and it represents the aggregation
44 : * of all input state that is mapped to that output interface.
45 : *
46 : * Finally, if host tracking is taking place, state is built on a
47 : * per-host basis. This is used to allow for immediate leaves and
48 : * query suppression (since there will be no ambiguity about when
49 : * state is to be deleted.)
50 : */
51 :
52 : /*
53 : * Instance entry
54 : *
55 : * The instance block contains global storage for GMP router support. This
56 : * is primarily to ensure that the code remains reentrant (no fixed storage.)
57 : * It also allows multiple instances of this code to be running, though the
58 : * semantics of that are beyond the scope of this code.
59 : *
60 : * Note that the tree of interfaces will not be in lexicographic order
61 : * by interface ID on little-endian machines.
62 : */
63 : typedef struct gmpr_instance_ {
64 : uint32_t rinst_magic; /* Magic number for robustness */
65 : task_thread rinst_thread; /* Link on global instance thread */
66 : task_thread rinst_client_thread; /* Head of client task_thread */
67 : task_thread rinst_startup_intf_thread; /* Head of intfs starting up */
68 :
69 : gmpx_patroot *rinst_intfs; /* Tree of interfaces */
70 : gmpx_patroot *rinst_global_state_root; /* Root of global state tree */
71 : gmp_proto rinst_proto; /* Protocol (IGMP/MLD) */
72 : uint32_t rinst_addrlen; /* Address length (v4 or v6) */
73 : gmp_addr_catalog rinst_addr_cat; /* Address catalog */
74 : uint32_t rinst_min_max_resp; /* Min value of max resp field */
75 :
76 : ordinal_handle rinst_ord_handle; /* Handle for client ordinals */
77 : void *rinst_context; /* Client instance context */
78 : gmpr_instance_context rinst_cb_context; /* Instance callbacks */
79 :
80 : uint32_t rinst_group_timeout; /* Group timeout count */
81 :
82 : uint32_t rinst_traceflags; /* Trace flags */
83 :
84 : gmpx_timer *rinst_smear_timer; /* Timer for query timer smearing */
85 :
86 : boolean rinst_host_tracking; /* TRUE if doing host tracking */
87 : boolean rinst_smear_timer_accelerated; /* TRUE if we're smearing soon */
88 : } gmpr_instance;
89 :
90 0 : THREAD_TO_STRUCT(gmpr_thread_to_instance, gmpr_instance, rinst_thread);
91 :
92 : /*
93 : * Query timer smear values
94 : *
95 : * In order to deal with large numbers of interfaces, we periodically smear
96 : * general query timers to smooth the transmission of queries. In addition,
97 : * whenever a new interface is created, we accelerate the smearing so that
98 : * it happens not long after the new interfaces arrive.
99 : */
100 : #define GMP_QUERY_SMEAR_IVL (30*60*MSECS_PER_SEC) /* Half hour seems OK */
101 : #define GMP_QUERY_QUICK_SMEAR_IVL (10*MSECS_PER_SEC) /* Quick fix */
102 :
103 : #define GMPR_INSTANCE_MAGIC 0x52696E73 /* 'Rins' */
104 :
105 : typedef enum {
106 : GMPR_BELOW_THRESHOLD = 0,
107 : GMPR_ABOVE_THRESHOLD_BELOW_LIMIT,
108 : GMPR_ABOVE_LIMIT
109 : }gmpr_limit_state_t;
110 :
111 : /*
112 : * Interface entry
113 : *
114 : * One of these entries is created for every interface mentioned by a client.
115 : * It is stored on a patricia tree in the instance, keyed by interface index.
116 : *
117 : * Note that an interface may play one of two roles, or both. The
118 : * first role is that of an input interface (one on which IGMP packets
119 : * are sent and received.) The other is that of an output interface
120 : * (one on which multicast traffic is forwarded.) Normally an
121 : * interface plays both roles, but when OIF mapping is taking place,
122 : * the two roles may be on different interfaces on a per-group or
123 : * per-source basis.
124 : */
125 : typedef struct gmpr_intf_ {
126 :
127 : /* Fundamental parameters */
128 :
129 : gmp_version rintf_ver; /* GMP version running */
130 : gmp_addr_string rintf_local_addr; /* Our address */
131 : gmp_addr_string rintf_querier_addr; /* Querier address */
132 :
133 : /* Linkages */
134 :
135 : gmpr_instance *rintf_instance; /* Owning instance */
136 : gmpx_patnode rintf_inst_patnode; /* Node on instance tree */
137 : gmpx_patnode rintf_global_patnode; /* Node on global tree */
138 : gmpx_patroot *rintf_group_root; /* Root of aggregated group records */
139 : uint32_t rintf_group_count; /* Number of groups */
140 : gmpx_patroot *rintf_oif_group_root; /* Root of output group records */
141 : uint32_t rintf_oif_group_count; /* Number of output groups */
142 : gmpx_intf_id rintf_id; /* Interface ID */
143 : gmpx_patroot *rintf_host_root; /* Root of host entries */
144 : task_thread rintf_startup_thread; /* Entry on instance startup thread */
145 :
146 : /* Query stuff */
147 :
148 : gmpx_timer *rintf_query_timer; /* General query timer */
149 : uint32_t rintf_query_ivl; /* General query timer interval */
150 : uint32_t rintf_local_query_ivl; /* Local general query interval */
151 : uint32_t rintf_query_resp_ivl; /* Query response interval */
152 : uint32_t rintf_local_query_resp_ivl; /* Local query response interval */
153 : uint32_t rintf_robustness; /* Robustness variable */
154 : uint32_t rintf_local_robustness; /* Local robustness variable */
155 : uint32_t rintf_lmq_ivl; /* Last member query interval */
156 : uint32_t rintf_lmq_count; /* Last member query count */
157 : uint32_t rintf_group_membership_ivl; /* Group membership interval */
158 : uint32_t rintf_lmqt; /* Last member query time */
159 : uint32_t rintf_other_querier_ivl; /* Other querier present interval */
160 : gmpx_timer *rintf_other_querier_present; /* Other querier present timer */
161 : boolean rintf_suppress_gen_query; /* Suppress general queries */
162 : boolean rintf_gen_query_requested; /* General query seq was requested */
163 : boolean rintf_first_query_pending; /* First query in sequence ready */
164 : boolean rintf_suppress_gs_query; /* Suppress GS/GSS queries */
165 :
166 : uint32_t rintf_startup_query_count; /* Count of initial queries */
167 :
168 : uint32_t rintf_channel_limit; /* Max number of channels */
169 : uint32_t rintf_channel_threshold; /* Percentage of maximum at which to
170 : start generating warnings */
171 : uint32_t rintf_log_interval; /* Time between consecutive limit log msgs */
172 : time_t last_log_time; /* Time last group limit related message
173 : was logged */
174 : uint32_t rintf_channel_count; /* Current channel count */
175 : uint32_t rintf_chan_limit_drops; /* Count of drops due to chan limit */
176 : gmpr_limit_state_t rintf_limit_state; /* if count is above/below chan limit/threshold */
177 :
178 : /* Transmission stuff */
179 :
180 : task_thread rintf_xmit_head; /* Head of xmit groups */
181 : boolean rintf_xmit_pending; /* TRUE if we have a pending xmit */
182 : boolean rintf_send_gen_query; /* TRUE if we should send gen query */
183 :
184 : boolean rintf_up; /* TRUE if interface is up */
185 : boolean rintf_fast_leaves; /* TRUE if doing fast leaves */
186 : boolean rintf_querier_enabled; /* TRUE if allowed to be V1 querier */
187 : boolean rintf_querier; /* TRUE if we are querier */
188 :
189 : /* Receive stuff */
190 :
191 : boolean rintf_passive_receive; /* Passive receive */
192 : } gmpr_intf;
193 :
194 7268 : GMPX_PATNODE_TO_STRUCT(gmpr_inst_patnode_to_intf, gmpr_intf,
195 : rintf_inst_patnode);
196 5390 : GMPX_PATNODE_TO_STRUCT(gmpr_global_patnode_to_intf, gmpr_intf,
197 : rintf_global_patnode);
198 :
199 : #define GMPR_QUERY_IVL_DEFAULT 125000 /* Default query interval */
200 : #define GMPR_QUERY_RESP_IVL_DEFAULT 10000 /* Default query response interval */
201 : #define GMPR_INIT_FIRST_QUERY_IVL 100 /* Initial query delay */
202 : #define GMPR_INIT_LATER_QUERY_IVL 2000 /* Later startup query delay */
203 : #define GMPR_LMQI_DEFAULT 1000 /* Default LMQI value */
204 :
205 :
206 : /*
207 : * Notification block
208 : *
209 : * This block contains linkages for notifications to clients about
210 : * changes to GMP state. It is embedded in groups (for notification
211 : * of group-wide changes) and address entries (for notification of
212 : * source changes.) The same mechanism is used for host-related
213 : * notifications, and is embedded in host group and host source
214 : * entries in the same way.
215 : *
216 : * The REFRESH_END type is used to mark the end of a client refresh
217 : * sequence; this block is embeded in the client structure itself.
218 : *
219 : * The type field provides the ability to obtain the address of the
220 : * enclosing data structure.
221 : *
222 : * In order to minimize the number of calls to the client callbacks,
223 : * we keep per-client indications of whether a notification callback
224 : * should be made. This is set when the first notification of the
225 : * type (regular or host) is enqueued, cleared when the callback is made,
226 : * and not set again until after the queue is drained.
227 : */
228 : typedef enum {
229 : GMPR_NOTIFY_GROUP = 1, /* Group notification */
230 : GMPR_NOTIFY_SOURCE, /* Source notification */
231 : GMPR_NOTIFY_REFRESH_END, /* End of refresh sequence */
232 : GMPR_NOTIFY_HOST_GROUP, /* Host group notification */
233 : GMPR_NOTIFY_HOST_SOURCE, /* Host source notification */
234 : } gmpr_notification_type;
235 :
236 : typedef struct gmpr_notify_block_ {
237 : gmpr_notification_type gmpr_notify_type; /* Notification type */
238 : task_thread gmpr_notify_thread; /* Entry on client notify thread */
239 : } gmpr_notify_block;
240 :
241 928 : THREAD_TO_STRUCT(gmpr_thread_to_notify_block, gmpr_notify_block,
242 : gmpr_notify_thread);
243 :
244 :
245 : /*
246 : * Input interface group entry
247 : *
248 : * This data structure defines the group record for an input interface.
249 : * This represents a group requested by one or more hosts connected to
250 : * the interface.
251 : *
252 : * Source addresses are kept in two lists, one for those with source
253 : * timers running, and the other for those with source timers stopped.
254 : * In Include mode, the running-timer list constitutes the included
255 : * sources. In Exclude mode, the stopped-timer list constitutes the
256 : * excluded sources.
257 : *
258 : * Two lists are maintained to help with sending queries. One list has
259 : * all of the sources to be queried that have timers greater than LMQT,
260 : * and the other has the sources to be queried that have timers less than
261 : * LMQT.
262 : *
263 : * Input groups are linked to OIF groups if the input group is a (*,G)
264 : * entry. Otherwise, the input group is not linked (but the individual
265 : * sources are.)
266 : */
267 : typedef struct gmpr_group_ {
268 :
269 : /* Linkages */
270 :
271 : gmpr_intf *rgroup_intf; /* Pointer back to interface */
272 : gmpx_patnode rgroup_intf_patnode; /* Node on interface tree of groups */
273 : task_thread rgroup_host_group_head; /* Head of host group thread */
274 : task_thread rgroup_oif_thread; /* Entry on OIF group thread */
275 : struct gmpr_ogroup_ *rgroup_oif_group; /* OIF group pointer */
276 :
277 : /* Group state */
278 :
279 : gmp_addr_string rgroup_addr; /* Group address */
280 : gmp_filter_mode rgroup_filter_mode; /* Include/Exclude */
281 : gmp_addr_list rgroup_src_addr_running; /* Sources with running timers */
282 : gmp_addr_list rgroup_src_addr_stopped; /* Sources with stopped timers */
283 : gmpx_timer *rgroup_group_timer; /* Group timer */
284 : gmp_addr_string rgroup_last_reporter; /* Address of last reporting host */
285 :
286 : /* Query stuff */
287 :
288 : gmpx_timer *rgroup_query_timer; /* For sending group queries */
289 : gmpx_timer *rgroup_gss_query_timer; /* For sending GSS queries */
290 : uint8_t rgroup_query_rexmit_count; /* Rexmit count for group queries */
291 : gmp_addr_list rgroup_query_lo_timers; /* List of sources with lo timers */
292 : gmp_addr_list rgroup_query_hi_timers; /* List of sources with hi timers */
293 :
294 : /* Version compatibility stuff */
295 :
296 : gmp_version rgroup_compatibility_mode; /* Group version */
297 : gmpx_timer *rgroup_basic_host_present; /* Basic version host present */
298 : gmpx_timer *rgroup_leaves_host_present; /* Leaves version host present */
299 :
300 : /* Transmission stuff */
301 :
302 : task_thread rgroup_xmit_thread; /* Entry on intf transmit list */
303 : boolean rgroup_send_gss_query; /* We need to send a GSS query */
304 : boolean rgroup_send_group_query; /* We need to send a group query */
305 : } gmpr_group;
306 :
307 3620 : GMPX_PATNODE_TO_STRUCT(gmpr_intf_patnode_to_group, gmpr_group,
308 : rgroup_intf_patnode);
309 2715 : THREAD_TO_STRUCT(gmpr_xmit_thread_to_group, gmpr_group, rgroup_xmit_thread);
310 75 : THREAD_TO_STRUCT(gmpr_oif_thread_to_group, gmpr_group, rgroup_oif_thread);
311 :
312 :
313 : /*
314 : * Input interface group member address entry
315 : *
316 : * This structure represents a single source address in an input
317 : * interface group. It consists of an address entry structure plus a
318 : * timer, used to age the address entry, and a retransmission counter,
319 : * used for counting GSS queries sent with this address. It also
320 : * carries a group pointer, so we can get back to the group as
321 : * necessary, and client notification linkages.
322 : *
323 : * The address entry is linked to the corresponding output entry, which
324 : * may be bound to a different interface if OIF mapping is in use.
325 : */
326 : typedef struct gmpr_group_addr_entry_
327 : {
328 : gmp_addr_list_entry rgroup_addr_entry; /* Address entry */
329 : gmpr_group *rgroup_addr_group; /* Owning group */
330 : gmpx_timer *rgroup_addr_timer; /* Timer */
331 : uint8_t rgroup_addr_rexmit_count; /* Query retransmission count */
332 : task_thread rgroup_addr_oif_thread; /* Entry on OIF thread */
333 : struct gmpr_ogroup_addr_entry_ *rgroup_addr_oif_addr; /* OIF address */
334 :
335 : /* Host stuff */
336 :
337 : task_thread rgroup_host_addr_head; /* Head of host address thread */
338 :
339 : /* Wasted space */
340 :
341 : gmp_addr_string rgroup_addr_last_reporter; /* Last host to mention us */
342 :
343 : } gmpr_group_addr_entry;
344 :
345 39 : THREAD_TO_STRUCT(gmpr_oif_thread_to_group_addr_entry, gmpr_group_addr_entry,
346 : rgroup_addr_oif_thread);
347 359 : EMBEDDED_STRUCT_TO_STRUCT(gmpr_addr_entry_to_group_entry,
348 : gmpr_group_addr_entry, gmp_addr_list_entry,
349 : rgroup_addr_entry);
350 :
351 :
352 : /*
353 : * Output interface group entry
354 : *
355 : * This structure represents a group on an output interface. For
356 : * generic IGMP/MLD, this will map one-to-one with the input interface
357 : * group entry and will be semantically the same. When OIF mapping is
358 : * taking place, this entry may have contributors from multiple input
359 : * interface groups.
360 : *
361 : * This structure contains two address lists, one for Include
362 : * contributions and one for Exclude contributions. This is necessary
363 : * because the contributing input interfaces may be in different
364 : * states (Include or Exclude.) If the output group is in Include
365 : * state, the set of sources is that on the Include list. If the
366 : * output group is in Exclude state, the set of sources is that on the
367 : * Exclude list, *minus* the ones on the Include list (since those are
368 : * not to be excluded.) Note that the same source address may be present
369 : * on both the include and exclude lists.
370 : *
371 : * If the output group is a (*,G), it has a thread of all contributing
372 : * input groups. If there are sources, the contributing input sources
373 : * are bound to the individual output sources.
374 : *
375 : * The output group is bound to the output interface.
376 : *
377 : * Client notifications are done with output groups and sources, since they
378 : * represent the actual forwarding state.
379 : */
380 : typedef struct gmpr_ogroup_ {
381 : gmpr_intf *rogroup_intf; /* Pointer back to interface */
382 : gmpx_patnode rogroup_intf_patnode; /* Node on interface tree of groups */
383 : gmpr_notify_block rogroup_client_thread[GMPX_MAX_RTR_CLIENTS];
384 : /* Notification blocks */
385 : boolean rogroup_send_full_notif[GMPX_MAX_RTR_CLIENTS];
386 : /* TRUE if we should send full notif */
387 : task_thread rogroup_global_thread; /* Entry on global state thread */
388 : task_thread rogroup_oif_head; /* Head of input groups contributing */
389 :
390 : /* Group state */
391 :
392 : gmp_addr_string rogroup_addr; /* Group address */
393 : gmp_filter_mode rogroup_filter_mode; /* Include/Exclude */
394 : gmp_addr_list rogroup_incl_src_addr; /* Active include sources */
395 : gmp_addr_list rogroup_excl_src_addr; /* Active exclude sources */
396 : gmp_addr_list rogroup_src_addr_deleted; /* Deleted sources for notify */
397 : } gmpr_ogroup;
398 :
399 5214 : GMPX_PATNODE_TO_STRUCT(gmpr_oif_patnode_to_group, gmpr_ogroup,
400 : rogroup_intf_patnode);
401 0 : THREAD_TO_STRUCT(gmpr_global_thread_to_group, gmpr_ogroup,
402 : rogroup_global_thread);
403 :
404 :
405 : /*
406 : * Output interface group member address entry
407 : *
408 : * This structure represents a single source address in an output
409 : * interface group. It represents a single source being included
410 : * or excluded on the output interface.
411 : *
412 : * Note that the same source address may be present on both the exclude
413 : * and include lists on the output group.
414 : *
415 : * A thread of all contributing input group sources is included.
416 : */
417 : typedef struct gmpr_ogroup_addr_entry_
418 : {
419 : gmp_addr_list_entry rogroup_addr_entry; /* Address entry */
420 : gmpr_ogroup *rogroup_addr_group; /* Owning group */
421 : task_thread rogroup_addr_oif_head; /* Head of contributing sources */
422 :
423 : /* Notification stuff */
424 :
425 : gmpr_notify_block rogroup_addr_client_thread[GMPX_MAX_RTR_CLIENTS];
426 : /* Notification blocks */
427 : boolean rogroup_notify; /* TRUE if notification required */
428 : } gmpr_ogroup_addr_entry;
429 :
430 :
431 243 : EMBEDDED_STRUCT_TO_STRUCT(gmpr_addr_entry_to_ogroup_entry,
432 : gmpr_ogroup_addr_entry, gmp_addr_list_entry,
433 : rogroup_addr_entry);
434 :
435 :
436 : /*
437 : * Client entry
438 : *
439 : * Each client has an associated data structure that tracks its associated
440 : * state.
441 : */
442 : typedef struct gmpr_client_ {
443 : uint32_t rclient_magic; /* Magic number for robustness */
444 : gmpr_instance *rclient_instance; /* Owning instance */
445 : ordinal_t rclient_ordinal; /* Client ordinal */
446 : task_thread rclient_thread; /* Link on instance client thread */
447 : void *rclient_context; /* Client context */
448 :
449 : task_thread rclient_notif_head; /* Head of group notifications */
450 : task_thread rclient_host_notif_head; /* Head of host notifications */
451 : gmpr_client_context rclient_cb_context; /* Client callback */
452 : gmpr_notify_block rclient_refresh_end_notif; /* End-refresh notification */
453 :
454 : gmpx_timer *rclient_startup_timer; /* Startup timer */
455 : boolean rclient_notify; /* TRUE if we need to notify */
456 : boolean rclient_host_notify; /* Ditto for host notifications */
457 : } gmpr_client;
458 :
459 2731 : THREAD_TO_STRUCT(gmpr_thread_to_client, gmpr_client, rclient_thread);
460 :
461 : #define GMPR_CLIENT_MAGIC 0x52636C69 /* 'Rcli' */
462 :
463 :
464 : /*
465 : * Host entry
466 : *
467 : * If host tracking is active, this structure exists for each host seen
468 : * in the protocol. Host entries are used for two purposes--accounting
469 : * and fast leaves.
470 : *
471 : * Host entries are added to a tree rooted at the interface and keyed
472 : * by the host address.
473 : */
474 : typedef struct gmpr_host_ {
475 : gmpx_patnode rhost_node; /* Node on interface tree */
476 : gmp_addr_string rhost_addr; /* Host address */
477 : gmpr_intf *rhost_intf; /* Interface pointer */
478 : gmpx_patroot *rhost_group_root; /* Root of group tree */
479 : } gmpr_host;
480 :
481 154 : GMPX_PATNODE_TO_STRUCT(gmpr_patnode_to_host, gmpr_host, rhost_node);
482 :
483 :
484 : /*
485 : * Host group
486 : *
487 : * This structure represents a group from the perspective of a host. It
488 : * lives on a tree rooted at the host entry, and on a thread rooted
489 : * at the main group entry.
490 : *
491 : * We only keep track of active groups and sources; in particular, if the
492 : * host requests a non-null Exclude list, we do not track those sources
493 : * here (in that case it would look like a group join.)
494 : *
495 : * If the rhgroup_group pointer is NULL, the entry is inactive (has no
496 : * active source or group state) and is not linked to the main group
497 : * entry. If the pointer is set and there are no sources present, the
498 : * group is active for all sources.
499 : *
500 : * Note that we don't keep a filter mode (include/exclude) here, because
501 : * we know by implication--a group with no sources is a (*,G), and a
502 : * group with sources is an Include-mode set of (S,G)s.
503 : *
504 : * We do limited refcounting to avoid double-freeing this structure
505 : * as a side effect of deleting source addresses.
506 : */
507 : typedef struct gmpr_host_group_ {
508 : gmpx_patnode rhgroup_node; /* Node on tree */
509 : gmp_addr_string rhgroup_addr; /* Group address */
510 : gmpr_host *rhgroup_host; /* Host pointer */
511 : gmp_addr_list rhgroup_addrs; /* List of sources */
512 : gmp_addr_list rhgroup_deleted; /* Deleted sources awaiting notify */
513 : task_thread rhgroup_thread; /* Entry on main group thread */
514 : gmpr_group *rhgroup_group; /* Pointer to main group entry */
515 : gmpx_timer *rhgroup_timer; /* Host group timer */
516 : gmpr_notify_block rhgroup_notify[GMPX_MAX_RTR_CLIENTS];
517 : /* Notification block */
518 : boolean rhgroup_is_deleted; /* Deleted, but locked */
519 : uint8_t rhgroup_lock_count; /* Lock count */
520 : } gmpr_host_group;
521 :
522 59 : THREAD_TO_STRUCT(gmpr_thread_to_host_group, gmpr_host_group, rhgroup_thread);
523 151 : GMPX_PATNODE_TO_STRUCT(gmpr_patnode_to_host_group, gmpr_host_group,
524 : rhgroup_node);
525 :
526 : /*
527 : * gmpr_host_group_active
528 : *
529 : * Returns TRUE if the host group is active (is bound to a group) or
530 : * FALSE otherwise.
531 : */
532 : static inline boolean
533 546 : gmpr_host_group_active (gmpr_host_group *host_group)
534 : {
535 : /* Tolerate NULL pointers. */
536 :
537 546 : if (!host_group)
538 0 : return FALSE;
539 :
540 : /* The host group is active if it's bound to a group. */
541 :
542 546 : return (host_group->rhgroup_group != NULL);
543 : }
544 :
545 :
546 : /*
547 : * Host group address entry
548 : *
549 : * This structure represents a single source address on a host group entry.
550 : */
551 : typedef struct gmpr_host_group_addr_ {
552 : gmp_addr_list_entry rhga_addr_ent; /* Address entry */
553 : task_thread rhga_thread; /* Entry on main addr entry thread */
554 : gmpr_group_addr_entry *rhga_source; /* Pointer to main addr entry */
555 : gmpr_notify_block rhga_notify[GMPX_MAX_RTR_CLIENTS];
556 : /* Notification block */
557 : gmpr_host_group *rhga_host_group; /* Pointer to owning host group */
558 : gmpx_timer *rhga_timer; /* Host source timer */
559 : } gmpr_host_group_addr;
560 :
561 323 : EMBEDDED_STRUCT_TO_STRUCT(gmpr_addr_entry_to_host_group_entry,
562 : gmpr_host_group_addr, gmp_addr_list_entry,
563 : rhga_addr_ent);
564 33 : THREAD_TO_STRUCT(gmpr_thread_to_host_group_addr_entry, gmpr_host_group_addr,
565 : rhga_thread);
566 :
567 :
568 : /*
569 : * Global table entries
570 : *
571 : * We keep a global linkage into the state across all interfaces and
572 : * groups. Looking up in the global table based on group leads to a
573 : * task_thread of all group entries within that instance that match the
574 : * group address. This is done so that the
575 : * gmp_router_which_interfaces() call can be implemented; it returns
576 : * all of the interfaces on which the entry was heard.
577 : *
578 : * This is an abomination and should be ripped out (at considerable memory
579 : * savings) once PIM becomes smart enough to not lose track of the interfaces
580 : * provided in the notifications.
581 : */
582 : typedef struct gmpr_global_group_ {
583 : patnode global_group_node; /* Entry on global tree */
584 : gmp_addr_string global_group_addr; /* Group address */
585 : task_thread global_group_head; /* Head of thread of groups */
586 : } gmpr_global_group;
587 :
588 74 : GMPX_PATNODE_TO_STRUCT(gmpr_patnode_to_global_group, gmpr_global_group,
589 : global_group_node);
590 :
591 : /*
592 : * Inlines...
593 : */
594 :
595 : /*
596 : * gmpr_client_notification_to_group
597 : *
598 : * Return the address of an output group, given a pointer to the
599 : * client notification and the client ordinal.
600 : *
601 : * Returns NULL with a null pointer.
602 : */
603 : static inline gmpr_ogroup *
604 116 : gmpr_client_notification_to_group (gmpr_notify_block *notify_block,
605 : ordinal_t ordinal)
606 : {
607 : uint8_t *byte_ptr;
608 : gmpr_ogroup *group;
609 :
610 116 : if (!notify_block)
611 0 : return NULL;
612 :
613 116 : gmpx_assert(ordinal < GMPX_MAX_RTR_CLIENTS);
614 :
615 : /*
616 : * Do the grody pointer math. First, adjust for the client
617 : * ordinal offset.
618 : */
619 116 : notify_block -= ordinal;
620 :
621 : /* Now back up to the start of the group. */
622 :
623 116 : byte_ptr = (uint8_t *) notify_block;
624 116 : byte_ptr -= offsetof(gmpr_ogroup, rogroup_client_thread);
625 :
626 116 : group = (gmpr_ogroup *) byte_ptr;
627 :
628 116 : return group;
629 : }
630 :
631 :
632 : /*
633 : * gmpr_client_notification_to_addr_entry
634 : *
635 : * Return the address of a group member address entry, given a pointer
636 : * to the client notification and the client ordinal.
637 : *
638 : * Returns NULL with a null pointer.
639 : */
640 : static inline gmpr_ogroup_addr_entry *
641 120 : gmpr_client_notification_to_addr_entry (gmpr_notify_block *notify_block,
642 : ordinal_t ordinal)
643 : {
644 : uint8_t *byte_ptr;
645 : gmpr_ogroup_addr_entry *group_addr;
646 :
647 120 : gmpx_assert(ordinal < GMPX_MAX_RTR_CLIENTS);
648 :
649 : /* Bail if the ordinal is out of range. */
650 :
651 120 : if (ordinal >= GMPX_MAX_RTR_CLIENTS)
652 0 : return NULL;
653 :
654 : /* Adjust for the client ordinal offset. */
655 :
656 120 : notify_block -= ordinal;
657 :
658 : /* Now back up to the start of the address entry. */
659 :
660 120 : byte_ptr = (uint8_t *) notify_block;
661 120 : byte_ptr -= offsetof(gmpr_ogroup_addr_entry, rogroup_addr_client_thread);
662 :
663 120 : group_addr = (gmpr_ogroup_addr_entry *) byte_ptr;
664 :
665 120 : return group_addr;
666 : }
667 :
668 : /*
669 : * gmpr_client_notification_to_host_group
670 : *
671 : * Return the address of a host group, given a pointer to the client
672 : * notification and the client ordinal.
673 : *
674 : * Returns NULL with a null pointer.
675 : */
676 : static inline gmpr_host_group *
677 156 : gmpr_client_notification_to_host_group (gmpr_notify_block *notify_block,
678 : ordinal_t ordinal)
679 : {
680 : uint8_t *byte_ptr;
681 : gmpr_host_group *host_group;
682 :
683 156 : if (!notify_block)
684 0 : return NULL;
685 :
686 156 : gmpx_assert(ordinal < GMPX_MAX_RTR_CLIENTS);
687 :
688 : /*
689 : * Do the grody pointer math. First, adjust for the client
690 : * ordinal offset.
691 : */
692 156 : notify_block -= ordinal;
693 :
694 : /* Now back up to the start of the group. */
695 :
696 156 : byte_ptr = (uint8_t *) notify_block;
697 156 : byte_ptr -= offsetof(gmpr_host_group, rhgroup_notify);
698 :
699 156 : host_group = (gmpr_host_group *) byte_ptr;
700 :
701 156 : return host_group;
702 : }
703 :
704 :
705 : /*
706 : * gmpr_client_notification_to_host_group_addr
707 : *
708 : * Return the address of a host group address entry, given a pointer
709 : * to the client notification and the client ordinal.
710 : *
711 : * Returns NULL with a null pointer.
712 : */
713 : static inline gmpr_host_group_addr *
714 236 : gmpr_client_notification_to_host_group_addr (gmpr_notify_block *notify_block,
715 : ordinal_t ordinal)
716 : {
717 : uint8_t *byte_ptr;
718 : gmpr_host_group_addr *group_addr;
719 :
720 236 : gmpx_assert(ordinal < GMPX_MAX_RTR_CLIENTS);
721 :
722 : /* Bail if the ordinal is out of range. */
723 :
724 236 : if (ordinal >= GMPX_MAX_RTR_CLIENTS)
725 0 : return NULL;
726 :
727 : /* Adjust for the client ordinal offset. */
728 :
729 236 : notify_block -= ordinal;
730 :
731 : /* Now back up to the start of the address entry. */
732 :
733 236 : byte_ptr = (uint8_t *) notify_block;
734 236 : byte_ptr -= offsetof(gmpr_host_group_addr, rhga_notify);
735 :
736 236 : group_addr = (gmpr_host_group_addr *) byte_ptr;
737 :
738 236 : return group_addr;
739 : }
740 :
741 :
742 : /*
743 : * gmpr_group_addr_deleted
744 : *
745 : * Returns TRUE if the address entry is on the group deleted list.
746 : */
747 : static inline boolean
748 147 : gmpr_group_addr_deleted (gmpr_ogroup_addr_entry *group_addr)
749 : {
750 : gmp_addr_list_entry *addr_entry;
751 : gmpr_ogroup *group;
752 :
753 147 : addr_entry = &group_addr->rogroup_addr_entry;
754 147 : group = group_addr->rogroup_addr_group;
755 147 : return (addr_entry->addr_ent_list == &group->rogroup_src_addr_deleted);
756 : }
757 :
758 :
759 : /*
760 : * gmpr_group_addr_included
761 : *
762 : * Returns TRUE if the address entry is on the group include list.
763 : */
764 : static inline boolean
765 60 : gmpr_group_addr_included (gmpr_ogroup_addr_entry *group_addr)
766 : {
767 : gmp_addr_list_entry *addr_entry;
768 : gmpr_ogroup *group;
769 :
770 60 : addr_entry = &group_addr->rogroup_addr_entry;
771 60 : group = group_addr->rogroup_addr_group;
772 60 : return (addr_entry->addr_ent_list == &group->rogroup_incl_src_addr);
773 : }
774 :
775 :
776 : /*
777 : * gmpr_group_addr_mode
778 : *
779 : * Returns the filter mode (include/exclude) associated with an output
780 : * group source entry.
781 : */
782 : static inline gmp_filter_mode
783 27 : gmpr_group_addr_mode (gmpr_ogroup_addr_entry *group_addr)
784 : {
785 : gmp_filter_mode mode;
786 :
787 27 : gmpx_assert(!gmpr_group_addr_deleted(group_addr));
788 27 : mode = GMP_FILTER_MODE_EXCLUDE;
789 27 : if (gmpr_group_addr_included(group_addr))
790 27 : mode = GMP_FILTER_MODE_INCLUDE;
791 :
792 27 : return mode;
793 : }
794 :
795 :
796 : /*
797 : * gmpr_group_addr_excluded
798 : *
799 : * Returns TRUE if the address entry is on the group exclude list.
800 : */
801 : static inline boolean
802 : gmpr_group_addr_excluded (gmpr_ogroup_addr_entry *group_addr)
803 : {
804 : gmp_addr_list_entry *addr_entry;
805 : gmpr_ogroup *group;
806 :
807 : addr_entry = &group_addr->rogroup_addr_entry;
808 : group = group_addr->rogroup_addr_group;
809 : return (addr_entry->addr_ent_list == &group->rogroup_excl_src_addr);
810 : }
811 :
812 :
813 : /*
814 : * gmpr_host_group_addr_deleted
815 : *
816 : * Returns TRUE if the address entry is on the host group deleted list.
817 : */
818 : static inline boolean
819 354 : gmpr_host_group_addr_deleted (gmpr_host_group_addr *group_addr)
820 : {
821 : gmp_addr_list_entry *addr_entry;
822 : gmpr_host_group *host_group;
823 :
824 354 : addr_entry = &group_addr->rhga_addr_ent;
825 354 : host_group = group_addr->rhga_host_group;
826 354 : return (addr_entry->addr_ent_list == &host_group->rhgroup_deleted);
827 : }
828 :
829 :
830 : /*
831 : * gmpr_group_is_active
832 : *
833 : * Returns TRUE if the input group is active (in Exclude mode, or a
834 : * non-null source list) or FALSE if not.
835 : */
836 : static inline boolean
837 55 : gmpr_group_is_active (gmpr_group *group)
838 : {
839 55 : if (group->rgroup_filter_mode == GMP_FILTER_MODE_EXCLUDE)
840 44 : return TRUE;
841 11 : if (!gmp_addr_list_empty(&group->rgroup_src_addr_running))
842 0 : return TRUE;
843 11 : return FALSE;
844 : }
845 :
846 :
847 : /*
848 : * gmpr_ogroup_is_active
849 : *
850 : * Returns TRUE if the output group is active (in Exclude mode, or a
851 : * non-null source list) or FALSE if not.
852 : */
853 : static inline boolean
854 236 : gmpr_ogroup_is_active (gmpr_ogroup *ogroup)
855 : {
856 236 : if (ogroup->rogroup_filter_mode == GMP_FILTER_MODE_EXCLUDE)
857 44 : return TRUE;
858 192 : if (!gmp_addr_list_empty(&ogroup->rogroup_incl_src_addr))
859 117 : return TRUE;
860 75 : return FALSE;
861 : }
862 :
863 :
864 : /*
865 : * gmpr_ogroup_source_list_by_mode
866 : *
867 : * Returns a pointer to the appropriate source list for an output group
868 : * (the include list if in Include mode, or the exclude if not) based
869 : * on the supplied filter mode.
870 : */
871 : static inline gmp_addr_list *
872 111 : gmpr_ogroup_source_list_by_mode (gmpr_ogroup *group, gmp_filter_mode mode)
873 : {
874 111 : if (mode == GMP_FILTER_MODE_INCLUDE) {
875 62 : return &group->rogroup_incl_src_addr;
876 : } else {
877 49 : return &group->rogroup_excl_src_addr;
878 : }
879 : }
880 :
881 :
882 : /*
883 : * gmpr_ogroup_source_list
884 : *
885 : * Returns a pointer to the appropriate source list for an output group
886 : * (the include list if in Include mode, or the exclude if not.)
887 : */
888 : static inline gmp_addr_list *
889 33 : gmpr_ogroup_source_list (gmpr_ogroup *group)
890 : {
891 33 : return gmpr_ogroup_source_list_by_mode(group, group->rogroup_filter_mode);
892 : }
893 :
894 :
895 : /*
896 : * gmpr_all_group_lists_empty
897 : *
898 : * Returns TRUE if there are no sources anywhere on a group, or FALSE if not.
899 : */
900 : static inline boolean
901 66 : gmpr_all_group_lists_empty (gmpr_group *group)
902 : {
903 96 : return (gmp_addr_list_empty(&group->rgroup_src_addr_running) &&
904 30 : gmp_addr_list_empty(&group->rgroup_src_addr_stopped));
905 : }
906 :
907 :
908 : /*
909 : * gmpr_group_source_list
910 : *
911 : * Returns a pointer to the appropriate source list for an input group
912 : * (the running list if in Include mode, or the stopped list if not.)
913 : */
914 : static inline gmp_addr_list *
915 22 : gmpr_group_source_list (gmpr_group *group)
916 : {
917 22 : if (group->rgroup_filter_mode == GMP_FILTER_MODE_INCLUDE) {
918 0 : return &group->rgroup_src_addr_running;
919 : } else {
920 22 : return &group->rgroup_src_addr_stopped;
921 : }
922 : }
923 :
924 :
925 : /*
926 : * gmpr_source_ord_is_active
927 : *
928 : * Returns TRUE if the source corresponding to an address ordinal is
929 : * active on an output group, or FALSE if not.
930 : *
931 : * The source is active if it is in the include list and the group is
932 : * in Include mode, or if it is in the exclude list and *not* in the
933 : * include list if the group is in Exclude mode.
934 : */
935 : static inline boolean
936 0 : gmpr_source_ord_is_active (gmpr_ogroup *group, ordinal_t ord)
937 : {
938 : boolean in_include;
939 :
940 : /* See if it's in the include list. */
941 :
942 0 : in_include = gmp_addr_in_list(&group->rogroup_incl_src_addr, ord);
943 :
944 : /* If the group is in Include mode, it's active if in the include list. */
945 :
946 0 : if (group->rogroup_filter_mode == GMP_FILTER_MODE_INCLUDE)
947 0 : return in_include;
948 :
949 : /*
950 : * Exclude mode. The source is active if it's in the exclude list and
951 : * not in the include list.
952 : */
953 0 : return (gmp_addr_in_list(&group->rogroup_excl_src_addr, ord) &&
954 : !in_include);
955 : }
956 :
957 :
958 : /*
959 : * gmpr_source_is_active
960 : *
961 : * Returns TRUE if a source is active on an output group, or FALSE if not.
962 : *
963 : * The source is assumed to be from the list matching the filter state
964 : * (include or exclude.) The source is active if the group is in
965 : * Include mode (since all sources are, by definition.) If the group
966 : * is in Exclude mode, the source is active (excluded) only if the
967 : * source is *not* in the Include list.
968 : */
969 : static inline boolean
970 0 : gmpr_source_is_active (gmpr_ogroup *group, gmpr_ogroup_addr_entry *group_addr)
971 : {
972 : /* Active if we're in include mode. */
973 :
974 0 : if (group->rogroup_filter_mode == GMP_FILTER_MODE_INCLUDE)
975 0 : return TRUE;
976 :
977 : /*
978 : * Active if the excluded source is *not* in the Include list, or
979 : * inactive if it is.
980 : */
981 0 : return (!gmp_addr_in_list(&group->rogroup_incl_src_addr,
982 : group_addr->rogroup_addr_entry.addr_ent_ord));
983 : }
984 :
985 :
986 : /*
987 : * oif_update_type
988 : *
989 : * Enum for gmpr_update_group_oif and gmpr_update_source_oif
990 : */
991 : typedef enum {
992 : OIF_DELETE, /* Deleting component */
993 : OIF_UPDATE, /* Updating component */
994 : } oif_update_type;
995 :
996 :
997 : /*
998 : * Externals
999 : */
1000 : extern gmpx_block_tag gmpr_instance_tag;
1001 : extern gmpx_block_tag gmpr_client_tag;
1002 : extern gmpx_block_tag gmpr_intf_tag;
1003 : extern gmpx_block_tag gmpr_host_tag;
1004 : extern gmpx_block_tag gmpr_host_group_tag;
1005 : extern gmpx_block_tag gmpr_host_group_addr_tag;
1006 : extern gmpx_block_tag gmpr_group_tag;
1007 : extern gmpx_block_tag gmpr_ogroup_tag;
1008 : extern gmpx_block_tag gmpr_group_addr_entry_tag;
1009 : extern gmpx_block_tag gmpr_ogroup_addr_entry_tag;
1010 : extern gmpx_block_tag gmpr_notification_tag;
1011 : extern gmpx_block_tag gmpr_host_notification_tag;
1012 : extern gmpx_block_tag gmpr_global_group_tag;
1013 : extern gmpx_block_tag gmpr_intf_list_tag;
1014 : extern gmpx_block_tag gmpr_intf_group_tag;
1015 : extern task_thread gmpr_global_instance_thread;
1016 : extern gmpx_patroot *gmpr_global_intf_tree[];
1017 :
1018 :
1019 : /* gmpr_instance.c */
1020 :
1021 : extern gmpr_instance *gmpr_instance_create(gmp_proto proto,
1022 : void *inst_context);
1023 : extern gmpr_instance *gmpr_get_instance(gmp_instance_id instance_id);
1024 : extern void gmpr_instance_destroy(gmpr_instance *instance);
1025 : extern void gmpr_accelerate_query_smear(gmpr_instance *instance);
1026 :
1027 : /* gmpr_client.c */
1028 :
1029 : extern gmpr_client *gmpr_create_client(gmpr_instance *instance);
1030 : extern gmpr_client *gmpr_get_client(gmp_client_id client_id);
1031 : extern void gmpr_destroy_client(gmpr_client *client);
1032 : extern void gmpr_destroy_instance_clients(gmpr_instance *instance);
1033 : typedef enum {NOTIFY_CONDITIONAL, NOTIFY_UNCONDITIONAL}
1034 : gmpr_source_notify_flag;
1035 : extern void gmpr_source_notify_clients(gmpr_ogroup_addr_entry *group_addr,
1036 : gmpr_source_notify_flag flag);
1037 : extern void gmpr_client_enqueue_all_groups(gmpr_client *client, boolean flush);
1038 : extern void gmpr_client_enqueue_all_intf_groups(gmpr_client *client,
1039 : gmpr_intf *intf,
1040 : boolean flush);
1041 : extern gmpr_client_notification *
1042 : gmpr_client_get_notification(gmpr_client *client,
1043 : gmpr_client_notification *last_notification);
1044 : extern void gmpr_free_notification(gmpr_client_notification *notification);
1045 : extern void gmpr_mode_change_notify_clients(gmpr_ogroup *group);
1046 : extern void gmpr_group_notify_clients(gmpr_ogroup *group);
1047 : extern void gmpr_alert_clients(gmpr_instance *instance);
1048 : extern boolean gmpr_notifications_active(gmpr_notify_block *notify_block);
1049 : extern void gmpr_set_notification_type(gmpr_notify_block *notify_block,
1050 : gmpr_notification_type notify_type);
1051 : extern void gmpr_flush_notifications(gmpr_notify_block *notify_block,
1052 : boolean just_delink);
1053 : extern void gmpr_enqueue_refresh_end(gmpr_client *client);
1054 :
1055 : /* gmpr_intf.c */
1056 :
1057 : extern int gmpr_intf_set_params(gmpr_instance *instance, gmpx_intf_id intf_id,
1058 : gmpr_intf_params *params);
1059 : extern gmpr_intf *gmpr_intf_lookup(gmpr_instance *instance,
1060 : gmpx_intf_id intf_id);
1061 : extern gmpr_intf *gmpr_intf_lookup_global(gmp_proto proto,
1062 : gmpx_intf_id intf_id);
1063 : extern void gmpr_kick_xmit(gmpr_intf *intf);
1064 : extern int gmpr_attach_intf_internal(gmpr_instance *instance,
1065 : gmpx_intf_id intf_id);
1066 : extern int gmpr_detach_intf_internal(gmpr_instance *instance,
1067 : gmpx_intf_id intf_id);
1068 : extern void gmpr_destroy_instance_intfs(gmpr_instance *instance);
1069 : extern void gmpr_intf_update_robustness(gmpr_intf *intf, uint32_t robustness);
1070 : extern void gmpr_intf_update_query_ivl(gmpr_intf *intf, uint32_t query_ivl);
1071 : extern void gmpr_update_querier(gmpr_intf *intf, gmp_addr_string *addr,
1072 : boolean querier);
1073 : extern void gmpr_setup_initial_query_timer(gmpr_intf *intf);
1074 : extern void gmpr_trigger_one_query(gmpr_intf *intf);
1075 : extern gmpr_intf *gmpr_next_instance_intf(gmpr_instance *instance,
1076 : gmpr_intf *prev_intf);
1077 :
1078 : /* gmpr_group.c */
1079 :
1080 : extern gmpr_group *gmpr_group_create(gmpr_intf *intf,
1081 : const gmp_addr_string *group_addr);
1082 : extern gmpr_group *gmpr_group_lookup(gmpr_intf *intf, const uint8_t *group);
1083 : extern gmpr_ogroup *gmpr_ogroup_lookup(gmpr_intf *intf, const uint8_t *group);
1084 : extern gmpx_timer *gmpr_create_change_report_timer(gmpr_group *group);
1085 : extern gmpr_group *gmpr_first_group_xmit(gmpr_intf *intf);
1086 : extern void gmpr_dequeue_group_xmit(gmpr_group *group);
1087 : extern void gmpr_attempt_group_free(gmpr_group *group);
1088 : extern boolean gmpr_attempt_ogroup_free(gmpr_ogroup *ogroup);
1089 : extern void gmpr_destroy_intf_groups(gmpr_intf *intf);
1090 : extern void gmpr_enqueue_group_xmit(gmpr_group *group);
1091 : extern void gmpr_init_group_addr_entry(gmpr_group *group,
1092 : gmp_addr_list_entry *addr_entry);
1093 : extern gmpr_global_group *gmpr_link_global_group(gmpr_ogroup *group);
1094 : extern void gmpr_delink_global_group(gmpr_ogroup *group);
1095 : extern gmpr_global_group *gmpr_lookup_global_group(gmpr_instance *instance,
1096 : uint8_t *group_addr);
1097 : extern void gmpr_evaluate_group_version(gmpr_group *group);
1098 : extern gmp_version gmpr_group_version(gmpr_intf *intf, gmpr_group *group);
1099 : extern boolean gmpr_group_forwards_all_sources(gmpr_ogroup *group);
1100 : extern boolean gmpr_group_forwards_source(gmpr_ogroup *group,
1101 : const uint8_t *source);
1102 : extern void gmpr_timeout_group(gmpr_group *group);
1103 : extern void gmpr_update_group_oif(gmpr_group *group, oif_update_type type);
1104 : extern void gmpr_update_source_oif(gmpr_group_addr_entry *group_addr,
1105 : oif_update_type type);
1106 : extern void gmpr_update_oif_mode_change(gmpr_group *group);
1107 : extern void gmpr_notify_oif_map_change_internal(gmpr_intf *intf);
1108 : extern gmpr_group *gmpr_next_intf_group(gmpr_intf *intf, gmpr_group *group);
1109 : extern gmpr_ogroup *gmpr_next_oif_group(gmpr_intf *oif, gmpr_ogroup *group);
1110 : extern void gmpr_update_intf_output_groups(gmpr_intf *intf);
1111 : extern void gmpr_flush_intf_input_groups(gmpr_intf *intf);
1112 : extern void gmpr_enqueue_all_source_notifications(gmpr_ogroup *ogroup,
1113 : gmpr_client *client);
1114 : extern void gmpr_flush_notifications_group(gmpr_ogroup *ogroup);
1115 : extern boolean gmpr_check_grp_limit(gmpr_intf *intf, boolean incr);
1116 :
1117 : /* gmpr_engine.c */
1118 :
1119 : extern void gmpr_register_packet_handler(void);
1120 : extern void gmpr_group_query_timer_expiry (gmpx_timer *timer, void *context);
1121 : extern void gmpr_group_timer_expiry (gmpx_timer *timer, void *context);
1122 : extern void gmpr_gss_query_timer_expiry (gmpx_timer *timer, void *context);
1123 : extern void gmpr_source_timer_expiry (gmpx_timer *timer, void *context);
1124 : extern void
1125 : gmpr_last_host_addr_ref_gone(gmpr_group_addr_entry *group_addr_entry);
1126 : extern void gmpr_last_host_group_ref_gone(gmpr_group *group);
1127 :
1128 : /* gmpr_host.c */
1129 :
1130 : extern void
1131 : gmpr_host_process_report(uint8_t *src_addr, gmp_report_rectype rec_type,
1132 : gmpr_group *group, gmp_addr_vect *source_vect);
1133 : extern gmpr_client_host_notification *
1134 : gmpr_client_get_host_notification(gmpr_client *client,
1135 : gmpr_client_host_notification *last_notification);
1136 : extern void gmpr_client_free_host_notification(
1137 : gmpr_client_host_notification *host_notif);
1138 : extern void gmpr_alert_host_clients(gmpr_instance *instance);
1139 : extern void gmpr_client_enqueue_all_host_groups(gmpr_client *client);
1140 : extern void gmpr_flush_host_notifications_client(gmpr_client *client);
1141 : extern void gmpr_destroy_intf_hosts(gmpr_intf *intf);
1142 : extern void gmpr_host_notify_oif_map_change(gmpr_group *group);
1143 : extern gmpr_host *gmpr_lookup_host(gmpr_intf *intf, const uint8_t *host_addr);
1144 :
1145 : #endif /* __GMPR_PRIVATE_H__ */
|