#include <vlib/vlib.h>
#include <vnet/ip/ip.h>
+#include <vlibapi/api_helper_macros.h>
#include <vnet/ip/igmp_packet.h>
#include <vnet/adj/adj_mcast.h>
+#include <igmp/igmp_types.h>
#include <igmp/igmp_format.h>
+#include <igmp/igmp_timer.h>
+#include <igmp/igmp_group.h>
+#include <igmp/igmp_config.h>
+#include <igmp/igmp_proxy.h>
-#define IGMP_QUERY_TIMER (60)
-#define IGMP_SG_TIMER (3 * IGMP_QUERY_TIMER)
+/**
+ * RFC 3376 Section 8.1
+ */
#define IGMP_DEFAULT_ROBUSTNESS_VARIABLE (2)
-#define IGMP_DBG 1
+#define IGMP_DBG(...) \
+ vlib_log_debug (igmp_main.logger, __VA_ARGS__);
-#if IGMP_DBG
-#define DBG(...) clib_warning(__VA_ARGS__)
+/**
+ * General Query address - 224.0.0.1
+ * Membership Report address - 224.0.0.22
+ * SSM default range 232/8
+ */
+#if CLIB_ARCH_IS_BIG_ENDIAN
+#define IGMP_GENERAL_QUERY_ADDRESS (0xE0000001)
+#define IGMP_MEMBERSHIP_REPORT_ADDRESS (0xE0000016)
+#define IGMP_SSM_DEFAULT (0xE8000000)
#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_;
+#define IGMP_GENERAL_QUERY_ADDRESS (0x010000E0)
+#define IGMP_MEMBERSHIP_REPORT_ADDRESS (0x160000E0)
+#define IGMP_SSM_DEFAULT (0x000000E8)
+#endif
-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;
+/** helper macro to get igmp membership group from pointer plus offset */
+#define group_ptr(p, l) ((igmp_membership_group_v3_t *)((u8*)(p) + (l)))
+#define group_cptr(p, l) ((const igmp_membership_group_v3_t *)((u8*)(p) + (l)))
+/**
+ * collection of data related to IGMP
+ */
typedef struct igmp_main_t_
{
- /** API message ID base */
+ /**
+ * API base message ID
+ */
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 */
+ /**
+ * API client registered for events
+ */
+ vpe_client_registration_t *api_clients;
+
+ /**
+ * per-interface DB of configs
+ */
+ u32 *igmp_config_by_sw_if_index;
+
+ /**
+ * the number of igmp configs for each mfib_index (VRF)
+ */
+ u32 *n_configs_per_mfib_index;
+
+ /**
+ * logger - VLIB log class
+ */
+ vlib_log_class_t logger;
+
+ /**
+ * pool of configs
+ */
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;
-
+ /**
+ * pool of groups
+ */
+ igmp_group_t *groups;
+ /**
+ * pool of sources
+ */
+ igmp_src_t *srcs;
+
+ /**
+ * per-vrf DB of proxy devices
+ */
+ u32 *igmp_proxy_device_by_vrf_id;
+
+ /**
+ * pool of proxy devices
+ */
+ igmp_proxy_device_t *proxy_devices;
} 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;
-}
+/**
+ * @brief IGMP interface enable/disable
+ * @param sw_if_index - Interface
+ * @param enable - enable/disable
+ * @param mode - Host or router
+ */
+int igmp_enable_disable (u32 sw_if_index, u8 enable, igmp_mode_t mode);
+
+/**
+ * @brief igmp listen
+ * Called by a host to request reception of multicast packets
+ * @param vm - vlib main
+ * @param filter - Filter mode
+ * @param sw_if_index - interface sw_if_index
+ * @param saddr - source address
+ * @param gaddr - group address
+ *
+ * Add/del (S,G) on an interface.
+ * send a status change report from the interface.
+ */
+int igmp_listen (vlib_main_t * vm,
+ igmp_filter_mode_t filter,
+ u32 sw_if_index,
+ const ip46_address_t * saddr, const ip46_address_t * gaddr);
+
+/**
+ * @brief Send an IGMP event to listening parties
+ * @param filter mode
+ * @param sw_if_index
+ * @param saddr
+ * @param gaddr
+ */
+void igmp_event (igmp_filter_mode_t filter,
+ u32 sw_if_index,
+ const ip46_address_t * saddr, const ip46_address_t * gaddr);
#endif /* _IGMP_H_ */