Merge "Submit initial test framework skeleton."
authorEd Warnicke <eaw@cisco.com>
Tue, 5 Jan 2016 03:13:02 +0000 (03:13 +0000)
committerGerrit Code Review <gerrit@projectrotterdam.info>
Tue, 5 Jan 2016 03:13:02 +0000 (03:13 +0000)
12 files changed:
build-root/emacs-lisp/README [new file with mode: 0644]
build-root/emacs-lisp/all-skel.el
build-root/emacs-lisp/plugin-all-apih-skel.el [new file with mode: 0644]
build-root/emacs-lisp/plugin-api-skel.el [new file with mode: 0644]
build-root/emacs-lisp/plugin-configure-skel.el [new file with mode: 0644]
build-root/emacs-lisp/plugin-h-skel.el [new file with mode: 0644]
build-root/emacs-lisp/plugin-main-skel.el [new file with mode: 0644]
build-root/emacs-lisp/plugin-makefile-skel.el [new file with mode: 0644]
build-root/emacs-lisp/plugin-msg-enum-skel.el [new file with mode: 0644]
build-root/emacs-lisp/plugin-node-skel.el [new file with mode: 0644]
build-root/emacs-lisp/plugin-test-skel.el [new file with mode: 0644]
build-root/emacs-lisp/plugin.el [new file with mode: 0644]

diff --git a/build-root/emacs-lisp/README b/build-root/emacs-lisp/README
new file mode 100644 (file)
index 0000000..7dac8a0
--- /dev/null
@@ -0,0 +1,86 @@
+How to construct a complete plugin using the emacs skeletons
+
+0. Install open-vpp, including the development package.
+
+1. Load emacs skeletons
+
+   M-x find-file all-skel.el
+   M-x eval-buffer
+
+2. Pick a single-word, lower-case name for your plugin. For example: macswap.
+Hereafter, we'll refer to the selected name as <plugin-name>.
+
+3. Generate the entire plugin:
+
+   M-x make-plugin
+   Plugin-name: <plugin-name>
+
+Or, generate each file individually:
+
+3. Create the required directories, e.g. under .../vpp
+
+   $ mkdir -p <plugin-name>-plugin/<plugin-name>
+
+4. Create <plugin-name>-plugin/{configure.ac,Makefile.am}
+
+   M-x find-file <plugin-name>-plugin/configure.ac
+   M-x plugin-configure-skel
+   
+   M-x find-file <plugin-name>-plugin/Makefile.am
+   M-x plugin-makefile.skel
+
+5. Create the api skeleton
+   M-x find-file <plugin-name>-plugin/<plugin-name>/<plugin-name>.api
+   M-x plugin-api-skel
+
+6. Create the api message enumeration header file
+   M-x find-file <plugin-name>-plugin/<plugin-name>/<plugin-name>_msg_enum.h
+   M-x plugin-msg-enum-skel
+
+7. Create the "all-api" header file
+   M-x find-file <plugin-name>-plugin/<plugin-name>/<plugin-name>_all_api_h.h
+   M-x plugin-all-apih-skel
+
+8. Create the main data structure definition header file
+   M-x find-file <plugin-name>-plugin/<plugin-name>/<plugin-name>.h
+   M-x plugin-h-skel
+
+9. Create the plugin main C file
+   M-x find-file <plugin-name>-plugin/<plugin-name>/<plugin-name>.c
+   M-x plugin-main-skel
+
+10. Create the vpp-api-test plugin main C file
+   M-x find-file <plugin-name>-plugin/<plugin-name>/<plugin-name>_test.c
+   M-x plugin-test-skel
+
+11. Create the data plane packet processing node
+   M-x find-file <plugin-name>-plugin/<plugin-name>/node.c
+   M-x plugin-node-skel
+
+12. Process autotools input files
+
+   $ cd <plugin-name>-plugin
+   $ autoreconf -i -f
+
+13. Build the plugin skeleton
+
+   $ mkdir build
+   $ cd build
+   $ ../configure --with-plugin-toolkit
+   $ make
+   $ sudo make install
+
+
+
+
+
+
+
+
+   
+
+
+
+
+
+
index afc2d37..fc96199 100644 (file)
@@ -1,11 +1,37 @@
+;;; 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.
+
+;; plugin all-in-1 program
+
+(load-file "./plugin.el")
+
 ;; list of clib / vlib / vnet / vpp skeleton files
 
 (load-file "./cli-cmd-skel.el")
