IGMP plugin

- host mode:
  igmp_listen - API to signal that the host has joined an (S,G)

- route mode:
  igmp_enable - API to enable the reception of host IGMP messages
  igmp_event - API to report the host join/leave from an (S,G)

Change-Id: Id180ec27dee617d33ab3088f5dcf6125d3aa9c8f
Signed-off-by: Jakub Grajciar <jgrajcia@cisco.com>
This commit is contained in:
Jakub Grajciar
2017-12-08 16:28:42 +01:00
committed by Chris Luke
parent 489cc82922
commit 7b867a8e49
20 changed files with 3190 additions and 2 deletions

View File

@ -216,6 +216,7 @@ PLUGIN_ENABLED(dpdk)
PLUGIN_ENABLED(flowprobe)
PLUGIN_ENABLED(gbp)
PLUGIN_ENABLED(gtpu)
PLUGIN_ENABLED(igmp)
PLUGIN_ENABLED(ila)
PLUGIN_ENABLED(ioam)
PLUGIN_ENABLED(ixge)

View File

@ -51,6 +51,10 @@ if ENABLE_GTPU_PLUGIN
include gtpu.am
endif
if ENABLE_IGMP_PLUGIN
include igmp.am
endif
if ENABLE_ILA_PLUGIN
include ila.am
endif

31
src/plugins/igmp.am Normal file
View File

@ -0,0 +1,31 @@
# Copyright (c) 2017 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
vppplugins_LTLIBRARIES += igmp_plugin.la
igmp_plugin_la_SOURCES = \
igmp/igmp.c \
igmp/cli.c \
igmp/igmp_api.c \
igmp/igmp_plugin.api.h \
igmp/input.c \
igmp/igmp_format.c
nobase_apiinclude_HEADERS += \
igmp/igmp_all_api_h.h \
igmp/igmp_msg_enum.h \
igmp/igmp.api.h
API_FILES += igmp/igmp.api
# vi:syntax=automake

211
src/plugins/igmp/cli.c Normal file
View File

