aboutsummaryrefslogtreecommitdiffstats
path: root/src/examples
diff options
context:
space:
mode:
Diffstat (limited to 'src/examples')
-rw-r--r--src/examples/sample-plugin/Makefile.am59
-rw-r--r--src/examples/sample-plugin/configure.ac11
-rw-r--r--src/examples/sample-plugin/sample.am31
-rw-r--r--src/examples/sample-plugin/sample/node.c295
-rw-r--r--src/examples/sample-plugin/sample/sample.api31
-rw-r--r--src/examples/sample-plugin/sample/sample.c238
-rw-r--r--src/examples/sample-plugin/sample/sample.h40
-rw-r--r--src/examples/sample-plugin/sample/sample_all_api_h.h16
-rw-r--r--src/examples/sample-plugin/sample/sample_msg_enum.h28
-rw-r--r--src/examples/sample-plugin/sample/sample_test.c180
-rw-r--r--src/examples/sample-plugin/sample_plugin_doc.md66
-rw-r--r--src/examples/srv6-sample-localsid/node.c261
-rwxr-xr-xsrc/examples/srv6-sample-localsid/srv6_localsid_sample.c179
-rw-r--r--src/examples/srv6-sample-localsid/srv6_localsid_sample.h61
-rw-r--r--src/examples/srv6-sample-localsid/srv6_sample_localsid_doc.md30
-rw-r--r--src/examples/vlib/dir.dox22
-rw-r--r--src/examples/vlib/main_stub.c417
-rw-r--r--src/examples/vlib/mc_test.c384
-rw-r--r--src/examples/vlib/plex_test.c527
19 files changed, 2876 insertions, 0 deletions
diff --git a/src/examples/sample-plugin/Makefile.am b/src/examples/sample-plugin/Makefile.am
new file mode 100644
index 00000000..a3a9a8d6
--- /dev/null
+++ b/src/examples/sample-plugin/Makefile.am
@@ -0,0 +1,59 @@
+# Copyright (c) 2015 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.
+
+AUTOMAKE_OPTIONS = foreign subdir-objects
+
+AM_CFLAGS = -Wall -I${top_srcdir} -I${top_builddir}
+AM_LDFLAGS = -module -shared -avoid-version
+AM_LIBTOOLFLAGS = --quiet
+SUFFIXES = .api.h .api .api.json
+API_FILES =
+BUILT_SOURCES =
+vppplugins_LTLIBRARIES =
+vppapitestplugins_LTLIBRARIES =
+noinst_HEADERS =
+nobase_apiinclude_HEADERS =
+ACLOCAL_AMFLAGS = -I m4
+
+vppapitestpluginsdir = ${libdir}/vpp_api_test_plugins
+vpppluginsdir = ${libdir}/vpp_plugins
+
+include sample.am
+
+%.api.h: %.api
+ mkdir -p `dirname $@` ; \
+ $(CC) $(CPPFLAGS) -E -P -C -x c $^ \
+ | vppapigen --input - --output $@ --show-name $@
+
+%.api.json: %.api
+ @echo " JSON APIGEN " $@ ; \
+ mkdir -p `dirname $@` ; \
+ $(CC) $(CPPFLAGS) -E -P -C -x c $^ \
+ | vppapigen --input - --json $@
+
+apidir = $(prefix)/api/plugins
+apiincludedir = ${includedir}/vpp_plugins
+
+api_DATA = \
+ $(patsubst %.api,%.api.json,$(API_FILES))
+
+BUILT_SOURCES += \
+ $(patsubst %.api,%.api.h,$(API_FILES))
+
+
+# Remove *.la files
+install-data-hook:
+ @(cd $(vpppluginsdir) && $(RM) $(vppplugins_LTLIBRARIES))
+ @(cd $(vppapitestpluginsdir) && $(RM) $(vppapitestplugins_LTLIBRARIES))
+
+CLEANFILES = $(BUILT_SOURCES)
diff --git a/src/examples/sample-plugin/configure.ac b/src/examples/sample-plugin/configure.ac
new file mode 100644
index 00000000..204da2fe
--- /dev/null
+++ b/src/examples/sample-plugin/configure.ac
@@ -0,0 +1,11 @@
+AC_INIT(vpp_plugins, 1.0)
+LT_INIT
+AM_INIT_AUTOMAKE
+AM_SILENT_RULES([yes])
+AC_PREFIX_DEFAULT([/usr])
+
+AC_PROG_CC
+
+AC_OUTPUT([Makefile])
+
+AC_CONFIG_MACRO_DIR([m4])
diff --git a/src/examples/sample-plugin/sample.am b/src/examples/sample-plugin/sample.am
new file mode 100644
index 00000000..871b610a
--- /dev/null
+++ b/src/examples/sample-plugin/sample.am
@@ -0,0 +1,31 @@
+# Copyright (c) 2016 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.
+
+vppapitestplugins_LTLIBRARIES += sample_test_plugin.la
+vppplugins_LTLIBRARIES += sample_plugin.la
+
+sample_plugin_la_SOURCES = \
+ sample/sample.c \
+ sample/node.c \
+ sample/sample_plugin.api.h
+
+API_FILES += sample/sample.api
+
+nobase_apiinclude_HEADERS += \
+ sample/sample_all_api_h.h \
+ sample/sample_msg_enum.h \
+ sample/sample.api.h
+
+sample_test_plugin_la_SOURCES = sample/sample_test.c sample/sample_plugin.api.h
+
+# vi:syntax=automake
diff --git a/src/examples/sample-plugin/sample/node.c b/src/examples/sample-plugin/sample/node.c
new file mode 100644
index 00000000..94c1706b
--- /dev/null
+++ b/src/examples/sample-plugin/sample/node.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2015 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/vnet.h>
+#include <vnet/pg/pg.h>
+#include <vppinfra/error.h>
+#include <sample/sample.h>
+
+typedef struct {
+ u32 next_index;
+ u32 sw_if_index;
+ u8 new_src_mac[6];
+ u8 new_dst_mac[6];
+} sample_trace_t;
+
+static u8 *
+format_mac_address (u8 * s, va_list * args)
+{
+ u8 *a = va_arg (*args, u8 *);
+ return format (s, "%02x:%02x:%02x:%02x:%02x:%02x",
+ a[0], a[1], a[2], a[3], a[4], a[5]);
+}
+
+/* packet trace format function */
+static u8 * format_sample_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 *);
+ sample_trace_t * t = va_arg (*args, sample_trace_t *);
+
+ s = format (s, "SAMPLE: sw_if_index %d, next index %d\n",
+ t->sw_if_index, t->next_index);
+ s = format (s, " new src %U -> new dst %U",
+ format_mac_address, t->new_src_mac,
+ format_mac_address, t->new_dst_mac);
+
+ return s;
+}
+
+vlib_node_registration_t sample_node;
+
+#define foreach_sample_error \
+_(SWAPPED, "Mac swap packets processed")
+
+typedef enum {
+#define _(sym,str) SAMPLE_ERROR_##sym,
+ foreach_sample_error
+#undef _
+ SAMPLE_N_ERROR,
+} sample_error_t;
+
+static char * sample_error_strings[] = {
+#define _(sym,string) string,
+ foreach_sample_error
+#undef _
+};
+
+typedef enum {
+ SAMPLE_NEXT_INTERFACE_OUTPUT,
+ SAMPLE_N_NEXT,
+} sample_next_t;
+
+#define foreach_mac_address_offset \
+_(0) \
+_(1) \
+_(2) \
+_(3) \
+_(4) \
+_(5)
+
+static uword
+sample_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ u32 n_left_from, * from, * to_next;
+ sample_next_t next_index;
+ u32 pkts_swapped = 0;
+
+ from = vlib_frame_vector_args (frame);
+ n_left_from = frame->n_vectors;
+ next_index = node->cached_next_index;
+
+ while (n_left_from > 0)
+ {
+ u32 n_left_to_next;
+
+ vlib_get_next_frame (vm, node, next_index,
+ to_next, n_left_to_next);
+
+ while (n_left_from >= 4 && n_left_to_next >= 2)
+ {
+ u32 next0 = SAMPLE_NEXT_INTERFACE_OUTPUT;
+ u32 next1 = SAMPLE_NEXT_INTERFACE_OUTPUT;
+ u32 sw_if_index0, sw_if_index1;
+ u8 tmp0[6], tmp1[6];
+ ethernet_header_t *en0, *en1;
+ u32 bi0, bi1;
+ vlib_buffer_t * b0, * b1;
+
+ /* Prefetch next iteration. */
+ {
+ vlib_buffer_t * p2, * p3;
+
+ p2 = vlib_get_buffer (vm, from[2]);
+ p3 = vlib_get_buffer (vm, from[3]);
+
+ vlib_prefetch_buffer_header (p2, LOAD);
+ vlib_prefetch_buffer_header (p3, LOAD);
+
+ CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
+ CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
+ }
+
+ /* speculatively enqueue b0 and b1 to the current next frame */
+ to_next[0] = bi0 = from[0];
+ to_next[1] = bi1 = from[1];
+ from += 2;
+ to_next += 2;
+ n_left_from -= 2;
+ n_left_to_next -= 2;
+
+ b0 = vlib_get_buffer (vm, bi0);
+ b1 = vlib_get_buffer (vm, bi1);
+
+ ASSERT (b0->current_data == 0);
+ ASSERT (b1->current_data == 0);
+
+ en0 = vlib_buffer_get_current (b0);
+ en1 = vlib_buffer_get_current (b1);
+
+ /* This is not the fastest way to swap src + dst mac addresses */
+#define _(a) tmp0[a] = en0->src_address[a];
+ foreach_mac_address_offset;
+#undef _
+#define _(a) en0->src_address[a] = en0->dst_address[a];
+ foreach_mac_address_offset;
+#undef _
+#define _(a) en0->dst_address[a] = tmp0[a];
+ foreach_mac_address_offset;
+#undef _
+
+#define _(a) tmp1[a] = en1->src_address[a];
+ foreach_mac_address_offset;
+#undef _
+#define _(a) en1->src_address[a] = en1->dst_address[a];
+ foreach_mac_address_offset;
+#undef _
+#define _(a) en1->dst_address[a] = tmp1[a];
+ foreach_mac_address_offset;
+#undef _
+
+
+
+ sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
+ sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
+
+ /* Send pkt back out the RX interface */
+ vnet_buffer(b0)->sw_if_index[VLIB_TX] = sw_if_index0;
+ vnet_buffer(b1)->sw_if_index[VLIB_TX] = sw_if_index1;
+
+ pkts_swapped += 2;
+
+ if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)))
+ {
+ if (b0->flags & VLIB_BUFFER_IS_TRACED)
+ {
+ sample_trace_t *t =
+ vlib_add_trace (vm, node, b0, sizeof (*t));
+ t->sw_if_index = sw_if_index0;
+ t->next_index = next0;
+ clib_memcpy (t->new_src_mac, en0->src_address,
+ sizeof (t->new_src_mac));
+ clib_memcpy (t->new_dst_mac, en0->dst_address,
+ sizeof (t->new_dst_mac));
+
+ }
+ if (b1->flags & VLIB_BUFFER_IS_TRACED)
+ {
+ sample_trace_t *t =
+ vlib_add_trace (vm, node, b1, sizeof (*t));
+ t->sw_if_index = sw_if_index1;
+ t->next_index = next1;
+ clib_memcpy (t->new_src_mac, en1->src_address,
+ sizeof (t->new_src_mac));
+ clib_memcpy (t->new_dst_mac, en1->dst_address,
+ sizeof (t->new_dst_mac));
+ }
+ }
+
+ /* verify speculative enqueues, maybe switch current next frame */
+ vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
+ to_next, n_left_to_next,
+ bi0, bi1, next0, next1);
+ }
+
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ u32 bi0;
+ vlib_buffer_t * b0;
+ u32 next0 = SAMPLE_NEXT_INTERFACE_OUTPUT;
+ u32 sw_if_index0;
+ u8 tmp0[6];
+ ethernet_header_t *en0;
+
+ /* speculatively enqueue b0 to the current next frame */
+ bi0 = from[0];
+ to_next[0] = bi0;
+ from += 1;
+ to_next += 1;
+ n_left_from -= 1;
+ n_left_to_next -= 1;
+
+ b0 = vlib_get_buffer (vm, bi0);
+ /*
+ * Direct from the driver, we should be at offset 0
+ * aka at &b0->data[0]
+ */
+ ASSERT (b0->current_data == 0);
+
+ en0 = vlib_buffer_get_current (b0);
+
+ /* This is not the fastest way to swap src + dst mac addresses */
+#define _(a) tmp0[a] = en0->src_address[a];
+ foreach_mac_address_offset;
+#undef _
+#define _(a) en0->src_address[a] = en0->dst_address[a];
+ foreach_mac_address_offset;
+#undef _
+#define _(a) en0->dst_address[a] = tmp0[a];
+ foreach_mac_address_offset;
+#undef _
+
+ sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
+
+ /* Send pkt back out the RX interface */
+ vnet_buffer(b0)->sw_if_index[VLIB_TX] = sw_if_index0;
+
+ if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
+ && (b0->flags & VLIB_BUFFER_IS_TRACED))) {
+ sample_trace_t *t =
+ vlib_add_trace (vm, node, b0, sizeof (*t));
+ t->sw_if_index = sw_if_index0;
+ t->next_index = next0;
+ clib_memcpy (t->new_src_mac, en0->src_address,
+ sizeof (t->new_src_mac));
+ clib_memcpy (t->new_dst_mac, en0->dst_address,
+ sizeof (t->new_dst_mac));
+ }
+
+ pkts_swapped += 1;
+
+ /* verify speculative enqueue, maybe switch current next frame */
+ vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
+ to_next, n_left_to_next,
+ bi0, next0);
+ }
+
+ vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+ }
+
+ vlib_node_increment_counter (vm, sample_node.index,
+ SAMPLE_ERROR_SWAPPED, pkts_swapped);
+ return frame->n_vectors;
+}
+
+VLIB_REGISTER_NODE (sample_node) = {
+ .function = sample_node_fn,
+ .name = "sample",
+ .vector_size = sizeof (u32),
+ .format_trace = format_sample_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(sample_error_strings),
+ .error_strings = sample_error_strings,
+
+ .n_next_nodes = SAMPLE_N_NEXT,
+
+ /* edit / add dispositions here */
+ .next_nodes = {
+ [SAMPLE_NEXT_INTERFACE_OUTPUT] = "interface-output",
+ },
+};
diff --git a/src/examples/sample-plugin/sample/sample.api b/src/examples/sample-plugin/sample/sample.api
new file mode 100644
index 00000000..d565c0b1
--- /dev/null
+++ b/src/examples/sample-plugin/sample/sample.api
@@ -0,0 +1,31 @@
+/* Hey Emacs use -*- mode: C -*- */
+/*
+ * Copyright (c) 2015 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.
+ */
+
+/* Define a simple binary API to control the feature */
+
+autoreply define sample_macswap_enable_disable {
+ /* Client identifier, set from api_main.my_client_index */
+ u32 client_index;
+
+ /* Arbitrary context, so client can match reply to request */
+ u32 context;
+
+ /* Enable / disable the feature */
+ u8 enable_disable;
+
+ /* Interface handle */
+ u32 sw_if_index;
+};
diff --git a/src/examples/sample-plugin/sample/sample.c b/src/examples/sample-plugin/sample/sample.c
new file mode 100644
index 00000000..3929ac23
--- /dev/null
+++ b/src/examples/sample-plugin/sample/sample.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2015 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.
+ */
+/**
+ * @file
+ * @brief Sample Plugin, plugin API / trace / CLI handling.
+ */
+
+#include <vnet/vnet.h>
+#include <vnet/plugin/plugin.h>
+#include <sample/sample.h>
+
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+#include <vlibsocket/api.h>
+
+/* define message IDs */
+#include <sample/sample_msg_enum.h>
+
+/* define message structures */
+#define vl_typedefs
+#include <sample/sample_all_api_h.h>
+#undef vl_typedefs
+
+/* define generated endian-swappers */
+#define vl_endianfun
+#include <sample/sample_all_api_h.h>
+#undef vl_endianfun
+
+/* instantiate all the print functions we know about */
+#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
+#define vl_printfun
+#include <sample/sample_all_api_h.h>
+#undef vl_printfun
+
+/* Get the API version number */
+#define vl_api_version(n,v) static u32 api_version=(v);
+#include <sample/sample_all_api_h.h>
+#undef vl_api_version
+
+#define REPLY_MSG_ID_BASE sm->msg_id_base
+#include <vlibapi/api_helper_macros.h>
+
+/* List of message types that this plugin understands */
+
+#define foreach_sample_plugin_api_msg \
+_(SAMPLE_MACSWAP_ENABLE_DISABLE, sample_macswap_enable_disable)
+
+/* *INDENT-OFF* */
+VLIB_PLUGIN_REGISTER () = {
+ .version = SAMPLE_PLUGIN_BUILD_VER,
+ .description = "Sample of VPP Plugin",
+};
+/* *INDENT-ON* */
+
+/**
+ * @brief Enable/disable the macswap plugin.
+ *
+ * Action function shared between message handler and debug CLI.
+ */
+
+int sample_macswap_enable_disable (sample_main_t * sm, u32 sw_if_index,
+ int enable_disable)
+{
+ vnet_sw_interface_t * sw;
+ int rv = 0;
+
+ /* Utterly wrong? */
+ if (pool_is_free_index (sm->vnet_main->interface_main.sw_interfaces,
+ sw_if_index))
+ return VNET_API_ERROR_INVALID_SW_IF_INDEX;
+
+ /* Not a physical port? */
+ sw = vnet_get_sw_interface (sm->vnet_main, sw_if_index);
+ if (sw->type != VNET_SW_INTERFACE_TYPE_HARDWARE)
+ return VNET_API_ERROR_INVALID_SW_IF_INDEX;
+
+ vnet_feature_enable_disable ("device-input", "sample",
+ sw_if_index, enable_disable, 0, 0);
+
+ return rv;
+}
+
+static clib_error_t *
+macswap_enable_disable_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ sample_main_t * sm = &sample_main;
+ u32 sw_if_index = ~0;
+ int enable_disable = 1;
+
+ int rv;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
+ if (unformat (input, "disable"))
+ enable_disable = 0;
+ else if (unformat (input, "%U", unformat_vnet_sw_interface,
+ sm->vnet_main, &sw_if_index))
+ ;
+ else
+ break;
+ }
+
+ if (sw_if_index == ~0)
+ return clib_error_return (0, "Please specify an interface...");
+
+ rv = sample_macswap_enable_disable (sm, sw_if_index, enable_disable);
+
+ switch(rv) {
+ case 0:
+ break;
+
+ case VNET_API_ERROR_INVALID_SW_IF_INDEX:
+ return clib_error_return
+ (0, "Invalid interface, only works on physical ports");
+ break;
+
+ case VNET_API_ERROR_UNIMPLEMENTED:
+ return clib_error_return (0, "Device driver doesn't support redirection");
+ break;
+
+ default:
+ return clib_error_return (0, "sample_macswap_enable_disable returned %d",
+ rv);
+ }
+ return 0;
+}
+
+/**
+ * @brief CLI command to enable/disable the sample macswap plugin.
+ */
+VLIB_CLI_COMMAND (sr_content_command, static) = {
+ .path = "sample macswap",
+ .short_help =
+ "sample macswap <interface-name> [disable]",
+ .function = macswap_enable_disable_command_fn,
+};
+
+/**
+ * @brief Plugin API message handler.
+ */
+static void vl_api_sample_macswap_enable_disable_t_handler
+(vl_api_sample_macswap_enable_disable_t * mp)
+{
+ vl_api_sample_macswap_enable_disable_reply_t * rmp;
+ sample_main_t * sm = &sample_main;
+ int rv;
+
+ rv = sample_macswap_enable_disable (sm, ntohl(mp->sw_if_index),
+ (int) (mp->enable_disable));
+
+ REPLY_MACRO(VL_API_SAMPLE_MACSWAP_ENABLE_DISABLE_REPLY);
+}
+
+/**
+ * @brief Set up the API message handling tables.
+ */
+static clib_error_t *
+sample_plugin_api_hookup (vlib_main_t *vm)
+{
+ sample_main_t * sm = &sample_main;
+#define _(N,n) \
+ vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base), \
+ #n, \
+ vl_api_##n##_t_handler, \
+ vl_noop_handler, \
+ vl_api_##n##_t_endian, \
+ vl_api_##n##_t_print, \
+ sizeof(vl_api_##n##_t), 1);
+ foreach_sample_plugin_api_msg;
+#undef _
+
+ return 0;
+}
+
+#define vl_msg_name_crc_list
+#include <sample/sample_all_api_h.h>
+#undef vl_msg_name_crc_list
+
+static void
+setup_message_id_table (sample_main_t * sm, api_main_t *am)
+{
+#define _(id,n,crc) \
+ vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base);
+ foreach_vl_msg_name_crc_sample;
+#undef _
+}
+
+/**
+ * @brief Initialize the sample plugin.
+ */
+static clib_error_t * sample_init (vlib_main_t * vm)
+{
+ sample_main_t * sm = &sample_main;
+ clib_error_t * error = 0;
+ u8 * name;
+
+ sm->vnet_main = vnet_get_main ();
+
+ name = format (0, "sample_%08x%c", api_version, 0);
+
+ /* Ask for a correctly-sized block of API message decode slots */
+ sm->msg_id_base = vl_msg_api_get_msg_ids
+ ((char *) name, VL_MSG_FIRST_AVAILABLE);
+
+ error = sample_plugin_api_hookup (vm);
+
+ /* Add our API messages to the global name_crc hash table */
+ setup_message_id_table (sm, &api_main);
+
+ vec_free(name);
+
+ return error;
+}
+
+VLIB_INIT_FUNCTION (sample_init);
+
+/**
+ * @brief Hook the sample plugin into the VPP graph hierarchy.
+ */
+VNET_FEATURE_INIT (sample, static) =
+{
+ .arc_name = "device-input",
+ .node_name = "sample",
+ .runs_before = VNET_FEATURES ("ethernet-input"),
+};
diff --git a/src/examples/sample-plugin/sample/sample.h b/src/examples/sample-plugin/sample/sample.h
new file mode 100644
index 00000000..c9778f74
--- /dev/null
+++ b/src/examples/sample-plugin/sample/sample.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015 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 __included_sample_h__
+#define __included_sample_h__
+
+#include <vnet/vnet.h>
+#include <vnet/ip/ip.h>
+#include <vnet/ethernet/ethernet.h>
+
+#include <vppinfra/hash.h>
+#include <vppinfra/error.h>
+#include <vppinfra/elog.h>
+
+typedef struct {
+ /* API message ID base */
+ u16 msg_id_base;
+
+ /* convenience */
+ vnet_main_t * vnet_main;
+} sample_main_t;
+
+sample_main_t sample_main;
+
+extern vlib_node_registration_t sample_node;
+
+#define SAMPLE_PLUGIN_BUILD_VER "1.0"
+
+#endif /* __included_sample_h__ */
diff --git a/src/examples/sample-plugin/sample/sample_all_api_h.h b/src/examples/sample-plugin/sample/sample_all_api_h.h
new file mode 100644
index 00000000..774d782f
--- /dev/null
+++ b/src/examples/sample-plugin/sample/sample_all_api_h.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2015 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 the generated file, see BUILT_SOURCES in Makefile.am */
+#include <sample/sample.api.h>
diff --git a/src/examples/sample-plugin/sample/sample_msg_enum.h b/src/examples/sample-plugin/sample/sample_msg_enum.h
new file mode 100644
index 00000000..af4172f7
--- /dev/null
+++ b/src/examples/sample-plugin/sample/sample_msg_enum.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015 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 included_sample_msg_enum_h
+#define included_sample_msg_enum_h
+
+#include <vppinfra/byte_order.h>
+
+#define vl_msg_id(n,h) n,
+typedef enum {
+#include <sample/sample_all_api_h.h>
+ /* We'll want to know how many messages IDs we need... */
+ VL_MSG_FIRST_AVAILABLE,
+} vl_msg_id_t;
+#undef vl_msg_id
+
+#endif /* included_sample_msg_enum_h */
diff --git a/src/examples/sample-plugin/sample/sample_test.c b/src/examples/sample-plugin/sample/sample_test.c
new file mode 100644
index 00000000..2298675b
--- /dev/null
+++ b/src/examples/sample-plugin/sample/sample_test.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2015 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.
+ */
+/*
+ *------------------------------------------------------------------
+ * sample_test.c - test harness plugin
+ *------------------------------------------------------------------
+ */
+
+#include <vat/vat.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+#include <vlibsocket/api.h>
+#include <vppinfra/error.h>
+
+#define __plugin_msg_base sample_test_main.msg_id_base
+#include <vlibapi/vat_helper_macros.h>
+
+uword unformat_sw_if_index (unformat_input_t * input, va_list * args);
+
+/* Declare message IDs */
+#include <sample/sample_msg_enum.h>
+
+/* define message structures */
+#define vl_typedefs
+#include <sample/sample_all_api_h.h>
+#undef vl_typedefs
+
+/* declare message handlers for each api */
+
+#define vl_endianfun /* define message structures */
+#include <sample/sample_all_api_h.h>
+#undef vl_endianfun
+
+/* instantiate all the print functions we know about */
+#define vl_print(handle, ...)
+#define vl_printfun
+#include <sample/sample_all_api_h.h>
+#undef vl_printfun
+
+/* Get the API version number. */
+#define vl_api_version(n,v) static u32 api_version=(v);
+#include <sample/sample_all_api_h.h>
+#undef vl_api_version
+
+
+typedef struct {
+ /* API message ID base */
+ u16 msg_id_base;
+ vat_main_t *vat_main;
+} sample_test_main_t;
+
+sample_test_main_t sample_test_main;
+
+#define foreach_standard_reply_retval_handler \
+_(sample_macswap_enable_disable_reply)
+
+#define _(n) \
+ static void vl_api_##n##_t_handler \
+ (vl_api_##n##_t * mp) \
+ { \
+ vat_main_t * vam = sample_test_main.vat_main; \
+ i32 retval = ntohl(mp->retval); \
+ if (vam->async_mode) { \
+ vam->async_errors += (retval < 0); \
+ } else { \
+ vam->retval = retval; \
+ vam->result_ready = 1; \
+ } \
+ }
+foreach_standard_reply_retval_handler;
+#undef _
+
+/*
+ * Table of message reply handlers, must include boilerplate handlers
+ * we just generated
+ */
+#define foreach_vpe_api_reply_msg \
+_(SAMPLE_MACSWAP_ENABLE_DISABLE_REPLY, sample_macswap_enable_disable_reply)
+
+
+static int api_sample_macswap_enable_disable (vat_main_t * vam)
+{
+ unformat_input_t * i = vam->input;
+ int enable_disable = 1;
+ u32 sw_if_index = ~0;
+ vl_api_sample_macswap_enable_disable_t * mp;
+ int ret;
+
+ /* Parse args required to build the message */
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) {
+ if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
+ ;
+ else if (unformat (i, "sw_if_index %d", &sw_if_index))
+ ;
+ else if (unformat (i, "disable"))
+ enable_disable = 0;
+ else
+ break;
+ }
+
+ if (sw_if_index == ~0) {
+ errmsg ("missing interface name / explicit sw_if_index number \n");
+ return -99;
+ }
+
+ /* Construct the API message */
+ M(SAMPLE_MACSWAP_ENABLE_DISABLE, mp);
+ mp->sw_if_index = ntohl (sw_if_index);
+ mp->enable_disable = enable_disable;
+
+ /* send it... */
+ S(mp);
+
+ /* Wait for a reply... */
+ W (ret);
+ return ret;
+}
+
+/*
+ * List of messages that the api test plugin sends,
+ * and that the data plane plugin processes
+ */
+#define foreach_vpe_api_msg \
+_(sample_macswap_enable_disable, "<intfc> [disable]")
+
+static void sample_api_hookup (vat_main_t *vam)
+{
+ sample_test_main_t * sm = &sample_test_main;
+ /* Hook up handlers for replies from the data plane plug-in */
+#define _(N,n) \
+ vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base), \
+ #n, \
+ vl_api_##n##_t_handler, \
+ vl_noop_handler, \
+ vl_api_##n##_t_endian, \
+ vl_api_##n##_t_print, \
+ sizeof(vl_api_##n##_t), 1);
+ foreach_vpe_api_reply_msg;
+#undef _
+
+ /* API messages we can send */
+#define _(n,h) hash_set_mem (vam->function_by_name, #n, api_##n);
+ foreach_vpe_api_msg;
+#undef _
+
+ /* Help strings */
+#define _(n,h) hash_set_mem (vam->help_by_name, #n, h);
+ foreach_vpe_api_msg;
+#undef _
+}
+
+clib_error_t * vat_plugin_register (vat_main_t *vam)
+{
+ sample_test_main_t * sm = &sample_test_main;
+ u8 * name;
+
+ sm->vat_main = vam;
+
+ name = format (0, "sample_%08x%c", api_version, 0);
+ sm->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name);
+
+ if (sm->msg_id_base != (u16) ~0)
+ sample_api_hookup (vam);
+
+ vec_free(name);
+
+ return 0;
+}
diff --git a/src/examples/sample-plugin/sample_plugin_doc.md b/src/examples/sample-plugin/sample_plugin_doc.md
new file mode 100644
index 00000000..501a8dca
--- /dev/null
+++ b/src/examples/sample-plugin/sample_plugin_doc.md
@@ -0,0 +1,66 @@
+# Sample plugin for VPP {#sample_plugin_doc}
+
+## Overview
+
+This is the VPP sample plugin demonstrates how to create a new plugin that integrates
+with VPP. The sample code implements a trival macswap algorithim that demonstrates plugin
+runtime integration with the VPP graph hierachy, api and cli.
+
+For deeper dive information see the annotations in the sample code itself. See [sample.c](@ref sample.c)
+
+## How to build and run the sample plugin.
+
+Now (re)build VPP.
+
+ $ make wipe
+
+Define environmental variable 'VPP_WITH_SAMPLE_PLUGIN=yes' with a process scope
+
+ $ VPP_WITH_SAMPLE_PLUGIN=yes make build
+
+or a session scope, and build VPP.
+
+ $ export VPP_WITH_SAMPLE_PLUGIN=yes
+ & make build
+
+Now run VPP and make sure the plugin is loaded.
+
+ $ make run
+ ...
+ load_one_plugin:184: Loaded plugin: memif_plugin.so (Packet Memory Interface (experimetal))
+ load_one_plugin:184: Loaded plugin: sample_plugin.so (Sample of VPP Plugin)
+ load_one_plugin:184: Loaded plugin: nat_plugin.so (Network Address Translation)
+ ...
+ DBGvpp#
+
+## How to create a new plugin
+
+To create a new plugin based on the sample plugin, copy and rename the sample plugin directory and automake config.
+
+ cp -r src/examples/sample-plugin/sample src/plugins/newplugin
+ cp src/examples/sample-plugin/sample.am src/plugins/newplugin.am
+
+Add the following entry to the plugins section of `src/configure.ac`.
+
+ PLUGIN_ENABLED(newplugin)
+
+Add the following entry to the plugins section of `src/plugins/Makefile.am`
+
+ if ENABLE_NEWPLUGIN
+ include newplugin.am
+ endif
+
+Now (re)build VPP.
+
+ $ make wipe
+ $ make build
+
+## Configuration
+
+To enable the sample plugin
+
+ sample macswap <interface name>
+
+To disable the sample plugin
+
+ sample macswap <interface name> disable
diff --git a/src/examples/srv6-sample-localsid/node.c b/src/examples/srv6-sample-localsid/node.c
new file mode 100644
index 00000000..3ac7108b
--- /dev/null
+++ b/src/examples/srv6-sample-localsid/node.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2015 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/vnet.h>
+#include <vnet/pg/pg.h>
+#include <vppinfra/error.h>
+#include <srv6-localsid/srv6_localsid_sample.h>
+
+typedef struct {
+ u32 localsid_index;
+} srv6_localsid_sample_trace_t;
+
+/* packet trace format function */
+static u8 * format_srv6_localsid_sample_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 *);
+ srv6_localsid_sample_trace_t * t = va_arg (*args, srv6_localsid_sample_trace_t *);
+ s = format (s, "SRv6-sample-localsid: localsid_index %d\n",
+ t->localsid_index);
+ return s;
+}
+
+vlib_node_registration_t srv6_localsid_sample_node;
+
+#define foreach_srv6_localsid_counter \
+_(PROCESSED, "srv6-sample-localsid processed packets") \
+_(NO_SRH, "(Error) No SRH.")
+
+typedef enum {
+#define _(sym,str) SRV6_LOCALSID_COUNTER_##sym,
+ foreach_srv6_localsid_counter
+#undef _
+ SRV6_LOCALSID_N_COUNTERS,
+} srv6_localsid_sample_counters;
+
+static char * srv6_localsid_counter_strings[] = {
+#define _(sym,string) string,
+ foreach_srv6_localsid_counter
+#undef _
+};
+
+typedef enum {
+ SRV6_SAMPLE_LOCALSID_NEXT_ERROR,
+ SRV6_SAMPLE_LOCALSID_NEXT_IP6LOOKUP,
+ SRV6_SAMPLE_LOCALSID_N_NEXT,
+} srv6_localsid_sample_next_t;
+
+/**
+ * @brief Function doing End processing.
+ */
+static_always_inline void
+end_srh_processing (vlib_node_runtime_t * node,
+ vlib_buffer_t * b0,
+ ip6_header_t * ip0,
+ ip6_sr_header_t * sr0,
+ ip6_sr_localsid_t * ls0,
+ u32 * next0,
+ u8 psp,
+ ip6_ext_header_t * prev0)
+{
+ ip6_address_t *new_dst0;
+
+ if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
+ {
+ if (sr0->segments_left == 1 && psp)
+ {
+ u32 new_l0, sr_len;
+ u64 *copy_dst0, *copy_src0;
+ u32 copy_len_u64s0 = 0;
+
+ ip0->dst_address.as_u64[0] = sr0->segments->as_u64[0];
+ ip0->dst_address.as_u64[1] = sr0->segments->as_u64[1];
+
+ /* Remove the SRH taking care of the rest of IPv6 ext header */
+ if (prev0)
+ prev0->next_hdr = sr0->protocol;
+ else
+ ip0->protocol = sr0->protocol;
+
+ sr_len = ip6_ext_header_len (sr0);
+ vlib_buffer_advance (b0, sr_len);
+ new_l0 = clib_net_to_host_u16 (ip0->payload_length) - sr_len;
+ ip0->payload_length = clib_host_to_net_u16 (new_l0);
+ copy_src0 = (u64 *) ip0;
+ copy_dst0 = copy_src0 + (sr0->length + 1);
+ /* number of 8 octet units to copy
+ * By default in absence of extension headers it is equal to length of ip6 header
+ * With extension headers it number of 8 octet units of ext headers preceding
+ * SR header
+ */
+ copy_len_u64s0 =
+ (((u8 *) sr0 - (u8 *) ip0) - sizeof (ip6_header_t)) >> 3;
+ copy_dst0[4 + copy_len_u64s0] = copy_src0[4 + copy_len_u64s0];
+ copy_dst0[3 + copy_len_u64s0] = copy_src0[3 + copy_len_u64s0];
+ copy_dst0[2 + copy_len_u64s0] = copy_src0[2 + copy_len_u64s0];
+ copy_dst0[1 + copy_len_u64s0] = copy_src0[1 + copy_len_u64s0];
+ copy_dst0[0 + copy_len_u64s0] = copy_src0[0 + copy_len_u64s0];
+
+ int i;
+ for (i = copy_len_u64s0 - 1; i >= 0; i--)
+ {
+ copy_dst0[i] = copy_src0[i];
+ }
+
+ if (ls0->behavior == SR_BEHAVIOR_X)
+ {
+ vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0->nh_adj;
+ *next0 = SR_LOCALSID_NEXT_IP6_REWRITE;
+ }
+ else if(ls0->behavior == SR_BEHAVIOR_T)
+ {
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->vrf_index;
+ }
+ }
+ else if (PREDICT_TRUE(sr0->segments_left > 0))
+ {
+ sr0->segments_left -= 1;
+ new_dst0 = (ip6_address_t *) (sr0->segments);
+ new_dst0 += sr0->segments_left;
+ ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
+ ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
+
+ if (ls0->behavior == SR_BEHAVIOR_X)
+ {
+ vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0->nh_adj;
+ *next0 = SR_LOCALSID_NEXT_IP6_REWRITE;
+ }
+ else if(ls0->behavior == SR_BEHAVIOR_T)
+ {
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->vrf_index;
+ }
+ }
+ else
+ {
+ *next0 = SR_LOCALSID_NEXT_ERROR;
+ b0->error = node->errors[SR_LOCALSID_ERROR_NO_MORE_SEGMENTS];
+ }
+ }
+ else
+ {
+ /* Error. Routing header of type != SR */
+ *next0 = SR_LOCALSID_NEXT_ERROR;
+ b0->error = node->errors[SR_LOCALSID_ERROR_NO_SRH];
+ }
+}
+
+/*
+ * @brief SRv6 Sample Localsid graph node
+ * WARNING: YOU MUST DO THE DUAL LOOP
+ */
+static uword
+srv6_localsid_sample_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+ u32 n_left_from, * from, * to_next;
+ u32 next_index;
+ u32 pkts_swapped = 0;
+
+ ip6_sr_main_t * sm = &sr_main;
+
+ from = vlib_frame_vector_args (frame);
+ n_left_from = frame->n_vectors;
+ next_index = node->cached_next_index;
+ u32 thread_index = vlib_get_thread_index ();
+
+ while (n_left_from > 0)
+ {
+ u32 n_left_to_next;
+
+ vlib_get_next_frame (vm, node, next_index,
+ to_next, n_left_to_next);
+
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ u32 bi0;
+ vlib_buffer_t * b0;
+ ip6_header_t * ip0 = 0;
+ ip6_sr_header_t * sr0;
+ ip6_ext_header_t *prev0
+ u32 next0 = SRV6_SAMPLE_LOCALSID_NEXT_IP6LOOKUP;
+ ip6_sr_localsid_t *ls0;
+ srv6_localsid_sample_per_sid_memory_t *ls0_mem;
+
+ bi0 = from[0];
+ to_next[0] = bi0;
+ from += 1;
+ to_next += 1;
+ n_left_from -= 1;
+ n_left_to_next -= 1;
+
+ b0 = vlib_get_buffer (vm, bi0);
+ ip0 = vlib_buffer_get_current (b0);
+ sr0 = (ip6_sr_header_t *)(ip0+1);
+
+ /* Lookup the SR End behavior based on IP DA (adj) */
+ ls0 = pool_elt_at_index (sm->localsids, vnet_buffer(b0)->ip.adj_index[VLIB_TX]);
+ ls0_mem = ls0->plugin_mem;
+
+ /* SRH processing */
+ ip6_ext_header_find_t (ip0, prev0, sr0, IP_PROTOCOL_IPV6_ROUTE);
+ end_decaps_srh_processing (node, b0, ip0, sr0, ls0, &next0);
+
+ /* ==================================================================== */
+ /* INSERT CODE HERE */
+ /* Example starts here */
+ //In this example we are changing the next VRF table by the one in CLI
+ vnet_buffer(b0)->sw_if_index[VLIB_TX] = ls0_mem->fib_table;
+ /* Example finishes here */
+ /* ==================================================================== */
+
+ if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ srv6_localsid_sample_trace_t *tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
+ tr->localsid_index = ls0 - sm->localsids;
+ }
+
+ /* This increments the SRv6 per LocalSID counters.*/
+ vlib_increment_combined_counter
+ (((next0 == SRV6_SAMPLE_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) : &(sm->sr_ls_valid_counters)),
+ thread_index,
+ ls0 - sm->localsids,
+ 1, vlib_buffer_length_in_chain (vm, b0));
+
+ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+ n_left_to_next, bi0, next0);
+
+ pkts_swapped ++;
+ }
+ vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+
+ }
+
+ return frame->n_vectors;
+}
+
+VLIB_REGISTER_NODE (srv6_localsid_sample_node) = {
+ .function = srv6_localsid_sample_fn,
+ .name = "srv6-localsid-sample",
+ .vector_size = sizeof (u32),
+ .format_trace = format_srv6_localsid_sample_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = SRV6_LOCALSID_N_COUNTERS,
+ .error_strings = srv6_localsid_counter_strings,
+ .n_next_nodes = SRV6_SAMPLE_LOCALSID_N_NEXT,
+ .next_nodes = {
+ [SRV6_SAMPLE_LOCALSID_NEXT_IP6LOOKUP] = "ip6-lookup",
+ [SRV6_SAMPLE_LOCALSID_NEXT_ERROR] = "error-drop",
+ },
+};
diff --git a/src/examples/srv6-sample-localsid/srv6_localsid_sample.c b/src/examples/srv6-sample-localsid/srv6_localsid_sample.c
new file mode 100755
index 00000000..ec16547e
--- /dev/null
+++ b/src/examples/srv6-sample-localsid/srv6_localsid_sample.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2015 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.
+ */
+/*
+ *------------------------------------------------------------------
+ * srv6_localsid_sample.c - Simple SRv6 LocalSID
+ *------------------------------------------------------------------
+ */
+
+#include <vnet/vnet.h>
+#include <vnet/plugin/plugin.h>
+#include <srv6-localsid/srv6_localsid_sample.h>
+
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+#include <vlibsocket/api.h>
+
+unsigned char srv6_localsid_name[32] = "Sample-SRv6-LocalSID-plugin";
+unsigned char keyword_str[32] = "new_srv6_localsid";
+unsigned char def_str[64] = "This is a definition of a sample new_srv6_localsid";
+unsigned char params_str[32] = "<fib_table>";
+
+/*****************************************/
+/* SRv6 LocalSID instantiation and removal functions */
+static int
+srv6_localsid_creation_fn (ip6_sr_localsid_t *localsid)
+{
+ /*
+ * Do you want to do anything fancy upon localsid instantiation?
+ * You can do it here
+ * (If return != 0 the localsid creation will be cancelled.)
+ */
+ /* As an example Im going to do a +1 to the fib table inserted by the user */
+ srv6_localsid_sample_per_sid_memory_t *ls_mem = localsid->plugin_mem;
+ ls_mem->fib_table += 1;
+ return 0;
+}
+
+static int
+srv6_localsid_removal_fn (ip6_sr_localsid_t *localsid)
+{
+ /* Do you want to do anything fancy upon localsid removal?
+ * You can do it here
+ * (If return != 0 the localsid removal will be cancelled.)
+ */
+ /*
+ * BTW if you stored something in localsid->plugin_mem you should clean it now
+ */
+
+ //In this example we are only cleaning the memory allocated per localsid
+ clib_mem_free(localsid->plugin_mem);
+ return 0;
+}
+
+/**********************************/
+/* SRv6 LocalSID format functions */
+/*
+ * Prints nicely the parameters of a localsid
+ * Example: print "Table 5"
+ */
+u8 *
+format_srv6_localsid_sample (u8 * s, va_list * args)
+{
+ srv6_localsid_sample_per_sid_memory_t *ls_mem = va_arg (*args, void *);
+ return (format (s, "Table: %u", ls_mem->fib_table));
+}
+
+/*
+ * Process the parameters of a localsid
+ * Example: process from:
+ * sr localsid address cafe::1 behavior new_srv6_localsid 5
+ * everything from behavior on... so in this case 'new_srv6_localsid 5'
+ * Notice that it MUST match the keyword_str and params_str defined above.
+ */
+uword
+unformat_srv6_localsid_sample (unformat_input_t * input, va_list * args)
+{
+ void **plugin_mem = va_arg (*args, void **);
+ srv6_localsid_sample_per_sid_memory_t *ls_mem;
+ u32 table_id;
+ if (unformat (input, "new_srv6_localsid %u", &table_id))
+ {
+ /* Allocate a portion of memory */
+ ls_mem = clib_mem_alloc_aligned_at_offset (
+ sizeof(srv6_localsid_sample_per_sid_memory_t), 0, 0, 1);
+
+ /* Set to zero the memory */
+ memset (ls_mem, 0, sizeof(srv6_localsid_sample_per_sid_memory_t));
+
+ /* Our brand-new car is ready */
+ ls_mem->fib_table = table_id;
+
+ /* Dont forget to add it to the localsid */
+ *plugin_mem = ls_mem;
+ return 1;
+ }
+ return 0;
+}
+
+/*************************/
+/* SRv6 LocalSID FIB DPO */
+static u8 *
+format_srv6_localsid_sample_dpo (u8 * s, va_list * args)
+{
+ index_t index = va_arg (*args, index_t);
+ CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
+
+ return (format (s, "SR: localsid_sample_index:[%u]", index));
+}
+
+void
+srv6_localsid_sample_dpo_lock (dpo_id_t * dpo)
+{
+}
+
+void
+srv6_localsid_sample_dpo_unlock (dpo_id_t * dpo)
+{
+}
+
+const static dpo_vft_t srv6_localsid_sample_vft = {
+ .dv_lock = srv6_localsid_sample_dpo_lock,
+ .dv_unlock = srv6_localsid_sample_dpo_unlock,
+ .dv_format = format_srv6_localsid_sample_dpo,
+};
+
+const static char *const srv6_localsid_sample_ip6_nodes[] = {
+ "srv6-localsid-sample",
+ NULL,
+};
+
+const static char *const *const srv6_localsid_sample_nodes[DPO_PROTO_NUM] = {
+ [DPO_PROTO_IP6] = srv6_localsid_sample_ip6_nodes,
+};
+
+/**********************/
+static clib_error_t * srv6_localsid_sample_init (vlib_main_t * vm)
+{
+ srv6_localsid_sample_main_t * sm = &srv6_localsid_sample_main;
+ int rv = 0;
+ /* Create DPO */
+ sm->srv6_localsid_sample_dpo_type = dpo_register_new_type (
+ &srv6_localsid_sample_vft, srv6_localsid_sample_nodes);
+
+ /* Register SRv6 LocalSID */
+ rv = sr_localsid_register_function (vm,
+ srv6_localsid_name,
+ keyword_str,
+ def_str,
+ params_str,
+ &sm->srv6_localsid_sample_dpo_type,
+ format_srv6_localsid_sample,
+ unformat_srv6_localsid_sample,
+ srv6_localsid_creation_fn,
+ srv6_localsid_removal_fn);
+ if (rv < 0)
+ clib_error_return (0, "SRv6 LocalSID function could not be registered.");
+ else
+ sm->srv6_localsid_behavior_id = rv;
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (srv6_localsid_sample_init);
+
+VLIB_PLUGIN_REGISTER () = {
+ .version = "1.0",
+};
diff --git a/src/examples/srv6-sample-localsid/srv6_localsid_sample.h b/src/examples/srv6-sample-localsid/srv6_localsid_sample.h
new file mode 100644
index 00000000..ef74ea3e
--- /dev/null
+++ b/src/examples/srv6-sample-localsid/srv6_localsid_sample.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2015 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 __included_srv6_localsid_sample_h__
+#define __included_srv6_localsid_sample_h__
+
+#include <vnet/vnet.h>
+#include <vnet/ip/ip.h>
+#include <vnet/srv6/sr.h>
+#include <vnet/srv6/sr_packet.h>
+
+#include <vppinfra/hash.h>
+#include <vppinfra/error.h>
+#include <vppinfra/elog.h>
+
+typedef struct {
+ /* API message ID base */
+ u16 msg_id_base;
+
+ /* convenience */
+ vlib_main_t * vlib_main;
+ vnet_main_t * vnet_main;
+
+ /* DPO type */
+ dpo_type_t srv6_localsid_sample_dpo_type;
+
+ /* SRv6 LocalSID behavior number */
+ u32 srv6_localsid_behavior_id;
+
+} srv6_localsid_sample_main_t;
+
+/*
+ * This is the memory that will be stored per each localsid
+ * the user instantiates
+ */
+typedef struct {
+ u32 fib_table; /* Stupid index used as an example.. */
+} srv6_localsid_sample_per_sid_memory_t ;
+
+srv6_localsid_sample_main_t srv6_localsid_sample_main;
+
+format_function_t format_srv6_localsid_sample;
+unformat_function_t unformat_srv6_localsid_sample;
+
+void srv6_localsid_sample_dpo_lock (dpo_id_t * dpo);
+void srv6_localsid_sample_dpo_unlock (dpo_id_t * dpo);
+
+extern vlib_node_registration_t srv6_localsid_sample_node;
+
+#endif /* __included_sample_h__ */
diff --git a/src/examples/srv6-sample-localsid/srv6_sample_localsid_doc.md b/src/examples/srv6-sample-localsid/srv6_sample_localsid_doc.md
new file mode 100644
index 00000000..cd717db8
--- /dev/null
+++ b/src/examples/srv6-sample-localsid/srv6_sample_localsid_doc.md
@@ -0,0 +1,30 @@
+# Sample SRv6 LocalSID documentation {#srv6_plugin_doc}
+
+## Introduction
+
+This plugin is an example of how an user can create a new SRv6 LocalSID behavior by using VPP plugins with the appropiate API calls to the existing SR code.
+
+This **example** plugin registers a new localsid behavior, with cli keyword 'new_srv6_localsid' which only takes one parameter, a fib-table. Upon recival of a packet, this plugin will enforce the next IP6 lookup in the specific fib-table specified by the user. (Indeed it will do the lookup in the fib_table n+1 (since for the shake of the example we increment the fib-table.)
+
+Notice that the plugin only 'defines' a new SRv6 LocalSID behavior, but the existing SR code in VNET is the one actually instantiating new LocalSIDs. Notice that there are callback functions such that when you create or remove a LocalSID you can actually setup specific parameters through the functions in this plugin.
+
+## Variables to watch for
+
+* srv6_localsid_name: This variable is the name (used as a unique key) identifying this SR LocalSID plugin.
+* keyword_str: This is the CLI keyword to be used for the plugin. In this example 'new_srv6_localsid'. (i.e. sr localsid address cafe::1 behavior new_srv6_localsid <parameters>)
+* def_str: This is a definition of this SR behavior. This is printed when you do 'show sr localsid behaviors'.
+* params_str: This is a definition of the parameters of this localsid. This is printed when you do 'show sr localsid behaviors'.
+
+## Functions to watch for
+
+* srv6_localsid_creation_fn: This function will be called every time a new SR LocalSID is instantiated with the behavior defined in this plugin.
+* srv6_localsid_removal_fn: This function will be called every time a new SR LocalSID is removed with the behavior defined in this plugin. This function tends to be used for freeing up all the memory created in the previous function.
+* format_srv6_localsid_sample: This function prints nicely the parameters of every SR LocalSID using this behavior.
+* unformat_srv6_localsid_sample: This function parses the CLI command when initialising a new SR LocalSID using this behavior. It parses all the parameters and ensures that the parameters are correct.
+* format_srv6_localsid_sample_dpo: This function formats the 'show ip6 fib' message for the SR LocalSIDs created with this plugin behavior.
+
+## Graph node
+
+The current graph node uses the function 'end_srh_processing' to do the Segment Routing Endpoint behavior. Notice that it does not allow the cleanup of a Segment Routing header (as per the SRv6 behavior specs).
+This function is identical to the one found in /src/vnet/srv6/sr_localsid.c
+In case that by some other reason you want to do decapsulation, or SRH clean_up you can use the functions 'end_decaps_srh_processing' or 'end_psp_srh_processing' respectively.
diff --git a/src/examples/vlib/dir.dox b/src/examples/vlib/dir.dox
new file mode 100644
index 00000000..d3ac0ee4
--- /dev/null
+++ b/src/examples/vlib/dir.dox
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Copyright (c) 2016 Comcast Cable Communications Management, LLC.
+ *
+ * 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.
+ */
+/* Doxygen directory documentation */
+/**
+@dir
+@brief Someone please fix this description
+@todo This directory needs a description.
+*/
diff --git a/src/examples/vlib/main_stub.c b/src/examples/vlib/main_stub.c
new file mode 100644
index 00000000..3b19c53f
--- /dev/null
+++ b/src/examples/vlib/main_stub.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2015 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 <vlib/unix/unix.h>
+#include <math.h>
+
+int
+main (int argc, char *argv[])
+{
+ return vlib_unix_main (argc, argv);
+}
+
+static clib_error_t *
+main_stub_init (vlib_main_t * vm)
+{
+ clib_error_t *error;
+
+ if ((error = unix_physmem_init (vm)))
+ return error;
+
+ if ((error = vlib_call_init_function (vm, unix_cli_init)))
+ return error;
+
+ return error;
+}
+
+VLIB_INIT_FUNCTION (main_stub_init);
+
+#if 0
+/* Node test code. */
+typedef struct
+{
+ int scalar;
+ int vector[0];
+} my_frame_t;
+
+static u8 *
+format_my_node_frame (u8 * s, va_list * va)
+{
+ vlib_frame_t *f = va_arg (*va, vlib_frame_t *);
+ my_frame_t *g = vlib_frame_args (f);
+ int i;
+
+ s = format (s, "scalar %d, vector { ", g->scalar);
+ for (i = 0; i < f->n_vectors; i++)
+ s = format (s, "%d, ", g->vector[i]);
+ s = format (s, " }");
+
+ return s;
+}
+
+static uword
+my_func (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
+{
+ vlib_node_t *node;
+ my_frame_t *y;
+ u32 i, n_left = 0;
+ static int serial;
+ int verbose;
+
+ node = vlib_get_node (vm, rt->node_index);
+
+ verbose = 0;
+
+ if (verbose && f)
+ vlib_cli_output (vm, "%v: call frame %p %U", node->name,
+ f, format_my_node_frame, f);
+
+ if (rt->n_next_nodes > 0)
+ {
+ vlib_frame_t *next = vlib_get_next_frame (vm, rt, /* next index */ 0);
+ n_left = VLIB_FRAME_SIZE - next->n_vectors;
+ y = vlib_frame_args (next);
+ y->scalar = serial++;
+ }
+ else
+ y = 0;
+
+ for (i = 0; i < 5; i++)
+ {
+ if (y)
+ {
+ ASSERT (n_left > 0);
+ n_left--;
+ y->vector[i] = y->scalar + i;
+ }
+ }
+ if (y)
+ vlib_put_next_frame (vm, rt, /* next index */ 0, n_left);
+
+ if (verbose)
+ vlib_cli_output (vm, "%v: return frame %p", node->name, f);
+
+ return i;
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (my_node1,static) = {
+ .function = my_func,
+ .type = VLIB_NODE_TYPE_INPUT,
+ .name = "my-node1",
+ .scalar_size = sizeof (my_frame_t),
+ .vector_size = STRUCT_SIZE_OF (my_frame_t, vector[0]),
+ .n_next_nodes = 1,
+ .next_nodes = {
+ [0] = "my-node2",
+ },
+};
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (my_node2,static) = {
+ .function = my_func,
+ .name = "my-node2",
+ .scalar_size = sizeof (my_frame_t),
+ .vector_size = STRUCT_SIZE_OF (my_frame_t, vector[0]),
+};
+/* *INDENT-ON* */
+
+#endif
+
+#if 0
+
+typedef enum
+{
+ MY_EVENT_TYPE1,
+ MY_EVENT_TYPE2,
+} my_process_completion_type_t;
+
+typedef struct
+{
+ int a;
+ f64 b;
+} my_process_event_data_t;
+
+static u8 *
+format_my_process_event_data (u8 * s, va_list * va)
+{
+ my_process_event_data_t *d = va_arg (*va, my_process_event_data_t *);
+ return format (s, "{ a %d b %.6f}", d->a, d->b);
+}
+
+static uword
+my_proc (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
+{
+ vlib_node_t *node;
+ u32 i;
+
+ node = vlib_get_node (vm, rt->node_index);
+
+ vlib_cli_output (vm, "%v: call frame %p", node->name, f);
+
+ for (i = 0; i < 5; i++)
+ {
+ vlib_cli_output (vm, "%v: %d", node->name, i);
+ vlib_process_suspend (vm, 1e0 /* secs */ );
+ }
+
+ vlib_cli_output (vm, "%v: return frame %p", node->name, f);
+
+ if (0)
+ {
+ uword n_events_seen, type, *data = 0;
+
+ for (n_events_seen = 0; n_events_seen < 2;)
+ {
+ vlib_process_wait_for_event (vm);
+ type = vlib_process_get_events (vm, &data);
+ n_events_seen += vec_len (data);
+ vlib_cli_output (vm, "%U %v: completion #%d type %d data 0x%wx",
+ format_time_interval, "h:m:s:u",
+ vlib_time_now (vm), node->name, i, type, data[0]);
+ _vec_len (data) = 0;
+ }
+
+ vec_free (data);
+ }
+ else
+ {
+ uword n_events_seen, i, type;
+ my_process_event_data_t *data;
+ for (n_events_seen = 0; n_events_seen < 2;)
+ {
+ vlib_process_wait_for_event (vm);
+ data = vlib_process_get_event_data (vm, &type);
+ vec_foreach_index (i, data)
+ {
+ vlib_cli_output (vm, "%U event type %d data %U",
+ format_time_interval, "h:m:s:u",
+ vlib_time_now (vm), type,
+ format_my_process_event_data, data);
+ }
+ n_events_seen += vec_len (data);
+ vlib_process_put_event_data (vm, data);
+ }
+ }
+
+ return i;
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (my_proc_node,static) = {
+ .function = my_proc,
+ .type = VLIB_NODE_TYPE_PROCESS,
+ .name = "my-proc",
+};
+/* *INDENT-ON* */
+
+static uword
+my_proc_input (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
+{
+ static int i;
+
+ if (i++ < 2)
+ {
+ if (0)
+ vlib_process_signal_event (vm, my_proc_node.index,
+ i == 1 ? MY_EVENT_TYPE1 : MY_EVENT_TYPE2,
+ 0x12340000 + i);
+ else
+ {
+ my_process_event_data_t *d;
+ f64 dt = 5;
+ d = vlib_process_signal_event_at_time (vm,
+ i * dt,
+ my_proc_node.index,
+ i ==
+ 1 ? MY_EVENT_TYPE1 :
+ MY_EVENT_TYPE2,
+ 1 /* elts */ ,
+ sizeof (d[0]));
+ d->a = i;
+ d->b = vlib_time_now (vm);
+ }
+ }
+ else
+ vlib_node_set_state (vm, rt->node_index, VLIB_NODE_STATE_DISABLED);
+
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (my_proc_input_node,static) = {
+ .function = my_proc_input,
+ .type = VLIB_NODE_TYPE_INPUT,
+ .name = "my-proc-input",
+};
+/* *INDENT-ON* */
+
+static uword
+_unformat_farith (unformat_input_t * i, va_list * args)
+{
+ u32 prec = va_arg (*args, u32);
+ f64 *result = va_arg (*args, f64 *);
+ f64 tmp[2];
+
+ /* Binary operations in from lowest to highest precedence. */
+ char *binops[] = {
+ "+%U", "-%U", "/%U", "*%U", "^%U",
+ };
+
+ if (prec <= ARRAY_LEN (binops) - 1
+ && unformat_user (i, _unformat_farith, prec + 1, &tmp[0]))
+ {
+ int p;
+ for (p = prec; p < ARRAY_LEN (binops); p++)
+ {
+ if (unformat (i, binops[p], _unformat_farith, prec + 0, &tmp[1]))
+ {
+ switch (binops[p][0])
+ {
+ case '+':
+ result[0] = tmp[0] + tmp[1];
+ break;
+ case '-':
+ result[0] = tmp[0] - tmp[1];
+ break;
+ case '/':
+ result[0] = tmp[0] / tmp[1];
+ break;
+ case '*':
+ result[0] = tmp[0] * tmp[1];
+ break;
+ case '^':
+ result[0] = pow (tmp[0], tmp[1]);
+ break;
+ default:
+ abort ();
+ }
+ return 1;
+ }
+ }
+ result[0] = tmp[0];
+ return 1;
+ }
+
+ else if (unformat (i, "-%U", _unformat_farith, prec + 0, &tmp[0]))
+ {
+ result[0] = -tmp[0];
+ return 1;
+ }
+
+ else if (unformat (i, "(%U)", _unformat_farith, 0, &tmp[0]))
+ {
+ result[0] = tmp[0];
+ return 1;
+ }
+
+ else if (unformat (i, "%f", result))
+ return 1;
+
+ else
+ return 0;
+}
+
+static uword
+unformat_farith (unformat_input_t * i, va_list * args)
+{
+ CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+ f64 *result = va_arg (*args, f64 *);
+ return unformat_user (i, _unformat_farith, 0, result);
+}
+
+static uword
+unformat_integer (unformat_input_t * i, va_list * args)
+{
+ CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+ u32 *data = va_arg (*args, u32 *);
+ return unformat (i, "%d", data);
+}
+
+static VLIB_CLI_PARSE_RULE (my_parse_rule1) =
+{
+.name = "decimal_integer",.short_help =
+ "a decimal integer",.unformat_function = unformat_integer,.data_size =
+ sizeof (u32),};
+
+static VLIB_CLI_PARSE_RULE (my_parse_rule2) =
+{
+.name = "float_expression",.short_help =
+ "floating point expression",.unformat_function =
+ unformat_farith,.data_size = sizeof (f64),};
+
+static clib_error_t *
+bar_command (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ switch (cmd->function_arg)
+ {
+ case 2:
+ {
+ u32 *d, *e;
+ d = vlib_cli_get_parse_rule_result (vm, 0);
+ e = vlib_cli_get_parse_rule_result (vm, 1);
+ vlib_cli_output (vm, "bar2 %d %d", d[0], e[0]);
+ break;
+ }
+
+ case 1:
+ {
+ u32 *d = vlib_cli_get_parse_rule_result (vm, 0);
+ vlib_cli_output (vm, "bar1 %d", d[0]);
+ break;
+ }
+
+ case 3:
+ {
+ f64 *d = vlib_cli_get_parse_rule_result (vm, 0);
+ vlib_cli_output (vm, "expr %.6f", d[0]);
+ }
+ }
+
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (bar_command2, static) = {
+ .path = "bar %decimal_integer",
+ .short_help = "bar1 command",
+ .function = bar_command,
+ .function_arg = 1,
+};
+VLIB_CLI_COMMAND (bar_command1, static) = {
+ .path = "bar %decimal_integer %decimal_integer",
+ .short_help = "bar2 command",
+ .function = bar_command,
+ .function_arg = 2,
+};
+VLIB_CLI_COMMAND (bar_command3, static) = {
+ .path = "zap %float_expression",
+ .short_help = "bar3 command",
+ .function = bar_command,
+ .function_arg = 3,
+};
+/* *INDENT-ON* */
+
+#endif
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/examples/vlib/mc_test.c b/src/examples/vlib/mc_test.c
new file mode 100644
index 00000000..e84a713c
--- /dev/null
+++ b/src/examples/vlib/mc_test.c
@@ -0,0 +1,384 @@
+/*
+ * mc_test.c: test program for vlib mc
+ *
+ * Copyright (c) 2010 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 <vlib/unix/mc_socket.h>
+#include <vppinfra/random.h>
+
+typedef struct
+{
+ u32 min_n_msg_bytes;
+ u32 max_n_msg_bytes;
+ u32 tx_serial;
+ u32 rx_serial;
+ u32 seed;
+ u32 verbose;
+ u32 validate;
+ u32 window_size;
+ f64 min_delay, max_delay;
+ f64 n_packets_to_send;
+} mc_test_main_t;
+
+always_inline u32
+choose_msg_size (mc_test_main_t * tm)
+{
+ u32 r = tm->min_n_msg_bytes;
+ if (tm->max_n_msg_bytes > tm->min_n_msg_bytes)
+ r +=
+ random_u32 (&tm->seed) % (1 + tm->max_n_msg_bytes -
+ tm->min_n_msg_bytes);
+ return r;
+}
+
+static mc_test_main_t mc_test_main;
+
+static void
+serialize_test_msg (serialize_main_t * m, va_list * va)
+{
+ mc_test_main_t *tm = &mc_test_main;
+ u32 n_bytes = choose_msg_size (tm);
+ u8 *msg;
+ int i;
+ serialize_integer (m, n_bytes, sizeof (n_bytes));
+ msg = serialize_get (m, n_bytes);
+ for (i = 0; i < n_bytes; i++)
+ msg[i] = i + tm->tx_serial;
+ tm->tx_serial += n_bytes;
+}
+
+static void
+unserialize_test_msg (serialize_main_t * m, va_list * va)
+{
+ mc_test_main_t *tm = &mc_test_main;
+ u32 i, n_bytes, dump_msg = tm->verbose;
+ u8 *p;
+ unserialize_integer (m, &n_bytes, sizeof (n_bytes));
+ p = unserialize_get (m, n_bytes);
+ if (tm->validate)
+ for (i = 0; i < n_bytes; i++)
+ if (p[i] != ((tm->rx_serial + i) & 0xff))
+ {
+ clib_warning ("corrupt msg at offset %d", i);
+ dump_msg = 1;
+ break;
+ }
+ if (dump_msg)
+ clib_warning ("got %d bytes, %U", n_bytes, format_hex_bytes, p, n_bytes);
+ tm->rx_serial += n_bytes;
+}
+
+MC_SERIALIZE_MSG (test_msg, static) =
+{
+.name = "test_msg",.serialize = serialize_test_msg,.unserialize =
+ unserialize_test_msg,};
+
+#define SERIALIZE 1
+
+#define EVENT_JOIN_STREAM 10
+#define EVENT_SEND_DATA 11
+
+static void
+test_rx_callback (mc_main_t * mcm,
+ mc_stream_t * stream,
+ mc_peer_id_t peer_id, u32 buffer_index)
+{
+ if (SERIALIZE)
+ {
+ return mc_unserialize (mcm, stream, buffer_index);
+ }
+ else
+ {
+#if DEBUG > 1
+ vlib_main_t *vm = mcm->vlib_main;
+ vlib_buffer_t *b = vlib_get_buffer (vm, buffer_index);
+ u8 *dp = vlib_buffer_get_current (b);
+
+ fformat (stdout, "RX from %U %U\n",
+ stream->transport->format_peer_id, peer_id,
+ format_hex_bytes, dp, tm->n_msg_bytes);
+
+#endif
+ }
+}
+
+static u8 *
+test_snapshot_callback (mc_main_t * mcm,
+ u8 * data_vector, u32 last_global_sequence_processed)
+{
+ if (SERIALIZE)
+ {
+ serialize_main_t m;
+
+ /* Append serialized data to data vector. */
+ serialize_open_vector (&m, data_vector);
+ m.stream.current_buffer_index = vec_len (data_vector);
+
+ return serialize_close_vector (&m);
+ }
+ else
+ return format (data_vector,
+ "snapshot, last global seq 0x%x",
+ last_global_sequence_processed);
+}
+
+static void
+test_handle_snapshot_callback (mc_main_t * mcm, u8 * data, u32 n_data_bytes)
+{
+ if (SERIALIZE)
+ {
+ serialize_main_t s;
+ unserialize_open_data (&s, data, n_data_bytes);
+ }
+ else
+ clib_warning ("snapshot `%*s'", n_data_bytes, data);
+}
+
+static mc_socket_main_t mc_socket_main;
+
+static uword
+mc_test_process (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * f)
+{
+ mc_test_main_t *tm = &mc_test_main;
+ mc_socket_main_t *msm = &mc_socket_main;
+ mc_main_t *mcm = &msm->mc_main;
+ uword event_type, *event_data = 0;
+ u32 data_serial = 0, stream_index;
+ f64 delay;
+ mc_stream_config_t config;
+ clib_error_t *error;
+ int i;
+ char *intfcs[] = { "eth1", "eth0", "ce" };
+
+ memset (&config, 0, sizeof (config));
+ config.name = "test";
+ config.window_size = tm->window_size;
+ config.rx_buffer = test_rx_callback;
+ config.catchup_snapshot = test_snapshot_callback;
+ config.catchup = test_handle_snapshot_callback;
+ stream_index = ~0;
+
+ msm->multicast_tx_ip4_address_host_byte_order = 0xefff0100;
+ msm->base_multicast_udp_port_host_byte_order = 0xffab;
+
+ error = mc_socket_main_init (&mc_socket_main, intfcs, ARRAY_LEN (intfcs));
+ if (error)
+ {
+ clib_error_report (error);
+ exit (1);
+ }
+
+ mcm->we_can_be_relay_master = 1;
+
+ while (1)
+ {
+ vlib_process_wait_for_event (vm);
+ event_type = vlib_process_get_events (vm, &event_data);
+
+ switch (event_type)
+ {
+ case EVENT_JOIN_STREAM:
+ stream_index = mc_stream_join (mcm, &config);
+ break;
+
+ case EVENT_SEND_DATA:
+ {
+ f64 times[2];
+
+ if (stream_index == ~0)
+ stream_index = mc_stream_join (mcm, &config);
+
+ times[0] = vlib_time_now (vm);
+ for (i = 0; i < event_data[0]; i++)
+ {
+ u32 bi;
+ if (SERIALIZE)
+ {
+ mc_serialize_stream (mcm, stream_index, &test_msg,
+ data_serial);
+ }
+ else
+ {
+ u8 *mp;
+ mp = mc_get_vlib_buffer (vm, sizeof (mp[0]), &bi);
+ mp[0] = data_serial;
+ mc_stream_send (mcm, stream_index, bi);
+ }
+ if (tm->min_delay > 0)
+ {
+ delay =
+ tm->min_delay +
+ random_f64 (&tm->seed) * (tm->max_delay -
+ tm->min_delay);
+ vlib_process_suspend (vm, delay);
+ }
+ data_serial++;
+ }
+ times[1] = vlib_time_now (vm);
+ clib_warning ("done sending %d; %.4e per sec",
+ event_data[0],
+ (f64) event_data[0] / (times[1] - times[0]));
+ break;
+ }
+
+ default:
+ clib_warning ("bug");
+ break;
+ }
+
+ if (event_data)
+ _vec_len (event_data) = 0;
+ }
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (mc_test_process_node, static) =
+{
+.function = mc_test_process,.type = VLIB_NODE_TYPE_PROCESS,.name =
+ "mc-test-process",};
+/* *INDENT-ON* */
+
+static clib_error_t *
+mc_test_command (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ f64 npkts = 10;
+
+ if (unformat (input, "join"))
+ {
+ vlib_cli_output (vm, "Join stream...\n");
+ vlib_process_signal_event (vm, mc_test_process_node.index,
+ EVENT_JOIN_STREAM, 0);
+ return 0;
+ }
+ else if (unformat (input, "send %f", &npkts) || unformat (input, "send"))
+ {
+ vlib_process_signal_event (vm, mc_test_process_node.index,
+ EVENT_SEND_DATA, (uword) npkts);
+ vlib_cli_output (vm, "Send %.0f pkts...\n", npkts);
+
+ return 0;
+ }
+ else
+ return unformat_parse_error (input);
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (test_mc_command, static) =
+{
+.path = "test mc",.short_help = "Test mc command",.function =
+ mc_test_command,};
+/* *INDENT-ON* */
+
+static clib_error_t *
+mc_show_command (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ mc_main_t *mcm = &mc_socket_main.mc_main;
+ vlib_cli_output (vm, "%U", format_mc_main, mcm);
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (show_mc_command, static) =
+{
+.path = "show mc",.short_help = "Show mc command",.function =
+ mc_show_command,};
+/* *INDENT-ON* */
+
+static clib_error_t *
+mc_clear_command (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ mc_main_t *mcm = &mc_socket_main.mc_main;
+ mc_clear_stream_stats (mcm);
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (clear_mc_command, static) =
+{
+.path = "clear mc",.short_help = "Clear mc command",.function =
+ mc_clear_command,};
+/* *INDENT-ON* */
+
+static clib_error_t *
+mc_config (vlib_main_t * vm, unformat_input_t * input)
+{
+ mc_test_main_t *tm = &mc_test_main;
+ mc_socket_main_t *msm = &mc_socket_main;
+ clib_error_t *error = 0;
+
+ tm->min_n_msg_bytes = 4;
+ tm->max_n_msg_bytes = 4;
+ tm->window_size = 8;
+ tm->seed = getpid ();
+ tm->verbose = 0;
+ tm->validate = 1;
+ tm->min_delay = 10e-6;
+ tm->max_delay = 10e-3;
+ tm->n_packets_to_send = 0;
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "interface %s", &msm->multicast_interface_name))
+ ;
+
+ else if (unformat (input, "n-bytes %d", &tm->max_n_msg_bytes))
+ tm->min_n_msg_bytes = tm->max_n_msg_bytes;
+ else if (unformat (input, "max-n-bytes %d", &tm->max_n_msg_bytes))
+ ;
+ else if (unformat (input, "min-n-bytes %d", &tm->min_n_msg_bytes))
+ ;
+ else if (unformat (input, "seed %d", &tm->seed))
+ ;
+ else if (unformat (input, "window %d", &tm->window_size))
+ ;
+ else if (unformat (input, "verbose"))
+ tm->verbose = 1;
+ else if (unformat (input, "no-validate"))
+ tm->validate = 0;
+ else if (unformat (input, "min-delay %f", &tm->min_delay))
+ ;
+ else if (unformat (input, "max-delay %f", &tm->max_delay))
+ ;
+ else if (unformat (input, "no-delay"))
+ tm->min_delay = tm->max_delay = 0;
+ else if (unformat (input, "n-packets %f", &tm->n_packets_to_send))
+ ;
+
+ else
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+ }
+
+ if (tm->n_packets_to_send > 0)
+ vlib_process_signal_event (vm, mc_test_process_node.index,
+ EVENT_SEND_DATA,
+ (uword) tm->n_packets_to_send);
+
+ return error;
+}
+
+VLIB_CONFIG_FUNCTION (mc_config, "mc");
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/examples/vlib/plex_test.c b/src/examples/vlib/plex_test.c
new file mode 100644
index 00000000..ce0c8ef1
--- /dev/null
+++ b/src/examples/vlib/plex_test.c
@@ -0,0 +1,527 @@
+/*
+ * Copyright (c) 2015 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/parse.h>
+#include <vlib/unix/unix.h>
+
+static u8 *
+format_value_v4_address (u8 * s, va_list * args)
+{
+ vlib_parse_value_t *v = va_arg (*args, vlib_parse_value_t *);
+ u32 a = v->value.as_uword;
+
+ s = format (s, "%d.%d.%d.%d",
+ (a >> 24) & 0xFF,
+ (a >> 16) & 0xFF, (a >> 8) & 0xFF, (a >> 0) & 0xFF);
+
+ return s;
+}
+
+static vlib_parse_match_t
+v4_address_match (vlib_parse_main_t * pm, vlib_parse_type_t * type,
+ vlib_lex_token_t * t, vlib_parse_value_t * valuep)
+{
+ u32 digit;
+ u32 value = 0;
+ int i;
+
+ if (vec_len (pm->tokens) - (t - pm->tokens) < 7)
+ return VLIB_PARSE_MATCH_FAIL;
+
+ /* NUMBER DOT NUMBER DOT NUMBER DOT NUMBER */
+
+ for (i = 0; i < 7; i++)
+ {
+ if ((i & 1) == 0)
+ {
+ if (t[i].token != VLIB_LEX_number)
+ return VLIB_PARSE_MATCH_FAIL;
+ if (t[i].value.as_uword > 0xff)
+ return VLIB_PARSE_MATCH_FAIL;
+ digit = t[i].value.as_uword;
+ value = (value << 8) | digit;
+ }
+ else
+ {
+ if (t[i].token != VLIB_LEX_dot)
+ return VLIB_PARSE_MATCH_FAIL;
+ }
+ }
+ /* note: caller advances by 1 */
+ pm->current_token_index += 6;
+ valuep->value.as_uword = value;
+ return VLIB_PARSE_MATCH_VALUE;
+}
+
+PARSE_TYPE_INIT (v4_address, v4_address_match, 0, format_value_v4_address)
+ static u8 *format_value_v4_address_and_mask (u8 * s, va_list * args)
+{
+ vlib_parse_value_t *v = va_arg (*args, vlib_parse_value_t *);
+ u32 *a = v->value.as_pointer;
+
+ s = format (s, "%d.%d.%d.%d",
+ (a[0] >> 24) & 0xFF,
+ (a[0] >> 16) & 0xFF, (a[0] >> 8) & 0xFF, (a[0] >> 0) & 0xFF);
+ s = format (s, "/%d", a[1]);
+
+ return s;
+}
+
+static vlib_parse_match_t
+v4_address_and_mask_match (vlib_parse_main_t * pm, vlib_parse_type_t * type,
+ vlib_lex_token_t * t, vlib_parse_value_t * valuep)
+{
+ u32 digit;
+ u32 address = 0;
+ u32 *rv = 0;
+ int i;
+
+ if (vec_len (pm->tokens) - (t - pm->tokens) < 9)
+ return VLIB_PARSE_MATCH_FAIL;
+
+ /* NUMBER DOT NUMBER DOT NUMBER DOT NUMBER */
+
+ for (i = 0; i < 7; i++)
+ {
+ if ((i & 1) == 0)
+ {
+ if (t[i].token != VLIB_LEX_number)
+ return VLIB_PARSE_MATCH_FAIL;
+ if (t[i].value.as_uword > 0xff)
+ return VLIB_PARSE_MATCH_FAIL;
+ digit = t[i].value.as_uword;
+ address = (address << 8) | digit;
+ }
+ else
+ {
+ if (t[i].token != VLIB_LEX_dot)
+ return VLIB_PARSE_MATCH_FAIL;
+ }
+ }
+
+ if (t[7].token != VLIB_LEX_slash || t[8].token != VLIB_LEX_number)
+ return VLIB_PARSE_MATCH_FAIL;
+
+ vec_add1 (rv, address);
+ vec_add1 (rv, t[8].value.as_uword);
+
+ /* note: caller advances by 1 */
+ pm->current_token_index += 8;
+ valuep->value.as_pointer = rv;
+ return VLIB_PARSE_MATCH_VALUE;
+}
+
+void
+v4_address_and_mask_cleanup (vlib_parse_value_t * valuep)
+{
+ u32 *trash = valuep->value.as_pointer;
+ vec_free (trash);
+}
+
+PARSE_TYPE_INIT (v4_address_and_mask, v4_address_and_mask_match,
+ v4_address_and_mask_cleanup,
+ format_value_v4_address_and_mask)
+ vlib_lex_main_t vlib_lex_main;
+
+
+
+ vlib_parse_match_t eval_factor0 (vlib_parse_main_t * pm,
+ vlib_parse_item_t * item,
+ vlib_parse_value_t * value)
+{
+ clib_warning ("%U", format_vlib_parse_value, pm);
+ return VLIB_PARSE_MATCH_RULE;
+}
+
+vlib_parse_match_t
+eval_factor1 (vlib_parse_main_t * pm,
+ vlib_parse_item_t * item, vlib_parse_value_t * value)
+{
+ clib_warning ("%U", format_vlib_parse_value, pm);
+ return VLIB_PARSE_MATCH_RULE;
+}
+
+vlib_parse_match_t
+eval_factor2 (vlib_parse_main_t * pm,
+ vlib_parse_item_t * item, vlib_parse_value_t * value)
+{
+ word a;
+ int index = vec_len (pm->parse_value) - 1;
+
+ a = pm->parse_value[index].value.as_word;
+
+ pm->parse_value[index].value.as_word = -a;
+ return VLIB_PARSE_MATCH_RULE;
+}
+
+vlib_parse_match_t
+eval_term0 (vlib_parse_main_t * pm,
+ vlib_parse_item_t * item, vlib_parse_value_t * value)
+{
+ clib_warning ("%U", format_vlib_parse_value, pm);
+ return VLIB_PARSE_MATCH_RULE;
+}
+
+vlib_parse_match_t
+eval_term1 (vlib_parse_main_t * pm,
+ vlib_parse_item_t * item, vlib_parse_value_t * value)
+{
+ uword a, b;
+ int index = vec_len (pm->parse_value) - 2;
+
+ a = pm->parse_value[index].value.as_uword;
+ b = pm->parse_value[index + 1].value.as_uword;
+
+ pm->parse_value[index].value.as_uword = a * b;
+ _vec_len (pm->parse_value) -= 1;
+ clib_warning ("%U", format_vlib_parse_value, pm);
+
+ return VLIB_PARSE_MATCH_RULE;
+}
+
+vlib_parse_match_t
+eval_term2 (vlib_parse_main_t * pm,
+ vlib_parse_item_t * item, vlib_parse_value_t * value)
+{
+ uword a, b;
+ int index = vec_len (pm->parse_value) - 2;
+
+ a = pm->parse_value[index].value.as_uword;
+ b = pm->parse_value[index + 1].value.as_uword;
+
+ pm->parse_value[index].value.as_uword = a / b;
+ _vec_len (pm->parse_value) -= 1;
+ clib_warning ("%U", format_vlib_parse_value, pm);
+
+ return VLIB_PARSE_MATCH_RULE;
+}
+
+vlib_parse_match_t
+eval_exp0 (vlib_parse_main_t * pm,
+ vlib_parse_item_t * item, vlib_parse_value_t * value)
+{
+ return VLIB_PARSE_MATCH_RULE;
+}
+
+vlib_parse_match_t
+eval_exp1 (vlib_parse_main_t * pm,
+ vlib_parse_item_t * item, vlib_parse_value_t * value)
+{
+ uword a, b;
+ int index = vec_len (pm->parse_value) - 2;
+
+ a = pm->parse_value[index].value.as_uword;
+ b = pm->parse_value[index + 1].value.as_uword;
+
+ pm->parse_value[index].value.as_uword = a + b;
+ _vec_len (pm->parse_value) -= 1;
+ clib_warning ("%U", format_vlib_parse_value, pm);
+
+ return VLIB_PARSE_MATCH_RULE;
+}
+
+vlib_parse_match_t
+eval_exp2 (vlib_parse_main_t * pm,
+ vlib_parse_item_t * item, vlib_parse_value_t * value)
+{
+ uword a, b;
+ int index = vec_len (pm->parse_value) - 2;
+
+ a = pm->parse_value[index].value.as_uword;
+ b = pm->parse_value[index + 1].value.as_uword;
+
+ pm->parse_value[index].value.as_uword = a - b;
+ _vec_len (pm->parse_value) -= 1;
+ clib_warning ("%U", format_vlib_parse_value, pm);
+
+ return VLIB_PARSE_MATCH_RULE;
+}
+
+vlib_parse_match_t
+eval_result (vlib_parse_main_t * pm,
+ vlib_parse_item_t * item, vlib_parse_value_t * value)
+{
+ clib_warning ("%U", format_vlib_parse_value, pm);
+ return VLIB_PARSE_MATCH_DONE;
+}
+
+vlib_parse_match_t
+noop_match_rule (vlib_parse_main_t * pm,
+ vlib_parse_item_t * item, vlib_parse_value_t * value)
+{
+ clib_warning ("%U", format_vlib_parse_value, pm);
+ return VLIB_PARSE_MATCH_RULE;
+}
+
+#if 0
+PARSE_INIT (t1, "moo", eval0);
+PARSE_INIT (t2, "moo cow mumble", eval1);
+PARSE_INIT (t3, "moo cow", eval2);
+PARSE_INIT (t4, "moo cow mumble grunch", eval3);
+#endif
+
+#if 0
+PARSE_INIT (r1, "eval <exp>", eval_result);
+
+PARSE_INIT (r2, "<exp> = <term><exp2>", eval_exp0);
+PARSE_INIT (r3, "<exp2> = <plus> <exp>", eval_exp1);
+PARSE_INIT (r4, "<exp2> = <minus> <exp>", eval_exp2);
+PARSE_INIT (r5, "<exp2> = ", noop_match_rule);
+PARSE_TYPE_INIT (exp, rule_match, 0, 0);
+PARSE_TYPE_INIT (exp2, rule_match, 0, 0);
+
+PARSE_INIT (r6, "<term> = <factor><term2>", eval_term0);
+PARSE_INIT (r7, "<term2> = <star> <term>", eval_term1);
+PARSE_INIT (r8, "<term2> = <slash> <term>", eval_term2);
+PARSE_INIT (r9, "<term2> = ", noop_match_rule);
+PARSE_TYPE_INIT (term, rule_match, 0, 0);
+PARSE_TYPE_INIT (term2, rule_match, 0, 0);
+
+PARSE_INIT (r11, "<factor> = <lpar> <exp> <rpar>", eval_factor1);
+PARSE_INIT (r10, "<factor> = <number>", eval_factor0);
+PARSE_INIT (r12, "<factor> = <minus> <factor>", eval_factor2);
+
+PARSE_TYPE_INIT (factor, rule_match, 0, 0);
+#endif
+
+PARSE_INIT (r1, "eval <exp>", eval_result);
+
+#if 1
+PARSE_INIT (r2, "<exp> = <term><exp2>", eval_exp0);
+PARSE_INIT (r3, "<exp2> = <plus> <exp>", eval_exp1);
+PARSE_INIT (r4, "<exp2> = <minus> <exp>", eval_exp2);
+PARSE_INIT (r5, "<exp2> = ", noop_match_rule);
+PARSE_TYPE_INIT (exp, rule_match, 0, 0);
+PARSE_TYPE_INIT (exp2, rule_match, 0, 0);
+
+PARSE_INIT (r6, "<term> = <factor><term2>", eval_term0);
+PARSE_INIT (r7, "<term2> = <star> <term>", eval_term1);
+PARSE_INIT (r8, "<term2> = <slash> <term>", eval_term2);
+PARSE_INIT (r9, "<term2> = ", noop_match_rule);
+PARSE_TYPE_INIT (term, rule_match, 0, 0);
+PARSE_TYPE_INIT (term2, rule_match, 0, 0);
+
+PARSE_INIT (r11, "<factor> = <lpar> <exp> <rpar>", eval_factor1);
+PARSE_INIT (r10, "<factor> = <number>", eval_factor0);
+PARSE_INIT (r12, "<factor> = <minus> <factor>", eval_factor2);
+
+PARSE_TYPE_INIT (factor, rule_match, 0, 0);
+#endif
+
+#if 0
+PARSE_TYPE_INIT (exp, rule_match, 0, 0);
+PARSE_INIT (r6, "<exp> = a b", eval_term0);
+PARSE_INIT (r7, "<exp> = c d", eval_term1);
+PARSE_INIT (r9, "<exp> = ", noop_match_rule);
+#endif
+
+#if 0
+#define foreach_rule_evaluator \
+_(0) \
+_(1) \
+_(2) \
+_(3)
+
+#define _(n) \
+vlib_parse_match_t eval##n (vlib_parse_main_t *pm, \
+ vlib_parse_item_t *item, \
+ vlib_parse_value_t *value) \
+{ \
+ clib_warning ("%U", format_vlib_parse_value, pm); \
+ return VLIB_PARSE_MATCH_DONE; \
+}
+foreach_rule_evaluator
+#undef _
+PARSE_INIT (r1, "eval <moo>", eval_result);
+
+PARSE_INIT (r2, "<moo> = cow", eval0);
+PARSE_INIT (r4, "<moo> = ", eval1);
+PARSE_TYPE_INIT (moo, rule_match, 0, 0);
+#endif
+
+
+clib_error_t *
+test_init (vlib_main_t * vm)
+{
+ clib_error_t *error;
+
+ if ((error = vlib_call_init_function (vm, parse_init)))
+ return error;
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (test_init);
+
+clib_error_t *
+vlib_stdlex_init (vlib_main_t * vm)
+{
+ vlib_lex_main_t *lm = &vlib_lex_main;
+ u16 top_index;
+ u16 slash_index, slash_star_index, slash_slash_index, slash_star_star_index;
+ u16 slash_token;
+ u16 word_index;
+ u16 zero_index, octal_index, decimal_index, hex_index, binary_index;
+
+ top_index = vlib_lex_add_table ("top");
+
+#define foreach_top_level_single_character_token \
+ _('(', lpar) \
+ _(')', rpar) \
+ _(';', semi) \
+ _('[', lbrack) \
+ _(']', rbrack) \
+ _('{', lcurly) \
+ _('}', rcurly) \
+ _('+', plus) \
+ _('-', minus) \
+ _('*', star) \
+ _('%', percent) \
+ _('@', atsign) \
+ _(',', comma) \
+ _('.', dot) \
+ _('?', qmark)
+
+#define _(c,t) \
+ vlib_lex_set_action_range(top_index,c,c,VLIB_LEX_RETURN,vlib_lex_add_token(lm, #t), top_index);
+ foreach_top_level_single_character_token;
+#undef _
+
+ /* Numbers */
+ zero_index = vlib_lex_add_table ("zero");
+ octal_index = vlib_lex_add_table ("octal");
+ decimal_index = vlib_lex_add_table ("decimal");
+ hex_index = vlib_lex_add_table ("hex");
+ binary_index = vlib_lex_add_table ("binary");
+
+ /* Support 0x 0b 0t and 0123 [octal] */
+ vlib_lex_set_action_range (top_index, '0', '0', VLIB_LEX_START_NUMBER, 10,
+ zero_index);
+ vlib_lex_set_action_range (top_index, '1', '9', VLIB_LEX_START_NUMBER, 10,
+ decimal_index);
+
+ vlib_lex_set_action_range (zero_index, 0, 0x7F, VLIB_LEX_RETURN_AND_RESCAN,
+ VLIB_LEX_number, top_index);
+
+ vlib_lex_set_action_range (zero_index, 'x', 'x', VLIB_LEX_IGNORE, ~0,
+ hex_index);
+ vlib_lex_set_action_range (zero_index, 'b', 'b', VLIB_LEX_IGNORE, ~0,
+ binary_index);
+ vlib_lex_set_action_range (zero_index, 't', 't', VLIB_LEX_IGNORE, ~0,
+ decimal_index);
+ vlib_lex_set_action_range (zero_index, '0', '7', VLIB_LEX_START_NUMBER, 8,
+ octal_index);
+
+ /* Octal */
+ vlib_lex_set_action_range (octal_index, 0, 0x7f, VLIB_LEX_RETURN_AND_RESCAN,
+ VLIB_LEX_number, top_index);
+ vlib_lex_set_action_range (octal_index, '0', '7', VLIB_LEX_ADD_TO_NUMBER, 8,
+ octal_index);
+
+ /* Decimal */
+ vlib_lex_set_action_range (decimal_index, 0, 0x7f,
+ VLIB_LEX_RETURN_AND_RESCAN, VLIB_LEX_number,
+ top_index);
+ vlib_lex_set_action_range (decimal_index, '0', '9', VLIB_LEX_ADD_TO_NUMBER,
+ 10, decimal_index);
+
+ /* Hex */
+ vlib_lex_set_action_range (hex_index, 0, 0x7f, VLIB_LEX_RETURN_AND_RESCAN,
+ VLIB_LEX_number, top_index);
+ vlib_lex_set_action_range (hex_index, '0', '9', VLIB_LEX_ADD_TO_NUMBER, 16,
+ hex_index);
+ vlib_lex_set_action_range (hex_index, 'a', 'f', VLIB_LEX_ADD_TO_NUMBER, 16,
+ hex_index);
+ vlib_lex_set_action_range (hex_index, 'A', 'F', VLIB_LEX_ADD_TO_NUMBER, 16,
+ hex_index);
+
+ /* Binary */
+ vlib_lex_set_action_range (binary_index, 0, 0x7f,
+ VLIB_LEX_RETURN_AND_RESCAN, VLIB_LEX_number,
+ top_index);
+ vlib_lex_set_action_range (binary_index, '0', '1', VLIB_LEX_ADD_TO_NUMBER,
+ 2, binary_index);
+
+ /* c/c++ comment syntax is the worst... */
+
+ slash_index = vlib_lex_add_table ("slash");
+ slash_star_index = vlib_lex_add_table ("slash_star");
+ slash_star_star_index = vlib_lex_add_table ("slash_star_star");
+ slash_slash_index = vlib_lex_add_table ("slash_slash");
+ slash_token = vlib_lex_add_token (lm, "slash");
+
+ /* Top level: see a slash, ignore, go to slash table */
+ vlib_lex_set_action_range (top_index, '/', '/', VLIB_LEX_IGNORE, ~0,
+ slash_index);
+
+ /* default for slash table: return SLASH, go to top table */
+ vlib_lex_set_action_range (slash_index, 1, 0x7F, VLIB_LEX_RETURN_AND_RESCAN,
+ slash_token, top_index);
+ /* see slash-slash, go to s-s table */
+ vlib_lex_set_action_range (slash_index, '/', '/', VLIB_LEX_IGNORE, ~0,
+ slash_slash_index);
+ /* see slash-star, go to s-* table */
+ vlib_lex_set_action_range (slash_index, '*', '*', VLIB_LEX_IGNORE, ~0,
+ slash_star_index);
+
+ /* EOL in s-s table, ignore, go to top table */
+ vlib_lex_set_action_range (slash_slash_index, '\n', '\n', VLIB_LEX_IGNORE,
+ ~0, top_index);
+
+ /* slash-star blah blah star */
+ vlib_lex_set_action_range (slash_star_index, '*', '*', VLIB_LEX_IGNORE, ~0,
+ slash_star_star_index);
+
+ /* slash star blah blah star slash */
+ vlib_lex_set_action_range (slash_star_star_index, '/', '/', VLIB_LEX_IGNORE,
+ ~0, top_index);
+
+ /* LT, =, GT */
+ vlib_lex_set_action_range (top_index, '<', '<', VLIB_LEX_RETURN,
+ VLIB_LEX_lt, top_index);
+ vlib_lex_set_action_range (top_index, '=', '=', VLIB_LEX_RETURN,
+ VLIB_LEX_equals, top_index);
+ vlib_lex_set_action_range (top_index, '>', '>', VLIB_LEX_RETURN,
+ VLIB_LEX_gt, top_index);
+
+ /* words, key and otherwise */
+ word_index = vlib_lex_add_table ("word");
+
+ vlib_lex_set_action_range (top_index, 'a', 'z', VLIB_LEX_ADD_TO_TOKEN, ~0,
+ word_index);
+ vlib_lex_set_action_range (top_index, 'A', 'Z', VLIB_LEX_ADD_TO_TOKEN, ~0,
+ word_index);
+
+ vlib_lex_set_action_range (word_index, 0, 0x7f, VLIB_LEX_KEYWORD_CHECK, ~0,
+ top_index);
+
+ vlib_lex_set_action_range (word_index, 'a', 'z', VLIB_LEX_ADD_TO_TOKEN, ~0,
+ word_index);
+ vlib_lex_set_action_range (word_index, 'A', 'Z', VLIB_LEX_ADD_TO_TOKEN, ~0,
+ word_index);
+ vlib_lex_set_action_range (word_index, '_', '_', VLIB_LEX_ADD_TO_TOKEN, ~0,
+ word_index);
+ vlib_lex_set_action_range (word_index, '0', '9', VLIB_LEX_ADD_TO_TOKEN, ~0,
+ word_index);
+
+ return 0;
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */