summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMaxime Peim <mpeim@cisco.com>2023-07-11 09:45:56 +0200
committerBeno�t Ganne <bganne@cisco.com>2023-09-04 07:57:44 +0000
commit77812045e720d1434dd36a1db90c35daad0c8e00 (patch)
tree4588ff65542af1edec3474010c5a8120efb04705 /src
parent2ceb818f8eca4b8aebd0a4f2b36a641c832d8819 (diff)
tracenode: filtering feature
In order to be able to filter on encapsulated packet, a new node has been added to the ip4/6-unicast arcs. Type: feature Change-Id: I1e8ee05bc6d0fce20cadd8319c81bab260c17d21 Signed-off-by: Maxime Peim <mpeim@cisco.com>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/tracenode/CMakeLists.txt37
-rw-r--r--src/plugins/tracenode/FEATURE.yaml8
-rw-r--r--src/plugins/tracenode/api.c64
-rw-r--r--src/plugins/tracenode/cli.c72
-rw-r--r--src/plugins/tracenode/node.c145
-rw-r--r--src/plugins/tracenode/plugin.c31
-rw-r--r--src/plugins/tracenode/test.c93
-rw-r--r--src/plugins/tracenode/tracenode.api42
-rw-r--r--src/plugins/tracenode/tracenode.c71
-rw-r--r--src/plugins/tracenode/tracenode.h43
10 files changed, 606 insertions, 0 deletions
diff --git a/src/plugins/tracenode/CMakeLists.txt b/src/plugins/tracenode/CMakeLists.txt
new file mode 100644
index 00000000000..6b6ba2e9865
--- /dev/null
+++ b/src/plugins/tracenode/CMakeLists.txt
@@ -0,0 +1,37 @@
+
+# Copyright (c) 2023 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+add_vpp_plugin(tracenode
+ SOURCES
+ node.c
+ api.c
+ cli.c
+ plugin.c
+ tracenode.c
+
+ MULTIARCH_SOURCES
+ node.c
+
+ API_FILES
+ tracenode.api
+
+ INSTALL_HEADERS
+ tracenode.h
+
+ API_TEST_SOURCES
+ test.c
+
+ COMPONENT
+ vpp-plugin-devtools
+)
diff --git a/src/plugins/tracenode/FEATURE.yaml b/src/plugins/tracenode/FEATURE.yaml
new file mode 100644
index 00000000000..c405dd11d59
--- /dev/null
+++ b/src/plugins/tracenode/FEATURE.yaml
@@ -0,0 +1,8 @@
+---
+name: Trace node
+maintainer: Maxime Peim <mpeim@cisco.com>
+features:
+ - allow trace filtering on encapsulated (inner) packets
+description: "Allow tracing on IP feature arc. Encapsulated packets can then be traced and filtered."
+state: experimental
+properties: [CLI, API]
diff --git a/src/plugins/tracenode/api.c b/src/plugins/tracenode/api.c
new file mode 100644
index 00000000000..0b01ad8b9f5
--- /dev/null
+++ b/src/plugins/tracenode/api.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2023 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vlib/vlib.h>
+#include <tracenode/tracenode.h>
+#include <vlibmemory/api.h>
+
+/* define message IDs */
+#include <tracenode/tracenode.api_enum.h>
+#include <tracenode/tracenode.api_types.h>
+
+#define REPLY_MSG_ID_BASE (tnm->msg_id_base)
+#include <vlibapi/api_helper_macros.h>
+
+static void
+vl_api_tracenode_enable_disable_t_handler (
+ vl_api_tracenode_enable_disable_t *mp)
+{
+ tracenode_main_t *tnm = &tracenode_main;
+ vl_api_tracenode_enable_disable_reply_t *rmp;
+ int rv = 0;
+
+ VALIDATE_SW_IF_INDEX (mp);
+
+ rv = tracenode_feature_enable_disable (ntohl (mp->sw_if_index), mp->is_pcap,
+ mp->enable);
+
+ BAD_SW_IF_INDEX_LABEL;
+
+ REPLY_MACRO (VL_API_TRACENODE_ENABLE_DISABLE_REPLY);
+}
+
+#include <tracenode/tracenode.api.c>
+
+clib_error_t *
+tracenode_plugin_api_hookup (vlib_main_t *vm)
+{
+ tracenode_main_t *tnm = &tracenode_main;
+
+ /* ask for a correctly-sized block of API message decode slots */
+ tnm->msg_id_base = setup_message_id_table ();
+
+ return 0;
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */ \ No newline at end of file
diff --git a/src/plugins/tracenode/cli.c b/src/plugins/tracenode/cli.c
new file mode 100644
index 00000000000..8d0ed4176d6
--- /dev/null
+++ b/src/plugins/tracenode/cli.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2023 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vlib/vlib.h>
+#include <tracenode/tracenode.h>
+
+static clib_error_t *
+tracenode_feature_cmd_fn (vlib_main_t *vm, unformat_input_t *input,
+ vlib_cli_command_t *cmd)
+{
+ unformat_input_t _line_input, *line_input = &_line_input;
+ u32 sw_if_index = ~0;
+ int enable = 1, is_pcap = 0;
+ int rv;
+
+ /* Get a line of input. */
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return 0;
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "disable"))
+ enable = 0;
+ else if (unformat (line_input, "pcap"))
+ is_pcap = 1;
+ else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
+ vnet_get_main (), &sw_if_index))
+ {
+ if (sw_if_index == 0)
+ return clib_error_return (0, "Local interface not supported...");
+ }
+
+ else
+ break;
+ }
+
+ if (sw_if_index == ~0)
+ return clib_error_return (0, "Software interface required");
+
+ if ((rv = tracenode_feature_enable_disable (sw_if_index, is_pcap, enable)) !=
+ 0)
+ return clib_error_return (
+ 0, "vnet_enable_disable_tracenode_feature returned %d", rv);
+
+ return 0;
+}
+
+VLIB_CLI_COMMAND (tracenode_feature, static) = {
+ .path = "tracenode feature",
+ .short_help = "tracenode feature <intfc> [disable] [pcap]",
+ .function = tracenode_feature_cmd_fn,
+};
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/tracenode/node.c b/src/plugins/tracenode/node.c
new file mode 100644
index 00000000000..444d93f1708
--- /dev/null
+++ b/src/plugins/tracenode/node.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2023 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vlib/vlib.h>
+#include <vnet/feature/feature.h>
+#include <vnet/classify/pcap_classify.h>
+
+typedef struct
+{
+ u32 sw_if_index;
+} tracenode_trace_t;
+
+static u8 *
+format_tracenode_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 *);
+ vnet_main_t *vnm = vnet_get_main ();
+ tracenode_trace_t *t = va_arg (*args, tracenode_trace_t *);
+
+ s = format (s, "Packet traced from interface %U added",
+ format_vnet_sw_if_index_name, vnm, t->sw_if_index);
+ return s;
+}
+
+static_always_inline u32
+tracenode_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
+ vlib_frame_t *frame, int is_pcap)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ vnet_pcap_t *pp = &vnm->pcap;
+ vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
+ u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
+ u32 *from = vlib_frame_vector_args (frame), *from0 = from;
+ const u32 n_tot = frame->n_vectors;
+ u32 n_left = n_tot;
+
+ vlib_get_buffers (vm, from, b, n_tot);
+
+ while (n_left > 0)
+ {
+ /* TODO: dual/quad loop */
+
+ /* enqueue b0 to the current next frame */
+ vnet_feature_next_u16 (next, b[0]);
+
+ /* buffer already traced */
+ if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
+ goto skip;
+
+ if (is_pcap && vnet_is_packet_pcaped (pp, b[0], ~0))
+ {
+ pcap_add_buffer (&pp->pcap_main, vm, from0[0],
+ pp->max_bytes_per_pkt);
+ }
+ else if (!is_pcap && vlib_trace_buffer (vm, node, next[0], b[0],
+ 1 /* follow_chain */))
+ {
+ tracenode_trace_t *tr = vlib_add_trace (vm, node, b[0], sizeof *tr);
+ tr->sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
+ }
+
+ skip:
+ b++;
+ from0++;
+ next++;
+ n_left--;
+ }
+
+ vlib_buffer_enqueue_to_next (vm, node, from, nexts, n_tot);
+ return n_tot;
+}
+
+VLIB_NODE_FN (trace_filtering_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+ return tracenode_inline (vm, node, frame, 0 /* is_pcap */);
+}
+
+VLIB_NODE_FN (pcap_filtering_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+ return tracenode_inline (vm, node, frame, 1 /* is_pcap */);
+}
+
+VLIB_REGISTER_NODE (trace_filtering_node) = {
+ .name = "trace-filtering",
+ .vector_size = sizeof (u32),
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .format_trace = format_tracenode_trace,
+};
+
+VLIB_REGISTER_NODE (pcap_filtering_node) = {
+ .name = "pcap-filtering",
+ .vector_size = sizeof (u32),
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .format_trace = format_tracenode_trace,
+};
+
+VNET_FEATURE_INIT (trace_filtering4, static) = {
+ .arc_name = "ip4-unicast",
+ .node_name = "trace-filtering",
+ .runs_after = VNET_FEATURES ("ip4-full-reassembly-feature",
+ "ip4-sv-reassembly-feature"),
+};
+
+VNET_FEATURE_INIT (trace_filtering6, static) = {
+ .arc_name = "ip6-unicast",
+ .node_name = "trace-filtering",
+ .runs_after = VNET_FEATURES ("ip6-full-reassembly-feature",
+ "ip6-sv-reassembly-feature"),
+};
+
+VNET_FEATURE_INIT (pcap_filtering4, static) = {
+ .arc_name = "ip4-unicast",
+ .node_name = "pcap-filtering",
+ .runs_after = VNET_FEATURES ("ip4-full-reassembly-feature",
+ "ip4-sv-reassembly-feature"),
+};
+
+VNET_FEATURE_INIT (pcap_filtering6, static) = {
+ .arc_name = "ip6-unicast",
+ .node_name = "pcap-filtering",
+ .runs_after = VNET_FEATURES ("ip6-full-reassembly-feature",
+ "ip6-sv-reassembly-feature"),
+};
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/tracenode/plugin.c b/src/plugins/tracenode/plugin.c
new file mode 100644
index 00000000000..19ce6ba5610
--- /dev/null
+++ b/src/plugins/tracenode/plugin.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2023 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/plugin/plugin.h>
+#include <vpp/app/version.h>
+
+VLIB_PLUGIN_REGISTER () = {
+ .version = VPP_BUILD_VER,
+ .description = "Tracing packet node",
+};
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/tracenode/test.c b/src/plugins/tracenode/test.c
new file mode 100644
index 00000000000..a409fd2a59a
--- /dev/null
+++ b/src/plugins/tracenode/test.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2023 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vat/vat.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+#include <vppinfra/error.h>
+#include <vnet/api_errno.h>
+#include <stdbool.h>
+
+#define __plugin_msg_base tracenode_test_main.msg_id_base
+#include <vlibapi/vat_helper_macros.h>
+
+/* Declare message IDs */
+#include <tracenode/tracenode.api_enum.h>
+#include <tracenode/tracenode.api_types.h>
+
+typedef struct
+{
+ /* API message ID base */
+ u16 msg_id_base;
+ vat_main_t *vat_main;
+} tracenode_test_main_t;
+
+tracenode_test_main_t tracenode_test_main;
+
+int
+api_tracenode_enable_disable (vat_main_t *vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_tracenode_enable_disable_t *mp;
+ u32 sw_if_index;
+ bool is_pcap, enable;
+
+ sw_if_index = ~0;
+ is_pcap = false;
+ enable = true;
+
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "disable"))
+ enable = 0;
+ else if (unformat (i, "pcap"))
+ is_pcap = 1;
+ else if (unformat (i, "%U", unformat_vnet_sw_interface, vnet_get_main (),
+ &sw_if_index))
+ {
+ if (sw_if_index == 0)
+ {
+ clib_warning ("Local interface not supported...");
+ return -99;
+ }
+ }
+
+ else
+ {
+ clib_warning ("Unknown input: %U\n", format_unformat_error, i);
+ return -99;
+ }
+ }
+
+ M (TRACENODE_ENABLE_DISABLE, mp);
+ mp->sw_if_index = htonl (sw_if_index);
+ mp->is_pcap = is_pcap;
+ mp->enable = enable;
+
+ int ret = 0;
+ S (mp);
+ W (ret);
+
+ return ret;
+}
+
+#include <tracenode/tracenode.api_test.c>
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/tracenode/tracenode.api b/src/plugins/tracenode/tracenode.api
new file mode 100644
index 00000000000..198f8218b55
--- /dev/null
+++ b/src/plugins/tracenode/tracenode.api
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2023 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+option version = "0.1.0";
+
+import "vnet/interface_types.api";
+
+/** \brief Enable/disable trace filtering feature
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param sw_if_index - interface on which to enable/disable trace filtering feature
+ @param is_pcap - if non-zero enable the feature for pcap capture, else for trace
+ @param enable - if non-zero then enable the feature, else disable it
+*/
+autoreply define tracenode_enable_disable
+{
+ u32 client_index;
+ u32 context;
+ vl_api_interface_index_t sw_if_index;
+ bool is_pcap [default=false];
+ bool enable [default=true];
+
+ option vat_help = "tracenode_enable_disable <intfc> [disable] [pcap]";
+};
+
+/*
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/tracenode/tracenode.c b/src/plugins/tracenode/tracenode.c
new file mode 100644
index 00000000000..e292c7da95c
--- /dev/null
+++ b/src/plugins/tracenode/tracenode.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2023 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vlib/vlib.h>
+#include <tracenode/tracenode.h>
+
+tracenode_main_t tracenode_main;
+
+int
+tracenode_feature_enable_disable (u32 sw_if_index, bool is_pcap, bool enable)
+{
+ tracenode_main_t *tnm = &tracenode_main;
+ char *node_name = is_pcap ? "pcap-filtering" : "trace-filtering";
+ int rv = 0;
+
+ if (pool_is_free_index (tnm->vnet_main->interface_main.sw_interfaces,
+ sw_if_index))
+ return VNET_API_ERROR_INVALID_SW_IF_INDEX;
+
+ if (clib_bitmap_get (tnm->feature_enabled_by_sw_if, sw_if_index) == enable)
+ return 0;
+
+ if ((rv = vnet_feature_enable_disable ("ip4-unicast", node_name, sw_if_index,
+ enable, 0, 0)) != 0)
+ return rv;
+
+ if ((rv = vnet_feature_enable_disable ("ip6-unicast", node_name, sw_if_index,
+ enable, 0, 0)) != 0)
+ return rv;
+
+ tnm->feature_enabled_by_sw_if =
+ clib_bitmap_set (tnm->feature_enabled_by_sw_if, sw_if_index, enable);
+
+ return 0;
+}
+
+static clib_error_t *
+tracenode_init (vlib_main_t *vm)
+{
+ tracenode_main_t *tnm = &tracenode_main;
+ clib_error_t *error = 0;
+
+ memset (tnm, 0, sizeof (*tnm));
+
+ tnm->vnet_main = vnet_get_main ();
+
+ error = tracenode_plugin_api_hookup (vm);
+
+ return error;
+}
+
+VLIB_INIT_FUNCTION (tracenode_init);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/tracenode/tracenode.h b/src/plugins/tracenode/tracenode.h
new file mode 100644
index 00000000000..7af60aa20b1
--- /dev/null
+++ b/src/plugins/tracenode/tracenode.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2023 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _TRACENODE_H_
+#define _TRACENODE_H_
+#include <vlib/vlib.h>
+#include <vnet/feature/feature.h>
+#include <stdbool.h>
+
+typedef struct
+{
+ vnet_main_t *vnet_main;
+ uword *feature_enabled_by_sw_if;
+ u16 msg_id_base;
+} tracenode_main_t;
+
+extern tracenode_main_t tracenode_main;
+
+clib_error_t *tracenode_plugin_api_hookup (vlib_main_t *vm);
+
+int tracenode_feature_enable_disable (u32 sw_if_index, bool is_pcap,
+ bool enable);
+
+#endif /* _TRACENODE_H_ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */