diff options
-rw-r--r-- | src/vnet/mfib/mfib_entry.c | 10 | ||||
-rw-r--r-- | src/vnet/mfib/mfib_entry.h | 3 | ||||
-rw-r--r-- | src/vpp/stats/stats.api | 60 | ||||
-rw-r--r-- | src/vpp/stats/stats.c | 380 | ||||
-rw-r--r-- | src/vpp/stats/stats.h | 16 | ||||
-rw-r--r-- | src/vpp/stats/stats.reg | 3 |
6 files changed, 461 insertions, 11 deletions
diff --git a/src/vnet/mfib/mfib_entry.c b/src/vnet/mfib/mfib_entry.c index 6c356c6b267..bc7f7dec406 100644 --- a/src/vnet/mfib/mfib_entry.c +++ b/src/vnet/mfib/mfib_entry.c @@ -1226,6 +1226,16 @@ mfib_entry_get_fib_index (fib_node_index_t mfib_entry_index) return (mfib_entry->mfe_fib_index); } +const dpo_id_t* +mfib_entry_contribute_ip_forwarding (fib_node_index_t mfib_entry_index) +{ + mfib_entry_t *mfib_entry; + + mfib_entry = mfib_entry_get(mfib_entry_index); + + return (&mfib_entry->mfe_rep); +} + void mfib_entry_contribute_forwarding (fib_node_index_t mfib_entry_index, fib_forward_chain_type_t type, diff --git a/src/vnet/mfib/mfib_entry.h b/src/vnet/mfib/mfib_entry.h index 96ee49f799e..a1d5acf9066 100644 --- a/src/vnet/mfib/mfib_entry.h +++ b/src/vnet/mfib/mfib_entry.h @@ -133,6 +133,9 @@ extern u32 mfib_entry_get_fib_index(fib_node_index_t fib_entry_index); extern int mfib_entry_is_sourced(fib_node_index_t fib_entry_index, mfib_source_t source); +extern const dpo_id_t*mfib_entry_contribute_ip_forwarding( + fib_node_index_t mfib_entry_index); + extern void mfib_entry_contribute_forwarding( fib_node_index_t mfib_entry_index, fib_forward_chain_type_t type, diff --git a/src/vpp/stats/stats.api b/src/vpp/stats/stats.api index ec1ca663adc..237415afbb8 100644 --- a/src/vpp/stats/stats.api +++ b/src/vpp/stats/stats.api @@ -133,6 +133,34 @@ autoreply define want_ip6_fib_stats u32 pid; }; +/** \brief Want IP4 muilticast FIB Stats, register for continuous stats + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param enable_disable - 1 = enable stats, 0 = disable + @param pid - pid of process requesting stats updates +*/ +autoreply define want_ip4_mfib_stats +{ + u32 client_index; + u32 context; + u32 enable_disable; + u32 pid; +}; + +/** \brief Want IP6 multicast FIB Stats, register for continuous stats + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param enable_disable - 1 = enable stats, 0 = disable + @param pid - pid of process requesting stats updates +*/ +autoreply define want_ip6_mfib_stats +{ + u32 client_index; + u32 context; + u32 enable_disable; + u32 pid; +}; + /** \brief Want IP4 NBR Stats, register for continuous stats @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -176,6 +204,22 @@ manual_print manual_endian define vnet_ip4_fib_counters vl_api_ip4_fib_counter_t c[count]; }; +typeonly manual_print manual_endian define ip4_mfib_counter +{ + u8 source[4]; + u8 group[4]; + u8 group_length; + u64 packets; + u64 bytes; +}; + +manual_print manual_endian define vnet_ip4_mfib_counters +{ + u32 vrf_id; + u32 count; + vl_api_ip4_mfib_counter_t c[count]; +}; + typeonly manual_print manual_endian define ip4_nbr_counter { u32 address; @@ -216,6 +260,22 @@ manual_print manual_endian define vnet_ip6_fib_counters vl_api_ip6_fib_counter_t c[count]; }; +typeonly manual_print manual_endian define ip6_mfib_counter +{ + u8 source[16]; + u8 group[16]; + u8 group_length; + u64 packets; + u64 bytes; +}; + +manual_print manual_endian define vnet_ip6_mfib_counters +{ + u32 vrf_id; + u32 count; + vl_api_ip6_mfib_counter_t c[count]; +}; + typeonly manual_print manual_endian define ip6_nbr_counter { u64 address[2]; diff --git a/src/vpp/stats/stats.c b/src/vpp/stats/stats.c index 6c6809e3b60..cd501428833 100644 --- a/src/vpp/stats/stats.c +++ b/src/vpp/stats/stats.c @@ -16,6 +16,7 @@ #include <signal.h> #include <vnet/fib/ip4_fib.h> #include <vnet/fib/fib_entry.h> +#include <vnet/mfib/mfib_entry.h> #include <vnet/dpo/load_balance.h> #define STATS_DEBUG 0 @@ -55,6 +56,8 @@ _(VNET_IP4_FIB_COUNTERS, vnet_ip4_fib_counters) \ _(WANT_IP4_FIB_STATS, want_ip4_fib_stats) \ _(VNET_IP6_FIB_COUNTERS, vnet_ip6_fib_counters) \ _(WANT_IP6_FIB_STATS, want_ip6_fib_stats) \ +_(WANT_IP4_MFIB_STATS, want_ip4_mfib_stats) \ +_(WANT_IP6_MFIB_STATS, want_ip6_mfib_stats) \ _(VNET_IP4_NBR_COUNTERS, vnet_ip4_nbr_counters) \ _(WANT_IP4_NBR_STATS, want_ip4_nbr_stats) \ _(VNET_IP6_NBR_COUNTERS, vnet_ip6_nbr_counters) \ @@ -80,6 +83,8 @@ setup_message_id_table (api_main_t * am) #define COMBINED_COUNTER_BATCH_SIZE 63 #define IP4_FIB_COUNTER_BATCH_SIZE 48 #define IP6_FIB_COUNTER_BATCH_SIZE 30 +#define IP4_MFIB_COUNTER_BATCH_SIZE 24 +#define IP6_MFIB_COUNTER_BATCH_SIZE 15 /* 5ms */ #define STATS_RELEASE_DELAY_NS (1000 * 1000 * 5) @@ -1597,6 +1602,299 @@ again: vl_msg_api_free (mp); } +static int +mfib_table_stats_walk_cb (fib_node_index_t fei, void *ctx) +{ + stats_main_t *sm = ctx; + do_ip46_fibs_t *do_fibs; + mfib_entry_t *entry; + + do_fibs = &sm->do_ip46_fibs; + entry = mfib_entry_get (fei); + + vec_add1 (do_fibs->mroutes, entry->mfe_prefix); + + return (1); +} + +static void +do_ip4_mfib_counters (stats_main_t * sm) +{ + ip4_main_t *im4 = &ip4_main; + api_main_t *am = sm->api_main; + vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr; + unix_shared_memory_queue_t *q = shmem_hdr->vl_input_queue; + mfib_prefix_t *pfx; + mfib_table_t *mfib; + do_ip46_fibs_t *do_fibs; + vl_api_vnet_ip4_mfib_counters_t *mp = 0; + u32 items_this_message; + vl_api_ip4_mfib_counter_t *ctrp = 0; + u32 start_at_mfib_index = 0; + int i, j, k; + + do_fibs = &sm->do_ip46_fibs; + + vec_reset_length (do_fibs->mfibs); + /* *INDENT-OFF* */ + pool_foreach (mfib, im4->mfibs, ({vec_add1(do_fibs->mfibs, mfib);})); + /* *INDENT-ON* */ + + for (j = 0; j < vec_len (do_fibs->mfibs); j++) + { + mfib = do_fibs->mfibs[j]; + /* We may have bailed out due to control-plane activity */ + while ((mfib - im4->mfibs) < start_at_mfib_index) + continue; + + if (mp == 0) + { + items_this_message = IP4_MFIB_COUNTER_BATCH_SIZE; + mp = vl_msg_api_alloc_as_if_client + (sizeof (*mp) + + items_this_message * sizeof (vl_api_ip4_mfib_counter_t)); + mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_MFIB_COUNTERS); + mp->count = 0; + mp->vrf_id = ntohl (mfib->mft_table_id); + ctrp = (vl_api_ip4_mfib_counter_t *) mp->c; + } + else + { + /* happens if the last MFIB was empty... */ + ASSERT (mp->count == 0); + mp->vrf_id = ntohl (mfib->mft_table_id); + } + + vec_reset_length (do_fibs->mroutes); + + /* + * walk the table with table updates blocked + */ + dslock (sm, 0 /* release hint */ , 1 /* tag */ ); + + mfib_table_walk (mfib->mft_index, + FIB_PROTOCOL_IP4, mfib_table_stats_walk_cb, sm); + dsunlock (sm); + + vec_foreach (pfx, do_fibs->mroutes) + { + const dpo_id_t *dpo_id; + fib_node_index_t mfei; + vlib_counter_t c; + u32 index; + + /* + * re-lookup the entry, since we suspend during the collection + */ + mfei = mfib_table_lookup (mfib->mft_index, pfx); + + if (FIB_NODE_INDEX_INVALID == mfei) + continue; + + dpo_id = mfib_entry_contribute_ip_forwarding (mfei); + index = (u32) dpo_id->dpoi_index; + + vlib_get_combined_counter (&replicate_main.repm_counters, + dpo_id->dpoi_index, &c); + /* + * If it has seen at least one packet, send it. + */ + if (c.packets > 0) + { + /* already in net byte order */ + memcpy (ctrp->group, &pfx->fp_grp_addr.ip4, 4); + memcpy (ctrp->source, &pfx->fp_src_addr.ip4, 4); + ctrp->group_length = pfx->fp_len; + ctrp->packets = clib_host_to_net_u64 (c.packets); + ctrp->bytes = clib_host_to_net_u64 (c.bytes); + mp->count++; + ctrp++; + + if (mp->count == items_this_message) + { + mp->count = htonl (items_this_message); + /* + * If the main thread's input queue is stuffed, + * drop the data structure lock (which the main thread + * may want), and take a pause. + */ + unix_shared_memory_queue_lock (q); + + while (unix_shared_memory_queue_is_full (q)) + { + unix_shared_memory_queue_unlock (q); + ip46_fib_stats_delay (sm, 0 /* sec */ , + STATS_RELEASE_DELAY_NS); + unix_shared_memory_queue_lock (q); + } + vl_msg_api_send_shmem_nolock (q, (u8 *) & mp); + unix_shared_memory_queue_unlock (q); + + items_this_message = IP4_MFIB_COUNTER_BATCH_SIZE; + mp = vl_msg_api_alloc_as_if_client + (sizeof (*mp) + + items_this_message * sizeof (vl_api_ip4_mfib_counter_t)); + mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_MFIB_COUNTERS); + mp->count = 0; + mp->vrf_id = ntohl (mfib->mft_table_id); + ctrp = (vl_api_ip4_mfib_counter_t *) mp->c; + } + } + } + + /* Flush any data from this mfib */ + if (mp->count) + { + mp->count = htonl (mp->count); + vl_msg_api_send_shmem (q, (u8 *) & mp); + mp = 0; + } + } + + /* If e.g. the last FIB had no reportable routes, free the buffer */ + if (mp) + vl_msg_api_free (mp); +} + +static void +do_ip6_mfib_counters (stats_main_t * sm) +{ + ip6_main_t *im6 = &ip6_main; + api_main_t *am = sm->api_main; + vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr; + unix_shared_memory_queue_t *q = shmem_hdr->vl_input_queue; + mfib_prefix_t *pfx; + mfib_table_t *mfib; + do_ip46_fibs_t *do_fibs; + vl_api_vnet_ip6_mfib_counters_t *mp = 0; + u32 items_this_message; + vl_api_ip6_mfib_counter_t *ctrp = 0; + u32 start_at_mfib_index = 0; + int i, j, k; + + do_fibs = &sm->do_ip46_fibs; + + vec_reset_length (do_fibs->mfibs); + /* *INDENT-OFF* */ + pool_foreach (mfib, im6->mfibs, ({vec_add1(do_fibs->mfibs, mfib);})); + /* *INDENT-ON* */ + + for (j = 0; j < vec_len (do_fibs->mfibs); j++) + { + mfib = do_fibs->mfibs[j]; + /* We may have bailed out due to control-plane activity */ + while ((mfib - im6->mfibs) < start_at_mfib_index) + continue; + + if (mp == 0) + { + items_this_message = IP6_MFIB_COUNTER_BATCH_SIZE; + mp = vl_msg_api_alloc_as_if_client + (sizeof (*mp) + + items_this_message * sizeof (vl_api_ip6_mfib_counter_t)); + mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_MFIB_COUNTERS); + mp->count = 0; + mp->vrf_id = ntohl (mfib->mft_table_id); + ctrp = (vl_api_ip6_mfib_counter_t *) mp->c; + } + else + { + /* happens if the last MFIB was empty... */ + ASSERT (mp->count == 0); + mp->vrf_id = ntohl (mfib->mft_table_id); + } + + vec_reset_length (do_fibs->mroutes); + + /* + * walk the table with table updates blocked + */ + dslock (sm, 0 /* release hint */ , 1 /* tag */ ); + + mfib_table_walk (mfib->mft_index, + FIB_PROTOCOL_IP6, mfib_table_stats_walk_cb, sm); + dsunlock (sm); + + vec_foreach (pfx, do_fibs->mroutes) + { + const dpo_id_t *dpo_id; + fib_node_index_t mfei; + vlib_counter_t c; + u32 index; + + /* + * re-lookup the entry, since we suspend during the collection + */ + mfei = mfib_table_lookup (mfib->mft_index, pfx); + + if (FIB_NODE_INDEX_INVALID == mfei) + continue; + + dpo_id = mfib_entry_contribute_ip_forwarding (mfei); + index = (u32) dpo_id->dpoi_index; + + vlib_get_combined_counter (&replicate_main.repm_counters, + dpo_id->dpoi_index, &c); + /* + * If it has seen at least one packet, send it. + */ + if (c.packets > 0) + { + /* already in net byte order */ + memcpy (ctrp->group, &pfx->fp_grp_addr.ip6, 16); + memcpy (ctrp->source, &pfx->fp_src_addr.ip6, 16); + ctrp->group_length = pfx->fp_len; + ctrp->packets = clib_host_to_net_u64 (c.packets); + ctrp->bytes = clib_host_to_net_u64 (c.bytes); + mp->count++; + ctrp++; + + if (mp->count == items_this_message) + { + mp->count = htonl (items_this_message); + /* + * If the main thread's input queue is stuffed, + * drop the data structure lock (which the main thread + * may want), and take a pause. + */ + unix_shared_memory_queue_lock (q); + + while (unix_shared_memory_queue_is_full (q)) + { + unix_shared_memory_queue_unlock (q); + ip46_fib_stats_delay (sm, 0 /* sec */ , + STATS_RELEASE_DELAY_NS); + unix_shared_memory_queue_lock (q); + } + vl_msg_api_send_shmem_nolock (q, (u8 *) & mp); + unix_shared_memory_queue_unlock (q); + + items_this_message = IP6_MFIB_COUNTER_BATCH_SIZE; + mp = vl_msg_api_alloc_as_if_client + (sizeof (*mp) + + items_this_message * sizeof (vl_api_ip6_mfib_counter_t)); + mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_MFIB_COUNTERS); + mp->count = 0; + mp->vrf_id = ntohl (mfib->mft_table_id); + ctrp = (vl_api_ip6_mfib_counter_t *) mp->c; + } + } + } + + /* Flush any data from this mfib */ + if (mp->count) + { + mp->count = htonl (mp->count); + vl_msg_api_send_shmem (q, (u8 *) & mp); + mp = 0; + } + } + + /* If e.g. the last FIB had no reportable routes, free the buffer */ + if (mp) + vl_msg_api_free (mp); +} + typedef struct { u32 fib_index; @@ -1819,6 +2117,12 @@ stats_thread_fn (void *arg) if (pool_elts (sm->stats_registrations[IDX_IP6_FIB_COUNTERS])) do_ip6_fib_counters (sm); + if (pool_elts (sm->stats_registrations[IDX_IP4_MFIB_COUNTERS])) + do_ip4_mfib_counters (sm); + + if (pool_elts (sm->stats_registrations[IDX_IP6_MFIB_COUNTERS])) + do_ip6_mfib_counters (sm); + if (pool_elts (sm->stats_registrations[IDX_IP4_NBR_COUNTERS])) do_ip4_nbr_counters (sm); @@ -1882,10 +2186,6 @@ static void } } - - - - static void vl_api_vnet_ip4_fib_counters_t_handler (vl_api_vnet_ip4_fib_counters_t * mp) { @@ -2206,6 +2506,42 @@ reply: } static void +vl_api_want_ip4_mfib_stats_t_handler (vl_api_want_ip4_mfib_stats_t * mp) +{ + stats_main_t *sm = &stats_main; + vpe_client_registration_t rp; + vl_api_want_ip4_mfib_stats_reply_t *rmp; + uword *p; + i32 retval = 0; + unix_shared_memory_queue_t *q; + u32 mfib; + + mfib = ~0; //Using same mechanism as _per_interface_ + rp.client_index = mp->client_index; + rp.client_pid = mp->pid; + + handle_client_registration (&rp, IDX_IP4_MFIB_COUNTERS, mfib, + mp->enable_disable); + +reply: + q = vl_api_client_index_to_input_queue (mp->client_index); + + if (!q) + { + sm->enable_poller = clear_client_for_stat (IDX_IP4_MFIB_COUNTERS, + mfib, mp->client_index); + return; + } + + rmp = vl_msg_api_alloc (sizeof (*rmp)); + rmp->_vl_msg_id = ntohs (VL_API_WANT_IP4_MFIB_STATS_REPLY); + rmp->context = mp->context; + rmp->retval = retval; + + vl_msg_api_send_shmem (q, (u8 *) & rmp); +} + +static void vl_api_want_ip6_fib_stats_t_handler (vl_api_want_ip6_fib_stats_t * mp) { stats_main_t *sm = &stats_main; @@ -2241,6 +2577,42 @@ reply: vl_msg_api_send_shmem (q, (u8 *) & rmp); } +static void +vl_api_want_ip6_mfib_stats_t_handler (vl_api_want_ip6_mfib_stats_t * mp) +{ + stats_main_t *sm = &stats_main; + vpe_client_registration_t rp; + vl_api_want_ip4_mfib_stats_reply_t *rmp; + uword *p; + i32 retval = 0; + unix_shared_memory_queue_t *q; + u32 mfib; + + mfib = ~0; //Using same mechanism as _per_interface_ + rp.client_index = mp->client_index; + rp.client_pid = mp->pid; + + handle_client_registration (&rp, IDX_IP6_MFIB_COUNTERS, mfib, + mp->enable_disable); + +reply: + q = vl_api_client_index_to_input_queue (mp->client_index); + + if (!q) + { + sm->enable_poller = clear_client_for_stat (IDX_IP6_MFIB_COUNTERS, + mfib, mp->client_index); + return; + } + + rmp = vl_msg_api_alloc (sizeof (*rmp)); + rmp->_vl_msg_id = ntohs (VL_API_WANT_IP6_MFIB_STATS_REPLY); + rmp->context = mp->context; + rmp->retval = retval; + + vl_msg_api_send_shmem (q, (u8 *) & rmp); +} + /* FIXME - NBR stats broken - this will be fixed in subsequent patch */ static void vl_api_want_ip4_nbr_stats_t_handler (vl_api_want_ip4_nbr_stats_t * mp) diff --git a/src/vpp/stats/stats.h b/src/vpp/stats/stats.h index 4343da3b040..3d30e379796 100644 --- a/src/vpp/stats/stats.h +++ b/src/vpp/stats/stats.h @@ -22,6 +22,7 @@ #include <pthread.h> #include <vlib/threads.h> #include <vnet/fib/fib_table.h> +#include <vnet/mfib/mfib_table.h> #include <vlib/unix/unix.h> #include <vlibmemory/api.h> #include <vlibmemory/unix_shared_memory_queue.h> @@ -41,12 +42,14 @@ typedef struct * */ /* from .../vnet/vnet/ip/lookup.c. Yuck */ +/* *INDENT-OFF* */ typedef CLIB_PACKED (struct - { - ip4_address_t address; -u32 address_length: 6; -u32 index: 26; - }) ip4_route_t; +{ + ip4_address_t address; + u32 address_length: 6; + u32 index: 26; +}) ip4_route_t; +/* *INDENT-ON* */ /* see interface.api */ typedef struct @@ -79,12 +82,13 @@ typedef struct u32 index; } ip6_route_t; - typedef struct { ip4_route_t *ip4routes; ip6_route_t *ip6routes; + mfib_prefix_t *mroutes; fib_table_t **fibs; + mfib_table_t **mfibs; hash_pair_t **pvec; uword *results; } do_ip46_fibs_t; diff --git a/src/vpp/stats/stats.reg b/src/vpp/stats/stats.reg index d76443c4978..4c548c5d6ad 100644 --- a/src/vpp/stats/stats.reg +++ b/src/vpp/stats/stats.reg @@ -39,4 +39,5 @@ stats_reg (IP6_FIB_COUNTERS) stats_reg (IP6_NBR_COUNTERS) stats_reg (PER_INTERFACE_COMBINED_COUNTERS) stats_reg (PER_INTERFACE_SIMPLE_COUNTERS) - +stats_reg (IP4_MFIB_COUNTERS) +stats_reg (IP6_MFIB_COUNTERS) |