LCOV - code coverage report
Current view: top level - plugins/igmp - igmp_report.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 75 78 96.2 %
Date: 2023-10-26 01:39:38 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /*
       2             :  *------------------------------------------------------------------
       3             :  * Copyright (c) 2018 Cisco and/or its affiliates.
       4             :  * Licensed under the Apache License, Version 2.0 (the "License");
       5             :  * you may not use this file except in compliance with the License.
       6             :  * You may obtain a copy of the License at:
       7             :  *
       8             :  *     http://www.apache.org/licenses/LICENSE-2.0
       9             :  *
      10             :  * Unless required by applicable law or agreed to in writing, software
      11             :  * distributed under the License is distributed on an "AS IS" BASIS,
      12             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13             :  * See the License for the specific language governing permissions and
      14             :  * limitations under the License.
      15             :  *------------------------------------------------------------------
      16             :  */
      17             : 
      18             : #include <igmp/igmp_report.h>
      19             : #include <igmp/igmp_pkt.h>
      20             : 
      21             : static ip46_address_t *
      22          13 : igmp_group_mk_source_list (const igmp_membership_group_v3_t * r)
      23             : {
      24          13 :   ip46_address_t *srcs = NULL;
      25             :   const ip4_address_t *s;
      26             :   u16 ii, n;
      27             : 
      28             :   /*
      29             :    * we validated this packet when we accepted it in the DP, so
      30             :    * this number is safe to use
      31             :    */
      32          13 :   n = clib_net_to_host_u16 (r->n_src_addresses);
      33             : 
      34          13 :   if (0 == n)
      35             :     {
      36             :       /* a (*,G) join has no source address specified */
      37           5 :       vec_validate (srcs, 0);
      38           5 :       srcs[0].ip4.as_u32 = 0;
      39             :     }
      40             :   else
      41             :     {
      42           8 :       vec_validate (srcs, n - 1);
      43           8 :       s = r->src_addresses;
      44             : 
      45          23 :       for (ii = 0; ii < n; ii++)
      46             :         {
      47          15 :           srcs[ii].ip4 = *s;
      48          15 :           s++;
      49             :         }
      50             :     }
      51             : 
      52          13 :   return (srcs);
      53             : }
      54             : 
      55             : static void
      56           2 : igmp_handle_group_exclude (igmp_config_t * config,
      57             :                            const igmp_membership_group_v3_t * igmp_group)
      58             : {
      59           2 :   ip46_address_t key = {
      60             :     .ip4 = igmp_group->group_address,
      61             :   };
      62             :   u16 n;
      63             : 
      64             :   /*
      65             :    * treat an exclude all sources as a *,G join
      66             :    */
      67           2 :   n = clib_net_to_host_u16 (igmp_group->n_src_addresses);
      68             : 
      69           2 :   if (0 == n)
      70             :     {
      71             :       ip46_address_t *src, *srcs;
      72             :       igmp_group_t *group;
      73             : 
      74           2 :       group = igmp_group_lookup (config, &key);
      75           2 :       srcs = igmp_group_mk_source_list (igmp_group);
      76             : 
      77           2 :       IGMP_DBG (" ..group-update: %U (*, %U)",
      78             :                 format_vnet_sw_if_index_name,
      79             :                 vnet_get_main (), config->sw_if_index, format_igmp_key, &key);
      80             : 
      81           2 :       if (NULL == group)
      82             :         {
      83           2 :           group = igmp_group_alloc (config, &key, IGMP_FILTER_MODE_INCLUDE);
      84             :         }
      85           4 :       vec_foreach (src, srcs)
      86             :       {
      87           2 :         igmp_group_src_update (group, src, IGMP_MODE_ROUTER);
      88             :       }
      89             : 
      90           2 :       vec_free (srcs);
      91             :     }
      92             :   else
      93             :     {
      94           0 :       IGMP_DBG (" ..group-update: %U (*, %U) source exclude ignored",
      95             :                 format_vnet_sw_if_index_name,
      96             :                 vnet_get_main (), config->sw_if_index, format_igmp_key, &key);
      97             :     }
      98           2 : }
      99             : 
     100             : static void
     101           5 : igmp_handle_group_block (igmp_config_t * config,
     102             :                          const igmp_membership_group_v3_t * igmp_group)
     103             : {
     104             :   ip46_address_t *s, *srcs;
     105             :   igmp_pkt_build_query_t bq;
     106             :   igmp_group_t *group;
     107           5 :   ip46_address_t key = {
     108             :     .ip4 = igmp_group->group_address,
     109             :   };
     110             : 
     111           5 :   srcs = igmp_group_mk_source_list (igmp_group);
     112           5 :   group = igmp_group_lookup (config, &key);
     113             : 
     114           5 :   IGMP_DBG (" ..group-block: %U (%U, %U)",
     115             :             format_vnet_sw_if_index_name,
     116             :             vnet_get_main (), config->sw_if_index,
     117             :             format_igmp_key, &key, format_igmp_src_addr_list, srcs);
     118             : 
     119           5 :   if (group)
     120             :     {
     121             :       igmp_src_t *src;
     122             :       /*
     123             :        * send a group+source specific query
     124             :        */
     125           4 :       igmp_pkt_build_query_init (&bq, config->sw_if_index);
     126           4 :       igmp_pkt_query_v3_add_group (&bq, group, srcs);
     127           4 :       igmp_pkt_query_v3_send (&bq);
     128             : 
     129             :       /*
     130             :        * for each source left/blocked drop the source expire timer to the leave
     131             :        * latency timer
     132             :        */
     133           9 :       vec_foreach (s, srcs)
     134             :       {
     135           5 :         src = igmp_src_lookup (group, s);
     136           5 :         if (NULL != src)
     137           5 :           igmp_src_blocked (src);
     138             :       }
     139             :     }
     140             :   /*
     141             :    * a block/leave from a group for which we have no state
     142             :    */
     143             : 
     144           5 :   vec_free (srcs);
     145           5 : }
     146             : 
     147             : static void
     148           9 : igmp_handle_group_update (igmp_config_t * config,
     149             :                           const igmp_membership_group_v3_t * igmp_group)
     150             : {
     151             :   ip46_address_t *src, *srcs;
     152             :   igmp_group_t *group;
     153           9 :   ip46_address_t key = {
     154             :     .ip4 = igmp_group->group_address,
     155             :   };
     156             : 
     157             :   /*
     158             :    * treat a TO_INC({}) as a (*,G) leave
     159             :    */
     160           9 :   if (0 == clib_net_to_host_u16 (igmp_group->n_src_addresses))
     161             :     {
     162           3 :       return (igmp_handle_group_block (config, igmp_group));
     163             :     }
     164             : 
     165           6 :   srcs = igmp_group_mk_source_list (igmp_group);
     166           6 :   group = igmp_group_lookup (config, &key);
     167             : 
     168           6 :   IGMP_DBG (" ..group-update: %U (%U, %U)",
     169             :             format_vnet_sw_if_index_name,
     170             :             vnet_get_main (), config->sw_if_index,
     171             :             format_igmp_key, &key, format_igmp_src_addr_list, srcs);
     172             : 
     173           6 :   if (NULL == group)
     174             :     {
     175           5 :       group = igmp_group_alloc (config, &key, IGMP_FILTER_MODE_INCLUDE);
     176             :     }
     177             : 
     178             :   /* create or update all sources */
     179          18 :   vec_foreach (src, srcs)
     180             :   {
     181          12 :     igmp_group_src_update (group, src, IGMP_MODE_ROUTER);
     182             :   }
     183             : 
     184           6 :   vec_free (srcs);
     185             : }
     186             : 
     187             : static void
     188          13 : igmp_handle_group (igmp_config_t * config,
     189             :                    const igmp_membership_group_v3_t * igmp_group)
     190             : {
     191          13 :   IGMP_DBG ("rx-group-report: %U",
     192             :             format_vnet_sw_if_index_name,
     193             :             vnet_get_main (), config->sw_if_index);
     194             : 
     195          13 :   switch (igmp_group->type)
     196             :     {
     197           9 :     case IGMP_MEMBERSHIP_GROUP_mode_is_include:
     198             :     case IGMP_MEMBERSHIP_GROUP_change_to_include:
     199             :     case IGMP_MEMBERSHIP_GROUP_allow_new_sources:
     200           9 :       igmp_handle_group_update (config, igmp_group);
     201           9 :       break;
     202           2 :     case IGMP_MEMBERSHIP_GROUP_block_old_sources:
     203           2 :       igmp_handle_group_block (config, igmp_group);
     204           2 :       break;
     205           2 :     case IGMP_MEMBERSHIP_GROUP_mode_is_exclude:
     206             :     case IGMP_MEMBERSHIP_GROUP_change_to_exclude:
     207           2 :       igmp_handle_group_exclude (config, igmp_group);
     208           2 :       break;
     209             :       /*
     210             :        * all other types ignored
     211             :        */
     212             :     }
     213          13 : }
     214             : 
     215             : void
     216          13 : igmp_handle_report (const igmp_report_args_t * args)
     217             : {
     218             :   const igmp_membership_group_v3_t *igmp_group;
     219             :   igmp_config_t *config;
     220             :   u16 n_groups, ii;
     221             : 
     222          13 :   config = igmp_config_lookup (args->sw_if_index);
     223             : 
     224          13 :   if (!config)
     225             :     /*
     226             :      * no IGMP config on the interface. quit
     227             :      */
     228           0 :     return;
     229             : 
     230          13 :   if (IGMP_MODE_HOST == config->mode)
     231             :     {
     232             :       /*
     233             :        * Hosts need not listen to the reports of other hosts.
     234             :        * we're done here
     235             :        */
     236           0 :       return;
     237             :     }
     238             : 
     239             :   /*
     240             :    * we validated this packet when we accepted it in the DP, so
     241             :    * this number is safe to use
     242             :    */
     243          13 :   n_groups = clib_net_to_host_u16 (args->report[0].n_groups);
     244          13 :   igmp_group = args->report[0].groups;
     245             : 
     246          26 :   for (ii = 0; ii < n_groups; ii++)
     247             :     {
     248          13 :       igmp_handle_group (config, igmp_group);
     249             : 
     250          13 :       igmp_group = group_cptr (igmp_group,
     251             :                                igmp_membership_group_v3_length (igmp_group));
     252             :     }
     253             : 
     254          13 :   igmp_proxy_device_merge_config (config, 0);
     255             : }
     256             : 
     257             : /*
     258             :  * fd.io coding-style-patch-verification: ON
     259             :  *
     260             :  * Local Variables:
     261             :  * eval: (c-set-style "gnu")
     262             :  * End:
     263             :  */

Generated by: LCOV version 1.14