VPP-108 : API calls to read classify table and sessions
[vpp.git] / vpp / api / api.c
index f99d9ce..302b7d4 100644 (file)
@@ -334,10 +334,12 @@ _(LISP_ENABLE_DISABLE, lisp_enable_disable)                             \
 _(LISP_GPE_ADD_DEL_IFACE, lisp_gpe_add_del_iface)                       \
 _(LISP_ADD_DEL_REMOTE_MAPPING, lisp_add_del_remote_mapping)             \
 _(LISP_PITR_SET_LOCATOR_SET, lisp_pitr_set_locator_set)                 \
+_(LISP_EID_TABLE_ADD_DEL_MAP, lisp_eid_table_add_del_map)               \
 _(LISP_LOCATOR_SET_DUMP, lisp_locator_set_dump)                         \
 _(LISP_LOCAL_EID_TABLE_DUMP, lisp_local_eid_table_dump)                 \
 _(LISP_GPE_TUNNEL_DUMP, lisp_gpe_tunnel_dump)                           \
 _(LISP_MAP_RESOLVER_DUMP, lisp_map_resolver_dump)                       \
+_(LISP_EID_TABLE_MAP_DUMP, lisp_eid_table_map_dump)                     \
 _(LISP_ENABLE_DISABLE_STATUS_DUMP,                                      \
   lisp_enable_disable_status_dump)                                      \
 _(LISP_ADD_DEL_MAP_REQUEST_ITR_RLOCS,                                   \
@@ -349,7 +351,20 @@ _(AF_PACKET_DELETE, af_packet_delete)                                   \
 _(POLICER_ADD_DEL, policer_add_del)                                     \
 _(POLICER_DUMP, policer_dump)                                           \
 _(NETMAP_CREATE, netmap_create)                                         \
-_(NETMAP_DELETE, netmap_delete)
+_(NETMAP_DELETE, netmap_delete)                                         \
+_(MPLS_GRE_TUNNEL_DUMP, mpls_gre_tunnel_dump)                           \
+_(MPLS_GRE_TUNNEL_DETAILS, mpls_gre_tunnel_details)                     \
+_(MPLS_ETH_TUNNEL_DUMP, mpls_eth_tunnel_dump)                           \
+_(MPLS_ETH_TUNNEL_DETAILS, mpls_eth_tunnel_details)                     \
+_(MPLS_FIB_ENCAP_DUMP, mpls_fib_encap_dump)                             \
+_(MPLS_FIB_ENCAP_DETAILS, mpls_fib_encap_details)                       \
+_(MPLS_FIB_DECAP_DUMP, mpls_fib_decap_dump)                             \
+_(MPLS_FIB_DECAP_DETAILS, mpls_fib_decap_details)                       \
+_(CLASSIFY_TABLE_IDS,classify_table_ids)                                \
+_(CLASSIFY_TABLE_BY_INTERFACE, classify_table_by_interface)             \
+_(CLASSIFY_TABLE_INFO,classify_table_info)                              \
+_(CLASSIFY_SESSION_DUMP,classify_session_dump)                          \
+_(CLASSIFY_SESSION_DETAILS,classify_session_details)
 
 #define QUOTE_(x) #x
 #define QUOTE(x) QUOTE_(x)
@@ -1345,6 +1360,8 @@ static void
 vl_api_sw_interface_set_vpath_t_handler (vl_api_sw_interface_set_vpath_t *mp)
 {
     vlib_main_t *vm = vlib_get_main();
+    ip4_main_t * im4 = &ip4_main;
+    ip6_main_t * im6 = &ip6_main;
     vl_api_sw_interface_set_vpath_reply_t * rmp;
     int rv = 0;
     u32 ci;
@@ -1364,36 +1381,52 @@ vl_api_sw_interface_set_vpath_t_handler (vl_api_sw_interface_set_vpath_t *mp)
     if (mp->enable) {
         ci = rx_cm4u->config_index_by_sw_if_index[sw_if_index]; //IP4 unicast
         ci = vnet_config_add_feature(vm, &rx_cm4u->config_main,
-                                     ci, IP4_RX_FEATURE_VPATH, 0, 0);
+                                     ci, 
+                                     im4->ip4_unicast_rx_feature_vpath,
+                                     0, 0);
         rx_cm4u->config_index_by_sw_if_index[sw_if_index] = ci;
         ci = rx_cm4m->config_index_by_sw_if_index[sw_if_index]; //IP4 mcast
         ci = vnet_config_add_feature(vm, &rx_cm4m->config_main,
-                                     ci, IP4_RX_FEATURE_VPATH, 0, 0);
+                                     ci, 
+                                     im4->ip4_multicast_rx_feature_vpath,
+                                     0, 0);
         rx_cm4m->config_index_by_sw_if_index[sw_if_index] = ci;
         ci = rx_cm6u->config_index_by_sw_if_index[sw_if_index]; //IP6 unicast
         ci = vnet_config_add_feature(vm, &rx_cm6u->config_main,
-                                     ci, IP6_RX_FEATURE_VPATH, 0, 0);
+                                     ci, 
+                                     im6->ip6_unicast_rx_feature_vpath,
+                                     0, 0);
         rx_cm6u->config_index_by_sw_if_index[sw_if_index] = ci;
         ci = rx_cm6m->config_index_by_sw_if_index[sw_if_index]; //IP6 mcast
         ci = vnet_config_add_feature(vm, &rx_cm6m->config_main,
-                                     ci, IP6_RX_FEATURE_VPATH, 0, 0);
+                                     ci, 
+                                     im6->ip6_multicast_rx_feature_vpath,
+                                     0, 0);
         rx_cm6m->config_index_by_sw_if_index[sw_if_index] = ci;
     } else {
         ci = rx_cm4u->config_index_by_sw_if_index[sw_if_index]; //IP4 unicast
         ci = vnet_config_del_feature(vm, &rx_cm4u->config_main,
-                                     ci, IP4_RX_FEATURE_VPATH, 0, 0);
+                                     ci, 
+                                     im4->ip4_unicast_rx_feature_vpath,
+                                     0, 0);
         rx_cm4u->config_index_by_sw_if_index[sw_if_index] = ci;
         ci = rx_cm4m->config_index_by_sw_if_index[sw_if_index]; //IP4 mcast
         ci = vnet_config_del_feature(vm, &rx_cm4m->config_main,
-                                     ci, IP4_RX_FEATURE_VPATH, 0, 0);
+                                     ci, 
+                                     im4->ip4_multicast_rx_feature_vpath,
+                                     0, 0);
         rx_cm4m->config_index_by_sw_if_index[sw_if_index] = ci;
         ci = rx_cm6u->config_index_by_sw_if_index[sw_if_index]; //IP6 unicast
         ci = vnet_config_del_feature(vm, &rx_cm6u->config_main,
-                                     ci, IP6_RX_FEATURE_VPATH, 0, 0);
+                                     ci, 
+                                     im6->ip6_unicast_rx_feature_vpath,
+                                     0, 0);
         rx_cm6u->config_index_by_sw_if_index[sw_if_index] = ci;
         ci = rx_cm6m->config_index_by_sw_if_index[sw_if_index]; //IP6 mcast
         ci = vnet_config_del_feature(vm, &rx_cm6m->config_main,
-                                     ci, IP6_RX_FEATURE_VPATH, 0, 0);
+                                     ci, 
+                                     im6->ip6_multicast_rx_feature_vpath,
+                                     0, 0);
         rx_cm6m->config_index_by_sw_if_index[sw_if_index] = ci;
     }
 