@ -0,0 +1,211 @@
/*
*------------------------------------------------------------------
* Copyright (c) 2017 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*------------------------------------------------------------------
*/
#include <stdint.h>
#include <sys/ioctl.h>
#include <inttypes.h>
#include <vlib/vlib.h>
#include <vlib/unix/unix.h>
#include <vnet/ip/ip.h>
#include <vnet/fib/fib_entry.h>
#include <vnet/fib/fib_table.h>
#include <vnet/mfib/mfib_table.h>
#include <igmp/igmp.h>
static clib_error_t *
igmp_clear_interface_command_fn (vlib_main_t * vm, unformat_input_t * input,
vlib_cli_command_t * cmd)
{
unformat_input_t _line_input, *line_input = &_line_input;
clib_error_t *error = NULL;
vnet_main_t *vnm = vnet_get_main ();
u32 sw_if_index;
igmp_main_t *im = &igmp_main;
igmp_config_t *config;
if (!unformat_user (input, unformat_line_input, line_input))
{
error =
clib_error_return (0, "'help clear igmp' or 'clear igmp ?' for help");
return error;
}
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
if (unformat
(line_input, "int %U", unformat_vnet_sw_interface, vnm,
&sw_if_index));
else
{
error =
clib_error_return (0, "unknown input '%U'", format_unformat_error,
line_input);
goto done;
}
}
config = igmp_config_lookup (im, sw_if_index);
if (config)
igmp_clear_config (config);
done:
unformat_free (line_input);
return error;
}
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (igmp_clear_interface_command, static) = {
.path = "clear igmp",
.short_help = "clear igmp int <interface>",
.function = igmp_clear_interface_command_fn,
};
/* *INDENT-ON* */
static clib_error_t *
igmp_listen_command_fn (vlib_main_t * vm, unformat_input_t * input,
vlib_cli_command_t * cmd)
{
unformat_input_t _line_input, *line_input = &_line_input;
clib_error_t *error = NULL;
u8 enable = 1;
ip46_address_t saddr, gaddr;
vnet_main_t *vnm = vnet_get_main ();
u32 sw_if_index;
int rv;
if (!unformat_user (input, unformat_line_input, line_input))
{
error =
clib_error_return (0,
"'help igmp listen' or 'igmp listen ?' for help");
return error;
}
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (line_input, "enable"))
enable = 1;
else if (unformat (line_input, "disable"))
enable = 0;
else
if (unformat
(line_input, "int %U", unformat_vnet_sw_interface, vnm,
&sw_if_index));
else
if (unformat (line_input, "saddr %U", unformat_ip46_address, &saddr));
else
if (unformat (line_input, "gaddr %U", unformat_ip46_address, &gaddr));
else
{
error =
clib_error_return (0, "unknown input '%U'", format_unformat_error,
line_input);
goto done;
}
}
if ((vnet_sw_interface_get_flags (vnm, sw_if_index)
&& VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0)
{
error = clib_error_return (0, "Interface is down");
goto done;
}
rv = igmp_listen (vm, enable, sw_if_index, saddr, gaddr,
/* cli_api_listen */ 1);
if (rv == -1)
{
if (enable)
error =
clib_error_return (0, "This igmp configuration already exists");
else
error =
clib_error_return (0, "This igmp configuration does not nexist");
}
else if (rv == -2)
error =
clib_error_return (0,
"Failed to add configuration, interface is in router mode");
done:
unformat_free (line_input);
return error;
}
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (igmp_listen_command, static) = {
.path = "igmp listen",
.short_help = "igmp listen [<enable|disable>] "
"int <interface> saddr <ip4-address> gaddr <ip4-address>",
.function = igmp_listen_command_fn,
};
/* *INDENT-ON* */
static clib_error_t *
igmp_show_command_fn (vlib_main_t * vm, unformat_input_t * input,
vlib_cli_command_t * cmd)
{
clib_error_t *error = NULL;
igmp_main_t *im = &igmp_main;
vnet_main_t *vnm = vnet_get_main ();
igmp_config_t *config;
igmp_sg_t *sg;
/* *INDENT-OFF* */
pool_foreach (config, im->configs, (
{
vlib_cli_output (vm, "interface: %U", format_vnet_sw_if_index_name,
vnm, config->sw_if_index);
pool_foreach (sg, config->sg, (
{
vlib_cli_output (vm, "\t(S,G): %U:%U:%U", format_ip46_address,
&sg->saddr, ip46_address_is_ip4 (&sg->saddr),
format_ip46_address, &sg->gaddr, ip46_address_is_ip4
(&sg->gaddr), format_igmp_report_type, sg->group_type);
}));
}));
/* *INDENT-ON* */
return error;
}
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (igmp_show_command, static) = {
.path = "show igmp config",
.short_help = "show igmp config",
.function = igmp_show_command_fn,
};
/* *INDENT-ON* */
clib_error_t *
igmp_cli_init (vlib_main_t * vm)
{
return 0;
}
VLIB_INIT_FUNCTION (igmp_cli_init);
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

45
src/plugins/igmp/error.h Normal file
View File

@ -0,0 +1,45 @@
/*
*------------------------------------------------------------------
* Copyright (c) 2017 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*------------------------------------------------------------------
*/
#ifndef _IGMP_ERROR_H_
#define _IGMP_ERROR_H_
#define foreach_igmp_error \
_ (NONE, "valid igmp packets") \
_ (UNSPECIFIED, "unspecified error") \
_ (INVALID_PROTOCOL, "invalid ip4 protocol") \
_ (BAD_CHECKSUM, "bad checksum") \
_ (UNKNOWN_TYPE, "unknown igmp message type") \
_ (CLI_API_CONFIG, "CLI/API configured (S,G)s on interface") \
typedef enum
{
#define _(sym,str) IGMP_ERROR_##sym,
foreach_igmp_error
#undef _
IGMP_N_ERROR,
} igmp_error_t;
#endif /* IGMP_ERROR_H */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

144
src/plugins/igmp/igmp.api Normal file
View File

