Metadata / opaque formatting belongs in vpp 30/16230/3
authorDave Barach <dave@barachs.net>
Tue, 27 Nov 2018 21:52:59 +0000 (16:52 -0500)
committerFlorin Coras <florin.coras@gmail.com>
Fri, 30 Nov 2018 20:18:54 +0000 (20:18 +0000)
VPP graph dispatch trace record description:

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   | Major Version | Minor Version | NStrings      | ProtoHint     |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   | Buffer index (big endian)                                     |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   + VPP graph node name ...     ...               | NULL octet    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   | Buffer Metadata ... ...                       | NULL octet    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   | Buffer Opaque ... ...                         | NULL octet    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   | Buffer Opaque 2 ... ...                       | NULL octet    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   | VPP ASCII packet trace (if NStrings > 4)      | NULL octet    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   | Packet data (up to 16K)                                       |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Graph dispatch records comprise a version stamp, an indication of how
many NULL-terminated strings will follow the record header, and a
protocol hint.

The buffer index allows downstream consumers of these data to easily
filter/track single packets as they traverse the forwarding
graph. FWIW, the 32-bit buffer index is stored in big endian format.

As of this writing, major version = 1, minor version = 0. Nstrings
will be either 4 or 5.

Here is the current set of protocol hints:

typedef enum
  {
    VLIB_NODE_PROTO_HINT_NONE = 0,
    VLIB_NODE_PROTO_HINT_ETHERNET,
    VLIB_NODE_PROTO_HINT_IP4,
    VLIB_NODE_PROTO_HINT_IP6,
    VLIB_NODE_PROTO_HINT_TCP,
    VLIB_NODE_PROTO_HINT_UDP,
    VLIB_NODE_N_PROTO_HINTS,
  } vlib_node_proto_hint_t;

Example: VLIB_NODE_PROTO_HINT_IP6 means that the first octet of packet
data SHOULD be 0x60, and should begin an ipv6 packet header.

Change-Id: Idf310bad80cc0e4207394c80f18db5f77c378741
Signed-off-by: Dave Barach <dave@barachs.net>
extras/wireshark/packet-vpp.c
src/vlib/main.c
src/vlib/main.h
src/vlib/node.c
src/vlib/node.h
src/vnet/buffer.c
src/vnet/buffer.h
src/vnet/interface_format.c
src/vnet/ip/ip4_input.c
src/vnet/tcp/tcp_output.c

index fc568da..5094f5d 100644 (file)
@@ -35,103 +35,49 @@ void proto_register_vpp(void);
 void proto_reg_handoff_vpp(void);
 
 static int proto_vpp = -1;
+static int proto_vpp_metadata = -1;
 static int proto_vpp_opaque = -1;
+static int proto_vpp_opaque2 = -1;
 static int proto_vpp_trace = -1;
 static int hf_vpp_nodename = -1;
+static int hf_vpp_metadata = -1;
 static int hf_vpp_buffer_index = -1;
-
-static int hf_vpp_buffer_current_data = -1;
-static int hf_vpp_buffer_current_length = -1;
-
-static int hf_vpp_buffer_flags = -1;
-static int hf_vpp_buffer_flag_non_default_freelist = -1;
-static int hf_vpp_buffer_flag_traced = -1;
-static int hf_vpp_buffer_flag_next_present = -1;
-static int hf_vpp_buffer_flag_total_length_valid = -1;
-static int hf_vpp_buffer_flag_ext_hdr_valid = -1;       
-static int hf_vpp_buffer_flag_l4_checksum_computed = -1;
-static int hf_vpp_buffer_flag_l4_checksum_correct = -1;
-static int hf_vpp_buffer_flag_vlan_2_deep = -1;
-static int hf_vpp_buffer_flag_vlan_1_deep = -1;
-static int hf_vpp_buffer_flag_span_clone = -1;
-static int hf_vpp_buffer_flag_loop_counter_valid = -1;
-static int hf_vpp_buffer_flag_locally_originated = -1;
-static int hf_vpp_buffer_flag_is_ip4 = -1;
-static int hf_vpp_buffer_flag_is_ip6 = -1;
-static int hf_vpp_buffer_flag_offload_ip_checksum = -1;
-static int hf_vpp_buffer_flag_offload_tcp_checksum = -1;
-static int hf_vpp_buffer_flag_offload_udp_checksum = -1;
-static int hf_vpp_buffer_flag_is_natted = -1;
-static int hf_vpp_buffer_flag_l2_hdr_offset_valid = -1;
-static int hf_vpp_buffer_flag_l3_hdr_offset_valid = -1;
-static int hf_vpp_buffer_flag_l4_hdr_offset_valid = -1;
-static int hf_vpp_buffer_flag_flow_report = -1;
-static int hf_vpp_buffer_flag_is_dvr = -1;
-static int hf_vpp_buffer_flag_qos_data_valid = -1;
-static int hf_vpp_buffer_flow_id = -1;
-static int hf_vpp_buffer_next_buffer = -1;
-static int hf_vpp_buffer_current_config_index = -1;
-static int hf_vpp_buffer_error_index = -1;
-static int hf_vpp_buffer_n_add_refs = -1;
-static int hf_vpp_buffer_buffer_pool_index = -1;
-
-static int hf_vpp_buffer_opaque_raw = -1;
-static int hf_vpp_buffer_opaque_opaque = -1;
-
+static int hf_vpp_buffer_opaque = -1;
+static int hf_vpp_buffer_opaque2 = -1;
 static int hf_vpp_buffer_trace = -1;
 
 static gint ett_vpp = -1;
 static gint ett_vpp_opaque = -1;
+static gint ett_vpp_opaque2 = -1;
+static gint ett_vpp_metadata = -1;
 static gint ett_vpp_trace = -1;
 
 static dissector_handle_t vpp_dissector_handle;
 static dissector_handle_t vpp_opaque_dissector_handle;
+static dissector_handle_t vpp_opaque2_dissector_handle;
+static dissector_handle_t vpp_metadata_dissector_handle;
 static dissector_handle_t vpp_trace_dissector_handle;
 
-static dissector_table_t vpp_subdissector_table;
+typedef enum
+  {
+    VLIB_NODE_PROTO_HINT_NONE = 0,
+    VLIB_NODE_PROTO_HINT_ETHERNET,
+    VLIB_NODE_PROTO_HINT_IP4,
+    VLIB_NODE_PROTO_HINT_IP6,
+    VLIB_NODE_PROTO_HINT_TCP,
+    VLIB_NODE_PROTO_HINT_UDP,
+    VLIB_NODE_N_PROTO_HINTS,
+  } vlib_node_proto_hint_t;
 
-/* List of next dissector names that we know about */
-#define foreach_next_dissector                  \
-_(eth_maybefcs)                                 \
-_(ip)                                           \
-_(ipv6)                                         \
-_(tcp)
+static dissector_handle_t next_dissectors[VLIB_NODE_N_PROTO_HINTS];
 
-#define _(a) static dissector_handle_t a##_dissector_handle;
-foreach_next_dissector;
-#undef _
-
-/* 
- * node-name, next dissector name pairs
- * 
- * Unfortunately, -Werror=c++-compat causes
- * the node names "ipX-not-enabled" to throw a shoe if
- * not explicitly quoted. Never mind that the first macro 
- * arg is [only] used as a string (#xxx). 
- */
-
-/* 
- * Note: in addition to these direct mappings, we 
- * send traces w/ b->data[b->current_data] = 0x45 to
- * the ip dissector, and 0x60 to the ipv6 dissector.
- *
- * It pays to add direct mappings for common places which
- * may receive broken packets during development. ip4-lookup and
- * ip6-lookup are obvious places where people send
- * hand-crafted packets which may turn out to be broken.
- */
-#define foreach_node_to_dissector_pair          \
-_("ethernet-input", eth_maybefcs)               \
-_("ip4-glean", ip)                              \
-_("ip4-icmp-error", ip)                         \
-_("ip4-input", ip)                              \
-_("ip4-input-no-checksum", ip)                  \
-_("ip4-local", ip)                              \
-_("ip4-lookup", ip)                             \
-_("ip4-udp-lookup", ip)                         \
-_("ip6-lookup", ipv6)                           \
-_("tcp4-output", tcp)                           \
-_("tcp6-output", tcp)
+/* List of next dissectors hints that we know about */
+#define foreach_next_dissector                  \
+_(VLIB_NODE_PROTO_HINT_ETHERNET, eth_maybefcs)  \
+_(VLIB_NODE_PROTO_HINT_IP4, ip)                 \
+_(VLIB_NODE_PROTO_HINT_IP6, ipv6)               \
+_(VLIB_NODE_PROTO_HINT_TCP, tcp)                \
+_(VLIB_NODE_PROTO_HINT_UDP, udp)
 
 static void
 add_multi_line_string_to_tree(proto_tree *tree, tvbuff_t *tvb, gint start,
@@ -151,6 +97,30 @@ add_multi_line_string_to_tree(proto_tree *tree, tvbuff_t *tvb, gint start,
     }
 }
 