@@ -4752,6 +4785,7 @@ vl_api_lisp_add_del_local_eid_t_handler(
     u32 locator_set_index = ~0, map_index = ~0;
     vnet_lisp_add_del_mapping_args_t _a, *a = &_a;
     u8 *name = NULL;
+    memset (a, 0, sizeof (a[0]));
 
     prefp = &gid_address_ippref(&eid);
     ip_eid = &ip_prefix_addr(prefp);
@@ -4778,18 +4812,30 @@ vl_api_lisp_add_del_local_eid_t_handler(
 
   /* XXX treat batch configuration */
     a->is_add = mp->is_add;
+    gid_address_vni (&eid) = clib_net_to_host_u32 (mp->vni);
     a->deid = eid;
     a->locator_set_index = locator_set_index;
     a->local = 1;
-
     rv = vnet_lisp_add_del_local_mapping(a, &map_index);
 
 out:
     vec_free(name);
+    gid_address_free (&a->deid);
 
     REPLY_MACRO(VL_API_LISP_ADD_DEL_LOCAL_EID_REPLY);
 }
 
+static void
+vl_api_lisp_eid_table_add_del_map_t_handler(
+    vl_api_lisp_eid_table_add_del_map_t *mp)
+{
+    vl_api_lisp_eid_table_add_del_map_reply_t *rmp;
+    int rv = 0;
+    rv = vnet_lisp_eid_table_map (clib_net_to_host_u32 (mp->vni),
+                                  clib_net_to_host_u32 (mp->vrf), mp->is_add);
+    REPLY_MACRO(VL_API_LISP_EID_TABLE_ADD_DEL_MAP_REPLY)
+}
+
 static void
 lisp_gpe_add_del_fwd_entry_set_address(
     vl_api_lisp_gpe_add_del_fwd_entry_t *mp,
@@ -4917,7 +4963,7 @@ vl_api_lisp_gpe_add_del_iface_t_handler(
     a->is_add = mp->is_add;
     a->table_id = mp->table_id;
     a->vni = mp->vni;
-    vnet_lisp_gpe_add_del_iface (a, 0);
+    rv = vnet_lisp_gpe_add_del_iface (a, 0);
 
     REPLY_MACRO(VL_API_LISP_GPE_ADD_DEL_IFACE_REPLY);
 }
@@ -5001,8 +5047,8 @@ vl_api_lisp_add_del_remote_mapping_t_handler (
     ip_address_t * deid_addr = &ip_prefix_addr(deid_pref);
     ip_prefix_len(seid_pref) = mp->seid_len;
     ip_prefix_len(deid_pref) = mp->deid_len;
-    gid_address_set_vni (seid, ntohl (mp->vni));
-    gid_address_set_vni (deid, ntohl (mp->vni));
+    gid_address_vni (seid) = ntohl (mp->vni);
+    gid_address_vni (deid) = ntohl (mp->vni);
 
     if (mp->eid_is_ip4) {
         ip_prefix_version(seid_pref) = IP4;
@@ -5154,7 +5200,7 @@ send_lisp_local_eid_table_details (mapping_t *mapit,
     }
     rmp->eid_prefix_len = ip_prefix_len(ip_prefix);
     rmp->context = context;
-
+    rmp->vni = clib_host_to_net_u32 (gid_address_vni (gid));
     vl_msg_api_send_shmem (q, (u8 *)&rmp);
 }
 
@@ -5211,7 +5257,7 @@ send_lisp_gpe_tunnel_details (lisp_gpe_tunnel_t *tunnel,
 
 static void
 vl_api_lisp_gpe_tunnel_dump_t_handler (
-    vl_api_lisp_local_eid_table_dump_t *mp)
+    vl_api_lisp_gpe_tunnel_dump_t *mp)
 {
     unix_shared_memory_queue_t * q = NULL;
     lisp_gpe_main_t * lgm = &lisp_gpe_main;
@@ -5281,6 +5327,28 @@ vl_api_lisp_map_resolver_dump_t_handler (
 
 }
 
+static void
+vl_api_lisp_eid_table_map_dump_t_handler (
+    vl_api_lisp_eid_table_map_dump_t *mp)
+{
+    unix_shared_memory_queue_t * q = NULL;
+    lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
+    hash_pair_t * p;
+
+    q = vl_api_client_index_to_input_queue (mp->client_index);
+    if (q == 0) {
+        return;
+    }
+    hash_foreach_pair (p, lcm->table_id_by_vni, {
+        vl_api_lisp_eid_table_map_details_t * rmp = NULL;
+        memset (rmp, 0, sizeof (*rmp));
+        rmp->_vl_msg_id = ntohs(VL_API_LISP_EID_TABLE_MAP_DETAILS);
+        rmp->vni = p->key;
+        rmp->vrf = p->value[0];
+        rmp->context = mp->context;
+    });
+}
+
 static void
 send_lisp_enable_disable_details (unix_shared_memory_queue_t *q,
                                       u32 context)
@@ -6249,6 +6317,544 @@ vl_api_netmap_delete_t_handler
     REPLY_MACRO(VL_API_NETMAP_DELETE_REPLY);
 }
 
+static void vl_api_mpls_gre_tunnel_details_t_handler (
+    vl_api_mpls_gre_tunnel_details_t * mp)
+{
+    clib_warning ("BUG");
+}
+
+static void send_mpls_gre_tunnel_entry (vpe_api_main_t * am,
+                                    unix_shared_memory_queue_t *q,
+                                    mpls_gre_tunnel_t * gt,
+                                    u32 index,
+                                    u32 context)
+{
+    vl_api_mpls_gre_tunnel_details_t * mp;
+
+    mp = vl_msg_api_alloc (sizeof (*mp));
+    memset (mp, 0, sizeof (*mp));
+    mp->_vl_msg_id = ntohs(VL_API_MPLS_GRE_TUNNEL_DETAILS);
+    mp->context = context;
+
+    if (gt != NULL) {
+        mp->tunnel_index    = htonl(index);
+        mp->tunnel_src      = gt->tunnel_src.as_u32;
+        mp->tunnel_dst      = gt->tunnel_dst.as_u32;
+        mp->intfc_address   = gt->intfc_address.as_u32;
+        mp->mask_width      = htonl(gt->mask_width);
+        mp->inner_fib_index = htonl(gt->inner_fib_index);
+        mp->outer_fib_index = htonl(gt->outer_fib_index);
+        mp->encap_index     = htonl(gt->encap_index);
+        mp->hw_if_index     = htonl(gt->hw_if_index);
+        mp->l2_only         = htonl(gt->l2_only);
+    }
+
+    mpls_main_t * mm = &mpls_main;
+    mpls_encap_t * e;
+    int i;
+    u32 len = 0;
+
+    e = pool_elt_at_index (mm->encaps, gt->encap_index);
+    len = vec_len (e->labels);
+    mp->nlabels = htonl(len);
+
+    for (i = 0; i < len; i++) {
+        mp->labels[i] = htonl(vnet_mpls_uc_get_label(
+                clib_host_to_net_u32(e->labels[i].label_exp_s_ttl)));
+    }
+
+    vl_msg_api_send_shmem (q, (u8 *)&mp);
+}
+
+static void
+vl_api_mpls_gre_tunnel_dump_t_handler (vl_api_mpls_gre_tunnel_dump_t *mp)
+{
+    vpe_api_main_t * am = &vpe_api_main;
+    unix_shared_memory_queue_t * q;
+    vlib_main_t * vm = &vlib_global_main;
+    mpls_main_t * mm = &mpls_main;
+    mpls_gre_tunnel_t * gt;
+    u32 index = ntohl(mp->tunnel_index);
+
+    q = vl_api_client_index_to_input_queue (mp->client_index);
+    if (q == 0)
+        return;
+
+    if (pool_elts (mm->gre_tunnels)) {
+        if(mp->tunnel_index >= 0) {
+            vlib_cli_output (vm, "MPLS-GRE tunnel %u", index);
+            gt = pool_elt_at_index (mm->gre_tunnels, index);
+            send_mpls_gre_tunnel_entry (am, q, gt, gt - mm->gre_tunnels, mp->context);
+        } else {
+            vlib_cli_output (vm, "MPLS-GRE tunnels");
+            pool_foreach (gt, mm->gre_tunnels,
+            ({
+              send_mpls_gre_tunnel_entry (am, q, gt, gt - mm->gre_tunnels, mp->context);
+            }));
+        }
+    } else {
+        vlib_cli_output (vm, "No MPLS-GRE tunnels");
+    }
+}
+
+static void vl_api_mpls_eth_tunnel_details_t_handler (
+    vl_api_mpls_eth_tunnel_details_t * mp)
+{
+    clib_warning ("BUG");
+}
+
+static void send_mpls_eth_tunnel_entry (vpe_api_main_t * am,
+                                    unix_shared_memory_queue_t *q,
+                                    mpls_eth_tunnel_t * et,
+                                    u32 index,
+                                    u32 context)
+{
+    vl_api_mpls_eth_tunnel_details_t * mp;
+
+    mp = vl_msg_api_alloc (sizeof (*mp));
+    memset (mp, 0, sizeof (*mp));
+    mp->_vl_msg_id = ntohs(VL_API_MPLS_ETH_TUNNEL_DETAILS);
+    mp->context = context;
+
+    if (et != NULL) {
+        mp->tunnel_index    = htonl(index);
+        memcpy(mp->tunnel_dst_mac, et->tunnel_dst, 6);
+        mp->intfc_address   = et->intfc_address.as_u32;
+        mp->tx_sw_if_index  = htonl(et->tx_sw_if_index);
+        mp->inner_fib_index = htonl(et->inner_fib_index);
+        mp->mask_width      = htonl(et->mask_width);
+        mp->encap_index     = htonl(et->encap_index);
+        mp->hw_if_index     = htonl(et->hw_if_index);
+        mp->l2_only         = htonl(et->l2_only);
+    }
+
+    mpls_main_t * mm = &mpls_main;
+    mpls_encap_t * e;
+    int i;
+    u32 len = 0;
+
+    e = pool_elt_at_index (mm->encaps, et->encap_index);
+    len = vec_len (e->labels);
+    mp->nlabels = htonl(len);
+
+    for (i = 0; i < len; i++) {
+        mp->labels[i] = htonl(vnet_mpls_uc_get_label(
+                clib_host_to_net_u32(e->labels[i].label_exp_s_ttl)));
+    }
+
+    vl_msg_api_send_shmem (q, (u8 *)&mp);
+}
+
+static void
+vl_api_mpls_eth_tunnel_dump_t_handler (vl_api_mpls_eth_tunnel_dump_t *mp)
+{
+    vpe_api_main_t * am = &vpe_api_main;
+    unix_shared_memory_queue_t * q;
+    vlib_main_t * vm = &vlib_global_main;
+    mpls_main_t * mm = &mpls_main;
+    mpls_eth_tunnel_t * et;
+    u32 index = ntohl(mp->tunnel_index);
+
+    q = vl_api_client_index_to_input_queue (mp->client_index);
+    if (q == 0)
+        return;
+
+    clib_warning("Received mpls_eth_tunnel_dump");
+    clib_warning("Received tunnel index: %u from client %u", index, mp->client_index);
+
+    if (pool_elts (mm->eth_tunnels)) {
+        if(mp->tunnel_index >= 0) {
+            vlib_cli_output (vm, "MPLS-Ethernet tunnel %u", index);
+            et = pool_elt_at_index (mm->eth_tunnels, index);
+            send_mpls_eth_tunnel_entry (am, q, et, et - mm->eth_tunnels, mp->context);
+        } else {
+            clib_warning("MPLS-Ethernet tunnels");
+            pool_foreach (et, mm->eth_tunnels,
+            ({
+                send_mpls_eth_tunnel_entry (am, q, et, et - mm->eth_tunnels, mp->context);
+            }));
+        }
+    } else {
+        clib_warning("No MPLS-Ethernet tunnels");
+    }
+}
+
+static void vl_api_mpls_fib_encap_details_t_handler (
+    vl_api_mpls_fib_encap_details_t * mp)
+{
+    clib_warning ("BUG");
+}
+
+static void send_mpls_fib_encap_details (vpe_api_main_t * am,
+                                    unix_shared_memory_queue_t *q,
+                                    show_mpls_fib_t *s,
+                                    u32 context)
+{
+    vl_api_mpls_fib_encap_details_t * mp;
+
+    mp = vl_msg_api_alloc (sizeof (*mp));
+    memset (mp, 0, sizeof (*mp));
+    mp->_vl_msg_id = ntohs(VL_API_MPLS_FIB_ENCAP_DETAILS);
+    mp->context = context;
+
+    mp->fib_index   = htonl(s->fib_index);
+    mp->entry_index = htonl(s->entry_index);
+    mp->dest        = s->dest;
+    mp->s_bit       = htonl(s->s_bit);
+
+    mpls_main_t * mm = &mpls_main;
+    mpls_encap_t * e;
+    int i;
+    u32 len = 0;
+
+    e = pool_elt_at_index (mm->encaps, s->entry_index);
+    len = vec_len (e->labels);
+    mp->nlabels = htonl(len);
+
+    for (i = 0; i < len; i++) {
+        mp->labels[i] = htonl(vnet_mpls_uc_get_label(
+                clib_host_to_net_u32(e->labels[i].label_exp_s_ttl)));
+    }
+
+    vl_msg_api_send_shmem (q, (u8 *)&mp);
+}
+
+static void
+vl_api_mpls_fib_encap_dump_t_handler (vl_api_mpls_fib_encap_dump_t *mp)
+{
+    vpe_api_main_t * am = &vpe_api_main;
+    unix_shared_memory_queue_t * q;
+    vlib_main_t * vm = &vlib_global_main;
+    u64 key;
+    u32 value;
+    show_mpls_fib_t *records = 0;
+    show_mpls_fib_t *s;
+    mpls_main_t * mm = &mpls_main;
+    ip4_main_t * im = &ip4_main;
+    ip4_fib_t * rx_fib;
+
+    q = vl_api_client_index_to_input_queue (mp->client_index);
+    if (q == 0)
+        return;
+
+    hash_foreach (key, value, mm->mpls_encap_by_fib_and_dest,
+    ({
+        vec_add2 (records, s, 1);
+        s->fib_index = (u32)(key>>32);
+        s->dest = (u32)(key & 0xFFFFFFFF);
+        s->entry_index = (u32) value;
+    }));
+
+    if (0 == vec_len(records)) {
+        vlib_cli_output(vm, "MPLS encap table empty");
+        goto out;
+    }
+
+    /* sort output by dst address within fib */
+    vec_sort_with_function(records, mpls_dest_cmp);
+    vec_sort_with_function(records, mpls_fib_index_cmp);
+    vlib_cli_output(vm, "MPLS encap table");
+    vlib_cli_output(vm, "%=6s%=16s%=16s", "Table", "Dest address", "Labels");
+    vec_foreach (s, records)
+    {
+        rx_fib = vec_elt_at_index(im->fibs, s->fib_index);
+        vlib_cli_output(vm, "%=6d%=16U%=16U", rx_fib->table_id,
+                format_ip4_address, &s->dest, format_mpls_encap_index, mm,
+                s->entry_index);
+        send_mpls_fib_encap_details (am, q, s, mp->context);
+    }
+
+out:
+    vec_free(records);
+}
+
+static void vl_api_mpls_fib_decap_details_t_handler (
+    vl_api_mpls_fib_decap_details_t * mp)
+{
+    clib_warning ("BUG");
+}
+
+static void send_mpls_fib_decap_details (vpe_api_main_t * am,
+                                    unix_shared_memory_queue_t *q,
+                                    show_mpls_fib_t *s,
+                                    u32 rx_table_id,
+                                    u32 tx_table_id,
+                                    char *swif_tag,
+                                    u32 context)
+{
+    vl_api_mpls_fib_decap_details_t * mp;
+
+    mp = vl_msg_api_alloc (sizeof (*mp));
+    memset (mp, 0, sizeof (*mp));
+    mp->_vl_msg_id = ntohs(VL_API_MPLS_FIB_DECAP_DETAILS);
+    mp->context = context;
+
+    mp->fib_index   = htonl(s->fib_index);
+    mp->entry_index = htonl(s->entry_index);
+    mp->dest        = s->dest;
+    mp->s_bit       = htonl(s->s_bit);
+    mp->label       = htonl(s->label);
+    mp->rx_table_id = htonl(rx_table_id);
+    mp->tx_table_id = htonl(tx_table_id);
+    strncpy ((char *) mp->swif_tag,
+             (char *) swif_tag, ARRAY_LEN(mp->swif_tag)-1);
+
+    vl_msg_api_send_shmem (q, (u8 *)&mp);
+}
+
+static void
+vl_api_mpls_fib_decap_dump_t_handler (vl_api_mpls_fib_decap_dump_t *mp)
+{
+    vpe_api_main_t * am = &vpe_api_main;
+    unix_shared_memory_queue_t * q;
+    vlib_main_t * vm = &vlib_global_main;
+    u64 key;
+    u32 value;
+    show_mpls_fib_t *records = 0;
+    show_mpls_fib_t *s;
+    mpls_main_t * mm = &mpls_main;
+    ip4_main_t * im = &ip4_main;
+    ip4_fib_t * rx_fib;
+    ip4_fib_t *tx_fib;
+    u32 tx_table_id;
+    char *swif_tag;
+
+    q = vl_api_client_index_to_input_queue (mp->client_index);
+    if (q == 0)
+        return;
+
+    hash_foreach (key, value, mm->mpls_decap_by_rx_fib_and_label,
+    ({
+        vec_add2 (records, s, 1);
+        s->fib_index = (u32)(key>>32);
+        s->entry_index = (u32) value;
+        s->label = ((u32) key)>>12;
+        s->s_bit = (key & (1<<8)) != 0;
+    }));
+
+    if (!vec_len(records)) {
+        vlib_cli_output(vm, "MPLS decap table empty");
+        goto out;
+    }
+
+    vec_sort_with_function(records, mpls_label_cmp);
+    vlib_cli_output(vm, "MPLS decap table");
+    vlib_cli_output(vm, "%=10s%=15s%=6s%=6s", "RX Table", "TX Table/Intfc",
+            "Label", "S-bit");
+    vec_foreach (s, records)
+    {
+        mpls_decap_t * d;
+        d = pool_elt_at_index(mm->decaps, s->entry_index);
+        if (d->next_index == MPLS_INPUT_NEXT_IP4_INPUT) {
+            tx_fib = vec_elt_at_index(im->fibs, d->tx_fib_index);
+            tx_table_id = tx_fib->table_id;
+            swif_tag = "     ";
+        } else {
+            tx_table_id = d->tx_fib_index;
+            swif_tag = "(i)  ";
+        }
+        rx_fib = vec_elt_at_index(im->fibs, s->fib_index);
+
+        vlib_cli_output(vm, "%=10d%=10d%=5s%=6d%=6d", rx_fib->table_id,
+                tx_table_id, swif_tag, s->label, s->s_bit);
+
+        send_mpls_fib_decap_details (am, q, s, rx_fib->table_id,
+                tx_table_id, swif_tag, mp->context);
+    }
+
+out:
+    vec_free(records);
+}
+
+static void vl_api_classify_table_ids_t_handler (vl_api_classify_table_ids_t *mp)
+{
+    unix_shared_memory_queue_t * q;
+
+    q = vl_api_client_index_to_input_queue (mp->client_index);
+    if (q == 0)
+        return;
+
+    vnet_classify_main_t * cm = &vnet_classify_main;
+    vnet_classify_table_t * t;
+    u32 * table_ids = 0;
+    u32 count;
+
+    pool_foreach (t, cm->tables,
+    ({
+        vec_add1 (table_ids, ntohl(t - cm->tables));
+    }));
+    count = vec_len(table_ids);
+
+    vl_api_classify_table_ids_reply_t *rmp;
+    rmp = vl_msg_api_alloc_as_if_client(sizeof (*rmp) + count);
+    rmp->_vl_msg_id = ntohs (VL_API_CLASSIFY_TABLE_IDS_REPLY);
+    rmp->context = mp->context;
+    rmp->count = ntohl(count);
+    clib_memcpy(rmp->ids, table_ids, count * sizeof(u32));
+    rmp->retval = 0;
+
+    vl_msg_api_send_shmem (q, (u8 *)&rmp);
+
+    vec_free (table_ids);
+}
+
+static void vl_api_classify_table_by_interface_t_handler (vl_api_classify_table_by_interface_t *mp)
+{
+    vl_api_classify_table_by_interface_reply_t *rmp;
+    int rv = 0;
+
+    u32 sw_if_index = ntohl(mp->sw_if_index);
+    u32 * acl = 0;
+
+    vec_validate (acl, INPUT_ACL_N_TABLES - 1);
+    vec_set (acl, ~0);
+
+    VALIDATE_SW_IF_INDEX(mp);
+
+    input_acl_main_t * am = &input_acl_main;
+
+    int if_idx;
+    u32 type;
+
+    for (type = 0; type < INPUT_ACL_N_TABLES; type++)
+    {
+       u32 * vec_tbl = am->classify_table_index_by_sw_if_index[type];
+               if (vec_len(vec_tbl)) {
+                       for (if_idx = 0; if_idx < vec_len (vec_tbl); if_idx++)
+                       {
+                           if (vec_elt(vec_tbl, if_idx) == ~0 || sw_if_index != if_idx) {
+                                   continue;
+                           }
+                           acl[type] = vec_elt(vec_tbl, if_idx);
+                       }
+               }
+    }
+
+    BAD_SW_IF_INDEX_LABEL;
+
+    REPLY_MACRO2(VL_API_CLASSIFY_TABLE_BY_INTERFACE_REPLY,
+    ({
+       rmp->sw_if_index = ntohl(sw_if_index);
+       rmp->l2_table_id = ntohl(acl[INPUT_ACL_TABLE_L2]);
+       rmp->ip4_table_id = ntohl(acl[INPUT_ACL_TABLE_IP4]);
+       rmp->ip6_table_id = ntohl(acl[INPUT_ACL_TABLE_IP6]);
+    }));
+    vec_free(acl);
+}
+
+static void vl_api_classify_table_info_t_handler (vl_api_classify_table_info_t *mp)
+{
+    unix_shared_memory_queue_t * q;
+
+    q = vl_api_client_index_to_input_queue (mp->client_index);
+    if (q == 0)
+        return;
+
+    vl_api_classify_table_info_reply_t *rmp = 0;
+
+    vnet_classify_main_t * cm = &vnet_classify_main;
+    u32 table_id = ntohl(mp->table_id);
+    vnet_classify_table_t * t;
+
+    pool_foreach (t, cm->tables,
+    ({
+        if (table_id == t - cm->tables) {
+            rmp = vl_msg_api_alloc_as_if_client(sizeof (*rmp) + t->match_n_vectors * sizeof (u32x4));
+            rmp->_vl_msg_id = ntohs (VL_API_CLASSIFY_TABLE_INFO_REPLY);
+            rmp->context = mp->context;
+            rmp->table_id = ntohl(table_id);
+            rmp->nbuckets = ntohl(t->nbuckets);
+            rmp->match_n_vectors = ntohl(t->match_n_vectors);
+            rmp->skip_n_vectors = ntohl(t->skip_n_vectors);
+            rmp->active_sessions = ntohl(t->active_elements);
+            rmp->next_table_index = ntohl(t->next_table_index);
+            rmp->miss_next_index = ntohl(t->miss_next_index);
+            rmp->mask_length = ntohl(t->match_n_vectors * sizeof (u32x4));
+            clib_memcpy(rmp->mask, t->mask, t->match_n_vectors * sizeof(u32x4));
+            rmp->retval = 0;
+            break;
+        }
+    }));
+
+    if (rmp == 0) {
+        rmp = vl_msg_api_alloc (sizeof (*rmp));
+        rmp->_vl_msg_id = ntohs((VL_API_CLASSIFY_TABLE_INFO_REPLY));
+        rmp->context = mp->context;
+        rmp->retval = ntohl(VNET_API_ERROR_CLASSIFY_TABLE_NOT_FOUND);
+    }
+
+    vl_msg_api_send_shmem (q, (u8 *)&rmp);
+}
+
+static void vl_api_classify_session_details_t_handler (vl_api_classify_session_details_t * mp)
+{
+    clib_warning ("BUG");
+}
+
+static void send_classify_session_details (unix_shared_memory_queue_t * q,
+                                           u32 table_id,
+                                           u32 match_length,
+                                           vnet_classify_entry_t * e,
+                                           u32 context)
+{
+    vl_api_classify_session_details_t *rmp;
+
+    rmp = vl_msg_api_alloc (sizeof (*rmp));
+    memset (rmp, 0, sizeof (*rmp));
+    rmp->_vl_msg_id = ntohs(VL_API_CLASSIFY_SESSION_DETAILS);
+    rmp->context = context;
+    rmp->table_id = ntohl(table_id);
+    rmp->hit_next_index = ntohl(e->next_index);
+    rmp->advance = ntohl(e->advance);
+    rmp->opaque_index = ntohl(e->opaque_index);
+    rmp->match_length = ntohl(match_length);
+    clib_memcpy(rmp->match, e->key, match_length);
+
+    vl_msg_api_send_shmem (q, (u8 *)&rmp);
+}
+
+static void vl_api_classify_session_dump_t_handler (vl_api_classify_session_dump_t *mp)
+{
+    vnet_classify_main_t * cm = &vnet_classify_main;
+    unix_shared_memory_queue_t * q;
+
+    u32 table_id = ntohl(mp->table_id);
+    vnet_classify_table_t * t;
+
+    q = vl_api_client_index_to_input_queue (mp->client_index);
+
+    pool_foreach (t, cm->tables,
+    ({
+        if (table_id == t - cm->tables) {
+            vnet_classify_bucket_t * b;
+            vnet_classify_entry_t * v, * save_v;
+            int i, j, k;
+
+            for (i = 0; i < t->nbuckets; i++)
+            {
+                b = &t->buckets [i];
+                if (b->offset == 0)
+                   continue;
+
+                save_v = vnet_classify_get_entry (t, b->offset);
+                for (j = 0; j < (1<<b->log2_pages); j++)
+                {
+                       for (k = 0; k < t->entries_per_page; k++)
+                       {
+                           v = vnet_classify_entry_at_index (t, save_v, j*t->entries_per_page + k);
+                           if (vnet_classify_entry_is_free (v))
+                               continue;
+
+                               send_classify_session_details(q, table_id,
+                                               t->match_n_vectors * sizeof (u32x4), v, mp->context);
+                       }
+                }
+            }
+            break;
+        }
+    }));
+}
+
 #define BOUNCE_HANDLER(nn)                                              \
 static void vl_api_##nn##_t_handler (                                   \
     vl_api_##nn##_t *mp)                                                \