+ .name = "ip6-pop-hop-by-hop",
+ .vector_size = sizeof (u32),
+ .format_trace = format_ip6_pop_hop_by_hop_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .sibling_of = "ip6-lookup",
+ .n_errors = ARRAY_LEN (ip6_pop_hop_by_hop_error_strings),
+ .error_strings = ip6_pop_hop_by_hop_error_strings,
+ /* See ip/lookup.h */
+ .n_next_nodes = 0,
+};
+/* *INDENT-ON* */
+
+typedef struct
+{
+ u32 protocol;
+ u32 next_index;
+} ip6_local_hop_by_hop_trace_t;
+
+#ifndef CLIB_MARCH_VARIANT
+
+/* packet trace format function */
+static u8 *
+format_ip6_local_hop_by_hop_trace (u8 * s, va_list * args)
+{
+ CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+ CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+ ip6_local_hop_by_hop_trace_t *t =
+ va_arg (*args, ip6_local_hop_by_hop_trace_t *);
+
+ s = format (s, "IP6_LOCAL_HOP_BY_HOP: protocol %d, next index %d\n",
+ t->protocol, t->next_index);
+ return s;
+}
+
+vlib_node_registration_t ip6_local_hop_by_hop_node;
+
+#endif /* CLIB_MARCH_VARIANT */
+
+#define foreach_ip6_local_hop_by_hop_error \
+_(UNKNOWN, "Unknown protocol ip6 local h-b-h packets dropped") \
+_(OK, "Good ip6 local h-b-h packets")
+
+typedef enum
+{
+#define _(sym,str) IP6_LOCAL_HOP_BY_HOP_ERROR_##sym,
+ foreach_ip6_local_hop_by_hop_error
+#undef _
+ IP6_LOCAL_HOP_BY_HOP_N_ERROR,
+} ip6_local_hop_by_hop_error_t;
+
+#ifndef CLIB_MARCH_VARIANT
+static char *ip6_local_hop_by_hop_error_strings[] = {
+#define _(sym,string) string,
+ foreach_ip6_local_hop_by_hop_error
+#undef _
+};
+#endif /* CLIB_MARCH_VARIANT */
+
+typedef enum
+{
+ IP6_LOCAL_HOP_BY_HOP_NEXT_DROP,
+ IP6_LOCAL_HOP_BY_HOP_N_NEXT,
+} ip6_local_hop_by_hop_next_t;
+
+always_inline uword
+ip6_local_hop_by_hop_inline (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * frame,
+ int is_trace)
+{
+ u32 n_left_from, *from;
+ vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
+ u16 nexts[VLIB_FRAME_SIZE], *next;
+ u32 ok = 0;
+ u32 unknown_proto_error = node->errors[IP6_LOCAL_HOP_BY_HOP_ERROR_UNKNOWN];
+ ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main;
+
+ /* Note: there is only one of these */
+ ip6_local_hop_by_hop_runtime_t *rt = hm->ip6_local_hbh_runtime;
+
+ from = vlib_frame_vector_args (frame);
+ n_left_from = frame->n_vectors;
+
+ vlib_get_buffers (vm, from, bufs, n_left_from);
+ b = bufs;
+ next = nexts;
+
+ while (n_left_from >= 4)
+ {
+ ip6_header_t *ip0, *ip1, *ip2, *ip3;
+ u8 *hbh0, *hbh1, *hbh2, *hbh3;
+
+ /* Prefetch next iteration. */
+ if (PREDICT_TRUE (n_left_from >= 8))
+ {
+ vlib_prefetch_buffer_header (b[4], STORE);
+ vlib_prefetch_buffer_header (b[5], STORE);
+ vlib_prefetch_buffer_header (b[6], STORE);
+ vlib_prefetch_buffer_header (b[7], STORE);
+ CLIB_PREFETCH (b[4]->data, CLIB_CACHE_LINE_BYTES, STORE);
+ CLIB_PREFETCH (b[5]->data, CLIB_CACHE_LINE_BYTES, STORE);
+ CLIB_PREFETCH (b[6]->data, CLIB_CACHE_LINE_BYTES, STORE);
+ CLIB_PREFETCH (b[7]->data, CLIB_CACHE_LINE_BYTES, STORE);
+ }
+
+ /*
+ * Leave current_data pointing at the IP header.
+ * It's reasonably likely that any registered handler
+ * will want to know where to find the ip6 header.
+ */
+ ip0 = vlib_buffer_get_current (b[0]);
+ ip1 = vlib_buffer_get_current (b[1]);
+ ip2 = vlib_buffer_get_current (b[2]);
+ ip3 = vlib_buffer_get_current (b[3]);
+
+ /* Look at hop-by-hop header */
+ hbh0 = ip6_next_header (ip0);
+ hbh1 = ip6_next_header (ip1);
+ hbh2 = ip6_next_header (ip2);
+ hbh3 = ip6_next_header (ip3);
+
+ /*
+ * ... to find the next header type and see if we
+ * have a handler for it...
+ */
+ next[0] = rt->next_index_by_protocol[*hbh0];
+ next[1] = rt->next_index_by_protocol[*hbh1];
+ next[2] = rt->next_index_by_protocol[*hbh2];
+ next[3] = rt->next_index_by_protocol[*hbh3];
+
+ b[0]->error = unknown_proto_error;
+ b[1]->error = unknown_proto_error;
+ b[2]->error = unknown_proto_error;
+ b[3]->error = unknown_proto_error;
+
+ /* Account for non-drop pkts */
+ ok += next[0] != 0;
+ ok += next[1] != 0;
+ ok += next[2] != 0;
+ ok += next[3] != 0;
+
+ if (is_trace)
+ {
+ if (b[0]->flags & VLIB_BUFFER_IS_TRACED)
+ {
+ ip6_local_hop_by_hop_trace_t *t =
+ vlib_add_trace (vm, node, b[0], sizeof (*t));
+ t->next_index = next[0];
+ t->protocol = *hbh0;
+ }
+ if (b[1]->flags & VLIB_BUFFER_IS_TRACED)
+ {
+ ip6_local_hop_by_hop_trace_t *t =
+ vlib_add_trace (vm, node, b[1], sizeof (*t));
+ t->next_index = next[1];
+ t->protocol = *hbh1;
+ }
+ if (b[2]->flags & VLIB_BUFFER_IS_TRACED)
+ {
+ ip6_local_hop_by_hop_trace_t *t =
+ vlib_add_trace (vm, node, b[2], sizeof (*t));
+ t->next_index = next[2];
+ t->protocol = *hbh2;
+ }
+ if (b[3]->flags & VLIB_BUFFER_IS_TRACED)
+ {
+ ip6_local_hop_by_hop_trace_t *t =
+ vlib_add_trace (vm, node, b[3], sizeof (*t));
+ t->next_index = next[3];
+ t->protocol = *hbh3;
+ }
+ }
+
+ b += 4;
+ next += 4;
+ n_left_from -= 4;
+ }
+
+ while (n_left_from > 0)
+ {
+ ip6_header_t *ip0;
+ u8 *hbh0;
+
+ ip0 = vlib_buffer_get_current (b[0]);