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-11-09 02:10:49 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             :  * 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__ */

Generated by: LCOV version 1.14