Emacs-lisp scripts to generate complete vpp plugins
Change-Id: Id71147a8d5e30aadfb90dc10ea9468cf36ef23a8 Signed-off-by: Dave Barach <dave@barachs.net>
This commit is contained in:
86
build-root/emacs-lisp/README
Normal file
86
build-root/emacs-lisp/README
Normal file
@ -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
|
||||||
|
$ make
|
||||||
|
$ sudo make install
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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
|
;; list of clib / vlib / vnet / vpp skeleton files
|
||||||
|
|
||||||
(load-file "./cli-cmd-skel.el")
|
(load-file "./cli-cmd-skel.el")
|
||||||
(load-file "./pipe-skel.el")
|
(load-file "./config-skel.el")
|
||||||
(load-file "./dual-loop-skel.el")
|
(load-file "./dual-loop-skel.el")
|
||||||
(load-file "./periodic-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-c-skel.el")
|
||||||
(load-file "./tunnel-h-skel.el")
|
|
||||||
(load-file "./tunnel-encap-skel.el")
|
|
||||||
(load-file "./tunnel-decap-skel.el")
|
(load-file "./tunnel-decap-skel.el")
|
||||||
|
(load-file "./tunnel-encap-skel.el")
|
||||||
|
(load-file "./tunnel-h-skel.el")
|
||||||
|
43
build-root/emacs-lisp/plugin-all-apih-skel.el
Normal file
43
build-root/emacs-lisp/plugin-all-apih-skel.el
Normal file
@ -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>
|
||||||
|
")
|
48
build-root/emacs-lisp/plugin-api-skel.el
Normal file
48
build-root/emacs-lisp/plugin-api-skel.el
Normal file
@ -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;
|
||||||
|
};
|
||||||
|
")
|
42
build-root/emacs-lisp/plugin-configure-skel.el
Normal file
42
build-root/emacs-lisp/plugin-configure-skel.el
Normal file
@ -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])
|
||||||
|
")
|
66
build-root/emacs-lisp/plugin-h-skel.el
Normal file
66
build-root/emacs-lisp/plugin-h-skel.el
Normal file
@ -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__ */
|
||||||
|
")
|
262
build-root/emacs-lisp/plugin-main-skel.el
Normal file
262
build-root/emacs-lisp/plugin-main-skel.el
Normal file
@ -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);
|
||||||
|
")
|
||||||
|
|
74
build-root/emacs-lisp/plugin-makefile-skel.el
Normal file
74
build-root/emacs-lisp/plugin-makefile-skel.el
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
;;; 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
|
||||||
|
endif
|
||||||
|
")
|
55
build-root/emacs-lisp/plugin-msg-enum-skel.el
Normal file
55
build-root/emacs-lisp/plugin-msg-enum-skel.el
Normal file
@ -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 */
|
||||||
|
")
|
295
build-root/emacs-lisp/plugin-node-skel.el
Normal file
295
build-root/emacs-lisp/plugin-node-skel.el
Normal file
@ -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\",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
")
|
235
build-root/emacs-lisp/plugin-test-skel.el
Normal file
235
build-root/emacs-lisp/plugin-test-skel.el
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
")
|
35
build-root/emacs-lisp/plugin.el
Normal file
35
build-root/emacs-lisp/plugin.el
Normal file
@ -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))))
|
||||||
|
|
Reference in New Issue
Block a user