LCOV - code coverage report
Current view: top level - plugins/igmp - igmp_api.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 120 168 71.4 %
Date: 2023-10-26 01:39:38 Functions: 17 22 77.3 %

          Line data    Source code
       1             : /*
       2             :  *------------------------------------------------------------------
       3             :  * Copyright (c) 2017 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.h>
      19             : 
      20             : #include <vlibapi/api.h>
      21             : #include <vlibmemory/api.h>
      22             : #include <vnet/ip/ip_types_api.h>
      23             : #include <igmp/igmp_ssm_range.h>
      24             : 
      25             : /* define message IDs */
      26             : #include <igmp/igmp.api_enum.h>
      27             : #include <igmp/igmp.api_types.h>
      28             : #include <vnet/format_fns.h>
      29             : 
      30             : #include <vlibapi/api_helper_macros.h>
      31             : 
      32             : #define IGMP_MSG_ID(_id) (_id + igmp_main.msg_id_base)
      33             : 
      34             : static void
      35          21 : vl_api_igmp_listen_t_handler (vl_api_igmp_listen_t * mp)
      36             : {
      37          21 :   vlib_main_t *vm = vlib_get_main ();
      38          21 :   vnet_main_t *vnm = vnet_get_main ();
      39             :   vl_api_igmp_listen_reply_t *rmp;
      40          21 :   int ii, rv = 0;
      41          21 :   ip46_address_t gaddr, *saddrs = NULL;
      42             : 
      43          21 :   VALIDATE_SW_IF_INDEX (&mp->group);
      44             : 
      45          21 :   if ((vnet_sw_interface_get_flags (vnm, ntohl (mp->group.sw_if_index)) &&
      46             :        VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0)
      47             :     {
      48             :       // FIXME - don't we clear this state on interface down ...
      49           0 :       rv = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
      50           0 :       goto done;
      51             :     }
      52             : 
      53          21 :   clib_memset (&gaddr, 0, sizeof (gaddr));
      54          21 :   clib_memcpy (&gaddr.ip4, &mp->group.gaddr, sizeof (ip4_address_t));
      55             : 
      56          21 :   vec_validate (saddrs, mp->group.n_srcs - 1);
      57             : 
      58         453 :   vec_foreach_index (ii, saddrs)
      59             :   {
      60         432 :     clib_memcpy (&saddrs[ii].ip4,
      61             :                  &mp->group.saddrs[ii], sizeof (ip4_address_t));
      62             :   }
      63             : 
      64          21 :   rv = igmp_listen (vm,
      65          21 :                     (mp->group.filter ?
      66             :                      IGMP_FILTER_MODE_INCLUDE :
      67             :                      IGMP_FILTER_MODE_EXCLUDE),
      68             :                     ntohl (mp->group.sw_if_index), saddrs, &gaddr);
      69             : 
      70          21 :   vec_free (saddrs);
      71             : 
      72          21 :   BAD_SW_IF_INDEX_LABEL;
      73          21 : done:;
      74          21 :   REPLY_MACRO (VL_API_IGMP_LISTEN_REPLY);
      75             : }
      76             : 
      77             : static void
      78          18 : vl_api_igmp_enable_disable_t_handler (vl_api_igmp_enable_disable_t * mp)
      79             : {
      80             :   vl_api_igmp_enable_disable_reply_t *rmp;
      81          18 :   int rv = 0;
      82             : 
      83          18 :   VALIDATE_SW_IF_INDEX (mp);
      84             : 
      85          18 :   rv = igmp_enable_disable (ntohl (mp->sw_if_index),
      86          18 :                             mp->enable,
      87          18 :                             (mp->mode ? IGMP_MODE_HOST : IGMP_MODE_ROUTER));
      88             : 
      89          18 :   BAD_SW_IF_INDEX_LABEL;
      90             : 
      91          18 :   REPLY_MACRO (VL_API_IGMP_ENABLE_DISABLE_REPLY);
      92             : }
      93             : 
      94             : static void
      95           1 : vl_api_igmp_proxy_device_add_del_t_handler (vl_api_igmp_proxy_device_add_del_t
      96             :                                             * mp)
      97             : {
      98             :   vl_api_igmp_proxy_device_add_del_reply_t *rmp;
      99           1 :   int rv = 0;
     100             : 
     101           1 :   VALIDATE_SW_IF_INDEX (mp);
     102             : 
     103             :   rv =
     104           1 :     igmp_proxy_device_add_del (ntohl (mp->vrf_id), ntohl (mp->sw_if_index),
     105           1 :                                mp->add);
     106             : 
     107           1 :   BAD_SW_IF_INDEX_LABEL;
     108             : 
     109           1 :   REPLY_MACRO (VL_API_IGMP_PROXY_DEVICE_ADD_DEL_REPLY);
     110             : }
     111             : 
     112             : static void
     113           2 :   vl_api_igmp_proxy_device_add_del_interface_t_handler
     114             :   (vl_api_igmp_proxy_device_add_del_interface_t * mp)
     115             : {
     116             :   vl_api_igmp_proxy_device_add_del_interface_reply_t *rmp;
     117           2 :   int rv = 0;
     118             : 
     119           2 :   VALIDATE_SW_IF_INDEX (mp);
     120             : 
     121             :   rv =
     122           2 :     igmp_proxy_device_add_del_interface (ntohl (mp->vrf_id),
     123           2 :                                          ntohl (mp->sw_if_index), mp->add);
     124             : 
     125           2 :   BAD_SW_IF_INDEX_LABEL;
     126             : 
     127           2 :   REPLY_MACRO (VL_API_IGMP_PROXY_DEVICE_ADD_DEL_INTERFACE_REPLY);
     128             : }
     129             : 
     130             : static void
     131          14 : send_igmp_details (vl_api_registration_t * rp, igmp_main_t * im,
     132             :                    igmp_config_t * config, igmp_group_t * group,
     133             :                    igmp_src_t * src, u32 context)
     134             : {
     135             :   vl_api_igmp_details_t *mp;
     136             : 
     137          14 :   mp = vl_msg_api_alloc (sizeof (*mp));
     138          14 :   clib_memset (mp, 0, sizeof (*mp));
     139             : 
     140          14 :   mp->_vl_msg_id = htons (IGMP_MSG_ID (VL_API_IGMP_DETAILS));
     141          14 :   mp->context = context;
     142          14 :   mp->sw_if_index = htonl (config->sw_if_index);
     143          14 :   clib_memcpy (&mp->saddr, &src->key->ip4, sizeof (src->key->ip4));
     144          14 :   clib_memcpy (&mp->gaddr, &group->key->ip4, sizeof (group->key->ip4));
     145             : 
     146          14 :   vl_api_send_msg (rp, (u8 *) mp);
     147          14 : }
     148             : 
     149             : static void
     150          14 : igmp_config_dump (igmp_main_t * im,
     151             :                   vl_api_registration_t * rp,
     152             :                   u32 context, igmp_config_t * config)
     153             : {
     154             :   igmp_group_t *group;
     155             :   igmp_src_t *src;
     156             : 
     157             :   /* *INDENT-OFF* */
     158        1444 :   FOR_EACH_GROUP (group, config,
     159             :     ({
     160             :       FOR_EACH_SRC (src, group, IGMP_FILTER_MODE_INCLUDE,
     161             :         ({
     162             :           send_igmp_details (rp, im, config, group, src, context);
     163             :         }));
     164             :     }));
     165             :   /* *INDENT-ON* */
     166          14 : }
     167             : 
     168             : static void
     169          15 : vl_api_igmp_dump_t_handler (vl_api_igmp_dump_t * mp)
     170             : {
     171          15 :   igmp_main_t *im = &igmp_main;
     172             :   igmp_config_t *config;
     173             :   u32 sw_if_index;
     174             :   vl_api_registration_t *rp;
     175             : 
     176          15 :   rp = vl_api_client_index_to_registration (mp->client_index);
     177          15 :   if (rp == 0)
     178           0 :     return;
     179             : 
     180          15 :   sw_if_index = ntohl (mp->sw_if_index);
     181          15 :   if (~0 == sw_if_index)
     182             :     {
     183             :       /* *INDENT-OFF* */
     184          13 :       pool_foreach (config, im->configs)
     185             :          {
     186           6 :           igmp_config_dump(im, rp, mp->context, config);
     187             :         }
     188             :       /* *INDENT-ON* */
     189             :     }
     190             :   else
     191             :     {
     192           8 :       config = igmp_config_lookup (sw_if_index);
     193           8 :       if (config)
     194             :         {
     195           8 :           igmp_config_dump (im, rp, mp->context, config);
     196             :         }
     197             :     }
     198             : }
     199             : 
     200             : static void
     201          20 : vl_api_igmp_clear_interface_t_handler (vl_api_igmp_clear_interface_t * mp)
     202             : {
     203             :   vl_api_igmp_clear_interface_reply_t *rmp;
     204             :   igmp_config_t *config;
     205          20 :   int rv = 0;
     206             : 
     207          20 :   config = igmp_config_lookup (ntohl (mp->sw_if_index));
     208          20 :   if (config)
     209           0 :     igmp_clear_config (config);
     210             : 
     211          20 :   REPLY_MACRO (VL_API_IGMP_CLEAR_INTERFACE_REPLY);
     212             : }
     213             : 
     214             : static vl_api_group_prefix_type_t
     215           0 : igmp_group_type_int_to_api (igmp_group_prefix_type_t t)
     216             : {
     217           0 :   switch (t)
     218             :     {
     219           0 :     case IGMP_GROUP_PREFIX_TYPE_ASM:
     220           0 :       return (htonl (ASM));
     221           0 :     case IGMP_GROUP_PREFIX_TYPE_SSM:
     222           0 :       return (htonl (SSM));
     223             :     }
     224             : 
     225           0 :   return (SSM);
     226             : }
     227             : 
     228             : static igmp_group_prefix_type_t
     229           0 : igmp_group_type_api_to_int (vl_api_group_prefix_type_t t)
     230             : {
     231           0 :   switch (htonl (t))
     232             :     {
     233           0 :     case ASM:
     234           0 :       return (IGMP_GROUP_PREFIX_TYPE_ASM);
     235           0 :     case SSM:
     236           0 :       return (IGMP_GROUP_PREFIX_TYPE_SSM);
     237             :     }
     238             : 
     239           0 :   return (IGMP_GROUP_PREFIX_TYPE_SSM);
     240             : }
     241             : 
     242             : static void
     243           0 : vl_api_igmp_group_prefix_set_t_handler (vl_api_igmp_group_prefix_set_t * mp)
     244             : {
     245             :   vl_api_igmp_group_prefix_set_reply_t *rmp;
     246             :   fib_prefix_t pfx;
     247           0 :   int rv = 0;
     248             : 
     249           0 :   ip_prefix_decode (&mp->gp.prefix, &pfx);
     250           0 :   igmp_group_prefix_set (&pfx, igmp_group_type_api_to_int (mp->gp.type));
     251             : 
     252           0 :   REPLY_MACRO (VL_API_IGMP_GROUP_PREFIX_SET_REPLY);
     253             : }
     254             : 
     255             : typedef struct igmp_ssm_range_walk_ctx_t_
     256             : {
     257             :   vl_api_registration_t *rp;
     258             :   u32 context;
     259             : } igmp_ssm_range_walk_ctx_t;
     260             : 
     261             : static walk_rc_t
     262           0 : igmp_ssm_range_walk_dump (const fib_prefix_t * pfx,
     263             :                           igmp_group_prefix_type_t type, void *args)
     264             : {
     265           0 :   igmp_ssm_range_walk_ctx_t *ctx = args;
     266             :   vl_api_igmp_group_prefix_details_t *mp;
     267             : 
     268           0 :   mp = vl_msg_api_alloc (sizeof (*mp));
     269           0 :   clib_memset (mp, 0, sizeof (*mp));
     270             : 
     271           0 :   mp->_vl_msg_id = htons (IGMP_MSG_ID (VL_API_IGMP_DETAILS));
     272           0 :   mp->context = ctx->context;
     273           0 :   mp->gp.type = igmp_group_type_int_to_api (type);
     274           0 :   ip_prefix_encode (pfx, &mp->gp.prefix);
     275             : 
     276           0 :   vl_api_send_msg (ctx->rp, (u8 *) mp);
     277             : 
     278           0 :   return (WALK_CONTINUE);
     279             : }
     280             : 
     281             : static void
     282           0 : vl_api_igmp_group_prefix_dump_t_handler (vl_api_igmp_dump_t * mp)
     283             : {
     284             :   vl_api_registration_t *rp;
     285             : 
     286           0 :   rp = vl_api_client_index_to_registration (mp->client_index);
     287           0 :   if (rp == 0)
     288           0 :     return;
     289             : 
     290           0 :   igmp_ssm_range_walk_ctx_t ctx = {
     291             :     .rp = rp,
     292           0 :     .context = mp->context,
     293             :   };
     294             : 
     295           0 :   igmp_ssm_range_walk (igmp_ssm_range_walk_dump, &ctx);
     296             : }
     297             : 
     298             : static vpe_client_registration_t *
     299           1 : igmp_api_client_lookup (igmp_main_t * im, u32 client_index)
     300             : {
     301             :   uword *p;
     302           1 :   vpe_client_registration_t *api_client = NULL;
     303             : 
     304           1 :   p = hash_get (im->igmp_api_client_by_client_index, client_index);
     305           1 :   if (p)
     306           0 :     api_client = vec_elt_at_index (im->api_clients, p[0]);
     307             : 
     308           1 :   return api_client;
     309             : }
     310             : 
     311             : static void
     312           1 : vl_api_want_igmp_events_t_handler (vl_api_want_igmp_events_t * mp)
     313             : {
     314           1 :   igmp_main_t *im = &igmp_main;
     315             :   vpe_client_registration_t *api_client;
     316             :   vl_api_want_igmp_events_reply_t *rmp;
     317           1 :   int rv = 0;
     318             : 
     319           1 :   api_client = igmp_api_client_lookup (im, mp->client_index);
     320           1 :   if (api_client)
     321             :     {
     322           0 :       if (mp->enable)
     323             :         {
     324           0 :           rv = VNET_API_ERROR_INVALID_REGISTRATION;
     325           0 :           goto done;
     326             :         }
     327           0 :       hash_unset (im->igmp_api_client_by_client_index,
     328             :                   api_client->client_index);
     329           0 :       pool_put (im->api_clients, api_client);
     330           0 :       goto done;
     331             :     }
     332           1 :   if (mp->enable)
     333             :     {
     334           1 :       pool_get (im->api_clients, api_client);
     335           1 :       clib_memset (api_client, 0, sizeof (vpe_client_registration_t));
     336           1 :       api_client->client_index = mp->client_index;
     337           1 :       api_client->client_pid = mp->pid;
     338           1 :       hash_set (im->igmp_api_client_by_client_index,
     339             :                 mp->client_index, api_client - im->api_clients);
     340           1 :       goto done;
     341             :     }
     342           0 :   rv = VNET_API_ERROR_INVALID_REGISTRATION;
     343             : 
     344           1 : done:
     345           1 :   REPLY_MACRO (VL_API_WANT_IGMP_EVENTS_REPLY);
     346             : }
     347             : 
     348             : static clib_error_t *
     349        1241 : want_igmp_events_reaper (u32 client_index)
     350             : {
     351        1241 :   igmp_main_t *im = &igmp_main;
     352             :   vpe_client_registration_t *api_client;
     353             :   uword *p;
     354             : 
     355        1241 :   p = hash_get (im->igmp_api_client_by_client_index, client_index);
     356             : 
     357        1241 :   if (p)
     358             :     {
     359           1 :       api_client = pool_elt_at_index (im->api_clients, p[0]);
     360           1 :       pool_put (im->api_clients, api_client);
     361           1 :       hash_unset (im->igmp_api_client_by_client_index, client_index);
     362             :     }
     363        1241 :   return (NULL);
     364             : }
     365             : 
     366         575 : VL_MSG_API_REAPER_FUNCTION (want_igmp_events_reaper);
     367             : 
     368             : void
     369          16 : send_igmp_event (vl_api_registration_t * rp,
     370             :                  igmp_filter_mode_t filter,
     371             :                  u32 sw_if_index,
     372             :                  const ip46_address_t * saddr, const ip46_address_t * gaddr)
     373             : {
     374          16 :   vl_api_igmp_event_t *mp = vl_msg_api_alloc (sizeof (*mp));
     375          16 :   clib_memset (mp, 0, sizeof (*mp));
     376             : 
     377          16 :   mp->_vl_msg_id = ntohs ((VL_API_IGMP_EVENT) + igmp_main.msg_id_base);
     378          16 :   mp->sw_if_index = htonl (sw_if_index);
     379          16 :   mp->filter = htonl (filter);
     380          16 :   clib_memcpy (&mp->saddr, &saddr->ip4, sizeof (ip4_address_t));
     381          16 :   clib_memcpy (&mp->gaddr, &gaddr->ip4, sizeof (ip4_address_t));
     382             : 
     383          16 :   vl_api_send_msg (rp, (u8 *) mp);
     384          16 : }
     385             : 
     386             : void
     387          21 : igmp_event (igmp_filter_mode_t filter,
     388             :             u32 sw_if_index,
     389             :             const ip46_address_t * saddr, const ip46_address_t * gaddr)
     390             : {
     391             :   vpe_client_registration_t *api_client;
     392             :   vl_api_registration_t *rp;
     393             :   igmp_main_t *im;
     394             : 
     395          21 :   im = &igmp_main;
     396             : 
     397          21 :   IGMP_DBG ("event: (%U, %U) %U %U",
     398             :             format_ip46_address, saddr, IP46_TYPE_ANY,
     399             :             format_ip46_address, saddr, IP46_TYPE_ANY,
     400             :             format_vnet_sw_if_index_name,
     401             :             vnet_get_main (), sw_if_index, format_igmp_filter_mode, filter);
     402             : 
     403             : 
     404             :   /* *INDENT-OFF* */
     405          37 :   pool_foreach (api_client, im->api_clients)
     406             :      {
     407          16 :       rp = vl_api_client_index_to_registration (api_client->client_index);
     408          16 :       if (rp)
     409          16 :         send_igmp_event (rp, filter, sw_if_index, saddr, gaddr);
     410             :     }
     411             :   /* *INDENT-ON* */
     412          21 : }
     413             : 
     414             : /* Set up the API message handling tables */
     415             : #include <igmp/igmp.api.c>
     416             : static clib_error_t *
     417         575 : igmp_plugin_api_hookup (vlib_main_t * vm)
     418             : {
     419         575 :   igmp_main_t *im = &igmp_main;
     420             : 
     421             :   /* Ask for a correctly-sized block of API message decode slots */
     422         575 :   im->msg_id_base = setup_message_id_table ();
     423             : 
     424         575 :   return 0;
     425             : }
     426             : 
     427        1151 : VLIB_API_INIT_FUNCTION (igmp_plugin_api_hookup);
     428             : 
     429             : /*
     430             :  * fd.io coding-style-patch-verification: ON
     431             :  *
     432             :  * Local Variables:
     433             :  * eval: (c-set-style "gnu")
     434             :  * End:
     435             :  */

Generated by: LCOV version 1.14