LCOV - code coverage report
Current view: top level - vnsw/agent/services/multicast/gmp_map - gmp_map.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 97 241 40.2 %
Date: 2026-08-03 02:19:58 Functions: 12 25 48.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2017 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include <cstdarg>
       6             : #include "task_map.h"
       7             : #include "oper/multicast.h"
       8             : 
       9             : #ifdef __cplusplus
      10             : extern "C" {
      11             : #endif
      12             : #include "mcast_common.h"
      13             : 
      14             : #include "task_map.h"
      15             : #include "task_thread_api.h"
      16             : #include "patricia_api.h"
      17             : 
      18             : #include "gmp.h"
      19             : #include "gmpx_environment.h"
      20             : #include "gmp_router.h"
      21             : #include "igmp_private.h"
      22             : #include "igmp_protocol.h"
      23             : #include "gmp_externs.h"
      24             : 
      25             : #include "gmp_intf.h"
      26             : #include "gmp_map.h"
      27             : #include "gmp_private.h"
      28             : #include "gmp_trace.h"
      29             : #include "gmpr_trace.h"
      30             : 
      31             : #define MAXSTRINGSIZE_1 1000
      32             : 
      33             : extern void gmpx_trace(void *context, const char *fmt, ...);
      34             : 
      35             : extern void gmp_set_def_igmp_version(uint32_t version);
      36             : extern void gmp_set_def_ipv4_ivl_params(uint32_t robust_count, uint32_t qivl,
      37             :                         uint32_t qrivl, uint32_t lmqi);
      38             : extern void gmp_set_def_intf_params(mc_af mcast_af);
      39             : #ifdef __cplusplus
      40             : }
      41             : #endif
      42             : 
      43             : mgm_global_data mgm_global[MCAST_AF_MAX];
      44             : gmpr_intf_params def_gmpr_intf_params[MCAST_AF_MAX];
      45             : 
      46             : static gmpr_instance_context gmp_inst_ctx = {
      47             :     gmp_oif_map_cb,     // rctx_oif_map_cb
      48             :     gmp_policy_cb,      // rctx_policy_cb
      49             :     gmp_ssm_check_cb,   // rctx_ssm_check_cb
      50             : };
      51             : 
      52             : static gmpr_client_context igmp_client_context = {
      53             :     igmp_notification_ready,        // rctx_notif_cb
      54             :     igmp_host_notification_ready,   // rctx_host_notif_cb
      55             :     mgm_querier_change,             // rctx_querier_cb
      56             :     TRUE,                           // rctx_delta_notifications
      57             :     FALSE,                          // rctx_full_notifications
      58             : };
      59             : 
      60             : // Value to be used for IGMP Version during init of GMP.
      61           0 : void gmp_set_def_igmp_version(uint32_t version)
      62             : {
      63           0 :     gmpr_intf_params *params = NULL;
      64             : 
      65           0 :     params = &def_gmpr_intf_params[MCAST_AF_IPV4];
      66           0 :     params->gmpr_ifparm_version = version;
      67           0 : }
      68             : 
      69             : // Default values to use for IGMP for querier related timer intervals in
      70             : // GMP code.
      71           1 : void gmp_set_def_ipv4_ivl_params(uint32_t robust_count, uint32_t qivl,
      72             :                         uint32_t qrivl, uint32_t lmqi)
      73             : {
      74           1 :     gmpr_intf_params *params = NULL;
      75             : 
      76           1 :     params = &def_gmpr_intf_params[MCAST_AF_IPV4];
      77           1 :     params->gmpr_ifparm_robustness = robust_count;
      78           1 :     params->gmpr_ifparm_qivl = qivl;
      79           1 :     params->gmpr_ifparm_qrivl = qrivl;
      80           1 :     params->gmpr_ifparm_lmqi = lmqi;
      81             : 
      82           1 :     return;
      83             : }
      84             : 
      85             : // Set of defaults for use by GMP as part of GMP initialization.
      86           1 : void gmp_set_def_intf_params(mc_af mcast_af)
      87             : {
      88           1 :     gmpr_intf_params *params = NULL;
      89             : 
      90           1 :     if (mcast_af == MCAST_AF_IPV4) {
      91             : 
      92           1 :         params = &def_gmpr_intf_params[mcast_af];
      93           1 :         params->gmpr_ifparm_version = IGMP_VERSION_3;
      94           1 :         gmp_set_def_ipv4_ivl_params(IGMP_ROBUST_COUNT, IGMP_QUERY_INTERVAL,
      95             :                             IGMP_QUERY_RESPONSE_INTERVAL,
      96             :                             IGMP_QUERY_LASTMEMBER_INTERVAL);
      97             :     } else {
      98           0 :         return;
      99             :     }
     100             : 
     101           1 :     params->gmpr_ifparm_fast_leave = FALSE;
     102           1 :     params->gmpr_ifparm_passive_receive = FALSE;
     103           1 :     params->gmpr_ifparm_suppress_gen_query = FALSE;
     104           1 :     params->gmpr_ifparm_suppress_gs_query = FALSE;
     105           1 :     params->gmpr_ifparm_chan_limit = 0;
     106           1 :     params->gmpr_ifparm_chan_threshold = 100;
     107           1 :     params->gmpr_ifparm_log_interval = 0;
     108             : 
     109           1 :     return;
     110             : }
     111             : 
     112             : // Create, initialization and return global data structure instance
     113             : // that is used as context and mapping data structure with
     114             : // GMP code.
     115           1 : mgm_global_data *gmp_init(mc_af mcast_af, task *tp, void *gmp_sm)
     116             : {
     117             :     gmp_proto proto;
     118             :     mgm_global_data *gd;
     119             : 
     120           1 :     if (mcast_af == MCAST_AF_IPV4) {
     121           1 :         proto = GMP_PROTO_IGMP;
     122             :     } else {
     123           0 :         return NULL;
     124             :     }
     125             : 
     126           1 :     gd = &mgm_global[mcast_af];
     127           1 :     gd->gmp_sm = gmp_sm;
     128           1 :     gd->tp = tp;
     129           1 :     gd->mgm_gd_af = mcast_af;
     130             : 
     131           1 :     gmp_register_io(GMP_ROLE_ROUTER, proto, gmp_xmit_ready);
     132           1 :     gmp_register_peek_function(GMP_ROLE_ROUTER, gmp_static_peek,
     133             :                                    gmp_static_peek);
     134             : 
     135           1 :     gd->mgm_gmpr_instance = gmpr_create_instance(proto, gd, &gmp_inst_ctx);
     136           1 :     gd->mgm_gmpr_client = gmpr_register(gd->mgm_gmpr_instance, gd,
     137             :                             &igmp_client_context);
     138           1 :     gmpr_update_trace_flags(gd->mgm_gmpr_instance, 0);
     139           1 :     gmp_set_def_intf_params(mcast_af);
     140             : 
     141           1 :     return gd;
     142             : }
     143             : 
     144             : // Deinit and destroy data structure once the GMP module is
     145             : // de-inited by the caller.
     146           1 : void gmp_deinit(mc_af mcast_af)
     147             : {
     148             :     mgm_global_data *gd;
     149             : 
     150           1 :     gd = &mgm_global[mcast_af];
     151           1 :     gmpr_detach(gd->mgm_gmpr_client);
     152           1 :     gmpr_destroy_instance(gd->mgm_gmpr_instance);
     153             : 
     154           1 :     gd->mgm_gmpr_client = NULL;
     155           1 :     gd->mgm_gmpr_instance = NULL;
     156             : 
     157           1 :     return;
     158             : }
     159             : 
     160             : // Set the interface params in the GMP.
     161           3 : void gmp_set_intf_params(mgm_global_data *gd, gmp_intf *gif)
     162             : {
     163             :     gmp_intf_handle *handle;
     164             : 
     165           3 :     if (gd->mgm_gd_af != MCAST_AF_IPV4) {
     166           0 :         return;
     167             :     }
     168             : 
     169           3 :     handle = gmp_gif_to_handle(gif);
     170           3 :     gmpr_set_intf_params(gd->mgm_gmpr_instance, handle, &gif->params);
     171           3 :     return;
     172             : }
     173             : 
     174             : // Attach an application interface context with GMP interface context.
     175             : // application interface context is generally the either per-IPAM
     176             : // gw or dns server in the context of the Agent.
     177           3 : gmp_intf *gmp_attach_intf(mgm_global_data *gd, void *mif_state)
     178             : {
     179           3 :     gmp_intf *gif = NULL;
     180             : 
     181           3 :     if (!gd) {
     182           0 :         return NULL;
     183             :     }
     184             : 
     185           3 :     if (gd->mgm_gd_af != MCAST_AF_IPV4) {
     186           0 :         return NULL;
     187             :     }
     188             : 
     189           3 :     gif = (gmp_intf *)malloc(sizeof(gmp_intf));
     190           3 :     if (!gif) {
     191           0 :         return NULL;
     192             :     }
     193             : 
     194           3 :     gif->vm_interface = mif_state;
     195           3 :     gif->gmpif_proto = GMP_PROTO_IGMP;
     196           3 :     gif->gmpif_handle.gmpifh_host = FALSE;
     197           3 :     std::memset(&gif->gmpif_handle.gmpifh_xmit_thread, 0, sizeof(task_thread));
     198           3 :     gmpr_attach_intf(gd->mgm_gmpr_instance, &gif->gmpif_handle);
     199           3 :     memcpy(&gif->params, &def_gmpr_intf_params[gd->mgm_gd_af],
     200             :                                     sizeof(gif->params));
     201           3 :     gmp_set_intf_params(gd, gif);
     202             : 
     203           3 :     return gif;
     204             : }
     205             : 
     206             : // Detach the interface created using above from the GMP.
     207           3 : void gmp_detach_intf(mgm_global_data *gd, gmp_intf *gif)
     208             : {
     209           3 :     if (!gd) {
     210           0 :         return;
     211             :     }
     212             : 
     213           3 :     gmpr_detach_intf(gd->mgm_gmpr_instance, &gif->gmpif_handle);
     214             : 
     215           3 :     free(gif);
     216             : 
     217           3 :     return;
     218             : }
     219             : 
     220             : // Update interface status - currently only IP Address.
     221           6 : boolean gmp_update_intf_state(mgm_global_data *gd, gmp_intf *gif,
     222             :                                 const gmp_addr_string *intf_addr)
     223             : {
     224           6 :     gmpr_update_intf_state(gd->mgm_gmpr_instance, gmp_gif_to_handle(gif),
     225             :                                 (const u_int8_t *)intf_addr);
     226           6 :     return TRUE;
     227             : }
     228             : 
     229             : // Update querying related params - currently query enable/disable.
     230           0 : boolean gmp_update_intf_querying(mgm_global_data *gd, gmp_intf *gif,
     231             :                                 boolean query)
     232             : {
     233           0 :     gif->params.gmpr_ifparm_suppress_gen_query = query;
     234           0 :     gif->params.gmpr_ifparm_suppress_gs_query = query;
     235           0 :     gmp_set_intf_params(gd, gif);
     236           0 :     return TRUE;
     237             : }
     238             : 
     239             : // Process the IGMP payload.
     240             : // Preprocessed IP header by Agent packet handler.
     241           0 : boolean gmp_process_pkt(mgm_global_data *gd, gmp_intf *gif,
     242             :                         void *rcv_pkt, u_int32_t packet_len,
     243             :                         const gmp_addr_string *src_addr,
     244             :                         const gmp_addr_string *dst_addr)
     245             : {
     246           0 :     boolean parse_ok = FALSE;
     247             : 
     248           0 :     if (gd->mgm_gd_af == MCAST_AF_IPV4) {
     249           0 :         parse_ok = igmp_process_pkt(rcv_pkt, src_addr->gmp_v4_addr,
     250           0 :                         dst_addr->gmp_v4_addr, packet_len,
     251             :                         gmp_gif_to_handle(gif), false, NULL, 0);
     252             :     }
     253             : 
     254           0 :     return parse_ok;
     255             : }
     256             : 
     257           0 : boolean gmp_oif_map_cb(void *inst_context UNUSED, gmp_intf_handle *handle,
     258             :                 u_int8_t *group_addr, u_int8_t *source_addr,
     259             :                 gmp_intf_handle **output_handle)
     260             : {
     261           0 :     *output_handle = handle;
     262           0 :     return TRUE;
     263             : }
     264             : 
     265             : // Handle Multicast Policy configured by user.
     266             : // Returns allow or deny the <S,G> at VN level.
     267           0 : boolean gmp_policy_cb(void *inst_context, gmp_intf_handle *handle,
     268             :                 u_int8_t *group_addr, u_int8_t *source_addr,
     269             :                 boolean static_group)
     270             : {
     271           0 :     mgm_global_data *gd = (mgm_global_data *)inst_context;
     272             :     gmp_intf *gif;
     273             :     gmp_addr_string g;
     274             :     gmp_addr_string s;
     275             : 
     276           0 :     if (!inst_context) {
     277           0 :         return FALSE;
     278             :     }
     279             : 
     280           0 :     gif = gmp_handle_to_gif(handle);
     281           0 :     if (!gif) {
     282           0 :         return FALSE;
     283             :     }
     284             : 
     285           0 :     if (static_group) {
     286           0 :         return FALSE;
     287             :     }
     288             : 
     289           0 :     if (!group_addr) {
     290           0 :         return FALSE;
     291             :     }
     292             : 
     293           0 :     memcpy(&g, group_addr, IPV4_ADDR_LEN);
     294           0 :     source_addr ? memcpy(&s, source_addr, IPV4_ADDR_LEN)
     295           0 :                 : memset(&s, 0x00, IPV4_ADDR_LEN);
     296             : 
     297           0 :     return gmp_policy_check(gd, gif, s, g);
     298             : }
     299             : 
     300           0 : boolean gmp_ssm_check_cb(void *inst_context UNUSED, gmp_intf_handle *handle,
     301             :                 u_int8_t *group_addr)
     302             : {
     303           0 :     return TRUE;
     304             : }
     305             : 
     306             : // Notification handler for handling <S,G>
     307             : // Values per-<S,G> can be adding, deleting or modifying <S,G>.
     308             : // Modifying can be change <S> from allow to block and vice-versa.
     309           0 : boolean gmp_client_notification(mgm_global_data *gd)
     310             : {
     311           0 :     boolean pending = FALSE;
     312             :     gmpr_client_notification *notification;
     313             :     gmp_intf *gif;
     314             :     gmp_intf_handle *handle;
     315             :     gmp_addr_string g;
     316             :     gmp_addr_string s;
     317           0 :     int notif_count = IGMP_MAX_NOTIF_PER_PASS;
     318             : 
     319             :     /*
     320             :      * Pull notifications until we run out, hit our max count, or the
     321             :      * protocol is busy.
     322             :      *
     323             :      * NOTE: We might go over the max notifications per pass,
     324             :      * ie. notif_count might be -ve, because we need to make sure that
     325             :      * the notifications for the (s,g) of the same group are being
     326             :      * processed in the same batch.
     327             :      */
     328           0 :     notification = NULL;
     329           0 :     while (notif_count-- > 0 || !gmpr_notification_last_sg(notification)) {
     330             :         notification =
     331           0 :             gmpr_get_notification(gd->mgm_gmpr_client, notification);
     332           0 :         if (!notification)
     333           0 :             break;
     334             : 
     335             :         /*
     336             :          * Process received notification...
     337             :          */
     338           0 :         handle = notification->notif_intf_id;
     339           0 :         gif = gmp_handle_to_gif(handle);
     340             : 
     341           0 :         memcpy(&g, &notification->notif_group_addr, IPV4_ADDR_LEN);
     342           0 :         memcpy(&s, &notification->notif_source_addr, IPV4_ADDR_LEN);
     343             : 
     344           0 :         switch (notification->notif_type) {
     345           0 :             case GMPR_NOTIF_ALLOW_SOURCE:
     346           0 :                 if (notification->notif_filter_mode ==
     347             :                         GMP_FILTER_MODE_INCLUDE) {
     348           0 :                     gmp_group_notify(gd, gif, MGM_GROUP_ADDED, s, g);
     349             :                 } else {
     350           0 :                     gmp_cache_resync_notify(gd, gif, s, g);
     351             :                 }
     352           0 :                 break;
     353             : 
     354           0 :             case GMPR_NOTIF_BLOCK_SOURCE:
     355           0 :                 if (notification->notif_filter_mode ==
     356             :                         GMP_FILTER_MODE_INCLUDE) {
     357           0 :                     gmp_group_notify(gd, gif, MGM_GROUP_REMOVED, s, g);
     358             :                 } else {
     359           0 :                     gmp_cache_resync_notify(gd, gif, s, g);
     360             :                 }
     361           0 :                 break;
     362             : 
     363           0 :             case GMPR_NOTIF_GROUP_DELETE:
     364           0 :                 gmp_group_notify(gd, gif, MGM_GROUP_SRC_REMOVED, s, g);
     365           0 :                 gmp_group_notify(gd, gif, MGM_GROUP_REMOVED, s, g);
     366           0 :                 break;
     367             : 
     368           0 :             case GMPR_NOTIF_GROUP_ADD_EXCL:
     369             :                 /*
     370             :                  * Check if PIM requested a refresh.
     371             :                  * If so we don't send a group and source REMOVE
     372             :                  * otherwise PIM will clear its state
     373             :                  */
     374           0 :                 if (gd->refresh_required == FALSE) {
     375           0 :                     gmp_group_notify(gd, gif, MGM_GROUP_SRC_REMOVED, s, g);
     376             :                 }
     377           0 :                 gmp_group_notify(gd, gif, MGM_GROUP_ADDED, s, g);
     378           0 :                 break;
     379             : 
     380           0 :             case GMPR_NOTIF_GROUP_ADD_INCL:
     381             :                 /*
     382             :                  * Check if PIM requested a refresh.
     383             :                  * If so we don't send a group and source REMOVE
     384             :                  * otherwise PIM will clear its state
     385             :                  */
     386           0 :                 if (gd->refresh_required == FALSE) {
     387           0 :                     gmp_group_notify(gd, gif, MGM_GROUP_SRC_REMOVED, s, g);
     388           0 :                     gmp_group_notify(gd, gif, MGM_GROUP_REMOVED, s, g);
     389             :                 }
     390           0 :                 break;
     391             : 
     392           0 :             case GMPR_NOTIF_REFRESH_END:
     393           0 :                 gd->refresh_required = FALSE;
     394           0 :                 break;
     395             : 
     396           0 :             default:
     397             :                 /* We should never get here */
     398           0 :                 assert(0);
     399             :         }
     400             :     }
     401             : 
     402             :     /*
     403             :      * If there's a notification pointer, it means that we bailed out due
     404             :      * to hitting the notification count limit or someone is too busy to
     405             :      * process the updates.
     406             :      *
     407             :      * Either way, we explicitly toss the notification block and then fall
     408             :      * out, which causes the job to be requeued.
     409             :      *
     410             :      * On the other hand, if the notification pointer is NULL, it means that
     411             :      * we drained the queue, in which case we should kill the job.
     412             :      */
     413           0 :      if (notification) {
     414           0 :          gmpr_return_notification(notification);
     415           0 :          pending = TRUE;
     416             :      }
     417             : 
     418           0 :      return pending;
     419             : }
     420             : 
     421             : // Per host, per-<S,G> notification to indicate join or leave
     422             : // among others of an host.
     423           0 : boolean gmp_client_host_notification(mgm_global_data *gd)
     424             : {
     425           0 :     boolean pending = FALSE;
     426           0 :     gmpr_client_host_notification *gmpr_notif = NULL;
     427             :     gmp_intf *gif;
     428             :     gmp_intf_handle *handle;
     429             :     gmp_addr_string g;
     430             :     gmp_addr_string s;
     431             :     gmp_addr_string h;
     432           0 :     int notif_count = IGMP_MAX_HOST_NOTIF_PER_PASS;
     433             : 
     434             :     /*
     435             :      *  Do this a limited number of times.
     436             :      */
     437           0 :     while (notif_count--) {
     438             :         /*
     439             :          *  Stop if there are no more notifications.
     440             :          */
     441             :         gmpr_notif =
     442           0 :             gmpr_get_host_notification(gd->mgm_gmpr_client, gmpr_notif);
     443           0 :         if (!gmpr_notif) {
     444           0 :             break;
     445             :         }
     446             : 
     447             :         /*
     448             :          *  Skip NULL MIFs (local groups).
     449             :          */
     450           0 :         handle = gmpr_notif->host_notif_intf_id;
     451           0 :         gif = gmp_handle_to_gif(handle);
     452           0 :         if (!gif) {
     453           0 :             continue;
     454             :         }
     455             : 
     456             :         /*
     457             :          *  Get needed addresses.
     458             :          */
     459           0 :         memcpy(&g, &gmpr_notif->host_notif_group_addr, IPV4_ADDR_LEN);
     460           0 :         memcpy(&s, &gmpr_notif->host_notif_source_addr, IPV4_ADDR_LEN);
     461           0 :         memcpy(&h, &gmpr_notif->host_notif_host_addr, IPV4_ADDR_LEN);
     462             : 
     463             :         /*
     464             :          *  Update mapped OIF module.
     465             :          */
     466           0 :         switch (gmpr_notif->host_notif_type) {
     467           0 :             case GMPR_NOTIF_HOST_UNKNOWN:
     468           0 :                 break;
     469             : 
     470           0 :             case GMPR_NOTIF_HOST_JOIN:
     471             :                 /*
     472             :                  *  This is a join.
     473             :                  */
     474           0 :                 gmp_host_update(gd, gif, TRUE, h, s, g);
     475           0 :                 break;
     476             : 
     477           0 :             case GMPR_NOTIF_HOST_LEAVE:
     478             :             case GMPR_NOTIF_HOST_TIMEOUT:
     479             :             case GMPR_NOTIF_HOST_IFDOWN:
     480             :                 /*
     481             :                  *  This is a leave.
     482             :                  */
     483           0 :                 gmp_host_update(gd, gif, FALSE, h, s, g);
     484           0 :                 break;
     485             : 
     486           0 :             default:
     487           0 :                 assert(0);
     488             :                 break;
     489             :         }
     490             :     }
     491             : 
     492             :     /*
     493             :      * If there's a notification pointer, it means that we bailed out
     494             :      * due to hitting the notification count limit.  In that case we
     495             :      * explicitly toss the notification block and then fall out, which
     496             :      * causes the job to be requeued.
     497             :      *
     498             :      * On the other hand, if the notification pointer is NULL, it means that
     499             :      * we drained the queue, in which case we should kill the job.
     500             :      */
     501           0 :     if (gmpr_notif) {
     502           0 :         gmpr_return_host_notification(gmpr_notif);
     503           0 :         pending = TRUE;
     504             :     }
     505             : 
     506           0 :     return pending;
     507             : }
     508             : 
     509             : // Top level handler to handle both <S,G> and also
     510             : // per-host, per-<S,G> notifications.
     511           0 : boolean gmp_notification_handler(mgm_global_data *gd)
     512             : {
     513           0 :     boolean pending = FALSE;
     514             : 
     515           0 :     pending |= gmp_client_notification(gd);
     516             : 
     517           0 :     pending |= gmp_client_host_notification(gd);
     518             : 
     519           0 :     return pending;
     520             : }
     521             : 
     522             : // per-<S,G> notification handler registered with GMP.
     523             : // Triggers the agent IGMP TaskTrigger instance
     524           0 : void igmp_notification_ready(void *context)
     525             : {
     526           0 :     mgm_global_data *gd = (mgm_global_data *)context;
     527             : 
     528           0 :     gmp_notification_ready(gd);
     529           0 : }
     530             : 
     531             : // per-host, per-<S,G> notification handler registered with GMP.
     532             : // Triggers the agent IGMP TaskTrigger instance
     533           0 : void igmp_host_notification_ready(void *context)
     534             : {
     535           0 :     mgm_global_data *gd = (mgm_global_data *)context;
     536             : 
     537           0 :     gmp_notification_ready(gd);
     538           0 : }
     539             : 
     540             : // No-op for now. Single querier support per-compute
     541           3 : void mgm_querier_change(void *cli_context UNUSED, gmp_intf_handle *handle,
     542             :                 boolean querier, u_int8_t *querier_addr)
     543             : {
     544           3 :     return;
     545             : }
     546             : 
     547             : // Tracing utility mapped to Multicast trace.
     548           1 : void gmpx_trace(void *context, const char *fmt, ...)
     549             : {
     550             :     va_list arglist;
     551             :     char dest[MAXSTRINGSIZE_1];
     552           1 :     va_start( arglist, fmt );
     553           1 :     vsprintf(dest, fmt, arglist);
     554           1 :     va_end( arglist );
     555             :     char buff[MAXSTRINGSIZE_1];
     556           1 :     snprintf(buff, sizeof(buff), dest, arglist);
     557             : 
     558           1 :     MCTRACE(Info, "igmp_trace: ", buff);
     559             : 
     560           2 :     return;
     561             : }
     562             : 
     563             : // Not used.
     564           0 : void gmpx_post_event(void *context, gmpx_event_type ev,
     565             :                 const void *parms, ...)
     566             : {
     567           0 :     return;
     568             : }
     569             : 
     570             : // Send one IGMP packet at a time.
     571           3 : bool igmp_send_one_packet(gmp_intf_handle *intf)
     572             : {
     573           3 :     uint8_t *pkt = NULL;
     574             :     gmp_addr_string dest_addr;
     575             :     mgm_global_data *gd;
     576             :     gmp_intf *gif;
     577             : 
     578           3 :     gd = &mgm_global[MCAST_AF_IPV4];
     579           3 :     gif = gmp_handle_to_gif(intf);
     580           3 :     if (!gif) {
     581           0 :         return false;
     582             :     }
     583             : 
     584           3 :     pkt = gmp_get_send_buffer(gd, gif);
     585           3 :     if (!pkt) {
     586           0 :         return false;
     587             :     }
     588             : 
     589           3 :     uint32_t formatted_len = igmp_next_xmit_packet(GMP_ROLE_ROUTER, intf, pkt,
     590             :                                     dest_addr.gmp_v4_addr, 1500, gd, 0);
     591           3 :     if (formatted_len == 0) {
     592           3 :         gmp_free_send_buffer(gd, gif, pkt);
     593           3 :         return false;
     594             :     }
     595             : 
     596           0 :     gmp_send_one_packet(gd, gif, pkt, formatted_len, dest_addr);
     597             : 
     598           0 :     gmp_free_send_buffer(gd, gif, pkt);
     599             : 
     600           0 :     return true;
     601             : }
     602             : 
     603             : // Called by GMP to send out IGMP packet.
     604           3 : void gmp_xmit_ready(gmp_role role, gmp_proto proto, gmpx_intf_id intf_id)
     605             : {
     606           3 :     if (role != GMP_ROLE_ROUTER) {
     607           0 :         return;
     608             :     }
     609             : 
     610           3 :     if (proto != GMP_PROTO_IGMP) {
     611           0 :         return;
     612             :     }
     613             : 
     614           3 :     gmp_intf_handle *intf = (gmp_intf_handle*)intf_id;
     615           3 :     if (!intf) {
     616           0 :         return;
     617             :     }
     618             : 
     619           3 :     while (igmp_send_one_packet(intf));
     620             : 
     621           3 :     return;
     622             : }
     623             : 
     624           0 : void gmp_static_peek(gmp_intf_handle *handle, gmp_proto proto,
     625             :                  gmp_packet *rcv_packet)
     626             : {
     627           0 :     return;
     628             : }
     629             : 

Generated by: LCOV version 1.14