@ -0,0 +1,144 @@
/*
*------------------------------------------------------------------
* Copyright (c) 2017 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*------------------------------------------------------------------
*/
option version = "1.0.0";
/** \brief
Used by a 'host' to enable the recption/listening of packets for a specific
multicast group
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param enable - if set, enable igmp messages on configuration
@param sw_if_index - interface sw index
@param saddr - source address
@param gaddr - group address
*/
autoreply define igmp_listen
{
u32 client_index;
u32 context;
u8 enable;
u32 sw_if_index;
u8 saddr[4];
u8 gaddr[4];
};
/** \brief
Used by a 'router' to enable the recption of IGMP packets and the
construction of group state for hosts on the link
multicast group
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param enable - if set, enable igmp messages on configuration
@param sw_if_index - interface sw index
*/
autoreply define igmp_enable_disable
{
u32 client_index;
u32 context;
u8 enable;
u32 sw_if_index;
};
/** \brief dump (S,G)s from interface
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param sw_if_index - interface sw index
@param dump_all - get (S,G)s from all interfaces
*/
define igmp_dump
{
u32 client_index;
u32 context;
u32 sw_if_index;
u8 dump_all;
};
/** \brief igmp details
@param context - sender context, to match reply w/ request
@param sw_if_index - interface sw index
@param saddr - source address
@param gaddr - group address
*/
define igmp_details
{
u32 context;
u32 sw_if_index;
u8 saddr[4];
u8 gaddr[4];
};
/** \brief remove all (S,G)s from an interface
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param sw_if_index - interface sw index
*/
autoreply define igmp_clear_interface
{
u32 client_index;
u32 context;
u32 sw_if_index;
};
/** \brief register for igmp events
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param pid - sender's pid
@param enable - 1 enable, 0 disable igmp events
*/
autoreply define want_igmp_events
{
u32 client_index;
u32 context;
u32 enable;
u32 pid;
};
service {
rpc want_igmp_events returns want_igmp_events_reply
events igmp_event;
};
/** \brief igmp event details
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param sw_if_index - interface sw index
@param saddr - source address
@param gaddr - group address
@param is_join - if set source is joining the group, else leaving
*/
define igmp_event
{
u32 context;
u32 sw_if_index;
u8 saddr[4];
u8 gaddr[4];
u8 is_join;
};
/*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

849
src/plugins/igmp/igmp.c Normal file

File diff suppressed because it is too large Load Diff

35
src/plugins/igmp/igmp.def Normal file
View File

@ -0,0 +1,35 @@
/*
*------------------------------------------------------------------
* Copyright (c) 2018 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*------------------------------------------------------------------
*/
igmp_type (0x11, membership_query)
igmp_type (0x12, membership_report_v1)
igmp_type (0x13, dvmrp)
igmp_type (0x14, pim_v1)
igmp_type (0x15, cisco_trace)
igmp_type (0x16, membership_report_v2)
igmp_type (0x17, leave_group_v2)
igmp_type (0x1e, traceroute_response)
igmp_type (0x1f, traceroute_request)
igmp_type (0x22, membership_report_v3)
igmp_type (0x30, router_advertisement)
igmp_type (0x32, router_termination)
igmp_report_type (1, mode_is_filter_include)
igmp_report_type (2, mode_is_filter_exclude)
igmp_report_type (3, change_to_filter_include)
igmp_report_type (4, change_to_filter_exclude)
igmp_report_type (5, allow_new_sources)
igmp_report_type (6, block_old_sources)

286
src/plugins/igmp/igmp.h Normal file
View File

