From 4868ff65eddfd694a1485d6c6c355f9a8ca9011d Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Thu, 9 Mar 2017 16:48:39 +0100 Subject: [PATCH] LISP statistics Change-Id: I399cac46d279e020ba33459ef759d9d29d3ac716 Signed-off-by: Filip Tehlar --- src/vat/api_format.c | 208 +++++++++++++++++++++++++++++++++ src/vnet/adj/adj_l2.c | 1 + src/vnet/lisp-cp/control.c | 72 ++++++++++-- src/vnet/lisp-cp/control.h | 14 +-- src/vnet/lisp-cp/lisp_types.c | 38 ++++++ src/vnet/lisp-cp/lisp_types.h | 3 + src/vnet/lisp-cp/one_api.c | 67 +++++++++++ src/vnet/lisp-cp/one_cli.c | 61 +++++++++- src/vnet/lisp-gpe/lisp_gpe.c | 2 + src/vnet/lisp-gpe/lisp_gpe.h | 30 +++++ src/vnet/lisp-gpe/lisp_gpe_adjacency.c | 100 ++++++++++++++++ src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c | 86 ++++++++++---- src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h | 3 + 13 files changed, 639 insertions(+), 46 deletions(-) diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 391fe9cf7c4..d34a97f65cb 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -2610,6 +2610,92 @@ vl_api_one_eid_table_details_t_handler_json (vl_api_one_eid_table_details_t vec_free (eid); } +static void +vl_api_one_stats_details_t_handler (vl_api_one_stats_details_t * mp) +{ + vat_main_t *vam = &vat_main; + u8 *seid = 0, *deid = 0; + u8 *(*format_ip_address_fcn) (u8 *, va_list *) = 0; + + deid = format (0, "%U", format_lisp_eid_vat, + mp->eid_type, mp->deid, mp->deid_pref_len, 0, 0, 0); + + seid = format (0, "%U", format_lisp_eid_vat, + mp->eid_type, mp->seid, mp->seid_pref_len, 0, 0, 0); + + vec_add1 (deid, 0); + vec_add1 (seid, 0); + + if (mp->is_ip4) + format_ip_address_fcn = format_ip4_address; + else + format_ip_address_fcn = format_ip6_address; + + + print (vam->ofp, "([%d] %s %s) (%U %U) %u %u", + clib_net_to_host_u32 (mp->vni), + seid, deid, + format_ip_address_fcn, mp->lloc, + format_ip_address_fcn, mp->rloc, + clib_net_to_host_u32 (mp->pkt_count), + clib_net_to_host_u32 (mp->bytes)); + + vec_free (deid); + vec_free (seid); +} + +static void +vl_api_one_stats_details_t_handler_json (vl_api_one_stats_details_t * mp) +{ + struct in6_addr ip6; + struct in_addr ip4; + vat_main_t *vam = &vat_main; + vat_json_node_t *node = 0; + u8 *deid = 0, *seid = 0; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + deid = format (0, "%U", format_lisp_eid_vat, + mp->eid_type, mp->deid, mp->deid_pref_len, 0, 0, 0); + + seid = format (0, "%U", format_lisp_eid_vat, + mp->eid_type, mp->seid, mp->seid_pref_len, 0, 0, 0); + + vec_add1 (deid, 0); + vec_add1 (seid, 0); + + vat_json_object_add_string_copy (node, "seid", seid); + vat_json_object_add_string_copy (node, "deid", deid); + vat_json_object_add_uint (node, "vni", clib_net_to_host_u32 (mp->vni)); + + if (mp->is_ip4) + { + clib_memcpy (&ip4, mp->lloc, sizeof (ip4)); + vat_json_object_add_ip4 (node, "lloc", ip4); + clib_memcpy (&ip4, mp->rloc, sizeof (ip4)); + vat_json_object_add_ip4 (node, "rloc", ip4); + } + else + { + clib_memcpy (&ip6, mp->lloc, sizeof (ip6)); + vat_json_object_add_ip6 (node, "lloc", ip6); + clib_memcpy (&ip6, mp->rloc, sizeof (ip6)); + vat_json_object_add_ip6 (node, "rloc", ip6); + } + vat_json_object_add_uint (node, "pkt_count", + clib_net_to_host_u32 (mp->pkt_count)); + vat_json_object_add_uint (node, "bytes", clib_net_to_host_u32 (mp->bytes)); + + vec_free (deid); + vec_free (seid); +} + static void vl_api_one_eid_table_map_details_t_handler (vl_api_one_eid_table_map_details_t * mp) @@ -2740,6 +2826,42 @@ static void vec_free (s); } +static void + vl_api_show_one_stats_enable_disable_reply_t_handler + (vl_api_show_one_stats_enable_disable_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + int retval = clib_net_to_host_u32 (mp->retval); + + if (retval) + goto end; + + print (vam->ofp, "%s", mp->is_en ? "enabled" : "disabled"); +end: + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_show_one_stats_enable_disable_reply_t_handler_json + (vl_api_show_one_stats_enable_disable_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t _node, *node = &_node; + int retval = clib_net_to_host_u32 (mp->retval); + + u8 *s = format (0, "%s", mp->is_en ? "enabled" : "disabled"); + vat_json_init_object (node); + vat_json_object_add_string_copy (node, "state", s); + + vat_json_print (vam->ofp, node); + vat_json_free (node); + + vam->retval = retval; + vam->result_ready = 1; + vec_free (s); +} + static void api_gpe_fwd_entry_net_to_host (vl_api_gpe_fwd_entry_t * e) { @@ -4040,6 +4162,7 @@ _(one_map_request_mode_reply) \ _(one_add_del_map_request_itr_rlocs_reply) \ _(one_eid_table_add_del_map_reply) \ _(one_use_petr_reply) \ +_(one_stats_enable_disable_reply) \ _(gpe_add_del_fwd_entry_reply) \ _(gpe_enable_disable_reply) \ _(gpe_set_encap_mode_reply) \ @@ -4263,6 +4386,10 @@ _(ONE_EID_TABLE_VNI_DETAILS, one_eid_table_vni_details) \ _(ONE_MAP_RESOLVER_DETAILS, one_map_resolver_details) \ _(ONE_MAP_SERVER_DETAILS, one_map_server_details) \ _(ONE_ADJACENCIES_GET_REPLY, one_adjacencies_get_reply) \ +_(ONE_STATS_DETAILS, one_stats_details) \ +_(ONE_STATS_ENABLE_DISABLE_REPLY, one_stats_enable_disable_reply) \ +_(SHOW_ONE_STATS_ENABLE_DISABLE_REPLY, \ + show_one_stats_enable_disable_reply) \ _(GPE_SET_ENCAP_MODE_REPLY, gpe_set_encap_mode_reply) \ _(GPE_GET_ENCAP_MODE_REPLY, gpe_get_encap_mode_reply) \ _(GPE_ADD_DEL_IFACE_REPLY, gpe_add_del_iface_reply) \ @@ -14214,6 +14341,64 @@ api_show_one_rloc_probe_state (vat_main_t * vam) #define api_show_lisp_rloc_probe_state api_show_one_rloc_probe_state +static int +api_one_stats_enable_disable (vat_main_t * vam) +{ + vl_api_one_stats_enable_disable_t *mp; + unformat_input_t *input = vam->input; + u8 is_set = 0; + u8 is_en = 0; + int ret; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "enable")) + { + is_set = 1; + is_en = 1; + } + else if (unformat (input, "disable")) + { + is_set = 1; + } + else + break; + } + + if (!is_set) + { + errmsg ("Value not set"); + return -99; + } + + M (ONE_STATS_ENABLE_DISABLE, mp); + mp->is_en = is_en; + + /* send */ + S (mp); + + /* wait for reply */ + W (ret); + return ret; +} + +static int +api_show_one_stats_enable_disable (vat_main_t * vam) +{ + vl_api_show_one_stats_enable_disable_t *mp; + int ret; + + M (SHOW_ONE_STATS_ENABLE_DISABLE, mp); + + /* send */ + S (mp); + + /* wait for reply */ + W (ret); + return ret; +} + static int api_show_one_map_request_mode (vat_main_t * vam) { @@ -15421,6 +15606,26 @@ api_one_map_resolver_dump (vat_main_t * vam) #define api_lisp_map_resolver_dump api_one_map_resolver_dump +static int +api_one_stats_dump (vat_main_t * vam) +{ + vl_api_one_stats_dump_t *mp; + vl_api_control_ping_t *mp_ping; + int ret; + + M (ONE_STATS_DUMP, mp); + /* send it... */ + S (mp); + + /* Use a control ping for synchronization */ + M (CONTROL_PING, mp_ping); + S (mp_ping); + + /* Wait for a reply... */ + W (ret); + return ret; +} + static int api_show_one_status (vat_main_t * vam) { @@ -18389,6 +18594,8 @@ _(one_locator_set_dump, "[local | remote]") \ _(one_locator_dump, "ls_index | ls_name ") \ _(one_eid_table_dump, "[eid / | ] [vni] " \ "[local] | [remote]") \ +_(one_stats_enable_disable, "enable|disalbe") \ +_(show_one_stats_enable_disable, "") \ _(one_eid_table_vni_dump, "") \ _(one_eid_table_map_dump, "l2|l3") \ _(one_map_resolver_dump, "") \ @@ -18397,6 +18604,7 @@ _(one_adjacencies_get, "vni ") \ _(show_one_rloc_probe_state, "") \ _(show_one_map_register_state, "") \ _(show_one_status, "") \ +_(one_stats_dump, "") \ _(one_get_map_request_itr_rlocs, "") \ _(show_one_pitr, "") \ _(show_one_use_petr, "") \ diff --git a/src/vnet/adj/adj_l2.c b/src/vnet/adj/adj_l2.c index 5a083643302..fb64e505633 100644 --- a/src/vnet/adj/adj_l2.c +++ b/src/vnet/adj/adj_l2.c @@ -93,6 +93,7 @@ adj_l2_rewrite_inline (vlib_main_t * vm, /* Update packet buffer attributes/set output interface. */ rw_len0 = adj0[0].rewrite_header.data_bytes; vnet_buffer(p0)->ip.save_rewrite_length = rw_len0; + vnet_buffer(p0)->sw_if_index[VLIB_TX] = adj0->rewrite_header.sw_if_index; vlib_increment_combined_counter(&adjacency_counters, cpu_index, diff --git a/src/vnet/lisp-cp/control.c b/src/vnet/lisp-cp/control.c index 5c90c03b9f0..47badeb9163 100644 --- a/src/vnet/lisp-cp/control.c +++ b/src/vnet/lisp-cp/control.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -284,6 +285,7 @@ dp_del_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index) if (fe->is_src_dst) gid_address_copy (&a->lcl_eid, &fe->leid); + vnet_lisp_del_fwd_stats (a, feip[0]); vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index); /* delete entry in fwd table */ @@ -1228,9 +1230,6 @@ vnet_lisp_add_del_adjacency (vnet_lisp_add_del_adjacency_args_t * a) if (a->is_add) { - /* TODO 1) check if src/dst 2) once we have src/dst working, use it in - * delete*/ - /* check if source eid has an associated mapping. If pitr mode is on, * just use the pitr's mapping */ local_mi = lcm->lisp_pitr ? lcm->pitr_map_index : @@ -2654,16 +2653,15 @@ lisp_get_vni_from_buffer_eth (lisp_cp_main_t * lcm, vlib_buffer_t * b) return vni; } -always_inline void +void get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b, - gid_address_t * src, gid_address_t * dst) + gid_address_t * src, gid_address_t * dst, + u16 type) { u32 vni = 0; - u16 type; memset (src, 0, sizeof (*src)); memset (dst, 0, sizeof (*dst)); - type = vnet_buffer (b)->lisp.overlay_afi; if (LISP_AFI_IP == type || LISP_AFI_IP6 == type) { @@ -2742,10 +2740,9 @@ lisp_cp_lookup_inline (vlib_main_t * vm, b0 = vlib_get_buffer (vm, pi0); b0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP]; - vnet_buffer (b0)->lisp.overlay_afi = overlay; /* src/dst eid pair */ - get_src_and_dst_eids_from_buffer (lcm, b0, &src, &dst); + get_src_and_dst_eids_from_buffer (lcm, b0, &src, &dst, overlay); /* if we have remote mapping for destination already in map-chache add forwarding tunnel directly. If not send a map-request */ @@ -3605,6 +3602,55 @@ lisp_cp_init (vlib_main_t * vm) return 0; } +static int +lisp_stats_api_fill (lisp_cp_main_t * lcm, lisp_gpe_main_t * lgm, + lisp_api_stats_t * stat, lisp_stats_key_t * key, + u32 stats_index) +{ + lisp_stats_t *s; + lisp_gpe_fwd_entry_key_t fwd_key; + const lisp_gpe_tunnel_t *lgt; + fwd_entry_t *fe; + + memset (stat, 0, sizeof (*stat)); + memset (&fwd_key, 0, sizeof (fwd_key)); + + fe = pool_elt_at_index (lcm->fwd_entry_pool, key->fwd_entry_index); + ASSERT (fe != 0); + + gid_to_dp_address (&fe->reid, &stat->deid); + gid_to_dp_address (&fe->leid, &stat->seid); + stat->vni = gid_address_vni (&fe->reid); + + lgt = lisp_gpe_tunnel_get (key->tunnel_index); + stat->loc_rloc = lgt->key->lcl; + stat->rmt_rloc = lgt->key->rmt; + + s = pool_elt_at_index (lgm->lisp_stats_pool, stats_index); + stat->stats = *s; + return 1; +} + +lisp_api_stats_t * +vnet_lisp_get_stats (void) +{ + lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main (); + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + lisp_api_stats_t *stats = 0, stat; + lisp_stats_key_t *key; + u32 index; + + /* *INDENT-OFF* */ + hash_foreach_mem (key, index, lgm->lisp_stats_index_by_key, + { + if (lisp_stats_api_fill (lcm, lgm, &stat, key, index)) + vec_add1 (stats, stat); + }); + /* *INDENT-ON* */ + + return stats; +} + static void * send_map_request_thread_fn (void *arg) { @@ -3810,7 +3856,11 @@ vnet_lisp_stats_enable_disable (u8 enable) if (vnet_lisp_enable_disable_status () == 0) return VNET_API_ERROR_LISP_DISABLED; - lcm->stats_enabled = enable; + if (enable) + lcm->flags |= LISP_FLAG_STATS_ENABLED; + else + lcm->flags &= ~LISP_FLAG_STATS_ENABLED; + return 0; } @@ -3822,7 +3872,7 @@ vnet_lisp_stats_enable_disable_state (void) if (vnet_lisp_enable_disable_status () == 0) return VNET_API_ERROR_LISP_DISABLED; - return lcm->stats_enabled; + return lcm->flags & LISP_FLAG_STATS_ENABLED; } /* *INDENT-OFF* */ diff --git a/src/vnet/lisp-cp/control.h b/src/vnet/lisp-cp/control.h index 933b34b66bc..eae8a184f76 100644 --- a/src/vnet/lisp-cp/control.h +++ b/src/vnet/lisp-cp/control.h @@ -95,7 +95,8 @@ typedef enum } map_request_mode_t; #define foreach_lisp_flag_bit \ - _(USE_PETR, "Use Proxy-ETR") + _(USE_PETR, "Use Proxy-ETR") \ + _(STATS_ENABLED, "Statistics enabled") typedef enum lisp_flag_bits { @@ -210,9 +211,6 @@ typedef struct /* timing wheel for mappping timeouts */ timing_wheel_t wheel; - /* statistics */ - u8 stats_enabled; - /* commodity */ ip4_main_t *im4; ip6_main_t *im6; @@ -235,6 +233,11 @@ vnet_lisp_cp_get_main () return &lisp_control_main; } +void +get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b, + gid_address_t * src, gid_address_t * dst, + u16 type); + typedef struct { u8 is_add; @@ -335,9 +338,6 @@ lisp_get_petr_mapping (lisp_cp_main_t * lcm) return pool_elt_at_index (lcm->mapping_pool, lcm->petr_map_index); } -u8 vnet_lisp_stats_enable_disable_state (void); -vnet_api_error_t vnet_lisp_stats_enable_disable (u8 enable); - #endif /* VNET_CONTROL_H_ */ /* diff --git a/src/vnet/lisp-cp/lisp_types.c b/src/vnet/lisp-cp/lisp_types.c index b6466686009..ad3a4bdf149 100644 --- a/src/vnet/lisp-cp/lisp_types.c +++ b/src/vnet/lisp-cp/lisp_types.c @@ -573,6 +573,44 @@ ip_address_parse (void *offset, u16 iana_afi, ip_address_t * dst) return (sizeof (u16) + size); } +void +gid_to_dp_address (gid_address_t * g, dp_address_t * d) +{ + switch (gid_address_type (g)) + { + case GID_ADDR_SRC_DST: + switch (gid_address_sd_dst_type (g)) + { + case FID_ADDR_IP_PREF: + ip_prefix_copy (&d->ippref, &gid_address_sd_dst_ippref (g)); + d->type = FID_ADDR_IP_PREF; + break; + case FID_ADDR_MAC: + mac_copy (&d->mac, &gid_address_sd_dst_mac (g)); + d->type = FID_ADDR_MAC; + break; + default: + clib_warning ("Source/Dest address type %d not supported!", + gid_address_sd_dst_type (g)); + break; + } + break; + case GID_ADDR_IP_PREFIX: + ip_prefix_copy (&d->ippref, &gid_address_ippref (g)); + d->type = FID_ADDR_IP_PREF; + break; + case GID_ADDR_MAC: + mac_copy (&d->mac, &gid_address_mac (g)); + d->type = FID_ADDR_MAC; + break; + case GID_ADDR_NSH: + default: + d->nsh = gid_address_nsh (g).spi << 8 | gid_address_nsh (g).si; + d->type = FID_ADDR_NSH; + break; + } +} + u32 lcaf_hdr_parse (void *offset, lcaf_t * lcaf) { diff --git a/src/vnet/lisp-cp/lisp_types.h b/src/vnet/lisp-cp/lisp_types.h index 672835bd760..a65a479e533 100644 --- a/src/vnet/lisp-cp/lisp_types.h +++ b/src/vnet/lisp-cp/lisp_types.h @@ -126,6 +126,8 @@ typedef struct typedef fid_address_t dp_address_t; #define fid_addr_ippref(_a) (_a)->ippref +#define fid_addr_prefix_length(_a) ip_prefix_len(&fid_addr_ippref(_a)) +#define fid_addr_ip_version(_a) ip_prefix_version(&fid_addr_ippref(_a)) #define fid_addr_mac(_a) (_a)->mac #define fid_addr_nsh(_a) (_a)->nsh #define fid_addr_type(_a) (_a)->type @@ -359,6 +361,7 @@ void build_src_dst (gid_address_t * sd, gid_address_t * src, gid_address_t * dst); void gid_address_from_ip (gid_address_t * g, ip_address_t * ip); +void gid_to_dp_address (gid_address_t * g, dp_address_t * d); #endif /* VNET_LISP_GPE_LISP_TYPES_H_ */ diff --git a/src/vnet/lisp-cp/one_api.c b/src/vnet/lisp-cp/one_api.c index 4faf624014b..ab9e7a635ce 100644 --- a/src/vnet/lisp-cp/one_api.c +++ b/src/vnet/lisp-cp/one_api.c @@ -58,6 +58,21 @@ #include +#define REPLY_DETAILS(t, body) \ +do { \ + unix_shared_memory_queue_t * q; \ + rv = vl_msg_api_pd_handler (mp, rv); \ + 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 = ntohs((t)); \ + rmp->context = mp->context; \ + do {body;} while (0); \ + vl_msg_api_send_shmem (q, (u8 *)&rmp); \ +} while(0); + #define foreach_vpe_api_msg \ _(ONE_ADD_DEL_LOCATOR_SET, one_add_del_locator_set) \ _(ONE_ADD_DEL_LOCATOR, one_add_del_locator) \ @@ -1300,10 +1315,62 @@ static void REPLY_MACRO (VL_API_ONE_ENABLE_DISABLE_REPLY); } +static void +lisp_fid_addr_to_api (fid_address_t * fid, u8 * dst, u8 * api_eid_type, + u8 * prefix_length) +{ + switch (fid_addr_type (fid)) + { + case FID_ADDR_IP_PREF: + *prefix_length = fid_addr_prefix_length (fid); + if (fid_addr_ip_version (fid) == IP4) + { + *api_eid_type = 0; /* ipv4 type */ + clib_memcpy (dst, &fid_addr_ippref (fid), 4); + } + else + { + *api_eid_type = 1; /* ipv6 type */ + clib_memcpy (dst, &fid_addr_ippref (fid), 16); + } + break; + case FID_ADDR_MAC: + *api_eid_type = 2; /* l2 mac type */ + mac_copy (dst, fid_addr_mac (fid)); + break; + default: + ASSERT (0); + } +} + static void vl_api_one_stats_dump_t_handler (vl_api_one_stats_dump_t * mp) { + vl_api_one_stats_details_t *rmp; + lisp_api_stats_t *stats, *stat; + u8 rv = 0; + stats = vnet_lisp_get_stats (); + vec_foreach (stat, stats) + { + /* *INDENT-OFF* */ + REPLY_DETAILS (VL_API_ONE_STATS_DETAILS, + ({ + lisp_fid_addr_to_api (&stat->deid, rmp->deid, &rmp->eid_type, + &rmp->deid_pref_len); + lisp_fid_addr_to_api (&stat->seid, rmp->seid, &rmp->eid_type, + &rmp->seid_pref_len); + rmp->vni = clib_host_to_net_u32 (stat->vni); + + rmp->is_ip4 = ip_addr_version (&stat->rmt_rloc) == IP4 ? 1 : 0; + ip_address_copy_addr (rmp->rloc, &stat->rmt_rloc); + ip_address_copy_addr (rmp->lloc, &stat->loc_rloc); + + rmp->pkt_count = clib_host_to_net_u32 (stat->stats.pkt_count); + rmp->bytes = clib_host_to_net_u32 (stat->stats.bytes); + })); + /* *INDENT-ON* */ + } } /* diff --git a/src/vnet/lisp-cp/one_cli.c b/src/vnet/lisp-cp/one_cli.c index 2ceeaf42fa7..b5bc5292fad 100644 --- a/src/vnet/lisp-cp/one_cli.c +++ b/src/vnet/lisp-cp/one_cli.c @@ -352,7 +352,7 @@ lisp_add_del_remote_mapping_command_fn (vlib_main_t * vm, } } - if (!eid_set) + if (!del_all && !eid_set) { clib_warning ("missing eid!"); goto done; @@ -372,8 +372,6 @@ lisp_add_del_remote_mapping_command_fn (vlib_main_t * vm, goto done; } - /* TODO build src/dst with seid */ - /* if it's a delete, clean forwarding */ if (!is_add) { @@ -1654,12 +1652,46 @@ lisp_show_stats_command_fn (vlib_main_t * vm, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (one_show_stats_command) = { - .path = "show one stats", - .short_help = "show ONE statistics", + .path = "show one statistics status", + .short_help = "show ONE statistics enable/disable status", .function = lisp_show_stats_command_fn, }; /* *INDENT-ON* */ +static clib_error_t * +lisp_show_stats_details_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + lisp_api_stats_t *stat, *stats = vnet_lisp_get_stats (); + + if (vec_len (stats) > 0) + vlib_cli_output (vm, + "[src-EID, dst-EID] [loc-rloc, rmt-rloc] count bytes\n"); + else + vlib_cli_output (vm, "No statistics found.\n"); + + vec_foreach (stat, stats) + { + vlib_cli_output (vm, "[%U, %U] [%U, %U] %7u %7u\n", + format_fid_address, &stat->seid, + format_fid_address, &stat->deid, + format_ip_address, &stat->loc_rloc, + format_ip_address, &stat->rmt_rloc, + stat->stats.pkt_count, stat->stats.bytes); + } + vec_free (stats); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (one_show_stats_details_command) = { + .path = "show one statistics details", + .short_help = "show ONE statistics", + .function = lisp_show_stats_details_command_fn, +}; +/* *INDENT-ON* */ + static clib_error_t * lisp_stats_enable_disable_command_fn (vlib_main_t * vm, unformat_input_t * input, @@ -1692,12 +1724,29 @@ done: /* *INDENT-OFF* */ VLIB_CLI_COMMAND (one_stats_enable_disable_command) = { - .path = "one stats", + .path = "one statistics", .short_help = "enable/disable ONE statistics collecting", .function = lisp_stats_enable_disable_command_fn, }; /* *INDENT-ON* */ +static clib_error_t * +lisp_stats_flush_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + vnet_lisp_flush_stats (); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (one_stats_flush_command) = { + .path = "one statistics flush", + .short_help = "Flush ONE statistics", + .function = lisp_stats_flush_command_fn, +}; +/* *INDENT-ON* */ + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vnet/lisp-gpe/lisp_gpe.c b/src/vnet/lisp-gpe/lisp_gpe.c index 446ad445592..1241ab9caec 100644 --- a/src/vnet/lisp-gpe/lisp_gpe.c +++ b/src/vnet/lisp-gpe/lisp_gpe.c @@ -424,6 +424,8 @@ lisp_gpe_init (vlib_main_t * vm) udp_register_dst_port (vm, UDP_DST_PORT_lisp_gpe6, lisp_gpe_ip6_input_node.index, 0 /* is_ip4 */ ); + lgm->lisp_stats_index_by_key = + hash_create_mem (0, sizeof (lisp_stats_key_t), sizeof (uword)); return 0; } diff --git a/src/vnet/lisp-gpe/lisp_gpe.h b/src/vnet/lisp-gpe/lisp_gpe.h index b5a50ec6884..be447024cb9 100644 --- a/src/vnet/lisp-gpe/lisp_gpe.h +++ b/src/vnet/lisp-gpe/lisp_gpe.h @@ -90,6 +90,28 @@ typedef struct tunnel_lookup uword *vni_by_sw_if_index; } tunnel_lookup_t; +typedef struct +{ + u32 fwd_entry_index; + u32 tunnel_index; +} lisp_stats_key_t; + +typedef struct +{ + u32 pkt_count; + u32 bytes; +} lisp_stats_t; + +typedef struct +{ + u32 vni; + dp_address_t deid; + dp_address_t seid; + ip_address_t loc_rloc; + ip_address_t rmt_rloc; + + lisp_stats_t stats; +} lisp_api_stats_t; typedef enum gpe_encap_mode_e { @@ -143,6 +165,9 @@ typedef struct lisp_gpe_main gpe_encap_mode_t encap_mode; + lisp_stats_t *lisp_stats_pool; + uword *lisp_stats_index_by_key; + /** convenience */ vlib_main_t *vlib_main; vnet_main_t *vnet_main; @@ -283,6 +308,11 @@ lisp_api_gpe_fwd_entry_t *vnet_lisp_gpe_fwd_entries_get_by_vni (u32 vni); gpe_encap_mode_t vnet_gpe_get_encap_mode (void); int vnet_gpe_set_encap_mode (gpe_encap_mode_t mode); +u8 vnet_lisp_stats_enable_disable_state (void); +vnet_api_error_t vnet_lisp_stats_enable_disable (u8 enable); +lisp_api_stats_t *vnet_lisp_get_stats (void); +void vnet_lisp_flush_stats (void); + #endif /* included_vnet_lisp_gpe_h */ /* diff --git a/src/vnet/lisp-gpe/lisp_gpe_adjacency.c b/src/vnet/lisp-gpe/lisp_gpe_adjacency.c index dbcf7134103..50662dd679f 100644 --- a/src/vnet/lisp-gpe/lisp_gpe_adjacency.c +++ b/src/vnet/lisp-gpe/lisp_gpe_adjacency.c @@ -19,6 +19,7 @@ */ #include +#include #include #include #include @@ -223,9 +224,108 @@ lisp_gpe_adj_proto_from_vnet_link_type (vnet_link_t linkt) #define is_v4_packet(_h) ((*(u8*) _h) & 0xF0) == 0x40 +static lisp_afi_e +lisp_afi_from_vnet_link_type (vnet_link_t link) +{ + switch (link) + { + case VNET_LINK_IP4: + return LISP_AFI_IP; + case VNET_LINK_IP6: + return LISP_AFI_IP6; + case VNET_LINK_ETHERNET: + return LISP_AFI_MAC; + default: + return LISP_AFI_NO_ADDR; + } +} + +static void +lisp_gpe_increment_stats_counters (lisp_cp_main_t * lcm, ip_adjacency_t * adj, + vlib_buffer_t * b) +{ + lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main (); + lisp_gpe_adjacency_t *ladj; + ip_address_t rloc; + index_t lai; + u32 si, di; + gid_address_t src, dst; + lisp_stats_t *stats; + uword *feip; + + ip46_address_to_ip_address (&adj->sub_type.nbr.next_hop, &rloc); + si = vnet_buffer (b)->sw_if_index[VLIB_TX]; + lai = lisp_adj_find (&rloc, si); + ASSERT (INDEX_INVALID != lai); + + ladj = pool_elt_at_index (lisp_adj_pool, lai); + + u8 *lisp_data = (u8 *) vlib_buffer_get_current (b); + + /* skip IP header */ + if (is_v4_packet (lisp_data)) + lisp_data += sizeof (ip4_header_t); + else + lisp_data += sizeof (ip6_header_t); + + /* skip UDP header */ + lisp_data += sizeof (udp_header_t); + // TODO: skip TCP? + + /* skip LISP GPE header */ + lisp_data += sizeof (lisp_gpe_header_t); + + i16 saved_current_data = b->current_data; + b->current_data = lisp_data - b->data; + + lisp_afi_e afi = lisp_afi_from_vnet_link_type (adj->ia_link); + get_src_and_dst_eids_from_buffer (lcm, b, &src, &dst, afi); + b->current_data = saved_current_data; + di = gid_dictionary_sd_lookup (&lcm->mapping_index_by_gid, &dst, &src); + if (PREDICT_FALSE (~0 == di)) + { + clib_warning ("dst mapping not found (%U, %U)", format_gid_address, + &src, format_gid_address, &dst); + return; + } + + feip = hash_get (lcm->fwd_entry_by_mapping_index, di); + if (PREDICT_FALSE (!feip)) + return; + + lisp_stats_key_t key; + memset (&key, 0, sizeof (key)); + key.fwd_entry_index = feip[0]; + key.tunnel_index = ladj->tunnel_index; + + uword *p = hash_get_mem (lgm->lisp_stats_index_by_key, &key); + if (p) + { + stats = pool_elt_at_index (lgm->lisp_stats_pool, p[0]); + } + else + { + pool_get (lgm->lisp_stats_pool, stats); + memset (stats, 0, sizeof (*stats)); + + lisp_stats_key_t *key_copy = clib_mem_alloc (sizeof (*key_copy)); + memcpy (key_copy, &key, sizeof (*key_copy)); + hash_set_mem (lgm->lisp_stats_index_by_key, key_copy, + stats - lgm->lisp_stats_pool); + } + stats->pkt_count++; + /* compute payload length starting after GPE */ + stats->bytes += b->current_length - (lisp_data - b->data - b->current_data); +} + static void lisp_gpe_fixup (vlib_main_t * vm, ip_adjacency_t * adj, vlib_buffer_t * b) { + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + + if (lcm->flags & LISP_FLAG_STATS_ENABLED) + lisp_gpe_increment_stats_counters (lcm, adj, b); + /* Fixup the checksum and len fields in the LISP tunnel encap * that was applied at the midchain node */ ip_udp_fixup_one (vm, b, is_v4_packet (vlib_buffer_get_current (b))); diff --git a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c index 2eb5ced60b0..f458a14c86b 100644 --- a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c +++ b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c @@ -329,28 +329,6 @@ delete_fib_entries (lisp_gpe_fwd_entry_t * lfe) lfe->eid_fib_index, &lfe->key->rmt.ippref); } -static void -gid_to_dp_address (gid_address_t * g, dp_address_t * d) -{ - switch (gid_address_type (g)) - { - case GID_ADDR_IP_PREFIX: - case GID_ADDR_SRC_DST: - ip_prefix_copy (&d->ippref, &gid_address_ippref (g)); - d->type = FID_ADDR_IP_PREF; - break; - case GID_ADDR_MAC: - mac_copy (&d->mac, &gid_address_mac (g)); - d->type = FID_ADDR_MAC; - break; - case GID_ADDR_NSH: - default: - d->nsh = gid_address_nsh (g).spi << 8 | gid_address_nsh (g).si; - d->type = FID_ADDR_NSH; - break; - } -} - static lisp_gpe_fwd_entry_t * find_fwd_entry (lisp_gpe_main_t * lgm, vnet_lisp_gpe_add_del_fwd_entry_args_t * a, @@ -1177,6 +1155,70 @@ vnet_lisp_gpe_add_del_fwd_entry (vnet_lisp_gpe_add_del_fwd_entry_args_t * a, } } +void +vnet_lisp_flush_stats (void) +{ + lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main (); + lisp_stats_t *stat; + + /* *INDENT-OFF* */ + pool_foreach (stat, lgm->lisp_stats_pool, + { + stat->pkt_count = 0; + stat->bytes = 0; + }); + /* *INDENT-ON* */ +} + +static void +lisp_del_adj_stats (lisp_gpe_main_t * lgm, u32 fwd_entry_index, u32 ti) +{ + hash_pair_t *hp; + lisp_stats_key_t key; + void *key_copy; + uword *p; + lisp_stats_t *s; + + memset (&key, 0, sizeof (key)); + key.fwd_entry_index = fwd_entry_index; + key.tunnel_index = ti; + + p = hash_get_mem (lgm->lisp_stats_index_by_key, &key); + if (p) + { + s = pool_elt_at_index (lgm->lisp_stats_pool, p[0]); + hp = hash_get_pair (lgm->lisp_stats_index_by_key, &key); + key_copy = (void *) (hp->key); + hash_unset_mem (lgm->lisp_stats_index_by_key, &key); + clib_mem_free (key_copy); + pool_put (lgm->lisp_stats_pool, s); + } +} + +void +vnet_lisp_del_fwd_stats (vnet_lisp_gpe_add_del_fwd_entry_args_t * a, + u32 fwd_entry_index) +{ + lisp_gpe_main_t *lgm = &lisp_gpe_main; + lisp_gpe_fwd_entry_key_t fe_key; + lisp_gpe_fwd_entry_t *lfe; + lisp_fwd_path_t *path; + const lisp_gpe_adjacency_t *ladj; + + lfe = find_fwd_entry (lgm, a, &fe_key); + if (!lfe) + return; + + if (LISP_GPE_FWD_ENTRY_TYPE_NORMAL != lfe->type) + return; + + vec_foreach (path, lfe->paths) + { + ladj = lisp_gpe_adjacency_get (path->lisp_adj); + lisp_del_adj_stats (lgm, fwd_entry_index, ladj->tunnel_index); + } +} + /** * @brief Flush all the forwrding entries */ diff --git a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h index d58895a3e28..618f7b5393d 100644 --- a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h +++ b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h @@ -206,6 +206,9 @@ extern u32 lisp_l2_fib_lookup (lisp_gpe_main_t * lgm, extern const dpo_id_t *lisp_nsh_fib_lookup (lisp_gpe_main_t * lgm, u32 spi_si); +extern void +vnet_lisp_del_fwd_stats (vnet_lisp_gpe_add_del_fwd_entry_args_t * a, + u32 fwd_entry_index); #endif /* -- 2.16.6