+static int
+dissect_vpp_metadata (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, 
+                    void* data _U_)
+{
+    int         offset   = 0;
+    proto_item *ti;
+    proto_tree *metadata_tree;
+    gint metadata_string_length;
+    
+    col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP-Metadata");
+    col_clear(pinfo->cinfo, COL_INFO);
+
+    ti = proto_tree_add_item(tree, proto_vpp_metadata, tvb, offset, -1, ENC_NA);
+    metadata_tree = proto_item_add_subtree(ti, ett_vpp_metadata);
+
+    /* How long is the metadata string? */
+    metadata_string_length = tvb_strsize (tvb, offset);
+    
+    add_multi_line_string_to_tree (metadata_tree, tvb, 0,
+                                   metadata_string_length, 
+                                   hf_vpp_metadata);
+    return tvb_captured_length(tvb);
+}
+
 static int
 dissect_vpp_trace (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, 
                     void* data _U_)
@@ -167,8 +137,7 @@ dissect_vpp_trace (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
     trace_tree = proto_item_add_subtree(ti, ett_vpp_trace);
 
     /* How long is the trace string? */
-    (void ) tvb_get_stringz_enc (wmem_packet_scope(), tvb, 0,
-                                 &trace_string_length, ENC_ASCII);
+    trace_string_length = tvb_strsize (tvb, offset);
     
     add_multi_line_string_to_tree (trace_tree, tvb, 0,
                                    trace_string_length, 
@@ -176,248 +145,6 @@ dissect_vpp_trace (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
     return tvb_captured_length(tvb);
 }
 
-/*
- * BIG FAT WARNING: it's impossible to #include the vpp header files,
- * so this is a private copy of .../src/vnet/buffer.h, with
- * some vpp typedefs thrown in for good measure.
- */
-
-typedef unsigned int u32;
-typedef unsigned short int u16;
-typedef short int i16;
-typedef unsigned char u8;
-typedef unsigned long long u64;
-
-typedef struct 
-{
-    u32 sw_if_index[2];
-    i16 l2_hdr_offset;
-    i16 l3_hdr_offset;
-    i16 l4_hdr_offset;
-    u8 feature_arc_index;
-    u8 dont_waste_me;
-
-    union
-    {
-        /* IP4/6 buffer opaque. */
-        struct
-        {
-            /* Adjacency from destination IP address lookup [VLIB_TX].
-               Adjacency from source IP address lookup [VLIB_RX].
-               This gets set to ~0 until source lookup is performed. */
-            u32 adj_index[2];
-
-            union
-            {
-                struct
-                {
-                    /* Flow hash value for this packet computed from IP src/dst address
-                       protocol and ports. */
-                    u32 flow_hash;
-
-                    union
-                    {
-                        /* next protocol */
-                        u32 save_protocol;
-
-                        /* Hint for transport protocols */
-                        u32 fib_index;
-                    };
-
-                    /* Rewrite length */
-                    u32 save_rewrite_length;
-
-                    /* MFIB RPF ID */
-                    u32 rpf_id;
-                };
-
-                /* ICMP */
-                struct
-                {
-                    u8 type;
-                    u8 code;
-                    u32 data;
-                } icmp;
-
-                /* reassembly */
-                union
-                {
-                    /* in/out variables */
-                    struct
-                    {
-                        u32 next_index;        /* index of next node - ignored if "feature" node */
-                        u16 estimated_mtu;     /* estimated MTU calculated during reassembly */
-                    };
-                    /* internal variables used during reassembly */
-                    struct
-                    {
-                        u16 fragment_first;
-                        u16 fragment_last;
-                        u16 range_first;
-                        u16 range_last;
-                        u32 next_range_bi;
-                        u16 ip6_frag_hdr_offset;
-                    };
-                } reass;
-            };
-
-        } ip;
-
-        /*
-         * MPLS:
-         * data copied from the MPLS header that was popped from the packet
-         * during the look-up.
-         */
-        struct
-        {
-            /* do not overlay w/ ip.adj_index[0,1] nor flow hash */
-            u32 pad[3];
-            u8 ttl;
-            u8 exp;
-            u8 first;
-            /* Rewrite length */
-            u32 save_rewrite_length;
-            /*
-             * BIER - the number of bytes in the header.
-             *  the len field in the header is not authoritative. It's the
-             * value in the table that counts.
-             */
-            struct
-            {
-                u8 n_bytes;
-            } bier;
-        } mpls;
-
-        /* l2 bridging path, only valid there */
-        struct opaque_l2
-        {
-            u32 feature_bitmap;
-            u16 bd_index;              /* bridge-domain index */
-            u8 l2_len;         /* ethernet header length */
-            u8 shg;                    /* split-horizon group */
-            u16 l2fib_sn;              /* l2fib bd/int seq_num */
-            u8 bd_age;         /* aging enabled */
-        } l2;
-
-        /* l2tpv3 softwire encap, only valid there */
-        struct
-        {
-            u32 pad[4];                /* do not overlay w/ ip.adj_index[0,1] */
-            u8 next_index;
-            u32 session_index;
-        } l2t;
-
-        /* L2 classify */
-        struct
-        {
-            struct opaque_l2 pad;
-            union
-            {
-                u32 table_index;
-                u32 opaque_index;
-            };
-            u64 hash;
-        } l2_classify;
-
-        /* vnet policer */
-        struct
-        {
-            u32 pad[8 - 2 - 1];        /* to end of opaque */
-            u32 index;
-        } policer;
-
-        /* interface output features */
-        struct
-        {
-            u32 flags;
-            u32 sad_index;
-        } ipsec;
-
-        /* MAP */
-        struct
-        {
-            u16 mtu;
-        } map;
-
-        /* MAP-T */
-        struct
-        {
-            u32 map_domain_index;
-            struct
-            {
-                u32 saddr, daddr;
-                u16 frag_offset;       //Fragmentation header offset
-                u16 l4_offset;         //L4 header overall offset
-                u8 l4_protocol;                //The final protocol number
-            } v6;                      //Used by ip6_map_t only
-            u16 checksum_offset;       //L4 checksum overall offset
-            u16 mtu;                   //Exit MTU
-        } map_t;
-
-        /* IP Fragmentation */
-        struct
-        {
-            u32 pad[2];                /* do not overlay w/ ip.adj_index[0,1] */
-            u16 mtu;
-            u8 next_index;
-            u8 flags;                  //See ip_frag.h
-        } ip_frag;
-
-        /* COP - configurable junk filter(s) */
-        struct
-        {
-            /* Current configuration index. */
-            u32 current_config_index;
-        } cop;
-
-        /* LISP */
-        struct
-        {
-            /* overlay address family */
-            u16 overlay_afi;
-        } lisp;
-
-        /* TCP */
-        struct
-        {
-            u32 connection_index;
-            u32 seq_number;
-            u32 seq_end;
-            u32 ack_number;
-            u16 hdr_offset;            /**< offset relative to ip hdr */
-            u16 data_offset;           /**< offset relative to ip hdr */
-            u16 data_len;              /**< data len */
-            u8 flags;
-        } tcp;
-
-        /* SCTP */
-        struct
-        {
-            u32 connection_index;
-            u16 sid; /**< Stream ID */
-            u16 ssn; /**< Stream Sequence Number */
-            u32 tsn; /**< Transmission Sequence Number */
-            u16 hdr_offset;            /**< offset relative to ip hdr */
-            u16 data_offset;           /**< offset relative to ip hdr */
-            u16 data_len;              /**< data len */
-            u8 subconn_idx; /**< index of the sub_connection being used */
-            u8 flags;
-        } sctp;
-
-        /* SNAT */
-        struct
-        {
-            u32 flags;
-        } snat;
-
-        u32 unused[6];
-    };
-} vnet_buffer_opaque_t;
-
-
-#define PTAS proto_tree_add_string(opaque_tree,                         \
-                                   hf_vpp_buffer_opaque_opaque,         \
-                                   tvb, 0, strlen(tmpbuf), tmpbuf)
 
 static int
 dissect_vpp_opaque (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, 
@@ -426,12 +153,7 @@ dissect_vpp_opaque (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
     int         offset   = 0;
     proto_item *ti;
     proto_tree *opaque_tree;
-    char tmpbuf [512];
-    int print_offset;
-    guint32 opaque[10];
-    vnet_buffer_opaque_t _o, *o = &_o;
-
-    int i;
+    gint opaque_string_length;
 
     col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP-Opaque");
     col_clear(pinfo->cinfo, COL_INFO);
@@ -439,191 +161,31 @@ dissect_vpp_opaque (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
     ti = proto_tree_add_item(tree, proto_vpp_opaque, tvb, offset, -1, ENC_NA);
     opaque_tree = proto_item_add_subtree(ti, ett_vpp_opaque);
 
-    print_offset = 0;
-    for (i = 0; i < 10; i++) {
-        opaque[i] = tvb_get_guint32 (tvb, offset + 4*i, ENC_LITTLE_ENDIAN);
-        snprintf (tmpbuf + print_offset, sizeof(tmpbuf) - print_offset, 
-                  "%08x ", opaque[i]);
-        print_offset = strlen (tmpbuf);
-    }
-    offset += 40;
-
-    proto_tree_add_string (opaque_tree, hf_vpp_buffer_opaque_raw, tvb, 0,
-                           strlen(tmpbuf), tmpbuf);
-
-    memset (o, 0, sizeof (*o));
-    memcpy (o, opaque, sizeof (opaque));
-    snprintf (tmpbuf, sizeof(tmpbuf), 
-              "sw_if_index[VLIB_RX]: %d, sw_if_index[VLIB_TX]: %d",
-              o->sw_if_index[0], o->sw_if_index[1]);
-    PTAS;
-
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "L2 offset %d, L3 offset %d, L4 offset %d, feature arc index %d",
-              (u32)(o->l2_hdr_offset),
-              (u32)(o->l3_hdr_offset),
-              (u32)(o->l4_hdr_offset), 
-              (u32)(o->feature_arc_index));
-    PTAS;
+    opaque_string_length = tvb_strsize (tvb, offset); 
+    add_multi_line_string_to_tree (opaque_tree, tvb, 0, opaque_string_length, 
+                                   hf_vpp_buffer_opaque);
 
-    snprintf (tmpbuf, sizeof(tmpbuf), 
-              "ip.adj_index[VLIB_RX]: %d, ip.adj_index[VLIB_TX]: %d",
-              (u32)(o->ip.adj_index[0]),
-              (u32)(o->ip.adj_index[1]));
-    PTAS;
-
-    snprintf (tmpbuf, sizeof(tmpbuf), 
-              "ip.flow_hash: 0x%x, ip.save_protocol: 0x%x, ip.fib_index: %d",
-              o->ip.flow_hash, o->ip.save_protocol, o->ip.fib_index);
-    PTAS;
-
-    snprintf (tmpbuf, sizeof(tmpbuf), 
-              "ip.save_rewrite_length: %d, ip.rpf_id: %d",
-              o->ip.save_rewrite_length, o->ip.rpf_id);
-    PTAS;
-
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "ip.icmp.type: %d ip.icmp.code: %d, ip.icmp.data: 0x%x",
-              (u32)(o->ip.icmp.type),
-              (u32)(o->ip.icmp.code),
-              o->ip.icmp.data);
-    PTAS;
-
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "ip.reass.next_index: %d, ip.reass.estimated_mtu: %d",
-              o->ip.reass.next_index, (u32)(o->ip.reass.estimated_mtu));
-    PTAS;
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "ip.reass.fragment_first: %d ip.reass.fragment_last: %d",
-              (u32)(o->ip.reass.fragment_first),
-              (u32)(o->ip.reass.fragment_last));
-    PTAS;
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "ip.reass.range_first: %d ip.reass.range_last: %d",
-              (u32)(o->ip.reass.range_first),
-              (u32)(o->ip.reass.range_last));
-    PTAS;
-
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "ip.reass.next_range_bi: 0x%x, ip.reass.ip6_frag_hdr_offset: %d",
-              o->ip.reass.next_range_bi, 
-              (u32)(o->ip.reass.ip6_frag_hdr_offset));
-    PTAS;
-
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "mpls.ttl: %d, mpls.exp: %d, mpls.first: %d, "
-              "mpls.save_rewrite_length: %d, mpls.bier.n_bytes: %d",
-              (u32)(o->mpls.ttl), (u32)(o->mpls.exp), (u32)(o->mpls.first),
-              o->mpls.save_rewrite_length, (u32)(o->mpls.bier.n_bytes));
-    PTAS;
-
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "l2.feature_bitmap: %08x, l2.bd_index: %d, l2.l2_len: %d, "
-              "l2.shg: %d, l2.l2fib_sn: %d, l2.bd_age: %d",
-              o->l2.feature_bitmap, (u32)(o->l2.bd_index),
-              (u32)(o->l2.l2_len), (u32)(o->l2.shg), (u32)(o->l2.l2fib_sn),
-              (u32)(o->l2.bd_age));
-    PTAS;
-        
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "l2t.next_index: %d, l2t.session_index: %d",
-              (u32)(o->l2t.next_index), o->l2t.session_index);
-    PTAS;
-
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "l2_classify.table_index: %d, l2_classify.opaque_index: %d, "
-              "l2_classify.hash: 0x%llx",
-              o->l2_classify.table_index,
-              o->l2_classify.opaque_index,
-              o->l2_classify.hash);
-    PTAS;
-
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "policer.index: %d", o->policer.index);
-    PTAS;
-
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "ipsec.flags: 0x%x, ipsec.sad_index: %d",
-              o->ipsec.flags, o->ipsec.sad_index);
-    PTAS;
-
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "map.mtu: %d", (u32)(o->map.mtu));
-    PTAS;
-
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "map_t.v6.saddr: 0x%x, map_t.v6.daddr: 0x%x, "
-              "map_t.v6.frag_offset: %d, map_t.v6.l4_offset: %d",
-              o->map_t.v6.saddr,
-              o->map_t.v6.daddr,
-              (u32)(o->map_t.v6.frag_offset),
-              (u32)(o->map_t.v6.l4_offset));
-    PTAS;
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "map_t.v6.l4_protocol: %d, map_t.checksum_offset: %d, "
-              "map_t.mtu: %d",
-              (u32)(o->map_t.v6.l4_protocol),
-              (u32)(o->map_t.checksum_offset),
-              (u32)(o->map_t.mtu));
-    PTAS;
-    
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "ip_frag.mtu: %d, ip_frag.next_index: %d, ip_frag.flags: 0x%x",
-              (u32)(o->ip_frag.mtu),
-              (u32)(o->ip_frag.next_index),
-              (u32)(o->ip_frag.flags));
-    PTAS;
+    return tvb_captured_length(tvb);
+}
 
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "cop.current_config_index: %d",
-              o->cop.current_config_index);
-    PTAS;
-    
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "lisp.overlay_afi: %d",
-              (u32)(o->lisp.overlay_afi));
-    PTAS;
+static int
+dissect_vpp_opaque2 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, 
+                    void* data _U_)
+{
+    int         offset   = 0;
+    proto_item *ti;
+    proto_tree *opaque2_tree;
+    gint opaque2_string_length;
 
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "tcp.connection_index: %d, tcp.seq_number: %d, tcp.seq_end: %d, "
-              "tcp.ack_number: %d, tcp.hdr_offset: %d, tcp.data_offset: %d",
-              o->tcp.connection_index,
-              o->tcp.seq_number,
-              o->tcp.seq_end,
-              o->tcp.ack_number,
-              (u32)(o->tcp.hdr_offset),
-              (u32)(o->tcp.data_offset));
-    PTAS;
+    col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP-Opaque2");
+    col_clear(pinfo->cinfo, COL_INFO);
 
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "tcp.data_len: %d, tcp.flags: 0x%x",
-              (u32)(o->tcp.data_len),
-              (u32)(o->tcp.flags));
-    PTAS;
+    ti = proto_tree_add_item(tree, proto_vpp_opaque2, tvb, offset, -1, ENC_NA);
+    opaque2_tree = proto_item_add_subtree(ti, ett_vpp_opaque2);
 
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "sctp.connection_index: %d, sctp.sid: %d, sctp.ssn: %d, "
-              "sctp.tsn: %d, sctp.hdr_offset: %d",
-              o->sctp.connection_index,
-              (u32)(o->sctp.sid),
-              (u32)(o->sctp.ssn),
-              (u32)(o->sctp.tsn),
-              (u32)(o->sctp.hdr_offset));
-    PTAS;
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "sctp.data_offset: %d, sctp.data_len: %d, sctp.subconn_idx: %d, "
-              "sctp.flags: 0x%x",
-              (u32)(o->sctp.data_offset),
-              (u32)(o->sctp.data_len),
-              (u32)(o->sctp.subconn_idx),
-              (u32)(o->sctp.flags));
-    PTAS;
-              
-    snprintf (tmpbuf, sizeof(tmpbuf),
-              "snat.flags: 0x%x",
-              o->snat.flags);
-    PTAS;
+    opaque2_string_length = tvb_strsize (tvb, offset); 
+    add_multi_line_string_to_tree (opaque2_tree, tvb, 0, opaque2_string_length, 
+                                   hf_vpp_buffer_opaque2);
 
     return tvb_captured_length(tvb);
 }