@ -0,0 +1,286 @@
/*
*------------------------------------------------------------------
* Copyright (c) 2017 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*------------------------------------------------------------------
*/
#ifndef _IGMP_H_
#define _IGMP_H_
#include <vlib/vlib.h>
#include <vnet/ip/ip.h>
#include <vnet/ip/igmp_packet.h>
#include <vnet/adj/adj_mcast.h>
#include <igmp/igmp_format.h>
#define IGMP_QUERY_TIMER (60)
#define IGMP_SG_TIMER (3 * IGMP_QUERY_TIMER)
#define IGMP_DEFAULT_ROBUSTNESS_VARIABLE (2)
#define IGMP_DBG 1
#if IGMP_DBG
#define DBG(...) clib_warning(__VA_ARGS__)
#else
#define DBG(...)
#endif /* IGMP_DBG */
#define group_ptr(p, l) ((igmp_membership_group_v3_t *)((void*)p + l))
enum
{
IGMP_PROCESS_EVENT_UPDATE_TIMER = 1,
} igmp_process_event_t;
typedef enum
{
IGMP_V1,
IGMP_V2,
IGMP_V3,
} igmp_ver_t;
struct igmp_config_t_;
typedef struct igmp_config_t_ igmp_config_t;
/* populate supplied bufefr with IGMP message */
typedef void (create_msg_t) (vlib_buffer_t * b, igmp_config_t * config);
typedef struct igmp_index_t_
{
u32 config_index;
u32 sg_index;
} igmp_index_t;
typedef struct igmp_sg_key_t_
{
ip46_address_t gaddr;
ip46_address_t saddr;
} igmp_sg_key_t;
typedef struct igmp_sg_t_
{
ip46_address_t gaddr;
ip46_address_t saddr;
igmp_membership_group_v3_type_t group_type;
/* check if expired (S,G) timer is valid */
f64 exp_time;
igmp_sg_key_t *key;
} igmp_sg_t;
typedef struct igmp_config_t_
{
u32 sw_if_index;
adj_index_t adj_index;
u8 cli_api_configured;
create_msg_t *next_create_msg;
igmp_ver_t igmp_ver;
u8 robustness_var;
u8 flags;
#define IGMP_CONFIG_FLAG_QUERY_RESP_RECVED (1 << 0)
#define IGMP_CONFIG_FLAG_CAN_SEND_REPORT (1 << 1)
uword *igmp_sg_by_key;
/* pool of (S,G)s per interface */
igmp_sg_t *sg;
} igmp_config_t;
struct igmp_timer_t_;
typedef struct igmp_timer_t_ igmp_timer_t;
typedef struct igmp_api_client_t_
{
u32 client_index;
u32 pid;
} igmp_api_client_t;
typedef struct
{
u8 *name;
igmp_type_t type;
} igmp_type_info_t;
typedef struct
{
u8 *name;
igmp_membership_group_v3_type_t type;
} igmp_report_type_info_t;
typedef struct igmp_main_t_
{
/** API message ID base */
u16 msg_id_base;
/* get api client by client_index */
uword *igmp_api_client_by_client_index;
/** pool of api clients registered for join/leave notifications */
igmp_api_client_t *api_clients;
/* get config index by config key */
uword *igmp_config_by_sw_if_index;
/** pool of igmp configurations */
igmp_config_t *configs;
/** buffer cache */
u32 **buffers;
/* next report/deletion */
igmp_index_t next_index;
/** pool of igmp timers */
igmp_timer_t *timers;
igmp_type_info_t *type_infos;
igmp_report_type_info_t *report_type_infos;
uword *type_info_by_type;
uword *report_type_info_by_report_type;
} igmp_main_t;
extern igmp_main_t igmp_main;
typedef void (igmp_timer_function_t) (vlib_main_t * vm,
vlib_node_runtime_t * rt,
igmp_main_t * im, igmp_timer_t * timer);
typedef struct igmp_timer_t_
{
f64 exp_time;
igmp_timer_function_t *func;
u32 sw_if_index;
void *data;
} igmp_timer_t;
extern vlib_node_registration_t igmp_timer_process_node;
extern vlib_node_registration_t igmp_input_node;
extern vlib_node_registration_t igmp_parse_query_node;
extern vlib_node_registration_t igmp_parse_report_node;
int igmp_listen (vlib_main_t * vm, u8 enable, u32 sw_if_index,
ip46_address_t saddr, ip46_address_t gaddr,
u8 cli_api_configured);
void igmp_clear_config (igmp_config_t * config);
void igmp_sort_timers (igmp_timer_t * timers);
void igmp_create_int_timer (f64 time, u32 sw_if_index,
igmp_timer_function_t * func);
void igmp_create_sg_timer (f64 time, u32 sw_if_index, igmp_sg_key_t * key,
igmp_timer_function_t * func);
void igmp_send_query (vlib_main_t * vm, vlib_node_runtime_t * rt,
igmp_main_t * im, igmp_timer_t * timer);
void igmp_query_resp_exp (vlib_main_t * vm, vlib_node_runtime_t * rt,
igmp_main_t * im, igmp_timer_t * timer);
void igmp_send_report (vlib_main_t * vm, vlib_node_runtime_t * rt,
igmp_main_t * im, igmp_timer_t * timer);
void igmp_send_state_changed (vlib_main_t * vm, vlib_node_runtime_t * rt,
igmp_main_t * im, igmp_timer_t * timer);
void igmp_sg_exp (vlib_main_t * vm, vlib_node_runtime_t * rt,
igmp_main_t * im, igmp_timer_t * timer);
static inline igmp_type_info_t *
igmp_get_type_info (igmp_main_t * im, u32 type)
{
uword *p;
p = hash_get (im->type_info_by_type, type);
return p ? vec_elt_at_index (im->type_infos, p[0]) : 0;
}
static inline igmp_report_type_info_t *
igmp_get_report_type_info (igmp_main_t * im, u8 report_type)
{
uword *p;
p = hash_get (im->report_type_info_by_report_type, report_type);
return p ? vec_elt_at_index (im->report_type_infos, p[0]) : 0;
}
void igmp_event (igmp_main_t * im, igmp_config_t * config, igmp_sg_t * sg);
typedef enum
{
IGMP_NEXT_IP4_REWRITE_MCAST_NODE,
IGMP_NEXT_IP6_REWRITE_MCAST_NODE,
IGMP_N_NEXT,
} igmp_next_t;
always_inline igmp_config_t *
igmp_config_lookup (igmp_main_t * im, u32 sw_if_index)
{
uword *p;
igmp_config_t *config = NULL;
p = hash_get_mem (im->igmp_config_by_sw_if_index, &sw_if_index);
if (p)
config = vec_elt_at_index (im->configs, p[0]);
return config;
}
always_inline igmp_sg_t *
igmp_sg_lookup (igmp_config_t * config, igmp_sg_key_t * key)
{
uword *p;
igmp_sg_t *sg = NULL;
if (!config)
return NULL;
p = hash_get_mem (config->igmp_sg_by_key, key);
if (p)
sg = vec_elt_at_index (config->sg, p[0]);
return sg;
}
always_inline igmp_api_client_t *
igmp_api_client_lookup (igmp_main_t * im, u32 client_index)
{
uword *p;
igmp_api_client_t *api_client = NULL;
p = hash_get_mem (im->igmp_api_client_by_client_index, &client_index);
if (p)
api_client = vec_elt_at_index (im->api_clients, p[0]);
return api_client;
}
#endif /* _IGMP_H_ */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

