X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Figmp%2Figmp_api.c;h=8c14fab4bc490e4a3bc12547ade090dabab587e2;hb=8c8acc027;hp=256f9245e353146096f17b8bfb611000b94e2b27;hpb=7b867a8e491357058d37838091ed67a2e77bce2c;p=vpp.git diff --git a/src/plugins/igmp/igmp_api.c b/src/plugins/igmp/igmp_api.c index 256f9245e35..8c14fab4bc4 100644 --- a/src/plugins/igmp/igmp_api.c +++ b/src/plugins/igmp/igmp_api.c @@ -19,6 +19,8 @@ #include #include +#include +#include /* define message IDs */ #include @@ -46,151 +48,303 @@ #include -#define foreach_igmp_plugin_api_msg \ -_(IGMP_LISTEN, igmp_listen) \ -_(IGMP_ENABLE_DISABLE, igmp_enable_disable) \ -_(IGMP_DUMP, igmp_dump) \ -_(IGMP_CLEAR_INTERFACE, igmp_clear_interface) \ -_(WANT_IGMP_EVENTS, want_igmp_events) \ +#define IGMP_MSG_ID(_id) (_id + igmp_main.msg_id_base) + +#define foreach_igmp_plugin_api_msg \ +_(IGMP_LISTEN, igmp_listen) \ +_(IGMP_ENABLE_DISABLE, igmp_enable_disable) \ +_(IGMP_PROXY_DEVICE_ADD_DEL, igmp_proxy_device_add_del) \ +_(IGMP_PROXY_DEVICE_ADD_DEL_INTERFACE, igmp_proxy_device_add_del_interface) \ +_(IGMP_DUMP, igmp_dump) \ +_(IGMP_CLEAR_INTERFACE, igmp_clear_interface) \ +_(IGMP_CLEAR_INTERFACE, igmp_clear_interface) \ +_(IGMP_GROUP_PREFIX_SET, igmp_group_prefix_set) \ +_(IGMP_GROUP_PREFIX_DUMP, igmp_group_prefix_dump) \ +_(WANT_IGMP_EVENTS, want_igmp_events) \ static void vl_api_igmp_listen_t_handler (vl_api_igmp_listen_t * mp) { vlib_main_t *vm = vlib_get_main (); vnet_main_t *vnm = vnet_get_main (); - igmp_main_t *im = &igmp_main; vl_api_igmp_listen_reply_t *rmp; - int rv = 0; - ip46_address_t saddr, gaddr; + int ii, rv = 0; + ip46_address_t gaddr, *saddrs = NULL; - if (!vnet_sw_interface_is_api_valid (vnm, ntohl (mp->sw_if_index))) - { - rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; - goto done; - } + VALIDATE_SW_IF_INDEX (&mp->group); - if ((vnet_sw_interface_get_flags (vnm, ntohl (mp->sw_if_index)) && + if ((vnet_sw_interface_get_flags (vnm, ntohl (mp->group.sw_if_index)) && VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0) { + // FIXME - don't we clear this state on interface down ... rv = VNET_API_ERROR_UNEXPECTED_INTF_STATE; goto done; } - clib_memcpy (&saddr.ip4.as_u8, mp->saddr, sizeof (u8) * 4); - clib_memcpy (&gaddr.ip4.as_u8, mp->gaddr, sizeof (u8) * 4); + clib_memset (&gaddr, 0, sizeof (gaddr)); + clib_memcpy (&gaddr.ip4, &mp->group.gaddr, sizeof (ip4_address_t)); - rv = igmp_listen (vm, mp->enable, ntohl (mp->sw_if_index), saddr, gaddr, 1); + vec_validate (saddrs, mp->group.n_srcs - 1); -done:; - unix_shared_memory_queue_t *q = - vl_api_client_index_to_input_queue (mp->client_index); - if (!q) - return; + vec_foreach_index (ii, saddrs) + { + clib_memcpy (&saddrs[ii].ip4, + &mp->group.saddrs[ii], sizeof (ip4_address_t)); + } - rmp = vl_msg_api_alloc (sizeof (*rmp)); - rmp->_vl_msg_id = htons ((VL_API_IGMP_LISTEN_REPLY) + im->msg_id_base); - rmp->context = mp->context; - rmp->retval = htonl (rv); + rv = igmp_listen (vm, + (mp->group.filter ? + IGMP_FILTER_MODE_INCLUDE : + IGMP_FILTER_MODE_EXCLUDE), + ntohl (mp->group.sw_if_index), saddrs, &gaddr); - vl_msg_api_send_shmem (q, (u8 *) & rmp); + vec_free (saddrs); + + BAD_SW_IF_INDEX_LABEL; +done:; + REPLY_MACRO (IGMP_MSG_ID (VL_API_IGMP_LISTEN_REPLY)); } static void vl_api_igmp_enable_disable_t_handler (vl_api_igmp_enable_disable_t * mp) { vl_api_igmp_enable_disable_reply_t *rmp; - igmp_main_t *im = &igmp_main; int rv = 0; - REPLY_MACRO (VL_API_IGMP_ENABLE_DISABLE_REPLY + im->msg_id_base); + VALIDATE_SW_IF_INDEX (mp); + + rv = igmp_enable_disable (ntohl (mp->sw_if_index), + mp->enable, + (mp->mode ? IGMP_MODE_HOST : IGMP_MODE_ROUTER)); + + BAD_SW_IF_INDEX_LABEL; + + REPLY_MACRO (IGMP_MSG_ID (VL_API_IGMP_ENABLE_DISABLE_REPLY)); +} + +static void +vl_api_igmp_proxy_device_add_del_t_handler (vl_api_igmp_proxy_device_add_del_t + * mp) +{ + vl_api_igmp_proxy_device_add_del_reply_t *rmp; + int rv = 0; + + VALIDATE_SW_IF_INDEX (mp); + + rv = + igmp_proxy_device_add_del (ntohl (mp->vrf_id), ntohl (mp->sw_if_index), + mp->add); + + BAD_SW_IF_INDEX_LABEL; + + REPLY_MACRO (IGMP_MSG_ID (VL_API_IGMP_PROXY_DEVICE_ADD_DEL_REPLY)); +} + +static void + vl_api_igmp_proxy_device_add_del_interface_t_handler + (vl_api_igmp_proxy_device_add_del_interface_t * mp) +{ + vl_api_igmp_proxy_device_add_del_interface_reply_t *rmp; + int rv = 0; + + VALIDATE_SW_IF_INDEX (mp); + + rv = + igmp_proxy_device_add_del_interface (ntohl (mp->vrf_id), + ntohl (mp->sw_if_index), mp->add); + + BAD_SW_IF_INDEX_LABEL; + + REPLY_MACRO (IGMP_MSG_ID + (VL_API_IGMP_PROXY_DEVICE_ADD_DEL_INTERFACE_REPLY)); } static void send_igmp_details (unix_shared_memory_queue_t * q, igmp_main_t * im, - igmp_config_t * config, igmp_sg_t * sg, u32 context) + igmp_config_t * config, igmp_group_t * group, + igmp_src_t * src, u32 context) { vl_api_igmp_details_t *mp; mp = vl_msg_api_alloc (sizeof (*mp)); - memset (mp, 0, sizeof (*mp)); + clib_memset (mp, 0, sizeof (*mp)); - mp->_vl_msg_id = htons (VL_API_IGMP_DETAILS + im->msg_id_base); + mp->_vl_msg_id = htons (IGMP_MSG_ID (VL_API_IGMP_DETAILS)); mp->context = context; mp->sw_if_index = htonl (config->sw_if_index); - clib_memcpy (mp->saddr, &sg->saddr.ip4, sizeof (u8) * 4); - clib_memcpy (mp->gaddr, &sg->gaddr.ip4, sizeof (u8) * 4); + clib_memcpy (mp->saddr, &src->key->ip4, sizeof (src->key->ip4)); + clib_memcpy (mp->gaddr, &group->key->ip4, sizeof (group->key->ip4)); vl_msg_api_send_shmem (q, (u8 *) & mp); } +static void +igmp_config_dump (igmp_main_t * im, + unix_shared_memory_queue_t * q, + u32 context, igmp_config_t * config) +{ + igmp_group_t *group; + igmp_src_t *src; + + /* *INDENT-OFF* */ + FOR_EACH_GROUP (group, config, + ({ + FOR_EACH_SRC (src, group, IGMP_FILTER_MODE_INCLUDE, + ({ + send_igmp_details (q, im, config, group, src, context); + })); + })); + /* *INDENT-ON* */ +} + static void vl_api_igmp_dump_t_handler (vl_api_igmp_dump_t * mp) { + unix_shared_memory_queue_t *q; igmp_main_t *im = &igmp_main; igmp_config_t *config; - igmp_sg_t *sg; + u32 sw_if_index; - unix_shared_memory_queue_t *q = - vl_api_client_index_to_input_queue (mp->client_index); + q = vl_api_client_index_to_input_queue (mp->client_index); if (!q) return; - if (mp->dump_all) + sw_if_index = ntohl (mp->sw_if_index); + if (~0 == sw_if_index) { /* *INDENT-OFF* */ - pool_foreach (config, im->configs, ( - { - pool_foreach (sg, config->sg, ( - { - send_igmp_details (q, im, config, sg, mp->context); - })); + pool_foreach (config, im->configs, + ({ + igmp_config_dump(im, q, mp->context, config); })); /* *INDENT-ON* */ - return; } - config = igmp_config_lookup (im, ntohl (mp->sw_if_index)); - if (config) + else { - /* *INDENT-OFF* */ - pool_foreach (sg, config->sg, ( + config = igmp_config_lookup (sw_if_index); + if (config) { - send_igmp_details (q, im, config, sg, mp->context); - })); - /* *INDENT-ON* */ + igmp_config_dump (im, q, mp->context, config); + } } } static void vl_api_igmp_clear_interface_t_handler (vl_api_igmp_clear_interface_t * mp) { - igmp_main_t *im = &igmp_main; - igmp_config_t *config; vl_api_igmp_clear_interface_reply_t *rmp; + igmp_config_t *config; int rv = 0; - config = igmp_config_lookup (im, ntohl (mp->sw_if_index)); + config = igmp_config_lookup (ntohl (mp->sw_if_index)); if (config) igmp_clear_config (config); - unix_shared_memory_queue_t *q = - vl_api_client_index_to_input_queue (mp->client_index); + REPLY_MACRO (IGMP_MSG_ID (VL_API_IGMP_CLEAR_INTERFACE_REPLY)); +} + +static vl_api_group_prefix_type_t +igmp_group_type_int_to_api (igmp_group_prefix_type_t t) +{ + switch (t) + { + case IGMP_GROUP_PREFIX_TYPE_ASM: + return (htonl (ASM)); + case IGMP_GROUP_PREFIX_TYPE_SSM: + return (htonl (SSM)); + } + + return (SSM); +} + +static igmp_group_prefix_type_t +igmp_group_type_api_to_int (vl_api_group_prefix_type_t t) +{ + switch (htonl (t)) + { + case ASM: + return (IGMP_GROUP_PREFIX_TYPE_ASM); + case SSM: + return (IGMP_GROUP_PREFIX_TYPE_SSM); + } + + return (IGMP_GROUP_PREFIX_TYPE_SSM); +} + +static void +vl_api_igmp_group_prefix_set_t_handler (vl_api_igmp_group_prefix_set_t * mp) +{ + vl_api_igmp_group_prefix_set_reply_t *rmp; + fib_prefix_t pfx; + int rv = 0; + + ip_prefix_decode (&mp->gp.prefix, &pfx); + igmp_group_prefix_set (&pfx, igmp_group_type_api_to_int (mp->gp.type)); + + REPLY_MACRO (IGMP_MSG_ID (VL_API_IGMP_GROUP_PREFIX_SET_REPLY)); +} + +typedef struct igmp_ssm_range_walk_ctx_t_ +{ + unix_shared_memory_queue_t *q; + u32 context; +} igmp_ssm_range_walk_ctx_t; + +static walk_rc_t +igmp_ssm_range_walk_dump (const fib_prefix_t * pfx, + igmp_group_prefix_type_t type, void *args) +{ + igmp_ssm_range_walk_ctx_t *ctx = args; + vl_api_igmp_group_prefix_details_t *mp; + + mp = vl_msg_api_alloc (sizeof (*mp)); + clib_memset (mp, 0, sizeof (*mp)); + + mp->_vl_msg_id = htons (IGMP_MSG_ID (VL_API_IGMP_DETAILS)); + mp->context = ctx->context; + mp->gp.type = igmp_group_type_int_to_api (type); + ip_prefix_encode (pfx, &mp->gp.prefix); + + vl_msg_api_send_shmem (ctx->q, (u8 *) & mp); + + return (WALK_CONTINUE); +} + +static void +vl_api_igmp_group_prefix_dump_t_handler (vl_api_igmp_dump_t * mp) +{ + unix_shared_memory_queue_t *q; + + q = vl_api_client_index_to_input_queue (mp->client_index); if (!q) return; - rmp = vl_msg_api_alloc (sizeof (*rmp)); - rmp->_vl_msg_id = - htons ((VL_API_IGMP_CLEAR_INTERFACE_REPLY) + im->msg_id_base); - rmp->context = mp->context; - rmp->retval = htonl (rv); + igmp_ssm_range_walk_ctx_t ctx = { + .q = q, + .context = mp->context, + }; + + igmp_ssm_range_walk (igmp_ssm_range_walk_dump, &ctx); +} + +static vpe_client_registration_t * +igmp_api_client_lookup (igmp_main_t * im, u32 client_index) +{ + uword *p; + vpe_client_registration_t *api_client = NULL; + + p = hash_get (im->igmp_api_client_by_client_index, client_index); + if (p) + api_client = vec_elt_at_index (im->api_clients, p[0]); - vl_msg_api_send_shmem (q, (u8 *) & rmp); + return api_client; } static void vl_api_want_igmp_events_t_handler (vl_api_want_igmp_events_t * mp) { igmp_main_t *im = &igmp_main; - igmp_api_client_t *api_client; + vpe_client_registration_t *api_client; vl_api_want_igmp_events_reply_t *rmp; int rv = 0; @@ -202,80 +356,93 @@ vl_api_want_igmp_events_t_handler (vl_api_want_igmp_events_t * mp) rv = VNET_API_ERROR_INVALID_REGISTRATION; goto done; } - hash_unset_mem (im->igmp_api_client_by_client_index, - &api_client->client_index); + hash_unset (im->igmp_api_client_by_client_index, + api_client->client_index); pool_put (im->api_clients, api_client); goto done; } if (mp->enable) { pool_get (im->api_clients, api_client); - memset (api_client, 0, sizeof (igmp_api_client_t)); + clib_memset (api_client, 0, sizeof (vpe_client_registration_t)); api_client->client_index = mp->client_index; - api_client->pid = mp->pid; - hash_set_mem (im->igmp_api_client_by_client_index, - &mp->client_index, api_client - im->api_clients); + api_client->client_pid = mp->pid; + hash_set (im->igmp_api_client_by_client_index, + mp->client_index, api_client - im->api_clients); goto done; } rv = VNET_API_ERROR_INVALID_REGISTRATION; done:; - unix_shared_memory_queue_t *q = - vl_api_client_index_to_input_queue (mp->client_index); - if (!q) - return; + REPLY_MACRO (VL_API_WANT_IGMP_EVENTS_REPLY + im->msg_id_base); +} + +static clib_error_t * +want_igmp_events_reaper (u32 client_index) +{ + igmp_main_t *im = &igmp_main; + vpe_client_registration_t *api_client; + uword *p; - rmp = vl_msg_api_alloc (sizeof (*rmp)); - rmp->_vl_msg_id = htons ((VL_API_WANT_IGMP_EVENTS_REPLY) + im->msg_id_base); - rmp->context = mp->context; - rmp->retval = htonl (rv); + p = hash_get (im->igmp_api_client_by_client_index, client_index); - vl_msg_api_send_shmem (q, (u8 *) & rmp); + if (p) + { + api_client = pool_elt_at_index (im->api_clients, p[0]); + pool_put (im->api_clients, api_client); + hash_unset (im->igmp_api_client_by_client_index, client_index); + } + return (NULL); } +VL_MSG_API_REAPER_FUNCTION (want_igmp_events_reaper); + void -send_igmp_event (unix_shared_memory_queue_t * q, u32 context, - igmp_main_t * im, igmp_config_t * config, igmp_sg_t * sg) +send_igmp_event (unix_shared_memory_queue_t * q, + u32 context, + igmp_filter_mode_t filter, + u32 sw_if_index, + const ip46_address_t * saddr, const ip46_address_t * gaddr) { vl_api_igmp_event_t *mp = vl_msg_api_alloc (sizeof (*mp)); - memset (mp, 0, sizeof (*mp)); + clib_memset (mp, 0, sizeof (*mp)); - mp->_vl_msg_id = ntohs ((VL_API_IGMP_EVENT) + im->msg_id_base); + mp->_vl_msg_id = ntohs ((VL_API_IGMP_EVENT) + igmp_main.msg_id_base); mp->context = context; - mp->sw_if_index = htonl (config->sw_if_index); - clib_memcpy (&mp->saddr, &sg->saddr.ip4, sizeof (ip4_address_t)); - clib_memcpy (&mp->gaddr, &sg->gaddr.ip4, sizeof (ip4_address_t)); - mp->is_join = - (sg->group_type == IGMP_MEMBERSHIP_GROUP_mode_is_filter_include) ? 1 : 0; + mp->sw_if_index = htonl (sw_if_index); + mp->filter = htonl (filter); + clib_memcpy (&mp->saddr, &saddr->ip4, sizeof (ip4_address_t)); + clib_memcpy (&mp->gaddr, &gaddr->ip4, sizeof (ip4_address_t)); vl_msg_api_send_shmem (q, (u8 *) & mp); } void -igmp_event (igmp_main_t * im, igmp_config_t * config, igmp_sg_t * sg) +igmp_event (igmp_filter_mode_t filter, + u32 sw_if_index, + const ip46_address_t * saddr, const ip46_address_t * gaddr) { - igmp_api_client_t *api_client; + vpe_client_registration_t *api_client; unix_shared_memory_queue_t *q; + igmp_main_t *im; + + im = &igmp_main; + + IGMP_DBG ("event: (%U, %U) %U %U", + format_ip46_address, saddr, IP46_TYPE_ANY, + format_ip46_address, saddr, IP46_TYPE_ANY, + format_vnet_sw_if_index_name, + vnet_get_main (), sw_if_index, format_igmp_filter_mode, filter); + + /* *INDENT-OFF* */ pool_foreach (api_client, im->api_clients, ({ q = vl_api_client_index_to_input_queue (api_client->client_index); if (q) - send_igmp_event (q, 0, im, config, sg); + send_igmp_event (q, 0, filter, sw_if_index, saddr, gaddr); })); /* *INDENT-ON* */ - if (sg->group_type == IGMP_MEMBERSHIP_GROUP_block_old_sources) - { - hash_unset_mem (config->igmp_sg_by_key, sg->key); - clib_mem_free (sg->key); - pool_put (config->sg, sg); - if (pool_elts (config->sg) == 0) - { - hash_unset_mem (im->igmp_config_by_sw_if_index, - &config->sw_if_index); - pool_put (im->configs, config); - } - } } #define vl_msg_name_crc_list