@@ -634,40 +196,13 @@ dissect_vpp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
 {
     proto_item *ti;
     proto_tree *vpp_tree;
-    tvbuff_t *opaque_tvb, *eth_tvb, *trace_tvb;
+    tvbuff_t *metadata_tvb, *opaque_tvb, *opaque2_tvb, *eth_tvb, *trace_tvb;
     int         offset   = 0;
-    guint8 major_version, minor_version;
-    guint8 name_length;
+    guint8 major_version, minor_version, string_count, protocol_hint;
     guint8 *name;
-    guint16 trace_length;
-    int i;
-    static const int *buffer_flags[] = {
-        &hf_vpp_buffer_flag_non_default_freelist,
-        &hf_vpp_buffer_flag_traced,
-        &hf_vpp_buffer_flag_next_present,
-        &hf_vpp_buffer_flag_total_length_valid,
-        &hf_vpp_buffer_flag_ext_hdr_valid,
-        &hf_vpp_buffer_flag_l4_checksum_computed,
-        &hf_vpp_buffer_flag_l4_checksum_correct,
-        &hf_vpp_buffer_flag_vlan_2_deep,
-        &hf_vpp_buffer_flag_vlan_1_deep,
-        &hf_vpp_buffer_flag_span_clone,
-        &hf_vpp_buffer_flag_loop_counter_valid,
-        &hf_vpp_buffer_flag_locally_originated,
-        &hf_vpp_buffer_flag_is_ip4,
-        &hf_vpp_buffer_flag_is_ip6,
-        &hf_vpp_buffer_flag_offload_ip_checksum,
-        &hf_vpp_buffer_flag_offload_tcp_checksum,
-        &hf_vpp_buffer_flag_offload_udp_checksum,
-        &hf_vpp_buffer_flag_is_natted,
-        &hf_vpp_buffer_flag_l2_hdr_offset_valid,
-        &hf_vpp_buffer_flag_l3_hdr_offset_valid,
-        &hf_vpp_buffer_flag_l4_hdr_offset_valid,
-        &hf_vpp_buffer_flag_flow_report,
-        &hf_vpp_buffer_flag_is_dvr,
-        &hf_vpp_buffer_flag_qos_data_valid,
-        NULL
-    };
+    guint len;
+    guint8 maybe_protocol_id; 
+    dissector_handle_t use_this_dissector;
 
     col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP");
     col_clear(pinfo->cinfo, COL_INFO);
@@ -685,77 +220,55 @@ dissect_vpp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
         ws_debug_printf ("WARNING: version mismatch (%d, %d)",
                          major_version, minor_version);
 
-    /* Skip the buffer index */
-    offset += 4;
-
-    /* Recover the node name */
-    name_length = tvb_get_guint8 (tvb, offset);
+    /* Number of counted strings in this trace record */
+    string_count = tvb_get_guint8 (tvb, offset);
     offset++;
 
-    name = (guint8 *) g_malloc (name_length + 1);
-    for (i = 0; i < name_length; i++, offset++) {
-        name[i] = tvb_get_guint8 (tvb, offset);
-    }
-    name[i] = 0;
+    /* 
+     * Hint: protocol which should be at b->data[b->current_data]
+     * It will be a while before vpp sends useful hints for every
+     * possible node, see heuristic below
+     */
+    protocol_hint = tvb_get_guint8 (tvb, offset);
     offset++;
 
-    proto_tree_add_string(vpp_tree, hf_vpp_nodename, tvb, 5, name_length,
-                          name);
+    /* Buffer Index */
     proto_tree_add_item(vpp_tree, hf_vpp_buffer_index, tvb,
-                        0 /* bi at offset 0 */, 4, ENC_LITTLE_ENDIAN);
-
-    proto_tree_add_item(vpp_tree, hf_vpp_buffer_current_data, tvb,
-                        offset, 2, ENC_LITTLE_ENDIAN);
-    offset += 2;
-    proto_tree_add_item(vpp_tree, hf_vpp_buffer_current_length, tvb,
-                        offset, 2, ENC_LITTLE_ENDIAN);
-    offset += 2;
-
-    proto_tree_add_bitmask(vpp_tree, tvb, offset,
-                           hf_vpp_buffer_flags, ett_vpp,
-                           buffer_flags, ENC_LITTLE_ENDIAN);
+                        offset, 4, ENC_BIG_ENDIAN);
     offset += 4;
 