View File

@ -0,0 +1,26 @@
/*
*------------------------------------------------------------------
* Copyright (c) 2017 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*------------------------------------------------------------------
*/
#include <igmp/igmp.api.h>
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

337
src/plugins/igmp/igmp_api.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,159 @@
/*
*------------------------------------------------------------------
* Copyright (c) 2018 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*------------------------------------------------------------------
*/
#include <igmp/igmp.h>
#include <vnet/ip/ip.h>
u8 *
format_igmp_type (u8 * s, va_list * args)
{
igmp_type_t type = va_arg (*args, igmp_type_t);
igmp_main_t *im = &igmp_main;
igmp_type_info_t *ti = igmp_get_type_info (im, type);
if (ti)
return format (s, "%s", ti->name);
else
return format (s, "unknown %d", type);
}
u8 *
format_igmp_report_type (u8 * s, va_list * args)
{
igmp_membership_group_v3_type_t report_type =
va_arg (*args, igmp_membership_group_v3_type_t);
igmp_main_t *im = &igmp_main;
igmp_report_type_info_t *rti = igmp_get_report_type_info (im, report_type);
if (rti)
return format (s, "%s", rti->name);
else
return format (s, "unknown %d", report_type);
}
u8 *
format_igmp_header (u8 * s, va_list * args)
{
igmp_header_t *hdr = va_arg (*args, igmp_header_t *);
u32 max_header_bytes = va_arg (*args, u32);
u32 indent;
if (max_header_bytes < sizeof (hdr[0]))
return format (s, "IGMP header truncated");
indent = format_get_indent (s);
indent += 2;
s =
format (s, "%U%U: code %u, checksum 0x%04x", format_white_space, indent,
format_igmp_type, hdr->type, hdr->code,
clib_net_to_host_u16 (hdr->checksum));
return s;
}
u8 *
format_igmp_report_v3 (u8 * s, va_list * args)
{
igmp_membership_report_v3_t *igmp =
va_arg (*args, igmp_membership_report_v3_t *);
u32 max_header_bytes = va_arg (*args, u32);
igmp_membership_group_v3_t *group;
u32 len = sizeof (igmp_membership_report_v3_t);
u32 indent;
if (max_header_bytes < sizeof (igmp[0]))
return format (s, "IGMP report truncated");
indent = format_get_indent (s);
indent += 2;
s =
format (s, "%Un_groups %u", format_white_space, indent,
clib_net_to_host_u16 (igmp->n_groups));
indent += 2;
int i, j = 0;
for (i = 0; i < clib_net_to_host_u16 (igmp->n_groups); i++)
{
group = group_ptr (igmp, len);
s =
format (s, "\n%U%U: %U, sources %u", format_white_space, indent,
format_igmp_report_type, group->type, format_ip4_address,
&group->dst_address,
clib_net_to_host_u16 (group->n_src_addresses));
indent += 2;
for (j = 0; j < clib_net_to_host_u16 (group->n_src_addresses); j++)
{
s =
format (s, "\n%U%U", format_white_space, indent,
format_ip4_address, &group->src_addresses[j]);
}
indent -= 2;
len +=
sizeof (igmp_membership_group_v3_t) +
(sizeof (ip4_address_t) *
clib_net_to_host_u16 (group->n_src_addresses));
}
return s;
}
u8 *
format_igmp_query_v3 (u8 * s, va_list * args)
{
igmp_membership_query_v3_t *igmp =
va_arg (*args, igmp_membership_query_v3_t *);
u32 max_header_bytes = va_arg (*args, u32);
u32 indent;
int i;
if (max_header_bytes < sizeof (igmp[0]))
return format (s, "IGMP query truncated");
indent = format_get_indent (s);
indent += 2;
ip4_address_t tmp;
tmp.as_u32 = 0;
if ((!ip4_address_compare (&igmp->dst, &tmp))
&& (igmp->n_src_addresses == 0))
s = format (s, "%UGeneral Query", format_white_space, indent);
else if (igmp->n_src_addresses == 0)
s = format (s, "%UGroup-Specific Query: %U", format_white_space, indent,
format_ip4_address, &igmp->dst);
else
{
s =
format (s, "%UGroup-and-Source-Specific Query: %U",
format_white_space, indent, format_ip4_address, &igmp->dst);
indent += 2;
for (i = 0; i < clib_net_to_host_u16 (igmp->n_src_addresses); i++)
{
s = format (s, "\n%U%U", format_white_space, indent,
format_ip4_address, &igmp->src_addresses[i]);
}
}
return s;
}
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

