LCOV - code coverage report
Current view: top level - vnsw/agent/services/multicast/grpmgmt - gmpr_private.h (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 93 111 83.8 %
Date: 2026-08-03 02:19:58 Functions: 32 36 88.9 %
Legend: Lines: hit not hit

          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__ */

Generated by: LCOV version 1.14