-    proto_tree_add_item(vpp_tree, hf_vpp_buffer_flow_id, tvb,
-                        offset, 4, ENC_LITTLE_ENDIAN);
-    offset += 4;
-
-    proto_tree_add_item(vpp_tree, hf_vpp_buffer_next_buffer, tvb,
-                        offset, 4, ENC_LITTLE_ENDIAN);
-    offset += 4;
-
-    proto_tree_add_item(vpp_tree, hf_vpp_buffer_current_config_index, tvb,
-                        offset, 4, ENC_LITTLE_ENDIAN);
-    offset += 4;
-
-    proto_tree_add_item(vpp_tree, hf_vpp_buffer_error_index, tvb,
-                        offset, 2, ENC_LITTLE_ENDIAN);
-    offset += 2;
-
-    proto_tree_add_item(vpp_tree, hf_vpp_buffer_n_add_refs, tvb,
-                        offset, 1, ENC_LITTLE_ENDIAN);
-    offset += 1;
-
-    proto_tree_add_item(vpp_tree, hf_vpp_buffer_buffer_pool_index, tvb,
-                        offset, 1, ENC_LITTLE_ENDIAN);
-    offset += 1;
-    
+    /* Nodename */
+    len = tvb_strsize (tvb, offset); 
+    name = tvb_get_string_enc (wmem_packet_scope(), tvb, offset, len,
+                               ENC_ASCII);
+    proto_tree_add_string (tree, hf_vpp_nodename, tvb, offset, len, name);
+    offset += len;
+
+    /* Metadata */
+    len = tvb_strsize (tvb, offset);
+    metadata_tvb = tvb_new_subset_remaining (tvb, offset);
+    call_dissector (vpp_metadata_dissector_handle, metadata_tvb, pinfo, tree);
+    offset += len;
+
+    /* Opaque */
+    len = tvb_strsize (tvb, offset);
     opaque_tvb = tvb_new_subset_remaining (tvb, offset);
     call_dissector (vpp_opaque_dissector_handle, opaque_tvb, pinfo, tree);
-    
-    /* Skip opaque */
-    offset += 40;
-    /* skip second opaque line */
-    offset += 64; 
+    offset += len;
 
-    trace_length = tvb_get_guint16 (tvb, offset, ENC_LITTLE_ENDIAN);
-    offset += 2;
+    /* Opaque2 */
+    len = tvb_strsize (tvb, offset);
+    opaque2_tvb = tvb_new_subset_remaining (tvb, offset);
+    call_dissector (vpp_opaque2_dissector_handle, opaque2_tvb, pinfo, tree);
+    offset += len;
 