View File

@ -0,0 +1,39 @@
/*
*------------------------------------------------------------------
* Copyright (c) 2018 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*------------------------------------------------------------------
*/
#ifndef _IGMP_FORMAT_H_
#define _IGMP_FORMAT_H_
u8 *format_igmp_type (u8 * s, va_list * args);
u8 *format_igmp_report_type (u8 * s, va_list * args);
u8 *format_igmp_header (u8 * s, va_list * args);
u8 *format_igmp_report_v3 (u8 * s, va_list * args);
u8 *format_igmp_query_v3 (u8 * s, va_list * args);
#endif /* IGMP_FORMAT_H */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

View File

@ -0,0 +1,39 @@
/*
*------------------------------------------------------------------
* Copyright (c) 2017 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*------------------------------------------------------------------
*/
#ifndef _IGMP_MSG_ENUM_H_
#define _IGMP_MSG_ENUM_H_
#include <vppinfra/byte_order.h>
#define vl_msg_id(n,h) n,
typedef enum
{
#include <igmp/igmp_all_api_h.h>
VL_MSG_FIRST_AVAILABLE,
} vl_msg_id_t;
#undef vl_msg_id
#endif /* IGMP_MSG_ENUM_H_ */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

550
src/plugins/igmp/input.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -40,6 +40,8 @@
#include <vnet/fib/fib_node_list.h>
#include <vnet/fib/fib_urpf_list.h>
#include <vlib/unix/plugin.h>
/*
* Add debugs for passing tests
*/
@ -827,7 +829,15 @@ fib_test_v4 (void)
* table, and 4 path-lists in the v6 MFIB table
*/
#define ENBR (5+5+2)
#define PNBR (5+5+6)
u32 PNBR = 5+5+2+4;
/*
* if the IGMP plugin is loaded this adds two more entries to the v4 MFIB
*/
if (vlib_get_plugin_symbol("igmp_plugin.so", "igmp_listen"))
PNBR += 2;
FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
fib_path_list_pool_size());
@ -4343,7 +4353,13 @@ fib_test_v6 (void)
* All entries are special so no path-list sharing.
*/
#define ENPS (5+4)
#define PNPS (5+4+4)
u32 PNPS = (5+4+4);
/*
* if the IGMP plugin is loaded this adds two more entries to the v4 MFIB
*/
if (vlib_get_plugin_symbol("igmp_plugin.so", "igmp_listen"))
PNPS += 2;
FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is %d",
fib_path_list_pool_size());

