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