-    if (trace_length > 0) {
+    /* Trace, if present */
+    if (string_count > 4)
+    {
+        len = tvb_strsize (tvb, offset);
         trace_tvb = tvb_new_subset_remaining (tvb, offset);
-        offset += trace_length;
-
         call_dissector (vpp_trace_dissector_handle, trace_tvb, pinfo, tree);
+        offset += len;
     }
 
     eth_tvb = tvb_new_subset_remaining (tvb, offset);
@@ -766,227 +279,103 @@ dissect_vpp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
      *
      * Failing that, pretend its an ethernet packet
      */ 
-    if (!dissector_try_string (vpp_subdissector_table, name, eth_tvb,
-                               pinfo, tree, NULL)) {
-        guint8 maybe_protocol_id; 
-        dissector_handle_t best_guess_dissector_handle
-            = eth_maybefcs_dissector_handle;
-
+    if (protocol_hint >= array_length(next_dissectors)) {
+        ws_debug_printf ("protocol_hint %d out of range (max %d)",
+                         (int) protocol_hint, 
+                         (int) array_length(next_dissectors));
+        protocol_hint = 0;
+    }
+    /* See setup for hint == 0 below */
+    use_this_dissector = next_dissectors [protocol_hint];
+    if (protocol_hint == 0) {
         maybe_protocol_id = tvb_get_guint8 (tvb, offset);
-
+            
         switch (maybe_protocol_id) {
         case 0x45:
-            best_guess_dissector_handle = ip_dissector_handle;
+            use_this_dissector = next_dissectors[VLIB_NODE_PROTO_HINT_IP4];
             break;
         case 0x60:
-            best_guess_dissector_handle = ipv6_dissector_handle;
+            use_this_dissector = next_dissectors[VLIB_NODE_PROTO_HINT_IP6];
             break;
         default:
             break;
         }
-        call_dissector (best_guess_dissector_handle, eth_tvb, pinfo, tree);
     }
-
-    g_free (name);
+    call_dissector (use_this_dissector, eth_tvb, pinfo, tree);
     return tvb_captured_length(tvb);
 }
 
 void
 proto_register_vpp(void)
 {
-  static hf_register_info hf[] = {
+  static hf_register_info vpp_hf[] = {
       { &hf_vpp_buffer_index,
-        { "BufferIndex", "vpp.bufferindex",  FT_UINT32, BASE_HEX, NULL, 0x0,
+        { "BufferIndex", "vpp.BufferIndex",  FT_UINT32, BASE_HEX, NULL, 0x0,
           NULL, HFILL },
       },
       { &hf_vpp_nodename,
-        { "NodeName", "vpp.nodename",  FT_STRINGZ, BASE_NONE, NULL, 0x0,
-          NULL, HFILL },
-      },
-      { &hf_vpp_buffer_current_data,
-        { "CurrentData", "vpp.current_data", FT_INT16, BASE_DEC, NULL, 0x0,
-          NULL, HFILL },
-      },
-      { &hf_vpp_buffer_current_length,
-        { "CurrentLength", "vpp.current_length", FT_UINT16, BASE_DEC, NULL, 0x0,
-          NULL, HFILL },
-      },
-
-      /* 
-       * Warning: buffer flag bits are not cast in concrete, and it's
-       * impossible to imagine trying to compile WS with even a subset 
-       * of the actual header files. 
-       * 
-       * See .../src/vlib/buffer.h, .../src/vnet/buffer.h in
-       * the fd.io vpp source tree.
-       */
-
-      { &hf_vpp_buffer_flags,
-        { "BufferFlags", "vpp.flags", FT_UINT32, BASE_HEX, NULL, 0x0,
+        { "NodeName", "vpp.NodeName",  FT_STRINGZ, BASE_NONE, NULL, 0x0,
           NULL, HFILL },
       },
+  };
 
-      { &hf_vpp_buffer_flag_non_default_freelist,
-        { "NonDefaultFreelist", "vpp.flags.non_default_freelist",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x1, NULL, HFILL },
-      },
-      { &hf_vpp_buffer_flag_traced,
-        { "Traced", "vpp.flags.traced",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x2, NULL, HFILL },
-      },
-      { &hf_vpp_buffer_flag_next_present,
-        { "NextPresent", "vpp.flags.next_present",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x4, NULL, HFILL },
-      },
-      { &hf_vpp_buffer_flag_total_length_valid,
-        { "TotalLengthValid", "vpp.flags.total_length_valid",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x8, NULL, HFILL },
-      },
-      { &hf_vpp_buffer_flag_ext_hdr_valid,
-        { "ExtHeaderValid", "vpp.flags.ext_hdr_valid",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x10, NULL, HFILL },
-      },
-
-      { &hf_vpp_buffer_flag_l4_checksum_computed,
-        { "L4ChecksumComputed", "vpp.flags.l4_checksum_computed",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x80000000, NULL, HFILL },
-      },
-      { &hf_vpp_buffer_flag_l4_checksum_correct,
-        { "L4ChecksumCorrect", "vpp.flags.l4_checksum_correct",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x40000000, NULL, HFILL },
-      },
-      { &hf_vpp_buffer_flag_vlan_2_deep,
-        { "Vlan2Deep", "vpp.flags.vlan_2_deep",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x20000000, NULL, HFILL },
-      },
-      { &hf_vpp_buffer_flag_vlan_1_deep,
-        { "Vlan1Deep", "vpp.flags.vlan_1_deep",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x10000000, NULL, HFILL },
-      },
-      { &hf_vpp_buffer_flag_span_clone,
-        { "SpanClone", "vpp.flags.span_clone",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x08000000, NULL, HFILL },
-      },
-      { &hf_vpp_buffer_flag_loop_counter_valid,
-        { "LoopCounterValid", "vpp.flags.loop_counter_valid",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x04000000, NULL, HFILL },
-      },
-      { &hf_vpp_buffer_flag_locally_originated,
-        { "LocallyOriginated", "vpp.flags.locally_originated",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x02000000, NULL, HFILL },
-      },
-      { &hf_vpp_buffer_flag_is_ip4,
-        { "IsIP4", "vpp.flags.is_ip4",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x01000000, NULL, HFILL },
-      },
-      { &hf_vpp_buffer_flag_is_ip6,
-        { "IsIP4", "vpp.flags.is_ip6",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00800000, NULL, HFILL },
-      },
-      { &hf_vpp_buffer_flag_offload_ip_checksum,
-        { "OffloadIPChecksum", "vpp.flags.offload_ip_checksum",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00400000, NULL, HFILL },
-      },
-      { &hf_vpp_buffer_flag_offload_tcp_checksum,
-        { "OffloadTCPChecksum", "vpp.flags.offload_tcp_checksum",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00200000, NULL, HFILL },
-      },
-      { &hf_vpp_buffer_flag_offload_udp_checksum,
-        { "OffloadUDPChecksum", "vpp.flags.offload_udp_checksum",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00100000, NULL, HFILL },
-      },
-      { &hf_vpp_buffer_flag_is_natted,
-        { "IsNATted", "vpp.flags.is_natted",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00080000, NULL, HFILL },
-      },
-      { &hf_vpp_buffer_flag_l2_hdr_offset_valid,
-        { "L2HdrOffsetValid", "vpp.flags.l2_hdr_offset_valid",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00040000, NULL, HFILL },
-      },
-      { &hf_vpp_buffer_flag_l3_hdr_offset_valid,
-        { "L3HdrOffsetValid", "vpp.flags.l3_hdr_offset_valid",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00020000, NULL, HFILL },
-      },
-      { &hf_vpp_buffer_flag_l4_hdr_offset_valid,
-        { "L4HdrOffsetValid", "vpp.flags.l4_hdr_offset_valid",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00010000, NULL, HFILL },
-      },
-      { &hf_vpp_buffer_flag_flow_report,
-        { "FlowReport", "vpp.flags.flow_report",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00008000, NULL, HFILL },
-      },
-      { &hf_vpp_buffer_flag_is_dvr,
-        { "IsDVR", "vpp.flags.is_dvr",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00004000, NULL, HFILL },
-      },
-      { &hf_vpp_buffer_flag_qos_data_valid,
-        { "QOSDataValid", "vpp.flags.qos_data_valid",
-          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00002000, NULL, HFILL },
-      },
-
-      { &hf_vpp_buffer_flow_id,
-        { "FlowID", "vpp.flow_id", FT_UINT32, BASE_DEC, NULL, 0x0,
-          NULL, HFILL },
-      },
-      { &hf_vpp_buffer_next_buffer,
-        { "NextBuffer", "vpp.next_buffer", FT_UINT32, BASE_DEC, NULL, 0x0,
-          NULL, HFILL },
-      },
-      { &hf_vpp_buffer_current_config_index,
-        { "CurrentConfigIndex", "vpp.current_config_index", 
-          FT_UINT32, BASE_DEC, NULL, 0x0,
-          NULL, HFILL },
-      },
-      { &hf_vpp_buffer_error_index,
-        { "ErrorIndex", "vpp.error_index", 
-          FT_UINT16, BASE_DEC, NULL, 0x0,
-          NULL, HFILL },
-      },
-      { &hf_vpp_buffer_n_add_refs,
-        { "AddRefs", "vpp.n_add_refs_index", 
-          FT_UINT8, BASE_DEC, NULL, 0x0,
-          NULL, HFILL },
-      },
-      { &hf_vpp_buffer_buffer_pool_index,
-        { "BufferPoolIndex", "vpp.buffer_pool_index", 
-          FT_UINT8, BASE_DEC, NULL, 0x0,
-          NULL, HFILL },
+  static hf_register_info metadata_hf[] = {
+      { &hf_vpp_metadata,
+        { "Metadata", "vpp.metadata",  
+          FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
       },
   };
 
   static hf_register_info opaque_hf[] = {
-      { &hf_vpp_buffer_opaque_raw,
-        { "Raw   ", "vppMetadata.opaque_raw",  FT_STRINGZ, BASE_NONE, NULL, 0x0,
-          NULL, HFILL },
+      { &hf_vpp_buffer_opaque,
+        { "Opaque", "vpp.opaque",  
+          FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
       },
-      { &hf_vpp_buffer_opaque_opaque,
-        { "Opaque", "vppMetadata.opaque",  
+  };
+
+  static hf_register_info opaque2_hf[] = {
+      { &hf_vpp_buffer_opaque2,
+        { "Opaque2", "vpp.opaque2",  
           FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
       },
   };
 
   static hf_register_info trace_hf[] = {
       { &hf_vpp_buffer_trace,
-        { "Trace", "vppTrace.trace",  FT_STRINGZ, BASE_NONE, NULL, 0x0,
+        { "Trace", "vpp.trace",  FT_STRINGZ, BASE_NONE, NULL, 0x0,
           NULL, HFILL },
       },
   };
 
-  static gint *ett[] = {
+  static gint *vpp_ett[] = {
     &ett_vpp,
   };
+  static gint *ett_metadata[] = {
+    &ett_vpp_metadata,
+  };
   static gint *ett_opaque[] = {
     &ett_vpp_opaque,
   };
+  static gint *ett_opaque2[] = {
+    &ett_vpp_opaque2,
+  };
   static gint *ett_trace[] = {
     &ett_vpp_trace,
   };
 
-  proto_vpp = proto_register_protocol("VPP Buffer Metadata", "VPP", "vpp");
-  proto_register_field_array(proto_vpp, hf, array_length(hf));
-  proto_register_subtree_array (ett, array_length(ett));
+  proto_vpp = proto_register_protocol("VPP Dispatch Trace", "VPP", "vpp");
+  proto_register_field_array(proto_vpp, vpp_hf, array_length(vpp_hf));
+  proto_register_subtree_array (vpp_ett, array_length(vpp_ett));
   register_dissector("vpp", dissect_vpp, proto_vpp);
 
+  proto_vpp_metadata = proto_register_protocol("VPP Buffer Metadata", 
+                                               "VPP-Metadata", 
+                                               "vpp-metadata");
+  proto_register_field_array(proto_vpp_metadata, metadata_hf, 
+                             array_length(metadata_hf));
+  proto_register_subtree_array (ett_metadata, array_length(ett_metadata));
+  register_dissector("vppMetadata", dissect_vpp_metadata, proto_vpp_metadata);
+
   proto_vpp_opaque = proto_register_protocol("VPP Buffer Opaque", "VPP-Opaque", 
                                              "vpp-opaque");
   proto_register_field_array(proto_vpp_opaque, opaque_hf, 
@@ -994,6 +383,14 @@ proto_register_vpp(void)
   proto_register_subtree_array (ett_opaque, array_length(ett_opaque));
   register_dissector("vppOpaque", dissect_vpp_opaque, proto_vpp_opaque);
 
+  proto_vpp_opaque2 = proto_register_protocol("VPP Buffer Opaque2", "VPP-Opaque2", 
+                                             "vpp-opaque2");
+  proto_register_field_array(proto_vpp_opaque2, opaque2_hf, 
+                             array_length(opaque2_hf));
+  proto_register_subtree_array (ett_opaque2, array_length(ett_opaque2));
+  register_dissector("vppOpaque2", dissect_vpp_opaque2, proto_vpp_opaque2);
+
+
   proto_vpp_trace = proto_register_protocol("VPP Buffer Trace", "VPP-Trace", 
                                              "vpp-trace");
   proto_register_field_array(proto_vpp_trace, trace_hf, 
@@ -1001,22 +398,22 @@ proto_register_vpp(void)
   proto_register_subtree_array (ett_trace, array_length(ett_trace));
   register_dissector("vppTrace", dissect_vpp_trace, proto_vpp_trace);
   
-  vpp_subdissector_table = register_dissector_table 
-      ("vpp", "VPP per-node next dissector table", proto_vpp,
-       FT_STRING, BASE_NONE);
-
-#define _(n,d)                                                  \
-  d##_dissector_handle = find_dissector(#d);                    \
-  dissector_add_string ("vpp", n, d##_dissector_handle);
-  foreach_node_to_dissector_pair;
+#define _(idx,dname) next_dissectors[idx] = find_dissector (#dname);
+  foreach_next_dissector;
 #undef _
+
+  /* if all else fails, dissect data as if ethernet MAC */
+  next_dissectors[VLIB_NODE_PROTO_HINT_NONE] = 
+      next_dissectors [VLIB_NODE_PROTO_HINT_ETHERNET];
 }
 
 void
 proto_reg_handoff_vpp(void)
 {
     vpp_dissector_handle = find_dissector("vpp");
+    vpp_metadata_dissector_handle = find_dissector("vppMetadata");
     vpp_opaque_dissector_handle = find_dissector("vppOpaque");
+    vpp_opaque2_dissector_handle = find_dissector("vppOpaque2");
     vpp_trace_dissector_handle = find_dissector("vppTrace");
     dissector_add_uint("wtap_encap", WTAP_ENCAP_USER13, vpp_dissector_handle);
 }
index d1babdb..949a77d 100644 (file)
@@ -945,25 +945,69 @@ add_trajectory_trace (vlib_buffer_t * b, u32 node_index)
 #endif
 }
 
+u8 *format_vnet_buffer_flags (u8 * s, va_list * args) __attribute__ ((weak));
+u8 *
+format_vnet_buffer_flags (u8 * s, va_list * args)
+{
+  s = format (s, "BUG STUB %s", __FUNCTION__);
+  return s;
+}
+
+u8 *format_vnet_buffer_opaque (u8 * s, va_list * args) __attribute__ ((weak));
+u8 *
+format_vnet_buffer_opaque (u8 * s, va_list * args)
+{
+  s = format (s, "BUG STUB %s", __FUNCTION__);
+  return s;
+}
+
+u8 *format_vnet_buffer_opaque2 (u8 * s, va_list * args)
+  __attribute__ ((weak));
+u8 *
+format_vnet_buffer_opaque2 (u8 * s, va_list * args)
+{
+  s = format (s, "BUG STUB %s", __FUNCTION__);
+  return s;
+}
+
+static u8 *
+format_buffer_metadata (u8 * s, va_list * args)
+{
+  vlib_buffer_t *b = va_arg (*args, vlib_buffer_t *);
+
+  s = format (s, "flags: %U\n", format_vnet_buffer_flags, b);
+  s = format (s, "current_data: %d, current_length: %d\n",
+             (i32) (b->current_data), (i32) (b->current_length));
+  s = format (s, "current_config_index: %d, flow_id: %x, next_buffer: %x\n",
+             b->current_config_index, b->flow_id, b->next_buffer);
+  s = format (s, "error: %d, n_add_refs: %d, buffer_pool_index: %d\n",
+             (u32) (b->error), (u32) (b->n_add_refs),
+             (u32) (b->buffer_pool_index));
+  s = format (s,
+             "trace_index: %d, recycle_count: %d, len_not_first_buf: %d\n",
+             b->trace_index, b->recycle_count,
+             b->total_length_not_including_first_buffer);
+  s = format (s, "free_list_index: %d\n", (u32) (b->free_list_index));
+  return s;
+}
+
+#define A(x) vec_add1(vm->pcap_buffer, (x))
+
 static void
 dispatch_pcap_trace (vlib_main_t * vm,
                     vlib_node_runtime_t * node, vlib_frame_t * frame)
 {
   int i;
   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **bufp, *b;
-  u8 name_tlv[64];
   pcap_main_t *pm = &vm->dispatch_pcap_main;
   vlib_trace_main_t *tm = &vm->trace_main;
   u32 capture_size;
   vlib_node_t *n;
-  u8 *packet_trace = 0;
   i32 n_left;
   f64 time_now = vlib_time_now (vm);
   u32 *from;
-  u32 name_length;
-  u16 trace_length;
-  u8 version[2];
   u8 *d;
+  u8 string_count;
 
   /* Input nodes don't have frames yet */
   if (frame == 0 || frame->n_vectors == 0)
@@ -973,15 +1017,7 @@ dispatch_pcap_trace (vlib_main_t * vm,
   vlib_get_buffers (vm, from, bufs, frame->n_vectors);
   bufp = bufs;
 
-  /* Create a node name TLV, since WS can't possibly guess */
   n = vlib_get_node (vm, node->node_index);
-  name_length = vec_len (n->name);
-  name_length = name_length < ARRAY_LEN (name_tlv) - 2 ?
-    name_length : ARRAY_LEN (name_tlv) - 2;
-
-  name_tlv[0] = (u8) name_length;
-  clib_memcpy_fast (name_tlv + 1, n->name, name_length);
-  name_tlv[name_length + 1] = 0;
 
   for (i = 0; i < frame->n_vectors; i++)
     {
@@ -989,10 +1025,34 @@ dispatch_pcap_trace (vlib_main_t * vm,
        {
          b = bufp[i];
 
-         version[0] = VLIB_PCAP_MAJOR_VERSION;
-         version[1] = VLIB_PCAP_MINOR_VERSION;
-
-         vec_reset_length (packet_trace);
+         vec_reset_length (vm->pcap_buffer);
+         string_count = 0;
+
+         /* Version, flags */
+         A ((u8) VLIB_PCAP_MAJOR_VERSION);
+         A ((u8) VLIB_PCAP_MINOR_VERSION);
+         A (0 /* string_count */ );
+         A (n->protocol_hint);
+
+         /* Buffer index (big endian) */
+         A ((from[i] >> 24) & 0xff);
+         A ((from[i] >> 16) & 0xff);
+         A ((from[i] >> 8) & 0xff);
+         A ((from[i] >> 0) & 0xff);
+
+         /* Node name, NULL-terminated ASCII */
+         vm->pcap_buffer = format (vm->pcap_buffer, "%v%c", n->name, 0);
+         string_count++;
+
+         vm->pcap_buffer = format (vm->pcap_buffer, "%U%c",
+                                   format_buffer_metadata, b, 0);
+         string_count++;
+         vm->pcap_buffer = format (vm->pcap_buffer, "%U%c",
+                                   format_vnet_buffer_opaque, b, 0);
+         string_count++;
+         vm->pcap_buffer = format (vm->pcap_buffer, "%U%c",
+                                   format_vnet_buffer_opaque2, b, 0);
+         string_count++;
 
          /* Is this packet traced? */
          if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED))
@@ -1000,55 +1060,29 @@ dispatch_pcap_trace (vlib_main_t * vm,
              vlib_trace_header_t **h
                = pool_elt_at_index (tm->trace_buffer_pool, b->trace_index);
 
-             packet_trace = format (packet_trace, "%U%c",
-                                    format_vlib_trace, vm, h[0], 0);
+             vm->pcap_buffer = format (vm->pcap_buffer, "%U%c",
+                                       format_vlib_trace, vm, h[0], 0);
+             string_count++;
            }
 
-         /* Figure out how many bytes we're capturing */
-          /* *INDENT-OFF* */
-         capture_size = (sizeof (vlib_buffer_t) - VLIB_BUFFER_PRE_DATA_SIZE)
-            + sizeof (version)
-            + vlib_buffer_length_in_chain (vm, b)
-            + sizeof (u32) + (name_length + 2) /* +2: count plus NULL byte */
-           + (vec_len (packet_trace) + 2);     /* +2: trace count */
-          /* *INDENT-ON* */
+         /* Save the string count */
+         vm->pcap_buffer[2] = string_count;
+
+         /* Figure out how many bytes in the pcap trace */
+         capture_size = vec_len (vm->pcap_buffer) +
+           +vlib_buffer_length_in_chain (vm, b);
 
          clib_spinlock_lock_if_init (&pm->lock);
          n_left = clib_min (capture_size, 16384);
          d = pcap_add_packet (pm, time_now, n_left, capture_size);
 
-         /* Copy the (major, minor) version numbers */
-         clib_memcpy_fast (d, version, sizeof (version));
-         d += sizeof (version);
-
-         /* Copy the buffer index */
-         clib_memcpy_fast (d, &from[i], sizeof (u32));
-         d += 4;
-
-         /* Copy the name TLV */
-         clib_memcpy_fast (d, name_tlv, name_length + 2);
-         d += name_length + 2;
-
-         /* Copy the buffer metadata, but not the rewrite space */
-         clib_memcpy_fast (d, b, sizeof (*b) - VLIB_BUFFER_PRE_DATA_SIZE);
-         d += sizeof (*b) - VLIB_BUFFER_PRE_DATA_SIZE;
-
-         trace_length = vec_len (packet_trace);
-         /* Copy the trace data length (may be zero) */
-         clib_memcpy_fast (d, &trace_length, sizeof (trace_length));
-         d += 2;
-
-         /* Copy packet trace data (if any) */
-         if (vec_len (packet_trace))
-           clib_memcpy_fast (d, packet_trace, vec_len (packet_trace));
-
-         d += vec_len (packet_trace);
+         /* Copy the header */
+         clib_memcpy_fast (d, vm->pcap_buffer, vec_len (vm->pcap_buffer));
+         d += vec_len (vm->pcap_buffer);
 
          n_left = clib_min
            (vlib_buffer_length_in_chain (vm, b),
-            16384 -
-            ((sizeof (*b) - VLIB_BUFFER_PRE_DATA_SIZE) +
-             (trace_length + 2)));
+            (16384 - vec_len (vm->pcap_buffer)));
          /* Copy the packet data */
          while (1)
            {
@@ -1064,7 +1098,6 @@ dispatch_pcap_trace (vlib_main_t * vm,
          clib_spinlock_unlock_if_init (&pm->lock);
        }
     }
-  vec_free (packet_trace);
 }
 
 static_always_inline u64
index 9fa294e..474756b 100644 (file)
@@ -134,6 +134,7 @@ typedef struct vlib_main_t
   /* Pcap dispatch trace main */
   pcap_main_t dispatch_pcap_main;
   uword dispatch_pcap_enable;
+  u8 *pcap_buffer;
 
   /* Error handling. */
   vlib_error_main_t error_main;
index 88185ce..69f5051 100644 (file)
@@ -350,6 +350,7 @@ register_node (vlib_main_t * vm, vlib_node_registration_t * r)
   clib_memset (n, 0, sizeof (n[0]));
   n->index = vec_len (nm->nodes);
   n->node_fn_registrations = r->node_fn_registrations;
+  n->protocol_hint = r->protocol_hint;
 
   vec_add1 (nm->nodes, n);
 
index fb2a83b..f41eb60 100644 (file)
@@ -55,6 +55,17 @@ typedef uword (vlib_node_function_t) (struct vlib_main_t * vm,
                                      struct vlib_node_runtime_t * node,
                                      struct vlib_frame_t * frame);
 
+typedef enum
+{
+  VLIB_NODE_PROTO_HINT_NONE = 0,
+  VLIB_NODE_PROTO_HINT_ETHERNET,
+  VLIB_NODE_PROTO_HINT_IP4,
+  VLIB_NODE_PROTO_HINT_IP6,
+  VLIB_NODE_PROTO_HINT_TCP,
+  VLIB_NODE_PROTO_HINT_UDP,
+  VLIB_NODE_N_PROTO_HINTS,
+} vlib_node_proto_hint_t;
+
 typedef enum
 {
   /* An internal node on the call graph (could be output). */
@@ -134,6 +145,9 @@ typedef struct _vlib_node_registration
   /* Node flags. */
   u16 flags;
 
+  /* protocol at b->data[b->current_data] upon entry to the dispatch fn */
+  u8 protocol_hint;
+
   /* Size of scalar and vector arguments in bytes. */
   u16 scalar_size, vector_size;
 
@@ -320,6 +334,9 @@ typedef struct vlib_node_t
   /* Number of bytes of run time data. */
   u8 runtime_data_bytes;
 
+  /* protocol at b->data[b->current_data] upon entry to the dispatch fn */
+  u8 protocol_hint;
+
   /* Number of error codes used by this node. */
   u16 n_errors;
 
index de1c735..cf61780 100644 (file)
@@ -24,9 +24,9 @@ format_vnet_buffer (u8 * s, va_list * args)
   u32 indent = format_get_indent (s);
   u8 *a = 0;
 
-#define _(bit, name, v) \
+#define _(bit,name,ss,v)                      \
   if (v && (b->flags & VNET_BUFFER_F_##name)) \
-    a = format (a, "%s ", v);
+    a = format (a, "%s ", ss);
   foreach_vnet_buffer_flag
 #undef _
     if (b->flags & VNET_BUFFER_F_L2_HDR_OFFSET_VALID)
index 8071081..d701e21 100644 (file)
 /**
  * Flags that are set in the high order bits of ((vlib_buffer*)b)->flags
  */
-#define foreach_vnet_buffer_flag \
-  _( 1, L4_CHECKSUM_COMPUTED, "l4-cksum-computed")     \
-  _( 2, L4_CHECKSUM_CORRECT, "l4-cksum-correct")       \
-  _( 3, VLAN_2_DEEP, "vlan-2-deep")                    \
-  _( 4, VLAN_1_DEEP, "vlan-1-deep")                    \
-  _( 5, SPAN_CLONE, "span-clone")                      \
-  _( 6, LOOP_COUNTER_VALID, 0)                          \
-  _( 7, LOCALLY_ORIGINATED, "local")                   \
-  _( 8, IS_IP4, "ip4")                                 \
-  _( 9, IS_IP6, "ip6")                                 \
-  _(10, OFFLOAD_IP_CKSUM, "offload-ip-cksum")          \
-  _(11, OFFLOAD_TCP_CKSUM, "offload-tcp-cksum")                \
-  _(12, OFFLOAD_UDP_CKSUM, "offload-udp-cksum")                \
-  _(13, IS_NATED, "nated")                             \
-  _(14, L2_HDR_OFFSET_VALID, 0)                                \
-  _(15, L3_HDR_OFFSET_VALID, 0)                                \
-  _(16, L4_HDR_OFFSET_VALID, 0)                                \
-  _(17, FLOW_REPORT, "flow-report")                    \
-  _(18, IS_DVR, "dvr")                                  \
-  _(19, QOS_DATA_VALID, 0)
+#define foreach_vnet_buffer_flag                        \
+  _( 1, L4_CHECKSUM_COMPUTED, "l4-cksum-computed", 1)  \
+  _( 2, L4_CHECKSUM_CORRECT, "l4-cksum-correct", 1)    \
+  _( 3, VLAN_2_DEEP, "vlan-2-deep", 1)                 \
+  _( 4, VLAN_1_DEEP, "vlan-1-deep", 1)                 \
+  _( 5, SPAN_CLONE, "span-clone", 1)                    \
+  _( 6, LOOP_COUNTER_VALID, "loop-counter-valid", 0)    \
+  _( 7, LOCALLY_ORIGINATED, "local", 1)                 \
+  _( 8, IS_IP4, "ip4", 1)                               \
+  _( 9, IS_IP6, "ip6", 1)                               \
+  _(10, OFFLOAD_IP_CKSUM, "offload-ip-cksum", 1)        \
+  _(11, OFFLOAD_TCP_CKSUM, "offload-tcp-cksum", 1)      \
+  _(12, OFFLOAD_UDP_CKSUM, "offload-udp-cksum", 1)      \
+  _(13, IS_NATED, "natted", 1)                          \
+  _(14, L2_HDR_OFFSET_VALID, "l2_hdr_offset_valid", 0)  \
+  _(15, L3_HDR_OFFSET_VALID, "l3_hdr_offset_valid", 0)  \
+  _(16, L4_HDR_OFFSET_VALID, "l4_hdr_offset_valid", 0)  \
+  _(17, FLOW_REPORT, "flow-report", 1)                  \
+  _(18, IS_DVR, "dvr", 1)                               \
+  _(19, QOS_DATA_VALID, "qos-data-valid", 0)
 
 #define VNET_BUFFER_FLAGS_VLAN_BITS \
   (VNET_BUFFER_F_VLAN_1_DEEP | VNET_BUFFER_F_VLAN_2_DEEP)
 
 enum
 {
-#define _(bit, name, v) VNET_BUFFER_F_##name  = (1 << LOG2_VLIB_BUFFER_FLAG_USER(bit)),
+#define _(bit, name, s, v) VNET_BUFFER_F_##name  = (1 << LOG2_VLIB_BUFFER_FLAG_USER(bit)),
   foreach_vnet_buffer_flag
 #undef _
 };
 
 enum
 {
-#define _(bit, name, v) VNET_BUFFER_F_LOG2_##name  = LOG2_VLIB_BUFFER_FLAG_USER(bit),
+#define _(bit, name, s, v) VNET_BUFFER_F_LOG2_##name  = LOG2_VLIB_BUFFER_FLAG_USER(bit),
   foreach_vnet_buffer_flag
 #undef _
 };
index c62e770..98be872 100644 (file)
@@ -367,6 +367,218 @@ format_vnet_sw_interface_name_override (u8 * s, va_list * args)
   return s;
 }
 
+u8 *
+format_vnet_buffer_flags (u8 * s, va_list * args)
+{
+  vlib_buffer_t *buf = va_arg (*args, vlib_buffer_t *);
+
+#define _(a,b,c,v) if (buf->flags & VNET_BUFFER_F_##b) s = format (s, "%s ", c);
+  foreach_vnet_buffer_flag;
+#undef _
+  return s;
+}
+
+u8 *
+format_vnet_buffer_opaque (u8 * s, va_list * args)
+{
+  vlib_buffer_t *b = va_arg (*args, vlib_buffer_t *);
+  vnet_buffer_opaque_t *o = (vnet_buffer_opaque_t *) b->opaque;
+  int i;
+
+  s = format (s, "raw: ");
+
+  for (i = 0; i < ARRAY_LEN (b->opaque); i++)
+    s = format (s, "%08x ", b->opaque[i]);
+
+  vec_add1 (s, '\n');
+
+  s = format (s,
+             "sw_if_index[VLIB_RX]: %d, sw_if_index[VLIB_TX]: %d",
+             o->sw_if_index[0], o->sw_if_index[1]);
+  vec_add1 (s, '\n');
+
+  s = format (s,
+             "L2 offset %d, L3 offset %d, L4 offset %d, feature arc index %d",
+             (u32) (o->l2_hdr_offset),
+             (u32) (o->l3_hdr_offset),
+             (u32) (o->l4_hdr_offset), (u32) (o->feature_arc_index));
+  vec_add1 (s, '\n');
+
+  s = format (s,
+             "ip.adj_index[VLIB_RX]: %d, ip.adj_index[VLIB_TX]: %d",
+             (u32) (o->ip.adj_index[0]), (u32) (o->ip.adj_index[1]));
+  vec_add1 (s, '\n');
+
+  s = format (s,
+             "ip.flow_hash: 0x%x, ip.save_protocol: 0x%x, ip.fib_index: %d",
+             o->ip.flow_hash, o->ip.save_protocol, o->ip.fib_index);
+  vec_add1 (s, '\n');
+
+  s = format (s,
+             "ip.save_rewrite_length: %d, ip.rpf_id: %d",
+             o->ip.save_rewrite_length, o->ip.rpf_id);
+  vec_add1 (s, '\n');
+
+  s = format (s,
+             "ip.icmp.type: %d ip.icmp.code: %d, ip.icmp.data: 0x%x",
+             (u32) (o->ip.icmp.type),
+             (u32) (o->ip.icmp.code), o->ip.icmp.data);
+  vec_add1 (s, '\n');
+
+  s = format (s,
+             "ip.reass.next_index: %d, ip.reass.estimated_mtu: %d",
+             o->ip.reass.next_index, (u32) (o->ip.reass.estimated_mtu));
+  vec_add1 (s, '\n');
+
+  s = format (s,
+             "ip.reass.fragment_first: %d ip.reass.fragment_last: %d",
+             (u32) (o->ip.reass.fragment_first),
+             (u32) (o->ip.reass.fragment_last));
+  vec_add1 (s, '\n');
+
+  s = format (s,
+             "ip.reass.range_first: %d ip.reass.range_last: %d",
+             (u32) (o->ip.reass.range_first),
+             (u32) (o->ip.reass.range_last));
+  vec_add1 (s, '\n');
+
+  s = format (s,
+             "ip.reass.next_range_bi: 0x%x, ip.reass.ip6_frag_hdr_offset: %d",
+             o->ip.reass.next_range_bi,
+             (u32) (o->ip.reass.ip6_frag_hdr_offset));
+  vec_add1 (s, '\n');
+
+  s = format (s,
+             "mpls.ttl: %d, mpls.exp: %d, mpls.first: %d, "
+             "mpls.save_rewrite_length: %d, mpls.bier.n_bytes: %d",
+             (u32) (o->mpls.ttl), (u32) (o->mpls.exp), (u32) (o->mpls.first),
+             o->mpls.save_rewrite_length, (u32) (o->mpls.bier.n_bytes));
+  vec_add1 (s, '\n');
+
+  s = format (s,
+             "l2.feature_bitmap: %08x, l2.bd_index: %d, l2.l2_len: %d, "
+             "l2.shg: %d, l2.l2fib_sn: %d, l2.bd_age: %d",
+             o->l2.feature_bitmap, (u32) (o->l2.bd_index),
+             (u32) (o->l2.l2_len), (u32) (o->l2.shg), (u32) (o->l2.l2fib_sn),
+             (u32) (o->l2.bd_age));
+  vec_add1 (s, '\n');
+
+  s = format (s,
+             "l2t.next_index: %d, l2t.session_index: %d",
+             (u32) (o->l2t.next_index), o->l2t.session_index);
+  vec_add1 (s, '\n');
+
+  s = format (s,
+             "l2_classify.table_index: %d, l2_classify.opaque_index: %d, "
+             "l2_classify.hash: 0x%llx",
+             o->l2_classify.table_index,
+             o->l2_classify.opaque_index, o->l2_classify.hash);
+  vec_add1 (s, '\n');
+
+  s = format (s, "policer.index: %d", o->policer.index);
+  vec_add1 (s, '\n');
+
+  s = format (s,
+             "ipsec.flags: 0x%x, ipsec.sad_index: %d",
+             o->ipsec.flags, o->ipsec.sad_index);
+  vec_add1 (s, '\n');
+
+  s = format (s, "map.mtu: %d", (u32) (o->map.mtu));
+  vec_add1 (s, '\n');
+
+  s = format (s,
+             "map_t.v6.saddr: 0x%x, map_t.v6.daddr: 0x%x, "
+             "map_t.v6.frag_offset: %d, map_t.v6.l4_offset: %d",
+             o->map_t.v6.saddr,
+             o->map_t.v6.daddr,
+             (u32) (o->map_t.v6.frag_offset), (u32) (o->map_t.v6.l4_offset));
+  vec_add1 (s, '\n');
+
+  s = format (s,
+             "map_t.v6.l4_protocol: %d, map_t.checksum_offset: %d, "
+             "map_t.mtu: %d",
+             (u32) (o->map_t.v6.l4_protocol),
+             (u32) (o->map_t.checksum_offset), (u32) (o->map_t.mtu));
+  vec_add1 (s, '\n');
+
+  s = format (s,
+             "ip_frag.mtu: %d, ip_frag.next_index: %d, ip_frag.flags: 0x%x",
+             (u32) (o->ip_frag.mtu),
+             (u32) (o->ip_frag.next_index), (u32) (o->ip_frag.flags));
+  vec_add1 (s, '\n');
+
+  s = format (s, "cop.current_config_index: %d", o->cop.current_config_index);
+  vec_add1 (s, '\n');
+
+  s = format (s, "lisp.overlay_afi: %d", (u32) (o->lisp.overlay_afi));
+  vec_add1 (s, '\n');
+
+  s = format
+    (s, "tcp.connection_index: %d, tcp.seq_number: %d, tcp.seq_end: %d, "
+     "tcp.ack_number: %d, tcp.hdr_offset: %d, tcp.data_offset: %d",
+     o->tcp.connection_index,
+     o->tcp.seq_number,
+     o->tcp.seq_end,
+     o->tcp.ack_number,
+     (u32) (o->tcp.hdr_offset), (u32) (o->tcp.data_offset));
+  vec_add1 (s, '\n');
+
+  s = format (s,
+             "tcp.data_len: %d, tcp.flags: 0x%x",
+             (u32) (o->tcp.data_len), (u32) (o->tcp.flags));
+  vec_add1 (s, '\n');
+
+  s = format (s,
+             "sctp.connection_index: %d, sctp.sid: %d, sctp.ssn: %d, "
+             "sctp.tsn: %d, sctp.hdr_offset: %d",
+             o->sctp.connection_index,
+             (u32) (o->sctp.sid),
+             (u32) (o->sctp.ssn),
+             (u32) (o->sctp.tsn), (u32) (o->sctp.hdr_offset));
+  vec_add1 (s, '\n');
+
+  s = format
+    (s, "sctp.data_offset: %d, sctp.data_len: %d, sctp.subconn_idx: %d, "
+     "sctp.flags: 0x%x",
+     (u32) (o->sctp.data_offset),
+     (u32) (o->sctp.data_len),
+     (u32) (o->sctp.subconn_idx), (u32) (o->sctp.flags));
+  vec_add1 (s, '\n');
+
+  s = format (s, "snat.flags: 0x%x", o->snat.flags);
+  vec_add1 (s, '\n');
+  return s;
+}
+
+u8 *
+format_vnet_buffer_opaque2 (u8 * s, va_list * args)
+{
+  vlib_buffer_t *b = va_arg (*args, vlib_buffer_t *);
+  vnet_buffer_opaque2_t *o = (vnet_buffer_opaque2_t *) b->opaque2;
+
+  int i;
+
+  s = format (s, "raw: ");
+
+  for (i = 0; i < ARRAY_LEN (b->opaque2); i++)
+    s = format (s, "%08x ", b->opaque2[i]);
+  vec_add1 (s, '\n');
+
+  s = format (s, "qos.bits: %x, qos.source: %x",
+             (u32) (o->qos.bits), (u32) (o->qos.source));
+  vec_add1 (s, '\n');
+  s = format (s, "loop_counter: %d", o->loop_counter);
+  vec_add1 (s, '\n');
+
+  s = format (s, "gbp.flags: %x, gbp.src_epg: %d",
+             (u32) (o->gbp.flags), (u32) (o->gbp.src_epg));
+  vec_add1 (s, '\n');
+
+  s = format (s, "pg_replay_timestamp: %llu", (u32) (o->pg_replay_timestamp));
+  vec_add1 (s, '\n');
+  return s;
+}
+
 uword
 unformat_vnet_hw_interface (unformat_input_t * input, va_list * args)
 {
index 696c4b6..91766b4 100644 (file)
@@ -317,6 +317,7 @@ char *ip4_error_strings[] = {
 VLIB_REGISTER_NODE (ip4_input_node) = {
   .name = "ip4-input",
   .vector_size = sizeof (u32),
+  .protocol_hint = VLIB_NODE_PROTO_HINT_IP4,
 
   .n_errors = IP4_N_ERROR,
   .error_strings = ip4_error_strings,
index 619dce1..2f15268 100644 (file)
@@ -2214,6 +2214,7 @@ VLIB_REGISTER_NODE (tcp4_output_node) =
   /* Takes a vector of packets. */
   .vector_size = sizeof (u32),
   .n_errors = TCP_N_ERROR,
+  .protocol_hint = VLIB_NODE_PROTO_HINT_TCP,
   .error_strings = tcp_error_strings,
   .n_next_nodes = TCP_OUTPUT_N_NEXT,
   .next_nodes = {
@@ -2236,6 +2237,7 @@ VLIB_REGISTER_NODE (tcp6_output_node) =
     /* Takes a vector of packets. */
   .vector_size = sizeof (u32),
   .n_errors = TCP_N_ERROR,
+  .protocol_hint = VLIB_NODE_PROTO_HINT_TCP,
   .error_strings = tcp_error_strings,
   .n_next_nodes = TCP_OUTPUT_N_NEXT,
   .next_nodes = {