View File

@ -83,6 +83,24 @@ typedef struct
ip4_address_t dst;
} igmp_message_t;
typedef struct
{
/* type 0x11 (IGMPv3) */
igmp_header_t header;
ip4_address_t dst;
/* Reserved, Suppress Router-Side Processing flag and
Querier's Robustness Variable RRRRSQQQ. */
u8 resv_s_qrv;
/* Querier's Query Interval Code */
u8 qqi_code;
u16 n_src_addresses;
ip4_address_t src_addresses[0];
} igmp_membership_query_v3_t;
#define foreach_igmp_membership_group_v3_type \
_ (1, mode_is_filter_include) \
_ (2, mode_is_filter_exclude) \

323
test/test_igmp.py Normal file

File diff suppressed because it is too large Load Diff

39
test/vpp_igmp.py Normal file
View File

@ -0,0 +1,39 @@
from vpp_object import VppObject
class IgmpSG():
def __init__(self, saddr, gaddr):
self.saddr = saddr
self.gaddr = gaddr
class VppIgmpConfig(VppObject):
def __init__(self, test, sw_if_index, sg=None):
self._test = test
self.sw_if_index = sw_if_index
if isinstance(sg, list):
self.sg_list = sg
else:
self.sg_list = []
self.sg_list.append(sg)
def add_sg(self, sg):
self.sg.append(sg)
def add_vpp_config(self):
for e in self.sg_list:
self._test.vapi.igmp_listen(
1, self.sw_if_index, e.saddr, e.gaddr)
def remove_vpp_config(self):
self._test.vapi.igmp_clear_interface(self.sw_if_index)
def __str__(self):
return self.object_id()
def object_id(self):
return "%s:%d" % (self.sg_list, self.sw_if_index)
def query_vpp_config(self):
return self._test.vapi.igmp_dump()

View File

@ -3291,3 +3291,39 @@ class VppPapiProvider(object):
{'sw_if_index': sw_if_index,
'input_source': input_source,
'enable': enable})
def igmp_listen(self, enable, sw_if_index, saddr, gaddr):
""" Listen for new (S,G) on specified interface
:param enable: add/del
:param sw_if_index: interface sw index
:param saddr: source ip4 addr
:param gaddr: group ip4 addr
"""
return self.api(self.papi.igmp_listen,
{'enable': enable,
'sw_if_index': sw_if_index,
'saddr': saddr,
'gaddr': gaddr})
def igmp_dump(self, sw_if_index=None):
""" Dump all (S,G) interface configurations """
if sw_if_index is None:
dump_all = 1
sw_if_index = 0
else:
dump_all = 0
return self.api(self.papi.igmp_dump, {'sw_if_index': sw_if_index,
'dump_all': dump_all})
def igmp_clear_interface(self, sw_if_index):
""" Remove all (S,G)s from specified interface
doesn't send IGMP report!
"""
return self.api(
self.papi.igmp_clear_interface, {
'sw_if_index': sw_if_index})
def want_igmp_events(self, enable=1):
return self.api(self.papi.want_igmp_events, {'enable': enable,
'pid': os.getpid()})