-(load-file "./pipe-skel.el")
+(load-file "./config-skel.el")
 (load-file "./dual-loop-skel.el")
 (load-file "./periodic-skel.el")
-(load-file "./config-skel.el")
+(load-file "./pipe-skel.el")
+(load-file "./plugin-all-apih-skel.el")
+(load-file "./plugin-api-skel.el")
+(load-file "./plugin-configure-skel.el")
+(load-file "./plugin-h-skel.el")
+(load-file "./plugin-main-skel.el")
+(load-file "./plugin-makefile-skel.el")
+(load-file "./plugin-msg-enum-skel.el")
+(load-file "./plugin-node-skel.el")
+(load-file "./plugin-test-skel.el")
 (load-file "./tunnel-c-skel.el")
-(load-file "./tunnel-h-skel.el")
-(load-file "./tunnel-encap-skel.el")
 (load-file "./tunnel-decap-skel.el")
+(load-file "./tunnel-encap-skel.el")
+(load-file "./tunnel-h-skel.el")
diff --git a/build-root/emacs-lisp/plugin-all-apih-skel.el b/build-root/emacs-lisp/plugin-all-apih-skel.el
new file mode 100644 (file)
index 0000000..8cc74b8
--- /dev/null
@@ -0,0 +1,43 @@
+;;; plugin-all-apih-skel.el - vpp engine plug-in "all-apih.c" skeleton
+;;;
+;;; 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.
+
+(require 'skeleton)
+
+(define-skeleton plugin-all-apih-skel
+"Insert a plug-in 'all_api_h.h' skeleton "
+nil
+'(if (not (boundp 'plugin-name))
+     (setq plugin-name (read-string "Plugin name: ")))
+'(setq PLUGIN-NAME (upcase plugin-name))
+"
+/*
+ * " plugin-name "_all_api_h.h - skeleton vpp engine plug-in api #include file
+ *
+ * Copyright (c) <current-year> <your-organization>
+ * 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 <" plugin-name "/" plugin-name ".api.h>
+")
diff --git a/build-root/emacs-lisp/plugin-api-skel.el b/build-root/emacs-lisp/plugin-api-skel.el
new file mode 100644 (file)
index 0000000..c838844
--- /dev/null
@@ -0,0 +1,48 @@
+;;; plugin-api-skel.el - vpp engine plug-in "all-apih.c" skeleton
+;;;
+;;; 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.
+
+(require 'skeleton)
+
+(define-skeleton plugin-api-skel
+"Insert a plug-in '<name>.api' skeleton "
+nil
+'(if (not (boundp 'plugin-name))
+     (setq plugin-name (read-string "Plugin name: ")))
+'(setq PLUGIN-NAME (upcase plugin-name))
+"
+/* Define a simple enable-disable binary API to control the feature */
+
+define " plugin-name "_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;
+};
+
+define " plugin-name "_enable_disable_reply {
+    /* From the request */
+    u32 context;
+
+    /* Return value, zero means all OK */
+    i32 retval;
+};
+")
diff --git a/build-root/emacs-lisp/plugin-configure-skel.el b/build-root/emacs-lisp/plugin-configure-skel.el
new file mode 100644 (file)
index 0000000..8f91f10
--- /dev/null
@@ -0,0 +1,42 @@
+;;; plugin-configure-skel.el - vpp engine plug-in "main.c" skeleton
+;;;
+;;; 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.
+
+(require 'skeleton)
+
+(define-skeleton plugin-configure-skel
+"Insert a plug-in 'configure.ac' skeleton "
+nil
+'(if (not (boundp 'plugin-name))
+     (setq plugin-name (read-string "Plugin name: ")))
+'(setq PLUGIN-NAME (upcase plugin-name))
+"
+AC_INIT(" plugin-name "_plugin, 1.0)
+AM_INIT_AUTOMAKE
+
+AC_PROG_LIBTOOL
+AM_PROG_AS
+AC_PROG_CC
+AM_PROG_CC_C_O
+
+AC_ARG_WITH(plugin-toolkit,
+            AC_HELP_STRING([--with-plugin-toolkit],
+            [build using the vpp toolkit]),
+            [with_plugin_toolkit=${prefix}/include],
+            [with_plugin_toolkit=.])
+
+AC_SUBST(TOOLKIT_INCLUDE,[${with_plugin_toolkit}])
+AM_CONDITIONAL(WITH_PLUGIN_TOOLKIT, test \"$with_plugin_toolkit\" != \".\")
+AC_OUTPUT([Makefile])
+")
diff --git a/build-root/emacs-lisp/plugin-h-skel.el b/build-root/emacs-lisp/plugin-h-skel.el
new file mode 100644 (file)
index 0000000..74e32c0
--- /dev/null
@@ -0,0 +1,66 @@
+;;; plugin-h-skel.el - vpp engine plug-in "main.c" skeleton
+;;;
+;;; 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.
+
+(require 'skeleton)
+
+(define-skeleton plugin-h-skel
+"Insert a plug-in 'main.c' skeleton "
+nil
+'(if (not (boundp 'plugin-name))
+     (setq plugin-name (read-string "Plugin name: ")))
+'(setq PLUGIN-NAME (upcase plugin-name))
+"
+/*
+ * " plugin-name ".h - skeleton vpp engine plug-in header file 
+ *
+ * Copyright (c) <current-year> <your-organization>
+ * 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_" plugin-name "_h__
+#define __included_" plugin-name "_h__
+
+#include <vnet/vnet.h>
+#include <vnet/ip/ip.h>
+#include <vnet/ethernet/ethernet.h>
+
+#include <vppinfra/hash.h>
+#include <vppinfra/error.h>
+
+typedef struct {
+    /* API message ID base */
+    u16 msg_id_base;
+
+    /* convenience */
+    vlib_main_t * vlib_main;
+    vnet_main_t * vnet_main;
+    ethernet_main_t * ethernet_main;
+} " plugin-name "_main_t;
+
+" plugin-name "_main_t " plugin-name "_main;
+
+vlib_node_registration_t " plugin-name "_node;
+
+#endif /* __included_" plugin-name "_h__ */
+")
diff --git a/build-root/emacs-lisp/plugin-main-skel.el b/build-root/emacs-lisp/plugin-main-skel.el
new file mode 100644 (file)
index 0000000..e9bd3b5
--- /dev/null
@@ -0,0 +1,262 @@
+;;; plugin-main-skel.el - vpp engine plug-in "main.c" skeleton
+;;;
+;;; 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.
+
+(require 'skeleton)
+
+(define-skeleton plugin-main-skel
+"Insert a plug-in 'main.c' skeleton "
+nil
+'(if (not (boundp 'plugin-name))
+     (setq plugin-name (read-string "Plugin name: ")))
+'(setq PLUGIN-NAME (upcase plugin-name))
+"
+/*
+ * " plugin-name ".c - skeleton vpp engine plug-in 
+ *
+ * Copyright (c) <current-year> <your-organization>
+ * 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 <vnet/vnet.h>
+#include <vnet/plugin/plugin.h>
+#include <" plugin-name "/" plugin-name ".h>
+
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+#include <vlibsocket/api.h>
+
+/* define message IDs */
+#include <" plugin-name "/" plugin-name "_msg_enum.h>
+
+/* define message structures */
+#define vl_typedefs
+#include <" plugin-name "/" plugin-name "_all_api_h.h> 
+#undef vl_typedefs
+
+/* define generated endian-swappers */
+#define vl_endianfun
+#include <" plugin-name "/" plugin-name "_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 <" plugin-name "/" plugin-name "_all_api_h.h> 
+#undef vl_printfun
+
+/* Get the API version number */
+#define vl_api_version(n,v) static u32 api_version=(v);
+#include <" plugin-name "/" plugin-name "_all_api_h.h>
+#undef vl_api_version
+
+/* 
+ * A handy macro to set up a message reply.
+ * Assumes that the following variables are available:
+ * mp - pointer to request message
+ * rmp - pointer to reply message type
+ * rv - return value
+ */
+
+#define REPLY_MACRO(t)                                          \\
+do {                                                            \\
+    unix_shared_memory_queue_t * q =                            \\
+    vl_api_client_index_to_input_queue (mp->client_index);      \\
+    if (!q)                                                     \\
+        return;                                                 \\
+                                                                \\
+    rmp = vl_msg_api_alloc (sizeof (*rmp));                     \\
+    rmp->_vl_msg_id = ntohs((t)+sm->msg_id_base);               \\
+    rmp->context = mp->context;                                 \\
+    rmp->retval = ntohl(rv);                                    \\
+                                                                \\
+    vl_msg_api_send_shmem (q, (u8 *)&rmp);                      \\
+} while(0);
+
+
+/* List of message types that this plugin understands */
+
+#define foreach_" plugin-name "_plugin_api_msg                           \\
+_(" PLUGIN-NAME "_ENABLE_DISABLE, " plugin-name "_enable_disable)
+
+/* 
+ * This routine exists to convince the vlib plugin framework that
+ * we haven't accidentally copied a random .dll into the plugin directory.
+ *
+ * Also collects global variable pointers passed from the vpp engine
+ */
+
+clib_error_t * 
+vlib_plugin_register (vlib_main_t * vm, vnet_plugin_handoff_t * h,
+                      int from_early_init)
+{
+  " plugin-name "_main_t * sm = &" plugin-name "_main;
+  clib_error_t * error = 0;
+
+  sm->vlib_main = vm;
+  sm->vnet_main = h->vnet_main;
+  sm->ethernet_main = h->ethernet_main;
+
+  return error;
+}
+
+/* Action function shared between message handler and debug CLI */
+
+int " plugin-name "_enable_disable (" plugin-name "_main_t * sm, u32 sw_if_index,
+                                   int enable_disable)
+{
+  vnet_sw_interface_t * sw;
+  int rv;
+  u32 node_index = enable_disable ? " plugin-name "_node.index : ~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;
+  
+  /* 
+   * Redirect pkts from the driver to the macswap node.
+   * Returns VNET_API_ERROR_UNIMPLEMENTED if the h/w driver
+   * doesn't implement the API. 
+   *
+   * Node_index = ~0 => shut off redirection
+   */
+  rv = vnet_hw_interface_rx_redirect_to_node (sm->vnet_main, sw_if_index,
+                                              node_index);
+  return rv;
+}
+
+static clib_error_t *
+" plugin-name "_enable_disable_command_fn (vlib_main_t * vm,
+                                   unformat_input_t * input,
+                                   vlib_cli_command_t * cmd)
+{
+  " plugin-name "_main_t * sm = &" plugin-name "_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 = " plugin-name "_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, \"" plugin-name "_enable_disable returned %d\",
+                              rv);
+  }
+  return 0;
+}
+
+VLIB_CLI_COMMAND (" plugin-name "_enable_disable_command, static) = {
+    .path = \"" plugin-name " enable-disable\",
+    .short_help = 
+    \"" plugin-name " enable-disable <interface-name> [disable]\",
+    .function = " plugin-name "_enable_disable_command_fn,
+};
+
+/* API message handler */
+static void vl_api_" plugin-name "_enable_disable_t_handler
+(vl_api_" plugin-name "_enable_disable_t * mp)
+{
+  vl_api_" plugin-name "_enable_disable_reply_t * rmp;
+  " plugin-name "_main_t * sm = &" plugin-name "_main;
+  int rv;
+
+  rv = " plugin-name "_enable_disable (sm, ntohl(mp->sw_if_index), 
+                                      (int) (mp->enable_disable));
+  
+  REPLY_MACRO(VL_API_" PLUGIN-NAME "_ENABLE_DISABLE_REPLY);
+}
+
+/* Set up the API message handling tables */
+static clib_error_t *
+" plugin-name "_plugin_api_hookup (vlib_main_t *vm)
+{
+  " plugin-name "_main_t * sm = &" plugin-name "_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_" plugin-name "_plugin_api_msg;
+#undef _
+
+    return 0;
+}
+
+static clib_error_t * " plugin-name "_init (vlib_main_t * vm)
+{
+  " plugin-name "_main_t * sm = &" plugin-name "_main;
+  clib_error_t * error = 0;
+  u8 * name;
+
+  name = format (0, \"" plugin-name "_%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 = " plugin-name "_plugin_api_hookup (vm);
+
+  vec_free(name);
+
+  return error;
+}
+
+VLIB_INIT_FUNCTION (" plugin-name "_init);
+")
+
diff --git a/build-root/emacs-lisp/plugin-makefile-skel.el b/build-root/emacs-lisp/plugin-makefile-skel.el
new file mode 100644 (file)
index 0000000..390f4a4
--- /dev/null
@@ -0,0 +1,76 @@
+;;; plugin-makefile-skel.el - vpp engine plug-in "main.c" skeleton
+;;;
+;;; 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.
+
+(require 'skeleton)
+
+(define-skeleton plugin-makefile-skel
+"Insert a plug-in 'Makefile.am' skeleton "
+nil
+'(if (not (boundp 'plugin-name))
+     (setq plugin-name (read-string "Plugin name: ")))
+'(setq PLUGIN-NAME (upcase plugin-name))
+"
+# Copyright (c) <current-year> <your-organization>
+# 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@TOOLKIT_INCLUDE@
+
+lib_LTLIBRARIES = " plugin-name "_plugin.la " plugin-name "_test_plugin.la
+" plugin-name "_plugin_la_SOURCES = " plugin-name "/" plugin-name ".c  \\
+        " plugin-name "/node.c \\
+       " plugin-name "/" plugin-name "_plugin.api.h 
+" plugin-name "_plugin_la_LDFLAGS = -module
+
+BUILT_SOURCES = " plugin-name "/" plugin-name ".api.h
+
+SUFFIXES = .api.h .api
+
+%.api.h: %.api
+       mkdir -p `dirname $@` ; \\
+       $(CC) $(CPPFLAGS) -E -P -C -x c $^ \\
+       | vppapigen --input - --output $@ --show-name $@
+
+nobase_include_HEADERS =                       \\
+  " plugin-name "/" plugin-name "_all_api_h.h                  \\
+  " plugin-name "/" plugin-name "_msg_enum.h                   \\
+  " plugin-name "/" plugin-name ".api.h
+
+" plugin-name "_test_plugin_la_SOURCES = \\
+  " plugin-name "/" plugin-name "_test.c " plugin-name "/" plugin-name "_plugin.api.h
+" plugin-name "_test_plugin_la_LDFLAGS = -module
+
+if WITH_PLUGIN_TOOLKIT
+install-data-hook:
+       mkdir /usr/lib/vpp_plugins || true
+       mkdir /usr/lib/vpp_api_test_plugins || true
+       cp $(prefix)/lib/" plugin-name "_plugin.so.*.*.* /usr/lib/vpp_plugins
+       cp $(prefix)/lib/" plugin-name "_test_plugin.so.*.*.* \\
+               /usr/lib/vpp_api_test_plugins
+       rm -f $(prefix)/lib/" plugin-name "_plugin.*
+       rm -f $(prefix)/lib/" plugin-name "_test_plugin.*
+endif
+")
diff --git a/build-root/emacs-lisp/plugin-msg-enum-skel.el b/build-root/emacs-lisp/plugin-msg-enum-skel.el
new file mode 100644 (file)
index 0000000..ef0348b
--- /dev/null
@@ -0,0 +1,55 @@
+;;; plugin-msg-enum-skel.el - vpp engine plug-in message enum skeleton
+;;;
+;;; 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.
+
+(require 'skeleton)
+
+(define-skeleton plugin-msg-enum-skel
+"Insert a plug-in message enumeration skeleton "
+nil
+'(if (not (boundp 'plugin-name))
+     (setq plugin-name (read-string "Plugin name: ")))
+'(setq PLUGIN-NAME (upcase plugin-name))
+"
+/*
+ * " plugin-name "_msg_enum.h - skeleton vpp engine plug-in message enumeration
+ *
+ * Copyright (c) <current-year> <your-organization>
+ * 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_" plugin-name "_msg_enum_h
+#define included_" plugin-name "_msg_enum_h
+
+#include <vppinfra/byte_order.h>
+
+#define vl_msg_id(n,h) n,
+typedef enum {
+#include <" plugin-name "/" plugin-name "_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_" plugin-name "_msg_enum_h */
+")
diff --git a/build-root/emacs-lisp/plugin-node-skel.el b/build-root/emacs-lisp/plugin-node-skel.el
new file mode 100644 (file)
index 0000000..03ebedd
--- /dev/null
@@ -0,0 +1,295 @@
+;;; plugin-node-skel.el - vpp engine plug-in "node.c" skeleton
+;;;
+;;; 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.
+
+(require 'skeleton)
+
+(define-skeleton plugin-node-skel
+"Insert a plug-in 'node.c' skeleton "
+nil
+'(if (not (boundp 'plugin-name))
+     (setq plugin-name (read-string "Plugin name: ")))
+'(setq PLUGIN-NAME (upcase plugin-name))
+"
+/*
+ * node.c - skeleton vpp engine plug-in dual-loop node skeleton
+ *
+ * Copyright (c) <current-year> <your-organization>
+ * 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 <" plugin-name "/" plugin-name ".h>
+
+typedef struct {
+  u32 next_index;
+  u32 sw_if_index;
+} " plugin-name "_trace_t;
+
+/* packet trace format function */
+static u8 * format_" plugin-name "_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 *);
+  " plugin-name "_trace_t * t = va_arg (*args, " plugin-name "_trace_t *);
+  
+  s = format (s, \"" PLUGIN-NAME ": sw_if_index %d, next index %d\",
+              t->sw_if_index, t->next_index);
+  return s;
+}
+
+vlib_node_registration_t " plugin-name "_node;
+
+#define foreach_" plugin-name "_error \\
+_(SWAPPED, \"Mac swap packets processed\")
+
+typedef enum {
+#define _(sym,str) " PLUGIN-NAME "_ERROR_##sym,
+  foreach_" plugin-name "_error
+#undef _
+  " PLUGIN-NAME "_N_ERROR,
+} " plugin-name "_error_t;
+
+static char * " plugin-name "_error_strings[] = {
+#define _(sym,string) string,
+  foreach_" plugin-name "_error
+#undef _
+};
+
+typedef enum {
+  " PLUGIN-NAME "_NEXT_INTERFACE_OUTPUT,
+  " PLUGIN-NAME "_N_NEXT,
+} " plugin-name "_next_t;
+
+#define foreach_mac_address_offset              \\
+_(0)                                            \\
+_(1)                                            \\
+_(2)                                            \\
+_(3)                                            \\
+_(4)                                            \\
+_(5)
+
+static uword
+" plugin-name "_node_fn (vlib_main_t * vm,
+                 vlib_node_runtime_t * node,
+                 vlib_frame_t * frame)
+{
+  u32 n_left_from, * from, * to_next;
+  " plugin-name "_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 = " PLUGIN-NAME "_NEXT_INTERFACE_OUTPUT;
+          u32 next1 = " PLUGIN-NAME "_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) 
+                {
+                    " plugin-name "_trace_t *t = 
+                      vlib_add_trace (vm, node, b0, sizeof (*t));
+                    t->sw_if_index = sw_if_index0;
+                    t->next_index = next0;
+                  }
+                if (b1->flags & VLIB_BUFFER_IS_TRACED) 
+                  {
+                    " plugin-name "_trace_t *t = 
+                      vlib_add_trace (vm, node, b1, sizeof (*t));
+                    t->sw_if_index = sw_if_index1;
+                    t->next_index = next1;
+                  }
+              }
+            
+            /* 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 = " PLUGIN-NAME "_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))) {
+            " plugin-name "_trace_t *t = 
+               vlib_add_trace (vm, node, b0, sizeof (*t));
+            t->sw_if_index = sw_if_index0;
+            t->next_index = next0;
+            }
+            
+          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, " plugin-name "_node.index, 
+                               " PLUGIN-NAME "_ERROR_SWAPPED, pkts_swapped);
+  return frame->n_vectors;
+}
+
+VLIB_REGISTER_NODE (" plugin-name "_node) = {
+  .function = " plugin-name "_node_fn,
+  .name = \"" plugin-name "\",
+  .vector_size = sizeof (u32),
+  .format_trace = format_" plugin-name "_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  
+  .n_errors = ARRAY_LEN(" plugin-name "_error_strings),
+  .error_strings = " plugin-name "_error_strings,
+
+  .n_next_nodes = " PLUGIN-NAME "_N_NEXT,
+
+  /* edit / add dispositions here */
+  .next_nodes = {
+        [" PLUGIN-NAME "_NEXT_INTERFACE_OUTPUT] = \"interface-output\",
+  },
+};
+")
diff --git a/build-root/emacs-lisp/plugin-test-skel.el b/build-root/emacs-lisp/plugin-test-skel.el
new file mode 100644 (file)
index 0000000..9d2374b
--- /dev/null
@@ -0,0 +1,235 @@
+;;; plugin-test-skel.el - vpp-api-test plug-in skeleton
+;;;
+;;; 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.
+
+(require 'skeleton)
+
+(define-skeleton plugin-test-skel
+"Insert a plug-in vpp-api-test skeleton "
+nil
+'(if (not (boundp 'plugin-name))
+     (setq plugin-name (read-string "Plugin name: ")))
+'(setq PLUGIN-NAME (upcase plugin-name))
+"
+/*
+ * " plugin-name ".c - skeleton vpp-api-test plug-in 
+ *
+ * Copyright (c) <current-year> <your-organization>
+ * 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 <vlibsocket/api.h>
+#include <vppinfra/error.h>
+
+uword unformat_sw_if_index (unformat_input_t * input, va_list * args);
+
+/* Declare message IDs */
+#include <" plugin-name "/" plugin-name "_msg_enum.h>
+
+/* define message structures */
+#define vl_typedefs
+#include <" plugin-name "/" plugin-name "_all_api_h.h> 
+#undef vl_typedefs
+
+/* declare message handlers for each api */
+
+#define vl_endianfun             /* define message structures */
+#include <" plugin-name "/" plugin-name "_all_api_h.h> 
+#undef vl_endianfun
+
+/* instantiate all the print functions we know about */
+#define vl_print(handle, ...)
+#define vl_printfun
+#include <" plugin-name "/" plugin-name "_all_api_h.h> 
+#undef vl_printfun
+
+/* Get the API version number. */
+#define vl_api_version(n,v) static u32 api_version=(v);
+#include <" plugin-name "/" plugin-name "_all_api_h.h>
+#undef vl_api_version
+
+
+typedef struct {
+    /* API message ID base */
+    u16 msg_id_base;
+    vat_main_t *vat_main;
+} " plugin-name "_test_main_t;
+
+" plugin-name "_test_main_t " plugin-name "_test_main;
+
+#define foreach_standard_reply_retval_handler   \\
+_(" plugin-name "_enable_disable_reply)
+
+#define _(n)                                            \\
+    static void vl_api_##n##_t_handler                  \\
+    (vl_api_##n##_t * mp)                               \\
+    {                                                   \\
+        vat_main_t * vam = " plugin-name "_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                                       \\
+_(" PLUGIN-NAME "_ENABLE_DISABLE_REPLY, " plugin-name "_enable_disable_reply)
+
+
+/* M: construct, but don't yet send a message */
+
+#define M(T,t)                                                  \\
+do {                                                            \\
+    vam->result_ready = 0;                                      \\
+    mp = vl_msg_api_alloc(sizeof(*mp));                         \\
+    memset (mp, 0, sizeof (*mp));                               \\
+    mp->_vl_msg_id = ntohs (VL_API_##T + sm->msg_id_base);      \\
+    mp->client_index = vam->my_client_index;                    \\
+} while(0);
+
+#define M2(T,t,n)                                               \\
+do {                                                            \\
+    vam->result_ready = 0;                                      \\
+    mp = vl_msg_api_alloc(sizeof(*mp)+(n));                     \\
+    memset (mp, 0, sizeof (*mp));                               \\
+    mp->_vl_msg_id = ntohs (VL_API_##T + sm->msg_id_base);      \\
+    mp->client_index = vam->my_client_index;                    \\
+} while(0);
+
+/* S: send a message */
+#define S (vl_msg_api_send_shmem (vam->vl_input_queue, (u8 *)&mp))
+
+/* W: wait for results, with timeout */
+#define W                                       \\
+do {                                            \\
+    timeout = vat_time_now (vam) + 1.0;         \\
+                                                \\
+    while (vat_time_now (vam) < timeout) {      \\
+        if (vam->result_ready == 1) {           \\
+            return (vam->retval);               \\
+        }                                       \\
+    }                                           \\
+    return -99;                                 \\
+} while(0);
+
+static int api_" plugin-name "_enable_disable (vat_main_t * vam)
+{
+    " plugin-name "_test_main_t * sm = &" plugin-name "_test_main;
+    unformat_input_t * i = vam->input;
+    f64 timeout;
+    int enable_disable = 1;
+    u32 sw_if_index = ~0;
+    vl_api_" plugin-name "_enable_disable_t * mp;
+
+    /* 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(" PLUGIN-NAME "_ENABLE_DISABLE, " plugin-name "_enable_disable);
+    mp->sw_if_index = ntohl (sw_if_index);
+    mp->enable_disable = enable_disable;
+
+    /* send it... */
+    S;
+
+    /* Wait for a reply... */
+    W;
+}
+
+/* 
+ * List of messages that the api test plugin sends,
+ * and that the data plane plugin processes
+ */
+#define foreach_vpe_api_msg \\
+_(" plugin-name "_enable_disable, \"<intfc> [disable]\")
+
+void vat_api_hookup (vat_main_t *vam)
+{
+    " plugin-name "_test_main_t * sm = &" plugin-name "_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)
+{
+  " plugin-name "_test_main_t * sm = &" plugin-name "_test_main;
+  u8 * name;
+
+  sm->vat_main = vam;
+
+  /* Ask the vpp engine for the first assigned message-id */
+  name = format (0, \"" plugin-name "_%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)
+    vat_api_hookup (vam);
+  
+  vec_free(name);
+  
+  return 0;
+}
+")
diff --git a/build-root/emacs-lisp/plugin.el b/build-root/emacs-lisp/plugin.el
new file mode 100644 (file)
index 0000000..4c24e7d
--- /dev/null
@@ -0,0 +1,35 @@
+(defun make-plugin ()
+  "Create a plugin"
+  (interactive)
+  (save-excursion
+    (let (cd-args cmd-args start-dir)
+      (setq start-dir default-directory)
+      (makunbound 'plugin-name)
+      (makunbound 'PLUGIN-NAME)
+      (setq plugin-name (read-string "Plugin name: "))
+      (setq PLUGIN-NAME (upcase plugin-name))
+      (setq cmd-args (concat "mkdir -p " plugin-name "-plugin/" plugin-name))
+      (shell-command cmd-args)
+      (setq cd-args (concat start-dir plugin-name "-plugin"))
+      (setq default-directory cd-args)
+      (find-file "Makefile.am")
+      (plugin-makefile-skel)
+      (find-file "configure.ac")
+      (plugin-configure-skel)
+      (setq default-directory (concat cd-args "/" plugin-name))
+      (find-file (concat plugin-name ".api"))
+      (plugin-api-skel)
+      (find-file (concat plugin-name "_all_api_h.h"))
+      (plugin-all-apih-skel)
+      (find-file (concat plugin-name ".h"))
+      (plugin-h-skel)
+      (find-file (concat plugin-name ".c"))
+      (plugin-main-skel)
+      (find-file (concat plugin-name "_msg_enum.h"))
+      (plugin-msg-enum-skel)
+      (find-file "node.c")
+      (plugin-node-skel)
+      (find-file (concat plugin-name "_test.c"))
+      (plugin-test-skel)
+      (cd start-dir))))
+