From 54ccf2261cb1f4afd966b7b1e92689183cb17836 Mon Sep 17 00:00:00 2001 From: Chris Luke Date: Mon, 25 Jul 2016 16:38:11 -0400 Subject: VPP-221 CLI auto-documentation infrastructure As a step before Doxygen, extract CLI-related struct initializers from the code and parse that into a summary of the CLI commands available with the provided help text, such as it is. At the moment this only renders this into an indexed Markdown file that Doxygen then picks up but later we can use this information to enrich the existing VLIB_CLI_COMMAND macro documentor as well as provide runtime documentation to VPP that is stored on disk outside the binary image. Additionally support a comment block immediately prior to VLIB_CLI_COMMAND CLI command definitions in the form /*? ... ?*/ that can be used to include long-form documentation without having it compiled into VPP. Examples of documenting CLI commands can be found in vlib/vlib/unix/cli.c which, whilst not perfect, should provide a starting point. Screen captures of sample output can be seen at https://chrisy.flirble.org/vpp/doxy-cli-example.png and https://chrisy.flirble.org/vpp/doxy-cli-index.png . Next, shift the Doxygen root makefile targets to their own Makefile. The primary reason for this is that the siphon targets do dependency tracking which means it needs to generate those dependencies whenever make is run; that is pointless if we're not going to generate any documentation. This includes the package dependencies since they since they sometimes unnecessarily interfere with the code build in some cases at the moment; later we will look to building a Python venv to host the Python modules we use. One final remark: In future we may consider deprecating .long_help in the VLIB_CLI_COMMAND structure entirely but add perhaps .usage_help. .short_help would be reserved for a summary of the command function and .usage_help provide the syntax of that command. These changes would provide great semantic value to the automaticly generated CLI documentation. I could also see having .long_help replaced by a mechanism that reads it from disk at runtime with a rudimentary Markdown/Doxygen filter so that we can use the same text that is used in the published documentation. Change-Id: I80d6fe349b47dce649fa77d21ffec0ddb45c7bbf Signed-off-by: Chris Luke --- doxygen/Makefile | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 doxygen/Makefile (limited to 'doxygen/Makefile') diff --git a/doxygen/Makefile b/doxygen/Makefile new file mode 100644 index 00000000..7bdc8ee9 --- /dev/null +++ b/doxygen/Makefile @@ -0,0 +1,122 @@ +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# Build the documentation +# + +# These should be passed in by the root Makefile +WS_ROOT ?= $(CURDIR)/.. +BR ?= $(WS_ROOT)/build-root + +# Package dependencies +DOC_DEB_DEPENDS = doxygen graphviz python-pyparsing +DOC_RPM_DEPENDS = doxygen graphviz pyparsing + +# Doxygen configuration and our utility scripts +DOXY_DIR ?= $(WS_ROOT)/doxygen + +# Input directories and files +DOXY_INPUT ?= \ + README.md \ + vppinfra \ + svm \ + vlib \ + vlib-api \ + vnet \ + vpp \ + vpp-api \ + plugins + +# Target directory for doxygen output +DOXY_OUTPUT ?= $(BR)/docs + +# Siphoned fragments end up in here +SIPHON_INPUT ?= $(DOXY_OUTPUT)/siphon_fragments + +# Siphoned fragements are processed into here +SIPHON_OUTPUT ?= $(DOXY_OUTPUT)/siphon_docs + +# Extra document inputs that are processed in addition to DOXY_INPUT +EXTRA_DOXY_INPUT += $(SIPHON_OUTPUT) + +# All the siphon types we know about +SIPHONS ?= clicmd + +SIPHON_FILES = $(addprefix $(SIPHON_INPUT)/,$(addsuffix .siphon,$(SIPHONS))) +SIPHON_DOCS = $(addprefix $(SIPHON_OUTPUT)/,$(addsuffix .md,$(SIPHONS))) + +$(BR)/.doxygen-bootstrap.ok: +ifeq ($(OS_ID),ubuntu) + @sudo -E apt-get $(CONFIRM) $(FORCE) install $(DOC_DEB_DEPENDS) +else ifneq ("$(wildcard /etc/redhat-release)","") + @sudo yum install $(CONFIRM) $(DOC_RPM_DEPENDS) +else + $(error "This option currently works only on Ubuntu or Centos systems") +endif + @touch $@ + +.PHONY: bootstrap-doxygen +bootstrap-doxygen: $(BR)/.doxygen-bootstrap.ok + +.DELETE_ON_ERROR: $(BR)/.doxygen-siphon.dep +$(BR)/.doxygen-siphon.dep: Makefile + set -e; rm -f "$@"; for input in $(DOXY_INPUT); do \ + find "$(WS_ROOT)/$$input" -type f \ + \( -name '*.[ch]' -or -name '*.dox' \) \ + -print | sed -e "s/^/\$$(SIPHON_FILES): /" >> $@; \ + done + +# Include the source -> siphon dependencies +-include $(BR)/.doxygen-siphon.dep + +.NOTPARALLEL: $(SIPHON_FILES) +$(SIPHON_FILES): $(DOXY_DIR)/siphon_generate.py $(BR)/.doxygen-bootstrap.ok + @rm -rf "$(SIPHON_INPUT)" "$(SIPHON_OUTPUT)" + @mkdir -p "$(SIPHON_INPUT)" "$(SIPHON_OUTPUT)" + set -e; for input in $(DOXY_INPUT); do \ + cd "$(WS_ROOT)"; \ + find "$$input" -type f \ + \( -name '*.[ch]' -or -name '*.dox' \) \ + -print >> $(SIPHON_INPUT)/files; \ + done + set -e; cd "$(WS_ROOT)"; $(DOXY_DIR)/siphon_generate.py \ + --output="$(SIPHON_INPUT)" \ + "@$(SIPHON_INPUT)/files" + + +.DELETE_ON_ERROR: $(SIPHON_DOCS) +$(SIPHON_OUTPUT)/%.md: $(SIPHON_INPUT)/%.siphon $(DOXY_DIR)/siphon_process.py + set -e; cd "$(WS_ROOT)"; \ + $(DOXY_DIR)/siphon_process.py --type=$(basename $(notdir $<)) \ + --output="$(SIPHON_OUTPUT)" $< > $@ + +# This target can be used just to generate the siphoned docs +.PHONY: doxygen-siphon +doxygen-siphon: $(SIPHON_DOCS) + +# Generate the doxygen docs +doxygen: $(SIPHON_DOCS) + @mkdir -p "$(DOXY_OUTPUT)" + set -e; cd "$(WS_ROOT)"; \ + ROOT="$(WS_ROOT)" \ + BUILD_ROOT="$(BR)" \ + INPUT="$(addprefix $(WS_ROOT)/,$(DOXY_INPUT)) $(EXTRA_DOXY_INPUT)" \ + HTML=YES \ + VERSION="`git describe --tags --dirty`" \ + doxygen $(DOXY_DIR)/doxygen.cfg + +wipe-doxygen: + rm -rf "$(BR)/docs" "$(BR)/.doxygen-siphon.d" + -- cgit 1.2.3-korg From e0d802bc5356594d4e9621ca4cf8cfa8069d9e8e Mon Sep 17 00:00:00 2001 From: Chris Luke Date: Wed, 31 Aug 2016 10:04:58 -0400 Subject: VPP-221 Loosen Doxygen CLI command struct parser Make the struct parser slighty slightly more accomodating of whitespace in places it has no business being. Also add missing OS_ID thing to Doxygen makefile. Change-Id: Id3d198fd926f7a6c2ed40bc2d08907aad5d5ac33 Signed-off-by: Chris Luke --- Makefile | 2 +- doxygen/Makefile | 1 + doxygen/siphon_process.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) (limited to 'doxygen/Makefile') diff --git a/Makefile b/Makefile index 5808a333..f218cb08 100644 --- a/Makefile +++ b/Makefile @@ -242,7 +242,7 @@ cscope: cscope.files export DOXY_DIR ?= $(WS_ROOT)/doxygen define make-doxy - @WS_ROOT="$(WS_ROOT)" BR="$(BR)" make -C $(DOXY_DIR) $@ + @OS_ID="$(OS_ID)" WS_ROOT="$(WS_ROOT)" BR="$(BR)" make -C $(DOXY_DIR) $@ endef .PHONY: bootstrap-doxygen doxygen wipe-doxygen diff --git a/doxygen/Makefile b/doxygen/Makefile index 7bdc8ee9..8e916526 100644 --- a/doxygen/Makefile +++ b/doxygen/Makefile @@ -19,6 +19,7 @@ # These should be passed in by the root Makefile WS_ROOT ?= $(CURDIR)/.. BR ?= $(WS_ROOT)/build-root +OS_ID ?= $(shell grep '^ID=' /etc/os-release | cut -f2- -d= | sed -e 's/\"//g') # Package dependencies DOC_DEB_DEPENDS = doxygen graphviz python-pyparsing diff --git a/doxygen/siphon_process.py b/doxygen/siphon_process.py index 80add4b9..82a166d3 100755 --- a/doxygen/siphon_process.py +++ b/doxygen/siphon_process.py @@ -181,7 +181,7 @@ def getMacroInitializerBNF(): expr = (literal | var) # TODO - member = pp.Combine(dot + varName + pp.Optional("[" + arrayIndex + "]")) + member = pp.Combine(dot + varName + pp.Optional("[" + arrayIndex + "]"), adjacent=False) value = (expr | cs) entry = pp.Group(pp.Optional(member + equals, default="") + value) -- cgit 1.2.3-korg From 16bcf7d8dcd411e6a6b8d217cce5e450f7357bb3 Mon Sep 17 00:00:00 2001 From: Chris Luke Date: Thu, 1 Sep 2016 14:31:46 -0400 Subject: VPP-346 A swathe of doc fixes Fixes various Doxygen warnings and other structural defects. Note: This does not attempt to improve the content of the documentation; only to improve the syntax and structure of it and in some cases the consistency. Change-Id: Ib1915f33edbdbc4558c85565de80dce323193906 Signed-off-by: Chris Luke --- doxygen/Makefile | 4 +++ doxygen/doxygen.cfg | 4 ++- doxygen/filter_c.py | 49 +++++++++++++++++++++++----------- doxygen/filter_h.py | 53 +++++++++++++++++++++++++++++++++++++ vnet/vnet/interface_cli.c | 9 ++++++- vnet/vnet/ip/lookup.h | 12 ++++++--- vnet/vnet/ipsec-gre/error.def | 2 +- vnet/vnet/ipsec-gre/interface.c | 2 +- vnet/vnet/ipsec-gre/ipsec_gre.c | 2 +- vnet/vnet/ipsec-gre/ipsec_gre.h | 2 +- vnet/vnet/ipsec-gre/node.c | 6 ++--- vnet/vnet/l2/l2_bd.c | 26 ++++++++++-------- vnet/vnet/l2/l2_efp_filter.c | 6 ++--- vnet/vnet/l2/l2_fib.c | 10 +++---- vnet/vnet/l2/l2_flood.c | 4 +-- vnet/vnet/l2/l2_fwd.c | 6 ++--- vnet/vnet/l2/l2_input.c | 19 ++++++------- vnet/vnet/l2/l2_input_classify.c | 31 +++++++++++----------- vnet/vnet/l2/l2_learn.c | 9 ++++--- vnet/vnet/l2/l2_output.c | 9 ++++--- vnet/vnet/l2/l2_output_acl.c | 4 +-- vnet/vnet/l2/l2_output_classify.c | 26 +++++++++--------- vnet/vnet/l2/l2_vtr.c | 6 ++--- vnet/vnet/l2/l2_xcrw.c | 3 ++- vnet/vnet/unix/tuntap.c | 8 +++--- vppinfra/vppinfra/bihash_template.c | 4 +-- vppinfra/vppinfra/bihash_template.h | 4 +-- 27 files changed, 208 insertions(+), 112 deletions(-) create mode 100755 doxygen/filter_h.py (limited to 'doxygen/Makefile') diff --git a/doxygen/Makefile b/doxygen/Makefile index 8e916526..df7d07d7 100644 --- a/doxygen/Makefile +++ b/doxygen/Makefile @@ -40,6 +40,9 @@ DOXY_INPUT ?= \ vpp-api \ plugins +DOXY_INCLUDE_PATH = $(shell set -e; cd $(WS_ROOT); for item in $(DOXY_INPUT); do find $$item -type d; done) +DOXY_INCLUDE_PATH += $(shell set -e; cpp -v &1 | grep -A 1000 '\#include' | awk '/^ /{print $$1}') + # Target directory for doxygen output DOXY_OUTPUT ?= $(BR)/docs @@ -114,6 +117,7 @@ doxygen: $(SIPHON_DOCS) ROOT="$(WS_ROOT)" \ BUILD_ROOT="$(BR)" \ INPUT="$(addprefix $(WS_ROOT)/,$(DOXY_INPUT)) $(EXTRA_DOXY_INPUT)" \ + INCLUDE_PATH="$(DOXY_INCLUDE_PATH)" \ HTML=YES \ VERSION="`git describe --tags --dirty`" \ doxygen $(DOXY_DIR)/doxygen.cfg diff --git a/doxygen/doxygen.cfg b/doxygen/doxygen.cfg index 82687cac..4eb0f373 100644 --- a/doxygen/doxygen.cfg +++ b/doxygen/doxygen.cfg @@ -234,6 +234,7 @@ ALIASES = ALIASES += "node=@xrefitem nodes \"Node Identifier\" \"Node Identifiers\" @c " ## Formatting for CLI commands and output +ALIASES += "cli{1}=
\1
" ALIASES += "clistart=
"
 ALIASES += "cliend=
" @@ -914,6 +915,7 @@ INPUT_FILTER = FILTER_PATTERNS = \ *.c=$(ROOT)/doxygen/filter_c.py \ + *.h=$(ROOT)/doxygen/filter_h.py \ *.api=$(ROOT)/doxygen/filter_api.py # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using @@ -2035,7 +2037,7 @@ SEARCH_INCLUDES = YES # preprocessor. # This tag requires that the tag SEARCH_INCLUDES is set to YES. -INCLUDE_PATH = $(INPUT) +INCLUDE_PATH = $(INCLUDE_PATH) # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the diff --git a/doxygen/filter_c.py b/doxygen/filter_c.py index 733fdefb..30b933ba 100755 --- a/doxygen/filter_c.py +++ b/doxygen/filter_c.py @@ -22,26 +22,45 @@ if len(sys.argv) < 2: sys.exit(1) replace_patterns = [ - # Search for VLIB_CLI_COMMAND, extract its parameter and add a docblock for it - ( re.compile("(?PVLIB_CLI_COMMAND)\s*[(](?P[a-zA-Z0-9_]+)(,[^)]*)?[)]"), r"/** @brief (@em constructor) \g (\g) */ vlib_cli_command_t \g"), - - # Search for VLIB_REGISTER_NODE, extract its parameter and add a docblock for it - ( re.compile("(?PVLIB_REGISTER_NODE)\s*[(](?P[a-zA-Z0-9_]+)(,[^)]*)?[)]"), r"/** @brief (@em constructor) \g (\g) */ vlib_node_registration_t \g"), + # Search for VLIB_CLI_COMMAND, extract its parameters and add a docblock for it + ( re.compile("(?PVLIB_CLI_COMMAND)\s*[(](?P[a-zA-Z0-9_]+)[)]"), + r"/** @brief (@em constructor) \g (\g) */ vlib_cli_command_t \g"), + ( re.compile("(?PVLIB_CLI_COMMAND)\s*[(](?P[a-zA-Z0-9_]+),\s*(?P[^)]*)[)]"), + r"/** @brief (@em constructor) \g (\g) */ \g vlib_cli_command_t \g"), + + # Search for VLIB_REGISTER_NODE, extract its parameters and add a docblock for it + ( re.compile("(?PVLIB_REGISTER_NODE)\s*[(](?P[a-zA-Z0-9_]+)[)]"), + r"/** @brief (@em constructor) \g (\g) */ vlib_node_registration_t \g"), + ( re.compile("(?PVLIB_REGISTER_NODE)\s*[(](?P[a-zA-Z0-9_]+),\s*(?P[^)]*)[)]"), + r"/** @brief (@em constructor) \g (\g) */ \g vlib_node_registration_t \g"), # Search for VLIB_INIT_FUNCTION, extract its parameter and add a docblock for it - ( re.compile("(?PVLIB_INIT_FUNCTION)\s*[(](?P[a-zA-Z0-9_]+)[)]"), r"/** @brief (@em constructor) \g (@ref \g) */ vlib_init_function_t * _vlib_init_function_\g"), - ( re.compile("(?PVLIB_DECLARE_INIT_FUNCTION)\s*[(](?P[a-zA-Z0-9_]+)[)]"), r"/** @brief (@em constructor) \g (@ref \g) */ vlib_init_function_t * _vlib_init_function_\g"), + ( re.compile("(?PVLIB_INIT_FUNCTION)\s*[(](?P[a-zA-Z0-9_]+)[)]"), + r"/** @brief (@em constructor) \g (@ref \g) */ vlib_init_function_t * _vlib_init_function_\g"), + ( re.compile("(?PVLIB_DECLARE_INIT_FUNCTION)\s*[(](?P[a-zA-Z0-9_]+)[)]"), + r"/** @brief (@em constructor) \g (@ref \g) */ vlib_init_function_t * _vlib_init_function_\g"), + + # Search for VLIB_LOOP_ENTER_FUNCTION, extract the parameters and add a docblock for it + ( re.compile("(?PVLIB_MAIN_LOOP_ENTER_FUNCTION)\s*[(](?P[a-zA-Z0-9_]+)(,[^)]*)?[)]"), + r"/** @brief (@em constructor) \g (@ref \g) */ _vlib_main_loop_enter_\g"), + ( re.compile("(?PVLIB_MAIN_LOOP_EXIT_FUNCTION)\s*[(](?P[a-zA-Z0-9_]+)(,[^)]*)?[)]"), + r"/** @brief (@em constructor) \g (@ref \g) */ _vlib_main_loop_exit_\g"), + + # Search for VLIB_CONFIG_FUNCTION, extract the parameters and add a docblock for it + ( re.compile("(?PVLIB_CONFIG_FUNCTION)\s*[(](?P[a-zA-Z0-9_]+),\s*(?P\"[^\"]+\")(,[^)]*)?[)]"), + r"/** @brief (@em constructor) \g (\g, \g) */ vlib_config_function_runtime_t _vlib_config_function_\g"), + ( re.compile("(?PVLIB_EARLY_CONFIG_FUNCTION)\s*[(](?P[a-zA-Z0-9_]+),\s*(?P\"[^\"]+\")(,[^)]*)?[)]"), + r"/** @brief (@em constructor) \g (\g, \g) */ vlib_config_function_runtime_t _vlib_config_function_\g"), - # Search for VLIB_LOOP_ENTER_FUNCTION, extract the 1st parameter (ignore any others) and add a docblock for it - ( re.compile("(?PVLIB_MAIN_LOOP_ENTER_FUNCTION)\s*[(](?P[a-zA-Z0-9_]+)(,[^)]*)?[)]"), r"/** @brief (@em constructor) \g (@ref \g) */ _vlib_main_loop_enter_\g"), - ( re.compile("(?PVLIB_MAIN_LOOP_EXIT_FUNCTION)\s*[(](?P[a-zA-Z0-9_]+)(,[^)]*)?[)]"), r"/** @brief (@em constructor) \g (@ref \g) */ _vlib_main_loop_exit_\g"), + # Search for "format_thing" and "unformat_thing" when used as a function pointer and add parens + ( re.compile("(?P
(^|,)\s*)(?P(un)?format_[a-zA-Z0-9_]+)(?P\s*(,|$))"),
+        r"\g
\g()\g" ),
 
-    # Search for VLIB_CONFIG_FUNCTION, extract the 1st parameter (ignore any others) and add a docblock for it
-    ( re.compile("(?PVLIB_CONFIG_FUNCTION)\s*[(](?P[a-zA-Z0-9_]+),\s*(?P\"[^\"]+\")(,[^)]*)?[)]"), r"/** @brief (@em constructor) \g (\g, \g) */ vlib_config_function_runtime_t _vlib_config_function_\g"),
-    ( re.compile("(?PVLIB_EARLY_CONFIG_FUNCTION)\s*[(](?P[a-zA-Z0-9_]+),\s*(?P\"[^\"]+\")(,[^)]*)?[)]"), r"/** @brief (@em constructor) \g (\g, \g) */ vlib_config_function_runtime_t _vlib_config_function_\g"),
+    # Search for CLIB_PAD_FROM_TO(...); and replace with padding
+    # #define CLIB_PAD_FROM_TO(from,to) u8 pad_##from[(to) - (from)]
+    ( re.compile("(?PCLIB_PAD_FROM_TO)\s*[(](?P[^,]+),\s*(?P[^)]+)[)]"),
+        r"/** Padding. */ u8 pad_\g[(\g) - (\g)]" ),
 
-    # Search for "format_thing" and "unformat_thing" when used as a function pointer and add parens
-    ( re.compile("(?P
(^|,)\s*)(?P(un)?format_[a-zA-Z0-9_]+)(?P\s*(,|$))") , r"\g
\g()\g" ),
 ]
 
 
diff --git a/doxygen/filter_h.py b/doxygen/filter_h.py
new file mode 100755
index 00000000..967388d5
--- /dev/null
+++ b/doxygen/filter_h.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+# Copyright (c) 2016 Comcast Cable Communications Management, LLC.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Filter for .c files to make various preprocessor tricks Doxygenish
+
+import os, sys, re
+
+if len(sys.argv) < 2:
+    sys.stderr.write("Usage: %s \n" % (sys.argv[0]))
+    sys.exit(1)
+
+replace_patterns = [
+    # Search for CLIB_PAD_FROM_TO(...); and replace with padding
+    # #define CLIB_PAD_FROM_TO(from,to) u8 pad_##from[(to) - (from)]
+    ( re.compile("(?PCLIB_PAD_FROM_TO)\s*[(](?P[^,]+),\s*(?P[^)]+)[)]"),
+        r"/** Padding. */ u8 pad_\g[(\g) - (\g)]" ),
+
+]
+
+
+filename = sys.argv[1]
+cwd = os.getcwd()
+if filename[0:len(cwd)] == cwd:
+    filename = filename[len(cwd):]
+    if filename[0] == "/":
+        filename = filename[1:]
+
+with open(filename) as fd:
+    line_num = 0
+
+    for line in fd:
+        line_num += 1
+        str = line[:-1] # filter \n
+
+        # Look for search/replace patterns
+        for p in replace_patterns:
+            str = p[0].sub(p[1], str)
+
+        sys.stdout.write(str+"\n")
+
+# All done
diff --git a/vnet/vnet/interface_cli.c b/vnet/vnet/interface_cli.c
index 7b9f5458..654edcaa 100644
--- a/vnet/vnet/interface_cli.c
+++ b/vnet/vnet/interface_cli.c
@@ -37,6 +37,11 @@
  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
+/**
+ * @file
+ * Interface CLI.
+ */
+
 #include 
 #include 
 #include 
@@ -432,7 +437,9 @@ VLIB_CLI_COMMAND (clear_interface_counters_command, static) = {
 };
 /* *INDENT-ON* */
 
-/** \detail
+/**
+ * Parse subinterface names.
+ *
  * The following subinterface syntax is supported. The first two are for
  * backwards compatability:
  *
diff --git a/vnet/vnet/ip/lookup.h b/vnet/vnet/ip/lookup.h
index fcd080a4..dcc9d25f 100644
--- a/vnet/vnet/ip/lookup.h
+++ b/vnet/vnet/ip/lookup.h
@@ -37,11 +37,15 @@
  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-/** @file Definitions for all things IP (v4|v6) unicast and multicast lookup related.
-    - Adjacency definitions and registration
-    - callbacks on route add
-    - callbacks on interface address change
+/**
+ * @file
+ * Definitions for all things IP (v4|v6) unicast and multicast lookup related.
+ *
+ * - Adjacency definitions and registration.
+ * - Callbacks on route add.
+ * - Callbacks on interface address change.
  */
+
 #ifndef included_ip_lookup_h
 #define included_ip_lookup_h
 
diff --git a/vnet/vnet/ipsec-gre/error.def b/vnet/vnet/ipsec-gre/error.def
index 0d7b4686..d84e8ed1 100644
--- a/vnet/vnet/ipsec-gre/error.def
+++ b/vnet/vnet/ipsec-gre/error.def
@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 /**
- * @file error.def
+ * @file
  * @brief L2-GRE over IPSec errors.
  */
 
diff --git a/vnet/vnet/ipsec-gre/interface.c b/vnet/vnet/ipsec-gre/interface.c
index 3e5d3954..dbf9df56 100644
--- a/vnet/vnet/ipsec-gre/interface.c
+++ b/vnet/vnet/ipsec-gre/interface.c
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 /**
- * @file interface.c
+ * @file
  * @brief L2-GRE over IPSec tunnel interface.
  *
  * Creates ipsec-gre tunnel interface.
diff --git a/vnet/vnet/ipsec-gre/ipsec_gre.c b/vnet/vnet/ipsec-gre/ipsec_gre.c
index 24ec6f4e..3d1b54fc 100644
--- a/vnet/vnet/ipsec-gre/ipsec_gre.c
+++ b/vnet/vnet/ipsec-gre/ipsec_gre.c
@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 /**
- * @file ipsec_gre.c
+ * @file
  * @brief L2-GRE over IPSec packet processing.
  *
  * Add GRE header to thr packet and send it to the esp-encrypt node.
diff --git a/vnet/vnet/ipsec-gre/ipsec_gre.h b/vnet/vnet/ipsec-gre/ipsec_gre.h
index 2b66c6a6..a2ca64b6 100644
--- a/vnet/vnet/ipsec-gre/ipsec_gre.h
+++ b/vnet/vnet/ipsec-gre/ipsec_gre.h
@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 /**
- * @file ipsec_gre.h
+ * @file
  * @brief L2-GRE over IPSec packet processing.
 */
 
diff --git a/vnet/vnet/ipsec-gre/node.c b/vnet/vnet/ipsec-gre/node.c
index 13102552..5a176088 100644
--- a/vnet/vnet/ipsec-gre/node.c
+++ b/vnet/vnet/ipsec-gre/node.c
@@ -13,10 +13,10 @@
  * limitations under the License.
  */
 /**
- * @file node.c
+ * @file
  * @brief L2-GRE over IPSec packet processing.
  *
- * Removes GRE header from the packet and send it to the l2-input node.
+ * Removes GRE header from the packet and sends it to the l2-input node.
 */
 
 #include 
@@ -68,7 +68,7 @@ u8 * format_ipsec_gre_rx_trace (u8 * s, va_list * args)
  *
  * @par Graph mechanics: buffer metadata, next index usage
  *
- * Uses:
+ * Uses:
  * - ip->src_address and ip->dst_address
  *     - Match tunnel by source and destination addresses in GRE IP header.
  *
diff --git a/vnet/vnet/l2/l2_bd.c b/vnet/vnet/l2/l2_bd.c
index 490a08f2..ddbe934a 100644
--- a/vnet/vnet/l2/l2_bd.c
+++ b/vnet/vnet/l2/l2_bd.c
@@ -35,7 +35,7 @@
 bd_main_t bd_main;
 
 /**
-  Init bridge domain if not done already
+  Init bridge domain if not done already.
   For feature bitmap, set all bits except ARP termination
 */
 void
@@ -175,7 +175,7 @@ VLIB_INIT_FUNCTION (l2bd_init);
 
 
 /**
-    Set the learn/forward/flood flags for the bridge domain
+    Set the learn/forward/flood flags for the bridge domain.
     Return 0 if ok, non-zero if for an error.
 */
 u32
@@ -224,7 +224,7 @@ bd_set_flags (vlib_main_t * vm, u32 bd_index, u32 flags, u32 enable)
 }
 
 /**
-   set bridge-domain learn enable/disable
+   Set bridge-domain learn enable/disable.
    The CLI format is:
    set bridge-domain learn  [disable]
 */
@@ -279,7 +279,7 @@ VLIB_CLI_COMMAND (bd_learn_cli, static) = {
 /* *INDENT-ON* */
 
 /**
-    set bridge-domain forward enable/disable
+    Set bridge-domain forward enable/disable.
     The CLI format is:
     set bridge-domain forward  [disable]
 */
@@ -333,7 +333,7 @@ VLIB_CLI_COMMAND (bd_fwd_cli, static) = {
 /* *INDENT-ON* */
 
 /**
-    set bridge-domain flood enable/disable
+    Set bridge-domain flood enable/disable.
     The CLI format is:
     set bridge-domain flood  [disable]
 */
@@ -388,7 +388,7 @@ VLIB_CLI_COMMAND (bd_flood_cli, static) = {
 /* *INDENT-ON* */
 
 /**
-    set bridge-domain unkown-unicast flood enable/disable
+    Set bridge-domain unkown-unicast flood enable/disable.
     The CLI format is:
     set bridge-domain uu-flood  [disable]
 */
@@ -443,7 +443,7 @@ VLIB_CLI_COMMAND (bd_uu_flood_cli, static) = {
 /* *INDENT-ON* */
 
 /**
-    set bridge-domain arp term enable/disable
+    Set bridge-domain arp term enable/disable.
     The CLI format is:
     set bridge-domain arp term  [disable]
 */
@@ -496,11 +496,15 @@ VLIB_CLI_COMMAND (bd_arp_term_cli, static) = {
 
 
 /**
+ * Add/delete IP address to MAC address mapping.
+ *
  * The clib hash implementation stores uword entries in the hash table.
  * The hash table mac_by_ip4 is keyed via IP4 address and store the
  * 6-byte MAC address directly in the hash table entry uword.
- * This only works for 64-bit processor with 8-byte uword; which means
- * this code *WILL NOT WORK* for a 32-bit prcessor with 4-byte uword.
+ *
+ * @warning This only works for 64-bit processor with 8-byte uword;
+ * which means this code *WILL NOT WORK* for a 32-bit prcessor with
+ * 4-byte uword.
  */
 u32
 bd_add_del_ip_mac (u32 bd_index,
@@ -573,7 +577,7 @@ bd_add_del_ip_mac (u32 bd_index,
 }
 
 /**
-    set bridge-domain arp entry add/delete
+    Set bridge-domain arp entry add/delete.
     The CLI format is:
     set bridge-domain arp entry    [del]
 */
@@ -689,7 +693,7 @@ format_vtr (u8 * s, va_list * args)
 }
 
 /**
-   show bridge-domain state
+   Show bridge-domain state.
    The CLI format is:
    show bridge-domain []
 */
diff --git a/vnet/vnet/l2/l2_efp_filter.c b/vnet/vnet/l2/l2_efp_filter.c
index 221db9ab..2038dce2 100644
--- a/vnet/vnet/l2/l2_efp_filter.c
+++ b/vnet/vnet/l2/l2_efp_filter.c
@@ -97,7 +97,7 @@ typedef enum
 
 /**
  *  Extract fields from the packet that will be used in interface
- *  classification
+ *  classification.
  */
 static_always_inline void
 extract_keys (vnet_main_t * vnet_main,
@@ -524,7 +524,7 @@ VLIB_NODE_FUNCTION_MULTIARCH (l2_efp_filter_node, l2_efp_filter_node_fn)
 VLIB_INIT_FUNCTION (l2_efp_filter_init);
 
 
-/** Enable/disable the EFP Filter check on the subinterface */
+/** Enable/disable the EFP Filter check on the subinterface. */
 void
 l2_efp_filter_configure (vnet_main_t * vnet_main, u32 sw_if_index, u32 enable)
 {
@@ -534,7 +534,7 @@ l2_efp_filter_configure (vnet_main_t * vnet_main, u32 sw_if_index, u32 enable)
 
 
 /**
- * set subinterface egress efp filter enable/disable
+ * Set subinterface egress efp filter enable/disable.
  * The CLI format is:
  *    set interface l2 efp-filter  [disable]]
  */
diff --git a/vnet/vnet/l2/l2_fib.c b/vnet/vnet/l2/l2_fib.c
index 4275e884..97620bfb 100644
--- a/vnet/vnet/l2/l2_fib.c
+++ b/vnet/vnet/l2/l2_fib.c
@@ -97,7 +97,7 @@ l2fib_table_dump (u32 bd_index, l2fib_entry_key_t ** l2fe_key,
     }
 }
 
-/** Display the contents of the l2fib */
+/** Display the contents of the l2fib. */
 static clib_error_t *
 show_l2fib (vlib_main_t * vm,
 	    unformat_input_t * input, vlib_cli_command_t * cmd)
@@ -228,8 +228,8 @@ l2fib_clear_table (uint keep_static)
   l2learn_main.global_learn_count = 0;
 }
 
-/** Clear all entries in L2FIB
- * TODO: Later we may want a way to remove only the non-static entries
+/** Clear all entries in L2FIB.
+ * @TODO: Later we may want a way to remove only the non-static entries
  */
 static clib_error_t *
 clear_l2fib (vlib_main_t * vm,
@@ -286,7 +286,7 @@ l2fib_add_entry (u64 mac,
 }
 
 /**
- * Add an entry to the L2FIB
+ * Add an entry to the L2FIB.
  * The CLI format is:
  *    l2fib add    [static] [bvi]
  *    l2fib add   filter
@@ -517,7 +517,7 @@ l2fib_del_entry (u64 mac, u32 bd_index)
 }
 
 /**
- * Delete an entry from the L2FIB
+ * Delete an entry from the L2FIB.
  * The CLI format is:
  *    l2fib del  
  */
diff --git a/vnet/vnet/l2/l2_flood.c b/vnet/vnet/l2/l2_flood.c
index 0654fe29..05df2a01 100644
--- a/vnet/vnet/l2/l2_flood.c
+++ b/vnet/vnet/l2/l2_flood.c
@@ -490,7 +490,7 @@ VLIB_INIT_FUNCTION (l2flood_init);
 
 
 
-/** Add the L3 input node for this ethertype to the next nodes structure */
+/** Add the L3 input node for this ethertype to the next nodes structure. */
 void
 l2flood_register_input_type (vlib_main_t * vm,
 			     ethernet_type_t type, u32 node_index)
@@ -505,7 +505,7 @@ l2flood_register_input_type (vlib_main_t * vm,
 
 
 /**
- * set subinterface flood enable/disable
+ * Set subinterface flood enable/disable.
  * The CLI format is:
  * set interface l2 flood  [disable]
  */
diff --git a/vnet/vnet/l2/l2_fwd.c b/vnet/vnet/l2/l2_fwd.c
index 4950b23a..8fa355e0 100644
--- a/vnet/vnet/l2/l2_fwd.c
+++ b/vnet/vnet/l2/l2_fwd.c
@@ -104,7 +104,7 @@ typedef enum
   L2FWD_N_NEXT,
 } l2fwd_next_t;
 
-/** Forward one packet based on the mac table lookup result */
+/** Forward one packet based on the mac table lookup result. */
 
 static_always_inline void
 l2fwd_process (vlib_main_t * vm,
@@ -400,7 +400,7 @@ VLIB_NODE_FUNCTION_MULTIARCH (l2fwd_node, l2fwd_node_fn)
 VLIB_INIT_FUNCTION (l2fwd_init);
 
 
-/** Add the L3 input node for this ethertype to the next nodes structure */
+/** Add the L3 input node for this ethertype to the next nodes structure. */
 void
 l2fwd_register_input_type (vlib_main_t * vm,
 			   ethernet_type_t type, u32 node_index)
@@ -415,7 +415,7 @@ l2fwd_register_input_type (vlib_main_t * vm,
 
 
 /**
- * set subinterface forward enable/disable
+ * Set subinterface forward enable/disable.
  * The CLI format is:
  *   set interface l2 forward  [disable]
  */
diff --git a/vnet/vnet/l2/l2_input.c b/vnet/vnet/l2/l2_input.c
index 5c39b797..24cb31fb 100644
--- a/vnet/vnet/l2/l2_input.c
+++ b/vnet/vnet/l2/l2_input.c
@@ -490,7 +490,7 @@ VLIB_NODE_FUNCTION_MULTIARCH (l2input_node, l2input_node_fn)
 VLIB_INIT_FUNCTION (l2input_init);
 
 
-/** Get a pointer to the config for the given interface */
+/** Get a pointer to the config for the given interface. */
 l2_input_config_t *
 l2input_intf_config (u32 sw_if_index)
 {
@@ -500,7 +500,7 @@ l2input_intf_config (u32 sw_if_index)
   return vec_elt_at_index (mp->configs, sw_if_index);
 }
 
-/** Enable (or disable) the feature in the bitmap for the given interface */
+/** Enable (or disable) the feature in the bitmap for the given interface. */
 u32
 l2input_intf_bitmap_enable (u32 sw_if_index, u32 feature_bitmap, u32 enable)
 {
@@ -536,10 +536,10 @@ l2input_set_bridge_features (u32 bd_index, u32 feat_mask, u32 feat_value)
 
 /**
  * Set the subinterface to run in l2 or l3 mode.
- * for L3 mode, just the sw_if_index is specified
- * for bridged mode, the bd id and bvi flag are also specified
- * for xconnect mode, the peer sw_if_index is also specified
- * Return 0 if ok, or non-0 if there was an error
+ * For L3 mode, just the sw_if_index is specified.
+ * For bridged mode, the bd id and bvi flag are also specified.
+ * For xconnect mode, the peer sw_if_index is also specified.
+ * Return 0 if ok, or non-0 if there was an error.
  */
 
 u32
@@ -771,7 +771,7 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, u32 mode, u32 sw_if_
 }
 
 /**
- * set subinterface in bridging mode with a bridge-domain ID
+ * Set subinterface in bridging mode with a bridge-domain ID.
  * The CLI format is:
  *   set interface l2 bridge   [bvi] [split-horizon-group]
  */
@@ -847,7 +847,7 @@ VLIB_CLI_COMMAND (int_l2_bridge_cli, static) = {
 /* *INDENT-ON* */
 
 /**
- * set subinterface in xconnect mode with another interface
+ * Set subinterface in xconnect mode with another interface.
  * The CLI format is:
  *   set interface l2 xconnect  
  */
@@ -897,7 +897,7 @@ VLIB_CLI_COMMAND (int_l2_xc_cli, static) = {
 /* *INDENT-ON* */
 
 /**
- * set subinterface in L3 mode
+ * Set subinterface in L3 mode.
  * The CLI format is:
  *   set interface l3 
  */
@@ -936,6 +936,7 @@ VLIB_CLI_COMMAND (int_l3_cli, static) = {
 /* *INDENT-ON* */
 
 /**
+ * Show interface mode.
  * The CLI format is:
  *    show mode [  ...]
  */
diff --git a/vnet/vnet/l2/l2_input_classify.c b/vnet/vnet/l2/l2_input_classify.c
index 1b9f911c..69cd113d 100644
--- a/vnet/vnet/l2/l2_input_classify.c
+++ b/vnet/vnet/l2/l2_input_classify.c
@@ -21,13 +21,14 @@
 
 /**
  * @file
- * @brief L2 input classifier
+ * @brief L2 input classifier.
  *
- * See also .../vnet/vnet/classify/vnet_classify.[ch]
+ * @sa @ref vnet/vnet/classify/vnet_classify.c
+ * @sa @ref vnet/vnet/classify/vnet_classify.h
  */
 
 /**
- * @brief l2_input_classifier packet trace record
+ * @brief l2_input_classifier packet trace record.
  */
 typedef struct
 {
@@ -42,7 +43,7 @@ typedef struct
 } l2_input_classify_trace_t;
 
 /**
- * @brief vlib node runtime
+ * @brief vlib node runtime.
  */
 typedef struct
 {
@@ -52,7 +53,7 @@ typedef struct
   l2_input_classify_main_t *l2cm;
 } l2_input_classify_runtime_t;
 
-/** packet trace format function */
+/** Packet trace format function. */
 static u8 *
 format_l2_input_classify_trace (u8 * s, va_list * args)
 {
@@ -66,7 +67,7 @@ format_l2_input_classify_trace (u8 * s, va_list * args)
   return s;
 }
 
-/** l2 input classifier main data structure */
+/** l2 input classifier main data structure. */
 l2_input_classify_main_t l2_input_classify_main;
 
 vlib_node_registration_t l2_input_classify_node;
@@ -106,19 +107,19 @@ static char *l2_input_classify_error_strings[] = {
  * @em Uses:
  * - (l2_input_classify_runtime_t *)
  *         rt->classify_table_index_by_sw_if_index
- *	   Head of the per-interface, perprotocol classifier table chain
- * 	   for a specific interface. ~0 => send pkts to the next
- * 	   feature in the L2 feature chain.
+ *	- Head of the per-interface, per-protocol classifier table chain
+ * 	  for a specific interface.
+ *      - @c ~0 => send pkts to the next feature in the L2 feature chain.
  * - vnet_buffer(b)->sw_if_index[VLIB_RX]
  * 	- Indicates the @c sw_if_index value of the interface that the
- * 	packet was received on.
- * - vnet_buffer (b0)->l2.feature_bitmap
+ * 	  packet was received on.
+ * - vnet_buffer(b0)->l2.feature_bitmap
  * 	- Used to steer packets across l2 features enabled on the interface
  * - (vnet_classify_entry_t) e0->next_index
  *	- Used to steer traffic when the classifier hits on a session
  * - (vnet_classify_entry_t) e0->advance
  *	- Signed quantity applied via vlib_buffer_advance
- * 	when the classifier hits on a session
+ * 	  when the classifier hits on a session
  * - (vnet_classify_table_t) t0->miss_next_index
  *	- Used to steer traffic when the classifier misses
  *
@@ -477,7 +478,7 @@ VLIB_REGISTER_NODE (l2_input_classify_node) = {
 VLIB_NODE_FUNCTION_MULTIARCH (l2_input_classify_node,
 			      l2_input_classify_node_fn);
 
-/** l2 input classsifier feature initialization */
+/** l2 input classsifier feature initialization. */
 clib_error_t *
 l2_input_classify_init (vlib_main_t * vm)
 {
@@ -505,7 +506,7 @@ l2_input_classify_init (vlib_main_t * vm)
 VLIB_INIT_FUNCTION (l2_input_classify_init);
 
 
-/** enable/disable l2 input classification on a specific interface */
+/** Enable/disable l2 input classification on a specific interface. */
 void
 vnet_l2_input_classify_enable_disable (u32 sw_if_index, int enable_disable)
 {
@@ -513,7 +514,7 @@ vnet_l2_input_classify_enable_disable (u32 sw_if_index, int enable_disable)
 			      (u32) enable_disable);
 }
 
-/** @brief Set l2 per-protocol, per-interface input classification tables
+/** @brief Set l2 per-protocol, per-interface input classification tables.
  *
  *  @param sw_if_index  interface handle
  *  @param ip4_table_index  ip4 classification table index, or ~0
diff --git a/vnet/vnet/l2/l2_learn.c b/vnet/vnet/l2/l2_learn.c
index 30f5617f..96d4816e 100644
--- a/vnet/vnet/l2/l2_learn.c
+++ b/vnet/vnet/l2/l2_learn.c
@@ -29,8 +29,9 @@
 #include 
 #include 
 
-/*
- * Ethernet bridge learning
+/**
+ * @file
+ * Ethernet bridge learning.
  *
  * Populate the mac table with entries mapping the packet's source mac + bridge
  * domain ID to the input sw_if_index.
@@ -102,7 +103,7 @@ typedef enum
 } l2learn_next_t;
 
 
-/** Perform learning on one packet based on the mac table lookup result */
+/** Perform learning on one packet based on the mac table lookup result. */
 
 static_always_inline void
 l2learn_process (vlib_node_runtime_t * node,
@@ -462,7 +463,7 @@ VLIB_INIT_FUNCTION (l2learn_init);
 
 
 /**
- * set subinterface learn enable/disable
+ * Set subinterface learn enable/disable.
  * The CLI format is:
  *    set interface l2 learn  [disable]
  */
diff --git a/vnet/vnet/l2/l2_output.c b/vnet/vnet/l2/l2_output.c
index 8bc43744..85678caf 100644
--- a/vnet/vnet/l2/l2_output.c
+++ b/vnet/vnet/l2/l2_output.c
@@ -73,9 +73,10 @@ static char *l2output_error_strings[] = {
 };
 
 /**
- * Return 0 if split horizon check passes, otherwise return non-zero
+ * Check for split horizon violations.
+ * Return 0 if split horizon check passes, otherwise return non-zero.
  * Packets should not be transmitted out an interface with the same
- * split-horizon group as the input interface, except if the shg is 0
+ * split-horizon group as the input interface, except if the @c shg is 0
  * in which case the check always passes.
  */
 static_always_inline u32
@@ -592,7 +593,7 @@ output_node_mapping_send_rpc (u32 node_index, u32 sw_if_index)
 #endif
 
 
-/** Create a mapping in the next node mapping table for the given sw_if_index */
+/** Create a mapping in the next node mapping table for the given sw_if_index. */
 u32
 l2output_create_output_node_mapping (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 node_index,	/* index of current node */
 				     u32 * output_node_index_vec,
@@ -660,7 +661,7 @@ l2output_intf_config (u32 sw_if_index)
   return vec_elt_at_index (mp->configs, sw_if_index);
 }
 
-/** Enable (or disable) the feature in the bitmap for the given interface */
+/** Enable (or disable) the feature in the bitmap for the given interface. */
 void
 l2output_intf_bitmap_enable (u32 sw_if_index, u32 feature_bitmap, u32 enable)
 {
diff --git a/vnet/vnet/l2/l2_output_acl.c b/vnet/vnet/l2/l2_output_acl.c
index 4597d42e..94a4d66b 100644
--- a/vnet/vnet/l2/l2_output_acl.c
+++ b/vnet/vnet/l2/l2_output_acl.c
@@ -306,8 +306,8 @@ VLIB_NODE_FUNCTION_MULTIARCH (l2_outacl_node, l2_outacl_node_fn)
 VLIB_INIT_FUNCTION (l2_outacl_init);
 
 #if 0
-/** @todo maybe someone will add output ACL's in the future
- * set subinterface outacl enable/disable
+/** @todo maybe someone will add output ACL's in the future.
+ * Set subinterface outacl enable/disable.
  * The CLI format is:
  *    set interface acl output  [disable]
  */
diff --git a/vnet/vnet/l2/l2_output_classify.c b/vnet/vnet/l2/l2_output_classify.c
index 1cb8b850..c04df3c2 100644
--- a/vnet/vnet/l2/l2_output_classify.c
+++ b/vnet/vnet/l2/l2_output_classify.c
@@ -12,18 +12,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/*
- * l2_classify.c
- */
 
 #include 
 #include 
 
 /**
  * @file
- * @brief L2 input classifier
+ * @brief L2 input classifier.
  *
- * See also .../vnet/vnet/classify/vnet_classify.[ch]
+ * @sa @ref vnet/vnet/classify/vnet_classify.c
+ * @sa @ref vnet/vnet/classify/vnet_classify.h
  */
 
 typedef struct
@@ -46,7 +44,7 @@ typedef struct
   l2_output_classify_main_t *l2cm;
 } l2_output_classify_runtime_t;
 
-/** packet trace format function */
+/** Packet trace format function. */
 static u8 *
 format_l2_output_classify_trace (u8 * s, va_list * args)
 {
@@ -61,7 +59,7 @@ format_l2_output_classify_trace (u8 * s, va_list * args)
   return s;
 }
 
-/** l2 output classifier main data structure */
+/** l2 output classifier main data structure. */
 l2_output_classify_main_t l2_output_classify_main;
 
 vlib_node_registration_t l2_output_classify_node;
@@ -477,7 +475,7 @@ VLIB_REGISTER_NODE (l2_output_classify_node) = {
 VLIB_NODE_FUNCTION_MULTIARCH (l2_output_classify_node,
 			      l2_output_classify_node_fn);
 
-/** l2 output classsifier feature initialization */
+/** l2 output classsifier feature initialization. */
 clib_error_t *
 l2_output_classify_init (vlib_main_t * vm)
 {
@@ -507,7 +505,7 @@ l2_output_classify_init (vlib_main_t * vm)
 
 VLIB_INIT_FUNCTION (l2_output_classify_init);
 
-/** enable/disable l2 input classification on a specific interface */
+/** Enable/disable l2 input classification on a specific interface. */
 void
 vnet_l2_output_classify_enable_disable (u32 sw_if_index, int enable_disable)
 {
@@ -516,15 +514,15 @@ vnet_l2_output_classify_enable_disable (u32 sw_if_index, int enable_disable)
 			       (u32) enable_disable);
 }
 
-/** @brief Set l2 per-protocol, per-interface output classification tables
+/** @brief Set l2 per-protocol, per-interface output classification tables.
  *
- *  @param sw_if_index  interface handle
- *  @param ip4_table_index  ip4 classification table index, or ~0
- *  @param ip6_table_index  ip6 classification table index, or ~0
+ *  @param sw_if_index        interface handle
+ *  @param ip4_table_index    ip4 classification table index, or ~0
+ *  @param ip6_table_index    ip6 classification table index, or ~0
  *  @param other_table_index  non-ip4, non-ip6 classification table index,
  *         or ~0
  *  @returns 0 on success, VNET_API_ERROR_NO_SUCH_TABLE, TABLE2, TABLE3
- *  if the indicated (non-~0) table does not exist.
+ *           if the indicated (non-~0) table does not exist.
  */
 
 int
diff --git a/vnet/vnet/l2/l2_vtr.c b/vnet/vnet/l2/l2_vtr.c
index 6250074e..3ec8b8a7 100644
--- a/vnet/vnet/l2/l2_vtr.c
+++ b/vnet/vnet/l2/l2_vtr.c
@@ -30,7 +30,7 @@
 #include 
 
 
-/** Just a placeholder. Also ensures file is not eliminated by linker. */
+/** Just a placeholder; ensures file is not eliminated by linker. */
 clib_error_t *
 l2_vtr_init (vlib_main_t * vm)
 {
@@ -254,7 +254,7 @@ done:
 }
 
 /**
- *  Get vtag tag rewrite on the given interface.
+ * Get vtag tag rewrite on the given interface.
  * Return 1 if there is an error, 0 if ok
  */
 u32
@@ -411,7 +411,7 @@ done:
 }
 
 /**
- * set subinterface vtr enable/disable
+ * Set subinterface vtr enable/disable.
  * The CLI format is:
  *    set interface l2 tag-rewrite  [disable | pop 1 | pop 2 | push {dot1q|dot1ad}  []]
  *
diff --git a/vnet/vnet/l2/l2_xcrw.c b/vnet/vnet/l2/l2_xcrw.c
index 95219e6e..344a8b96 100644
--- a/vnet/vnet/l2/l2_xcrw.c
+++ b/vnet/vnet/l2/l2_xcrw.c
@@ -14,7 +14,8 @@
  */
 #include 
 
-/*
+/**
+ * @file
  * General L2 / L3 cross-connect, used to set up
  * "L2 interface <--> your-favorite-tunnel-encap" tunnels.
  *
diff --git a/vnet/vnet/unix/tuntap.c b/vnet/vnet/unix/tuntap.c
index 83e7ec4f..b3fbc7f3 100644
--- a/vnet/vnet/unix/tuntap.c
+++ b/vnet/vnet/unix/tuntap.c
@@ -786,9 +786,9 @@ tuntap_ip4_add_del_interface_address (ip4_main_t * im,
 }
 
 /**
- * @brief workaround for a known #include bug
- * #include  causes multiple definitions if
- * netinet/in.h is also included.
+ * @brief workaround for a known include file bug.
+ * including @c  causes multiple definitions if
+ * @c 
Date: Thu, 1 Sep 2016 09:04:01 -0400
Subject: VPP-221 Improve doxygen dependency check

Only try to install packages if they're not installed.
Saves a trip through sudo which is useful when you have a
non-privileged account generating the docs.

Change-Id: I3709aceb15516a45ea2f9510d91c6d2e42c8c349
Signed-off-by: Chris Luke 
---
 doxygen/Makefile | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

(limited to 'doxygen/Makefile')

diff --git a/doxygen/Makefile b/doxygen/Makefile
index df7d07d7..f3ddb2c9 100644
--- a/doxygen/Makefile
+++ b/doxygen/Makefile
@@ -63,7 +63,11 @@ SIPHON_DOCS = $(addprefix $(SIPHON_OUTPUT)/,$(addsuffix .md,$(SIPHONS)))
 
 $(BR)/.doxygen-bootstrap.ok:
 ifeq ($(OS_ID),ubuntu)
-	@sudo -E apt-get $(CONFIRM) $(FORCE) install $(DOC_DEB_DEPENDS)
+	@set -e; inst=; \
+		for i in $(DOC_DEB_DEPENDS); do \
+			dpkg-query --show $$i >/dev/null 2>&1 || inst="$$inst $$i"; \
+		done; \
+		[ "$$inst" ] && sudo apt-get $(CONFIRM) $(FORCE) install $$inst
 else ifneq ("$(wildcard /etc/redhat-release)","")
 	@sudo yum install $(CONFIRM) $(DOC_RPM_DEPENDS)
 else
-- 
cgit 1.2.3-korg


From d4024f586216a6bf4e2dfb667df8149b7f95b5c6 Mon Sep 17 00:00:00 2001
From: Chris Luke 
Date: Tue, 6 Sep 2016 09:32:36 -0400
Subject: VPP-346 More VPP doc fixes

- Fix issue in Doxy dependency check when nothing needs to be installed.
  'set -e' and plain '[]' logic don't mix well.
- Fix Makefile snafu when building Doxy output for a single file.
- Include only one of vnet/vnet/buffer.c/dpdk_buffer.c in docs depending on
  DPDKness. This could do with some improvement in future, eg to properly
  align the pre-doxy steps with what Doxy does.
- Fix rendering of 'inline' tag in Doxygen by having it interpret
  always_inline as "inline static".
- Bunch of duplicate CLI command structure names that confused docs and may
  one day have caused debugging issues.
- Several other Doxygen syntax issues fixed, like documenting non-existant
  parameters (usually just the wrong parameter name, typos, etc)

Change-Id: Ia8cca545e5de9f8750602bffa3c4548acc8971aa
Signed-off-by: Chris Luke 
---
 doxygen/Makefile                       | 37 +++++++++++++++++++++++++++-------
 doxygen/doxygen.cfg                    |  5 +++--
 doxygen/siphon_generate.py             | 21 +++++++++++++------
 vlib/vlib/buffer.c                     |  8 ++++++++
 vlib/vlib/buffer_funcs.h               |  4 ++--
 vlib/vlib/counter.h                    |  4 ++--
 vlib/vlib/dpdk_buffer.c                |  8 ++++++++
 vlib/vlib/vlib_process_doc.h           |  6 +++---
 vnet/vnet/classify/policer_classify.c  |  2 +-
 vnet/vnet/devices/dpdk/node.c          |  4 ++--
 vnet/vnet/ip/ip6_forward.c             |  4 ++--
 vnet/vnet/ip/ip_feature_registration.c |  4 ++--
 vnet/vnet/ipsec-gre/node.c             |  6 +++---
 vnet/vnet/unix/pcap.c                  | 11 ++++++----
 vnet/vnet/unix/tapcli.c                |  8 ++++----
 vnet/vnet/vxlan-gpe/decap.c            |  2 +-
 vppinfra/vppinfra/bihash_8_8.h         |  2 +-
 vppinfra/vppinfra/bihash_doc.h         |  2 +-
 vppinfra/vppinfra/bitmap.h             |  8 ++++----
 19 files changed, 99 insertions(+), 47 deletions(-)

(limited to 'doxygen/Makefile')

diff --git a/doxygen/Makefile b/doxygen/Makefile
index f3ddb2c9..471b6fd7 100644
--- a/doxygen/Makefile
+++ b/doxygen/Makefile
@@ -40,8 +40,27 @@ DOXY_INPUT ?= \
 	vpp-api \
 	plugins
 
+# Files to exclude, from pre-Doxygen steps, eg because they're
+# selectively compiled.
+# Examples would be to exclude non-DPDK related sources when
+# there's a DPDK equivalent that conflicts.
+# This is specifically for the pre-Doxygen steps; Doxygen uses
+# @cond for this instead.
+DOXY_PRE_EXCLUDE ?= \
+	vlib/vlib/buffer.c
+
+# Generate a regexp for filenames to exclude
+DOXY_PRE_EXCLUDE_REGEXP = ($(subst .,\.,$(shell echo '$(strip $(DOXY_PRE_EXCLUDE))' | sed -e 's/ /|/g')))
+
+# Discover all the directories we might, possibly, maybe, have include files in
 DOXY_INCLUDE_PATH = $(shell set -e; cd $(WS_ROOT); for item in $(DOXY_INPUT); do find $$item -type d; done)
-DOXY_INCLUDE_PATH += $(shell set -e; cpp -v &1 | grep -A 1000 '\#include' | awk '/^ /{print $$1}')
+
+# Discover if we have CPP available
+CPP ?= $(shell which cpp)
+ifneq ($(strip $(CPP)),)
+# Add whatever directories CPP normally includes
+DOXY_INCLUDE_PATH += $(shell set -e; $(CPP) -v &1 | grep -A 1000 '\#include' | awk '/^ /{print $$1}')
+endif
 
 # Target directory for doxygen output
 DOXY_OUTPUT ?= $(BR)/docs
@@ -67,7 +86,7 @@ ifeq ($(OS_ID),ubuntu)
 		for i in $(DOC_DEB_DEPENDS); do \
 			dpkg-query --show $$i >/dev/null 2>&1 || inst="$$inst $$i"; \
 		done; \
-		[ "$$inst" ] && sudo apt-get $(CONFIRM) $(FORCE) install $$inst
+		if [ "$$inst" ]; then sudo apt-get $(CONFIRM) $(FORCE) install $$inst; fi
 else ifneq ("$(wildcard /etc/redhat-release)","")
 	@sudo yum install $(CONFIRM) $(DOC_RPM_DEPENDS)
 else
@@ -82,8 +101,10 @@ bootstrap-doxygen: $(BR)/.doxygen-bootstrap.ok
 $(BR)/.doxygen-siphon.dep: Makefile
 	set -e; rm -f "$@"; for input in $(DOXY_INPUT); do \
 		find "$(WS_ROOT)/$$input" -type f \
-			\( -name '*.[ch]' -or -name '*.dox' \) \
-			-print | sed -e "s/^/\$$(SIPHON_FILES): /" >> $@; \
+			\( -name '*.[ch]' -or -name '*.dox' \) -print \
+			| grep -v -E '^$(WS_ROOT)/$(DOXY_PRE_EXCLUDE_REGEXP)$$' \
+			| sed -e "s/^/\$$(SIPHON_FILES): /" \
+			>> $@; \
 	done
 
 # Include the source -> siphon dependencies
@@ -93,11 +114,13 @@ $(BR)/.doxygen-siphon.dep: Makefile
 $(SIPHON_FILES): $(DOXY_DIR)/siphon_generate.py $(BR)/.doxygen-bootstrap.ok
 	@rm -rf "$(SIPHON_INPUT)" "$(SIPHON_OUTPUT)"
 	@mkdir -p "$(SIPHON_INPUT)" "$(SIPHON_OUTPUT)"
-	set -e; for input in $(DOXY_INPUT); do \
+	@touch $(SIPHON_INPUT)/files
+	for input in $(DOXY_INPUT); do \
 		cd "$(WS_ROOT)"; \
 		find "$$input" -type f \
-			\( -name '*.[ch]' -or -name '*.dox' \) \
-			-print >> $(SIPHON_INPUT)/files; \
+			\( -name '*.[ch]' -or -name '*.dox' \) -print \
+			| grep -v -E '^$(DOXY_PRE_EXCLUDE_REGEXP)$$' \
+			>> $(SIPHON_INPUT)/files; \
 	done
 	set -e; cd "$(WS_ROOT)"; $(DOXY_DIR)/siphon_generate.py \
 		--output="$(SIPHON_INPUT)" \
diff --git a/doxygen/doxygen.cfg b/doxygen/doxygen.cfg
index 4eb0f373..971a1595 100644
--- a/doxygen/doxygen.cfg
+++ b/doxygen/doxygen.cfg
@@ -644,7 +644,7 @@ GENERATE_DEPRECATEDLIST= YES
 # sections, marked by \if  ... \endif and \cond 
 # ... \endcond blocks.
 
-ENABLED_SECTIONS       =
+ENABLED_SECTIONS       = DPDK
 
 # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
 # initial value of a variable or macro / define can have for it to appear in the
@@ -2061,7 +2061,8 @@ PREDEFINED             = \
 	__ORDER_LITTLE_ENDIAN__=1234 \
 	__BYTE_ORDER__=1234 \
 	__FLOAT_WORD_ORDER__=1234 \
-	DPDK=1
+	DPDK=1 \
+	always_inline:="static inline"
 	
 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
 # tag can be used to specify a list of macro names that should be expanded. The
diff --git a/doxygen/siphon_generate.py b/doxygen/siphon_generate.py
index 457757b5..8b999114 100755
--- a/doxygen/siphon_generate.py
+++ b/doxygen/siphon_generate.py
@@ -80,6 +80,21 @@ def count_braces(str, count=0, found=False):
 # Collated output for each siphon
 output = {}
 
+# Build a list of known siphons
+known_siphons = []
+for item in siphon_patterns:
+	siphon = item[1]
+	if siphon not in known_siphons:
+		known_siphons.append(siphon)
+
+# Setup information for siphons we know about
+for siphon in known_siphons:
+	output[siphon] = {
+            "file": "%s/%s.siphon" % (args.output, siphon),
+            "global": {},
+            "items": [],
+        }
+
 # Pre-process file names in case they indicate a file with
 # a list of files
 files = []
@@ -233,12 +248,6 @@ for filename in files:
             if close_siphon is not None:
                 # Write the siphoned contents to the right place
                 siphon_name = close_siphon[0]
-                if siphon_name not in output:
-                    output[siphon_name] = {
-                        "global": {},
-                        "items": [],
-                        "file": "%s/%s.siphon" % (args.output, close_siphon[0])
-                    }
 
                 # Copy directives for the file
                 details = {}
diff --git a/vlib/vlib/buffer.c b/vlib/vlib/buffer.c
index 84cecc27..e1be2005 100644
--- a/vlib/vlib/buffer.c
+++ b/vlib/vlib/buffer.c
@@ -37,6 +37,13 @@
  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
+/**
+ * @cond (!DPDK)
+ * @file
+ *
+ * Allocate/free network buffers.
+ */
+
 #include 
 
 uword
@@ -1527,6 +1534,7 @@ VLIB_CLI_COMMAND (show_buffers_command, static) = {
 };
 /* *INDENT-ON* */
 
+/** @endcond */
 /*
  * fd.io coding-style-patch-verification: ON
  *
diff --git a/vlib/vlib/buffer_funcs.h b/vlib/vlib/buffer_funcs.h
index 8b80be16..497a6bb0 100644
--- a/vlib/vlib/buffer_funcs.h
+++ b/vlib/vlib/buffer_funcs.h
@@ -75,7 +75,7 @@ vlib_get_buffer (vlib_main_t * vm, u32 buffer_index)
 /** \brief Translate buffer pointer into buffer index
 
     @param vm - (vlib_main_t *) vlib main data structure pointer
-    @param b - (void *) buffer pointer
+    @param p - (void *) buffer pointer
     @return - (u32) buffer index
 */
 always_inline u32
@@ -135,7 +135,7 @@ vlib_buffer_index_length_in_chain (vlib_main_t * vm, u32 bi)
 /** \brief Copy buffer contents to memory
 
     @param vm - (vlib_main_t *) vlib main data structure pointer
-    @param bi - (u32) buffer index
+    @param buffer_index - (u32) buffer index
     @param contents - (u8 *) memory, must be large enough
     @return - (uword) length of buffer chain
 */
diff --git a/vlib/vlib/counter.h b/vlib/vlib/counter.h
index 28686b4b..a7903206 100644
--- a/vlib/vlib/counter.h
+++ b/vlib/vlib/counter.h
@@ -168,7 +168,7 @@ typedef struct
 } vlib_counter_t;
 
 /** Add two combined counters, results in the first counter
-    @param [in/out] a - (vlib_counter_t *) dst counter
+    @param [in,out] a - (vlib_counter_t *) dst counter
     @param b - (vlib_counter_t *) src counter
 */
 
@@ -180,7 +180,7 @@ vlib_counter_add (vlib_counter_t * a, vlib_counter_t * b)
 }
 
 /** Subtract combined counters, results in the first counter
-    @param [in/out] a - (vlib_counter_t *) dst counter
+    @param [in,out] a - (vlib_counter_t *) dst counter
     @param b - (vlib_counter_t *) src counter
 */
 always_inline void
diff --git a/vlib/vlib/dpdk_buffer.c b/vlib/vlib/dpdk_buffer.c
index 828bc81f..e617be2a 100644
--- a/vlib/vlib/dpdk_buffer.c
+++ b/vlib/vlib/dpdk_buffer.c
@@ -37,6 +37,13 @@
  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
+/**
+ * @cond DPDK
+ * @file
+ *
+ * Allocate/free network buffers with DPDK.
+ */
+
 #include 
 
 #include 
@@ -1398,6 +1405,7 @@ buffer_state_validation_init (vlib_main_t * vm)
 VLIB_INIT_FUNCTION (buffer_state_validation_init);
 #endif
 
+/** @endcond */
 /*
  * fd.io coding-style-patch-verification: ON
  *
diff --git a/vlib/vlib/vlib_process_doc.h b/vlib/vlib/vlib_process_doc.h
index 43a51b57..a47c5e4b 100644
--- a/vlib/vlib/vlib_process_doc.h
+++ b/vlib/vlib/vlib_process_doc.h
@@ -57,8 +57,8 @@
 
     Here's an example:
 
-    
-    #define EXAMPLE_POLL_PERIOD 10.0
+    
+    \#define EXAMPLE_POLL_PERIOD 10.0
 
     static uword
     example_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
@@ -120,7 +120,7 @@
       .type = VLIB_NODE_TYPE_PROCESS,
       .name = "example-process",
     };
-    
+
In this example, the VLIB process node waits for an event to occur, or for 10 seconds to elapse. The code demuxes on the event diff --git a/vnet/vnet/classify/policer_classify.c b/vnet/vnet/classify/policer_classify.c index e4580a20..498f83b5 100644 --- a/vnet/vnet/classify/policer_classify.c +++ b/vnet/vnet/classify/policer_classify.c @@ -161,7 +161,7 @@ set_policer_classify_command_fn (vlib_main_t * vm, return 0; } -VLIB_CLI_COMMAND (set_input_acl_command, static) = { +VLIB_CLI_COMMAND (set_policer_classify_command, static) = { .path = "set policer classify", .short_help = "set policer classify interface [ip4-table ]\n" diff --git a/vnet/vnet/devices/dpdk/node.c b/vnet/vnet/devices/dpdk/node.c index 7b2914a8..54a6a503 100644 --- a/vnet/vnet/devices/dpdk/node.c +++ b/vnet/vnet/devices/dpdk/node.c @@ -660,9 +660,9 @@ poll_rate_limit (dpdk_main_t * dm) b->current_length and dispatch directly to ip4-input-no-checksum, or ip6-input. Trace the packet if required. - @param vm vlib_main_t corresponding to the current thread + @param vm vlib_main_t corresponding to the current thread @param node vlib_node_runtime_t - @param frame vlib_frame_t input-node, not used. + @param f vlib_frame_t input-node, not used. @par Graph mechanics: buffer metadata, next index usage diff --git a/vnet/vnet/ip/ip6_forward.c b/vnet/vnet/ip/ip6_forward.c index b076ed04..c9779602 100644 --- a/vnet/vnet/ip/ip6_forward.c +++ b/vnet/vnet/ip/ip6_forward.c @@ -3297,7 +3297,7 @@ add_del_ip6_interface_table (vlib_main_t * vm, return error; } -VLIB_CLI_COMMAND (set_interface_ip_table_command, static) = { +VLIB_CLI_COMMAND (set_interface_ip6_table_command, static) = { .path = "set interface ip6 table", .function = add_del_ip6_interface_table, .short_help = "set interface ip6 table " @@ -3442,7 +3442,7 @@ show_ip6_local_command_fn (vlib_main_t * vm, -VLIB_CLI_COMMAND (show_ip_local, static) = { +VLIB_CLI_COMMAND (show_ip6_local, static) = { .path = "show ip6 local", .function = show_ip6_local_command_fn, .short_help = "Show ip6 local protocol table", diff --git a/vnet/vnet/ip/ip_feature_registration.c b/vnet/vnet/ip/ip_feature_registration.c index baf7ea27..9505a09e 100644 --- a/vnet/vnet/ip/ip_feature_registration.c +++ b/vnet/vnet/ip/ip_feature_registration.c @@ -39,7 +39,7 @@ feature subgraph arc, which needs to run before @c ip4-lookup. In either base code or a plugin,
-    #include 
+    \#include 
     
and add the new feature as shown: @@ -57,7 +57,7 @@ @c my-ip4-unicast-feature on an interface:
-    ip4_main_t *im = &ip4_main;
+    ip4_main_t *im = \&ip4_main;
     ip_lookup_main_t *lm = &im->lookup_main;
     ip_config_main_t *rx_cm =
         &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
diff --git a/vnet/vnet/ipsec-gre/node.c b/vnet/vnet/ipsec-gre/node.c
index 5a176088..d20f248a 100644
--- a/vnet/vnet/ipsec-gre/node.c
+++ b/vnet/vnet/ipsec-gre/node.c
@@ -62,9 +62,9 @@ u8 * format_ipsec_gre_rx_trace (u8 * s, va_list * args)
  *
  * This node remove GRE header.
  *
- * @param vm vlib_main_t corresponding to the current thread.
- * @param node vlib_node_runtime_t data for this node.
- * @param frame vlib_frame_t whose contents should be dispatched.
+ * @param vm         vlib_main_t corresponding to the current thread.
+ * @param node       vlib_node_runtime_t data for this node.
+ * @param from_frame vlib_frame_t whose contents should be dispatched.
  *
  * @par Graph mechanics: buffer metadata, next index usage
  *
diff --git a/vnet/vnet/unix/pcap.c b/vnet/vnet/unix/pcap.c
index 5c8a14bd..bba225f7 100644
--- a/vnet/vnet/unix/pcap.c
+++ b/vnet/vnet/unix/pcap.c
@@ -43,21 +43,24 @@
 /**
  * @file
  * @brief PCAP function.
- *  Usage
  *
- * #include 
+ * Usage:
+ *
+ * 
+ * \#include 
  *
  * static pcap_main_t pcap = {
  *  .file_name = "/tmp/ip4",
  *  .n_packets_to_capture = 2,
  *  .packet_type = PCAP_PACKET_TYPE_ip,
  * };
+ * 
* * To add a buffer: * - * pcap_add_buffer (&pcap, vm, pi0, 128); + *
pcap_add_buffer (&pcap, vm, pi0, 128);
* - * File will be written after n_packets_to_capture or call to pcap_write (&pcap). + * File will be written after @c n_packets_to_capture or call to pcap_write (&pcap). * */ diff --git a/vnet/vnet/unix/tapcli.c b/vnet/vnet/unix/tapcli.c index 608b2209..c2328f0d 100644 --- a/vnet/vnet/unix/tapcli.c +++ b/vnet/vnet/unix/tapcli.c @@ -802,10 +802,10 @@ static tapcli_interface_t *tapcli_get_new_tapif() /** * @brief Connect a TAP interface * - * @param *vm - vlib_main_t - * @param *intfc_name - u8 - * @param *hwaddr_arg - u8 - * @param *sw_if_index - u32 + * @param vm - vlib_main_t + * @param intfc_name - u8 + * @param hwaddr_arg - u8 + * @param sw_if_indexp - u32 * * @return rc - int * diff --git a/vnet/vnet/vxlan-gpe/decap.c b/vnet/vnet/vxlan-gpe/decap.c index 70cf08e1..7eca3f6b 100644 --- a/vnet/vnet/vxlan-gpe/decap.c +++ b/vnet/vnet/vxlan-gpe/decap.c @@ -96,7 +96,7 @@ static u8 * format_vxlan_gpe_with_length (u8 * s, va_list * args) * @param *vm * @param *node * @param *from_frame - * @param ip_ip4 + * @param is_ip4 * * @return from_frame->n_vectors * diff --git a/vppinfra/vppinfra/bihash_8_8.h b/vppinfra/vppinfra/bihash_8_8.h index b5f4e3bf..9b5da5a2 100644 --- a/vppinfra/vppinfra/bihash_8_8.h +++ b/vppinfra/vppinfra/bihash_8_8.h @@ -54,7 +54,7 @@ clib_bihash_hash_8_8 (clib_bihash_kv_8_8_t * v) /** Format a clib_bihash_kv_8_8_t instance @param s - u8 * vector under construction - @param v (vararg) - the (key,value) pair to format + @param args (vararg) - the (key,value) pair to format @return s - the u8 * vector under construction */ static inline u8 * diff --git a/vppinfra/vppinfra/bihash_doc.h b/vppinfra/vppinfra/bihash_doc.h index da3d0a9b..e6ab9db6 100644 --- a/vppinfra/vppinfra/bihash_doc.h +++ b/vppinfra/vppinfra/bihash_doc.h @@ -108,7 +108,7 @@ void clib_bihash_free (clib_bihash * h); /** Add or delete a (key,value) pair from a bi-hash table @param h - the bi-hash table to search - @param add_kv - the (key,value) pair to add + @param add_v - the (key,value) pair to add @param is_add - add=1, delete=0 @returns 0 on success, < 0 on error @note This function will replace an existing (key,value) pair if the diff --git a/vppinfra/vppinfra/bitmap.h b/vppinfra/vppinfra/bitmap.h index 4c27820d..9e1ae493 100644 --- a/vppinfra/vppinfra/bitmap.h +++ b/vppinfra/vppinfra/bitmap.h @@ -81,7 +81,7 @@ clib_bitmap_is_equal (uword * a, uword * b) } /** Duplicate a bitmap - @param ai - pointer to a bitmap + @param v - pointer to a bitmap @returns a duplicate of the bitmap */ #define clib_bitmap_dup(v) vec_dup(v) @@ -158,9 +158,9 @@ clib_bitmap_set_no_check (uword * a, uword i, uword new_value) /** Sets the ith bit of a bitmap to new_value Removes trailing zeros from the bitmap - @param a - pointer to the bitmap + @param ai - pointer to the bitmap @param i - the bit position to interrogate - @param new_value - new value for the bit + @param value - new value for the bit @returns the old value of the bit */ always_inline uword * @@ -588,7 +588,7 @@ _(andnoti, a = a & ~b, 1) _(ori, a = a | b, 0) _(xori, a = a ^ b, 1) /** Return a random bitmap of the requested length @param ai - pointer to the destination bitmap @param n_bits - number of bits to allocate - @param [in/out] seed - pointer to the random number seed + @param [in,out] seed - pointer to the random number seed @returns a reasonably random bitmap based. See random.h. */ always_inline uword * -- cgit 1.2.3-korg From 3b480933c80cac8963995b61f48ee9aedb3d6e16 Mon Sep 17 00:00:00 2001 From: Chris Luke Date: Wed, 7 Sep 2016 13:28:59 -0400 Subject: VPP-346 Improve Doxygen include path mechanism - If present, include the directories where API header files are generated into. - Improve extraction of include paths from CPP - Generalize the file/directory exclusion This reduces some of the "warning" chatter from Doxygen. Change-Id: I7ac02bff1639fe63f11263176020b0f040255017 Signed-off-by: Chris Luke --- doxygen/Makefile | 76 +++++++++++++++++++++++++++++++++++++---------------- doxygen/doxygen.cfg | 2 +- 2 files changed, 55 insertions(+), 23 deletions(-) (limited to 'doxygen/Makefile') diff --git a/doxygen/Makefile b/doxygen/Makefile index 471b6fd7..b75c9c6b 100644 --- a/doxygen/Makefile +++ b/doxygen/Makefile @@ -28,38 +28,63 @@ DOC_RPM_DEPENDS = doxygen graphviz pyparsing # Doxygen configuration and our utility scripts DOXY_DIR ?= $(WS_ROOT)/doxygen -# Input directories and files -DOXY_INPUT ?= \ - README.md \ +# Primary source directories +DOXY_SRC_DIRECTORIES = \ vppinfra \ svm \ vlib \ vlib-api \ vnet \ vpp \ - vpp-api \ + vpp-api + +# Input directories and files +DOXY_INPUT ?= \ + README.md \ + $(DOXY_SRC_DIRECTORIES) \ plugins # Files to exclude, from pre-Doxygen steps, eg because they're # selectively compiled. # Examples would be to exclude non-DPDK related sources when # there's a DPDK equivalent that conflicts. -# This is specifically for the pre-Doxygen steps; Doxygen uses -# @cond for this instead. -DOXY_PRE_EXCLUDE ?= \ - vlib/vlib/buffer.c +# These must be left-anchored paths for the regexp below to work. +DOXY_EXCLUDE ?= \ + vlib/vlib/buffer.c \ + vlib/example \ + plugins/sample-plugin # Generate a regexp for filenames to exclude -DOXY_PRE_EXCLUDE_REGEXP = ($(subst .,\.,$(shell echo '$(strip $(DOXY_PRE_EXCLUDE))' | sed -e 's/ /|/g'))) - -# Discover all the directories we might, possibly, maybe, have include files in -DOXY_INCLUDE_PATH = $(shell set -e; cd $(WS_ROOT); for item in $(DOXY_INPUT); do find $$item -type d; done) +DOXY_EXCLUDE_REGEXP = ($(subst .,\.,$(shell echo '$(strip $(DOXY_EXCLUDE))' | sed -e 's/ /|/g'))) + +# Include all the normal source directories in the include file path +DOXY_INCLUDE_PATH = $(DOXY_SRC_DIRECTORIES) + +# Also include any plugin directories that exist +DOXY_INCLUDE_PATH += \ + $(shell find $(WS_ROOT)/plugins -maxdepth 1 -type d | sed -e 's@^$(WS_ROOT)/*@@') + +# Find API header directories and include them in the header path. +# This is only useful if VPP and plugins are already built; nothing +# here depends on those targets. We don't build documentation for these +# header files, they're just added to the INCLUDE search path for Doxygen. +_vpp_br = $(shell find "$(BR)" -maxdepth 1 -type d \ + '(' -name build-vpp_debug-native -o -name build-vpp-native ')' -print \ + | sed -e 's@^$(WS_ROOT)/*@@' -e 1q) +ifneq ($(strip $(_vpp_br)),) +DOXY_INCLUDE_PATH += \ + $(_vpp_br)/vlib-api \ + $(_vpp_br)/vpp +# Also include any plugin directories that exist +DOXY_INCLUDE_PATH += \ + $(shell find $(WS_ROOT)/$(_vpp_br)/plugins -maxdepth 1 -type d | sed -e 's@^$(WS_ROOT)/*@@') +endif # Discover if we have CPP available -CPP ?= $(shell which cpp) -ifneq ($(strip $(CPP)),) -# Add whatever directories CPP normally includes -DOXY_INCLUDE_PATH += $(shell set -e; $(CPP) -v &1 | grep -A 1000 '\#include' | awk '/^ /{print $$1}') +_cpp = $(shell which cpp) +ifneq ($(strip $(_cpp)),) +# Add whatever directories CPP normally includes to the header path +DOXY_INCLUDE_PATH += $(shell set -e; $(_cpp) -v &1 | awk 'f&&/^ /{print $$1} /^\#include/{f=1}') endif # Target directory for doxygen output @@ -81,6 +106,7 @@ SIPHON_FILES = $(addprefix $(SIPHON_INPUT)/,$(addsuffix .siphon,$(SIPHONS))) SIPHON_DOCS = $(addprefix $(SIPHON_OUTPUT)/,$(addsuffix .md,$(SIPHONS))) $(BR)/.doxygen-bootstrap.ok: + @echo "Checking whether dependencies for Doxygen are installed..." ifeq ($(OS_ID),ubuntu) @set -e; inst=; \ for i in $(DOC_DEB_DEPENDS); do \ @@ -99,10 +125,11 @@ bootstrap-doxygen: $(BR)/.doxygen-bootstrap.ok .DELETE_ON_ERROR: $(BR)/.doxygen-siphon.dep $(BR)/.doxygen-siphon.dep: Makefile - set -e; rm -f "$@"; for input in $(DOXY_INPUT); do \ + @echo "Building siphon dependencies..." + @set -e; rm -f "$@"; for input in $(DOXY_INPUT); do \ find "$(WS_ROOT)/$$input" -type f \ \( -name '*.[ch]' -or -name '*.dox' \) -print \ - | grep -v -E '^$(WS_ROOT)/$(DOXY_PRE_EXCLUDE_REGEXP)$$' \ + | grep -v -E '^$(WS_ROOT)/$(DOXY_EXCLUDE_REGEXP)' \ | sed -e "s/^/\$$(SIPHON_FILES): /" \ >> $@; \ done @@ -115,21 +142,24 @@ $(SIPHON_FILES): $(DOXY_DIR)/siphon_generate.py $(BR)/.doxygen-bootstrap.ok @rm -rf "$(SIPHON_INPUT)" "$(SIPHON_OUTPUT)" @mkdir -p "$(SIPHON_INPUT)" "$(SIPHON_OUTPUT)" @touch $(SIPHON_INPUT)/files - for input in $(DOXY_INPUT); do \ + @echo "Collating source file list for siphoning..." + @for input in $(DOXY_INPUT); do \ cd "$(WS_ROOT)"; \ find "$$input" -type f \ \( -name '*.[ch]' -or -name '*.dox' \) -print \ - | grep -v -E '^$(DOXY_PRE_EXCLUDE_REGEXP)$$' \ + | grep -v -E '^$(DOXY_EXCLUDE_REGEXP)' \ >> $(SIPHON_INPUT)/files; \ done - set -e; cd "$(WS_ROOT)"; $(DOXY_DIR)/siphon_generate.py \ + @echo "Generating siphons..." + @set -e; cd "$(WS_ROOT)"; $(DOXY_DIR)/siphon_generate.py \ --output="$(SIPHON_INPUT)" \ "@$(SIPHON_INPUT)/files" .DELETE_ON_ERROR: $(SIPHON_DOCS) $(SIPHON_OUTPUT)/%.md: $(SIPHON_INPUT)/%.siphon $(DOXY_DIR)/siphon_process.py - set -e; cd "$(WS_ROOT)"; \ + @echo "Processing siphon from $(notdir $<)..." + @set -e; cd "$(WS_ROOT)"; \ $(DOXY_DIR)/siphon_process.py --type=$(basename $(notdir $<)) \ --output="$(SIPHON_OUTPUT)" $< > $@ @@ -140,11 +170,13 @@ doxygen-siphon: $(SIPHON_DOCS) # Generate the doxygen docs doxygen: $(SIPHON_DOCS) @mkdir -p "$(DOXY_OUTPUT)" + @echo "Running Doxygen..." set -e; cd "$(WS_ROOT)"; \ ROOT="$(WS_ROOT)" \ BUILD_ROOT="$(BR)" \ INPUT="$(addprefix $(WS_ROOT)/,$(DOXY_INPUT)) $(EXTRA_DOXY_INPUT)" \ INCLUDE_PATH="$(DOXY_INCLUDE_PATH)" \ + EXCLUDE="$(DOXY_EXCLUDE)" \ HTML=YES \ VERSION="`git describe --tags --dirty`" \ doxygen $(DOXY_DIR)/doxygen.cfg diff --git a/doxygen/doxygen.cfg b/doxygen/doxygen.cfg index 971a1595..7b24ae86 100644 --- a/doxygen/doxygen.cfg +++ b/doxygen/doxygen.cfg @@ -826,7 +826,7 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = +EXCLUDE = $(EXCLUDE) # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded -- cgit 1.2.3-korg From c87fa6dede65ab180d8f5cc396d9039882d0baad Mon Sep 17 00:00:00 2001 From: Chris Luke Date: Fri, 9 Sep 2016 17:51:42 -0400 Subject: On Ubuntu check for graphviz system config - Sometimes it seems Ubuntu doesn't always set up the Graphviz handler config. If it's missing, generate it. Change-Id: I2c1e566817de8415f8b360c6f967cd76307a2a52 Signed-off-by: Chris Luke --- doxygen/Makefile | 3 +++ 1 file changed, 3 insertions(+) (limited to 'doxygen/Makefile') diff --git a/doxygen/Makefile b/doxygen/Makefile index b75c9c6b..ef52c493 100644 --- a/doxygen/Makefile +++ b/doxygen/Makefile @@ -113,6 +113,9 @@ ifeq ($(OS_ID),ubuntu) dpkg-query --show $$i >/dev/null 2>&1 || inst="$$inst $$i"; \ done; \ if [ "$$inst" ]; then sudo apt-get $(CONFIRM) $(FORCE) install $$inst; fi + @if [ ! -f /usr/lib/graphviz/config6a ]; then \ + sudo dot -c; \ + fi else ifneq ("$(wildcard /etc/redhat-release)","") @sudo yum install $(CONFIRM) $(DOC_RPM_DEPENDS) else -- cgit 1.2.3-korg From 35425140386cfd092e547e511ad2d3cbe804a459 Mon Sep 17 00:00:00 2001 From: Chris Luke Date: Fri, 9 Sep 2016 20:16:04 -0400 Subject: Check for zero-sized Graphvix config file on Ubuntu; VPP-396 - The previous change only accounted for a missing Graphviz config file; apparently it can be zero-sized too. Change-Id: Ic6957d10cdc7cb7b9da72d2b2a0f8913100870c5 Signed-off-by: Chris Luke --- doxygen/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'doxygen/Makefile') diff --git a/doxygen/Makefile b/doxygen/Makefile index ef52c493..954191eb 100644 --- a/doxygen/Makefile +++ b/doxygen/Makefile @@ -113,7 +113,8 @@ ifeq ($(OS_ID),ubuntu) dpkg-query --show $$i >/dev/null 2>&1 || inst="$$inst $$i"; \ done; \ if [ "$$inst" ]; then sudo apt-get $(CONFIRM) $(FORCE) install $$inst; fi - @if [ ! -f /usr/lib/graphviz/config6a ]; then \ + @if [ ! -s /usr/lib/graphviz/config6a ]; then \ + echo "Rebuidlding system Graphviz configuration."; \ sudo dot -c; \ fi else ifneq ("$(wildcard /etc/redhat-release)","") -- cgit 1.2.3-korg From 5ccbaa97a86715bfee2ab44523075a93a8abb698 Mon Sep 17 00:00:00 2001 From: Chris Luke Date: Wed, 14 Sep 2016 12:42:54 -0400 Subject: Add structure to some of the documentation; VPP-223 Moves the random .md files, when rendered by Doxygen, into a config examples tree. We may later flesh this out into a more complete user documentation section. Change-Id: If423b82f1047f1c84f90876a786313054b5f7c77 Signed-off-by: Chris Luke --- README.md | 5 +- doxygen/Makefile | 6 +- doxygen/user_doc.md | 10 + plugins/ioam-plugin/ioam/Readme.md | 465 ---------------------------- plugins/ioam-plugin/ioam/ioam_plugin_doc.md | 464 +++++++++++++++++++++++++++ plugins/lb-plugin/README.md | 141 --------- plugins/lb-plugin/lb_plugin_doc.md | 141 +++++++++ vnet/vnet/ipsec-gre/ipsec_gre_doc.md | 2 +- vnet/vnet/lldp/lldp.md | 84 ----- vnet/vnet/lldp/lldp_doc.md | 84 +++++ vnet/vnet/map/map_doc.md | 2 +- 11 files changed, 710 insertions(+), 694 deletions(-) create mode 100644 doxygen/user_doc.md delete mode 100644 plugins/ioam-plugin/ioam/Readme.md create mode 100644 plugins/ioam-plugin/ioam/ioam_plugin_doc.md delete mode 100644 plugins/lb-plugin/README.md create mode 100644 plugins/lb-plugin/lb_plugin_doc.md delete mode 100644 vnet/vnet/lldp/lldp.md create mode 100644 vnet/vnet/lldp/lldp_doc.md (limited to 'doxygen/Makefile') diff --git a/README.md b/README.md index ccc832c4..bf26c9de 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Directory name | Description g2 | Event log visualization tool gmod | perf related? perftool | Performance tool - plugins | VPP bundled plugins directory +@ref plugins | VPP bundled plugins directory @ref svm | Shared virtual memory allocation library test | Unit tests @ref vlib | VPP application library source @@ -90,5 +90,8 @@ for this can be found [on the Setting up Vagrant wiki page] ## More information. +Several modules provide documentation, see @subpage user_doc for more +information. + Visit the [VPP wiki](https://wiki.fd.io/view/VPP) for details on more advanced building strategies and development notes. diff --git a/doxygen/Makefile b/doxygen/Makefile index 954191eb..0a69c2df 100644 --- a/doxygen/Makefile +++ b/doxygen/Makefile @@ -40,10 +40,14 @@ DOXY_SRC_DIRECTORIES = \ # Input directories and files DOXY_INPUT ?= \ - README.md \ + $(wildcard $(WS_ROOT)/*.md) \ + $(wildcard $(DOXY_DIR)/*.md) \ $(DOXY_SRC_DIRECTORIES) \ plugins +# Strip leading workspace path from input names +DOXY_INPUT := $(subst $(WS_ROOT)/,,$(DOXY_INPUT)) + # Files to exclude, from pre-Doxygen steps, eg because they're # selectively compiled. # Examples would be to exclude non-DPDK related sources when diff --git a/doxygen/user_doc.md b/doxygen/user_doc.md new file mode 100644 index 00000000..b08ac86a --- /dev/null +++ b/doxygen/user_doc.md @@ -0,0 +1,10 @@ +User Configuration Examples {#user_doc} +=========================== + +Several modules provide operational documentation. + +- @subpage ipsec_gre_doc +- @subpage map_doc +- @subpage lldp_doc +- @subpage ioam_plugin_doc +- @subpage lb_plugin_doc diff --git a/plugins/ioam-plugin/ioam/Readme.md b/plugins/ioam-plugin/ioam/Readme.md deleted file mode 100644 index 469a15a1..00000000 --- a/plugins/ioam-plugin/ioam/Readme.md +++ /dev/null @@ -1,465 +0,0 @@ - -## VPP Inband OAM (iOAM) - -In-band OAM (iOAM) is an implementation study to record operational -information in the packet while the packet traverses a path between -two points in the network. - -Overview of iOAM can be found in [iOAM-Devnet] page. -The following IETF drafts detail the motivation and mechanism for -recording operational information: - - [iOAM-ietf-requirements] - Describes motivation and usecases for iOAM - - [iOAM-ietf-data] - Describes data records that can be collected using iOAM - - [iOAM-ietf-transport] - Lists out the transport protocols - and mechanism to carry iOAM data records - - [iOAM-ietf-proof-of-transit] - Describes the idea of Proof of Transit (POT) - and mechanisms to operationalize the idea - -## Terminology -In-band OAM is expected to be deployed in a specific domain rather -than on the overall Internet. The part of the network which employs in-band OAM -is referred to as **"in-band OAM-domain"**. - -In-band OAM data is added to a packet on entering the in-band OAM-domain -and is removed from the packet when exiting the domain. -Within the in-band OAM-domain, network nodes that the packet traverses -may update the in-band OAM data records. - -- The node which adds in-band OAM data to the packet is called the -**"in-band OAM encapsulating node"**. - -- The node which removes the in-band OAM data is referred to as the -**"in-band OAM decapsulating node"**. - -- Nodes within the domain which are aware of in-band OAM data and read -and/or write or process the in-band OAM data are called -**"in-band OAM transit nodes"**. - -## Features supported in the current release -VPP can function as in-band OAM encapsulating, transit and decapsulating node. -In this version of VPP in-band OAM data is transported as options in an -IPv6 hop-by-hop extension header. Hence in-band OAM can be enabled -for IPv6 traffic. - -The following iOAM features are supported: - -- **In-band OAM Tracing** : In-band OAM supports multiple data records to be -recorded in the packet as the packet traverses the network. -These data records offer insights into the operational behavior of the network. -The following information can be collected in the tracing -data from the nodes a packet traverses: - - Node ID - - Ingress interface ID - - Egress interface ID - - Timestamp - - Pre-configured application data - -- **In-band OAM Proof of Transit (POT)**: Proof of transit iOAM data is -added to every packet for verifying that a packet traverses a specific -set of nodes. -In-band OAM data is updated at every node that is enabled with iOAM -proof of transit and is used to verify whether a packet traversed -all the specified nodes. When the verifier receives each packet, -it can validate whether the packet traversed the specified nodes. - - -## Configuration -Configuring iOAM involves: -- Selecting the packets for which iOAM data must be inserted, updated or removed - - Selection of packets for iOAM data insertion on iOAM encapsulating node. - Selection of packets is done by 5-tuple based classification - - Selection of packets for updating iOAM data is implicitly done on the - presence of iOAM options in the packet - - Selection of packets for removing the iOAM data is done on 5-tuple - based classification -- The kind of data to be collected - - Tracing data - - Proof of transit -- Additional details for processing iOAM data to be collected - - For trace data - trace type, number of nodes to be recorded in the trace, - time stamp precision, etc. - - For POT data - configuration of POT profile required to process the POT data - -The CLI for configuring iOAM is explained here followed by detailed steps -and examples to deploy iOAM on VPP as an encapsulating, transit or -decapsulating iOAM node in the subsequent sub-sections. - -VPP iOAM configuration for enabling trace and POT is as follows: - - set ioam rewrite trace-type <0x1f|0x7|0x9|0x11|0x19> - trace-elts trace-tsp <0|1|2|3> - node-id app-data [pot] - -A description of each of the options of the CLI follows: -- trace-type : An entry in the "Node data List" array of the trace option -can have different formats, following the needs of the a deployment. -For example: Some deployments might only be interested -in recording the node identifiers, whereas others might be interested -in recording node identifier and timestamp. -The following types are currently supported: - - 0x1f : Node data to include hop limit (8 bits), node ID (24 bits), - ingress and egress interface IDs (16 bits each), timestamp (32 bits), - application data (32 bits) - - 0x7 : Node data to include hop limit (8 bits), node ID (24 bits), - ingress and egress interface IDs (16 bits each) - - 0x9 : Node data to include hop limit (8 bits), node ID (24 bits), - timestamp (32 bits) - - 0x11: Node data to include hop limit (8 bits), node ID (24 bits), - application data (32 bits) - - 0x19: Node data to include hop limit (8 bits), node ID (24 bits), - timestamp (32 bits), application data (32 bits) -- trace-elts : Defines the length of the node data array in the trace option. -- trace-tsp : Defines the timestamp precision to use with the enumerated value - for precision as follows: - - 0 : 32bits timestamp in seconds - - 1 : 32bits timestamp in milliseconds - - 2 : 32bits timestamp in microseconds - - 3 : 32bits timestamp in nanoseconds -- node-id : Unique identifier for the node, included in the node ID - field of the node data in trace option. -- app-data : The value configured here is included as is in -application data field of node data in trace option. -- pot : Enables POT option to be included in the iOAM options. - -### Trace configuration - -#### On in-band OAM encapsulating node - - **Configure classifier and apply ACL** to select packets for - iOAM data insertion - - Example to enable iOAM data insertion for all the packets - towards IPv6 address db06::06: - - vpp# classify table miss-next node ip6-lookup mask l3 ip6 dst - - vpp# classify session acl-hit-next node ip6-add-hop-by-hop - table-index 0 match l3 ip6 dst db06::06 - - vpp# set int input acl intfc GigabitEthernet0/0/0 ip6-table 0 - - - **Enable tracing** : Specify node ID, maximum number of nodes for which - trace data should be recorded, type of data to be included for recording, - optionally application data to be included - - Example to enable tracing with a maximum of 4 nodes recorded - and the data to be recorded to include - hop limit, node id, - ingress and egress interface IDs, timestamp (millisecond precision), - application data (0x1234): - - - vpp# set ioam rewrite trace-type 0x1f trace-elts 4 trace-tsp 1 - node-id 0x1 app-data 0x1234 - - - -#### On in-band OAM transit node -- The transit node requires trace type, timestamp precision, node ID and -optionally application data to be configured, -to update its node data in the trace option. - -Example: - - vpp# set ioam rewrite trace-type 0x1f trace-elts 4 trace-tsp 1 - node-id 0x2 app-data 0x1234 - -#### On the In-band OAM decapsulating node -- The decapsulating node similar to encapsulating node requires -**classification** of the packets to remove iOAM data from. - - Example to decapsulate iOAM data for packets towards - db06::06, configure classifier and enable it as an ACL as follows: - - - vpp# classify table miss-next node ip6-lookup mask l3 ip6 dst - - vpp# classify session acl-hit-next node ip6-lookup table-index 0 - match l3 ip6 dst db06::06 opaque-index 100 - - vpp# set int input acl intfc GigabitEthernet0/0/0 ip6-table 0 - - -- Decapsulating node requires trace type, timestamp precision, -node ID and optionally application data to be configured, -to update its node data in the trace option before it is decapsulated. - -Example: - - vpp# set ioam rewrite trace-type 0x1f trace-elts 4 - trace-tsp 1 node-id 0x3 app-data 0x1234 - - -### Proof of Transit configuration - -For details on proof-of-transit, -see the IETF draft [iOAM-ietf-proof-of-transit]. -To enable Proof of Transit all the nodes that participate -and hence are verified for transit need a proof of transit profile. -A script to generate a proof of transit profile as per the mechanism -described in [iOAM-ietf-proof-of-transit] will be available at [iOAM-Devnet]. - -The Proof of transit mechanism implemented here is based on -Shamir's Secret Sharing algorithm. -The overall algorithm uses two polynomials -POLY-1 and POLY-2. The degree of polynomials depends on number of nodes -to be verified for transit. -POLY-1 is secret and constant. Each node gets a point on POLY-1 -at setup-time and keeps it secret. -POLY-2 is public, random and per packet. -Each node is assigned a point on POLY-1 and POLY-2 with the same x index. -Each node derives its point on POLY-2 each time a packet arrives at it. -A node then contributes its points on POLY-1 and POLY-2 to construct -POLY-3 (POLY-3 = POLY-1 + POLY-2) using lagrange extrapolation and -forwards it towards the verifier by updating POT data in the packet. -The verifier constructs POLY-3 from the accumulated value from all the nodes -and its own points on POLY-1 and POLY-2 and verifies whether -POLY-3 = POLY-1 + POLY-2. Only the verifier knows POLY-1. -The solution leverages finite field arithmetic in a field of size "prime number" -for reasons explained in description of Shamir's secret sharing algorithm. - -Here is an explanation of POT profile list and profile configuration CLI to -realize the above mechanism. -It is best to use the script provided at [iOAM-Devnet] to generate -this configuration. -- **Create POT profile** : set pot profile name id [0-1] -[validator-key 0xu64] prime-number 0xu64 secret_share 0xu64 -lpc 0xu64 polynomial2 0xu64 bits-in-random [0-64] - - name : Profile list name. - - id : Profile id, it can be 0 or 1. - A maximum of two profiles can be configured per profile list. - - validator-key : Secret key configured only on the - verifier/decapsulating node used to compare and verify proof of transit. - - prime-number : Prime number for finite field arithmetic as required by the - proof of transit mechanism. - - secret_share : Unique point for each node on the secret polynomial POLY-1. - - lpc : Lagrange Polynomial Constant(LPC) calculated per node based on - its point (x value used for evaluating the points on the polynomial) - on the polynomial used in lagrange extrapolation - for reconstructing polynomial (POLY-3). - - polynomial2 : Is the pre-evaluated value of the point on - 2nd polynomial(POLY-2). This is unique for each node. - It is pre-evaluated for all the coefficients of POLY-2 except - for the constant part of the polynomial that changes per packet - and is received as part of the POT data in the packet. - - bits-in-random : To control the size of the random number to be - generated. This number has to match the other numbers generated and used - in the profile as per the algorithm. - -- **Set a configured profile as active/in-use** : -set pot profile-active name ID [0-1] - - name : Name of the profile list to be used for computing - POT data per packet. - - ID : Identifier of the profile within the list to be used. - -#### On In-band OAM encapsulating node - - Configure the classifier and apply ACL to select packets for iOAM data insertion. - - Example to enable iOAM data insertion for all the packet towards - IPv6 address db06::06 - - - - vpp# classify table miss-next node ip6-lookup mask l3 ip6 dst - - vpp# classify session acl-hit-next node - ip6-add-hop-by-hop table-index 0 match l3 ip6 dst db06::06 - - vpp# set int input acl intfc GigabitEthernet0/0/0 ip6-table 0 - - - - Configure the proof of transit profile list with profiles. -Each profile list referred to by a name can contain 2 profiles, -only one is in use for updating proof of transit data at any time. - - Example profile list example with a profile generated from the - script to verify transit through 3 nodes is: - - - vpp# set pot profile name example id 0 prime-number 0x7fff0000fa884685 - secret_share 0x6c22eff0f45ec56d lpc 0x7fff0000fa884682 - polynomial2 0xffb543d4a9c bits-in-random 63 - - - Enable one of the profiles from the configured profile list as active - so that is will be used for calculating proof of transit - -Example enable profile ID 0 from profile list example configured above: - - - vpp# set pot profile-active name example ID 0 - - - - Enable POT option to be inserted - - - vpp# set ioam rewrite pot - - -#### On in-band OAM transit node - - Configure the proof of transit profile list with profiles for transit node. -Example: - - - vpp# set pot profile name example id 0 prime-number 0x7fff0000fa884685 - secret_share 0x564cdbdec4eb625d lpc 0x1 - polynomial2 0x23f3a227186a bits-in-random 63 - -#### On in-band OAM decapsulating node / verifier -- The decapsulating node, similar to the encapsulating node requires -classification of the packets to remove iOAM data from. - - Example to decapsulate iOAM data for packets towards db06::06 - configure classifier and enable it as an ACL as follows: - - - vpp# classify table miss-next node ip6-lookup mask l3 ip6 dst - - vpp# classify session acl-hit-next node ip6-lookup table-index 0 - match l3 ip6 dst db06::06 opaque-index 100 - - vpp# set int input acl intfc GigabitEthernet0/0/0 ip6-table 0 - -- To update and verify the proof of transit, POT profile list should be configured. - - Example POT profile list configured as follows: - - vpp# set pot profile name example id 0 validate-key 0x7fff0000fa88465d - prime-number 0x7fff0000fa884685 secret_share 0x7a08fbfc5b93116d lpc 0x3 - polynomial2 0x3ff738597ce bits-in-random 63 - -## Operational data - -Following CLIs are available to check iOAM operation: -- To check iOAM configuration that are effective use "show ioam summary" - -Example: - - vpp# show ioam summary - REWRITE FLOW CONFIGS - Not configured - HOP BY HOP OPTIONS - TRACE CONFIG - - Trace Type : 0x1f (31) - Trace timestamp precision : 1 (Milliseconds) - Num of trace nodes : 4 - Node-id : 0x2 (2) - App Data : 0x1234 (4660) - POT OPTION - 1 (Enabled) - Try 'show ioam pot and show pot profile' for more information - -- To find statistics about packets for which iOAM options were -added (encapsulating node) and removed (decapsulating node) execute -*show errors* - -Example on encapsulating node: - - - vpp# show error - Count Node Reason - 1208804706 ip6-inacl input ACL hits - 1208804706 ip6-add-hop-by-hop Pkts w/ added ip6 hop-by-hop options - -Example on decapsulating node: - - vpp# show error - Count Node Reason - 69508569 ip6-inacl input ACL hits - 69508569 ip6-pop-hop-by-hop Pkts w/ removed ip6 hop-by-hop options - -- To check the POT profiles use "show pot profile" - -Example: - - vpp# show pot profile - Profile list in use : example - POT Profile at index: 0 - ID : 0 - Validator : False (0) - Secret share : 0x564cdbdec4eb625d (6218586935324795485) - Prime number : 0x7fff0000fa884685 (9223090566081300101) - 2nd polynomial(eval) : 0x23f3a227186a (39529304496234) - LPC : 0x1 (1) - Bit mask : 0x7fffffffffffffff (9223372036854775807) - Profile index in use: 0 - Pkts passed : 0x36 (54) - -- To get statistics of POT for packets use "show ioam pot" - -Example at encapsulating or transit node: - - vpp# show ioam pot - Pkts with ip6 hop-by-hop POT options - 54 - Pkts with ip6 hop-by-hop POT options but no profile set - 0 - Pkts with POT in Policy - 0 - Pkts with POT out of Policy - 0 - - -Example at decapsulating/verification node: - - - vpp# show ioam pot - Pkts with ip6 hop-by-hop POT options - 54 - Pkts with ip6 hop-by-hop POT options but no profile set - 0 - Pkts with POT in Policy - 54 - Pkts with POT out of Policy - 0 - -- Tracing - enable trace of IPv6 packets to view the data inserted and -collected. - -Example when the nodes are receiving data over a DPDK interface: -Enable tracing using "trace add dpdk-input 20" and -execute "show trace" to view the iOAM data collected: - - - vpp# trace add dpdk-input 20 - - vpp# show trace - - ------------------- Start of thread 0 vpp_main ------------------- - - Packet 1 - - 00:00:19:294697: dpdk-input - GigabitEthernetb/0/0 rx queue 0 - buffer 0x10e6b: current data 0, length 214, free-list 0, totlen-nifb 0, trace 0x0 - PKT MBUF: port 0, nb_segs 1, pkt_len 214 - buf_len 2176, data_len 214, ol_flags 0x0, data_off 128, phys_addr 0xe9a35a00 - packet_type 0x0 - IP6: 00:50:56:9c:df:72 -> 00:50:56:9c:be:55 - IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 - tos 0x00, flow label 0x0, hop limit 63, payload length 160 - 00:00:19:294737: ethernet-input - IP6: 00:50:56:9c:df:72 -> 00:50:56:9c:be:55 - 00:00:19:294753: ip6-input - IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 - tos 0x00, flow label 0x0, hop limit 63, payload length 160 - 00:00:19:294757: ip6-lookup - fib 0 adj-idx 15 : indirect via db05::2 flow hash: 0x00000000 - IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 - tos 0x00, flow label 0x0, hop limit 63, payload length 160 - 00:00:19:294802: ip6-hop-by-hop - IP6_HOP_BY_HOP: next index 5 len 96 traced 96 Trace Type 0x1f , 1 elts left - [0] ttl 0x0 node ID 0x0 ingress 0x0 egress 0x0 ts 0x0 - app 0x0 - [1] ttl 0x3e node ID 0x3 ingress 0x1 egress 0x2 ts 0xb68c2213 - app 0x1234 - [2] ttl 0x3f node ID 0x2 ingress 0x1 egress 0x2 ts 0xb68c2204 - app 0x1234 - [3] ttl 0x40 node ID 0x1 ingress 0x5 egress 0x6 ts 0xb68c2200 - app 0x1234 - POT opt present - random = 0x577a916946071950, Cumulative = 0x10b46e78a35a392d, Index = 0x0 - 00:00:19:294810: ip6-rewrite - tx_sw_if_index 1 adj-idx 14 : GigabitEthernetb/0/0 - IP6: 00:50:56:9c:be:55 -> 00:50:56:9c:df:72 flow hash: 0x00000000 - IP6: 00:50:56:9c:be:55 -> 00:50:56:9c:df:72 - IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 - tos 0x00, flow label 0x0, hop limit 62, payload length 160 - 00:00:19:294814: GigabitEthernetb/0/0-output - GigabitEthernetb/0/0 - IP6: 00:50:56:9c:be:55 -> 00:50:56:9c:df:72 - IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 - tos 0x00, flow label 0x0, hop limit 62, payload length 160 - 00:00:19:294820: GigabitEthernetb/0/0-tx - GigabitEthernetb/0/0 tx queue 0 - buffer 0x10e6b: current data 0, length 214, free-list 0, totlen-nifb 0, trace 0x0 - IP6: 00:50:56:9c:be:55 -> 00:50:56:9c:df:72 - - IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 - - tos 0x00, flow label 0x0, hop limit 62, payload length 160 - - -[iOAM-Devnet]: -[iOAM-ietf-requirements]: -[iOAM-ietf-transport]: -[iOAM-ietf-data]: -[iOAM-ietf-proof-of-transit]: diff --git a/plugins/ioam-plugin/ioam/ioam_plugin_doc.md b/plugins/ioam-plugin/ioam/ioam_plugin_doc.md new file mode 100644 index 00000000..343abcf7 --- /dev/null +++ b/plugins/ioam-plugin/ioam/ioam_plugin_doc.md @@ -0,0 +1,464 @@ +## VPP Inband OAM (iOAM) {#ioam_plugin_doc} + +In-band OAM (iOAM) is an implementation study to record operational +information in the packet while the packet traverses a path between +two points in the network. + +Overview of iOAM can be found in [iOAM-Devnet] page. +The following IETF drafts detail the motivation and mechanism for +recording operational information: + - [iOAM-ietf-requirements] - Describes motivation and usecases for iOAM + - [iOAM-ietf-data] - Describes data records that can be collected using iOAM + - [iOAM-ietf-transport] - Lists out the transport protocols + and mechanism to carry iOAM data records + - [iOAM-ietf-proof-of-transit] - Describes the idea of Proof of Transit (POT) + and mechanisms to operationalize the idea + +## Terminology +In-band OAM is expected to be deployed in a specific domain rather +than on the overall Internet. The part of the network which employs in-band OAM +is referred to as **"in-band OAM-domain"**. + +In-band OAM data is added to a packet on entering the in-band OAM-domain +and is removed from the packet when exiting the domain. +Within the in-band OAM-domain, network nodes that the packet traverses +may update the in-band OAM data records. + +- The node which adds in-band OAM data to the packet is called the +**"in-band OAM encapsulating node"**. + +- The node which removes the in-band OAM data is referred to as the +**"in-band OAM decapsulating node"**. + +- Nodes within the domain which are aware of in-band OAM data and read +and/or write or process the in-band OAM data are called +**"in-band OAM transit nodes"**. + +## Features supported in the current release +VPP can function as in-band OAM encapsulating, transit and decapsulating node. +In this version of VPP in-band OAM data is transported as options in an +IPv6 hop-by-hop extension header. Hence in-band OAM can be enabled +for IPv6 traffic. + +The following iOAM features are supported: + +- **In-band OAM Tracing** : In-band OAM supports multiple data records to be +recorded in the packet as the packet traverses the network. +These data records offer insights into the operational behavior of the network. +The following information can be collected in the tracing +data from the nodes a packet traverses: + - Node ID + - Ingress interface ID + - Egress interface ID + - Timestamp + - Pre-configured application data + +- **In-band OAM Proof of Transit (POT)**: Proof of transit iOAM data is +added to every packet for verifying that a packet traverses a specific +set of nodes. +In-band OAM data is updated at every node that is enabled with iOAM +proof of transit and is used to verify whether a packet traversed +all the specified nodes. When the verifier receives each packet, +it can validate whether the packet traversed the specified nodes. + + +## Configuration +Configuring iOAM involves: +- Selecting the packets for which iOAM data must be inserted, updated or removed + - Selection of packets for iOAM data insertion on iOAM encapsulating node. + Selection of packets is done by 5-tuple based classification + - Selection of packets for updating iOAM data is implicitly done on the + presence of iOAM options in the packet + - Selection of packets for removing the iOAM data is done on 5-tuple + based classification +- The kind of data to be collected + - Tracing data + - Proof of transit +- Additional details for processing iOAM data to be collected + - For trace data - trace type, number of nodes to be recorded in the trace, + time stamp precision, etc. + - For POT data - configuration of POT profile required to process the POT data + +The CLI for configuring iOAM is explained here followed by detailed steps +and examples to deploy iOAM on VPP as an encapsulating, transit or +decapsulating iOAM node in the subsequent sub-sections. + +VPP iOAM configuration for enabling trace and POT is as follows: + + set ioam rewrite trace-type <0x1f|0x7|0x9|0x11|0x19> + trace-elts trace-tsp <0|1|2|3> + node-id app-data [pot] + +A description of each of the options of the CLI follows: +- trace-type : An entry in the "Node data List" array of the trace option +can have different formats, following the needs of the a deployment. +For example: Some deployments might only be interested +in recording the node identifiers, whereas others might be interested +in recording node identifier and timestamp. +The following types are currently supported: + - 0x1f : Node data to include hop limit (8 bits), node ID (24 bits), + ingress and egress interface IDs (16 bits each), timestamp (32 bits), + application data (32 bits) + - 0x7 : Node data to include hop limit (8 bits), node ID (24 bits), + ingress and egress interface IDs (16 bits each) + - 0x9 : Node data to include hop limit (8 bits), node ID (24 bits), + timestamp (32 bits) + - 0x11: Node data to include hop limit (8 bits), node ID (24 bits), + application data (32 bits) + - 0x19: Node data to include hop limit (8 bits), node ID (24 bits), + timestamp (32 bits), application data (32 bits) +- trace-elts : Defines the length of the node data array in the trace option. +- trace-tsp : Defines the timestamp precision to use with the enumerated value + for precision as follows: + - 0 : 32bits timestamp in seconds + - 1 : 32bits timestamp in milliseconds + - 2 : 32bits timestamp in microseconds + - 3 : 32bits timestamp in nanoseconds +- node-id : Unique identifier for the node, included in the node ID + field of the node data in trace option. +- app-data : The value configured here is included as is in +application data field of node data in trace option. +- pot : Enables POT option to be included in the iOAM options. + +### Trace configuration + +#### On in-band OAM encapsulating node + - **Configure classifier and apply ACL** to select packets for + iOAM data insertion + - Example to enable iOAM data insertion for all the packets + towards IPv6 address db06::06: + + vpp# classify table miss-next node ip6-lookup mask l3 ip6 dst + + vpp# classify session acl-hit-next node ip6-add-hop-by-hop + table-index 0 match l3 ip6 dst db06::06 + + vpp# set int input acl intfc GigabitEthernet0/0/0 ip6-table 0 + + - **Enable tracing** : Specify node ID, maximum number of nodes for which + trace data should be recorded, type of data to be included for recording, + optionally application data to be included + - Example to enable tracing with a maximum of 4 nodes recorded + and the data to be recorded to include - hop limit, node id, + ingress and egress interface IDs, timestamp (millisecond precision), + application data (0x1234): + + + vpp# set ioam rewrite trace-type 0x1f trace-elts 4 trace-tsp 1 + node-id 0x1 app-data 0x1234 + + + +#### On in-band OAM transit node +- The transit node requires trace type, timestamp precision, node ID and +optionally application data to be configured, +to update its node data in the trace option. + +Example: + + vpp# set ioam rewrite trace-type 0x1f trace-elts 4 trace-tsp 1 + node-id 0x2 app-data 0x1234 + +#### On the In-band OAM decapsulating node +- The decapsulating node similar to encapsulating node requires +**classification** of the packets to remove iOAM data from. + - Example to decapsulate iOAM data for packets towards + db06::06, configure classifier and enable it as an ACL as follows: + + + vpp# classify table miss-next node ip6-lookup mask l3 ip6 dst + + vpp# classify session acl-hit-next node ip6-lookup table-index 0 + match l3 ip6 dst db06::06 opaque-index 100 + + vpp# set int input acl intfc GigabitEthernet0/0/0 ip6-table 0 + + +- Decapsulating node requires trace type, timestamp precision, +node ID and optionally application data to be configured, +to update its node data in the trace option before it is decapsulated. + +Example: + + vpp# set ioam rewrite trace-type 0x1f trace-elts 4 + trace-tsp 1 node-id 0x3 app-data 0x1234 + + +### Proof of Transit configuration + +For details on proof-of-transit, +see the IETF draft [iOAM-ietf-proof-of-transit]. +To enable Proof of Transit all the nodes that participate +and hence are verified for transit need a proof of transit profile. +A script to generate a proof of transit profile as per the mechanism +described in [iOAM-ietf-proof-of-transit] will be available at [iOAM-Devnet]. + +The Proof of transit mechanism implemented here is based on +Shamir's Secret Sharing algorithm. +The overall algorithm uses two polynomials +POLY-1 and POLY-2. The degree of polynomials depends on number of nodes +to be verified for transit. +POLY-1 is secret and constant. Each node gets a point on POLY-1 +at setup-time and keeps it secret. +POLY-2 is public, random and per packet. +Each node is assigned a point on POLY-1 and POLY-2 with the same x index. +Each node derives its point on POLY-2 each time a packet arrives at it. +A node then contributes its points on POLY-1 and POLY-2 to construct +POLY-3 (POLY-3 = POLY-1 + POLY-2) using lagrange extrapolation and +forwards it towards the verifier by updating POT data in the packet. +The verifier constructs POLY-3 from the accumulated value from all the nodes +and its own points on POLY-1 and POLY-2 and verifies whether +POLY-3 = POLY-1 + POLY-2. Only the verifier knows POLY-1. +The solution leverages finite field arithmetic in a field of size "prime number" +for reasons explained in description of Shamir's secret sharing algorithm. + +Here is an explanation of POT profile list and profile configuration CLI to +realize the above mechanism. +It is best to use the script provided at [iOAM-Devnet] to generate +this configuration. +- **Create POT profile** : set pot profile name id [0-1] +[validator-key 0xu64] prime-number 0xu64 secret_share 0xu64 +lpc 0xu64 polynomial2 0xu64 bits-in-random [0-64] + - name : Profile list name. + - id : Profile id, it can be 0 or 1. + A maximum of two profiles can be configured per profile list. + - validator-key : Secret key configured only on the + verifier/decapsulating node used to compare and verify proof of transit. + - prime-number : Prime number for finite field arithmetic as required by the + proof of transit mechanism. + - secret_share : Unique point for each node on the secret polynomial POLY-1. + - lpc : Lagrange Polynomial Constant(LPC) calculated per node based on + its point (x value used for evaluating the points on the polynomial) + on the polynomial used in lagrange extrapolation + for reconstructing polynomial (POLY-3). + - polynomial2 : Is the pre-evaluated value of the point on + 2nd polynomial(POLY-2). This is unique for each node. + It is pre-evaluated for all the coefficients of POLY-2 except + for the constant part of the polynomial that changes per packet + and is received as part of the POT data in the packet. + - bits-in-random : To control the size of the random number to be + generated. This number has to match the other numbers generated and used + in the profile as per the algorithm. + +- **Set a configured profile as active/in-use** : +set pot profile-active name ID [0-1] + - name : Name of the profile list to be used for computing + POT data per packet. + - ID : Identifier of the profile within the list to be used. + +#### On In-band OAM encapsulating node + - Configure the classifier and apply ACL to select packets for iOAM data insertion. + - Example to enable iOAM data insertion for all the packet towards + IPv6 address db06::06 - + + + vpp# classify table miss-next node ip6-lookup mask l3 ip6 dst + + vpp# classify session acl-hit-next node + ip6-add-hop-by-hop table-index 0 match l3 ip6 dst db06::06 + + vpp# set int input acl intfc GigabitEthernet0/0/0 ip6-table 0 + + + - Configure the proof of transit profile list with profiles. +Each profile list referred to by a name can contain 2 profiles, +only one is in use for updating proof of transit data at any time. + - Example profile list example with a profile generated from the + script to verify transit through 3 nodes is: + + + vpp# set pot profile name example id 0 prime-number 0x7fff0000fa884685 + secret_share 0x6c22eff0f45ec56d lpc 0x7fff0000fa884682 + polynomial2 0xffb543d4a9c bits-in-random 63 + + - Enable one of the profiles from the configured profile list as active + so that is will be used for calculating proof of transit + +Example enable profile ID 0 from profile list example configured above: + + + vpp# set pot profile-active name example ID 0 + + + - Enable POT option to be inserted + + + vpp# set ioam rewrite pot + + +#### On in-band OAM transit node + - Configure the proof of transit profile list with profiles for transit node. +Example: + + + vpp# set pot profile name example id 0 prime-number 0x7fff0000fa884685 + secret_share 0x564cdbdec4eb625d lpc 0x1 + polynomial2 0x23f3a227186a bits-in-random 63 + +#### On in-band OAM decapsulating node / verifier +- The decapsulating node, similar to the encapsulating node requires +classification of the packets to remove iOAM data from. + - Example to decapsulate iOAM data for packets towards db06::06 + configure classifier and enable it as an ACL as follows: + + + vpp# classify table miss-next node ip6-lookup mask l3 ip6 dst + + vpp# classify session acl-hit-next node ip6-lookup table-index 0 + match l3 ip6 dst db06::06 opaque-index 100 + + vpp# set int input acl intfc GigabitEthernet0/0/0 ip6-table 0 + +- To update and verify the proof of transit, POT profile list should be configured. + - Example POT profile list configured as follows: + + vpp# set pot profile name example id 0 validate-key 0x7fff0000fa88465d + prime-number 0x7fff0000fa884685 secret_share 0x7a08fbfc5b93116d lpc 0x3 + polynomial2 0x3ff738597ce bits-in-random 63 + +## Operational data + +Following CLIs are available to check iOAM operation: +- To check iOAM configuration that are effective use "show ioam summary" + +Example: + + vpp# show ioam summary + REWRITE FLOW CONFIGS - Not configured + HOP BY HOP OPTIONS - TRACE CONFIG - + Trace Type : 0x1f (31) + Trace timestamp precision : 1 (Milliseconds) + Num of trace nodes : 4 + Node-id : 0x2 (2) + App Data : 0x1234 (4660) + POT OPTION - 1 (Enabled) + Try 'show ioam pot and show pot profile' for more information + +- To find statistics about packets for which iOAM options were +added (encapsulating node) and removed (decapsulating node) execute +*show errors* + +Example on encapsulating node: + + + vpp# show error + Count Node Reason + 1208804706 ip6-inacl input ACL hits + 1208804706 ip6-add-hop-by-hop Pkts w/ added ip6 hop-by-hop options + +Example on decapsulating node: + + vpp# show error + Count Node Reason + 69508569 ip6-inacl input ACL hits + 69508569 ip6-pop-hop-by-hop Pkts w/ removed ip6 hop-by-hop options + +- To check the POT profiles use "show pot profile" + +Example: + + vpp# show pot profile + Profile list in use : example + POT Profile at index: 0 + ID : 0 + Validator : False (0) + Secret share : 0x564cdbdec4eb625d (6218586935324795485) + Prime number : 0x7fff0000fa884685 (9223090566081300101) + 2nd polynomial(eval) : 0x23f3a227186a (39529304496234) + LPC : 0x1 (1) + Bit mask : 0x7fffffffffffffff (9223372036854775807) + Profile index in use: 0 + Pkts passed : 0x36 (54) + +- To get statistics of POT for packets use "show ioam pot" + +Example at encapsulating or transit node: + + vpp# show ioam pot + Pkts with ip6 hop-by-hop POT options - 54 + Pkts with ip6 hop-by-hop POT options but no profile set - 0 + Pkts with POT in Policy - 0 + Pkts with POT out of Policy - 0 + + +Example at decapsulating/verification node: + + + vpp# show ioam pot + Pkts with ip6 hop-by-hop POT options - 54 + Pkts with ip6 hop-by-hop POT options but no profile set - 0 + Pkts with POT in Policy - 54 + Pkts with POT out of Policy - 0 + +- Tracing - enable trace of IPv6 packets to view the data inserted and +collected. + +Example when the nodes are receiving data over a DPDK interface: +Enable tracing using "trace add dpdk-input 20" and +execute "show trace" to view the iOAM data collected: + + + vpp# trace add dpdk-input 20 + + vpp# show trace + + ------------------- Start of thread 0 vpp_main ------------------- + + Packet 1 + + 00:00:19:294697: dpdk-input + GigabitEthernetb/0/0 rx queue 0 + buffer 0x10e6b: current data 0, length 214, free-list 0, totlen-nifb 0, trace 0x0 + PKT MBUF: port 0, nb_segs 1, pkt_len 214 + buf_len 2176, data_len 214, ol_flags 0x0, data_off 128, phys_addr 0xe9a35a00 + packet_type 0x0 + IP6: 00:50:56:9c:df:72 -> 00:50:56:9c:be:55 + IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 + tos 0x00, flow label 0x0, hop limit 63, payload length 160 + 00:00:19:294737: ethernet-input + IP6: 00:50:56:9c:df:72 -> 00:50:56:9c:be:55 + 00:00:19:294753: ip6-input + IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 + tos 0x00, flow label 0x0, hop limit 63, payload length 160 + 00:00:19:294757: ip6-lookup + fib 0 adj-idx 15 : indirect via db05::2 flow hash: 0x00000000 + IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 + tos 0x00, flow label 0x0, hop limit 63, payload length 160 + 00:00:19:294802: ip6-hop-by-hop + IP6_HOP_BY_HOP: next index 5 len 96 traced 96 Trace Type 0x1f , 1 elts left + [0] ttl 0x0 node ID 0x0 ingress 0x0 egress 0x0 ts 0x0 + app 0x0 + [1] ttl 0x3e node ID 0x3 ingress 0x1 egress 0x2 ts 0xb68c2213 + app 0x1234 + [2] ttl 0x3f node ID 0x2 ingress 0x1 egress 0x2 ts 0xb68c2204 + app 0x1234 + [3] ttl 0x40 node ID 0x1 ingress 0x5 egress 0x6 ts 0xb68c2200 + app 0x1234 + POT opt present + random = 0x577a916946071950, Cumulative = 0x10b46e78a35a392d, Index = 0x0 + 00:00:19:294810: ip6-rewrite + tx_sw_if_index 1 adj-idx 14 : GigabitEthernetb/0/0 + IP6: 00:50:56:9c:be:55 -> 00:50:56:9c:df:72 flow hash: 0x00000000 + IP6: 00:50:56:9c:be:55 -> 00:50:56:9c:df:72 + IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 + tos 0x00, flow label 0x0, hop limit 62, payload length 160 + 00:00:19:294814: GigabitEthernetb/0/0-output + GigabitEthernetb/0/0 + IP6: 00:50:56:9c:be:55 -> 00:50:56:9c:df:72 + IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 + tos 0x00, flow label 0x0, hop limit 62, payload length 160 + 00:00:19:294820: GigabitEthernetb/0/0-tx + GigabitEthernetb/0/0 tx queue 0 + buffer 0x10e6b: current data 0, length 214, free-list 0, totlen-nifb 0, trace 0x0 + IP6: 00:50:56:9c:be:55 -> 00:50:56:9c:df:72 + + IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 + + tos 0x00, flow label 0x0, hop limit 62, payload length 160 + + +[iOAM-Devnet]: +[iOAM-ietf-requirements]: +[iOAM-ietf-transport]: +[iOAM-ietf-data]: +[iOAM-ietf-proof-of-transit]: diff --git a/plugins/lb-plugin/README.md b/plugins/lb-plugin/README.md deleted file mode 100644 index 4effe533..00000000 --- a/plugins/lb-plugin/README.md +++ /dev/null @@ -1,141 +0,0 @@ -# Load Balancer plugin for VPP - -## Version - -The load balancer plugin is currently in *beta* version. -Both CLIs and APIs are subject to *heavy* changes. -Wich also means feedback is really welcome regarding features, apis, etc... - -## Overview - -This plugin provides load balancing for VPP in a way that is largely inspired -from Google's MagLev: http://research.google.com/pubs/pub44824.html - -The load balancer is configured with a set of Virtual IPs (VIP, which can be -prefixes), and for each VIP, with a set of Application Server addresses (ASs). - -Traffic received for a given VIP (or VIP prefix) is tunneled using GRE towards -the different ASs in a way that (tries to) ensure that a given session will -always be tunneled to the same AS. - -Both VIPs or ASs can be IPv4 or IPv6, but for a given VIP, all ASs must be using -the same encap. type (i.e. IPv4+GRE or IPv6+GRE). Meaning that for a given VIP, -all AS addresses must be of the same family. - -## Performances - -The load balancer has been tested up to 1 millions flows and still forwards more -than 3Mpps per core in such circumstances. -Although 3Mpps seems already good, it is likely that performances will be improved -in next versions. - -## Configuration - -### Global LB parameters - -The load balancer needs to be configured with some parameters: - - lb conf [ip4-src-address ] [ip6-src-address ] - [buckets ] [timeout ] - -ip4-src-address: the source address used to send encap. packets using IPv4. - -ip6-src-address: the source address used to send encap. packets using IPv6. - -buckets: the *per-thread* established-connexions-table number of buckets. - -timeout: the number of seconds a connection will remain in the - established-connexions-table while no packet for this flow - is received. - - -### Configure the VIPs - - lb vip [encap (gre6|gre4)] [new_len ] [del] - -new_len is the size of the new-connection-table. It should be 1 or 2 orders of -magnitude bigger than the number of ASs for the VIP in order to ensure a good -load balancing. - -Examples: - - lb vip 2002::/16 encap gre6 new_len 1024 - lb vip 2003::/16 encap gre4 new_len 2048 - lb vip 80.0.0.0/8 encap gre6 new_len 16 - lb vip 90.0.0.0/8 encap gre4 new_len 1024 - -### Configure the ASs (for each VIP) - - lb as [
[
[...]]] [del] - -You can add (or delete) as many ASs at a time (for a single VIP). -Note that the AS address family must correspond to the VIP encap. IP family. - -Examples: - - lb as 2002::/16 2001::2 2001::3 2001::4 - lb as 2003::/16 10.0.0.1 10.0.0.2 - lb as 80.0.0.0/8 2001::2 - lb as 90.0.0.0/8 10.0.0.1 - - - -## Monitoring - -The plugin provides quite a bunch of counters and information. -These are still subject to quite significant changes. - - show lb - show lb vip - show lb vip verbose - - show node counters - - -## Design notes - -### Multi-Threading - -MagLev is a distributed system which pseudo-randomly generates a -new-connections-table based on AS names such that each server configured with -the same set of ASs ends up with the same table. Connection stickyness is then -ensured with an established-connections-table. Using ECMP, it is assumed (but -not relied on) that servers will mostly receive traffic for different flows. - -This implementation pushes the parallelism a little bit further by using -one established-connections table per thread. This is equivalent to assuming -that RSS will make a job similar to ECMP, and is pretty useful as threads don't -need to get a lock in order to write in the table. - -### Hash Table - -A load balancer requires an efficient read and write hash table. The hash table -used by ip6-forward is very read-efficient, but not so much for writing. In -addition, it is not a big deal if writing into the hash table fails (again, -MagLev uses a flow table but does not heaviliy relies on it). - -The plugin therefore uses a very specific (and stupid) hash table. - - Fixed (and power of 2) number of buckets (configured at runtime) - - Fixed (and power of 2) elements per buckets (configured at compilation time) - -### Reference counting - -When an AS is removed, there is two possible ways to react. - - Keep using the AS for established connections - - Change AS for established connections (likely to cause error for TCP) - -In the first case, although an AS is removed from the configuration, its -associated state needs to stay around as long as it is used by at least one -thread. - -In order to avoid locks, a specific reference counter is used. The design is quite -similar to clib counters but: - - It is possible to decrease the value - - Summing will not zero the per-thread counters - - Only the thread can reallocate its own counters vector (to avoid concurrency issues) - -This reference counter is lock free, but reading a count of 0 does not mean -the value can be freed unless it is ensured by *other* means that no other thread -is concurrently referencing the object. In the case of this plugin, it is assumed -that no concurrent event will take place after a few seconds. - diff --git a/plugins/lb-plugin/lb_plugin_doc.md b/plugins/lb-plugin/lb_plugin_doc.md new file mode 100644 index 00000000..c7885ffb --- /dev/null +++ b/plugins/lb-plugin/lb_plugin_doc.md @@ -0,0 +1,141 @@ +# Load Balancer plugin for VPP {#lb_plugin_doc} + +## Version + +The load balancer plugin is currently in *beta* version. +Both CLIs and APIs are subject to *heavy* changes. +Wich also means feedback is really welcome regarding features, apis, etc... + +## Overview + +This plugin provides load balancing for VPP in a way that is largely inspired +from Google's MagLev: http://research.google.com/pubs/pub44824.html + +The load balancer is configured with a set of Virtual IPs (VIP, which can be +prefixes), and for each VIP, with a set of Application Server addresses (ASs). + +Traffic received for a given VIP (or VIP prefix) is tunneled using GRE towards +the different ASs in a way that (tries to) ensure that a given session will +always be tunneled to the same AS. + +Both VIPs or ASs can be IPv4 or IPv6, but for a given VIP, all ASs must be using +the same encap. type (i.e. IPv4+GRE or IPv6+GRE). Meaning that for a given VIP, +all AS addresses must be of the same family. + +## Performances + +The load balancer has been tested up to 1 millions flows and still forwards more +than 3Mpps per core in such circumstances. +Although 3Mpps seems already good, it is likely that performances will be improved +in next versions. + +## Configuration + +### Global LB parameters + +The load balancer needs to be configured with some parameters: + + lb conf [ip4-src-address ] [ip6-src-address ] + [buckets ] [timeout ] + +ip4-src-address: the source address used to send encap. packets using IPv4. + +ip6-src-address: the source address used to send encap. packets using IPv6. + +buckets: the *per-thread* established-connexions-table number of buckets. + +timeout: the number of seconds a connection will remain in the + established-connexions-table while no packet for this flow + is received. + + +### Configure the VIPs + + lb vip [encap (gre6|gre4)] [new_len ] [del] + +new_len is the size of the new-connection-table. It should be 1 or 2 orders of +magnitude bigger than the number of ASs for the VIP in order to ensure a good +load balancing. + +Examples: + + lb vip 2002::/16 encap gre6 new_len 1024 + lb vip 2003::/16 encap gre4 new_len 2048 + lb vip 80.0.0.0/8 encap gre6 new_len 16 + lb vip 90.0.0.0/8 encap gre4 new_len 1024 + +### Configure the ASs (for each VIP) + + lb as [
[
[...]]] [del] + +You can add (or delete) as many ASs at a time (for a single VIP). +Note that the AS address family must correspond to the VIP encap. IP family. + +Examples: + + lb as 2002::/16 2001::2 2001::3 2001::4 + lb as 2003::/16 10.0.0.1 10.0.0.2 + lb as 80.0.0.0/8 2001::2 + lb as 90.0.0.0/8 10.0.0.1 + + + +## Monitoring + +The plugin provides quite a bunch of counters and information. +These are still subject to quite significant changes. + + show lb + show lb vip + show lb vip verbose + + show node counters + + +## Design notes + +### Multi-Threading + +MagLev is a distributed system which pseudo-randomly generates a +new-connections-table based on AS names such that each server configured with +the same set of ASs ends up with the same table. Connection stickyness is then +ensured with an established-connections-table. Using ECMP, it is assumed (but +not relied on) that servers will mostly receive traffic for different flows. + +This implementation pushes the parallelism a little bit further by using +one established-connections table per thread. This is equivalent to assuming +that RSS will make a job similar to ECMP, and is pretty useful as threads don't +need to get a lock in order to write in the table. + +### Hash Table + +A load balancer requires an efficient read and write hash table. The hash table +used by ip6-forward is very read-efficient, but not so much for writing. In +addition, it is not a big deal if writing into the hash table fails (again, +MagLev uses a flow table but does not heaviliy relies on it). + +The plugin therefore uses a very specific (and stupid) hash table. + - Fixed (and power of 2) number of buckets (configured at runtime) + - Fixed (and power of 2) elements per buckets (configured at compilation time) + +### Reference counting + +When an AS is removed, there is two possible ways to react. + - Keep using the AS for established connections + - Change AS for established connections (likely to cause error for TCP) + +In the first case, although an AS is removed from the configuration, its +associated state needs to stay around as long as it is used by at least one +thread. + +In order to avoid locks, a specific reference counter is used. The design is quite +similar to clib counters but: + - It is possible to decrease the value + - Summing will not zero the per-thread counters + - Only the thread can reallocate its own counters vector (to avoid concurrency issues) + +This reference counter is lock free, but reading a count of 0 does not mean +the value can be freed unless it is ensured by *other* means that no other thread +is concurrently referencing the object. In the case of this plugin, it is assumed +that no concurrent event will take place after a few seconds. + diff --git a/vnet/vnet/ipsec-gre/ipsec_gre_doc.md b/vnet/vnet/ipsec-gre/ipsec_gre_doc.md index e9e5fdd9..e1bb9cda 100644 --- a/vnet/vnet/ipsec-gre/ipsec_gre_doc.md +++ b/vnet/vnet/ipsec-gre/ipsec_gre_doc.md @@ -1,4 +1,4 @@ -# VPP L2-GRE over IPsec implementation +# VPP L2-GRE over IPsec implementation {#ipsec_gre_doc} This is a memo intended to contain documentation of the VPP L2-GRE over IPsec implementation. Everything that is not directly obvious should come here. diff --git a/vnet/vnet/lldp/lldp.md b/vnet/vnet/lldp/lldp.md deleted file mode 100644 index 55de8f06..00000000 --- a/vnet/vnet/lldp/lldp.md +++ /dev/null @@ -1,84 +0,0 @@ -# VPP Link Layer Discovery Protocol (LLDP) implementation - -This is a memo intended to contain documentation of the VPP LLDP implementation -Everything that is not directly obvious should come here. - - -## LLDP -LLDP is a link layer protocol to advertise the capabilities and current status of the system. - -There are 2 nodes handling LLDP - -1.) input-node which processes incoming packets and updates the local database -2.) process-node which is responsible for sending out LLDP packets from VPP side - - -### Configuration - -LLDP has a global configuration and a per-interface enable setting. - -Global configuration is modified using the "set lldp" command - -set lldp [system-name ] [tx-hold ] [tx-interval ] - -system-name: the name of the VPP system sent to peers in the system-name TLV -tx-hold: multiplier for tx-interval when setting time-to-live (TTL) value in the LLDP packets (TTL = tx-hold * tx-interval + 1, if TTL > 65535, then TTL = 65535) -tx-interval: time interval between sending out LLDP packets - -Per interface setting is done using the "set interface lldp" command - -set interface lldp (enable | disable) - -interface: the name of the interface for which to enable/disable LLDP - - -### Configuration example - -Configure system-name as "VPP" and transmit interval to 10 seconds: - -set lldp system-name VPP tx-interval 10 - -Enable LLDP on interface TenGigabitEthernet5/0/1 - -set interface lldp TenGigabitEthernet5/0/1 enable - - -### Operational data - -The list of LLDP-enabled interfaces which are up can be shown using "show lldp" command - -Example: -DBGvpp# show lldp -Local interface Peer chassis ID Remote port ID Last heard Last sent Status -GigabitEthernet2/0/1 never 27.0s ago inactive -TenGigabitEthernet5/0/1 8c:60:4f:dd:ca:52 Eth1/3/3 20.1s ago 18.3s ago active - -All LLDP configuration data with all LLDP-enabled interfaces can be shown using "show lldp detail" command - -Example: -DBGvpp# show lldp detail -LLDP configuration: -Configured system name: vpp -Configured tx-hold: 4 -Configured tx-interval: 30 - -LLDP-enabled interface table: - -Interface name: GigabitEthernet2/0/1 -Interface/peer state: inactive(timeout) -Last known peer chassis ID: -Last known peer port ID: -Last packet sent: 12.4s ago -Last packet received: never - -Interface name: GigabitEthernet2/0/2 -Interface/peer state: interface down -Last packet sent: never - -Interface name: TenGigabitEthernet5/0/1 -Interface/peer state: active -Peer chassis ID: 8c:60:4f:dd:ca:52(MAC address) -Remote port ID: Eth1/3/3(Locally assigned) -Last packet sent: 3.6s ago -Last packet received: 5.5s ago - diff --git a/vnet/vnet/lldp/lldp_doc.md b/vnet/vnet/lldp/lldp_doc.md new file mode 100644 index 00000000..bac480a5 --- /dev/null +++ b/vnet/vnet/lldp/lldp_doc.md @@ -0,0 +1,84 @@ +# VPP Link Layer Discovery Protocol (LLDP) implementation {#lldp_doc} + +This is a memo intended to contain documentation of the VPP LLDP implementation +Everything that is not directly obvious should come here. + + +## LLDP +LLDP is a link layer protocol to advertise the capabilities and current status of the system. + +There are 2 nodes handling LLDP + +1.) input-node which processes incoming packets and updates the local database +2.) process-node which is responsible for sending out LLDP packets from VPP side + + +### Configuration + +LLDP has a global configuration and a per-interface enable setting. + +Global configuration is modified using the "set lldp" command + +set lldp [system-name ] [tx-hold ] [tx-interval ] + +system-name: the name of the VPP system sent to peers in the system-name TLV +tx-hold: multiplier for tx-interval when setting time-to-live (TTL) value in the LLDP packets (TTL = tx-hold * tx-interval + 1, if TTL > 65535, then TTL = 65535) +tx-interval: time interval between sending out LLDP packets + +Per interface setting is done using the "set interface lldp" command + +set interface lldp (enable | disable) + +interface: the name of the interface for which to enable/disable LLDP + + +### Configuration example + +Configure system-name as "VPP" and transmit interval to 10 seconds: + +set lldp system-name VPP tx-interval 10 + +Enable LLDP on interface TenGigabitEthernet5/0/1 + +set interface lldp TenGigabitEthernet5/0/1 enable + + +### Operational data + +The list of LLDP-enabled interfaces which are up can be shown using "show lldp" command + +Example: +DBGvpp# show lldp +Local interface Peer chassis ID Remote port ID Last heard Last sent Status +GigabitEthernet2/0/1 never 27.0s ago inactive +TenGigabitEthernet5/0/1 8c:60:4f:dd:ca:52 Eth1/3/3 20.1s ago 18.3s ago active + +All LLDP configuration data with all LLDP-enabled interfaces can be shown using "show lldp detail" command + +Example: +DBGvpp# show lldp detail +LLDP configuration: +Configured system name: vpp +Configured tx-hold: 4 +Configured tx-interval: 30 + +LLDP-enabled interface table: + +Interface name: GigabitEthernet2/0/1 +Interface/peer state: inactive(timeout) +Last known peer chassis ID: +Last known peer port ID: +Last packet sent: 12.4s ago +Last packet received: never + +Interface name: GigabitEthernet2/0/2 +Interface/peer state: interface down +Last packet sent: never + +Interface name: TenGigabitEthernet5/0/1 +Interface/peer state: active +Peer chassis ID: 8c:60:4f:dd:ca:52(MAC address) +Remote port ID: Eth1/3/3(Locally assigned) +Last packet sent: 3.6s ago +Last packet received: 5.5s ago + diff --git a/vnet/vnet/map/map_doc.md b/vnet/vnet/map/map_doc.md index 230c52df..17f3c511 100644 --- a/vnet/vnet/map/map_doc.md +++ b/vnet/vnet/map/map_doc.md @@ -1,4 +1,4 @@ -# VPP MAP and Lw4o6 implementation +# VPP MAP and Lw4o6 implementation {#map_doc} This is a memo intended to contain documentation of the VPP MAP and Lw4o6 implementations. Everything that is not directly obvious should come here. -- cgit 1.2.3-korg From 90f52bf990791ea73479ffc50fc1eb3450de443a Mon Sep 17 00:00:00 2001 From: Chris Luke Date: Mon, 12 Sep 2016 08:55:13 -0400 Subject: Refactor pre-Doxy siphon scripts; VPP-396 - Modularize the code to make the Siphon process easier to maintain. - Move much of the output rendering into Jinja2 templates. - Add syscfg siphon type for startup config documentation. - Add sample syscfg documentation. - Add clicfg and syscfg preamble docs, adapted from their wiki pages. - Fix sorting of CLI items across multiple directories. Change-Id: Ib8288fe005adfea68ceed75a38ff8eba25d3cc79 Signed-off-by: Chris Luke --- doxygen/Makefile | 48 +++- doxygen/dir.dox.sample | 1 + doxygen/doxygen.cfg | 3 + doxygen/siphon-generate | 74 +++++ doxygen/siphon-process | 67 +++++ doxygen/siphon/__init__.py | 24 ++ doxygen/siphon/generate.py | 304 ++++++++++++++++++++ doxygen/siphon/generate_clicmd.py | 22 ++ doxygen/siphon/generate_syscfg.py | 22 ++ doxygen/siphon/parsers.py | 149 ++++++++++ doxygen/siphon/process.py | 271 ++++++++++++++++++ doxygen/siphon/process_clicmd.py | 56 ++++ doxygen/siphon/process_syscfg.py | 30 ++ doxygen/siphon_generate.py | 322 --------------------- doxygen/siphon_process.py | 323 ---------------------- doxygen/siphon_templates/clicmd/index_entry.md | 17 ++ doxygen/siphon_templates/clicmd/index_header.md | 130 +++++++++ doxygen/siphon_templates/clicmd/item_format.md | 59 ++++ doxygen/siphon_templates/default/index_entry.md | 16 ++ doxygen/siphon_templates/default/index_section.md | 18 ++ doxygen/siphon_templates/default/item_format.md | 16 ++ doxygen/siphon_templates/default/item_header.md | 18 ++ doxygen/siphon_templates/syscfg/index_header.md | 111 ++++++++ doxygen/siphon_templates/syscfg/item_format.md | 42 +++ vlib/vlib/unix/cj.c | 35 ++- vlib/vlib/unix/cli.c | 6 +- vlib/vlib/unix/dir.dox | 3 +- vlib/vlib/unix/main.c | 53 ++++ 28 files changed, 1580 insertions(+), 660 deletions(-) create mode 100755 doxygen/siphon-generate create mode 100755 doxygen/siphon-process create mode 100644 doxygen/siphon/__init__.py create mode 100644 doxygen/siphon/generate.py create mode 100644 doxygen/siphon/generate_clicmd.py create mode 100644 doxygen/siphon/generate_syscfg.py create mode 100644 doxygen/siphon/parsers.py create mode 100644 doxygen/siphon/process.py create mode 100644 doxygen/siphon/process_clicmd.py create mode 100644 doxygen/siphon/process_syscfg.py delete mode 100755 doxygen/siphon_generate.py delete mode 100755 doxygen/siphon_process.py create mode 100644 doxygen/siphon_templates/clicmd/index_entry.md create mode 100644 doxygen/siphon_templates/clicmd/index_header.md create mode 100644 doxygen/siphon_templates/clicmd/item_format.md create mode 100644 doxygen/siphon_templates/default/index_entry.md create mode 100644 doxygen/siphon_templates/default/index_section.md create mode 100644 doxygen/siphon_templates/default/item_format.md create mode 100644 doxygen/siphon_templates/default/item_header.md create mode 100644 doxygen/siphon_templates/syscfg/index_header.md create mode 100644 doxygen/siphon_templates/syscfg/item_format.md (limited to 'doxygen/Makefile') diff --git a/doxygen/Makefile b/doxygen/Makefile index 0a69c2df..97225f3c 100644 --- a/doxygen/Makefile +++ b/doxygen/Makefile @@ -16,14 +16,18 @@ # Build the documentation # +# Default target +.PHONY: all +all: doxygen + # These should be passed in by the root Makefile WS_ROOT ?= $(CURDIR)/.. BR ?= $(WS_ROOT)/build-root OS_ID ?= $(shell grep '^ID=' /etc/os-release | cut -f2- -d= | sed -e 's/\"//g') # Package dependencies -DOC_DEB_DEPENDS = doxygen graphviz python-pyparsing -DOC_RPM_DEPENDS = doxygen graphviz pyparsing +DOC_DEB_DEPENDS = doxygen graphviz python-pyparsing python-jinja2 +DOC_RPM_DEPENDS = doxygen graphviz pyparsing python-jinja2 # Doxygen configuration and our utility scripts DOXY_DIR ?= $(WS_ROOT)/doxygen @@ -104,19 +108,22 @@ SIPHON_OUTPUT ?= $(DOXY_OUTPUT)/siphon_docs EXTRA_DOXY_INPUT += $(SIPHON_OUTPUT) # All the siphon types we know about -SIPHONS ?= clicmd +SIPHONS ?= clicmd syscfg SIPHON_FILES = $(addprefix $(SIPHON_INPUT)/,$(addsuffix .siphon,$(SIPHONS))) SIPHON_DOCS = $(addprefix $(SIPHON_OUTPUT)/,$(addsuffix .md,$(SIPHONS))) -$(BR)/.doxygen-bootstrap.ok: +$(BR)/.doxygen-bootstrap.ok: Makefile @echo "Checking whether dependencies for Doxygen are installed..." ifeq ($(OS_ID),ubuntu) @set -e; inst=; \ for i in $(DOC_DEB_DEPENDS); do \ dpkg-query --show $$i >/dev/null 2>&1 || inst="$$inst $$i"; \ done; \ - if [ "$$inst" ]; then sudo apt-get $(CONFIRM) $(FORCE) install $$inst; fi + if [ "$$inst" ]; then \ + sudo apt-get update; \ + sudo apt-get $(CONFIRM) $(FORCE) install $$inst; \ + fi @if [ ! -s /usr/lib/graphviz/config6a ]; then \ echo "Rebuidlding system Graphviz configuration."; \ sudo dot -c; \ @@ -145,8 +152,12 @@ $(BR)/.doxygen-siphon.dep: Makefile # Include the source -> siphon dependencies -include $(BR)/.doxygen-siphon.dep +# Generate .siphon files that contain fragments of source file that +# relate to the siphons we support. .NOTPARALLEL: $(SIPHON_FILES) -$(SIPHON_FILES): $(DOXY_DIR)/siphon_generate.py $(BR)/.doxygen-bootstrap.ok +$(SIPHON_FILES): $(BR)/.doxygen-bootstrap.ok \ + $(DOXY_DIR)/siphon-generate \ + $(wildcard $(DOXY_DIR)/siphon/*.py) @rm -rf "$(SIPHON_INPUT)" "$(SIPHON_OUTPUT)" @mkdir -p "$(SIPHON_INPUT)" "$(SIPHON_OUTPUT)" @touch $(SIPHON_INPUT)/files @@ -159,23 +170,33 @@ $(SIPHON_FILES): $(DOXY_DIR)/siphon_generate.py $(BR)/.doxygen-bootstrap.ok >> $(SIPHON_INPUT)/files; \ done @echo "Generating siphons..." - @set -e; cd "$(WS_ROOT)"; $(DOXY_DIR)/siphon_generate.py \ + @set -e; \ + cd "$(WS_ROOT)"; \ + $(DOXY_DIR)/siphon-generate \ --output="$(SIPHON_INPUT)" \ "@$(SIPHON_INPUT)/files" - +# Process the .siphon source fragments and render them into doxygen flavored +# markdown documentation .DELETE_ON_ERROR: $(SIPHON_DOCS) -$(SIPHON_OUTPUT)/%.md: $(SIPHON_INPUT)/%.siphon $(DOXY_DIR)/siphon_process.py +$(SIPHON_OUTPUT)/%.md: $(SIPHON_INPUT)/%.siphon \ + $(DOXY_DIR)/siphon-process \ + $(wildcard $(DOXY_DIR)/siphon/*.py) \ + $(wildcard $(DOXY_DIR)/siphon_templates/*/*.md) @echo "Processing siphon from $(notdir $<)..." - @set -e; cd "$(WS_ROOT)"; \ - $(DOXY_DIR)/siphon_process.py --type=$(basename $(notdir $<)) \ - --output="$(SIPHON_OUTPUT)" $< > $@ + @set -e; \ + cd "$(WS_ROOT)"; \ + $(DOXY_DIR)/siphon-process \ + --type=$(basename $(notdir $<)) \ + --output="$@" \ + "$<" # This target can be used just to generate the siphoned docs .PHONY: doxygen-siphon doxygen-siphon: $(SIPHON_DOCS) # Generate the doxygen docs +.PHONY: doxygen doxygen: $(SIPHON_DOCS) @mkdir -p "$(DOXY_OUTPUT)" @echo "Running Doxygen..." @@ -189,6 +210,9 @@ doxygen: $(SIPHON_DOCS) VERSION="`git describe --tags --dirty`" \ doxygen $(DOXY_DIR)/doxygen.cfg +.PHONY: wipe-doxygen wipe-doxygen: rm -rf "$(BR)/docs" "$(BR)/.doxygen-siphon.d" +.PHONY: clean +clean: wipe-doxygen diff --git a/doxygen/dir.dox.sample b/doxygen/dir.dox.sample index 500fe595..ccdd095a 100644 --- a/doxygen/dir.dox.sample +++ b/doxygen/dir.dox.sample @@ -27,3 +27,4 @@ This looks like a C file but it is not part of the build; it is purely for documentation. */ /*? %%clicmd:group_label CLI section description%% ?*/ +/*? %%syscfg:group_label Startup config section description%% ?*/ diff --git a/doxygen/doxygen.cfg b/doxygen/doxygen.cfg index 8844965b..7675b693 100644 --- a/doxygen/doxygen.cfg +++ b/doxygen/doxygen.cfg @@ -244,6 +244,9 @@ ALIASES += "cliexcmd{1}=@clistartvpp# \1@cliend" ALIASES += "cliexstart{1}=@cliexcmd{\1}@clistart" ALIASES += "cliexend=@cliend" +## Formatting for config directives +ALIASES += "cfgcmd{2}=@par
\1 \2
" +ALIASES += "cfgcmd{1}=@par
\1
" # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" diff --git a/doxygen/siphon-generate b/doxygen/siphon-generate new file mode 100755 index 00000000..bdfd58d8 --- /dev/null +++ b/doxygen/siphon-generate @@ -0,0 +1,74 @@ +#!/usr/bin/env python +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Looks for preprocessor macros with struct initializers and siphons them +# off into another file for later parsing; ostensibly to generate +# documentation from struct initializer data. + +import os, sys, argparse, logging +import siphon + +DEFAULT_LOGFILE = None +DEFAULT_LOGLEVEL = "info" +DEFAULT_OUTPUT = "build-root/docs/siphons" +DEFAULT_PREFIX = os.getcwd() + +ap = argparse.ArgumentParser() +ap.add_argument("--log-file", default=DEFAULT_LOGFILE, + help="Log file [%s]" % DEFAULT_LOGFILE) +ap.add_argument("--log-level", default=DEFAULT_LOGLEVEL, + choices=["debug", "info", "warning", "error", "critical"], + help="Logging level [%s]" % DEFAULT_LOGLEVEL) + +ap.add_argument("--output", '-o', metavar="directory", default=DEFAULT_OUTPUT, + help="Output directory for .siphon files [%s]" % DEFAULT_OUTPUT) +ap.add_argument("--input-prefix", metavar="path", default=DEFAULT_PREFIX, + help="Prefix to strip from input pathnames [%s]" % DEFAULT_PREFIX) +ap.add_argument("input", nargs='+', metavar="input_file", + help="Input C source files") +args = ap.parse_args() + +logging.basicConfig(filename=args.log_file, + level=getattr(logging, args.log_level.upper(), None)) +log = logging.getLogger("siphon_generate") + + +generate = siphon.generate.Generate(output_directory=args.output, + input_prefix=args.input_prefix) + +# Pre-process file names in case they indicate a file with +# a list of files +files = [] +for filename in args.input: + if filename.startswith('@'): + with open(filename[1:], 'r') as fp: + lines = fp.readlines() + for line in lines: + file = line.strip() + if file not in files: + files.append(file) + lines = None + else: + if filename not in files: + files.append(filename) + +# Iterate all the input files we've been given +for filename in files: + generate.parse(filename) + +# Write the extracted data +generate.deliver() + +# All done diff --git a/doxygen/siphon-process b/doxygen/siphon-process new file mode 100755 index 00000000..ea9df96f --- /dev/null +++ b/doxygen/siphon-process @@ -0,0 +1,67 @@ +#!/usr/bin/env python +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Filter for .siphon files that are generated by other filters. +# The idea is to siphon off certain initializers so that we can better +# auto-document the contents of that initializer. + +import os, sys, argparse, logging +import siphon + +DEFAULT_LOGFILE = None +DEFAULT_LOGLEVEL = "info" +DEFAULT_SIPHON ="clicmd" +DEFAULT_OUTPUT = None +DEFAULT_TEMPLATES = os.path.dirname(__file__) + "/siphon_templates" + +ap = argparse.ArgumentParser() +ap.add_argument("--log-file", default=DEFAULT_LOGFILE, + help="Log file [%s]" % DEFAULT_LOGFILE) +ap.add_argument("--log-level", default=DEFAULT_LOGLEVEL, + choices=["debug", "info", "warning", "error", "critical"], + help="Logging level [%s]" % DEFAULT_LOGLEVEL) + +ap.add_argument("--type", '-t', metavar="siphon_type", default=DEFAULT_SIPHON, + choices=siphon.process.siphons.keys(), + help="Siphon type to process [%s]" % DEFAULT_SIPHON) +ap.add_argument("--output", '-o', metavar="file", default=DEFAULT_OUTPUT, + help="Output file (uses stdout if not defined) [%s]" % DEFAULT_OUTPUT) +ap.add_argument("--templates", metavar="directory", default=DEFAULT_TEMPLATES, + help="Path to render templates directory [%s]" % DEFAULT_TEMPLATES) +ap.add_argument("input", nargs='+', metavar="input_file", + help="Input .siphon files") +args = ap.parse_args() + +logging.basicConfig(filename=args.log_file, + level=getattr(logging, args.log_level.upper(), None)) +log = logging.getLogger("siphon_process") + +# Determine where to send the generated output +if args.output is None: + out = sys.stdout +else: + out = open(args.output, "w+") + +# Get our processor +klass = siphon.process.siphons[args.type] +processor = klass(template_directory=args.templates) + +# Load the input files +processor.load_json(args.input) + +# Process the data +processor.process(out=out) + +# All done diff --git a/doxygen/siphon/__init__.py b/doxygen/siphon/__init__.py new file mode 100644 index 00000000..437a1df1 --- /dev/null +++ b/doxygen/siphon/__init__.py @@ -0,0 +1,24 @@ +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Siphon classes + +import generate +import generate_clicmd +import generate_syscfg + +import parsers +import process +import process_clicmd +import process_syscfg diff --git a/doxygen/siphon/generate.py b/doxygen/siphon/generate.py new file mode 100644 index 00000000..d6b6faf3 --- /dev/null +++ b/doxygen/siphon/generate.py @@ -0,0 +1,304 @@ +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Generate .siphon source fragments for later processing + +import logging +import os, sys, re, json + +"""List of (regexp, siphon_name) tuples for matching the start of C + initializer blocks in source files. Each siphon class registers + themselves on tihs list.""" +siphon_patterns = [] + +class Generate(object): + """Matches a siphon comment block start""" + siphon_block_start = re.compile("^\s*/\*\?\s*(.*)$") + + """Matches a siphon comment block stop""" + siphon_block_stop = re.compile("^(.*)\s*\?\*/\s*$") + + """Siphon block directive delimiter""" + siphon_block_delimiter = "%%" + + """Matches a siphon block directive such as + '%clicmd:group_label Debug CLI%'""" + siphon_block_directive = re.compile("(%s)\s*([a-zA-Z0-9_:]+)\s+(.*)\s*(%s)" % \ + (siphon_block_delimiter, siphon_block_delimiter)) + + """Matches the start of an initializer block""" + siphon_initializer = re.compile("\s*=") + + """Collated output for each siphon""" + output = None + + """Directory prefix to strip from input filenames to keep things tidy.""" + input_prefix = None + + """List of known siphons""" + known_siphons = None + + """Logging handler""" + log = None + + + def __init__(self, output_directory, input_prefix): + super(Generate, self).__init__() + self.log = logging.getLogger("siphon.generate") + + # Build a list of known siphons + self.known_siphons = [] + for item in siphon_patterns: + siphon = item[1] + if siphon not in self.known_siphons: + self.known_siphons.append(siphon) + + # Setup information for siphons we know about + self.output = {} + for siphon in self.known_siphons: + self.output[siphon] = { + "file": "%s/%s.siphon" % (output_directory, siphon), + "global": {}, + "items": [], + } + + self.input_prefix = input_prefix + + + """ + count open and close braces in str + return (0, index) when braces were found and count becomes 0. + index indicates the position at which the last closing brace was + found. + return (-1, -1) if a closing brace is found before any opening one. + return (count, -1) if not all opening braces are closed, count is the + current depth + """ + def count_braces(self, str, count=0, found=False): + for index in range(0, len(str)): + if str[index] == '{': + count += 1; + found = True + elif str[index] == '}': + if count == 0: + # means we never found an open brace + return (-1, -1) + count -= 1; + + if count == 0 and found: + return (count, index) + + return (count, -1) + + def parse(self, filename): + # Strip the current directory off the start of the + # filename for brevity + if filename[0:len(self.input_prefix)] == self.input_prefix: + filename = filename[len(self.input_prefix):] + if filename[0] == "/": + filename = filename[1:] + + # Work out the abbreviated directory name + directory = os.path.dirname(filename) + if directory[0:2] == "./": + directory = directory[2:] + elif directory[0:len(self.input_prefix)] == self.input_prefix: + directory = directory[len(self.input_prefix):] + if directory[0] == "/": + directory = directory[1:] + + # Open the file and explore its contents... + self.log.info("Siphoning from %s." % filename) + directives = {} + with open(filename) as fd: + siphon = None + close_siphon = None + siphon_block = "" + in_block = False + line_num = 0 + siphon_line = 0 + + for line in fd: + line_num += 1 + str = line[:-1] # filter \n + + """See if there is a block directive and if so extract it""" + def process_block_directive(str, directives): + m = self.siphon_block_directive.search(str) + if m is not None: + k = m.group(2) + v = m.group(3).strip() + directives[k] = v + # Return only the parts we did not match + return str[0:m.start(1)] + str[m.end(4):] + + return str + + def process_block_prefix(str): + if str.startswith(" * "): + str = str[3:] + elif str == " *": + str = "" + return str + + if not in_block: + # See if the line contains the start of a siphon doc block + m = self.siphon_block_start.search(str) + if m is not None: + in_block = True + t = m.group(1) + + # Now check if the block closes on the same line + m = self.siphon_block_stop.search(t) + if m is not None: + t = m.group(1) + in_block = False + + # Check for directives + t = process_block_directive(t, directives) + + # Filter for normal comment prefixes + t = process_block_prefix(t) + + # Add what is left + siphon_block += t + + # Skip to next line + continue + + else: + # Check to see if we have an end block marker + m = self.siphon_block_stop.search(str) + if m is not None: + in_block = False + t = m.group(1) + else: + t = str + + # Check for directives + t = process_block_directive(t, directives) + + # Filter for normal comment prefixes + t = process_block_prefix(t) + + # Add what is left + siphon_block += t + "\n" + + # Skip to next line + continue + + + if siphon is None: + # Look for blocks we need to siphon + for p in siphon_patterns: + if p[0].match(str): + siphon = [ p[1], str + "\n", 0 ] + siphon_line = line_num + + # see if we have an initializer + m = self.siphon_initializer.search(str) + if m is not None: + # count the braces on this line + (count, index) = \ + self.count_braces(str[m.start():]) + siphon[2] = count + # TODO - it's possible we have the + # initializer all on the first line + # we should check for it, but also + # account for the possibility that + # the open brace is on the next line + #if count == 0: + # # braces balanced + # close_siphon = siphon + # siphon = None + else: + # no initializer: close the siphon right now + close_siphon = siphon + siphon = None + else: + # See if we should end the siphon here - do we have + # balanced braces? + (count, index) = self.count_braces(str, + count=siphon[2], found=True) + if count == 0: + # braces balanced - add the substring and + # close the siphon + siphon[1] += str[:index+1] + ";\n" + close_siphon = siphon + siphon = None + else: + # add the whole string, move on + siphon[2] = count + siphon[1] += str + "\n" + + if close_siphon is not None: + # Write the siphoned contents to the right place + siphon_name = close_siphon[0] + + # Copy directives for the file + details = {} + for key in directives: + if ":" in key: + (sn, label) = key.split(":") + if sn == siphon_name: + details[label] = directives[key] + else: + details[key] = directives[key] + + # Copy details for this block + details['file'] = filename + details['directory'] = directory + details['line_start'] = siphon_line + details['line_end'] = line_num + details['siphon_block'] = siphon_block.strip() + details["block"] = close_siphon[1] + + # Store the item + self.output[siphon_name]['items'].append(details) + + # All done + close_siphon = None + siphon_block = "" + + # Update globals + for key in directives.keys(): + if ':' not in key: + continue + + if filename.endswith("/dir.dox"): + # very special! use the parent directory name + l = directory + else: + l = filename + + (sn, label) = key.split(":") + + if sn not in self.output: + self.output[sn] = {} + if 'global' not in self.output[sn]: + self.output[sn]['global'] = {} + if l not in self.output[sn]['global']: + self.output[sn]['global'][l] = {} + + self.output[sn]['global'][l][label] = directives[key] + + def deliver(self): + # Write out the data + for siphon in self.output.keys(): + self.log.info("Saving siphon data %s." % siphon) + s = self.output[siphon] + with open(s['file'], "a") as fp: + json.dump(s, fp, + separators=(',', ': '), indent=4, sort_keys=True) + diff --git a/doxygen/siphon/generate_clicmd.py b/doxygen/siphon/generate_clicmd.py new file mode 100644 index 00000000..7b131110 --- /dev/null +++ b/doxygen/siphon/generate_clicmd.py @@ -0,0 +1,22 @@ +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import generate, re + +# Register our regexp +generate.siphon_patterns.append(( + re.compile("(?PVLIB_CLI_COMMAND)\s*" + "[(](?P[a-zA-Z0-9_]+)(,[^)]*)?[)]"), + "clicmd" +)) diff --git a/doxygen/siphon/generate_syscfg.py b/doxygen/siphon/generate_syscfg.py new file mode 100644 index 00000000..c77936a9 --- /dev/null +++ b/doxygen/siphon/generate_syscfg.py @@ -0,0 +1,22 @@ +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import generate, re + +# Register our regexp +generate.siphon_patterns.append(( + re.compile("(?PVLIB_CONFIG_FUNCTION)\s*" + '[(](?P[a-zA-Z0-9_]+)\s*,\s*"(?P[^"]*)"[)]'), + "syscfg" +)) diff --git a/doxygen/siphon/parsers.py b/doxygen/siphon/parsers.py new file mode 100644 index 00000000..6fe8600d --- /dev/null +++ b/doxygen/siphon/parsers.py @@ -0,0 +1,149 @@ +# 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. + +import cgi, pyparsing as pp + +# Some useful primitives +ident = pp.Word(pp.alphas + "_", pp.alphas + pp.nums + "_") +intNum = pp.Word(pp.nums) +hexNum = pp.Literal("0x") + pp.Word(pp.hexnums) +octalNum = pp.Literal("0") + pp.Word("01234567") +integer = (hexNum | octalNum | intNum) + \ + pp.Optional(pp.Literal("ULL") | pp.Literal("LL") | pp.Literal("L")) +floatNum = pp.Regex(r'\d+(\.\d*)?([eE]\d+)?') + pp.Optional(pp.Literal("f")) +char = pp.Literal("'") + pp.Word(pp.printables, exact=1) + pp.Literal("'") +arrayIndex = integer | ident + +lbracket = pp.Literal("(").suppress() +rbracket = pp.Literal(")").suppress() +lbrace = pp.Literal("{").suppress() +rbrace = pp.Literal("}").suppress() +comma = pp.Literal(",").suppress() +equals = pp.Literal("=").suppress() +dot = pp.Literal(".").suppress() +semicolon = pp.Literal(";").suppress() + +# initializer := { [member = ] (variable | expression | { initializer } ) } +typeName = ident +varName = ident +typeSpec = pp.Optional("unsigned") + \ + pp.oneOf("int long short float double char u8 i8 void") + \ + pp.Optional(pp.Word("*"), default="") +typeCast = pp.Combine( "(" + ( typeSpec | typeName ) + ")" ).suppress() + +string = pp.Combine(pp.OneOrMore(pp.QuotedString(quoteChar='"', + escChar='\\', multiline=True)), adjacent=False) +literal = pp.Optional(typeCast) + (integer | floatNum | char | string) +var = pp.Combine(pp.Optional(typeCast) + varName + + pp.Optional("[" + arrayIndex + "]")) + +# This could be more complete, but suffices for our uses +expr = (literal | var) + +"""Parse and render a block of text into a Python dictionary.""" +class Parser(object): + """Compiled PyParsing BNF""" + _parser = None + + def __init__(self): + super(Parser, self).__init__() + self._parser = self.BNF() + + def BNF(self): + raise NotImplementedError + + def item(self, item): + raise NotImplementedError + + def parse(self, input): + item = self._parser.parseString(input).asList() + return self.item(item) + + +"""Parser for function-like macros - without the closing semi-colon.""" +class ParserFunctionMacro(Parser): + def BNF(self): + # VLIB_CONFIG_FUNCTION (unix_config, "unix") + macroName = ident + params = pp.Group(pp.ZeroOrMore(expr + comma) + expr) + macroParams = lbracket + params + rbracket + + return macroName + macroParams + + def item(self, item): + r = { + "macro": item[0], + "name": item[1][1], + "function": item[1][0], + } + + return r + + +"""Parser for function-like macros with a closing semi-colon.""" +class ParseFunctionMacroStmt(ParserFunctionMacro): + def BNF(self): + # VLIB_CONFIG_FUNCTION (unix_config, "unix"); + function_macro = super(ParseFunctionMacroStmt, self).BNF() + mi = function_macro + semicolon + mi.ignore(pp.cppStyleComment) + + return mi + + +""" +Parser for our struct initializers which are composed from a +function-like macro, equals sign, and then a normal C struct initalizer +block. +""" +class MacroInitializer(ParserFunctionMacro): + def BNF(self): + # VLIB_CLI_COMMAND (show_sr_tunnel_command, static) = { + # .path = "show sr tunnel", + # .short_help = "show sr tunnel [name ]", + # .function = show_sr_tunnel_fn, + # }; + cs = pp.Forward() + + + member = pp.Combine(dot + varName + pp.Optional("[" + arrayIndex + "]"), + adjacent=False) + value = (expr | cs) + + entry = pp.Group(pp.Optional(member + equals, default="") + value) + entries = (pp.ZeroOrMore(entry + comma) + entry + pp.Optional(comma)) | \ + (pp.ZeroOrMore(entry + comma)) + + cs << (lbrace + entries + rbrace) + + macroName = ident + params = pp.Group(pp.ZeroOrMore(expr + comma) + expr) + macroParams = lbracket + params + rbracket + + function_macro = super(MacroInitializer, self).BNF() + mi = function_macro + equals + pp.Group(cs) + semicolon + mi.ignore(pp.cppStyleComment) + + return mi + + def item(self, item): + r = { + "macro": item[0], + "name": item[1][0], + "params": item[2], + "value": {}, + } + + for param in item[2]: + r["value"][param[0]] = cgi.escape(param[1]) + + return r diff --git a/doxygen/siphon/process.py b/doxygen/siphon/process.py new file mode 100644 index 00000000..c7f8f1a2 --- /dev/null +++ b/doxygen/siphon/process.py @@ -0,0 +1,271 @@ +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Generation template class + +import logging, os,sys, cgi, json, jinja2, HTMLParser + +# Classes register themselves in this dictionary +"""Mapping of known processors to their classes""" +siphons = {} + + +"""Generate rendered output for siphoned data.""" +class Siphon(object): + + # Set by subclasses + """Our siphon name""" + name = None + + # Set by subclasses + """Name of an identifier used by this siphon""" + identifier = None + + # Set by subclasses + """The pyparsing object to use to parse with""" + _parser = None + + """The input data""" + _cmds = None + + """Group key to (directory,file) mapping""" + _group = None + + """Logging handler""" + log = None + + """Directory to look for siphon rendering templates""" + template_directory = None + + """Template environment, if we're using templates""" + _tplenv = None + + def __init__(self, template_directory=None): + super(Siphon, self).__init__() + self.log = logging.getLogger("siphon.process.%s" % self.name) + + if template_directory is not None: + self.template_directory = template_directory + searchpath = [ + template_directory + "/" + self.name, + template_directory + "/" + "default", + ] + loader = jinja2.FileSystemLoader(searchpath=searchpath) + self._tplenv = jinja2.Environment( + loader=loader, + trim_blocks=True, + keep_trailing_newline=True) + + # Convenience, get a reference to the internal escape and + # unescape methods in cgi and HTMLParser. These then become + # available to templates to use, if needed. + self._h = HTMLParser.HTMLParser() + self.escape = cgi.escape + self.unescape = self._h.unescape + + + # Output renderers + + """Returns an object to be used as the sorting key in the item index.""" + def index_sort_key(self, group): + return group + + """Returns a string to use as the header at the top of the item index.""" + def index_header(self): + return self.template("index_header") + + """Returns the string fragment to use for each section in the item + index.""" + def index_section(self, group): + return self.template("index_section", group=group) + + """Returns the string fragment to use for each entry in the item index.""" + def index_entry(self, meta, item): + return self.template("index_entry", meta=meta, item=item) + + """Returns an object, typically a string, to be used as the sorting key + for items within a section.""" + def item_sort_key(self, item): + return item['name'] + + """Returns a key for grouping items together.""" + def group_key(self, directory, file, macro, name): + _global = self._cmds['_global'] + + if file in _global and 'group_label' in _global[file]: + self._group[file] = (directory, file) + return file + + self._group[directory] = (directory, None) + return directory + + """Returns a key for identifying items within a grouping.""" + def item_key(self, directory, file, macro, name): + return name + + """Returns a string to use as the header when rendering the item.""" + def item_header(self, group): + return self.template("item_header", group=group) + + """Returns a string to use as the body when rendering the item.""" + def item_format(self, meta, item): + return self.template("item_format", meta=meta, item=item) + + """Returns a string to use as the label for the page reference.""" + def page_label(self, group): + return "_".join(( + self.name, + self.sanitize_label(group) + )) + + """Returns a title to use for a page.""" + def page_title(self, group): + _global = self._cmds['_global'] + (directory, file) = self._group[group] + + if file and file in _global and 'group_label' in _global[file]: + return _global[file]['group_label'] + + if directory in _global and 'group_label' in _global[directory]: + return _global[directory]['group_label'] + + return directory + + """Returns a string to use as the label for the section reference.""" + def item_label(self, group, item): + return "__".join(( + self.name, + item + )) + + """Label sanitizer; for creating Doxygen references""" + def sanitize_label(self, value): + return value.replace(" ", "_") \ + .replace("/", "_") \ + .replace(".", "_") + + """Template processor""" + def template(self, name, **kwargs): + tpl = self._tplenv.get_template(name + ".md") + return tpl.render( + this=self, + **kwargs) + + + # Processing methods + + """Parse the input file into a more usable dictionary structure.""" + def load_json(self, files): + self._cmds = {} + self._group = {} + + line_num = 0 + line_start = 0 + for filename in files: + filename = os.path.relpath(filename) + self.log.info("Parsing items in file \"%s\"." % filename) + data = None + with open(filename, "r") as fd: + data = json.load(fd) + + self._cmds['_global'] = data['global'] + + # iterate the items loaded and regroup it + for item in data["items"]: + try: + o = self._parser.parse(item['block']) + except: + self.log.error("Exception parsing item: %s\n%s" \ + % (json.dumps(item, separators=(',', ': '), + indent=4), + item['block'])) + raise + + # Augment the item with metadata + o["meta"] = {} + for key in item: + if key == 'block': + continue + o['meta'][key] = item[key] + + # Load some interesting fields + directory = item['directory'] + file = item['file'] + macro = o["macro"] + name = o["name"] + + # Generate keys to group items by + group_key = self.group_key(directory, file, macro, name) + item_key = self.item_key(directory, file, macro, name) + + if group_key not in self._cmds: + self._cmds[group_key] = {} + + self._cmds[group_key][item_key] = o + + """Iterate over the input data, calling render methods to generate the + output.""" + def process(self, out=None): + + if out is None: + out = sys.stdout + + # Accumulated body contents + contents = "" + + # Write the header for this siphon type + out.write(self.index_header()) + + # Sort key helper for the index + def group_sort_key(group): + return self.index_sort_key(group) + + # Iterate the dictionary and process it + for group in sorted(self._cmds.keys(), key=group_sort_key): + if group.startswith('_'): + continue + + self.log.info("Processing items in group \"%s\" (%s)." % \ + (group, group_sort_key(group))) + + # Generate the section index entry (write it now) + out.write(self.index_section(group)) + + # Generate the item header (save for later) + contents += self.item_header(group) + + def item_sort_key(key): + return self.item_sort_key(self._cmds[group][key]) + + for key in sorted(self._cmds[group].keys(), key=item_sort_key): + self.log.debug("--- Processing key \"%s\" (%s)." % \ + (key, item_sort_key(key))) + + o = self._cmds[group][key] + meta = { + "directory": o['meta']['directory'], + "file": o['meta']['file'], + "macro": o['macro'], + "key": key, + "label": self.item_label(group, key), + } + + # Generate the index entry for the item (write it now) + out.write(self.index_entry(meta, o)) + + # Generate the item itself (save for later) + contents += self.item_format(meta, o) + + # Deliver the accumulated body output + out.write(contents) diff --git a/doxygen/siphon/process_clicmd.py b/doxygen/siphon/process_clicmd.py new file mode 100644 index 00000000..9b3bd35c --- /dev/null +++ b/doxygen/siphon/process_clicmd.py @@ -0,0 +1,56 @@ +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Generate clicmd formatted output + +import process, parsers + +class SiphonCLICMD(process.Siphon): + + name = "clicmd" + identifier = "VLIB_CLI_COMMAND" + + def __init__(self, *args, **kwargs): + super(SiphonCLICMD, self).__init__(*args, **kwargs) + self._parser = parsers.MacroInitializer() + + + # Output renderers + + def index_sort_key(self, group): + _global = self._cmds['_global'] + if group not in self._group: + return group + (directory, file) = self._group[group] + + if file in _global and 'group_label' in _global[file]: + return _global[file]['group_label'] + + if directory in _global and 'group_label' in _global[directory]: + return _global[directory]['group_label'] + + return group + + def item_sort_key(self, item): + return item['value']['path'] + + def item_label(self, group, item): + return "_".join(( + self.name, + self.sanitize_label(self._cmds[group][item]['value']['path']) + )) + + +# Register our processor +process.siphons["clicmd"] = SiphonCLICMD diff --git a/doxygen/siphon/process_syscfg.py b/doxygen/siphon/process_syscfg.py new file mode 100644 index 00000000..94be5910 --- /dev/null +++ b/doxygen/siphon/process_syscfg.py @@ -0,0 +1,30 @@ +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Generate syscfg formatted output + +import process, parsers + +class SiphonSYSCFG(process.Siphon): + + name = "syscfg" + identifier = "VLIB_CONFIG_FUNCTION" + + def __init__(self, *args, **kwargs): + super(SiphonSYSCFG, self).__init__(*args, **kwargs) + self._parser = parsers.ParseFunctionMacroStmt() + + +# Register our processor +process.siphons["syscfg"] = SiphonSYSCFG diff --git a/doxygen/siphon_generate.py b/doxygen/siphon_generate.py deleted file mode 100755 index 8b999114..00000000 --- a/doxygen/siphon_generate.py +++ /dev/null @@ -1,322 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2016 Comcast Cable Communications Management, LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Looks for preprocessor macros with struct initializers and siphons them -# off into another file for later parsing; ostensibly to generate -# documentation from struct initializer data. - -import os, sys, re, argparse, json - -DEFAULT_OUTPUT = "build-root/docs/siphons" -DEFAULT_PREFIX = os.getcwd() - -ap = argparse.ArgumentParser() -ap.add_argument("--output", '-o', metavar="directory", default=DEFAULT_OUTPUT, - help="Output directory for .siphon files [%s]" % DEFAULT_OUTPUT) -ap.add_argument("--input-prefix", metavar="path", default=DEFAULT_PREFIX, - help="Prefix to strip from input pathnames [%s]" % DEFAULT_PREFIX) -ap.add_argument("input", nargs='+', metavar="input_file", - help="Input C source files") -args = ap.parse_args() - -"""Patterns that match the start of code blocks we want to siphon""" -siphon_patterns = [ - ( re.compile("(?PVLIB_CLI_COMMAND)\s*[(](?P[a-zA-Z0-9_]+)(,[^)]*)?[)]"), "clicmd" ), -] - -"""Matches a siphon comment block start""" -siphon_block_start = re.compile("^\s*/\*\?\s*(.*)$") - -"""Matches a siphon comment block stop""" -siphon_block_stop = re.compile("^(.*)\s*\?\*/\s*$") - -"""Siphon block directive delimiter""" -siphon_block_delimiter = "%%" - -"""Matches a siphon block directive such as '%clicmd:group_label Debug CLI%'""" -siphon_block_directive = re.compile("(%s)\s*([a-zA-Z0-9_:]+)\s+(.*)\s*(%s)" % \ - (siphon_block_delimiter, siphon_block_delimiter)) - -"""Matches the start of an initializer block""" -siphon_initializer = re.compile("\s*=") - -""" -count open and close braces in str -return (0, index) when braces were found and count becomes 0. -index indicates the position at which the last closing brace was -found. -return (-1, -1) if a closing brace is found before any opening one. -return (count, -1) if not all opening braces are closed, count is the -current depth -""" -def count_braces(str, count=0, found=False): - for index in range(0, len(str)): - if str[index] == '{': - count += 1; - found = True - elif str[index] == '}': - if count == 0: - # means we never found an open brace - return (-1, -1) - count -= 1; - - if count == 0 and found: - return (count, index) - - return (count, -1) - -# Collated output for each siphon -output = {} - -# Build a list of known siphons -known_siphons = [] -for item in siphon_patterns: - siphon = item[1] - if siphon not in known_siphons: - known_siphons.append(siphon) - -# Setup information for siphons we know about -for siphon in known_siphons: - output[siphon] = { - "file": "%s/%s.siphon" % (args.output, siphon), - "global": {}, - "items": [], - } - -# Pre-process file names in case they indicate a file with -# a list of files -files = [] -for filename in args.input: - if filename.startswith('@'): - with open(filename[1:], 'r') as fp: - lines = fp.readlines() - for line in lines: - files.append(line.strip()) - lines = None - else: - files.append(filename) - -# Iterate all the input files we've been given -for filename in files: - # Strip the current directory off the start of the - # filename for brevity - if filename[0:len(args.input_prefix)] == args.input_prefix: - filename = filename[len(args.input_prefix):] - if filename[0] == "/": - filename = filename[1:] - - # Work out the abbreviated directory name - directory = os.path.dirname(filename) - if directory[0:2] == "./": - directory = directory[2:] - elif directory[0:len(args.input_prefix)] == args.input_prefix: - directory = directory[len(args.input_prefix):] - if directory[0] == "/": - directory = directory[1:] - - # Open the file and explore its contents... - sys.stderr.write("Siphoning from %s...\n" % filename) - directives = {} - with open(filename) as fd: - siphon = None - close_siphon = None - siphon_block = "" - in_block = False - line_num = 0 - siphon_line = 0 - - for line in fd: - line_num += 1 - str = line[:-1] # filter \n - - """See if there is a block directive and if so extract it""" - def process_block_directive(str, directives): - m = siphon_block_directive.search(str) - if m is not None: - k = m.group(2) - v = m.group(3).strip() - directives[k] = v - # Return only the parts we did not match - return str[0:m.start(1)] + str[m.end(4):] - - return str - - def process_block_prefix(str): - if str.startswith(" * "): - str = str[3:] - elif str == " *": - str = "" - return str - - if not in_block: - # See if the line contains the start of a siphon doc block - m = siphon_block_start.search(str) - if m is not None: - in_block = True - t = m.group(1) - - # Now check if the block closes on the same line - m = siphon_block_stop.search(t) - if m is not None: - t = m.group(1) - in_block = False - - # Check for directives - t = process_block_directive(t, directives) - - # Filter for normal comment prefixes - t = process_block_prefix(t) - - # Add what is left - siphon_block += t - - # Skip to next line - continue - - else: - # Check to see if we have an end block marker - m = siphon_block_stop.search(str) - if m is not None: - in_block = False - t = m.group(1) - else: - t = str - - # Check for directives - t = process_block_directive(t, directives) - - # Filter for normal comment prefixes - t = process_block_prefix(t) - - # Add what is left - siphon_block += t + "\n" - - # Skip to next line - continue - - - if siphon is None: - # Look for blocks we need to siphon - for p in siphon_patterns: - if p[0].match(str): - siphon = [ p[1], str + "\n", 0 ] - siphon_line = line_num - - # see if we have an initializer - m = siphon_initializer.search(str) - if m is not None: - # count the braces on this line - (count, index) = count_braces(str[m.start():]) - siphon[2] = count - # TODO - it's possible we have the initializer all on the first line - # we should check for it, but also account for the possibility that - # the open brace is on the next line - #if count == 0: - # # braces balanced - # close_siphon = siphon - # siphon = None - else: - # no initializer: close the siphon right now - close_siphon = siphon - siphon = None - else: - # See if we should end the siphon here - do we have balanced - # braces? - (count, index) = count_braces(str, count=siphon[2], found=True) - if count == 0: - # braces balanced - add the substring and close the siphon - siphon[1] += str[:index+1] + ";\n" - close_siphon = siphon - siphon = None - else: - # add the whole string, move on - siphon[2] = count - siphon[1] += str + "\n" - - if close_siphon is not None: - # Write the siphoned contents to the right place - siphon_name = close_siphon[0] - - # Copy directives for the file - details = {} - for key in directives: - if ":" in key: - (sn, label) = key.split(":") - if sn == siphon_name: - details[label] = directives[key] - else: - details[key] = directives[key] - - # Copy details for this block - details['file'] = filename - details['line_start'] = siphon_line - details['line_end'] = line_num - details['siphon_block'] = siphon_block.strip() - - # Some defaults - if "group" not in details: - if "group_label" in details: - # use the filename since group labels are mostly of file scope - details['group'] = details['file'] - else: - details['group'] = directory - - if "group_label" not in details: - details['group_label'] = details['group'] - - details["block"] = close_siphon[1] - - # Store the item - output[siphon_name]['items'].append(details) - - # All done - close_siphon = None - siphon_block = "" - - # Update globals - for key in directives.keys(): - if ':' not in key: - continue - - if filename.endswith("/dir.dox"): - # very special! use the parent directory name - l = directory - else: - l = filename - - (sn, label) = key.split(":") - - if sn not in output: - output[sn] = {} - if 'global' not in output[sn]: - output[sn]['global'] = {} - if l not in output[sn]['global']: - output[sn]['global'][l] = {} - if 'file' not in output[sn]: - output[sn]['file'] = "%s/%s.siphon" % (args.output, sn) - if 'items' not in output[sn]: - output[sn]['items'] = [] - - output[sn]['global'][l][label] = directives[key] - - -# Write out the data -for siphon in output.keys(): - sys.stderr.write("Saving siphon %s...\n" % siphon) - s = output[siphon] - with open(s['file'], "a") as fp: - json.dump(s, fp, separators=(',', ': '), indent=4, sort_keys=True) - -# All done diff --git a/doxygen/siphon_process.py b/doxygen/siphon_process.py deleted file mode 100755 index 82a166d3..00000000 --- a/doxygen/siphon_process.py +++ /dev/null @@ -1,323 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2016 Comcast Cable Communications Management, LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Filter for .siphon files that are generated by other filters. -# The idea is to siphon off certain initializers so that we can better -# auto-document the contents of that initializer. - -import os, sys, re, argparse, cgi, json -import pyparsing as pp - -import pprint - -DEFAULT_SIPHON ="clicmd" -DEFAULT_OUTPUT = None -DEFAULT_PREFIX = os.getcwd() - -siphon_map = { - 'clicmd': "VLIB_CLI_COMMAND", -} - -ap = argparse.ArgumentParser() -ap.add_argument("--type", '-t', metavar="siphon_type", default=DEFAULT_SIPHON, - choices=siphon_map.keys(), - help="Siphon type to process [%s]" % DEFAULT_SIPHON) -ap.add_argument("--output", '-o', metavar="directory", default=DEFAULT_OUTPUT, - help="Output directory for .md files [%s]" % DEFAULT_OUTPUT) -ap.add_argument("--input-prefix", metavar="path", default=DEFAULT_PREFIX, - help="Prefix to strip from input pathnames [%s]" % DEFAULT_PREFIX) -ap.add_argument("input", nargs='+', metavar="input_file", - help="Input .siphon files") -args = ap.parse_args() - -if args.output is None: - sys.stderr.write("Error: Siphon processor requires --output to be set.") - sys.exit(1) - - -def clicmd_index_sort(cfg, group, dec): - if group in dec and 'group_label' in dec[group]: - return dec[group]['group_label'] - return group - -def clicmd_index_header(cfg): - s = "# CLI command index\n" - s += "\n[TOC]\n" - return s - -def clicmd_index_section(cfg, group, md): - return "\n@subpage %s\n\n" % md - -def clicmd_index_entry(cfg, meta, item): - v = item["value"] - return "* [%s](@ref %s)\n" % (v["path"], meta["label"]) - -def clicmd_sort(cfg, meta, item): - return item['value']['path'] - -def clicmd_header(cfg, group, md, dec): - if group in dec and 'group_label' in dec[group]: - label = dec[group]['group_label'] - else: - label = group - return "\n@page %s %s\n" % (md, label) - -def clicmd_format(cfg, meta, item): - v = item["value"] - s = "\n@section %s %s\n" % (meta['label'], v['path']) - - # The text from '.short_help = '. - # Later we should split this into short_help and usage_help - # since the latter is how it is primarily used but the former - # is also needed. - if "short_help" in v: - tmp = v["short_help"].strip() - - # Bit hacky. Add a trailing period if it doesn't have one. - if tmp[-1] != ".": - tmp += "." - - s += "### Summary/usage\n %s\n\n" % tmp - - # This is seldom used and will likely be deprecated - if "long_help" in v: - tmp = v["long_help"] - - s += "### Long help\n %s\n\n" % tmp - - # Extracted from the code in /*? ... ?*/ blocks - if "siphon_block" in item["meta"]: - sb = item["meta"]["siphon_block"] - - if sb != "": - # hack. still needed? - sb = sb.replace("\n", "\\n") - try: - sb = json.loads('"'+sb+'"') - s += "### Description\n%s\n\n" % sb - except: - pass - - # Gives some developer-useful linking - if "item" in meta or "function" in v: - s += "### Declaration and implementation\n\n" - - if "item" in meta: - s += "Declaration: @ref %s (%s:%d)\n\n" % \ - (meta['item'], meta["file"], int(item["meta"]["line_start"])) - - if "function" in v: - s += "Implementation: @ref %s.\n\n" % v["function"] - - return s - - -siphons = { - "VLIB_CLI_COMMAND": { - "index_sort_key": clicmd_index_sort, - "index_header": clicmd_index_header, - "index_section": clicmd_index_section, - "index_entry": clicmd_index_entry, - 'sort_key': clicmd_sort, - "header": clicmd_header, - "format": clicmd_format, - } -} - - -# PyParsing definition for our struct initializers which look like this: -# VLIB_CLI_COMMAND (show_sr_tunnel_command, static) = { -# .path = "show sr tunnel", -# .short_help = "show sr tunnel [name ]", -# .function = show_sr_tunnel_fn, -#}; -def getMacroInitializerBNF(): - cs = pp.Forward() - ident = pp.Word(pp.alphas + "_", pp.alphas + pp.nums + "_") - intNum = pp.Word(pp.nums) - hexNum = pp.Literal("0x") + pp.Word(pp.hexnums) - octalNum = pp.Literal("0") + pp.Word("01234567") - integer = (hexNum | octalNum | intNum) + \ - pp.Optional(pp.Literal("ULL") | pp.Literal("LL") | pp.Literal("L")) - floatNum = pp.Regex(r'\d+(\.\d*)?([eE]\d+)?') + pp.Optional(pp.Literal("f")) - char = pp.Literal("'") + pp.Word(pp.printables, exact=1) + pp.Literal("'") - arrayIndex = integer | ident - - lbracket = pp.Literal("(").suppress() - rbracket = pp.Literal(")").suppress() - lbrace = pp.Literal("{").suppress() - rbrace = pp.Literal("}").suppress() - comma = pp.Literal(",").suppress() - equals = pp.Literal("=").suppress() - dot = pp.Literal(".").suppress() - semicolon = pp.Literal(";").suppress() - - # initializer := { [member = ] (variable | expression | { initializer } ) } - typeName = ident - varName = ident - - typeSpec = pp.Optional("unsigned") + \ - pp.oneOf("int long short float double char u8 i8 void") + \ - pp.Optional(pp.Word("*"), default="") - typeCast = pp.Combine( "(" + ( typeSpec | typeName ) + ")" ).suppress() - - string = pp.Combine(pp.OneOrMore(pp.QuotedString(quoteChar='"', - escChar='\\', multiline=True)), adjacent=False) - literal = pp.Optional(typeCast) + (integer | floatNum | char | string) - var = pp.Combine(pp.Optional(typeCast) + varName + pp.Optional("[" + arrayIndex + "]")) - - expr = (literal | var) # TODO - - - member = pp.Combine(dot + varName + pp.Optional("[" + arrayIndex + "]"), adjacent=False) - value = (expr | cs) - - entry = pp.Group(pp.Optional(member + equals, default="") + value) - entries = (pp.ZeroOrMore(entry + comma) + entry + pp.Optional(comma)) | \ - (pp.ZeroOrMore(entry + comma)) - - cs << (lbrace + entries + rbrace) - - macroName = ident - params = pp.Group(pp.ZeroOrMore(expr + comma) + expr) - macroParams = lbracket + params + rbracket - - mi = macroName + pp.Optional(macroParams) + equals + pp.Group(cs) + semicolon - mi.ignore(pp.cppStyleComment) - return mi - - -mi = getMacroInitializerBNF() - -# Parse the input file into a more usable dictionary structure -cmds = {} -line_num = 0 -line_start = 0 -for filename in args.input: - sys.stderr.write("Parsing items in file \"%s\"...\n" % filename) - data = None - with open(filename, "r") as fd: - data = json.load(fd) - - cmds['_global'] = data['global'] - - # iterate the items loaded and regroup it - for item in data["items"]: - try: - o = mi.parseString(item['block']).asList() - except: - sys.stderr.write("Exception parsing item: %s\n%s\n" \ - % (json.dumps(item, separators=(',', ': '), indent=4), - item['block'])) - raise - - group = item['group'] - file = item['file'] - macro = o[0] - param = o[1][0] - - if group not in cmds: - cmds[group] = {} - - if file not in cmds[group]: - cmds[group][file] = {} - - if macro not in cmds[group][file]: - cmds[group][file][macro] = {} - - c = { - 'params': o[2], - 'meta': {}, - 'value': {}, - } - - for key in item: - if key == 'block': - continue - c['meta'][key] = item[key] - - for i in c['params']: - c['value'][i[0]] = cgi.escape(i[1]) - - cmds[group][file][macro][param] = c - - -# Write the header for this siphon type -cfg = siphons[siphon_map[args.type]] -sys.stdout.write(cfg["index_header"](cfg)) -contents = "" - -def group_sort_key(item): - if "index_sort_key" in cfg: - return cfg["index_sort_key"](cfg, item, cmds['_global']) - return item - -# Iterate the dictionary and process it -for group in sorted(cmds.keys(), key=group_sort_key): - if group.startswith('_'): - continue - - sys.stderr.write("Processing items in group \"%s\"...\n" % group) - - cfg = siphons[siphon_map[args.type]] - md = group.replace("/", "_").replace(".", "_") - sys.stdout.write(cfg["index_section"](cfg, group, md)) - - if "header" in cfg: - dec = cmds['_global'] - contents += cfg["header"](cfg, group, md, dec) - - for file in sorted(cmds[group].keys()): - if group.startswith('_'): - continue - - sys.stderr.write("- Processing items in file \"%s\"...\n" % file) - - for macro in sorted(cmds[group][file].keys()): - if macro != siphon_map[args.type]: - continue - sys.stderr.write("-- Processing items in macro \"%s\"...\n" % macro) - cfg = siphons[macro] - - meta = { - "group": group, - "file": file, - "macro": macro, - "md": md, - } - - def item_sort_key(item): - if "sort_key" in cfg: - return cfg["sort_key"](cfg, meta, cmds[group][file][macro][item]) - return item - - for param in sorted(cmds[group][file][macro].keys(), key=item_sort_key): - sys.stderr.write("--- Processing item \"%s\"...\n" % param) - - meta["item"] = param - - # mangle "md" and the item to make a reference label - meta["label"] = "%s___%s" % (meta["md"], param) - - if "index_entry" in cfg: - s = cfg["index_entry"](cfg, meta, cmds[group][file][macro][param]) - sys.stdout.write(s) - - if "format" in cfg: - contents += cfg["format"](cfg, meta, cmds[group][file][macro][param]) - -sys.stdout.write(contents) - -# All done diff --git a/doxygen/siphon_templates/clicmd/index_entry.md b/doxygen/siphon_templates/clicmd/index_entry.md new file mode 100644 index 00000000..1fa9ec9b --- /dev/null +++ b/doxygen/siphon_templates/clicmd/index_entry.md @@ -0,0 +1,17 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} +{% set v = item['value'] %} +{{ "* [%s](@ref %s)" % (v['path'], meta["label"]) }} diff --git a/doxygen/siphon_templates/clicmd/index_header.md b/doxygen/siphon_templates/clicmd/index_header.md new file mode 100644 index 00000000..4167f4dc --- /dev/null +++ b/doxygen/siphon_templates/clicmd/index_header.md @@ -0,0 +1,130 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} +# Debug CLI {{'{#'}}clicmd} + +The VPP network stack comes equipped with a set of commands that are useful +for debugging. + +The easiest way to access the CLI (with proper permissions) is to use the +vppctl command: + +``` +sudo vppctl +``` + +The CLI parser matches static keyword strings, eventually invoking an action +function. Unambiguous partial keyword matching always occurs. The action +functions consume input until satisfied or until they fail. This model makes +for easy coding, but does not guarantee useful "help" output. It's up to the +CLI command writer to add useful help strings. + +You can find the source code of CLI commands by searching for instances of the +@c VLIB_CLI_COMMAND macro in the code source files. + +Please help maintain and improve this document to make and keep these commands +clear and useful! + +@todo Document where to modify this CLI intro text. + + +## Debug and Telnet CLI + +The debug CLI is enabled with the unix interactive parameter or startup +configuration option. This causes VPP to start without daemonizing and +presents a command line interface on the terminal where it is run. + +The Telnet CLI is enabled with the `cli-listen localhost:5002` option which +will cause VPP to listen for TCP connections on the localhost address port +@c 5002. A Telnet client can then connect to this port (for example, `telnet +localhost 5002`) and will receive a command line prompt. + +This configuration will enable both mechanisms: + +``` +unix { + interactive + cli-listen localhost:5002 +} +``` + +The debug CLI can operate in line mode, which may be useful when running +inside an IDE like Emacs. This is enabled with the option +`unix cli-line-mode`. Several other options exist that alter how this +CLI works, see the @ref syscfg section for details. + +The CLI starts with a banner graphic (which can be disabled) and a prompt. The +prompt will typically read `vpp` for a release version of VPP and `DBGvpp#` +for a development version with debugging enabled, for example: + + _______ _ _ _____ ___ + __/ __/ _ \ (_)__ | | / / _ \/ _ \ + _/ _// // / / / _ \ | |/ / ___/ ___/ + /_/ /____(_)_/\___/ |___/_/ /_/ + + vpp# + +versus: + + _______ _ _ _____ ___ + __/ __/ _ \ (_)__ | | / / _ \/ _ \ + _/ _// // / / / _ \ | |/ / ___/ ___/ + /_/ /____(_)_/\___/ |___/_/ /_/ + + DBGvpp# + +This prompt can be configured with the `unix cli-prompt` setting and the +banner is disabled with `unix cli-no-banner`. + +## CLI features + +The CLI has several editing features that make it easy to use. + +- Cursor keys left/right will move the cursor within a command line; + typing will insert at the cursor; erase will erase at the cursor. + +- Ctrl-left/right will search for the start of the next word to + the left or right. +- Home/end will jump the cursor to the start and end of the line. +- Cursor keys up/down and ^P/^N iterate through the command history + buffer. Lines from the history buffer may be edited. New commands + are added to the end of the buffer when executed; though + duplicates of the previous command are not added. +- ^U erases the line contents from the left of the cursor to the + start. +- ^K erases the contents from the cursor to the end. +- ^S/^R will search the command history forwards or in reverse for + a command; start typing for matches to auto complete. +- ^L will clear the screen (if supported by the terminal) and repaint + the prompt and any current line. The cursor position is also + retained. +- The CLI can be closed with the quit command. Alternatively, ^D on + an empty input line will also close the session. Closing the debug + session will also shutdown VPP. + +Output that exceeds the length of a terminal page will be buffered, up to a +limit. + +- Space or page-down displays the next page. +- Enter or down-arrow displays the next line. +- Page-up goes back a page. +- Up-arrow goes up a line. +- Home/end jump to the start/end of the buffered output. +- The key q quits the pager. Space and enter will also quit the + pager if the end of the buffer has been reached. + +## Index of CLI commands + +[TOC] diff --git a/doxygen/siphon_templates/clicmd/item_format.md b/doxygen/siphon_templates/clicmd/item_format.md new file mode 100644 index 00000000..77d0484b --- /dev/null +++ b/doxygen/siphon_templates/clicmd/item_format.md @@ -0,0 +1,59 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} +{% set v = item['value'] %} +{{ "@section %s %s" % (meta['label'], v['path']) }} +{% if 'short_help' in v %} + +### Summary/usage + +{% set str = v['short_help'] %} +{% set period = "." if str[-1] != "." else "" %} +{% set prefix = " " if "[" in str or "<" in str or "|" in str else "" %} +{% set str = this.unescape(str) %} +{{ "%s%s%s" % (prefix, str, period) }} +{% endif %} +{% if 'long_help' in v %} +{# This is seldom used and will likely be deprecated #} + +### Long help + +{{ v['long_help'] }} +{%- endif %} +{% if 'siphon_block' in item['meta'] %} +{% set sb = item["meta"]["siphon_block"] %} +{% if sb %} +{# Extracted from the code in /*? ... ?*/ blocks #} + +### Description + +{{ sb }} +{% endif %} +{% endif %} +{% if "item" in meta or "function" in v %} +{# Gives some developer-useful linking #} + +### Declaration and implementation +{% if "item" in meta %} + +{{ "Declaration: @ref %s (@ref %s line %d)" % + (meta['item'], meta["file"], item["meta"]["line_start"]) }} +{% endif %} +{% if "function" in v %} + +{{ "Implementation: @ref %s." % v["function"] }} +{% endif %} +{% endif %} + diff --git a/doxygen/siphon_templates/default/index_entry.md b/doxygen/siphon_templates/default/index_entry.md new file mode 100644 index 00000000..479dcdb2 --- /dev/null +++ b/doxygen/siphon_templates/default/index_entry.md @@ -0,0 +1,16 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} +{{ "* [%s](@ref %s)" % (item["name"], meta["label"]) }} diff --git a/doxygen/siphon_templates/default/index_section.md b/doxygen/siphon_templates/default/index_section.md new file mode 100644 index 00000000..3c9d2b47 --- /dev/null +++ b/doxygen/siphon_templates/default/index_section.md @@ -0,0 +1,18 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} + +@subpage {{ this.page_label(group) }} + diff --git a/doxygen/siphon_templates/default/item_format.md b/doxygen/siphon_templates/default/item_format.md new file mode 100644 index 00000000..ed1b1bf7 --- /dev/null +++ b/doxygen/siphon_templates/default/item_format.md @@ -0,0 +1,16 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} +{{ raise NotImplementedError }} diff --git a/doxygen/siphon_templates/default/item_header.md b/doxygen/siphon_templates/default/item_header.md new file mode 100644 index 00000000..0c21e51f --- /dev/null +++ b/doxygen/siphon_templates/default/item_header.md @@ -0,0 +1,18 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} + +{{ "@page %s %s" % (this.page_label(group), this.page_title(group)) }} + diff --git a/doxygen/siphon_templates/syscfg/index_header.md b/doxygen/siphon_templates/syscfg/index_header.md new file mode 100644 index 00000000..5d338a04 --- /dev/null +++ b/doxygen/siphon_templates/syscfg/index_header.md @@ -0,0 +1,111 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} +# Startup Configuration {{'{#'}}syscfg} + +The VPP network stack comes with several configuration options that can be +provided either on the command line or in a configuration file. + +Specific applications built on the stack have been known to require a dozen +arguments, depending on requirements. This section describes commonly-used +options and parameters. + +You can find command-line argument parsers in the source code by searching for +instances of the `VLIB_CONFIG_FUNCTION` macro. The invocation +`VLIB_CONFIG_FUNCTION(foo_config, "foo")` will cause the function +`foo_config` to receive all the options and values supplied in a parameter +block named "`foo`", for example: `foo { arg1 arg2 arg3 ... }`. + +@todo Tell the nice people where this document lives so that the might +help improve it! + +## Command-line arguments + +Parameters are grouped by a section name. When providing more than one +parameter to a section all parameters for that section must be wrapped in +curly braces. + +``` +/usr/bin/vpp unix { interactive cli-listen 127.0.0.1:5002 } +``` + +Which will produce output similar to this: + + + _______ _ _ _____ ___ + __/ __/ _ \ (_)__ | | / / _ \/ _ \ + _/ _// // / / / _ \ | |/ / ___/ ___/ + /_/ /____(_)_/\___/ |___/_/ /_/ + + vpp# + +When providing only one such parameter the braces are optional. For example, +the following command argument, `unix interactive` does not have braces: + +``` +/usr/bin/vpp unix interactive +``` + +The command line can be presented as a single string or as several; anything +given on the command line is concatenated with spaces into a single string +before parsing. + +VPP applications must be able to locate their own executable images. The +simplest way to ensure this will work is to invoke a VPP application by giving +its absolute path; for example: `/usr/bin/vpp `. At startup, VPP +applications parse through their own ELF-sections (primarily) to make lists +of init, configuration, and exit handlers. + +When developing with VPP, in _gdb_ it's often sufficient to start an application +like this at the `(gdb)` prompt: + +``` +run unix interactive +``` + +## Configuration file + +It is also possible to supply parameters in a startup configuration file the +path of which is provided to the VPP application on its command line. + +The format of the configuration file is a simple text file with the same +content as the command line but with the benefit of being able to use newlines +to make the content easier to read. For example: + +``` +unix { + nodaemon + log /tmp/vpp.log + full-coredump + cli-listen localhost:5002 +} +api-trace { + on +} +dpdk { + dev 0000:03:00.0 +} +``` + +VPP is then instructed to load this file with the `-c` option: + +``` +/usr/bin/vpp -c /etc/vpp/startup.conf +``` + +## Index of startup command sections + +[TOC] + diff --git a/doxygen/siphon_templates/syscfg/item_format.md b/doxygen/siphon_templates/syscfg/item_format.md new file mode 100644 index 00000000..5d3bb5c8 --- /dev/null +++ b/doxygen/siphon_templates/syscfg/item_format.md @@ -0,0 +1,42 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} +{% set v = item['value'] %} +{{ "@section %s %s" % (meta['label'], item['name']) }} +{% if 'siphon_block' in item['meta'] %} +{% set sb = item["meta"]["siphon_block"] %} +{% if sb %} +{# Extracted from the code in /*? ... ?*/ blocks #} + +### Description + +{{ sb }} +{% endif %} +{% endif %} +{% if "item" in meta or "function" in item %} +{# Gives some developer-useful linking #} + +### Declaration and implementation +{% if "item" in meta %} + +{{ "Declaration: @ref %s (@ref %s line %d)" % + (meta['item'], meta["file"], item["meta"]["line_start"]) }} +{% endif %} +{% if "function" in item %} + +{{ "Implementation: @ref %s." % item["function"] }} +{% endif %} +{% endif %} + diff --git a/vlib/vlib/unix/cj.c b/vlib/vlib/unix/cj.c index 553b450f..33ba163a 100644 --- a/vlib/vlib/unix/cj.c +++ b/vlib/vlib/unix/cj.c @@ -17,6 +17,16 @@ *------------------------------------------------------------------ */ +/** + * @file + * Circular joournal diagnostic mechanism. + * + * The @c cj thread-safe circular log buffer scheme is occasionally useful + * when chasing bugs. Calls to it should not be checked in. + */ +/*? %%clicmd:group_label Circular Journal %% ?*/ +/*? %%syscfg:group_label Circular Journal %% ?*/ + #include #include @@ -94,6 +104,18 @@ cj_config (vlib_main_t * vm, unformat_input_t * input) return 0; } +/*? + * Configure the circular journal diagnostic mechanism. This is only useful + * if you, the deveoper, have written code to make use of the circular + * journal. + * + * @cfgcmd{records, <number>} + * Configure the number of records to allocate for the circular journal. + * + * @cfgcmd{on} + * Enable the collection of records in the circular journal at the + * earliest opportunity. +?*/ VLIB_CONFIG_FUNCTION (cj_config, "cj"); void @@ -220,10 +242,21 @@ cj_command_fn (vlib_main_t * vm, return 0; } +/*? + * Enable, disable the collection of diagnostic data into a + * circular journal or dump the circular journal diagnostic data. + * This is only useful if you, the deveoper, have written code to make + * use of the circular journal. + * + * When dumping the data it is formatted and sent to @c stderr of the + * VPP process; when running VPP in unix interactive mode + * this is typically the same place as the Debug CLI. +?*/ + /* *INDENT-OFF* */ VLIB_CLI_COMMAND (cj_command,static) = { .path = "cj", - .short_help = "cj", + .short_help = "cj ", .function = cj_command_fn, }; /* *INDENT-ON* */ diff --git a/vlib/vlib/unix/cli.c b/vlib/vlib/unix/cli.c index bf09ee0c..69fca6ec 100644 --- a/vlib/vlib/unix/cli.c +++ b/vlib/vlib/unix/cli.c @@ -42,7 +42,8 @@ * Provides a command line interface so humans can interact with VPP. * This is predominantly a debugging and testing mechanism. */ -/*? %%clicmd:group_label Debug CLI %% ?*/ +/*? %%clicmd:group_label Command line session %% ?*/ +/*? %%syscfg:group_label Command line session %% ?*/ #include #include @@ -2504,6 +2505,9 @@ unix_cli_config (vlib_main_t * vm, unformat_input_t * input) return 0; } +/*? + * This module has no configurable parameters. +?*/ VLIB_CONFIG_FUNCTION (unix_cli_config, "unix-cli"); /** Called when VPP is shutting down, this restores the system diff --git a/vlib/vlib/unix/dir.dox b/vlib/vlib/unix/dir.dox index cdded0f1..1380fa56 100644 --- a/vlib/vlib/unix/dir.dox +++ b/vlib/vlib/unix/dir.dox @@ -23,5 +23,6 @@ VLIB application library Unix interface layer. */ -/*? %%clicmd:group_label VLIB Unix stuff%% ?*/ +/*? %%clicmd:group_label Unix Interface %% ?*/ +/*? %%syscfg:group_label Unix Interface %% ?*/ diff --git a/vlib/vlib/unix/main.c b/vlib/vlib/unix/main.c index 3087c283..562778e0 100644 --- a/vlib/vlib/unix/main.c +++ b/vlib/vlib/unix/main.c @@ -407,6 +407,59 @@ unix_config (vlib_main_t * vm, unformat_input_t * input) } /* unix { ... } configuration. */ +/*? + * + * @cfgcmd{interactive} + * Attach CLI to stdin/out and provide a debugging command line interface. + * Implies @c nodaemon. + * + * @cfgcmd{nodaemon} + * Do not fork or background the VPP process. Typically used when invoking + * VPP applications from a process monitor. + * + * @cfgcmd{exec, <filename>} + * @par startup-config <filename> + * Read startup operational configuration from @c filename. + * The contents of the file will be performed as though entered at the CLI. + * The two keywords are aliases for the same function; if both are specified, + * only the last will have an effect. + * + * @cfgcmd{log, <filename>} + * Logs the startup configuration and all subsequent CLI commands in + * @c filename. + * Very useful in situations where folks don't remember or can't be bothered + * to include CLI commands in bug reports. + * + * @cfgcmd{full-coredump} + * Ask the Linux kernel to dump all memory-mapped address regions, instead + * of just text+data+bss. + * + * @cfgcmd{cli-listen, <address:port>} + * Bind the CLI to listen at the address and port given. @clocalhost + * on TCP port @c 5002, given as cli-listen localhost:5002, + * is typical. + * + * @cfgcmd{cli-line-mode} + * Disable character-by-character I/O on stdin. Useful when combined with, + * for example, emacs M-x gud-gdb. + * + * @cfgcmd{cli-prompt, <string>} + * Configure the CLI prompt to be @c string. + * + * @cfgcmd{cli-history-limit, <nn>} + * Limit commmand history to @c nn lines. A value of @c 0 + * disables command history. Default value: @c 50 + * + * @cfgcmd{cli-no-banner} + * Disable the login banner on stdin and Telnet connections. + * + * @cfgcmd{cli-no-pager} + * Disable the output pager. + * + * @cfgcmd{cli-pager-buffer-limit, <nn>} + * Limit pager buffer to @c nn lines of output. + * A value of @c 0 disables the pager. Default value: @c 100000 +?*/ VLIB_CONFIG_FUNCTION (unix_config, "unix"); static clib_error_t * -- cgit 1.2.3-korg From 36d25063828f65a6e864bc56b488bef3c4abcaa4 Mon Sep 17 00:00:00 2001 From: Chris Luke Date: Thu, 22 Sep 2016 20:52:26 -0400 Subject: Enable doc building on MacOS Simple tweak to the Makefiles to allow "make doxygen" to work natively on Macs - assuming the appropriate things have been installed first, which it tests for. Change-Id: I1a3e72759d533270a0512de38595c3bc3f71dee0 Signed-off-by: Chris Luke --- Makefile | 3 +++ doxygen/Makefile | 26 +++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) (limited to 'doxygen/Makefile') diff --git a/Makefile b/Makefile index b3bd8d3c..59f14e3e 100644 --- a/Makefile +++ b/Makefile @@ -24,8 +24,11 @@ GDB_ARGS= -ex "handle SIGUSR1 noprint nostop" # # OS Detection # +# We allow Darwin (MacOS) for docs generation; VPP build will still fail. +ifneq ($(shell uname),Darwin) OS_ID = $(shell grep '^ID=' /etc/os-release | cut -f2- -d= | sed -e 's/\"//g') OS_VERSION_ID= $(shell grep '^VERSION_ID=' /etc/os-release | cut -f2- -d= | sed -e 's/\"//g') +endif DEB_DEPENDS = curl build-essential autoconf automake bison libssl-dev ccache DEB_DEPENDS += debhelper dkms git libtool libganglia1-dev libapr1-dev dh-systemd diff --git a/doxygen/Makefile b/doxygen/Makefile index 97225f3c..7031e84d 100644 --- a/doxygen/Makefile +++ b/doxygen/Makefile @@ -23,11 +23,20 @@ all: doxygen # These should be passed in by the root Makefile WS_ROOT ?= $(CURDIR)/.. BR ?= $(WS_ROOT)/build-root + +# We support MacOS for docs generation +ifeq ($(shell uname),Darwin) +OS_ID = darwin +endif + +# Work out the OS if we haven't already OS_ID ?= $(shell grep '^ID=' /etc/os-release | cut -f2- -d= | sed -e 's/\"//g') # Package dependencies DOC_DEB_DEPENDS = doxygen graphviz python-pyparsing python-jinja2 DOC_RPM_DEPENDS = doxygen graphviz pyparsing python-jinja2 +DOC_MAC_BIN_DEPENDS = doxygen dot git +DOC_MAC_PY_DEPENDS = pyparsing jinja2 # Doxygen configuration and our utility scripts DOXY_DIR ?= $(WS_ROOT)/doxygen @@ -130,8 +139,23 @@ ifeq ($(OS_ID),ubuntu) fi else ifneq ("$(wildcard /etc/redhat-release)","") @sudo yum install $(CONFIRM) $(DOC_RPM_DEPENDS) +else ifeq ($(OS_ID),darwin) + @set -e; \ + for bin in $(DOC_MAC_BIN_DEPENDS); do \ + which -s $${bin} || (\ + echo "Program '$${bin}' not found, please install it."; \ + false; \ + ); \ + done + @set -e; \ + for py in $(DOC_MAC_PY_DEPENDS); do \ + python -c "import $${py}" >/dev/null 2>&1 || (\ + echo "Python package '$${py}' not found, please install it."; \ + false; \ + ); \ + done else - $(error "This option currently works only on Ubuntu or Centos systems") + $(error "Building documentation currently works only on Ubuntu, CentOS or MacOS systems.") endif @touch $@ -- cgit 1.2.3-korg From c3f92adf6be41263eb466e074e4136d29b50b59a Mon Sep 17 00:00:00 2001 From: Chris Luke Date: Wed, 5 Oct 2016 15:45:19 -0400 Subject: Add support for using documentation siphons in multiple ways Experiental support for generating multiple output formats from the same siphoned data. Adds a contrived example to generate a plain list of all CLI commands (the "itemlist" format). Eventually we can consider moving the tempate procesisng into the Output class as well as a way to override how the data is traversed (ordered). Change-Id: I77629a74a8fa0c7e583993469dc50491f72f13e7 Signed-off-by: Chris Luke --- doxygen/Makefile | 36 ++++-- doxygen/siphon-process | 6 +- doxygen/siphon/process.py | 79 +++++++++---- doxygen/siphon_templates/clicmd/index_entry.md | 17 --- doxygen/siphon_templates/clicmd/index_header.md | 130 --------------------- doxygen/siphon_templates/clicmd/item_format.md | 59 ---------- doxygen/siphon_templates/default/index_entry.md | 16 --- doxygen/siphon_templates/default/index_section.md | 18 --- doxygen/siphon_templates/default/item_format.md | 16 --- doxygen/siphon_templates/default/item_header.md | 18 --- .../itemlist/clicmd/item_format.itemlist | 17 +++ .../itemlist/default/index_entry.itemlist | 15 +++ .../itemlist/default/index_header.itemlist | 15 +++ .../itemlist/default/index_section.itemlist | 15 +++ .../itemlist/default/item_format.itemlist | 16 +++ .../itemlist/default/item_header.itemlist | 15 +++ .../itemlist/syscfg/item_format.itemlist | 17 +++ .../markdown/clicmd/index_entry.md | 17 +++ .../markdown/clicmd/index_header.md | 130 +++++++++++++++++++++ .../markdown/clicmd/item_format.md | 59 ++++++++++ .../markdown/default/index_entry.md | 16 +++ .../markdown/default/index_section.md | 18 +++ .../markdown/default/item_format.md | 16 +++ .../markdown/default/item_header.md | 18 +++ .../markdown/syscfg/index_header.md | 111 ++++++++++++++++++ .../markdown/syscfg/item_format.md | 42 +++++++ doxygen/siphon_templates/syscfg/index_header.md | 111 ------------------ doxygen/siphon_templates/syscfg/item_format.md | 42 ------- 28 files changed, 626 insertions(+), 459 deletions(-) delete mode 100644 doxygen/siphon_templates/clicmd/index_entry.md delete mode 100644 doxygen/siphon_templates/clicmd/index_header.md delete mode 100644 doxygen/siphon_templates/clicmd/item_format.md delete mode 100644 doxygen/siphon_templates/default/index_entry.md delete mode 100644 doxygen/siphon_templates/default/index_section.md delete mode 100644 doxygen/siphon_templates/default/item_format.md delete mode 100644 doxygen/siphon_templates/default/item_header.md create mode 100644 doxygen/siphon_templates/itemlist/clicmd/item_format.itemlist create mode 100644 doxygen/siphon_templates/itemlist/default/index_entry.itemlist create mode 100644 doxygen/siphon_templates/itemlist/default/index_header.itemlist create mode 100644 doxygen/siphon_templates/itemlist/default/index_section.itemlist create mode 100644 doxygen/siphon_templates/itemlist/default/item_format.itemlist create mode 100644 doxygen/siphon_templates/itemlist/default/item_header.itemlist create mode 100644 doxygen/siphon_templates/itemlist/syscfg/item_format.itemlist create mode 100644 doxygen/siphon_templates/markdown/clicmd/index_entry.md create mode 100644 doxygen/siphon_templates/markdown/clicmd/index_header.md create mode 100644 doxygen/siphon_templates/markdown/clicmd/item_format.md create mode 100644 doxygen/siphon_templates/markdown/default/index_entry.md create mode 100644 doxygen/siphon_templates/markdown/default/index_section.md create mode 100644 doxygen/siphon_templates/markdown/default/item_format.md create mode 100644 doxygen/siphon_templates/markdown/default/item_header.md create mode 100644 doxygen/siphon_templates/markdown/syscfg/index_header.md create mode 100644 doxygen/siphon_templates/markdown/syscfg/item_format.md delete mode 100644 doxygen/siphon_templates/syscfg/index_header.md delete mode 100644 doxygen/siphon_templates/syscfg/item_format.md (limited to 'doxygen/Makefile') diff --git a/doxygen/Makefile b/doxygen/Makefile index 7031e84d..92fa3635 100644 --- a/doxygen/Makefile +++ b/doxygen/Makefile @@ -121,6 +121,7 @@ SIPHONS ?= clicmd syscfg SIPHON_FILES = $(addprefix $(SIPHON_INPUT)/,$(addsuffix .siphon,$(SIPHONS))) SIPHON_DOCS = $(addprefix $(SIPHON_OUTPUT)/,$(addsuffix .md,$(SIPHONS))) +SIPHON_ITEMLIST = $(addprefix $(SIPHON_OUTPUT)/,$(addsuffix .itemlist,$(filter clicmd,$(SIPHONS)))) $(BR)/.doxygen-bootstrap.ok: Makefile @echo "Checking whether dependencies for Doxygen are installed..." @@ -200,24 +201,37 @@ $(SIPHON_FILES): $(BR)/.doxygen-bootstrap.ok \ --output="$(SIPHON_INPUT)" \ "@$(SIPHON_INPUT)/files" -# Process the .siphon source fragments and render them into doxygen flavored -# markdown documentation -.DELETE_ON_ERROR: $(SIPHON_DOCS) -$(SIPHON_OUTPUT)/%.md: $(SIPHON_INPUT)/%.siphon \ +# Evaluate this to build a siphon doc output target for each desired +# output type: +# $(eval $(call siphon-process,file_extension,output_type_name)) +define siphon-process +$(SIPHON_OUTPUT)/%.$(1): $(SIPHON_INPUT)/%.siphon \ $(DOXY_DIR)/siphon-process \ $(wildcard $(DOXY_DIR)/siphon/*.py) \ - $(wildcard $(DOXY_DIR)/siphon_templates/*/*.md) - @echo "Processing siphon from $(notdir $<)..." + $(wildcard $(DOXY_DIR)/siphon_templates/$(2)/*/*.$(1)) + @echo "Processing siphon for $(2) from $$(notdir $$<)..." @set -e; \ cd "$(WS_ROOT)"; \ $(DOXY_DIR)/siphon-process \ - --type=$(basename $(notdir $<)) \ - --output="$@" \ - "$<" + --type=$$(basename $$(notdir $$<)) \ + --format=$(2) \ + --output="$$@" \ + "$$<" +endef + +# Process the .siphon source fragments and render them into doxygen flavored +# markdown documentation +.DELETE_ON_ERROR: $(SIPHON_DOCS) +$(eval $(call siphon-process,md,markdown)) + +# Process the .siphon source fragments and render them into a list of cli +# commands. +.DELETE_ON_ERROR: $(SIPHON_ITEMLIST) +$(eval $(call siphon-process,itemlist,itemlist)) -# This target can be used just to generate the siphoned docs +# This target can be used just to generate the siphoned things .PHONY: doxygen-siphon -doxygen-siphon: $(SIPHON_DOCS) +doxygen-siphon: $(SIPHON_DOCS) $(SIPHON_ITEMLIST) # Generate the doxygen docs .PHONY: doxygen diff --git a/doxygen/siphon-process b/doxygen/siphon-process index ea9df96f..698da882 100755 --- a/doxygen/siphon-process +++ b/doxygen/siphon-process @@ -23,6 +23,7 @@ import siphon DEFAULT_LOGFILE = None DEFAULT_LOGLEVEL = "info" DEFAULT_SIPHON ="clicmd" +DEFAULT_FORMAT = "markdown" DEFAULT_OUTPUT = None DEFAULT_TEMPLATES = os.path.dirname(__file__) + "/siphon_templates" @@ -36,6 +37,9 @@ ap.add_argument("--log-level", default=DEFAULT_LOGLEVEL, ap.add_argument("--type", '-t', metavar="siphon_type", default=DEFAULT_SIPHON, choices=siphon.process.siphons.keys(), help="Siphon type to process [%s]" % DEFAULT_SIPHON) +ap.add_argument("--format", '-f', default=DEFAULT_FORMAT, + choices=siphon.process.formats.keys(), + help="Output format to generate [%s]" % DEFAULT_FORMAT) ap.add_argument("--output", '-o', metavar="file", default=DEFAULT_OUTPUT, help="Output file (uses stdout if not defined) [%s]" % DEFAULT_OUTPUT) ap.add_argument("--templates", metavar="directory", default=DEFAULT_TEMPLATES, @@ -56,7 +60,7 @@ else: # Get our processor klass = siphon.process.siphons[args.type] -processor = klass(template_directory=args.templates) +processor = klass(template_directory=args.templates, format=args.format) # Load the input files processor.load_json(args.input) diff --git a/doxygen/siphon/process.py b/doxygen/siphon/process.py index 34e829c5..f3119ea8 100644 --- a/doxygen/siphon/process.py +++ b/doxygen/siphon/process.py @@ -20,6 +20,9 @@ import logging, os,sys, cgi, json, jinja2, HTMLParser """Mapping of known processors to their classes""" siphons = {} +"""Mapping of known output formats to their classes""" +formats = {} + """Generate rendered output for siphoned data.""" class Siphon(object): @@ -51,28 +54,36 @@ class Siphon(object): """Template environment, if we're using templates""" _tplenv = None - def __init__(self, template_directory=None): + def __init__(self, template_directory, format): super(Siphon, self).__init__() self.log = logging.getLogger("siphon.process.%s" % self.name) - if template_directory is not None: - self.template_directory = template_directory - searchpath = [ - template_directory + "/" + self.name, - template_directory + "/" + "default", - ] - loader = jinja2.FileSystemLoader(searchpath=searchpath) - self._tplenv = jinja2.Environment( - loader=loader, - trim_blocks=True, - keep_trailing_newline=True) - - # Convenience, get a reference to the internal escape and - # unescape methods in cgi and HTMLParser. These then become - # available to templates to use, if needed. - self._h = HTMLParser.HTMLParser() - self.escape = cgi.escape - self.unescape = self._h.unescape + # Get our output format details + fmt_klass = formats[format] + fmt = fmt_klass() + self._format = fmt + + # Sort out the template search path + def _tpldir(name): + return os.sep.join((template_directory, fmt.name, name)) + + self.template_directory = template_directory + searchpath = [ + _tpldir(self.name), + _tpldir("default"), + ] + loader = jinja2.FileSystemLoader(searchpath=searchpath) + self._tplenv = jinja2.Environment( + loader=loader, + trim_blocks=True, + keep_trailing_newline=True) + + # Convenience, get a reference to the internal escape and + # unescape methods in cgi and HTMLParser. These then become + # available to templates to use, if needed. + self._h = HTMLParser.HTMLParser() + self.escape = cgi.escape + self.unescape = self._h.unescape # Output renderers @@ -157,7 +168,7 @@ class Siphon(object): """Template processor""" def template(self, name, **kwargs): - tpl = self._tplenv.get_template(name + ".md") + tpl = self._tplenv.get_template(name + self._format.extension) return tpl.render( this=self, **kwargs) @@ -270,3 +281,31 @@ class Siphon(object): # Deliver the accumulated body output out.write(contents) + + +"""Output format class""" +class Format(object): + + """Name of this output format""" + name = None + + """Expected file extension of templates that build this format""" + extension = None + + +"""Markdown output format""" +class FormatMarkdown(Format): + name = "markdown" + extension = ".md" + +# Register 'markdown' +formats["markdown"] = FormatMarkdown + + +"""Itemlist output format""" +class FormatItemlist(Format): + name = "itemlist" + extension = ".itemlist" + +# Register 'itemlist' +formats["itemlist"] = FormatItemlist diff --git a/doxygen/siphon_templates/clicmd/index_entry.md b/doxygen/siphon_templates/clicmd/index_entry.md deleted file mode 100644 index 1fa9ec9b..00000000 --- a/doxygen/siphon_templates/clicmd/index_entry.md +++ /dev/null @@ -1,17 +0,0 @@ -{# -# Copyright (c) 2016 Comcast Cable Communications Management, LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#} -{% set v = item['value'] %} -{{ "* [%s](@ref %s)" % (v['path'], meta["label"]) }} diff --git a/doxygen/siphon_templates/clicmd/index_header.md b/doxygen/siphon_templates/clicmd/index_header.md deleted file mode 100644 index 4167f4dc..00000000 --- a/doxygen/siphon_templates/clicmd/index_header.md +++ /dev/null @@ -1,130 +0,0 @@ -{# -# Copyright (c) 2016 Comcast Cable Communications Management, LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#} -# Debug CLI {{'{#'}}clicmd} - -The VPP network stack comes equipped with a set of commands that are useful -for debugging. - -The easiest way to access the CLI (with proper permissions) is to use the -vppctl command: - -``` -sudo vppctl -``` - -The CLI parser matches static keyword strings, eventually invoking an action -function. Unambiguous partial keyword matching always occurs. The action -functions consume input until satisfied or until they fail. This model makes -for easy coding, but does not guarantee useful "help" output. It's up to the -CLI command writer to add useful help strings. - -You can find the source code of CLI commands by searching for instances of the -@c VLIB_CLI_COMMAND macro in the code source files. - -Please help maintain and improve this document to make and keep these commands -clear and useful! - -@todo Document where to modify this CLI intro text. - - -## Debug and Telnet CLI - -The debug CLI is enabled with the unix interactive parameter or startup -configuration option. This causes VPP to start without daemonizing and -presents a command line interface on the terminal where it is run. - -The Telnet CLI is enabled with the `cli-listen localhost:5002` option which -will cause VPP to listen for TCP connections on the localhost address port -@c 5002. A Telnet client can then connect to this port (for example, `telnet -localhost 5002`) and will receive a command line prompt. - -This configuration will enable both mechanisms: - -``` -unix { - interactive - cli-listen localhost:5002 -} -``` - -The debug CLI can operate in line mode, which may be useful when running -inside an IDE like Emacs. This is enabled with the option -`unix cli-line-mode`. Several other options exist that alter how this -CLI works, see the @ref syscfg section for details. - -The CLI starts with a banner graphic (which can be disabled) and a prompt. The -prompt will typically read `vpp` for a release version of VPP and `DBGvpp#` -for a development version with debugging enabled, for example: - - _______ _ _ _____ ___ - __/ __/ _ \ (_)__ | | / / _ \/ _ \ - _/ _// // / / / _ \ | |/ / ___/ ___/ - /_/ /____(_)_/\___/ |___/_/ /_/ - - vpp# - -versus: - - _______ _ _ _____ ___ - __/ __/ _ \ (_)__ | | / / _ \/ _ \ - _/ _// // / / / _ \ | |/ / ___/ ___/ - /_/ /____(_)_/\___/ |___/_/ /_/ - - DBGvpp# - -This prompt can be configured with the `unix cli-prompt` setting and the -banner is disabled with `unix cli-no-banner`. - -## CLI features - -The CLI has several editing features that make it easy to use. - -- Cursor keys left/right will move the cursor within a command line; - typing will insert at the cursor; erase will erase at the cursor. - -- Ctrl-left/right will search for the start of the next word to - the left or right. -- Home/end will jump the cursor to the start and end of the line. -- Cursor keys up/down and ^P/^N iterate through the command history - buffer. Lines from the history buffer may be edited. New commands - are added to the end of the buffer when executed; though - duplicates of the previous command are not added. -- ^U erases the line contents from the left of the cursor to the - start. -- ^K erases the contents from the cursor to the end. -- ^S/^R will search the command history forwards or in reverse for - a command; start typing for matches to auto complete. -- ^L will clear the screen (if supported by the terminal) and repaint - the prompt and any current line. The cursor position is also - retained. -- The CLI can be closed with the quit command. Alternatively, ^D on - an empty input line will also close the session. Closing the debug - session will also shutdown VPP. - -Output that exceeds the length of a terminal page will be buffered, up to a -limit. - -- Space or page-down displays the next page. -- Enter or down-arrow displays the next line. -- Page-up goes back a page. -- Up-arrow goes up a line. -- Home/end jump to the start/end of the buffered output. -- The key q quits the pager. Space and enter will also quit the - pager if the end of the buffer has been reached. - -## Index of CLI commands - -[TOC] diff --git a/doxygen/siphon_templates/clicmd/item_format.md b/doxygen/siphon_templates/clicmd/item_format.md deleted file mode 100644 index 288dae40..00000000 --- a/doxygen/siphon_templates/clicmd/item_format.md +++ /dev/null @@ -1,59 +0,0 @@ -{# -# Copyright (c) 2016 Comcast Cable Communications Management, LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#} -{% set v = item['value'] %} -{{ "@section %s %s" % (meta['label'], v['path']) }} -{% if 'short_help' in v %} - -### Summary/usage - -{% set str = v['short_help'] %} -{% set period = "." if str[-1] != "." else "" %} -{% set prefix = " " if "[" in str or "<" in str or "|" in str else "" %} -{% set str = this.unescape(str) %} -{{ "%s%s%s" % (prefix, str, period) }} -{% endif %} -{% if 'long_help' in v %} -{# This is seldom used and will likely be deprecated #} - -### Long help - -{{ v['long_help'] }} -{% endif %} -{% if 'siphon_block' in item['meta'] %} -{% set sb = item["meta"]["siphon_block"] %} -{% if sb %} -{# Extracted from the code in /*? ... ?*/ blocks #} - -### Description - -{{ sb }} -{% endif %} -{% endif %} -{% if 'name' in meta or 'function' in v %} -{# Gives some developer-useful linking #} - -### Declaration and implementation -{% if "name" in meta %} - -{{ "Declaration: @ref %s (@ref %s line %d)" % - (meta['name'], meta["file"], item["meta"]["line_start"]) }} -{% endif %} -{% if "function" in v %} - -{{ "Implementation: @ref %s." % v["function"] }} -{% endif %} -{% endif %} - diff --git a/doxygen/siphon_templates/default/index_entry.md b/doxygen/siphon_templates/default/index_entry.md deleted file mode 100644 index 479dcdb2..00000000 --- a/doxygen/siphon_templates/default/index_entry.md +++ /dev/null @@ -1,16 +0,0 @@ -{# -# Copyright (c) 2016 Comcast Cable Communications Management, LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#} -{{ "* [%s](@ref %s)" % (item["name"], meta["label"]) }} diff --git a/doxygen/siphon_templates/default/index_section.md b/doxygen/siphon_templates/default/index_section.md deleted file mode 100644 index 3c9d2b47..00000000 --- a/doxygen/siphon_templates/default/index_section.md +++ /dev/null @@ -1,18 +0,0 @@ -{# -# Copyright (c) 2016 Comcast Cable Communications Management, LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#} - -@subpage {{ this.page_label(group) }} - diff --git a/doxygen/siphon_templates/default/item_format.md b/doxygen/siphon_templates/default/item_format.md deleted file mode 100644 index ed1b1bf7..00000000 --- a/doxygen/siphon_templates/default/item_format.md +++ /dev/null @@ -1,16 +0,0 @@ -{# -# Copyright (c) 2016 Comcast Cable Communications Management, LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#} -{{ raise NotImplementedError }} diff --git a/doxygen/siphon_templates/default/item_header.md b/doxygen/siphon_templates/default/item_header.md deleted file mode 100644 index 0c21e51f..00000000 --- a/doxygen/siphon_templates/default/item_header.md +++ /dev/null @@ -1,18 +0,0 @@ -{# -# Copyright (c) 2016 Comcast Cable Communications Management, LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#} - -{{ "@page %s %s" % (this.page_label(group), this.page_title(group)) }} - diff --git a/doxygen/siphon_templates/itemlist/clicmd/item_format.itemlist b/doxygen/siphon_templates/itemlist/clicmd/item_format.itemlist new file mode 100644 index 00000000..195c3780 --- /dev/null +++ b/doxygen/siphon_templates/itemlist/clicmd/item_format.itemlist @@ -0,0 +1,17 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} +{# Just output the command path #} +{{ item['value']['path'] }} diff --git a/doxygen/siphon_templates/itemlist/default/index_entry.itemlist b/doxygen/siphon_templates/itemlist/default/index_entry.itemlist new file mode 100644 index 00000000..3b2494fb --- /dev/null +++ b/doxygen/siphon_templates/itemlist/default/index_entry.itemlist @@ -0,0 +1,15 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} diff --git a/doxygen/siphon_templates/itemlist/default/index_header.itemlist b/doxygen/siphon_templates/itemlist/default/index_header.itemlist new file mode 100644 index 00000000..3b2494fb --- /dev/null +++ b/doxygen/siphon_templates/itemlist/default/index_header.itemlist @@ -0,0 +1,15 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} diff --git a/doxygen/siphon_templates/itemlist/default/index_section.itemlist b/doxygen/siphon_templates/itemlist/default/index_section.itemlist new file mode 100644 index 00000000..3b2494fb --- /dev/null +++ b/doxygen/siphon_templates/itemlist/default/index_section.itemlist @@ -0,0 +1,15 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} diff --git a/doxygen/siphon_templates/itemlist/default/item_format.itemlist b/doxygen/siphon_templates/itemlist/default/item_format.itemlist new file mode 100644 index 00000000..ed1b1bf7 --- /dev/null +++ b/doxygen/siphon_templates/itemlist/default/item_format.itemlist @@ -0,0 +1,16 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} +{{ raise NotImplementedError }} diff --git a/doxygen/siphon_templates/itemlist/default/item_header.itemlist b/doxygen/siphon_templates/itemlist/default/item_header.itemlist new file mode 100644 index 00000000..3b2494fb --- /dev/null +++ b/doxygen/siphon_templates/itemlist/default/item_header.itemlist @@ -0,0 +1,15 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} diff --git a/doxygen/siphon_templates/itemlist/syscfg/item_format.itemlist b/doxygen/siphon_templates/itemlist/syscfg/item_format.itemlist new file mode 100644 index 00000000..02320519 --- /dev/null +++ b/doxygen/siphon_templates/itemlist/syscfg/item_format.itemlist @@ -0,0 +1,17 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} +{# Just output the item name #} +{{ item['name'] }} diff --git a/doxygen/siphon_templates/markdown/clicmd/index_entry.md b/doxygen/siphon_templates/markdown/clicmd/index_entry.md new file mode 100644 index 00000000..1fa9ec9b --- /dev/null +++ b/doxygen/siphon_templates/markdown/clicmd/index_entry.md @@ -0,0 +1,17 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} +{% set v = item['value'] %} +{{ "* [%s](@ref %s)" % (v['path'], meta["label"]) }} diff --git a/doxygen/siphon_templates/markdown/clicmd/index_header.md b/doxygen/siphon_templates/markdown/clicmd/index_header.md new file mode 100644 index 00000000..4167f4dc --- /dev/null +++ b/doxygen/siphon_templates/markdown/clicmd/index_header.md @@ -0,0 +1,130 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} +# Debug CLI {{'{#'}}clicmd} + +The VPP network stack comes equipped with a set of commands that are useful +for debugging. + +The easiest way to access the CLI (with proper permissions) is to use the +vppctl command: + +``` +sudo vppctl +``` + +The CLI parser matches static keyword strings, eventually invoking an action +function. Unambiguous partial keyword matching always occurs. The action +functions consume input until satisfied or until they fail. This model makes +for easy coding, but does not guarantee useful "help" output. It's up to the +CLI command writer to add useful help strings. + +You can find the source code of CLI commands by searching for instances of the +@c VLIB_CLI_COMMAND macro in the code source files. + +Please help maintain and improve this document to make and keep these commands +clear and useful! + +@todo Document where to modify this CLI intro text. + + +## Debug and Telnet CLI + +The debug CLI is enabled with the unix interactive parameter or startup +configuration option. This causes VPP to start without daemonizing and +presents a command line interface on the terminal where it is run. + +The Telnet CLI is enabled with the `cli-listen localhost:5002` option which +will cause VPP to listen for TCP connections on the localhost address port +@c 5002. A Telnet client can then connect to this port (for example, `telnet +localhost 5002`) and will receive a command line prompt. + +This configuration will enable both mechanisms: + +``` +unix { + interactive + cli-listen localhost:5002 +} +``` + +The debug CLI can operate in line mode, which may be useful when running +inside an IDE like Emacs. This is enabled with the option +`unix cli-line-mode`. Several other options exist that alter how this +CLI works, see the @ref syscfg section for details. + +The CLI starts with a banner graphic (which can be disabled) and a prompt. The +prompt will typically read `vpp` for a release version of VPP and `DBGvpp#` +for a development version with debugging enabled, for example: + + _______ _ _ _____ ___ + __/ __/ _ \ (_)__ | | / / _ \/ _ \ + _/ _// // / / / _ \ | |/ / ___/ ___/ + /_/ /____(_)_/\___/ |___/_/ /_/ + + vpp# + +versus: + + _______ _ _ _____ ___ + __/ __/ _ \ (_)__ | | / / _ \/ _ \ + _/ _// // / / / _ \ | |/ / ___/ ___/ + /_/ /____(_)_/\___/ |___/_/ /_/ + + DBGvpp# + +This prompt can be configured with the `unix cli-prompt` setting and the +banner is disabled with `unix cli-no-banner`. + +## CLI features + +The CLI has several editing features that make it easy to use. + +- Cursor keys left/right will move the cursor within a command line; + typing will insert at the cursor; erase will erase at the cursor. + +- Ctrl-left/right will search for the start of the next word to + the left or right. +- Home/end will jump the cursor to the start and end of the line. +- Cursor keys up/down and ^P/^N iterate through the command history + buffer. Lines from the history buffer may be edited. New commands + are added to the end of the buffer when executed; though + duplicates of the previous command are not added. +- ^U erases the line contents from the left of the cursor to the + start. +- ^K erases the contents from the cursor to the end. +- ^S/^R will search the command history forwards or in reverse for + a command; start typing for matches to auto complete. +- ^L will clear the screen (if supported by the terminal) and repaint + the prompt and any current line. The cursor position is also + retained. +- The CLI can be closed with the quit command. Alternatively, ^D on + an empty input line will also close the session. Closing the debug + session will also shutdown VPP. + +Output that exceeds the length of a terminal page will be buffered, up to a +limit. + +- Space or page-down displays the next page. +- Enter or down-arrow displays the next line. +- Page-up goes back a page. +- Up-arrow goes up a line. +- Home/end jump to the start/end of the buffered output. +- The key q quits the pager. Space and enter will also quit the + pager if the end of the buffer has been reached. + +## Index of CLI commands + +[TOC] diff --git a/doxygen/siphon_templates/markdown/clicmd/item_format.md b/doxygen/siphon_templates/markdown/clicmd/item_format.md new file mode 100644 index 00000000..288dae40 --- /dev/null +++ b/doxygen/siphon_templates/markdown/clicmd/item_format.md @@ -0,0 +1,59 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} +{% set v = item['value'] %} +{{ "@section %s %s" % (meta['label'], v['path']) }} +{% if 'short_help' in v %} + +### Summary/usage + +{% set str = v['short_help'] %} +{% set period = "." if str[-1] != "." else "" %} +{% set prefix = " " if "[" in str or "<" in str or "|" in str else "" %} +{% set str = this.unescape(str) %} +{{ "%s%s%s" % (prefix, str, period) }} +{% endif %} +{% if 'long_help' in v %} +{# This is seldom used and will likely be deprecated #} + +### Long help + +{{ v['long_help'] }} +{% endif %} +{% if 'siphon_block' in item['meta'] %} +{% set sb = item["meta"]["siphon_block"] %} +{% if sb %} +{# Extracted from the code in /*? ... ?*/ blocks #} + +### Description + +{{ sb }} +{% endif %} +{% endif %} +{% if 'name' in meta or 'function' in v %} +{# Gives some developer-useful linking #} + +### Declaration and implementation +{% if "name" in meta %} + +{{ "Declaration: @ref %s (@ref %s line %d)" % + (meta['name'], meta["file"], item["meta"]["line_start"]) }} +{% endif %} +{% if "function" in v %} + +{{ "Implementation: @ref %s." % v["function"] }} +{% endif %} +{% endif %} + diff --git a/doxygen/siphon_templates/markdown/default/index_entry.md b/doxygen/siphon_templates/markdown/default/index_entry.md new file mode 100644 index 00000000..479dcdb2 --- /dev/null +++ b/doxygen/siphon_templates/markdown/default/index_entry.md @@ -0,0 +1,16 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} +{{ "* [%s](@ref %s)" % (item["name"], meta["label"]) }} diff --git a/doxygen/siphon_templates/markdown/default/index_section.md b/doxygen/siphon_templates/markdown/default/index_section.md new file mode 100644 index 00000000..3c9d2b47 --- /dev/null +++ b/doxygen/siphon_templates/markdown/default/index_section.md @@ -0,0 +1,18 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} + +@subpage {{ this.page_label(group) }} + diff --git a/doxygen/siphon_templates/markdown/default/item_format.md b/doxygen/siphon_templates/markdown/default/item_format.md new file mode 100644 index 00000000..ed1b1bf7 --- /dev/null +++ b/doxygen/siphon_templates/markdown/default/item_format.md @@ -0,0 +1,16 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} +{{ raise NotImplementedError }} diff --git a/doxygen/siphon_templates/markdown/default/item_header.md b/doxygen/siphon_templates/markdown/default/item_header.md new file mode 100644 index 00000000..0c21e51f --- /dev/null +++ b/doxygen/siphon_templates/markdown/default/item_header.md @@ -0,0 +1,18 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} + +{{ "@page %s %s" % (this.page_label(group), this.page_title(group)) }} + diff --git a/doxygen/siphon_templates/markdown/syscfg/index_header.md b/doxygen/siphon_templates/markdown/syscfg/index_header.md new file mode 100644 index 00000000..5d338a04 --- /dev/null +++ b/doxygen/siphon_templates/markdown/syscfg/index_header.md @@ -0,0 +1,111 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} +# Startup Configuration {{'{#'}}syscfg} + +The VPP network stack comes with several configuration options that can be +provided either on the command line or in a configuration file. + +Specific applications built on the stack have been known to require a dozen +arguments, depending on requirements. This section describes commonly-used +options and parameters. + +You can find command-line argument parsers in the source code by searching for +instances of the `VLIB_CONFIG_FUNCTION` macro. The invocation +`VLIB_CONFIG_FUNCTION(foo_config, "foo")` will cause the function +`foo_config` to receive all the options and values supplied in a parameter +block named "`foo`", for example: `foo { arg1 arg2 arg3 ... }`. + +@todo Tell the nice people where this document lives so that the might +help improve it! + +## Command-line arguments + +Parameters are grouped by a section name. When providing more than one +parameter to a section all parameters for that section must be wrapped in +curly braces. + +``` +/usr/bin/vpp unix { interactive cli-listen 127.0.0.1:5002 } +``` + +Which will produce output similar to this: + + + _______ _ _ _____ ___ + __/ __/ _ \ (_)__ | | / / _ \/ _ \ + _/ _// // / / / _ \ | |/ / ___/ ___/ + /_/ /____(_)_/\___/ |___/_/ /_/ + + vpp# + +When providing only one such parameter the braces are optional. For example, +the following command argument, `unix interactive` does not have braces: + +``` +/usr/bin/vpp unix interactive +``` + +The command line can be presented as a single string or as several; anything +given on the command line is concatenated with spaces into a single string +before parsing. + +VPP applications must be able to locate their own executable images. The +simplest way to ensure this will work is to invoke a VPP application by giving +its absolute path; for example: `/usr/bin/vpp `. At startup, VPP +applications parse through their own ELF-sections (primarily) to make lists +of init, configuration, and exit handlers. + +When developing with VPP, in _gdb_ it's often sufficient to start an application +like this at the `(gdb)` prompt: + +``` +run unix interactive +``` + +## Configuration file + +It is also possible to supply parameters in a startup configuration file the +path of which is provided to the VPP application on its command line. + +The format of the configuration file is a simple text file with the same +content as the command line but with the benefit of being able to use newlines +to make the content easier to read. For example: + +``` +unix { + nodaemon + log /tmp/vpp.log + full-coredump + cli-listen localhost:5002 +} +api-trace { + on +} +dpdk { + dev 0000:03:00.0 +} +``` + +VPP is then instructed to load this file with the `-c` option: + +``` +/usr/bin/vpp -c /etc/vpp/startup.conf +``` + +## Index of startup command sections + +[TOC] + diff --git a/doxygen/siphon_templates/markdown/syscfg/item_format.md b/doxygen/siphon_templates/markdown/syscfg/item_format.md new file mode 100644 index 00000000..53136115 --- /dev/null +++ b/doxygen/siphon_templates/markdown/syscfg/item_format.md @@ -0,0 +1,42 @@ +{# +# Copyright (c) 2016 Comcast Cable Communications Management, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#} +{% set v = item['value'] %} +{{ "@section %s %s" % (meta['label'], item['name']) }} +{% if 'siphon_block' in item['meta'] %} +{% set sb = item["meta"]["siphon_block"] %} +{% if sb %} +{# Extracted from the code in /*? ... ?*/ blocks #} + +### Description + +{{ sb }} +{% endif %} +{% endif %} +{% if "name" in meta or "function" in item %} +{# Gives some developer-useful linking #} + +### Declaration and implementation +{% if "name" in meta %} + +{{ "Declaration: @ref %s (@ref %s line %d)" % + (meta['name'], meta["file"], item["meta"]["line_start"]) }} +{% endif %} +{% if "function" in item %} + +{{ "Implementation: @ref %s." % item["function"] }} +{% endif %} +{% endif %} + diff --git a/doxygen/siphon_templates/syscfg/index_header.md b/doxygen/siphon_templates/syscfg/index_header.md deleted file mode 100644 index 5d338a04..00000000 --- a/doxygen/siphon_templates/syscfg/index_header.md +++ /dev/null @@ -1,111 +0,0 @@ -{# -# Copyright (c) 2016 Comcast Cable Communications Management, LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#} -# Startup Configuration {{'{#'}}syscfg} - -The VPP network stack comes with several configuration options that can be -provided either on the command line or in a configuration file. - -Specific applications built on the stack have been known to require a dozen -arguments, depending on requirements. This section describes commonly-used -options and parameters. - -You can find command-line argument parsers in the source code by searching for -instances of the `VLIB_CONFIG_FUNCTION` macro. The invocation -`VLIB_CONFIG_FUNCTION(foo_config, "foo")` will cause the function -`foo_config` to receive all the options and values supplied in a parameter -block named "`foo`", for example: `foo { arg1 arg2 arg3 ... }`. - -@todo Tell the nice people where this document lives so that the might -help improve it! - -## Command-line arguments - -Parameters are grouped by a section name. When providing more than one -parameter to a section all parameters for that section must be wrapped in -curly braces. - -``` -/usr/bin/vpp unix { interactive cli-listen 127.0.0.1:5002 } -``` - -Which will produce output similar to this: - - - _______ _ _ _____ ___ - __/ __/ _ \ (_)__ | | / / _ \/ _ \ - _/ _// // / / / _ \ | |/ / ___/ ___/ - /_/ /____(_)_/\___/ |___/_/ /_/ - - vpp# - -When providing only one such parameter the braces are optional. For example, -the following command argument, `unix interactive` does not have braces: - -``` -/usr/bin/vpp unix interactive -``` - -The command line can be presented as a single string or as several; anything -given on the command line is concatenated with spaces into a single string -before parsing. - -VPP applications must be able to locate their own executable images. The -simplest way to ensure this will work is to invoke a VPP application by giving -its absolute path; for example: `/usr/bin/vpp `. At startup, VPP -applications parse through their own ELF-sections (primarily) to make lists -of init, configuration, and exit handlers. - -When developing with VPP, in _gdb_ it's often sufficient to start an application -like this at the `(gdb)` prompt: - -``` -run unix interactive -``` - -## Configuration file - -It is also possible to supply parameters in a startup configuration file the -path of which is provided to the VPP application on its command line. - -The format of the configuration file is a simple text file with the same -content as the command line but with the benefit of being able to use newlines -to make the content easier to read. For example: - -``` -unix { - nodaemon - log /tmp/vpp.log - full-coredump - cli-listen localhost:5002 -} -api-trace { - on -} -dpdk { - dev 0000:03:00.0 -} -``` - -VPP is then instructed to load this file with the `-c` option: - -``` -/usr/bin/vpp -c /etc/vpp/startup.conf -``` - -## Index of startup command sections - -[TOC] - diff --git a/doxygen/siphon_templates/syscfg/item_format.md b/doxygen/siphon_templates/syscfg/item_format.md deleted file mode 100644 index 53136115..00000000 --- a/doxygen/siphon_templates/syscfg/item_format.md +++ /dev/null @@ -1,42 +0,0 @@ -{# -# Copyright (c) 2016 Comcast Cable Communications Management, LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#} -{% set v = item['value'] %} -{{ "@section %s %s" % (meta['label'], item['name']) }} -{% if 'siphon_block' in item['meta'] %} -{% set sb = item["meta"]["siphon_block"] %} -{% if sb %} -{# Extracted from the code in /*? ... ?*/ blocks #} - -### Description - -{{ sb }} -{% endif %} -{% endif %} -{% if "name" in meta or "function" in item %} -{# Gives some developer-useful linking #} - -### Declaration and implementation -{% if "name" in meta %} - -{{ "Declaration: @ref %s (@ref %s line %d)" % - (meta['name'], meta["file"], item["meta"]["line_start"]) }} -{% endif %} -{% if "function" in item %} - -{{ "Implementation: @ref %s." % item["function"] }} -{% endif %} -{% endif %} - -- cgit 1.2.3-korg From fdc62abdc113ea63dc867375bd49ef3043dcd290 Mon Sep 17 00:00:00 2001 From: Chris Luke Date: Wed, 28 Dec 2016 09:44:47 -0500 Subject: Repair Doxygen build infrastructure After Gerrit 4430 much of the documentation failed to build, but silently so it was easily missed; equally missing that several paths have been missing for a while. - Correct paths after directory tree changes. - Doxygen now bails when input paths don't exist. - Fix up some of the less deranged entries in the documentation index. - Exclude the LUA tree, its documentation is a mess. Change-Id: I35e6b433feee5e05bca772d93aa1635c724db734 Signed-off-by: Chris Luke --- README.md | 30 +++++++++++----------- doxygen/Makefile | 38 +++++++++++++++++++-------- doxygen/user_doc.md | 2 ++ src/vnet/bfd/bfd_doc.md | 4 ++- src/vnet/span/span.md | 65 ----------------------------------------------- src/vnet/span/span_doc.md | 65 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 112 insertions(+), 92 deletions(-) delete mode 100644 src/vnet/span/span.md create mode 100644 src/vnet/span/span_doc.md (limited to 'doxygen/Makefile') diff --git a/README.md b/README.md index cf43a4df..8520b395 100644 --- a/README.md +++ b/README.md @@ -30,22 +30,22 @@ Directory name | Description build-root | Build output directory doxygen | Documentation generator configuration dpdk | DPDK patches and build infrastructure - g2 | Event log visualization tool - perftool | Performance tool -@ref plugins | VPP bundled plugins directory -@ref svm | Shared virtual memory allocation library +@ref plugins | Not-yet-relocated VPP bundled plugins directory +@ref src | VPP source code +@ref src/plugins | VPP bundled plugins directory +@ref src/svm | Shared virtual memory allocation library + src/tests | Unit tests + src/vat | VPP API test program +@ref src/vlib | VPP application library +@ref src/vlibapi | VPP API library +@ref src/vlibmemory | VPP Memory management +@ref src/vlibsocket | VPP Socket I/O +@ref src/vnet | VPP networking +@ref src/vpp | VPP application +@ref src/vpp-api | VPP application API bindings +@ref src/vppinfra | VPP core library test | Unit tests -@ref vlib | VPP application library source -@ref vlib-api | VPP API library source -@ref vnet | VPP networking source -@ref vpp | VPP application source -@ref vpp-api | VPP application API source - vppapigen | VPP API generator source - vpp-api-test | VPP API test program source -@ref vppinfra | VPP core library source - -(If the page you are viewing is not generated by Doxygen then -ignore any @@ref labels in the above table.) +@ref vpp-api | Not-yet-relocated API bindings ## Getting started diff --git a/doxygen/Makefile b/doxygen/Makefile index 92fa3635..ffce3c13 100644 --- a/doxygen/Makefile +++ b/doxygen/Makefile @@ -42,13 +42,17 @@ DOC_MAC_PY_DEPENDS = pyparsing jinja2 DOXY_DIR ?= $(WS_ROOT)/doxygen # Primary source directories +DOXY_SRC ?= src DOXY_SRC_DIRECTORIES = \ - vppinfra \ - svm \ - vlib \ - vlib-api \ - vnet \ - vpp \ + $(DOXY_SRC)/vppinfra \ + $(DOXY_SRC)/svm \ + $(DOXY_SRC)/vlib \ + $(DOXY_SRC)/vlibapi \ + $(DOXY_SRC)/vlibmemory \ + $(DOXY_SRC)/vlibsocket \ + $(DOXY_SRC)/vnet \ + $(DOXY_SRC)/vpp \ + $(DOXY_SRC)/vpp-api \ vpp-api # Input directories and files @@ -56,6 +60,7 @@ DOXY_INPUT ?= \ $(wildcard $(WS_ROOT)/*.md) \ $(wildcard $(DOXY_DIR)/*.md) \ $(DOXY_SRC_DIRECTORIES) \ + $(DOXY_SRC)/plugins \ plugins # Strip leading workspace path from input names @@ -67,9 +72,10 @@ DOXY_INPUT := $(subst $(WS_ROOT)/,,$(DOXY_INPUT)) # there's a DPDK equivalent that conflicts. # These must be left-anchored paths for the regexp below to work. DOXY_EXCLUDE ?= \ - vlib/vlib/buffer.c \ - vlib/example \ - plugins/sample-plugin + $(DOXY_SRC)/vlib/vlib/buffer.c \ + $(DOXY_SRC)/vlib/example \ + plugins/sample-plugin \ + vpp-api/lua # Generate a regexp for filenames to exclude DOXY_EXCLUDE_REGEXP = ($(subst .,\.,$(shell echo '$(strip $(DOXY_EXCLUDE))' | sed -e 's/ /|/g'))) @@ -164,9 +170,11 @@ endif bootstrap-doxygen: $(BR)/.doxygen-bootstrap.ok .DELETE_ON_ERROR: $(BR)/.doxygen-siphon.dep -$(BR)/.doxygen-siphon.dep: Makefile +$(BR)/.doxygen-siphon.dep: Makefile \ + $(addprefix,$(WSROOT),$(DOXY_INPUT)) @echo "Building siphon dependencies..." - @set -e; rm -f "$@"; for input in $(DOXY_INPUT); do \ + @rm -f "$@"; for input in $(DOXY_INPUT); do \ + [ -e "$(WS_ROOT)/$$input" ] && \ find "$(WS_ROOT)/$$input" -type f \ \( -name '*.[ch]' -or -name '*.dox' \) -print \ | grep -v -E '^$(WS_ROOT)/$(DOXY_EXCLUDE_REGEXP)' \ @@ -182,7 +190,15 @@ $(BR)/.doxygen-siphon.dep: Makefile .NOTPARALLEL: $(SIPHON_FILES) $(SIPHON_FILES): $(BR)/.doxygen-bootstrap.ok \ $(DOXY_DIR)/siphon-generate \ + $(addprefix,$(WSROOT),$(DOXY_INPUT)) \ $(wildcard $(DOXY_DIR)/siphon/*.py) + @echo "Validating source tree..." + @set -e; for input in $(DOXY_INPUT); do \ + if [ ! -e "$(WS_ROOT)/$$input" ]; then \ + echo "ERROR: Input path '$$input' does not exist." >&2; \ + exit 1; \ + fi; \ + done @rm -rf "$(SIPHON_INPUT)" "$(SIPHON_OUTPUT)" @mkdir -p "$(SIPHON_INPUT)" "$(SIPHON_OUTPUT)" @touch $(SIPHON_INPUT)/files diff --git a/doxygen/user_doc.md b/doxygen/user_doc.md index 2e87c877..40303439 100644 --- a/doxygen/user_doc.md +++ b/doxygen/user_doc.md @@ -12,3 +12,5 @@ Several modules provide operational, dataplane-user focused documentation. - @subpage ioam_plugin_doc - @subpage lb_plugin_doc - @subpage flowperpkt_plugin_doc +- @subpage span_doc +- @subpage bfd_doc diff --git a/src/vnet/bfd/bfd_doc.md b/src/vnet/bfd/bfd_doc.md index 1333ed77..3e86b178 100644 --- a/src/vnet/bfd/bfd_doc.md +++ b/src/vnet/bfd/bfd_doc.md @@ -1 +1,3 @@ -TODO +# BFD Notes {#bfd_doc} + +@todo Someone needs to produce this or remove the stub file. diff --git a/src/vnet/span/span.md b/src/vnet/span/span.md deleted file mode 100644 index ee3f814f..00000000 --- a/src/vnet/span/span.md +++ /dev/null @@ -1,65 +0,0 @@ -# VPP SPAN implementation - -This is a memo intended to contain documentation of the VPP SPAN implementation. -Everything that is not directly obvious should come here. - - -## Switched Port Analyzer (SPAN) -Port mirroring is used on a network switch to send a copy of network packets seen on one switch port to a network monitoring connection on another switch port. -Can be used by network engineers or administrators to measure performnce, analyze and debug data or diagnose errors on a network. - -### RX traffic node -There is one static node to mirror incomming packets. -* span-input: Creates a copy of incomming buffer due to incomming buffers can be reused internally. - -Chaining: dpdk-input -> span-input -> -* original buffer is sent to ethernet-input for processing -* buffer copy is sent to interface-output - -### Configuration -SPAN supports the following CLI configuration commands: - -#### Enable/Disable SPAN (CLI) - set interface span [disable | destination ] - -: mirrored interface name -destination : monitoring interface name -disable: delete mirroring - -#### Enable/Disabl SPAN (API) -SPAN supports the following API configuration command: - sw_interface_span_enable_disable src GigabitEthernet0/8/0 dst GigabitEthernet0/9/0 - sw_interface_span_enable_disable src_sw_if_index 1 dst_sw_if_index 2 - -src/src_sw_if_index: mirrored interface name -dst/dst_sw_if_index: monitoring interface name - -#### Remove SPAN entry (API) -SPAN supports the following API configuration command: - sw_interface_span_enable_disable src_sw_if_index 1 dst_sw_if_index 2 disable - -src_sw_if_index: mirrored interface name -dst_sw_if_index: monitoring interface name - -### Configuration example - -Mirror all packets on interface GigabitEthernet0/10/0 to interface GigabitEthernet0/11/0. - -Configure IPv4 addresses on mirrored interface: -set interface ip address GigabitEthernet0/10/0 192.168.1.13/24 -set interface state GigabitEthernet0/10/0 up - -Configure IPv4 addresses on monitoring interface: -set interface ip address GigabitEthernet0/11/0 192.168.2.13/24 -set interface state GigabitEthernet0/11/0 up - -Configure SPAN -set span src GigabitEthernet0/10/0 dst GigabitEthernet0/11/0 - -### Operational data - -Active SPAN mirroring CLI show command: - show interfaces span - -Active SPAN mirroring API dump command: - sw_interface_span_dump diff --git a/src/vnet/span/span_doc.md b/src/vnet/span/span_doc.md new file mode 100644 index 00000000..46480b28 --- /dev/null +++ b/src/vnet/span/span_doc.md @@ -0,0 +1,65 @@ +# VPP SPAN implementation {#span_doc} + +This is a memo intended to contain documentation of the VPP SPAN implementation. +Everything that is not directly obvious should come here. + + +## Switched Port Analyzer (SPAN) +Port mirroring is used on a network switch to send a copy of network packets seen on one switch port to a network monitoring connection on another switch port. +Can be used by network engineers or administrators to measure performnce, analyze and debug data or diagnose errors on a network. + +### RX traffic node +There is one static node to mirror incomming packets. +* span-input: Creates a copy of incomming buffer due to incomming buffers can be reused internally. + +Chaining: dpdk-input -> span-input -> +* original buffer is sent to ethernet-input for processing +* buffer copy is sent to interface-output + +### Configuration +SPAN supports the following CLI configuration commands: + +#### Enable/Disable SPAN (CLI) + set interface span [disable | destination ] + +: mirrored interface name +destination : monitoring interface name +disable: delete mirroring + +#### Enable/Disabl SPAN (API) +SPAN supports the following API configuration command: + sw_interface_span_enable_disable src GigabitEthernet0/8/0 dst GigabitEthernet0/9/0 + sw_interface_span_enable_disable src_sw_if_index 1 dst_sw_if_index 2 + +src/src_sw_if_index: mirrored interface name +dst/dst_sw_if_index: monitoring interface name + +#### Remove SPAN entry (API) +SPAN supports the following API configuration command: + sw_interface_span_enable_disable src_sw_if_index 1 dst_sw_if_index 2 disable + +src_sw_if_index: mirrored interface name +dst_sw_if_index: monitoring interface name + +### Configuration example + +Mirror all packets on interface GigabitEthernet0/10/0 to interface GigabitEthernet0/11/0. + +Configure IPv4 addresses on mirrored interface: +set interface ip address GigabitEthernet0/10/0 192.168.1.13/24 +set interface state GigabitEthernet0/10/0 up + +Configure IPv4 addresses on monitoring interface: +set interface ip address GigabitEthernet0/11/0 192.168.2.13/24 +set interface state GigabitEthernet0/11/0 up + +Configure SPAN +set span src GigabitEthernet0/10/0 dst GigabitEthernet0/11/0 + +### Operational data + +Active SPAN mirroring CLI show command: + show interfaces span + +Active SPAN mirroring API dump command: + sw_interface_span_dump -- cgit 1.2.3-korg From cb034b9b374927c7552e36dcbc306d8456b2a0cb Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Wed, 28 Dec 2016 18:38:59 +0100 Subject: Move java,lua api and remaining plugins to src/ Change-Id: I1c3b87e886603678368428ae56a6bd3327cbc90d Signed-off-by: Damjan Marion --- .gitignore | 10 +- Makefile | 21 +- build-data/packages/plugins.mk | 34 - build-data/packages/vnet.mk | 47 - build-data/packages/vpp-api.mk | 9 - build-data/platforms.mk | 20 +- build-data/platforms/vpp.mk | 4 +- build-data/platforms/vpp_lite.mk | 2 +- build-root/deb/debian/.gitignore | 4 +- build-root/deb/debian/control | 16 +- build-root/packages/tools.mk | 2 +- build-root/rpm/vpp.spec | 70 +- build-root/scripts/find-api-core-contents | 2 +- build-root/scripts/find-dev-contents | 8 +- build-root/scripts/find-plugins-contents | 4 +- build-root/scripts/find-python-api-contents | 8 - build-root/scripts/find-vpp-api-java-contents | 8 + build-root/scripts/find-vpp-api-lua-contents | 6 + build-root/scripts/find-vpp-api-python-contents | 8 + doxygen/Makefile | 7 +- plugins/Makefile.am | 15 - plugins/acl-plugin/Makefile.am | 114 -- plugins/acl-plugin/acl/acl.api | 444 ----- plugins/acl-plugin/acl/acl.c | 1901 ------------------- plugins/acl-plugin/acl/acl.h | 148 -- plugins/acl-plugin/acl/acl_all_api_h.h | 321 ---- plugins/acl-plugin/acl/acl_msg_enum.h | 28 - plugins/acl-plugin/acl/acl_test.c | 1024 ---------- .../fd/vpp/jvpp/acl/test/AclExpectedDumpData.java | 135 -- .../jvpp/io/fd/vpp/jvpp/acl/test/AclTestData.java | 101 - .../io/fd/vpp/jvpp/acl/test/AclTestRequests.java | 141 -- .../io/fd/vpp/jvpp/acl/test/FutureApiTest.java | 68 - .../acl/jvpp/io/fd/vpp/jvpp/acl/test/Readme.txt | 1 - plugins/acl-plugin/acl/jvpp_acl.c | 124 -- plugins/acl-plugin/acl/jvpp_acl.h | 45 - plugins/acl-plugin/acl/l2sess.c | 243 --- plugins/acl-plugin/acl/l2sess.h | 150 -- plugins/acl-plugin/acl/l2sess_node.c | 816 -------- plugins/acl-plugin/acl/node_in.c | 168 -- plugins/acl-plugin/acl/node_in.h | 12 - plugins/acl-plugin/acl/node_out.c | 175 -- plugins/acl-plugin/acl/node_out.h | 12 - plugins/acl-plugin/configure.ac | 24 - plugins/acl-plugin/test/run-python | 28 - plugins/acl-plugin/test/run-scapy | 26 - plugins/acl-plugin/test/test_acl_plugin.py | 118 -- plugins/configure.ac | 5 - plugins/ioam-plugin/Makefile.am | 338 ---- plugins/ioam-plugin/configure.ac | 25 - plugins/ioam-plugin/ioam/dir.dox | 18 - plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.c | 232 --- plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.h | 47 - plugins/ioam-plugin/ioam/encap/ip6_ioam_pot.c | 276 --- plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.c | 109 -- plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.h | 70 - .../ioam/encap/ip6_ioam_seqno_analyse.c | 141 -- plugins/ioam-plugin/ioam/encap/ip6_ioam_trace.c | 438 ----- .../ioam-plugin/ioam/export-common/ioam_export.h | 616 ------ .../export-vxlan-gpe/vxlan_gpe_ioam_export.api | 42 - .../ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.c | 271 --- .../vxlan_gpe_ioam_export_all_api_h.h | 16 - .../vxlan_gpe_ioam_export_msg_enum.h | 28 - .../export-vxlan-gpe/vxlan_gpe_ioam_export_test.c | 215 --- .../vxlan_gpe_ioam_export_thread.c | 49 - .../ioam/export-vxlan-gpe/vxlan_gpe_node.c | 162 -- plugins/ioam-plugin/ioam/export/ioam_export.api | 42 - plugins/ioam-plugin/ioam/export/ioam_export.c | 282 --- .../ioam/export/ioam_export_all_api_h.h | 16 - .../ioam-plugin/ioam/export/ioam_export_msg_enum.h | 28 - plugins/ioam-plugin/ioam/export/ioam_export_test.c | 206 --- .../ioam-plugin/ioam/export/ioam_export_thread.c | 38 - plugins/ioam-plugin/ioam/export/jvpp_ioam_export.c | 124 -- plugins/ioam-plugin/ioam/export/jvpp_ioam_export.h | 45 - plugins/ioam-plugin/ioam/export/node.c | 151 -- plugins/ioam-plugin/ioam/ioam_plugin_doc.md | 464 ----- .../jvpp/ioamexport/test/IoamExportApiTest.java | 56 - .../jvpp/io/fd/vpp/jvpp/ioamexport/test/Readme.txt | 1 - .../fd/vpp/jvpp/ioampot/test/IoamPotApiTest.java | 75 - .../jvpp/io/fd/vpp/jvpp/ioampot/test/Readme.txt | 1 - .../vpp/jvpp/ioamtrace/test/IoamTraceApiTest.java | 77 - .../jvpp/io/fd/vpp/jvpp/ioamtrace/test/Readme.txt | 1 - plugins/ioam-plugin/ioam/lib-pot/jvpp_ioam_pot.c | 124 -- plugins/ioam-plugin/ioam/lib-pot/jvpp_ioam_pot.h | 45 - plugins/ioam-plugin/ioam/lib-pot/math64.h | 159 -- plugins/ioam-plugin/ioam/lib-pot/pot.api | 133 -- plugins/ioam-plugin/ioam/lib-pot/pot_all_api_h.h | 16 - plugins/ioam-plugin/ioam/lib-pot/pot_api.c | 292 --- plugins/ioam-plugin/ioam/lib-pot/pot_msg_enum.h | 28 - plugins/ioam-plugin/ioam/lib-pot/pot_test.c | 365 ---- plugins/ioam-plugin/ioam/lib-pot/pot_util.c | 445 ----- plugins/ioam-plugin/ioam/lib-pot/pot_util.h | 195 -- .../ioam-plugin/ioam/lib-trace/jvpp_ioam_trace.c | 124 -- .../ioam-plugin/ioam/lib-trace/jvpp_ioam_trace.h | 45 - plugins/ioam-plugin/ioam/lib-trace/trace.api | 92 - .../ioam-plugin/ioam/lib-trace/trace_all_api_h.h | 16 - plugins/ioam-plugin/ioam/lib-trace/trace_api.c | 252 --- .../ioam-plugin/ioam/lib-trace/trace_msg_enum.h | 28 - plugins/ioam-plugin/ioam/lib-trace/trace_test.c | 292 --- plugins/ioam-plugin/ioam/lib-trace/trace_util.c | 206 --- plugins/ioam-plugin/ioam/lib-trace/trace_util.h | 247 --- .../ioam-plugin/ioam/lib-vxlan-gpe/ioam_decap.c | 223 --- .../ioam-plugin/ioam/lib-vxlan-gpe/ioam_encap.c | 194 -- plugins/ioam-plugin/ioam/lib-vxlan-gpe/ioam_pop.c | 353 ---- .../ioam-plugin/ioam/lib-vxlan-gpe/ioam_transit.c | 188 -- .../ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe.api | 181 -- .../ioam/lib-vxlan-gpe/vxlan_gpe_all_api_h.h | 16 - .../ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_api.c | 378 ---- .../ioam/lib-vxlan-gpe/vxlan_gpe_ioam.c | 773 -------- .../ioam/lib-vxlan-gpe/vxlan_gpe_ioam.h | 183 -- .../ioam/lib-vxlan-gpe/vxlan_gpe_ioam_packet.h | 61 - .../ioam/lib-vxlan-gpe/vxlan_gpe_ioam_trace.c | 552 ------ .../ioam/lib-vxlan-gpe/vxlan_gpe_ioam_util.h | 172 -- .../ioam/lib-vxlan-gpe/vxlan_gpe_msg_enum.h | 28 - .../ioam/lib-vxlan-gpe/vxlan_gpe_test.c | 600 ------ plugins/lb-plugin/Makefile.am | 55 - plugins/lb-plugin/configure.ac | 9 - plugins/lb-plugin/lb/api.c | 228 --- plugins/lb-plugin/lb/cli.c | 250 --- plugins/lb-plugin/lb/lb.api | 71 - plugins/lb-plugin/lb/lb.c | 844 --------- plugins/lb-plugin/lb/lb.h | 333 ---- plugins/lb-plugin/lb/lb_test.c | 293 --- plugins/lb-plugin/lb/lbhash.h | 216 --- plugins/lb-plugin/lb/node.c | 419 ----- plugins/lb-plugin/lb/refcount.c | 41 - plugins/lb-plugin/lb/refcount.h | 67 - plugins/lb-plugin/lb/util.c | 72 - plugins/lb-plugin/lb/util.h | 40 - plugins/lb-plugin/lb_plugin_doc.md | 141 -- plugins/sample-plugin/Makefile.am | 56 - plugins/sample-plugin/configure.ac | 9 - plugins/sample-plugin/sample/node.c | 295 --- plugins/sample-plugin/sample/sample.api | 39 - plugins/sample-plugin/sample/sample.c | 255 --- plugins/sample-plugin/sample/sample.h | 40 - plugins/sample-plugin/sample/sample_all_api_h.h | 16 - plugins/sample-plugin/sample/sample_msg_enum.h | 28 - plugins/sample-plugin/sample/sample_test.c | 213 --- plugins/snat-plugin/Makefile.am | 113 -- plugins/snat-plugin/configure.ac | 32 - plugins/snat-plugin/snat/in2out.c | 1597 ---------------- .../io/fd/vpp/jvpp/snat/test/CallbackApiTest.java | 68 - .../snat/jvpp/io/fd/vpp/jvpp/snat/test/Readme.txt | 1 - plugins/snat-plugin/snat/jvpp_snat.c | 124 -- plugins/snat-plugin/snat/jvpp_snat.h | 45 - plugins/snat-plugin/snat/out2in.c | 1261 ------------- plugins/snat-plugin/snat/snat.api | 283 --- plugins/snat-plugin/snat/snat.c | 1957 -------------------- plugins/snat-plugin/snat/snat.h | 259 --- plugins/snat-plugin/snat/snat_all_api_h.h | 19 - plugins/snat-plugin/snat/snat_msg_enum.h | 31 - plugins/snat-plugin/snat/snat_test.c | 602 ------ src/Makefile.am | 10 +- src/configure.ac | 42 +- src/examples/sample-plugin/Makefile.am | 56 + src/examples/sample-plugin/configure.ac | 9 + src/examples/sample-plugin/sample/node.c | 295 +++ src/examples/sample-plugin/sample/sample.api | 39 + src/examples/sample-plugin/sample/sample.c | 255 +++ src/examples/sample-plugin/sample/sample.h | 40 + .../sample-plugin/sample/sample_all_api_h.h | 16 + .../sample-plugin/sample/sample_msg_enum.h | 28 + src/examples/sample-plugin/sample/sample_test.c | 213 +++ src/m4/ax_vpp_find_jdk8.m4 | 29 + src/plugins/Makefile.am | 18 + src/plugins/acl.am | 35 + src/plugins/acl/acl.api | 444 +++++ src/plugins/acl/acl.c | 1901 +++++++++++++++++++ src/plugins/acl/acl.h | 148 ++ src/plugins/acl/acl_all_api_h.h | 321 ++++ src/plugins/acl/acl_msg_enum.h | 28 + src/plugins/acl/acl_test.c | 1024 ++++++++++ src/plugins/acl/l2sess.c | 243 +++ src/plugins/acl/l2sess.h | 150 ++ src/plugins/acl/l2sess_node.c | 816 ++++++++ src/plugins/acl/node_in.c | 168 ++ src/plugins/acl/node_in.h | 12 + src/plugins/acl/node_out.c | 175 ++ src/plugins/acl/node_out.h | 12 + src/plugins/acl/test/run-python | 28 + src/plugins/acl/test/run-scapy | 26 + src/plugins/acl/test/test_acl_plugin.py | 118 ++ src/plugins/ioam.am | 150 ++ src/plugins/ioam/dir.dox | 18 + src/plugins/ioam/encap/ip6_ioam_e2e.c | 232 +++ src/plugins/ioam/encap/ip6_ioam_e2e.h | 47 + src/plugins/ioam/encap/ip6_ioam_pot.c | 276 +++ src/plugins/ioam/encap/ip6_ioam_seqno.c | 109 ++ src/plugins/ioam/encap/ip6_ioam_seqno.h | 70 + src/plugins/ioam/encap/ip6_ioam_seqno_analyse.c | 141 ++ src/plugins/ioam/encap/ip6_ioam_trace.c | 438 +++++ src/plugins/ioam/export-common/ioam_export.h | 616 ++++++ .../export-vxlan-gpe/vxlan_gpe_ioam_export.api | 42 + .../ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.c | 271 +++ .../vxlan_gpe_ioam_export_all_api_h.h | 16 + .../vxlan_gpe_ioam_export_msg_enum.h | 28 + .../export-vxlan-gpe/vxlan_gpe_ioam_export_test.c | 215 +++ .../vxlan_gpe_ioam_export_thread.c | 49 + src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_node.c | 162 ++ src/plugins/ioam/export/ioam_export.api | 42 + src/plugins/ioam/export/ioam_export.c | 282 +++ src/plugins/ioam/export/ioam_export_all_api_h.h | 16 + src/plugins/ioam/export/ioam_export_msg_enum.h | 28 + src/plugins/ioam/export/ioam_export_test.c | 206 +++ src/plugins/ioam/export/ioam_export_thread.c | 38 + src/plugins/ioam/export/node.c | 151 ++ src/plugins/ioam/ioam_plugin_doc.md | 464 +++++ src/plugins/ioam/lib-pot/math64.h | 159 ++ src/plugins/ioam/lib-pot/pot.api | 133 ++ src/plugins/ioam/lib-pot/pot_all_api_h.h | 16 + src/plugins/ioam/lib-pot/pot_api.c | 292 +++ src/plugins/ioam/lib-pot/pot_msg_enum.h | 28 + src/plugins/ioam/lib-pot/pot_test.c | 365 ++++ src/plugins/ioam/lib-pot/pot_util.c | 445 +++++ src/plugins/ioam/lib-pot/pot_util.h | 195 ++ src/plugins/ioam/lib-trace/trace.api | 92 + src/plugins/ioam/lib-trace/trace_all_api_h.h | 16 + src/plugins/ioam/lib-trace/trace_api.c | 252 +++ src/plugins/ioam/lib-trace/trace_msg_enum.h | 28 + src/plugins/ioam/lib-trace/trace_test.c | 292 +++ src/plugins/ioam/lib-trace/trace_util.c | 206 +++ src/plugins/ioam/lib-trace/trace_util.h | 247 +++ src/plugins/ioam/lib-vxlan-gpe/ioam_decap.c | 223 +++ src/plugins/ioam/lib-vxlan-gpe/ioam_encap.c | 194 ++ src/plugins/ioam/lib-vxlan-gpe/ioam_pop.c | 353 ++++ src/plugins/ioam/lib-vxlan-gpe/ioam_transit.c | 188 ++ src/plugins/ioam/lib-vxlan-gpe/ioam_vxlan_gpe.api | 181 ++ .../ioam/lib-vxlan-gpe/vxlan_gpe_all_api_h.h | 16 + src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_api.c | 378 ++++ src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.c | 773 ++++++++ src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.h | 183 ++ .../ioam/lib-vxlan-gpe/vxlan_gpe_ioam_packet.h | 61 + .../ioam/lib-vxlan-gpe/vxlan_gpe_ioam_trace.c | 552 ++++++ .../ioam/lib-vxlan-gpe/vxlan_gpe_ioam_util.h | 172 ++ .../ioam/lib-vxlan-gpe/vxlan_gpe_msg_enum.h | 28 + src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_test.c | 600 ++++++ src/plugins/lb.am | 42 + src/plugins/lb/api.c | 228 +++ src/plugins/lb/cli.c | 250 +++ src/plugins/lb/lb.api | 71 + src/plugins/lb/lb.c | 844 +++++++++ src/plugins/lb/lb.h | 333 ++++ src/plugins/lb/lb_plugin_doc.md | 141 ++ src/plugins/lb/lb_test.c | 293 +++ src/plugins/lb/lbhash.h | 216 +++ src/plugins/lb/node.c | 419 +++++ src/plugins/lb/refcount.c | 41 + src/plugins/lb/refcount.h | 67 + src/plugins/lb/util.c | 72 + src/plugins/lb/util.h | 40 + src/plugins/snat.am | 33 + src/plugins/snat/in2out.c | 1597 ++++++++++++++++ src/plugins/snat/out2in.c | 1261 +++++++++++++ src/plugins/snat/snat.api | 283 +++ src/plugins/snat/snat.c | 1957 ++++++++++++++++++++ src/plugins/snat/snat.h | 259 +++ src/plugins/snat/snat_all_api_h.h | 19 + src/plugins/snat/snat_msg_enum.h | 31 + src/plugins/snat/snat_test.c | 602 ++++++ src/suffix-rules.mk | 6 +- src/tools/g2/configure.ac | 12 - src/tools/perftool/configure.ac | 12 - src/tools/vppapigen/configure.ac | 14 - src/vpp-api/java/Makefile.am | 199 ++ src/vpp-api/java/Readme.txt | 236 +++ .../fd/vpp/jvpp/acl/test/AclExpectedDumpData.java | 135 ++ .../io/fd/vpp/jvpp/acl/test/AclTestData.java | 101 + .../io/fd/vpp/jvpp/acl/test/AclTestRequests.java | 141 ++ .../io/fd/vpp/jvpp/acl/test/FutureApiTest.java | 68 + .../jvpp-acl/io/fd/vpp/jvpp/acl/test/Readme.txt | 1 + src/vpp-api/java/jvpp-acl/jvpp_acl.c | 124 ++ src/vpp-api/java/jvpp-acl/jvpp_acl.h | 45 + src/vpp-api/java/jvpp-common/jvpp_common.c | 65 + src/vpp-api/java/jvpp-common/jvpp_common.h | 67 + .../io/fd/vpp/jvpp/core/test/CallbackApiTest.java | 96 + .../test/CallbackJVppFacadeNotificationTest.java | 87 + .../vpp/jvpp/core/test/CallbackJVppFacadeTest.java | 103 ++ .../core/test/CallbackNotificationApiTest.java | 94 + .../io/fd/vpp/jvpp/core/test/ControlPingTest.java | 68 + .../vpp/jvpp/core/test/CreateSubInterfaceTest.java | 120 ++ .../jvpp/core/test/FutureApiNotificationTest.java | 55 + .../io/fd/vpp/jvpp/core/test/FutureApiTest.java | 123 ++ .../io/fd/vpp/jvpp/core/test/L2AclTest.java | 195 ++ .../fd/vpp/jvpp/core/test/LispAdjacencyTest.java | 124 ++ .../fd/vpp/jvpp/core/test/NotificationUtils.java | 53 + .../jvpp-core/io/fd/vpp/jvpp/core/test/Readme.txt | 17 + src/vpp-api/java/jvpp-core/jvpp_core.c | 117 ++ .../jvpp/ioamexport/test/IoamExportApiTest.java | 56 + .../io/fd/vpp/jvpp/ioamexport/test/Readme.txt | 1 + .../java/jvpp-ioamexport/jvpp_ioam_export.c | 124 ++ .../java/jvpp-ioamexport/jvpp_ioam_export.h | 45 + .../fd/vpp/jvpp/ioampot/test/IoamPotApiTest.java | 75 + .../io/fd/vpp/jvpp/ioampot/test/Readme.txt | 1 + src/vpp-api/java/jvpp-ioampot/jvpp_ioam_pot.c | 124 ++ src/vpp-api/java/jvpp-ioampot/jvpp_ioam_pot.h | 45 + .../vpp/jvpp/ioamtrace/test/IoamTraceApiTest.java | 77 + .../io/fd/vpp/jvpp/ioamtrace/test/Readme.txt | 1 + src/vpp-api/java/jvpp-ioamtrace/jvpp_ioam_trace.c | 124 ++ src/vpp-api/java/jvpp-ioamtrace/jvpp_ioam_trace.h | 45 + .../java/jvpp-registry/io/fd/vpp/jvpp/JVpp.java | 56 + .../jvpp-registry/io/fd/vpp/jvpp/JVppRegistry.java | 76 + .../io/fd/vpp/jvpp/JVppRegistryImpl.java | 147 ++ .../io/fd/vpp/jvpp/NativeLibraryLoader.java | 73 + .../io/fd/vpp/jvpp/VppBaseCallException.java | 60 + .../io/fd/vpp/jvpp/VppCallbackException.java | 47 + .../io/fd/vpp/jvpp/VppConnection.java | 45 + .../io/fd/vpp/jvpp/VppInvocationException.java | 33 + .../io/fd/vpp/jvpp/VppJNIConnection.java | 137 ++ .../fd/vpp/jvpp/callback/ControlPingCallback.java | 29 + .../io/fd/vpp/jvpp/callback/JVppCallback.java | 29 + .../jvpp/callback/JVppNotificationCallback.java | 24 + .../io/fd/vpp/jvpp/dto/ControlPing.java | 34 + .../io/fd/vpp/jvpp/dto/ControlPingReply.java | 58 + .../jvpp-registry/io/fd/vpp/jvpp/dto/JVppDump.java | 24 + .../io/fd/vpp/jvpp/dto/JVppNotification.java | 23 + .../io/fd/vpp/jvpp/dto/JVppReply.java | 24 + .../io/fd/vpp/jvpp/dto/JVppReplyDump.java | 25 + .../io/fd/vpp/jvpp/dto/JVppRequest.java | 34 + .../vpp/jvpp/future/AbstractFutureJVppInvoker.java | 141 ++ .../io/fd/vpp/jvpp/future/FutureJVppInvoker.java | 49 + .../jvpp/notification/NotificationRegistry.java | 25 + .../notification/NotificationRegistryProvider.java | 28 + .../io/fd/vpp/jvpp/test/ConnectionTest.java | 44 + src/vpp-api/java/jvpp-registry/jvpp_registry.c | 352 ++++ .../io/fd/vpp/jvpp/snat/test/CallbackApiTest.java | 68 + .../jvpp-snat/io/fd/vpp/jvpp/snat/test/Readme.txt | 1 + src/vpp-api/java/jvpp-snat/jvpp_snat.c | 124 ++ src/vpp-api/java/jvpp-snat/jvpp_snat.h | 45 + src/vpp-api/java/jvpp/gen/jvpp_gen.py | 185 ++ src/vpp-api/java/jvpp/gen/jvppgen/__init__.py | 0 src/vpp-api/java/jvpp/gen/jvppgen/callback_gen.py | 105 ++ src/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py | 308 +++ src/vpp-api/java/jvpp/gen/jvppgen/jni_gen.py | 295 +++ src/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py | 343 ++++ .../jvpp/gen/jvppgen/jvpp_callback_facade_gen.py | 324 ++++ .../jvpp/gen/jvppgen/jvpp_future_facade_gen.py | 331 ++++ src/vpp-api/java/jvpp/gen/jvppgen/jvpp_impl_gen.py | 219 +++ .../java/jvpp/gen/jvppgen/notification_gen.py | 199 ++ src/vpp-api/java/jvpp/gen/jvppgen/types_gen.py | 227 +++ src/vpp-api/java/jvpp/gen/jvppgen/util.py | 220 +++ src/vpp-api/lua/README.md | 50 + src/vpp-api/lua/bench.lua | 70 + src/vpp-api/lua/examples/cli/README.md | 5 + src/vpp-api/lua/examples/cli/lua-cli.lua | 747 ++++++++ src/vpp-api/lua/examples/example-acl-plugin.lua | 110 ++ src/vpp-api/lua/examples/example-classifier.lua | 51 + src/vpp-api/lua/examples/example-cli.lua | 44 + src/vpp-api/lua/examples/lute/README.md | 66 + src/vpp-api/lua/examples/lute/lute.lua | 777 ++++++++ .../lua/examples/lute/script-inout-acl-noacl.lute | 329 ++++ .../lua/examples/lute/script-inout-acl-old.lute | 329 ++++ .../lua/examples/lute/script-inout-acl.lute | 329 ++++ src/vpp-api/lua/examples/lute/script.lute | 7 + src/vpp-api/lua/examples/lute/sessions-acl.lute | 308 +++ src/vpp-api/lua/vpp-lapi.lua | 989 ++++++++++ src/vpp.am | 2 +- src/vppapigen.am | 6 +- vpp-api/Makefile.am | 4 - vpp-api/configure.ac | 12 - vpp-api/java/Makefile.am | 116 -- vpp-api/java/Readme.txt | 236 --- vpp-api/java/configure.ac | 24 - vpp-api/java/jvpp-common/jvpp_common.c | 65 - vpp-api/java/jvpp-common/jvpp_common.h | 67 - .../io/fd/vpp/jvpp/core/test/CallbackApiTest.java | 96 - .../test/CallbackJVppFacadeNotificationTest.java | 87 - .../vpp/jvpp/core/test/CallbackJVppFacadeTest.java | 103 -- .../core/test/CallbackNotificationApiTest.java | 94 - .../io/fd/vpp/jvpp/core/test/ControlPingTest.java | 68 - .../vpp/jvpp/core/test/CreateSubInterfaceTest.java | 120 -- .../jvpp/core/test/FutureApiNotificationTest.java | 55 - .../io/fd/vpp/jvpp/core/test/FutureApiTest.java | 123 -- .../io/fd/vpp/jvpp/core/test/L2AclTest.java | 195 -- .../fd/vpp/jvpp/core/test/LispAdjacencyTest.java | 124 -- .../fd/vpp/jvpp/core/test/NotificationUtils.java | 53 - .../jvpp-core/io/fd/vpp/jvpp/core/test/Readme.txt | 17 - vpp-api/java/jvpp-core/jvpp_core.c | 117 -- .../java/jvpp-registry/io/fd/vpp/jvpp/JVpp.java | 56 - .../jvpp-registry/io/fd/vpp/jvpp/JVppRegistry.java | 76 - .../io/fd/vpp/jvpp/JVppRegistryImpl.java | 147 -- .../io/fd/vpp/jvpp/NativeLibraryLoader.java | 73 - .../io/fd/vpp/jvpp/VppBaseCallException.java | 60 - .../io/fd/vpp/jvpp/VppCallbackException.java | 47 - .../io/fd/vpp/jvpp/VppConnection.java | 45 - .../io/fd/vpp/jvpp/VppInvocationException.java | 33 - .../io/fd/vpp/jvpp/VppJNIConnection.java | 137 -- .../fd/vpp/jvpp/callback/ControlPingCallback.java | 29 - .../io/fd/vpp/jvpp/callback/JVppCallback.java | 29 - .../jvpp/callback/JVppNotificationCallback.java | 24 - .../io/fd/vpp/jvpp/dto/ControlPing.java | 34 - .../io/fd/vpp/jvpp/dto/ControlPingReply.java | 58 - .../jvpp-registry/io/fd/vpp/jvpp/dto/JVppDump.java | 24 - .../io/fd/vpp/jvpp/dto/JVppNotification.java | 23 - .../io/fd/vpp/jvpp/dto/JVppReply.java | 24 - .../io/fd/vpp/jvpp/dto/JVppReplyDump.java | 25 - .../io/fd/vpp/jvpp/dto/JVppRequest.java | 34 - .../vpp/jvpp/future/AbstractFutureJVppInvoker.java | 141 -- .../io/fd/vpp/jvpp/future/FutureJVppInvoker.java | 49 - .../jvpp/notification/NotificationRegistry.java | 25 - .../notification/NotificationRegistryProvider.java | 28 - .../io/fd/vpp/jvpp/test/ConnectionTest.java | 44 - vpp-api/java/jvpp-registry/jvpp_registry.c | 352 ---- vpp-api/java/jvpp/gen/jvpp_gen.py | 171 -- vpp-api/java/jvpp/gen/jvppgen/__init__.py | 0 vpp-api/java/jvpp/gen/jvppgen/callback_gen.py | 105 -- vpp-api/java/jvpp/gen/jvppgen/dto_gen.py | 308 --- vpp-api/java/jvpp/gen/jvppgen/jni_gen.py | 295 --- vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py | 343 ---- .../jvpp/gen/jvppgen/jvpp_callback_facade_gen.py | 324 ---- .../jvpp/gen/jvppgen/jvpp_future_facade_gen.py | 331 ---- vpp-api/java/jvpp/gen/jvppgen/jvpp_impl_gen.py | 219 --- vpp-api/java/jvpp/gen/jvppgen/notification_gen.py | 199 -- vpp-api/java/jvpp/gen/jvppgen/types_gen.py | 227 --- vpp-api/java/jvpp/gen/jvppgen/util.py | 220 --- vpp-api/java/m4/ax_check_java_home.m4 | 80 - vpp-api/java/m4/ax_check_java_plugin.m4 | 101 - vpp-api/java/m4/ax_java_check_class.m4 | 85 - vpp-api/java/m4/ax_java_options.m4 | 48 - vpp-api/java/m4/ax_libgcj_jar.m4 | 83 - vpp-api/java/m4/ax_prog_jar.m4 | 49 - vpp-api/java/m4/ax_prog_java.m4 | 115 -- vpp-api/java/m4/ax_prog_java_cc.m4 | 104 -- vpp-api/java/m4/ax_prog_java_works.m4 | 134 -- vpp-api/java/m4/ax_prog_javac.m4 | 79 - vpp-api/java/m4/ax_prog_javac_works.m4 | 72 - vpp-api/java/m4/ax_prog_javadoc.m4 | 50 - vpp-api/java/m4/ax_prog_javah.m4 | 64 - vpp-api/java/m4/ax_try_compile_java.m4 | 55 - vpp-api/java/m4/ax_try_run_java.m4 | 56 - vpp-api/lua/README.md | 50 - vpp-api/lua/bench.lua | 70 - vpp-api/lua/examples/cli/README.md | 5 - vpp-api/lua/examples/cli/lua-cli.lua | 747 -------- vpp-api/lua/examples/example-acl-plugin.lua | 110 -- vpp-api/lua/examples/example-classifier.lua | 51 - vpp-api/lua/examples/example-cli.lua | 44 - vpp-api/lua/examples/lute/README.md | 66 - vpp-api/lua/examples/lute/lute.lua | 777 -------- .../lua/examples/lute/script-inout-acl-noacl.lute | 329 ---- .../lua/examples/lute/script-inout-acl-old.lute | 329 ---- vpp-api/lua/examples/lute/script-inout-acl.lute | 329 ---- vpp-api/lua/examples/lute/script.lute | 7 - vpp-api/lua/examples/lute/sessions-acl.lute | 308 --- vpp-api/lua/vpp-lapi.lua | 989 ---------- 444 files changed, 38673 insertions(+), 40252 deletions(-) delete mode 100644 build-data/packages/plugins.mk delete mode 100644 build-data/packages/vnet.mk delete mode 100644 build-data/packages/vpp-api.mk delete mode 100755 build-root/scripts/find-python-api-contents create mode 100755 build-root/scripts/find-vpp-api-java-contents create mode 100755 build-root/scripts/find-vpp-api-lua-contents create mode 100755 build-root/scripts/find-vpp-api-python-contents delete mode 100644 plugins/acl-plugin/Makefile.am delete mode 100644 plugins/acl-plugin/acl/acl.api delete mode 100644 plugins/acl-plugin/acl/acl.c delete mode 100644 plugins/acl-plugin/acl/acl.h delete mode 100644 plugins/acl-plugin/acl/acl_all_api_h.h delete mode 100644 plugins/acl-plugin/acl/acl_msg_enum.h delete mode 100644 plugins/acl-plugin/acl/acl_test.c delete mode 100644 plugins/acl-plugin/acl/jvpp/io/fd/vpp/jvpp/acl/test/AclExpectedDumpData.java delete mode 100644 plugins/acl-plugin/acl/jvpp/io/fd/vpp/jvpp/acl/test/AclTestData.java delete mode 100644 plugins/acl-plugin/acl/jvpp/io/fd/vpp/jvpp/acl/test/AclTestRequests.java delete mode 100644 plugins/acl-plugin/acl/jvpp/io/fd/vpp/jvpp/acl/test/FutureApiTest.java delete mode 100644 plugins/acl-plugin/acl/jvpp/io/fd/vpp/jvpp/acl/test/Readme.txt delete mode 100644 plugins/acl-plugin/acl/jvpp_acl.c delete mode 100644 plugins/acl-plugin/acl/jvpp_acl.h delete mode 100644 plugins/acl-plugin/acl/l2sess.c delete mode 100644 plugins/acl-plugin/acl/l2sess.h delete mode 100644 plugins/acl-plugin/acl/l2sess_node.c delete mode 100644 plugins/acl-plugin/acl/node_in.c delete mode 100644 plugins/acl-plugin/acl/node_in.h delete mode 100644 plugins/acl-plugin/acl/node_out.c delete mode 100644 plugins/acl-plugin/acl/node_out.h delete mode 100644 plugins/acl-plugin/configure.ac delete mode 100755 plugins/acl-plugin/test/run-python delete mode 100755 plugins/acl-plugin/test/run-scapy delete mode 100644 plugins/acl-plugin/test/test_acl_plugin.py delete mode 100644 plugins/ioam-plugin/Makefile.am delete mode 100644 plugins/ioam-plugin/configure.ac delete mode 100644 plugins/ioam-plugin/ioam/dir.dox delete mode 100644 plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.c delete mode 100644 plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.h delete mode 100644 plugins/ioam-plugin/ioam/encap/ip6_ioam_pot.c delete mode 100644 plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.c delete mode 100644 plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.h delete mode 100644 plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno_analyse.c delete mode 100644 plugins/ioam-plugin/ioam/encap/ip6_ioam_trace.c delete mode 100644 plugins/ioam-plugin/ioam/export-common/ioam_export.h delete mode 100644 plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.api delete mode 100644 plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.c delete mode 100644 plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_all_api_h.h delete mode 100644 plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_msg_enum.h delete mode 100644 plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_test.c delete mode 100644 plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_thread.c delete mode 100644 plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_node.c delete mode 100644 plugins/ioam-plugin/ioam/export/ioam_export.api delete mode 100644 plugins/ioam-plugin/ioam/export/ioam_export.c delete mode 100644 plugins/ioam-plugin/ioam/export/ioam_export_all_api_h.h delete mode 100644 plugins/ioam-plugin/ioam/export/ioam_export_msg_enum.h delete mode 100644 plugins/ioam-plugin/ioam/export/ioam_export_test.c delete mode 100644 plugins/ioam-plugin/ioam/export/ioam_export_thread.c delete mode 100644 plugins/ioam-plugin/ioam/export/jvpp_ioam_export.c delete mode 100644 plugins/ioam-plugin/ioam/export/jvpp_ioam_export.h delete mode 100644 plugins/ioam-plugin/ioam/export/node.c delete mode 100644 plugins/ioam-plugin/ioam/ioam_plugin_doc.md delete mode 100644 plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioamexport/test/IoamExportApiTest.java delete mode 100644 plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioamexport/test/Readme.txt delete mode 100644 plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioampot/test/IoamPotApiTest.java delete mode 100644 plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioampot/test/Readme.txt delete mode 100644 plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioamtrace/test/IoamTraceApiTest.java delete mode 100644 plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioamtrace/test/Readme.txt delete mode 100644 plugins/ioam-plugin/ioam/lib-pot/jvpp_ioam_pot.c delete mode 100644 plugins/ioam-plugin/ioam/lib-pot/jvpp_ioam_pot.h delete mode 100644 plugins/ioam-plugin/ioam/lib-pot/math64.h delete mode 100644 plugins/ioam-plugin/ioam/lib-pot/pot.api delete mode 100644 plugins/ioam-plugin/ioam/lib-pot/pot_all_api_h.h delete mode 100644 plugins/ioam-plugin/ioam/lib-pot/pot_api.c delete mode 100644 plugins/ioam-plugin/ioam/lib-pot/pot_msg_enum.h delete mode 100644 plugins/ioam-plugin/ioam/lib-pot/pot_test.c delete mode 100644 plugins/ioam-plugin/ioam/lib-pot/pot_util.c delete mode 100644 plugins/ioam-plugin/ioam/lib-pot/pot_util.h delete mode 100644 plugins/ioam-plugin/ioam/lib-trace/jvpp_ioam_trace.c delete mode 100644 plugins/ioam-plugin/ioam/lib-trace/jvpp_ioam_trace.h delete mode 100644 plugins/ioam-plugin/ioam/lib-trace/trace.api delete mode 100644 plugins/ioam-plugin/ioam/lib-trace/trace_all_api_h.h delete mode 100644 plugins/ioam-plugin/ioam/lib-trace/trace_api.c delete mode 100644 plugins/ioam-plugin/ioam/lib-trace/trace_msg_enum.h delete mode 100644 plugins/ioam-plugin/ioam/lib-trace/trace_test.c delete mode 100644 plugins/ioam-plugin/ioam/lib-trace/trace_util.c delete mode 100644 plugins/ioam-plugin/ioam/lib-trace/trace_util.h delete mode 100644 plugins/ioam-plugin/ioam/lib-vxlan-gpe/ioam_decap.c delete mode 100644 plugins/ioam-plugin/ioam/lib-vxlan-gpe/ioam_encap.c delete mode 100644 plugins/ioam-plugin/ioam/lib-vxlan-gpe/ioam_pop.c delete mode 100644 plugins/ioam-plugin/ioam/lib-vxlan-gpe/ioam_transit.c delete mode 100644 plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe.api delete mode 100644 plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_all_api_h.h delete mode 100644 plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_api.c delete mode 100644 plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.c delete mode 100644 plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.h delete mode 100644 plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_packet.h delete mode 100644 plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_trace.c delete mode 100644 plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_util.h delete mode 100644 plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_msg_enum.h delete mode 100644 plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_test.c delete mode 100644 plugins/lb-plugin/Makefile.am delete mode 100644 plugins/lb-plugin/configure.ac delete mode 100644 plugins/lb-plugin/lb/api.c delete mode 100644 plugins/lb-plugin/lb/cli.c delete mode 100644 plugins/lb-plugin/lb/lb.api delete mode 100644 plugins/lb-plugin/lb/lb.c delete mode 100644 plugins/lb-plugin/lb/lb.h delete mode 100644 plugins/lb-plugin/lb/lb_test.c delete mode 100644 plugins/lb-plugin/lb/lbhash.h delete mode 100644 plugins/lb-plugin/lb/node.c delete mode 100644 plugins/lb-plugin/lb/refcount.c delete mode 100644 plugins/lb-plugin/lb/refcount.h delete mode 100644 plugins/lb-plugin/lb/util.c delete mode 100644 plugins/lb-plugin/lb/util.h delete mode 100644 plugins/lb-plugin/lb_plugin_doc.md delete mode 100644 plugins/sample-plugin/Makefile.am delete mode 100644 plugins/sample-plugin/configure.ac delete mode 100644 plugins/sample-plugin/sample/node.c delete mode 100644 plugins/sample-plugin/sample/sample.api delete mode 100644 plugins/sample-plugin/sample/sample.c delete mode 100644 plugins/sample-plugin/sample/sample.h delete mode 100644 plugins/sample-plugin/sample/sample_all_api_h.h delete mode 100644 plugins/sample-plugin/sample/sample_msg_enum.h delete mode 100644 plugins/sample-plugin/sample/sample_test.c delete mode 100644 plugins/snat-plugin/Makefile.am delete mode 100644 plugins/snat-plugin/configure.ac delete mode 100644 plugins/snat-plugin/snat/in2out.c delete mode 100644 plugins/snat-plugin/snat/jvpp/io/fd/vpp/jvpp/snat/test/CallbackApiTest.java delete mode 100644 plugins/snat-plugin/snat/jvpp/io/fd/vpp/jvpp/snat/test/Readme.txt delete mode 100644 plugins/snat-plugin/snat/jvpp_snat.c delete mode 100644 plugins/snat-plugin/snat/jvpp_snat.h delete mode 100644 plugins/snat-plugin/snat/out2in.c delete mode 100644 plugins/snat-plugin/snat/snat.api delete mode 100644 plugins/snat-plugin/snat/snat.c delete mode 100644 plugins/snat-plugin/snat/snat.h delete mode 100644 plugins/snat-plugin/snat/snat_all_api_h.h delete mode 100644 plugins/snat-plugin/snat/snat_msg_enum.h delete mode 100644 plugins/snat-plugin/snat/snat_test.c create mode 100644 src/examples/sample-plugin/Makefile.am create mode 100644 src/examples/sample-plugin/configure.ac create mode 100644 src/examples/sample-plugin/sample/node.c create mode 100644 src/examples/sample-plugin/sample/sample.api create mode 100644 src/examples/sample-plugin/sample/sample.c create mode 100644 src/examples/sample-plugin/sample/sample.h create mode 100644 src/examples/sample-plugin/sample/sample_all_api_h.h create mode 100644 src/examples/sample-plugin/sample/sample_msg_enum.h create mode 100644 src/examples/sample-plugin/sample/sample_test.c create mode 100644 src/m4/ax_vpp_find_jdk8.m4 create mode 100644 src/plugins/acl.am create mode 100644 src/plugins/acl/acl.api create mode 100644 src/plugins/acl/acl.c create mode 100644 src/plugins/acl/acl.h create mode 100644 src/plugins/acl/acl_all_api_h.h create mode 100644 src/plugins/acl/acl_msg_enum.h create mode 100644 src/plugins/acl/acl_test.c create mode 100644 src/plugins/acl/l2sess.c create mode 100644 src/plugins/acl/l2sess.h create mode 100644 src/plugins/acl/l2sess_node.c create mode 100644 src/plugins/acl/node_in.c create mode 100644 src/plugins/acl/node_in.h create mode 100644 src/plugins/acl/node_out.c create mode 100644 src/plugins/acl/node_out.h create mode 100755 src/plugins/acl/test/run-python create mode 100755 src/plugins/acl/test/run-scapy create mode 100644 src/plugins/acl/test/test_acl_plugin.py create mode 100644 src/plugins/ioam.am create mode 100644 src/plugins/ioam/dir.dox create mode 100644 src/plugins/ioam/encap/ip6_ioam_e2e.c create mode 100644 src/plugins/ioam/encap/ip6_ioam_e2e.h create mode 100644 src/plugins/ioam/encap/ip6_ioam_pot.c create mode 100644 src/plugins/ioam/encap/ip6_ioam_seqno.c create mode 100644 src/plugins/ioam/encap/ip6_ioam_seqno.h create mode 100644 src/plugins/ioam/encap/ip6_ioam_seqno_analyse.c create mode 100644 src/plugins/ioam/encap/ip6_ioam_trace.c create mode 100644 src/plugins/ioam/export-common/ioam_export.h create mode 100644 src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.api create mode 100644 src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.c create mode 100644 src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_all_api_h.h create mode 100644 src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_msg_enum.h create mode 100644 src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_test.c create mode 100644 src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_thread.c create mode 100644 src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_node.c create mode 100644 src/plugins/ioam/export/ioam_export.api create mode 100644 src/plugins/ioam/export/ioam_export.c create mode 100644 src/plugins/ioam/export/ioam_export_all_api_h.h create mode 100644 src/plugins/ioam/export/ioam_export_msg_enum.h create mode 100644 src/plugins/ioam/export/ioam_export_test.c create mode 100644 src/plugins/ioam/export/ioam_export_thread.c create mode 100644 src/plugins/ioam/export/node.c create mode 100644 src/plugins/ioam/ioam_plugin_doc.md create mode 100644 src/plugins/ioam/lib-pot/math64.h create mode 100644 src/plugins/ioam/lib-pot/pot.api create mode 100644 src/plugins/ioam/lib-pot/pot_all_api_h.h create mode 100644 src/plugins/ioam/lib-pot/pot_api.c create mode 100644 src/plugins/ioam/lib-pot/pot_msg_enum.h create mode 100644 src/plugins/ioam/lib-pot/pot_test.c create mode 100644 src/plugins/ioam/lib-pot/pot_util.c create mode 100644 src/plugins/ioam/lib-pot/pot_util.h create mode 100644 src/plugins/ioam/lib-trace/trace.api create mode 100644 src/plugins/ioam/lib-trace/trace_all_api_h.h create mode 100644 src/plugins/ioam/lib-trace/trace_api.c create mode 100644 src/plugins/ioam/lib-trace/trace_msg_enum.h create mode 100644 src/plugins/ioam/lib-trace/trace_test.c create mode 100644 src/plugins/ioam/lib-trace/trace_util.c create mode 100644 src/plugins/ioam/lib-trace/trace_util.h create mode 100644 src/plugins/ioam/lib-vxlan-gpe/ioam_decap.c create mode 100644 src/plugins/ioam/lib-vxlan-gpe/ioam_encap.c create mode 100644 src/plugins/ioam/lib-vxlan-gpe/ioam_pop.c create mode 100644 src/plugins/ioam/lib-vxlan-gpe/ioam_transit.c create mode 100644 src/plugins/ioam/lib-vxlan-gpe/ioam_vxlan_gpe.api create mode 100644 src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_all_api_h.h create mode 100644 src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_api.c create mode 100644 src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.c create mode 100644 src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.h create mode 100644 src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_packet.h create mode 100644 src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_trace.c create mode 100644 src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_util.h create mode 100644 src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_msg_enum.h create mode 100644 src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_test.c create mode 100644 src/plugins/lb.am create mode 100644 src/plugins/lb/api.c create mode 100644 src/plugins/lb/cli.c create mode 100644 src/plugins/lb/lb.api create mode 100644 src/plugins/lb/lb.c create mode 100644 src/plugins/lb/lb.h create mode 100644 src/plugins/lb/lb_plugin_doc.md create mode 100644 src/plugins/lb/lb_test.c create mode 100644 src/plugins/lb/lbhash.h create mode 100644 src/plugins/lb/node.c create mode 100644 src/plugins/lb/refcount.c create mode 100644 src/plugins/lb/refcount.h create mode 100644 src/plugins/lb/util.c create mode 100644 src/plugins/lb/util.h create mode 100644 src/plugins/snat.am create mode 100644 src/plugins/snat/in2out.c create mode 100644 src/plugins/snat/out2in.c create mode 100644 src/plugins/snat/snat.api create mode 100644 src/plugins/snat/snat.c create mode 100644 src/plugins/snat/snat.h create mode 100644 src/plugins/snat/snat_all_api_h.h create mode 100644 src/plugins/snat/snat_msg_enum.h create mode 100644 src/plugins/snat/snat_test.c delete mode 100644 src/tools/g2/configure.ac delete mode 100644 src/tools/perftool/configure.ac delete mode 100644 src/tools/vppapigen/configure.ac create mode 100644 src/vpp-api/java/Makefile.am create mode 100644 src/vpp-api/java/Readme.txt create mode 100644 src/vpp-api/java/jvpp-acl/io/fd/vpp/jvpp/acl/test/AclExpectedDumpData.java create mode 100644 src/vpp-api/java/jvpp-acl/io/fd/vpp/jvpp/acl/test/AclTestData.java create mode 100644 src/vpp-api/java/jvpp-acl/io/fd/vpp/jvpp/acl/test/AclTestRequests.java create mode 100644 src/vpp-api/java/jvpp-acl/io/fd/vpp/jvpp/acl/test/FutureApiTest.java create mode 100644 src/vpp-api/java/jvpp-acl/io/fd/vpp/jvpp/acl/test/Readme.txt create mode 100644 src/vpp-api/java/jvpp-acl/jvpp_acl.c create mode 100644 src/vpp-api/java/jvpp-acl/jvpp_acl.h create mode 100644 src/vpp-api/java/jvpp-common/jvpp_common.c create mode 100644 src/vpp-api/java/jvpp-common/jvpp_common.h create mode 100644 src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackApiTest.java create mode 100644 src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackJVppFacadeNotificationTest.java create mode 100644 src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackJVppFacadeTest.java create mode 100644 src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackNotificationApiTest.java create mode 100644 src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/ControlPingTest.java create mode 100644 src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CreateSubInterfaceTest.java create mode 100644 src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/FutureApiNotificationTest.java create mode 100644 src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/FutureApiTest.java create mode 100644 src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/L2AclTest.java create mode 100644 src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/LispAdjacencyTest.java create mode 100644 src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/NotificationUtils.java create mode 100644 src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/Readme.txt create mode 100644 src/vpp-api/java/jvpp-core/jvpp_core.c create mode 100644 src/vpp-api/java/jvpp-ioamexport/io/fd/vpp/jvpp/ioamexport/test/IoamExportApiTest.java create mode 100644 src/vpp-api/java/jvpp-ioamexport/io/fd/vpp/jvpp/ioamexport/test/Readme.txt create mode 100644 src/vpp-api/java/jvpp-ioamexport/jvpp_ioam_export.c create mode 100644 src/vpp-api/java/jvpp-ioamexport/jvpp_ioam_export.h create mode 100644 src/vpp-api/java/jvpp-ioampot/io/fd/vpp/jvpp/ioampot/test/IoamPotApiTest.java create mode 100644 src/vpp-api/java/jvpp-ioampot/io/fd/vpp/jvpp/ioampot/test/Readme.txt create mode 100644 src/vpp-api/java/jvpp-ioampot/jvpp_ioam_pot.c create mode 100644 src/vpp-api/java/jvpp-ioampot/jvpp_ioam_pot.h create mode 100644 src/vpp-api/java/jvpp-ioamtrace/io/fd/vpp/jvpp/ioamtrace/test/IoamTraceApiTest.java create mode 100644 src/vpp-api/java/jvpp-ioamtrace/io/fd/vpp/jvpp/ioamtrace/test/Readme.txt create mode 100644 src/vpp-api/java/jvpp-ioamtrace/jvpp_ioam_trace.c create mode 100644 src/vpp-api/java/jvpp-ioamtrace/jvpp_ioam_trace.h create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVpp.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVppRegistry.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVppRegistryImpl.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/NativeLibraryLoader.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppBaseCallException.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppCallbackException.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppConnection.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppInvocationException.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppJNIConnection.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/ControlPingCallback.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/JVppCallback.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/JVppNotificationCallback.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/ControlPing.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/ControlPingReply.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppDump.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppNotification.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppReply.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppReplyDump.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppRequest.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/future/AbstractFutureJVppInvoker.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/future/FutureJVppInvoker.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/notification/NotificationRegistry.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/notification/NotificationRegistryProvider.java create mode 100644 src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/test/ConnectionTest.java create mode 100644 src/vpp-api/java/jvpp-registry/jvpp_registry.c create mode 100644 src/vpp-api/java/jvpp-snat/io/fd/vpp/jvpp/snat/test/CallbackApiTest.java create mode 100644 src/vpp-api/java/jvpp-snat/io/fd/vpp/jvpp/snat/test/Readme.txt create mode 100644 src/vpp-api/java/jvpp-snat/jvpp_snat.c create mode 100644 src/vpp-api/java/jvpp-snat/jvpp_snat.h create mode 100755 src/vpp-api/java/jvpp/gen/jvpp_gen.py create mode 100644 src/vpp-api/java/jvpp/gen/jvppgen/__init__.py create mode 100644 src/vpp-api/java/jvpp/gen/jvppgen/callback_gen.py create mode 100644 src/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py create mode 100644 src/vpp-api/java/jvpp/gen/jvppgen/jni_gen.py create mode 100644 src/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py create mode 100644 src/vpp-api/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py create mode 100644 src/vpp-api/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py create mode 100644 src/vpp-api/java/jvpp/gen/jvppgen/jvpp_impl_gen.py create mode 100644 src/vpp-api/java/jvpp/gen/jvppgen/notification_gen.py create mode 100644 src/vpp-api/java/jvpp/gen/jvppgen/types_gen.py create mode 100644 src/vpp-api/java/jvpp/gen/jvppgen/util.py create mode 100644 src/vpp-api/lua/README.md create mode 100644 src/vpp-api/lua/bench.lua create mode 100644 src/vpp-api/lua/examples/cli/README.md create mode 100644 src/vpp-api/lua/examples/cli/lua-cli.lua create mode 100644 src/vpp-api/lua/examples/example-acl-plugin.lua create mode 100644 src/vpp-api/lua/examples/example-classifier.lua create mode 100644 src/vpp-api/lua/examples/example-cli.lua create mode 100644 src/vpp-api/lua/examples/lute/README.md create mode 100644 src/vpp-api/lua/examples/lute/lute.lua create mode 100644 src/vpp-api/lua/examples/lute/script-inout-acl-noacl.lute create mode 100644 src/vpp-api/lua/examples/lute/script-inout-acl-old.lute create mode 100644 src/vpp-api/lua/examples/lute/script-inout-acl.lute create mode 100644 src/vpp-api/lua/examples/lute/script.lute create mode 100644 src/vpp-api/lua/examples/lute/sessions-acl.lute create mode 100644 src/vpp-api/lua/vpp-lapi.lua delete mode 100644 vpp-api/Makefile.am delete mode 100644 vpp-api/configure.ac delete mode 100644 vpp-api/java/Makefile.am delete mode 100644 vpp-api/java/Readme.txt delete mode 100644 vpp-api/java/configure.ac delete mode 100644 vpp-api/java/jvpp-common/jvpp_common.c delete mode 100644 vpp-api/java/jvpp-common/jvpp_common.h delete mode 100644 vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackApiTest.java delete mode 100644 vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackJVppFacadeNotificationTest.java delete mode 100644 vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackJVppFacadeTest.java delete mode 100644 vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackNotificationApiTest.java delete mode 100644 vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/ControlPingTest.java delete mode 100644 vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CreateSubInterfaceTest.java delete mode 100644 vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/FutureApiNotificationTest.java delete mode 100644 vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/FutureApiTest.java delete mode 100644 vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/L2AclTest.java delete mode 100644 vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/LispAdjacencyTest.java delete mode 100644 vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/NotificationUtils.java delete mode 100644 vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/Readme.txt delete mode 100644 vpp-api/java/jvpp-core/jvpp_core.c delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVpp.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVppRegistry.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVppRegistryImpl.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/NativeLibraryLoader.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppBaseCallException.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppCallbackException.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppConnection.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppInvocationException.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppJNIConnection.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/ControlPingCallback.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/JVppCallback.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/JVppNotificationCallback.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/ControlPing.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/ControlPingReply.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppDump.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppNotification.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppReply.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppReplyDump.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppRequest.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/future/AbstractFutureJVppInvoker.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/future/FutureJVppInvoker.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/notification/NotificationRegistry.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/notification/NotificationRegistryProvider.java delete mode 100644 vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/test/ConnectionTest.java delete mode 100644 vpp-api/java/jvpp-registry/jvpp_registry.c delete mode 100755 vpp-api/java/jvpp/gen/jvpp_gen.py delete mode 100644 vpp-api/java/jvpp/gen/jvppgen/__init__.py delete mode 100644 vpp-api/java/jvpp/gen/jvppgen/callback_gen.py delete mode 100644 vpp-api/java/jvpp/gen/jvppgen/dto_gen.py delete mode 100644 vpp-api/java/jvpp/gen/jvppgen/jni_gen.py delete mode 100644 vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py delete mode 100644 vpp-api/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py delete mode 100644 vpp-api/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py delete mode 100644 vpp-api/java/jvpp/gen/jvppgen/jvpp_impl_gen.py delete mode 100644 vpp-api/java/jvpp/gen/jvppgen/notification_gen.py delete mode 100644 vpp-api/java/jvpp/gen/jvppgen/types_gen.py delete mode 100644 vpp-api/java/jvpp/gen/jvppgen/util.py delete mode 100644 vpp-api/java/m4/ax_check_java_home.m4 delete mode 100644 vpp-api/java/m4/ax_check_java_plugin.m4 delete mode 100644 vpp-api/java/m4/ax_java_check_class.m4 delete mode 100644 vpp-api/java/m4/ax_java_options.m4 delete mode 100644 vpp-api/java/m4/ax_libgcj_jar.m4 delete mode 100644 vpp-api/java/m4/ax_prog_jar.m4 delete mode 100644 vpp-api/java/m4/ax_prog_java.m4 delete mode 100644 vpp-api/java/m4/ax_prog_java_cc.m4 delete mode 100644 vpp-api/java/m4/ax_prog_java_works.m4 delete mode 100644 vpp-api/java/m4/ax_prog_javac.m4 delete mode 100644 vpp-api/java/m4/ax_prog_javac_works.m4 delete mode 100644 vpp-api/java/m4/ax_prog_javadoc.m4 delete mode 100644 vpp-api/java/m4/ax_prog_javah.m4 delete mode 100644 vpp-api/java/m4/ax_try_compile_java.m4 delete mode 100644 vpp-api/java/m4/ax_try_run_java.m4 delete mode 100644 vpp-api/lua/README.md delete mode 100644 vpp-api/lua/bench.lua delete mode 100644 vpp-api/lua/examples/cli/README.md delete mode 100644 vpp-api/lua/examples/cli/lua-cli.lua delete mode 100644 vpp-api/lua/examples/example-acl-plugin.lua delete mode 100644 vpp-api/lua/examples/example-classifier.lua delete mode 100644 vpp-api/lua/examples/example-cli.lua delete mode 100644 vpp-api/lua/examples/lute/README.md delete mode 100644 vpp-api/lua/examples/lute/lute.lua delete mode 100644 vpp-api/lua/examples/lute/script-inout-acl-noacl.lute delete mode 100644 vpp-api/lua/examples/lute/script-inout-acl-old.lute delete mode 100644 vpp-api/lua/examples/lute/script-inout-acl.lute delete mode 100644 vpp-api/lua/examples/lute/script.lute delete mode 100644 vpp-api/lua/examples/lute/sessions-acl.lute delete mode 100644 vpp-api/lua/vpp-lapi.lua (limited to 'doxygen/Makefile') diff --git a/.gitignore b/.gitignore index c12eedfb..61c407ff 100644 --- a/.gitignore +++ b/.gitignore @@ -80,11 +80,11 @@ GTAGS *.pyc # Python api generator -/vpp-api/python/build -/vpp-api/python/dist -/vpp-api/python/vpp_papi.egg-info -/vpp-api/python/vpp_papi/memclnt.py -/vpp-api/python/vpp_papi/vpe.py +/src/vpp-api/python/build +/src/vpp-api/python/dist +/src/vpp-api/python/vpp_papi.egg-info +/src/vpp-api/python/vpp_papi/memclnt.py +/src/vpp-api/python/vpp_papi/vpe.py # Build files in the test directory /test/*.ok diff --git a/Makefile b/Makefile index eeb9837a..9187404c 100644 --- a/Makefile +++ b/Makefile @@ -57,7 +57,7 @@ endif .PHONY: help bootstrap wipe wipe-release build build-release rebuild rebuild-release .PHONY: run run-release debug debug-release build-vat run-vat pkg-deb pkg-rpm -.PHONY: ctags cscope plugins plugins-release build-vpp-api +.PHONY: ctags cscope .PHONY: test test-debug retest retest-debug test-doc test-wipe-doc test-help test-wipe .PHONY: test-cov test-wipe-cov @@ -69,8 +69,6 @@ help: @echo " wipe-release - wipe all products of release build " @echo " build - build debug binaries" @echo " build-release - build release binaries" - @echo " plugins - build debug plugin binaries" - @echo " plugins-release - build release plugin binaries" @echo " rebuild - wipe and build debug binares" @echo " rebuild-release - wipe and build release binares" @echo " run - run debug binary" @@ -83,8 +81,6 @@ help: @echo " retest - run functional tests" @echo " retest-debug - run functional tests (debug build)" @echo " test-help - show help on test framework" - @echo " build-vat - build vpp-api-test tool" - @echo " build-vpp-api - build vpp-api" @echo " run-vat - run vpp-api-test tool" @echo " pkg-deb - build DEB packages" @echo " pkg-rpm - build RPM packages" @@ -206,19 +202,10 @@ wipe-release: $(BR)/.bootstrap.ok rebuild-release: wipe-release build-release -plugins: $(BR)/.bootstrap.ok - $(call make,$(PLATFORM)_debug,plugins-install) - -plugins-release: $(BR)/.bootstrap.ok - $(call make,$(PLATFORM),plugins-install) - -build-vpp-api: $(BR)/.bootstrap.ok - $(call make,$(PLATFORM)_debug,vpp-api-install) - VPP_PYTHON_PREFIX=$(BR)/python define test - $(if $(filter-out $(3),retest),make -C $(BR) PLATFORM=$(1) TAG=$(2) vpp-api-install plugins-install vpp-install,) + $(if $(filter-out $(3),retest),make -C $(BR) PLATFORM=$(1) TAG=$(2) vpp-install,) make -C test \ BR=$(BR) \ VPP_TEST_BUILD_DIR=$(BR)/build-$(2)-native \ @@ -265,12 +252,12 @@ define run @echo "WARNING: STARTUP_CONF not defined or file doesn't exist." @echo " Running with minimal startup config: $(MINIMAL_STARTUP_CONF)\n" @cd $(STARTUP_DIR) && \ - sudo $(2) $(1)/vpp/bin/vpp $(MINIMAL_STARTUP_CONF) plugin_path $(1)/plugins/lib64/vpp_plugins + sudo $(2) $(1)/vpp/bin/vpp $(MINIMAL_STARTUP_CONF) plugin_path $(1)/vpp/lib64/vpp_plugins endef else define run @cd $(STARTUP_DIR) && \ - sudo $(2) $(1)/vpp/bin/vpp $(shell cat $(STARTUP_CONF) | sed -e 's/#.*//') plugin_path $(1)/plugins/lib64/vpp_plugins + sudo $(2) $(1)/vpp/bin/vpp $(shell cat $(STARTUP_CONF) | sed -e 's/#.*//') plugin_path $(1)/vpp/lib64/vpp_plugins endef endif diff --git a/build-data/packages/plugins.mk b/build-data/packages/plugins.mk deleted file mode 100644 index b4d67a28..00000000 --- a/build-data/packages/plugins.mk +++ /dev/null @@ -1,34 +0,0 @@ -plugins_configure_depend = \ - vpp-api-install \ - vpp-install - -plugins_CPPFLAGS = $(call installed_includes_fn, \ - vpp \ - vpp-api) - -plugins_LDFLAGS = $(call installed_libs_fn, \ - vpp) - -ifeq ($($(PLATFORM)_enable_tests),yes) -plugins_configure_args += --enable-tests -endif - -# Platform dependent configure flags -plugins_configure_args += $(plugins_configure_args_$(PLATFORM)) - -# include & link with openssl only if needed -ifneq ($($(PLATFORM)_uses_openssl),no) -plugins_CPPFLAGS += $(call installed_includes_fn, openssl) -plugins_LDFLAGS += $(call installed_libs_fn, openssl) -endif - -ifneq ($($(PLATFORM)_uses_dpdk),no) -ifeq ($($(PLATFORM)_uses_external_dpdk),yes) -plugins_CPPFLAGS += -I$($(PLATFORM)_dpdk_inc_dir) -plugins_LDFLAGS += -L$($(PLATFORM)_dpdk_lib_dir) -else -plugins_configure_depend += dpdk-install -plugins_CPPFLAGS += $(call installed_includes_fn, dpdk) -plugins_LDFLAGS += $(call installed_libs_fn, dpdk) -endif -endif diff --git a/build-data/packages/vnet.mk b/build-data/packages/vnet.mk deleted file mode 100644 index 57c444e8..00000000 --- a/build-data/packages/vnet.mk +++ /dev/null @@ -1,47 +0,0 @@ -vnet_configure_depend = \ - vppinfra-install \ - svm-install \ - vlib-api-install \ - vlib-install - -vnet_CPPFLAGS = $(call installed_includes_fn, \ - vppinfra \ - svm \ - vlib \ - vlib-api) - -vnet_LDFLAGS = $(call installed_libs_fn, \ - vppinfra \ - svm \ - vlib \ - vlib-api) - -ifeq ($($(PLATFORM)_enable_tests),yes) -vnet_configure_args += --enable-tests -endif - -# Platform dependent configure flags -vnet_configure_args += $(vnet_configure_args_$(PLATFORM)) - -# include & link with openssl only if needed -ifneq ($($(PLATFORM)_uses_openssl),no) -vnet_CPPFLAGS += $(call installed_includes_fn, openssl) -vnet_LDFLAGS += $(call installed_libs_fn, openssl) -endif - -ifneq ($($(PLATFORM)_uses_dpdk),no) -ifeq ($($(PLATFORM)_uses_external_dpdk),yes) -vnet_CPPFLAGS += -I$($(PLATFORM)_dpdk_inc_dir) -vnet_LDFLAGS += -L$($(PLATFORM)_dpdk_lib_dir) -else -vnet_configure_depend += dpdk-install -vnet_CPPFLAGS += $(call installed_includes_fn, dpdk) -vnet_LDFLAGS += $(call installed_libs_fn, dpdk) -endif -ifeq ($($(PLATFORM)_uses_dpdk_cryptodev),yes) -vnet_configure_args += --with-dpdk-crypto -endif -ifeq ($($(PLATFORM)_uses_dpdk_mlx5_pmd),yes) -vnet_configure_args += --with-dpdk-mlx5-pmd -endif -endif diff --git a/build-data/packages/vpp-api.mk b/build-data/packages/vpp-api.mk deleted file mode 100644 index d9e8d72e..00000000 --- a/build-data/packages/vpp-api.mk +++ /dev/null @@ -1,9 +0,0 @@ -vpp-api_configure_depend = \ - vpp-install - -vpp-api_CPPFLAGS = $(call installed_includes_fn, \ - vpp) - -vpp-api_LDFLAGS = - -vpp-api_CPPFLAGS += -I/usr/lib/jvm/java-8-openjdk-amd64/include diff --git a/build-data/platforms.mk b/build-data/platforms.mk index 88dd3ed8..6f21b6dc 100644 --- a/build-data/platforms.mk +++ b/build-data/platforms.mk @@ -25,7 +25,7 @@ install-deb: $(patsubst %,%-find-source,$(ROOT_PACKAGES)) \ : generate file manifests ; \ find $(INSTALL_PREFIX)$(ARCH)/*/bin -type f -print \ - | sed -e 's:.*:../& /usr/bin:' \ + | sed -e 's:.*:../& /usr/bin:' | grep -v vppapigen \ > deb/debian/vpp.install ; \ \ : core api definitions ; \ @@ -51,9 +51,17 @@ install-deb: $(patsubst %,%-find-source,$(ROOT_PACKAGES)) ./scripts/find-plugins-contents $(INSTALL_PREFIX)$(ARCH) \ deb/debian/vpp-plugins.install ; \ \ - : python-api package ; \ - ./scripts/find-python-api-contents $(INSTALL_PREFIX)$(ARCH) \ - deb/debian/vpp-python-api.install ; \ + : vpp-api-lua package ; \ + ./scripts/find-vpp-api-lua-contents $(INSTALL_PREFIX)$(ARCH) \ + deb/debian/vpp-api-lua.install ; \ + \ + : vpp-api-java package ; \ + ./scripts/find-vpp-api-java-contents $(INSTALL_PREFIX)$(ARCH) \ + deb/debian/vpp-api-java.install ; \ + \ + : vpp-api-python package ; \ + ./scripts/find-vpp-api-python-contents $(INSTALL_PREFIX)$(ARCH) \ + deb/debian/vpp-api-python.install ; \ \ : dpdk headers ; \ ./scripts/find-dpdk-contents $(INSTALL_PREFIX)$(ARCH) \ @@ -70,9 +78,9 @@ install-deb: $(patsubst %,%-find-source,$(ROOT_PACKAGES)) : dev package needs a couple of additions ; \ echo ../build-tool-native/tools/vppapigen /usr/bin \ >> deb/debian/vpp-dev.install ; \ - echo ../../vpp-api/java/jvpp/gen/jvpp_gen.py /usr/bin \ + echo ../../src/vpp-api/java/jvpp/gen/jvpp_gen.py /usr/bin \ >> deb/debian/vpp-dev.install ; \ - for i in $$(ls ../vpp-api/java/jvpp/gen/jvppgen/*.py); do \ + for i in $$(ls ../src/vpp-api/java/jvpp/gen/jvppgen/*.py); do \ echo ../$${i} /usr/lib/python2.7/dist-packages/jvppgen \ >> deb/debian/vpp-dev.install; \ done; \ diff --git a/build-data/platforms/vpp.mk b/build-data/platforms/vpp.mk index 513a4db4..c9a214ac 100644 --- a/build-data/platforms/vpp.mk +++ b/build-data/platforms/vpp.mk @@ -29,15 +29,13 @@ vpp_uses_dpdk = yes # Uncoment to enable building unit tests # vpp_enable_tests = yes -vpp_root_packages = vpp vpp-api gmod plugins +vpp_root_packages = vpp gmod vpp_configure_args_vpp = --with-dpdk # Set these parameters carefully. The vlib_buffer_t is 128 bytes, i.e. vlib_configure_args_vpp = --with-pre-data=128 -plugins_configure_args_vpp = --with-dpdk - # DPDK configuration parameters # vpp_uses_dpdk_cryptodev = yes # vpp_uses_dpdk_mlx5_pmd = yes diff --git a/build-data/platforms/vpp_lite.mk b/build-data/platforms/vpp_lite.mk index 55805d10..a556b487 100644 --- a/build-data/platforms/vpp_lite.mk +++ b/build-data/platforms/vpp_lite.mk @@ -27,7 +27,7 @@ vpp_lite_uses_dpdk = no # Uncoment to enable building unit tests #vpp_lite_enable_tests = yes -vpp_lite_root_packages = vpp vpp-api gmod +vpp_lite_root_packages = vpp gmod vlib_configure_args_vpp_lite = --with-pre-data=128 diff --git a/build-root/deb/debian/.gitignore b/build-root/deb/debian/.gitignore index 75d8fbbc..c5e915a8 100644 --- a/build-root/deb/debian/.gitignore +++ b/build-root/deb/debian/.gitignore @@ -11,4 +11,6 @@ vpp-dpdk-dev/ vpp-dpdk-dkms/ vpp-dbg/ vppctl/ -vpp-python-api/ +vpp-api-lua/ +vpp-api-java/ +vpp-api-python/ diff --git a/build-root/deb/debian/control b/build-root/deb/debian/control index 643774e3..de48c903 100644 --- a/build-root/deb/debian/control +++ b/build-root/deb/debian/control @@ -60,7 +60,21 @@ Depends: ${shlibs:Depends}, ${misc:Depends} Description: DPDK 2.1 igb_uio_driver This package contains Linux kernel modules distributed with DPDK. -Package: vpp-python-api +Package: vpp-api-lua +Architecture: any +Depends: ${python:Depends}, ${misc:Depends}, vpp (= ${source:Version}) +Description: VPP LUA API bindings + This package contains VPP lua api bindings + . + +Package: vpp-api-java +Architecture: any +Depends: ${python:Depends}, ${misc:Depends}, vpp (= ${source:Version}) +Description: VPP Java API bindings + This package contains VPP java api bindings + . + +Package: vpp-api-python Architecture: any Depends: ${python:Depends}, ${misc:Depends}, vpp (= ${source:Version}) Description: VPP Python API bindings diff --git a/build-root/packages/tools.mk b/build-root/packages/tools.mk index 506e024b..d64a7959 100644 --- a/build-root/packages/tools.mk +++ b/build-root/packages/tools.mk @@ -1,3 +1,3 @@ tools_source = src -tools_configure_args = --disable-vlib +tools_configure_args = --disable-vlib --disable-svm --disable-japi diff --git a/build-root/rpm/vpp.spec b/build-root/rpm/vpp.spec index 654424c0..149ac51c 100644 --- a/build-root/rpm/vpp.spec +++ b/build-root/rpm/vpp.spec @@ -71,12 +71,28 @@ Requires: vpp = %{_version}-%{_release} %description plugins This package contains VPP plugins -%package python-api +%package api-lua +Summary: VPP api lua bindings +Group: Development/Libraries +Requires: vpp = %{_version}-%{_release}, vpp-lib = %{_version}-%{_release} + +%description api-lua +This package contains the lua bindings for the vpp api + +%package api-java +Summary: VPP api java bindings +Group: Development/Libraries +Requires: vpp = %{_version}-%{_release}, vpp-lib = %{_version}-%{_release} + +%description api-java +This package contains the java bindings for the vpp api + +%package api-python Summary: VPP api python bindings Group: Development/Libraries Requires: vpp = %{_version}-%{_release}, vpp-lib = %{_version}-%{_release}, python-setuptools -%description python-api +%description api-python This package contains the python bindings for the vpp api %prep @@ -131,6 +147,22 @@ do install -p -m 644 $file %{buildroot}/usr/share/vpp/api done +# Lua bindings +mkdir -p -m755 %{buildroot}/usr/share/doc/vpp/examples/lua/examples/cli +mkdir -p -m755 %{buildroot}/usr/share/doc/vpp/examples/lua/examples/lute +for file in $(cd %{_mu_build_dir}/%{_vpp_install_dir}/../../src/vpp-api/lua && git ls-files .) +do + install -p -m 644 %{_mu_build_dir}/%{_vpp_install_dir}/../../src/vpp-api/lua/$file \ + %{buildroot}/usr/share/doc/vpp/examples/lua/$file +done + +# Java bindings +mkdir -p -m755 %{buildroot}/usr/share/java +for file in $(find %{_mu_build_dir}/%{_vpp_install_dir}/vpp/share/java -type f -name '*.jar' -print ) +do + install -p -m 644 $file %{buildroot}/usr/share/java +done + # Python bindings mkdir -p -m755 %{buildroot}%{python2_sitelib} install -p -m 666 %{_mu_build_dir}/%{_vpp_install_dir}/*/lib/python2.7/site-packages/vpp_papi-*.egg %{buildroot}%{python2_sitelib} @@ -151,16 +183,16 @@ do done mkdir -p -m755 %{buildroot}%{python2_sitelib}/jvppgen -install -p -m755 %{_mu_build_dir}/../vpp-api/java/jvpp/gen/jvpp_gen.py %{buildroot}/usr/bin -for i in $(ls %{_mu_build_dir}/../vpp-api/java/jvpp/gen/jvppgen/*.py); do +install -p -m755 %{_mu_build_dir}/../src/vpp-api/java/jvpp/gen/jvpp_gen.py %{buildroot}/usr/bin +for i in $(ls %{_mu_build_dir}/../src/vpp-api/java/jvpp/gen/jvppgen/*.py); do install -p -m666 ${i} %{buildroot}%{python2_sitelib}/jvppgen done; # sample plugin mkdir -p -m755 %{buildroot}/usr/share/doc/vpp/examples/sample-plugin/sample -for file in $(cd %{_mu_build_dir}/%{_vpp_install_dir}/../../plugins/sample-plugin && git ls-files .) +for file in $(cd %{_mu_build_dir}/%{_vpp_install_dir}/../../src/examples/sample-plugin && git ls-files .) do - install -p -m 644 %{_mu_build_dir}/%{_vpp_install_dir}/../../plugins/sample-plugin/$file \ + install -p -m 644 %{_mu_build_dir}/%{_vpp_install_dir}/../../src/examples/sample-plugin/$file \ %{buildroot}/usr/share/doc/vpp/examples/sample-plugin/$file done @@ -170,24 +202,12 @@ done # mkdir -p -m755 %{buildroot}/usr/lib/vpp_plugins mkdir -p -m755 %{buildroot}/usr/lib/vpp_api_test_plugins -for file in $(cd %{_mu_build_dir}/%{_vpp_install_dir}/plugins/lib64/vpp_plugins && find -type f -print) -do - install -p -m 644 %{_mu_build_dir}/%{_vpp_install_dir}/plugins/lib64/vpp_plugins/$file \ - %{buildroot}/usr/lib/vpp_plugins/$file -done - for file in $(cd %{_mu_build_dir}/%{_vpp_install_dir}/vpp/lib64/vpp_plugins && find -type f -print) do install -p -m 644 %{_mu_build_dir}/%{_vpp_install_dir}/vpp/lib64/vpp_plugins/$file \ %{buildroot}/usr/lib/vpp_plugins/$file done -for file in $(cd %{_mu_build_dir}/%{_vpp_install_dir}/plugins/lib64/vpp_api_test_plugins && find -type f -print) -do - install -p -m 644 %{_mu_build_dir}/%{_vpp_install_dir}/plugins/lib64/vpp_api_test_plugins/$file \ - %{buildroot}/usr/lib/vpp_api_test_plugins/$file -done - for file in $(cd %{_mu_build_dir}/%{_vpp_install_dir}/vpp/lib64/vpp_api_test_plugins && find -type f -print) do install -p -m 644 %{_mu_build_dir}/%{_vpp_install_dir}/vpp/lib64/vpp_api_test_plugins/$file \ @@ -208,13 +228,13 @@ done sysctl --system %systemd_post vpp.service -%post python-api +%post api-python easy_install -z %{python2_sitelib}/vpp_papi-*.egg %preun %systemd_preun vpp.service -%preun python-api +%preun api-python easy_install -mxNq vpp_papi %postun @@ -255,7 +275,15 @@ fi %{_libdir}/* /usr/share/vpp/api/* -%files python-api +%files api-lua +%defattr(644,root,root) +/usr/share/doc/vpp/examples/lua + +%files api-java +%defattr(644,root,root) +/usr/share/java/* + +%files api-python %defattr(644,root,root) %{python2_sitelib}/vpp_papi-*.egg diff --git a/build-root/scripts/find-api-core-contents b/build-root/scripts/find-api-core-contents index f1f96f1f..c1af69db 100755 --- a/build-root/scripts/find-api-core-contents +++ b/build-root/scripts/find-api-core-contents @@ -1,6 +1,6 @@ #!/bin/bash -for i in $(find ${1}/vpp -name *.api.json -type f -print); do +for i in $(find ${1}/vpp/share/vpp/api/core -name *.api.json -type f -print); do echo ../${i} /usr/share/vpp/api/ >> ${2} done for i in $(find ${1}/vlib-api -name *.api.json -type f -print); do diff --git a/build-root/scripts/find-dev-contents b/build-root/scripts/find-dev-contents index 2dc6cc4d..d4f7b63f 100755 --- a/build-root/scripts/find-dev-contents +++ b/build-root/scripts/find-dev-contents @@ -16,16 +16,16 @@ do done # sample plugin -paths=`(cd ..; find plugins/sample-plugin -type f -print | grep -v autom4te)` +paths=`(cd ..; find src/examples/sample-plugin -type f -print | grep -v autom4te)` for path in $paths do - relpath=`echo $path | sed -e 's:.*plugins/::'` + relpath=`echo $path | sed -e 's:.*src/examples/::'` dir=`dirname $relpath` if [ $dir = "sample-plugin" ] ; then - echo ../../$path /usr/share/doc/vpp/examples/plugins/sample-plugin >> $2 + echo ../../$path /usr/share/doc/vpp/examples/sample-plugin/ >> $2 else echo ../../$path \ - /usr/share/doc/vpp/examples/plugins/$dir >> $2 + /usr/share/doc/vpp/examples/$dir >> $2 fi done diff --git a/build-root/scripts/find-plugins-contents b/build-root/scripts/find-plugins-contents index 4108f790..ae2a4271 100755 --- a/build-root/scripts/find-plugins-contents +++ b/build-root/scripts/find-plugins-contents @@ -2,11 +2,11 @@ rm -f $2 -for i in ${1}/{plugins,vpp}/lib64/vpp_plugins/*.so; do +for i in ${1}/vpp/lib64/vpp_plugins/*.so; do echo ../${i} /usr/lib/vpp_plugins >> ${2} done -for i in ${1}/{plugins,vpp}/lib64/vpp_api_test_plugins/*.so; do +for i in ${1}/vpp/lib64/vpp_api_test_plugins/*.so; do echo ../${i} /usr/lib/vpp_api_test_plugins >> ${2} done diff --git a/build-root/scripts/find-python-api-contents b/build-root/scripts/find-python-api-contents deleted file mode 100755 index 24e8532c..00000000 --- a/build-root/scripts/find-python-api-contents +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -rm -f $2 - -for i in $(find ${1}/{vpp,vpp-api}/lib/python2.7/site-packages/ -type f -print); do - echo ../${i} /usr/lib/python2.7/site-packages/vpp_papi >> ${2} -done - diff --git a/build-root/scripts/find-vpp-api-java-contents b/build-root/scripts/find-vpp-api-java-contents new file mode 100755 index 00000000..5f1bf197 --- /dev/null +++ b/build-root/scripts/find-vpp-api-java-contents @@ -0,0 +1,8 @@ +#!/bin/bash + +rm -f $2 + +for i in $(find ${1}/vpp/share/java/ -type f -print); do + echo ../${i} /usr/share/java >> ${2} +done + diff --git a/build-root/scripts/find-vpp-api-lua-contents b/build-root/scripts/find-vpp-api-lua-contents new file mode 100755 index 00000000..f1173db8 --- /dev/null +++ b/build-root/scripts/find-vpp-api-lua-contents @@ -0,0 +1,6 @@ +#!/bin/bash + +#i for now put everything into examples directory + +echo ../../src/vpp-api/lua /usr/share/vpp/examples > ${2} + diff --git a/build-root/scripts/find-vpp-api-python-contents b/build-root/scripts/find-vpp-api-python-contents new file mode 100755 index 00000000..819c9122 --- /dev/null +++ b/build-root/scripts/find-vpp-api-python-contents @@ -0,0 +1,8 @@ +#!/bin/bash + +rm -f $2 + +for i in $(find ${1}/vpp/lib/python2.7/site-packages/ -type f -print); do + echo ../${i} /usr/lib/python2.7/site-packages/vpp_papi >> ${2} +done + diff --git a/doxygen/Makefile b/doxygen/Makefile index ffce3c13..face5b44 100644 --- a/doxygen/Makefile +++ b/doxygen/Makefile @@ -52,8 +52,7 @@ DOXY_SRC_DIRECTORIES = \ $(DOXY_SRC)/vlibsocket \ $(DOXY_SRC)/vnet \ $(DOXY_SRC)/vpp \ - $(DOXY_SRC)/vpp-api \ - vpp-api + $(DOXY_SRC)/vpp-api # Input directories and files DOXY_INPUT ?= \ @@ -74,8 +73,8 @@ DOXY_INPUT := $(subst $(WS_ROOT)/,,$(DOXY_INPUT)) DOXY_EXCLUDE ?= \ $(DOXY_SRC)/vlib/vlib/buffer.c \ $(DOXY_SRC)/vlib/example \ - plugins/sample-plugin \ - vpp-api/lua + $(DOXY_SRC)/vpp-api/lua \ + plugins/sample-plugin # Generate a regexp for filenames to exclude DOXY_EXCLUDE_REGEXP = ($(subst .,\.,$(shell echo '$(strip $(DOXY_EXCLUDE))' | sed -e 's/ /|/g'))) diff --git a/plugins/Makefile.am b/plugins/Makefile.am index a101e47f..20676fc8 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -28,22 +28,7 @@ if ENABLE_sample_PLUGIN SUBDIRS += sample-plugin endif -if ENABLE_ioam_PLUGIN -SUBDIRS += ioam-plugin -endif - if ENABLE_vcgn_PLUGIN SUBDIRS += vcgn-plugin endif -if ENABLE_snat_PLUGIN -SUBDIRS += snat-plugin -endif - -if ENABLE_lb_PLUGIN -SUBDIRS += lb-plugin -endif - -if ENABLE_acl_PLUGIN -SUBDIRS += acl-plugin -endif diff --git a/plugins/acl-plugin/Makefile.am b/plugins/acl-plugin/Makefile.am deleted file mode 100644 index 798a32bb..00000000 --- a/plugins/acl-plugin/Makefile.am +++ /dev/null @@ -1,114 +0,0 @@ -# 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. - -AUTOMAKE_OPTIONS = foreign subdir-objects - -AM_CFLAGS = -Wall -AM_LDFLAGS = -module -shared -avoid-version - -vppapitestpluginsdir = ${libdir}/vpp_api_test_plugins -vpppluginsdir = ${libdir}/vpp_plugins - -vppapitestplugins_LTLIBRARIES = acl_test_plugin.la -vppplugins_LTLIBRARIES = acl_plugin.la - -acl_plugin_la_SOURCES = \ - acl/acl.c \ - acl/node_in.c \ - acl/node_out.c \ - acl/l2sess.c \ - acl/l2sess_node.c \ - acl/l2sess.h \ - acl/acl_plugin.api.h - -BUILT_SOURCES = acl/acl.api.h acl/acl.api.json - -SUFFIXES = .api.h .api .api.json - -# -# ACL API -# -%.api.h: %.api - mkdir -p `dirname $@` ; \ - $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ - | vppapigen --input - --output $@ --show-name $@ - -%.api.json: %.api - @echo " JSON APIGEN " $@ ; \ - mkdir -p `dirname $@` ; \ - $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ - | vppapigen --input - --json $@ - -apidir = $(prefix)/acl -api_DATA = acl/acl.api.json - -noinst_HEADERS = \ - acl/acl_all_api_h.h \ - acl/acl_msg_enum.h \ - acl/acl.api.h - -acl_test_plugin_la_SOURCES = acl/acl_test.c acl/acl_plugin.api.h - -# Remove *.la files -install-data-hook: - @(cd $(vpppluginsdir) && $(RM) $(vppplugins_LTLIBRARIES)) - @(cd $(vppapitestpluginsdir) && $(RM) $(vppapitestplugins_LTLIBRARIES)) - -# -# Java code generation -# -jvpp_registry_root = ../../vpp-api/java -jvpp_registry_version = 17.04 -jacl_jarfile = jvpp-acl-$(PACKAGE_VERSION).jar -jvpp_package_dir = io/fd/vpp/jvpp/acl -jvpp_root = acl/jvpp -jvpp_target_dir = target -jvpp_target = $(jvpp_root)/$(jvpp_target_dir) - -lib_LTLIBRARIES = libjvpp_acl.la -libjvpp_acl_la_SOURCES = acl/acl.api.h acl/jvpp_acl.c acl/jvpp/io_fd_vpp_jvpp_acl_JVppAclImpl.h -libjvpp_acl_la_LIBADD = -lvlibmemoryclient -lvlibapi -lvppinfra \ - -lpthread -lm -lrt -L$(jvpp_registry_root)/.libs -ljvpp_common -libjvpp_acl_la_LDFLAGS = -module -libjvpp_acl_la_CPPFLAGS = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -I../ -I$(srcdir)/../ - -BUILT_SOURCES += $(jvpp_root)/io_fd_vpp_jvpp_acl_JVppAclImpl.h - -$(jvpp_root)/io_fd_vpp_jvpp_acl_JVppAclImpl.h: acl/acl.api.json - dir=`pwd`; \ - mkdir -p $(jvpp_target); \ - mkdir -p $(jvpp_root)/$(jvpp_package_dir); \ - cd $(jvpp_root)/$(jvpp_package_dir); \ - mkdir -p types dto future callfacade callback notification test; \ - @srcdir@/$(jvpp_registry_root)/jvpp/gen/jvpp_gen.py -i $${dir}/acl/acl.api.json --plugin_name acl; \ - cd -; \ - mv -f $(jvpp_root)/$(jvpp_package_dir)/jvpp_acl_gen.h $(jvpp_root)/jvpp_acl_gen.h; \ - cp $(srcdir)/$(jvpp_root)/$(jvpp_package_dir)/test/*.java $(jvpp_root)/$(jvpp_package_dir)/test/; \ - cd $(jvpp_root); \ - $(JAVAC) -classpath .:$(jvpp_target_dir):../../$(jvpp_registry_root)/jvpp-registry-$(jvpp_registry_version).jar -d $(jvpp_target_dir) $(jvpp_package_dir)/*.java \ - $(jvpp_package_dir)/types/*.java \ - $(jvpp_package_dir)/dto/*.java \ - $(jvpp_package_dir)/callback/*.java \ - $(jvpp_package_dir)/notification/*.java \ - $(jvpp_package_dir)/future/*.java \ - $(jvpp_package_dir)/callfacade/*.java \ - $(jvpp_package_dir)/test/*.java \ - || (echo "acl jvpp compilation failed: $$?"; exit 1); \ - $(JAVAH) -classpath .:$(jvpp_target_dir):../../$(jvpp_registry_root)/jvpp-registry-$(jvpp_registry_version).jar -d . io.fd.vpp.jvpp.acl.JVppAclImpl ; - -$(jacl_jarfile): libjvpp_acl.la - cp .libs/libjvpp_acl.so.0.0.0 $(jvpp_target); \ - cd $(jvpp_target); \ - $(JAR) cfv $(JARFLAGS) ../../../$@ libjvpp_acl.so.0.0.0 $(jvpp_package_dir)/* ; cd ..; - -all-local: $(jacl_jarfile) diff --git a/plugins/acl-plugin/acl/acl.api b/plugins/acl-plugin/acl/acl.api deleted file mode 100644 index 58a5a171..00000000 --- a/plugins/acl-plugin/acl/acl.api +++ /dev/null @@ -1,444 +0,0 @@ -/* Hey Emacs use -*- mode: C -*- */ -/* - * 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. - */ - -/** \file - This file defines the vpp control-plane API messages - used to control the ACL plugin -*/ - - -/** \brief Get the plugin version - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ - -define acl_plugin_get_version -{ - u32 client_index; - u32 context; -}; - -/** \brief Reply to get the plugin version - @param context - returned sender context, to match reply w/ request - @param major - Incremented every time a known breaking behavior change is introduced - @param minor - Incremented with small changes, may be used to avoid buggy versions -*/ - -define acl_plugin_get_version_reply -{ - u32 context; - u32 major; - u32 minor; -}; - -/** \brief Access List Rule entry - @param is_permit - deny (0), permit (1), or permit+reflect(2) action on this rule. - @param is_ipv6 - IP addresses in this rule are IPv6 (1) or IPv4 (0) - @param src_ip_addr - Source prefix value - @param src_ip_prefix_len - Source prefix length - @param dst_ip_addr - Destination prefix value - @param dst_ip_prefix_len - Destination prefix length - @param proto - L4 protocol (http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml) - @param srcport_or_icmptype_first - beginning of source port or ICMP4/6 type range - @param srcport_or_icmptype_last - end of source port or ICMP4/6 type range - @param dstport_or_icmpcode_first - beginning of destination port or ICMP4/6 code range - @param dstport_or_icmpcode_last - end of destination port or ICMP4/6 code range - @param tcp_flags_mask - if proto==6, match masked TCP flags with this value - @param tcp_flags_value - if proto==6, mask to AND the TCP flags in the packet with -*/ - -typeonly manual_print manual_endian define acl_rule -{ - u8 is_permit; - u8 is_ipv6; - u8 src_ip_addr[16]; - u8 src_ip_prefix_len; - u8 dst_ip_addr[16]; - u8 dst_ip_prefix_len; -/* - * L4 protocol. IANA number. 1 = ICMP, 58 = ICMPv6, 6 = TCP, 17 = UDP. - * 0 => ignore L4 and ignore the ports/tcpflags when matching. - */ - u8 proto; -/* - * If the L4 protocol is TCP or UDP, the below - * hold ranges of ports, else if the L4 is ICMP/ICMPv6 - * they hold ranges of ICMP(v6) types/codes. - * - * Ranges are inclusive, i.e. to match "any" TCP/UDP port, - * use first=0,last=65535. For ICMP(v6), - * use first=0,last=255. - */ - u16 srcport_or_icmptype_first; - u16 srcport_or_icmptype_last; - u16 dstport_or_icmpcode_first; - u16 dstport_or_icmpcode_last; -/* - * for proto = 6, this matches if the - * TCP flags in the packet, ANDed with tcp_flags_mask, - * is equal to tcp_flags_value. - */ - u8 tcp_flags_mask; - u8 tcp_flags_value; -}; - -/** \brief MACIP Access List Rule entry - @param is_permit - deny (0), permit (1) action on this rule. - @param is_ipv6 - IP addresses in this rule are IPv6 (1) or IPv4 (0) - @param src_mac - match masked source MAC address against this value - @param src_mac_mask - AND source MAC address with this value before matching - @param src_ip_addr - Source prefix value - @param src_ip_prefix_len - Source prefix length -*/ - -typeonly manual_print manual_endian define macip_acl_rule -{ - u8 is_permit; - u8 is_ipv6; -/* - * The source mac of the packet ANDed with src_mac_mask. - * The source ip[46] address in the packet is matched - * against src_ip_addr, with src_ip_prefix_len set to 0. - * - * For better performance, minimize the number of - * (src_mac_mask, src_ip_prefix_len) combinations - * in a MACIP ACL. - */ - u8 src_mac[6]; - u8 src_mac_mask[6]; - u8 src_ip_addr[16]; - u8 src_ip_prefix_len; -}; - -/** \brief Replace an existing ACL in-place or create a new ACL - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param acl_index - an existing ACL entry (0..0xfffffffe) to replace, or 0xffffffff to make new ACL - @param tag - a string value stored along with the ACL, for descriptive purposes - @param count - number of ACL rules - @r - Rules for this access-list -*/ - -manual_print manual_endian define acl_add_replace -{ - u32 client_index; - u32 context; - u32 acl_index; /* ~0 to add, existing ACL# to replace */ - u8 tag[64]; /* What gets in here gets out in the corresponding tag field when dumping the ACLs. */ - u32 count; - vl_api_acl_rule_t r[count]; -}; - -/** \brief Reply to add/replace ACL - @param context - returned sender context, to match reply w/ request - @param acl_index - index of the updated or newly created ACL - @param retval 0 - no error -*/ - -define acl_add_replace_reply -{ - u32 context; - u32 acl_index; - i32 retval; -}; - -/** \brief Delete an ACL - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param acl_index - ACL index to delete -*/ - -define acl_del -{ - u32 client_index; - u32 context; - u32 acl_index; -}; - -/** \brief Reply to delete the ACL - @param context - returned sender context, to match reply w/ request - @param retval 0 - no error -*/ - -define acl_del_reply -{ - u32 context; - i32 retval; -}; - -/* acl_interface_add_del(_reply) to be deprecated in lieu of acl_interface_set_acl_list */ -/** \brief Use acl_interface_set_acl_list instead - Append/remove an ACL index to/from the list of ACLs checked for an interface - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param is_add - add or delete the ACL index from the list - @param is_input - check the ACL on input (1) or output (0) - @param sw_if_index - the interface to alter the list of ACLs on - @param acl_index - index of ACL for the operation -*/ - -define acl_interface_add_del -{ - u32 client_index; - u32 context; - u8 is_add; -/* - * is_input = 0 => ACL applied on interface egress - * is_input = 1 => ACL applied on interface ingress - */ - u8 is_input; - u32 sw_if_index; - u32 acl_index; -}; - -/** \brief Reply to alter the ACL list - @param context - returned sender context, to match reply w/ request - @param retval 0 - no error -*/ - -define acl_interface_add_del_reply -{ - u32 context; - i32 retval; -}; - -/** \brief Set the vector of input/output ACLs checked for an interface - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param sw_if_index - the interface to alter the list of ACLs on - @param count - total number of ACL indices in the vector - @param n_input - this many first elements correspond to input ACLs, the rest - output - @param acls - vector of ACL indices -*/ - -manual_endian define acl_interface_set_acl_list -{ - u32 client_index; - u32 context; - u32 sw_if_index; - u8 count; - u8 n_input; /* First n_input ACLs are set as a list of input ACLs, the rest are applied as output */ - u32 acls[count]; -}; - -/** \brief Reply to set the ACL list on an interface - @param context - returned sender context, to match reply w/ request - @param retval 0 - no error -*/ - -define acl_interface_set_acl_list_reply -{ - u32 context; - i32 retval; -}; - -/** \brief Dump the specific ACL contents or all of the ACLs' contents - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param acl_index - ACL index to dump, ~0 to dump all ACLs -*/ - -define acl_dump -{ - u32 client_index; - u32 context; - u32 acl_index; /* ~0 for all ACLs */ -}; - -/** \brief Details about a single ACL contents - @param context - returned sender context, to match reply w/ request - @param acl_index - ACL index whose contents are being sent in this message - @param tag - Descriptive tag value which was supplied at ACL creation - @param count - Number of rules in this ACL - @param r - Array of rules within this ACL -*/ - -manual_print manual_endian define acl_details -{ - u32 context; - u32 acl_index; - u8 tag[64]; /* Same blob that was supplied to us when creating the ACL, one hopes. */ - u32 count; - vl_api_acl_rule_t r[count]; -}; - -/** \brief Dump the list(s) of ACL applied to specific or all interfaces - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param sw_if_index - interface to dump the ACL list for -*/ - -define acl_interface_list_dump -{ - u32 client_index; - u32 context; - u32 sw_if_index; /* ~0 for all interfaces */ -}; - -/** \brief Details about a single ACL contents - @param context - returned sender context, to match reply w/ request - @param sw_if_index - interface for which the list of ACLs is applied - @param count - total length of acl indices vector - @param n_input - this many of indices in the beginning are input ACLs, the rest - output - @param acls - the vector of ACL indices -*/ - -manual_endian define acl_interface_list_details -{ - u32 context; - u32 sw_if_index; - u8 count; - u8 n_input; - u32 acls[count]; -}; - -/** \brief Add a MACIP ACL - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param tag - descriptive value for this MACIP ACL - @param count - number of rules in this ACL - @param r - vector of MACIP ACL rules -*/ - -manual_print manual_endian define macip_acl_add -{ - u32 client_index; - u32 context; - u8 tag[64]; - u32 count; - vl_api_macip_acl_rule_t r[count]; -}; - -/** \brief Reply to add MACIP ACL - @param context - returned sender context, to match reply w/ request - @param acl_index - index of the newly created ACL - @param retval 0 - no error -*/ - -define macip_acl_add_reply -{ - u32 context; - u32 acl_index; - i32 retval; -}; - -/** \brief Delete a MACIP ACL - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param acl_index - MACIP ACL index to delete -*/ - -define macip_acl_del -{ - u32 client_index; - u32 context; - u32 acl_index; -}; - -/** \brief Reply to delete the MACIP ACL - @param context - returned sender context, to match reply w/ request - @param retval 0 - no error -*/ - -define macip_acl_del_reply -{ - u32 context; - i32 retval; -}; - -/** \brief Add or delete a MACIP ACL to/from interface - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param is_add - add (1) or delete (0) ACL from being used on an interface - @param sw_if_index - interface to apply the action to - @param acl_index - MACIP ACL index -*/ - -define macip_acl_interface_add_del -{ - u32 client_index; - u32 context; - u8 is_add; - /* macip ACLs are always input */ - u32 sw_if_index; - u32 acl_index; -}; - -/** \brief Reply to apply/unapply the MACIP ACL - @param context - returned sender context, to match reply w/ request - @param retval 0 - no error -*/ - -define macip_acl_interface_add_del_reply -{ - u32 context; - i32 retval; -}; - -/** \brief Dump one or all defined MACIP ACLs - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param acl_index - MACIP ACL index or ~0 to dump all ACLs -*/ - -define macip_acl_dump -{ - u32 client_index; - u32 context; - u32 acl_index; /* ~0 for all ACLs */ -}; - -/** \brief Details about one MACIP ACL - @param context - returned sender context, to match reply w/ request - @param acl_index - index of this MACIP ACL - @param tag - descriptive tag which was supplied during the creation - @param count - length of the vector of MACIP ACL rules - @param r - rules comprising this ACL -*/ - -manual_print manual_endian define macip_acl_details -{ - u32 context; - u32 acl_index; - u8 tag[64]; - u32 count; - vl_api_macip_acl_rule_t r[count]; -}; - -/** \brief Get the vector of MACIP ACL IDs applied to the interfaces - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ - -define macip_acl_interface_get -{ - u32 client_index; - u32 context; -}; - -/** \brief Reply with the vector of MACIP ACLs by sw_if_index - @param context - returned sender context, to match reply w/ request - @param count - total number of elements in the vector - @param acls - the vector of active MACACL indices per sw_if_index -*/ - -define macip_acl_interface_get_reply -{ - u32 context; - u32 count; - u32 acls[count]; -}; - diff --git a/plugins/acl-plugin/acl/acl.c b/plugins/acl-plugin/acl/acl.c deleted file mode 100644 index 8ff5a6b7..00000000 --- a/plugins/acl-plugin/acl/acl.c +++ /dev/null @@ -1,1901 +0,0 @@ -/* - * 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. - */ - -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -/* define message IDs */ -#include - -/* define message structures */ -#define vl_typedefs -#include -#undef vl_typedefs - -/* define generated endian-swappers */ -#define vl_endianfun -#include -#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 -#undef vl_printfun - -/* Get the API version number */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#undef vl_api_version - -#include "node_in.h" -#include "node_out.h" - -acl_main_t acl_main; - -/* - * 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); - -#define REPLY_MACRO2(t, body) \ -do { \ - unix_shared_memory_queue_t * q; \ - rv = vl_msg_api_pd_handler (mp, rv); \ - 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)+am->msg_id_base); \ - rmp->context = mp->context; \ - rmp->retval = ntohl(rv); \ - do {body;} while (0); \ - vl_msg_api_send_shmem (q, (u8 *)&rmp); \ -} while(0); - -#define REPLY_MACRO3(t, n, body) \ -do { \ - unix_shared_memory_queue_t * q; \ - rv = vl_msg_api_pd_handler (mp, rv); \ - q = vl_api_client_index_to_input_queue (mp->client_index); \ - if (!q) \ - return; \ - \ - rmp = vl_msg_api_alloc (sizeof (*rmp) + n); \ - rmp->_vl_msg_id = ntohs((t)+am->msg_id_base); \ - rmp->context = mp->context; \ - rmp->retval = ntohl(rv); \ - do {body;} while (0); \ - vl_msg_api_send_shmem (q, (u8 *)&rmp); \ -} while(0); - - -/* List of message types that this plugin understands */ - -#define foreach_acl_plugin_api_msg \ -_(ACL_PLUGIN_GET_VERSION, acl_plugin_get_version) \ -_(ACL_ADD_REPLACE, acl_add_replace) \ -_(ACL_DEL, acl_del) \ -_(ACL_INTERFACE_ADD_DEL, acl_interface_add_del) \ -_(ACL_INTERFACE_SET_ACL_LIST, acl_interface_set_acl_list) \ -_(ACL_DUMP, acl_dump) \ -_(ACL_INTERFACE_LIST_DUMP, acl_interface_list_dump) \ -_(MACIP_ACL_ADD, macip_acl_add) \ -_(MACIP_ACL_DEL, macip_acl_del) \ -_(MACIP_ACL_INTERFACE_ADD_DEL, macip_acl_interface_add_del) \ -_(MACIP_ACL_DUMP, macip_acl_dump) \ -_(MACIP_ACL_INTERFACE_GET, macip_acl_interface_get) - -/* - * 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) -{ - acl_main_t *am = &acl_main; - clib_error_t *error = 0; - - am->vlib_main = vm; - am->vnet_main = h->vnet_main; - am->ethernet_main = h->ethernet_main; - - l2sess_vlib_plugin_register(vm, h, from_early_init); - - return error; -} - - -static void -vl_api_acl_plugin_get_version_t_handler (vl_api_acl_plugin_get_version_t * mp) -{ - acl_main_t *am = &acl_main; - vl_api_acl_plugin_get_version_reply_t *rmp; - int msg_size = sizeof (*rmp); - unix_shared_memory_queue_t *q; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - { - return; - } - - rmp = vl_msg_api_alloc (msg_size); - memset (rmp, 0, msg_size); - rmp->_vl_msg_id = - ntohs (VL_API_ACL_PLUGIN_GET_VERSION_REPLY + am->msg_id_base); - rmp->context = mp->context; - rmp->major = htonl (ACL_PLUGIN_VERSION_MAJOR); - rmp->minor = htonl (ACL_PLUGIN_VERSION_MINOR); - - vl_msg_api_send_shmem (q, (u8 *) & rmp); -} - - -static int -acl_add_list (u32 count, vl_api_acl_rule_t rules[], - u32 * acl_list_index, u8 * tag) -{ - acl_main_t *am = &acl_main; - acl_list_t *a; - acl_rule_t *r; - acl_rule_t *acl_new_rules; - int i; - - if (*acl_list_index != ~0) - { - /* They supplied some number, let's see if this ACL exists */ - if (pool_is_free_index (am->acls, *acl_list_index)) - { - /* tried to replace a non-existent ACL, no point doing anything */ - return -1; - } - } - - /* Create and populate the rules */ - acl_new_rules = clib_mem_alloc_aligned (sizeof (acl_rule_t) * count, - CLIB_CACHE_LINE_BYTES); - if (!acl_new_rules) - { - /* Could not allocate rules. New or existing ACL - bail out regardless */ - return -1; - } - - for (i = 0; i < count; i++) - { - r = &acl_new_rules[i]; - r->is_permit = rules[i].is_permit; - r->is_ipv6 = rules[i].is_ipv6; - if (r->is_ipv6) - { - memcpy (&r->src, rules[i].src_ip_addr, sizeof (r->src)); - memcpy (&r->dst, rules[i].dst_ip_addr, sizeof (r->dst)); - } - else - { - memcpy (&r->src.ip4, rules[i].src_ip_addr, sizeof (r->src.ip4)); - memcpy (&r->dst.ip4, rules[i].dst_ip_addr, sizeof (r->dst.ip4)); - } - r->src_prefixlen = rules[i].src_ip_prefix_len; - r->dst_prefixlen = rules[i].dst_ip_prefix_len; - r->proto = rules[i].proto; - r->src_port_or_type_first = rules[i].srcport_or_icmptype_first; - r->src_port_or_type_last = rules[i].srcport_or_icmptype_last; - r->dst_port_or_code_first = rules[i].dstport_or_icmpcode_first; - r->dst_port_or_code_last = rules[i].dstport_or_icmpcode_last; - r->tcp_flags_value = rules[i].tcp_flags_value; - r->tcp_flags_mask = rules[i].tcp_flags_mask; - } - - if (~0 == *acl_list_index) - { - /* Get ACL index */ - pool_get_aligned (am->acls, a, CLIB_CACHE_LINE_BYTES); - memset (a, 0, sizeof (*a)); - /* Will return the newly allocated ACL index */ - *acl_list_index = a - am->acls; - } - else - { - a = am->acls + *acl_list_index; - /* Get rid of the old rules */ - clib_mem_free (a->rules); - } - a->rules = acl_new_rules; - a->count = count; - memcpy (a->tag, tag, sizeof (a->tag)); - - return 0; -} - -static int -acl_del_list (u32 acl_list_index) -{ - acl_main_t *am = &acl_main; - acl_list_t *a; - int i, ii; - if (pool_is_free_index (am->acls, acl_list_index)) - { - return -1; - } - - /* delete any references to the ACL */ - for (i = 0; i < vec_len (am->output_acl_vec_by_sw_if_index); i++) - { - for (ii = 0; ii < vec_len (am->output_acl_vec_by_sw_if_index[i]); - /* see body */ ) - { - if (acl_list_index == am->output_acl_vec_by_sw_if_index[i][ii]) - { - vec_del1 (am->output_acl_vec_by_sw_if_index[i], ii); - } - else - { - ii++; - } - } - } - for (i = 0; i < vec_len (am->input_acl_vec_by_sw_if_index); i++) - { - for (ii = 0; ii < vec_len (am->input_acl_vec_by_sw_if_index[i]); - /* see body */ ) - { - if (acl_list_index == am->input_acl_vec_by_sw_if_index[i][ii]) - { - vec_del1 (am->input_acl_vec_by_sw_if_index[i], ii); - } - else - { - ii++; - } - } - } - - /* now we can delete the ACL itself */ - a = &am->acls[acl_list_index]; - if (a->rules) - { - clib_mem_free (a->rules); - } - pool_put (am->acls, a); - return 0; -} - -/* Some aids in ASCII graphing the content */ -#define XX "\377" -#define __ "\000" -#define _(x) -#define v - -u8 ip4_5tuple_mask[] = -_(" dmac smac etype ") -_(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v __ __ v - _(" v ihl totlen ") - _(0x0000) - __ __ __ __ - _(" ident fl+fo ") - _(0x0004) - __ __ __ __ - _(" ttl pr checksum ") - _(0x0008) - __ XX __ __ - _(" src address ") - _(0x000C) - XX XX XX XX - _(" dst address ") - _(0x0010) - XX XX XX XX - _("L4 T/U sport dport ") - _(tcpudp) - XX XX XX XX - _(padpad) - __ __ __ __ - _(padpad) - __ __ __ __ - _(padeth) - __ __; - - u8 ip6_5tuple_mask[] = - _(" dmac smac etype ") - _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v __ __ v - _(" v tc + flow ") - _(0x0000) __ __ __ __ - _(" plen nh hl ") - _(0x0004) __ __ XX __ - _(" src address ") - _(0x0008) XX XX XX XX - _(0x000C) XX XX XX XX - _(0x0010) XX XX XX XX - _(0x0014) XX XX XX XX - _(" dst address ") - _(0x0018) XX XX XX XX - _(0x001C) XX XX XX XX - _(0x0020) XX XX XX XX - _(0x0024) XX XX XX XX - _("L4T/U sport dport ") - _(tcpudp) XX XX XX XX _(padpad) __ __ __ __ _(padeth) __ __; - -#undef XX -#undef __ -#undef _ -#undef v - - static int count_skip (u8 * p, u32 size) -{ - u64 *p64 = (u64 *) p; - /* Be tolerant to null pointer */ - if (0 == p) - return 0; - - while ((0ULL == *p64) && ((u8 *) p64 - p) < size) - { - p64++; - } - return (p64 - (u64 *) p) / 2; -} - -static int -acl_classify_add_del_table_big (vnet_classify_main_t * cm, u8 * mask, - u32 mask_len, u32 next_table_index, - u32 miss_next_index, u32 * table_index, - int is_add) -{ - u32 nbuckets = 65536; - u32 memory_size = 2 << 30; - u32 skip = count_skip (mask, mask_len); - u32 match = (mask_len / 16) - skip; - u8 *skip_mask_ptr = mask + 16 * skip; - u32 current_data_flag = 0; - int current_data_offset = 0; - - if (0 == match) - match = 1; - - return vnet_classify_add_del_table (cm, skip_mask_ptr, nbuckets, - memory_size, skip, match, - next_table_index, miss_next_index, - table_index, current_data_flag, - current_data_offset, is_add, - 1 /* delete_chain */); -} - -static int -acl_classify_add_del_table_small (vnet_classify_main_t * cm, u8 * mask, - u32 mask_len, u32 next_table_index, - u32 miss_next_index, u32 * table_index, - int is_add) -{ - u32 nbuckets = 32; - u32 memory_size = 2 << 20; - u32 skip = count_skip (mask, mask_len); - u32 match = (mask_len / 16) - skip; - u8 *skip_mask_ptr = mask + 16 * skip; - u32 current_data_flag = 0; - int current_data_offset = 0; - - if (0 == match) - match = 1; - - return vnet_classify_add_del_table (cm, skip_mask_ptr, nbuckets, - memory_size, skip, match, - next_table_index, miss_next_index, - table_index, current_data_flag, - current_data_offset, is_add, - 1 /* delete_chain */); -} - - -static int -acl_unhook_l2_input_classify (acl_main_t * am, u32 sw_if_index) -{ - vnet_classify_main_t *cm = &vnet_classify_main; - u32 ip4_table_index = ~0; - u32 ip6_table_index = ~0; - - vec_validate_init_empty (am->acl_ip4_input_classify_table_by_sw_if_index, - sw_if_index, ~0); - vec_validate_init_empty (am->acl_ip6_input_classify_table_by_sw_if_index, - sw_if_index, ~0); - - vnet_l2_input_classify_enable_disable (sw_if_index, 0); - - if (am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] != ~0) - { - ip4_table_index = - am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index]; - am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] = ~0; - acl_classify_add_del_table_big (cm, ip4_5tuple_mask, - sizeof (ip4_5tuple_mask) - 1, ~0, - am->l2_input_classify_next_acl, - &ip4_table_index, 0); - } - if (am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] != ~0) - { - ip6_table_index = - am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index]; - am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] = ~0; - acl_classify_add_del_table_big (cm, ip6_5tuple_mask, - sizeof (ip6_5tuple_mask) - 1, ~0, - am->l2_input_classify_next_acl, - &ip6_table_index, 0); - } - - return 0; -} - -static int -acl_unhook_l2_output_classify (acl_main_t * am, u32 sw_if_index) -{ - vnet_classify_main_t *cm = &vnet_classify_main; - u32 ip4_table_index = ~0; - u32 ip6_table_index = ~0; - - vec_validate_init_empty (am->acl_ip4_output_classify_table_by_sw_if_index, - sw_if_index, ~0); - vec_validate_init_empty (am->acl_ip6_output_classify_table_by_sw_if_index, - sw_if_index, ~0); - - vnet_l2_output_classify_enable_disable (sw_if_index, 0); - - if (am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] != ~0) - { - ip4_table_index = - am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index]; - am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] = ~0; - acl_classify_add_del_table_big (cm, ip4_5tuple_mask, - sizeof (ip4_5tuple_mask) - 1, ~0, - am->l2_output_classify_next_acl, - &ip4_table_index, 0); - } - if (am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] != ~0) - { - ip6_table_index = - am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index]; - am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] = ~0; - acl_classify_add_del_table_big (cm, ip6_5tuple_mask, - sizeof (ip6_5tuple_mask) - 1, ~0, - am->l2_output_classify_next_acl, - &ip6_table_index, 0); - } - - return 0; -} - -static int -acl_hook_l2_input_classify (acl_main_t * am, u32 sw_if_index) -{ - vnet_classify_main_t *cm = &vnet_classify_main; - u32 ip4_table_index = ~0; - u32 ip6_table_index = ~0; - int rv; - - /* in case there were previous tables attached */ - acl_unhook_l2_input_classify (am, sw_if_index); - rv = - acl_classify_add_del_table_big (cm, ip4_5tuple_mask, - sizeof (ip4_5tuple_mask) - 1, ~0, - am->l2_input_classify_next_acl, - &ip4_table_index, 1); - if (rv) - return rv; - rv = - acl_classify_add_del_table_big (cm, ip6_5tuple_mask, - sizeof (ip6_5tuple_mask) - 1, ~0, - am->l2_input_classify_next_acl, - &ip6_table_index, 1); - if (rv) - { - acl_classify_add_del_table_big (cm, ip4_5tuple_mask, - sizeof (ip4_5tuple_mask) - 1, ~0, - am->l2_input_classify_next_acl, - &ip4_table_index, 0); - return rv; - } - rv = - vnet_l2_input_classify_set_tables (sw_if_index, ip4_table_index, - ip6_table_index, ~0); - clib_warning - ("ACL enabling on interface sw_if_index %d, setting tables to the following: ip4: %d ip6: %d\n", - sw_if_index, ip4_table_index, ip6_table_index); - if (rv) - { - acl_classify_add_del_table_big (cm, ip6_5tuple_mask, - sizeof (ip6_5tuple_mask) - 1, ~0, - am->l2_input_classify_next_acl, - &ip6_table_index, 0); - acl_classify_add_del_table_big (cm, ip4_5tuple_mask, - sizeof (ip4_5tuple_mask) - 1, ~0, - am->l2_input_classify_next_acl, - &ip4_table_index, 0); - return rv; - } - - am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] = - ip4_table_index; - am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] = - ip6_table_index; - - vnet_l2_input_classify_enable_disable (sw_if_index, 1); - return rv; -} - -static int -acl_hook_l2_output_classify (acl_main_t * am, u32 sw_if_index) -{ - vnet_classify_main_t *cm = &vnet_classify_main; - u32 ip4_table_index = ~0; - u32 ip6_table_index = ~0; - int rv; - - /* in case there were previous tables attached */ - acl_unhook_l2_output_classify (am, sw_if_index); - rv = - acl_classify_add_del_table_big (cm, ip4_5tuple_mask, - sizeof (ip4_5tuple_mask) - 1, ~0, - am->l2_output_classify_next_acl, - &ip4_table_index, 1); - if (rv) - return rv; - rv = - acl_classify_add_del_table_big (cm, ip6_5tuple_mask, - sizeof (ip6_5tuple_mask) - 1, ~0, - am->l2_output_classify_next_acl, - &ip6_table_index, 1); - if (rv) - { - acl_classify_add_del_table_big (cm, ip4_5tuple_mask, - sizeof (ip4_5tuple_mask) - 1, ~0, - am->l2_output_classify_next_acl, - &ip4_table_index, 0); - return rv; - } - rv = - vnet_l2_output_classify_set_tables (sw_if_index, ip4_table_index, - ip6_table_index, ~0); - clib_warning - ("ACL enabling on interface sw_if_index %d, setting tables to the following: ip4: %d ip6: %d\n", - sw_if_index, ip4_table_index, ip6_table_index); - if (rv) - { - acl_classify_add_del_table_big (cm, ip6_5tuple_mask, - sizeof (ip6_5tuple_mask) - 1, ~0, - am->l2_output_classify_next_acl, - &ip6_table_index, 0); - acl_classify_add_del_table_big (cm, ip4_5tuple_mask, - sizeof (ip4_5tuple_mask) - 1, ~0, - am->l2_output_classify_next_acl, - &ip4_table_index, 0); - return rv; - } - - am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] = - ip4_table_index; - am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] = - ip6_table_index; - - vnet_l2_output_classify_enable_disable (sw_if_index, 1); - return rv; -} - - -int -acl_interface_in_enable_disable (acl_main_t * am, u32 sw_if_index, - int enable_disable) -{ - int rv; - - /* Utterly wrong? */ - if (pool_is_free_index (am->vnet_main->interface_main.sw_interfaces, - sw_if_index)) - return VNET_API_ERROR_INVALID_SW_IF_INDEX; - - if (enable_disable) - { - rv = acl_hook_l2_input_classify (am, sw_if_index); - } - else - { - rv = acl_unhook_l2_input_classify (am, sw_if_index); - } - - return rv; -} - -int -acl_interface_out_enable_disable (acl_main_t * am, u32 sw_if_index, - int enable_disable) -{ - int rv; - - /* Utterly wrong? */ - if (pool_is_free_index (am->vnet_main->interface_main.sw_interfaces, - sw_if_index)) - return VNET_API_ERROR_INVALID_SW_IF_INDEX; - - if (enable_disable) - { - rv = acl_hook_l2_output_classify (am, sw_if_index); - } - else - { - rv = acl_unhook_l2_output_classify (am, sw_if_index); - } - - return rv; -} - - -static int -acl_interface_add_inout_acl (u32 sw_if_index, u8 is_input, u32 acl_list_index) -{ - acl_main_t *am = &acl_main; - if (is_input) - { - vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index); - vec_add (am->input_acl_vec_by_sw_if_index[sw_if_index], &acl_list_index, - 1); - acl_interface_in_enable_disable (am, sw_if_index, 1); - } - else - { - vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index); - vec_add (am->output_acl_vec_by_sw_if_index[sw_if_index], - &acl_list_index, 1); - acl_interface_out_enable_disable (am, sw_if_index, 1); - } - return 0; -} - -static int -acl_interface_del_inout_acl (u32 sw_if_index, u8 is_input, u32 acl_list_index) -{ - acl_main_t *am = &acl_main; - int i; - int rv = -1; - if (is_input) - { - vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index); - for (i = 0; i < vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]); - i++) - { - if (acl_list_index == - am->input_acl_vec_by_sw_if_index[sw_if_index][i]) - { - vec_del1 (am->input_acl_vec_by_sw_if_index[sw_if_index], i); - rv = 0; - break; - } - } - if (0 == vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index])) - { - acl_interface_in_enable_disable (am, sw_if_index, 0); - } - } - else - { - vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index); - for (i = 0; - i < vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]); i++) - { - if (acl_list_index == - am->output_acl_vec_by_sw_if_index[sw_if_index][i]) - { - vec_del1 (am->output_acl_vec_by_sw_if_index[sw_if_index], i); - rv = 0; - break; - } - } - if (0 == vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index])) - { - acl_interface_out_enable_disable (am, sw_if_index, 0); - } - } - return rv; -} - -static void -acl_interface_reset_inout_acls (u32 sw_if_index, u8 is_input) -{ - acl_main_t *am = &acl_main; - if (is_input) - { - acl_interface_in_enable_disable (am, sw_if_index, 0); - vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index); - vec_reset_length (am->input_acl_vec_by_sw_if_index[sw_if_index]); - } - else - { - acl_interface_out_enable_disable (am, sw_if_index, 0); - vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index); - vec_reset_length (am->output_acl_vec_by_sw_if_index[sw_if_index]); - } -} - -static int -acl_interface_add_del_inout_acl (u32 sw_if_index, u8 is_add, u8 is_input, - u32 acl_list_index) -{ - int rv = -1; - if (is_add) - { - rv = - acl_interface_add_inout_acl (sw_if_index, is_input, acl_list_index); - } - else - { - rv = - acl_interface_del_inout_acl (sw_if_index, is_input, acl_list_index); - } - return rv; -} - - -static void * -get_ptr_to_offset (vlib_buffer_t * b0, int offset) -{ - u8 *p = vlib_buffer_get_current (b0) + offset; - return p; -} - -static u8 -acl_get_l4_proto (vlib_buffer_t * b0, int node_is_ip6) -{ - u8 proto; - int proto_offset; - if (node_is_ip6) - { - proto_offset = 20; - } - else - { - proto_offset = 23; - } - proto = *((u8 *) vlib_buffer_get_current (b0) + proto_offset); - return proto; -} - -static int -acl_match_addr (ip46_address_t * addr1, ip46_address_t * addr2, int prefixlen, - int is_ip6) -{ - if (prefixlen == 0) - { - /* match any always succeeds */ - return 1; - } - if (is_ip6) - { - if (memcmp (addr1, addr2, prefixlen / 8)) - { - /* If the starting full bytes do not match, no point in bittwidling the thumbs further */ - return 0; - } - if (prefixlen % 8) - { - u8 b1 = *((u8 *) addr1 + 1 + prefixlen / 8); - u8 b2 = *((u8 *) addr2 + 1 + prefixlen / 8); - u8 mask0 = (0xff - ((1 << (8 - (prefixlen % 8))) - 1)); - return (b1 & mask0) == b2; - } - else - { - /* The prefix fits into integer number of bytes, so nothing left to do */ - return 1; - } - } - else - { - uint32_t a1 = ntohl (addr1->ip4.as_u32); - uint32_t a2 = ntohl (addr2->ip4.as_u32); - uint32_t mask0 = 0xffffffff - ((1 << (32 - prefixlen)) - 1); - return (a1 & mask0) == a2; - } -} - -static int -acl_match_port (u16 port, u16 port_first, u16 port_last, int is_ip6) -{ - return ((port >= port_first) && (port <= port_last)); -} - -static int -acl_packet_match (acl_main_t * am, u32 acl_index, vlib_buffer_t * b0, - u8 * r_action, int *r_is_ip6, u32 * r_acl_match_p, - u32 * r_rule_match_p, u32 * trace_bitmap) -{ - ethernet_header_t *h0; - u16 type0; - - ip46_address_t src, dst; - int is_ip6; - int is_ip4; - u8 proto; - u16 src_port; - u16 dst_port; - u8 tcp_flags = 0; - int i; - acl_list_t *a; - acl_rule_t *r; - - h0 = vlib_buffer_get_current (b0); - type0 = clib_net_to_host_u16 (h0->type); - is_ip4 = (type0 == ETHERNET_TYPE_IP4); - is_ip6 = (type0 == ETHERNET_TYPE_IP6); - - if (!(is_ip4 || is_ip6)) - { - return 0; - } - /* The bunch of hardcoded offsets here is intentional to get rid of them - ASAP, when getting to a faster matching code */ - if (is_ip4) - { - clib_memcpy (&src.ip4, get_ptr_to_offset (b0, 26), 4); - clib_memcpy (&dst.ip4, get_ptr_to_offset (b0, 30), 4); - proto = acl_get_l4_proto (b0, 0); - if (1 == proto) - { - *trace_bitmap |= 0x00000001; - /* type */ - src_port = *(u8 *) get_ptr_to_offset (b0, 34); - /* code */ - dst_port = *(u8 *) get_ptr_to_offset (b0, 35); - } - else - { - /* assume TCP/UDP */ - src_port = (*(u16 *) get_ptr_to_offset (b0, 34)); - dst_port = (*(u16 *) get_ptr_to_offset (b0, 36)); - /* UDP gets ability to check on an oddball data byte as a bonus */ - tcp_flags = *(u8 *) get_ptr_to_offset (b0, 14 + 20 + 13); - } - } - else /* is_ipv6 implicitly */ - { - clib_memcpy (&src, get_ptr_to_offset (b0, 22), 16); - clib_memcpy (&dst, get_ptr_to_offset (b0, 38), 16); - proto = acl_get_l4_proto (b0, 1); - if (58 == proto) - { - *trace_bitmap |= 0x00000002; - /* type */ - src_port = *(u8 *) get_ptr_to_offset (b0, 54); - /* code */ - dst_port = *(u8 *) get_ptr_to_offset (b0, 55); - } - else - { - /* assume TCP/UDP */ - src_port = (*(u16 *) get_ptr_to_offset (b0, 54)); - dst_port = (*(u16 *) get_ptr_to_offset (b0, 56)); - tcp_flags = *(u8 *) get_ptr_to_offset (b0, 14 + 40 + 13); - } - } - if (pool_is_free_index (am->acls, acl_index)) - { - if (r_acl_match_p) - *r_acl_match_p = acl_index; - if (r_rule_match_p) - *r_rule_match_p = -1; - /* the ACL does not exist but is used for policy. Block traffic. */ - return 0; - } - a = am->acls + acl_index; - for (i = 0; i < a->count; i++) - { - r = a->rules + i; - if (is_ip6 != r->is_ipv6) - { - continue; - } - if (!acl_match_addr (&dst, &r->dst, r->dst_prefixlen, is_ip6)) - continue; - if (!acl_match_addr (&src, &r->src, r->src_prefixlen, is_ip6)) - continue; - if (r->proto) - { - if (proto != r->proto) - continue; - if (!acl_match_port - (src_port, r->src_port_or_type_first, r->src_port_or_type_last, - is_ip6)) - continue; - if (!acl_match_port - (dst_port, r->dst_port_or_code_first, r->dst_port_or_code_last, - is_ip6)) - continue; - /* No need for check of proto == TCP, since in other rules both fields should be zero, so this match will succeed */ - if ((tcp_flags & r->tcp_flags_mask) != r->tcp_flags_value) - continue; - } - /* everything matches! */ - *r_action = r->is_permit; - *r_is_ip6 = is_ip6; - if (r_acl_match_p) - *r_acl_match_p = acl_index; - if (r_rule_match_p) - *r_rule_match_p = i; - return 1; - } - return 0; -} - -void -input_acl_packet_match (u32 sw_if_index, vlib_buffer_t * b0, u32 * nextp, - u32 * acl_match_p, u32 * rule_match_p, - u32 * trace_bitmap) -{ - acl_main_t *am = &acl_main; - uint8_t action = 0; - int is_ip6 = 0; - int i; - vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index); - for (i = 0; i < vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]); - i++) - { - if (acl_packet_match - (am, am->input_acl_vec_by_sw_if_index[sw_if_index][i], b0, &action, - &is_ip6, acl_match_p, rule_match_p, trace_bitmap)) - { - if (is_ip6) - { - *nextp = am->acl_in_ip6_match_next[action]; - } - else - { - *nextp = am->acl_in_ip4_match_next[action]; - } - return; - } - } - if (vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]) > 0) - { - /* If there are ACLs and none matched, deny by default */ - *nextp = 0; - } - -} - -void -output_acl_packet_match (u32 sw_if_index, vlib_buffer_t * b0, u32 * nextp, - u32 * acl_match_p, u32 * rule_match_p, - u32 * trace_bitmap) -{ - acl_main_t *am = &acl_main; - uint8_t action = 0; - int is_ip6 = 0; - int i; - vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index); - for (i = 0; i < vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]); - i++) - { - if (acl_packet_match - (am, am->output_acl_vec_by_sw_if_index[sw_if_index][i], b0, &action, - &is_ip6, acl_match_p, rule_match_p, trace_bitmap)) - { - if (is_ip6) - { - *nextp = am->acl_out_ip6_match_next[action]; - } - else - { - *nextp = am->acl_out_ip4_match_next[action]; - } - return; - } - } - if (vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]) > 0) - { - /* If there are ACLs and none matched, deny by default */ - *nextp = 0; - } -} - -typedef struct -{ - u8 is_ipv6; - u8 mac_mask[6]; - u8 prefix_len; - u32 count; - u32 table_index; -} macip_match_type_t; - -static u32 -macip_find_match_type (macip_match_type_t * mv, u8 * mac_mask, u8 prefix_len, - u8 is_ipv6) -{ - u32 i; - if (mv) - { - for (i = 0; i < vec_len (mv); i++) - { - if ((mv[i].prefix_len == prefix_len) && (mv[i].is_ipv6 == is_ipv6) - && (0 == memcmp (mv[i].mac_mask, mac_mask, 6))) - { - return i; - } - } - } - return ~0; -} - - -/* Get metric used to sort match types. - The more specific and the more often seen - the bigger the metric */ -static int -match_type_metric (macip_match_type_t * m) -{ - /* FIXME: count the ones in the MAC mask as well, check how well this heuristic works in real life */ - return m->prefix_len + m->is_ipv6 + 10 * m->count; -} - -static int -match_type_compare (macip_match_type_t * m1, macip_match_type_t * m2) -{ - /* Ascending sort based on the metric values */ - return match_type_metric (m1) - match_type_metric (m2); -} - -/* Get the offset of L3 source within ethernet packet */ -static int -get_l3_src_offset(int is6) -{ - if(is6) - return (sizeof(ethernet_header_t) + offsetof(ip6_header_t, src_address)); - else - return (sizeof(ethernet_header_t) + offsetof(ip4_header_t, src_address)); -} - -static int -macip_create_classify_tables (acl_main_t * am, u32 macip_acl_index) -{ - macip_match_type_t *mvec = NULL; - macip_match_type_t *mt; - macip_acl_list_t *a = &am->macip_acls[macip_acl_index]; - int i; - u32 match_type_index; - u32 last_table; - u8 mask[5 * 16]; - vnet_classify_main_t *cm = &vnet_classify_main; - - /* Count the number of different types of rules */ - for (i = 0; i < a->count; i++) - { - if (~0 == - (match_type_index = - macip_find_match_type (mvec, a->rules[i].src_mac_mask, - a->rules[i].src_prefixlen, - a->rules[i].is_ipv6))) - { - match_type_index = vec_len (mvec); - vec_validate (mvec, match_type_index); - memcpy (mvec[match_type_index].mac_mask, - a->rules[match_type_index].src_mac_mask, 6); - mvec[match_type_index].prefix_len = a->rules[i].src_prefixlen; - mvec[match_type_index].is_ipv6 = a->rules[i].is_ipv6; - mvec[match_type_index].table_index = ~0; - } - mvec[match_type_index].count++; - } - /* Put the most frequently used tables last in the list so we can create classifier tables in reverse order */ - vec_sort_with_function (mvec, match_type_compare); - /* Create the classifier tables */ - last_table = ~0; - vec_foreach (mt, mvec) - { - int mask_len; - int is6 = mt->is_ipv6; - int l3_src_offs = get_l3_src_offset(is6); - memset (mask, 0, sizeof (mask)); - memcpy (&mask[6], mt->mac_mask, 6); - for (i = 0; i < (mt->prefix_len / 8); i++) - { - mask[l3_src_offs + i] = 0xff; - } - if (mt->prefix_len % 8) - { - mask[l3_src_offs + (mt->prefix_len / 8)] = - 0xff - ((1 << (8 - mt->prefix_len % 8)) - 1); - } - /* - * Round-up the number of bytes needed to store the prefix, - * and round up the number of vectors too - */ - mask_len = ((l3_src_offs + ((mt->prefix_len+7) / 8) + - (sizeof (u32x4)-1))/sizeof(u32x4)) * sizeof (u32x4); - acl_classify_add_del_table_small (cm, mask, mask_len, last_table, - (~0 == last_table) ? 0 : ~0, &mt->table_index, - 1); - last_table = mt->table_index; - } - a->ip4_table_index = ~0; - a->ip6_table_index = ~0; - a->l2_table_index = last_table; - - /* Populate the classifier tables with rules from the MACIP ACL */ - for (i = 0; i < a->count; i++) - { - u32 action = 0; - u32 metadata = 0; - int is6 = a->rules[i].is_ipv6; - int l3_src_offs = get_l3_src_offset(is6); - memset (mask, 0, sizeof (mask)); - memcpy (&mask[6], a->rules[i].src_mac, 6); - if (is6) - { - memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip6, 16); - } - else - { - memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip4, 4); - } - match_type_index = - macip_find_match_type (mvec, a->rules[i].src_mac_mask, - a->rules[i].src_prefixlen, - a->rules[i].is_ipv6); - /* add session to table mvec[match_type_index].table_index; */ - vnet_classify_add_del_session (cm, mvec[match_type_index].table_index, - mask, a->rules[i].is_permit ? ~0 : 0, i, - 0, action, metadata, 1); - } - return 0; -} - -static void -macip_destroy_classify_tables (acl_main_t * am, u32 macip_acl_index) -{ - vnet_classify_main_t *cm = &vnet_classify_main; - macip_acl_list_t *a = &am->macip_acls[macip_acl_index]; - - if (a->ip4_table_index != ~0) - { - acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->ip4_table_index, 0); - a->ip4_table_index = ~0; - } - if (a->ip6_table_index != ~0) - { - acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->ip6_table_index, 0); - a->ip6_table_index = ~0; - } - if (a->l2_table_index != ~0) - { - acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->l2_table_index, 0); - a->l2_table_index = ~0; - } -} - -static int -macip_acl_add_list (u32 count, vl_api_macip_acl_rule_t rules[], - u32 * acl_list_index, u8 * tag) -{ - acl_main_t *am = &acl_main; - macip_acl_list_t *a; - macip_acl_rule_t *r; - macip_acl_rule_t *acl_new_rules; - int i; - - /* Create and populate the rules */ - acl_new_rules = clib_mem_alloc_aligned (sizeof (macip_acl_rule_t) * count, - CLIB_CACHE_LINE_BYTES); - if (!acl_new_rules) - { - /* Could not allocate rules. New or existing ACL - bail out regardless */ - return -1; - } - - for (i = 0; i < count; i++) - { - r = &acl_new_rules[i]; - r->is_permit = rules[i].is_permit; - r->is_ipv6 = rules[i].is_ipv6; - memcpy (&r->src_mac, rules[i].src_mac, 6); - memcpy (&r->src_mac_mask, rules[i].src_mac_mask, 6); - if(rules[i].is_ipv6) - memcpy (&r->src_ip_addr.ip6, rules[i].src_ip_addr, 16); - else - memcpy (&r->src_ip_addr.ip4, rules[i].src_ip_addr, 4); - r->src_prefixlen = rules[i].src_ip_prefix_len; - } - - /* Get ACL index */ - pool_get_aligned (am->macip_acls, a, CLIB_CACHE_LINE_BYTES); - memset (a, 0, sizeof (*a)); - /* Will return the newly allocated ACL index */ - *acl_list_index = a - am->macip_acls; - - a->rules = acl_new_rules; - a->count = count; - memcpy (a->tag, tag, sizeof (a->tag)); - - /* Create and populate the classifer tables */ - macip_create_classify_tables (am, *acl_list_index); - - return 0; -} - - -/* No check for validity of sw_if_index - the callers were supposed to validate */ - -static int -macip_acl_interface_del_acl (acl_main_t * am, u32 sw_if_index) -{ - int rv; - u32 macip_acl_index; - macip_acl_list_t *a; - vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0); - macip_acl_index = am->macip_acl_by_sw_if_index[sw_if_index]; - /* No point in deleting MACIP ACL which is not applied */ - if (~0 == macip_acl_index) - return -1; - a = &am->macip_acls[macip_acl_index]; - /* remove the classifier tables off the interface L2 ACL */ - rv = - vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index, - a->ip6_table_index, a->l2_table_index, 0); - /* Unset the MACIP ACL index */ - am->macip_acl_by_sw_if_index[sw_if_index] = ~0; - return rv; -} - -/* No check for validity of sw_if_index - the callers were supposed to validate */ - -static int -macip_acl_interface_add_acl (acl_main_t * am, u32 sw_if_index, - u32 macip_acl_index) -{ - macip_acl_list_t *a; - int rv; - if (pool_is_free_index (am->macip_acls, macip_acl_index)) - { - return -1; - } - a = &am->macip_acls[macip_acl_index]; - vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0); - /* If there already a MACIP ACL applied, unapply it */ - if (~0 != am->macip_acl_by_sw_if_index[sw_if_index]) - macip_acl_interface_del_acl(am, sw_if_index); - am->macip_acl_by_sw_if_index[sw_if_index] = macip_acl_index; - /* Apply the classifier tables for L2 ACLs */ - rv = - vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index, - a->ip6_table_index, a->l2_table_index, 1); - return rv; -} - -static int -macip_acl_del_list (u32 acl_list_index) -{ - acl_main_t *am = &acl_main; - macip_acl_list_t *a; - int i; - if (pool_is_free_index (am->macip_acls, acl_list_index)) - { - return -1; - } - - /* delete any references to the ACL */ - for (i = 0; i < vec_len (am->macip_acl_by_sw_if_index); i++) - { - if (am->macip_acl_by_sw_if_index[i] == acl_list_index) - { - macip_acl_interface_del_acl (am, i); - } - } - - /* Now that classifier tables are detached, clean them up */ - macip_destroy_classify_tables (am, acl_list_index); - - /* now we can delete the ACL itself */ - a = &am->macip_acls[acl_list_index]; - if (a->rules) - { - clib_mem_free (a->rules); - } - pool_put (am->macip_acls, a); - return 0; -} - - -static int -macip_acl_interface_add_del_acl (u32 sw_if_index, u8 is_add, - u32 acl_list_index) -{ - acl_main_t *am = &acl_main; - int rv = -1; - if (is_add) - { - rv = macip_acl_interface_add_acl (am, sw_if_index, acl_list_index); - } - else - { - rv = macip_acl_interface_del_acl (am, sw_if_index); - } - return rv; -} - -/* API message handler */ -static void -vl_api_acl_add_replace_t_handler (vl_api_acl_add_replace_t * mp) -{ - vl_api_acl_add_replace_reply_t *rmp; - acl_main_t *am = &acl_main; - int rv; - u32 acl_list_index = ntohl (mp->acl_index); - - rv = acl_add_list (ntohl (mp->count), mp->r, &acl_list_index, mp->tag); - - /* *INDENT-OFF* */ - REPLY_MACRO2(VL_API_ACL_ADD_REPLACE_REPLY, - ({ - rmp->acl_index = htonl(acl_list_index); - })); - /* *INDENT-ON* */ -} - -static void -vl_api_acl_del_t_handler (vl_api_acl_del_t * mp) -{ - acl_main_t *sm = &acl_main; - vl_api_acl_del_reply_t *rmp; - int rv; - - rv = acl_del_list (ntohl (mp->acl_index)); - - REPLY_MACRO (VL_API_ACL_DEL_REPLY); -} - -static void -vl_api_acl_interface_add_del_t_handler (vl_api_acl_interface_add_del_t * mp) -{ - acl_main_t *sm = &acl_main; - vnet_interface_main_t *im = &sm->vnet_main->interface_main; - u32 sw_if_index = ntohl (mp->sw_if_index); - vl_api_acl_interface_add_del_reply_t *rmp; - int rv = -1; - - if (pool_is_free_index(im->sw_interfaces, sw_if_index)) - rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; - else - rv = - acl_interface_add_del_inout_acl (sw_if_index, mp->is_add, - mp->is_input, ntohl (mp->acl_index)); - - REPLY_MACRO (VL_API_ACL_INTERFACE_ADD_DEL_REPLY); -} - -static void -vl_api_acl_interface_set_acl_list_t_handler - (vl_api_acl_interface_set_acl_list_t * mp) -{ - acl_main_t *sm = &acl_main; - vl_api_acl_interface_set_acl_list_reply_t *rmp; - int rv = 0; - int i; - vnet_interface_main_t *im = &sm->vnet_main->interface_main; - u32 sw_if_index = ntohl (mp->sw_if_index); - - if (pool_is_free_index(im->sw_interfaces, sw_if_index)) - rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; - else - { - acl_interface_reset_inout_acls (sw_if_index, 0); - acl_interface_reset_inout_acls (sw_if_index, 1); - - for (i = 0; i < mp->count; i++) - { - acl_interface_add_del_inout_acl (sw_if_index, 1, (i < mp->n_input), - ntohl (mp->acls[i])); - } - } - - REPLY_MACRO (VL_API_ACL_INTERFACE_SET_ACL_LIST_REPLY); -} - -static void -copy_acl_rule_to_api_rule (vl_api_acl_rule_t * api_rule, acl_rule_t * r) -{ - api_rule->is_permit = r->is_permit; - api_rule->is_ipv6 = r->is_ipv6; - if(r->is_ipv6) - { - memcpy (api_rule->src_ip_addr, &r->src, sizeof (r->src)); - memcpy (api_rule->dst_ip_addr, &r->dst, sizeof (r->dst)); - } - else - { - memcpy (api_rule->src_ip_addr, &r->src.ip4, sizeof (r->src.ip4)); - memcpy (api_rule->dst_ip_addr, &r->dst.ip4, sizeof (r->dst.ip4)); - } - api_rule->src_ip_prefix_len = r->src_prefixlen; - api_rule->dst_ip_prefix_len = r->dst_prefixlen; - api_rule->proto = r->proto; - api_rule->srcport_or_icmptype_first = r->src_port_or_type_first; - api_rule->srcport_or_icmptype_last = r->src_port_or_type_last; - api_rule->dstport_or_icmpcode_first = r->dst_port_or_code_first; - api_rule->dstport_or_icmpcode_last = r->dst_port_or_code_last; - api_rule->tcp_flags_mask = r->tcp_flags_mask; - api_rule->tcp_flags_value = r->tcp_flags_value; -} - -static void -send_acl_details (acl_main_t * am, unix_shared_memory_queue_t * q, - acl_list_t * acl, u32 context) -{ - vl_api_acl_details_t *mp; - vl_api_acl_rule_t *rules; - int i; - int msg_size = sizeof (*mp) + sizeof (mp->r[0]) * acl->count; - - mp = vl_msg_api_alloc (msg_size); - memset (mp, 0, msg_size); - mp->_vl_msg_id = ntohs (VL_API_ACL_DETAILS + am->msg_id_base); - - /* fill in the message */ - mp->context = context; - mp->count = htonl (acl->count); - mp->acl_index = htonl (acl - am->acls); - memcpy (mp->tag, acl->tag, sizeof (mp->tag)); - // clib_memcpy (mp->r, acl->rules, acl->count * sizeof(acl->rules[0])); - rules = mp->r; - for (i = 0; i < acl->count; i++) - { - copy_acl_rule_to_api_rule (&rules[i], &acl->rules[i]); - } - - clib_warning("Sending acl details for ACL index %d", ntohl(mp->acl_index)); - vl_msg_api_send_shmem (q, (u8 *) & mp); -} - - -static void -vl_api_acl_dump_t_handler (vl_api_acl_dump_t * mp) -{ - acl_main_t *am = &acl_main; - u32 acl_index; - acl_list_t *acl; - - int rv = -1; - unix_shared_memory_queue_t *q; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - { - return; - } - - if (mp->acl_index == ~0) - { - /* *INDENT-OFF* */ - /* Just dump all ACLs */ - pool_foreach (acl, am->acls, - ({ - send_acl_details(am, q, acl, mp->context); - })); - /* *INDENT-ON* */ - } - else - { - acl_index = ntohl (mp->acl_index); - if (!pool_is_free_index (am->acls, acl_index)) - { - acl = &am->acls[acl_index]; - send_acl_details (am, q, acl, mp->context); - } - } - - if (rv == -1) - { - /* FIXME API: should we signal an error here at all ? */ - return; - } -} - -static void -send_acl_interface_list_details (acl_main_t * am, - unix_shared_memory_queue_t * q, - u32 sw_if_index, u32 context) -{ - vl_api_acl_interface_list_details_t *mp; - int msg_size; - int n_input; - int n_output; - int count; - int i = 0; - - vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index); - vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index); - - n_input = vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]); - n_output = vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]); - count = n_input + n_output; - - msg_size = sizeof (*mp); - msg_size += sizeof (mp->acls[0]) * count; - - mp = vl_msg_api_alloc (msg_size); - memset (mp, 0, msg_size); - mp->_vl_msg_id = - ntohs (VL_API_ACL_INTERFACE_LIST_DETAILS + am->msg_id_base); - - /* fill in the message */ - mp->context = context; - mp->sw_if_index = htonl (sw_if_index); - mp->count = count; - mp->n_input = n_input; - for (i = 0; i < n_input; i++) - { - mp->acls[i] = htonl (am->input_acl_vec_by_sw_if_index[sw_if_index][i]); - } - for (i = 0; i < n_output; i++) - { - mp->acls[n_input + i] = - htonl (am->output_acl_vec_by_sw_if_index[sw_if_index][i]); - } - - vl_msg_api_send_shmem (q, (u8 *) & mp); -} - -static void -vl_api_acl_interface_list_dump_t_handler (vl_api_acl_interface_list_dump_t * - mp) -{ - acl_main_t *am = &acl_main; - vnet_sw_interface_t *swif; - vnet_interface_main_t *im = &am->vnet_main->interface_main; - - u32 sw_if_index; - unix_shared_memory_queue_t *q; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - { - return; - } - - if (mp->sw_if_index == ~0) - { - /* *INDENT-OFF* */ - pool_foreach (swif, im->sw_interfaces, - ({ - send_acl_interface_list_details(am, q, swif->sw_if_index, mp->context); - })); - /* *INDENT-ON* */ - } - else - { - sw_if_index = ntohl (mp->sw_if_index); - if (!pool_is_free_index(im->sw_interfaces, sw_if_index)) - send_acl_interface_list_details (am, q, sw_if_index, mp->context); - } -} - -/* MACIP ACL API handlers */ - -static void -vl_api_macip_acl_add_t_handler (vl_api_macip_acl_add_t * mp) -{ - vl_api_macip_acl_add_reply_t *rmp; - acl_main_t *am = &acl_main; - int rv; - u32 acl_list_index = ~0; - - rv = - macip_acl_add_list (ntohl (mp->count), mp->r, &acl_list_index, mp->tag); - - /* *INDENT-OFF* */ - REPLY_MACRO2(VL_API_MACIP_ACL_ADD_REPLY, - ({ - rmp->acl_index = htonl(acl_list_index); - })); - /* *INDENT-ON* */ -} - -static void -vl_api_macip_acl_del_t_handler (vl_api_macip_acl_del_t * mp) -{ - acl_main_t *sm = &acl_main; - vl_api_macip_acl_del_reply_t *rmp; - int rv; - - rv = macip_acl_del_list (ntohl (mp->acl_index)); - - REPLY_MACRO (VL_API_MACIP_ACL_DEL_REPLY); -} - -static void -vl_api_macip_acl_interface_add_del_t_handler - (vl_api_macip_acl_interface_add_del_t * mp) -{ - acl_main_t *sm = &acl_main; - vl_api_macip_acl_interface_add_del_reply_t *rmp; - int rv = -1; - vnet_interface_main_t *im = &sm->vnet_main->interface_main; - u32 sw_if_index = ntohl (mp->sw_if_index); - - if (pool_is_free_index(im->sw_interfaces, sw_if_index)) - rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; - else - rv = - macip_acl_interface_add_del_acl (ntohl (mp->sw_if_index), mp->is_add, - ntohl (mp->acl_index)); - - REPLY_MACRO (VL_API_MACIP_ACL_INTERFACE_ADD_DEL_REPLY); -} - -static void -send_macip_acl_details (acl_main_t * am, unix_shared_memory_queue_t * q, - macip_acl_list_t * acl, u32 context) -{ - vl_api_macip_acl_details_t *mp; - vl_api_macip_acl_rule_t *rules; - macip_acl_rule_t *r; - int i; - int msg_size = sizeof (*mp) + (acl ? sizeof (mp->r[0]) * acl->count : 0); - - mp = vl_msg_api_alloc (msg_size); - memset (mp, 0, msg_size); - mp->_vl_msg_id = ntohs (VL_API_MACIP_ACL_DETAILS + am->msg_id_base); - - /* fill in the message */ - mp->context = context; - if (acl) - { - memcpy (mp->tag, acl->tag, sizeof (mp->tag)); - mp->count = htonl (acl->count); - mp->acl_index = htonl (acl - am->macip_acls); - rules = mp->r; - for (i = 0; i < acl->count; i++) - { - r = &acl->rules[i]; - rules[i].is_permit = r->is_permit; - rules[i].is_ipv6 = r->is_ipv6; - memcpy (rules[i].src_mac, &r->src_mac, sizeof (r->src_mac)); - memcpy (rules[i].src_mac_mask, &r->src_mac_mask, - sizeof (r->src_mac_mask)); - if (r->is_ipv6) - memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip6, - sizeof (r->src_ip_addr.ip6)); - else - memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip4, - sizeof (r->src_ip_addr.ip4)); - rules[i].src_ip_prefix_len = r->src_prefixlen; - } - } - else - { - /* No martini, no party - no ACL applied to this interface. */ - mp->acl_index = ~0; - mp->count = 0; - } - - vl_msg_api_send_shmem (q, (u8 *) & mp); -} - - -static void -vl_api_macip_acl_dump_t_handler (vl_api_macip_acl_dump_t * mp) -{ - acl_main_t *am = &acl_main; - macip_acl_list_t *acl; - - unix_shared_memory_queue_t *q; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - { - return; - } - - if (mp->acl_index == ~0) - { - /* Just dump all ACLs for now, with sw_if_index = ~0 */ - pool_foreach (acl, am->macip_acls, ( - { - send_macip_acl_details (am, q, acl, - mp-> - context);} - )); - /* *INDENT-ON* */ - } - else - { - u32 acl_index = ntohl (mp->acl_index); - if (!pool_is_free_index (am->macip_acls, acl_index)) - { - acl = &am->macip_acls[acl_index]; - send_macip_acl_details (am, q, acl, mp->context); - } - } -} - -static void -vl_api_macip_acl_interface_get_t_handler (vl_api_macip_acl_interface_get_t * - mp) -{ - acl_main_t *am = &acl_main; - vl_api_macip_acl_interface_get_reply_t *rmp; - u32 count = vec_len (am->macip_acl_by_sw_if_index); - int msg_size = sizeof (*rmp) + sizeof (rmp->acls[0]) * count; - unix_shared_memory_queue_t *q; - int i; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - { - return; - } - - rmp = vl_msg_api_alloc (msg_size); - memset (rmp, 0, msg_size); - rmp->_vl_msg_id = - ntohs (VL_API_MACIP_ACL_INTERFACE_GET_REPLY + am->msg_id_base); - rmp->context = mp->context; - rmp->count = htonl (count); - for (i = 0; i < count; i++) - { - rmp->acls[i] = htonl (am->macip_acl_by_sw_if_index[i]); - } - - vl_msg_api_send_shmem (q, (u8 *) & rmp); -} - - - -/* Set up the API message handling tables */ -static clib_error_t * -acl_plugin_api_hookup (vlib_main_t * vm) -{ - acl_main_t *sm = &acl_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_acl_plugin_api_msg; -#undef _ - - return 0; -} - -#define vl_msg_name_crc_list -#include -#undef vl_msg_name_crc_list - -static void -setup_message_id_table (acl_main_t * sm, api_main_t * am) -{ -#define _(id,n,crc) \ - vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base); - foreach_vl_msg_name_crc_acl; -#undef _ -} - -u32 -register_match_action_nexts (u32 next_in_ip4, u32 next_in_ip6, - u32 next_out_ip4, u32 next_out_ip6) -{ - acl_main_t *am = &acl_main; - u32 act = am->n_match_actions; - if (am->n_match_actions == 255) - { - return ~0; - } - am->n_match_actions++; - am->acl_in_ip4_match_next[act] = next_in_ip4; - am->acl_in_ip6_match_next[act] = next_in_ip6; - am->acl_out_ip4_match_next[act] = next_out_ip4; - am->acl_out_ip6_match_next[act] = next_out_ip6; - return act; -} - -void -acl_setup_nodes (void) -{ - vlib_main_t *vm = vlib_get_main (); - acl_main_t *am = &acl_main; - vlib_node_t *n; - - n = vlib_get_node_by_name (vm, (u8 *) "l2-input-classify"); - am->l2_input_classify_next_acl = - vlib_node_add_next_with_slot (vm, n->index, acl_in_node.index, ~0); - n = vlib_get_node_by_name (vm, (u8 *) "l2-output-classify"); - am->l2_output_classify_next_acl = - vlib_node_add_next_with_slot (vm, n->index, acl_out_node.index, ~0); - - feat_bitmap_init_next_nodes (vm, acl_in_node.index, L2INPUT_N_FEAT, - l2input_get_feat_names (), - am->acl_in_node_input_next_node_index); - - memset (&am->acl_in_ip4_match_next[0], 0, - sizeof (am->acl_in_ip4_match_next)); - memset (&am->acl_in_ip6_match_next[0], 0, - sizeof (am->acl_in_ip6_match_next)); - memset (&am->acl_out_ip4_match_next[0], 0, - sizeof (am->acl_out_ip4_match_next)); - memset (&am->acl_out_ip6_match_next[0], 0, - sizeof (am->acl_out_ip6_match_next)); - am->n_match_actions = 0; - - register_match_action_nexts (0, 0, 0, 0); /* drop */ - register_match_action_nexts (~0, ~0, ~0, ~0); /* permit */ - register_match_action_nexts (ACL_IN_L2S_INPUT_IP4_ADD, ACL_IN_L2S_INPUT_IP6_ADD, ACL_OUT_L2S_OUTPUT_IP4_ADD, ACL_OUT_L2S_OUTPUT_IP6_ADD); /* permit + create session */ -} - - - -static clib_error_t * -acl_init (vlib_main_t * vm) -{ - acl_main_t *am = &acl_main; - clib_error_t *error = 0; - memset (am, 0, sizeof (*am)); - am->vlib_main = vm; - am->vnet_main = vnet_get_main (); - - u8 *name = format (0, "acl_%08x%c", api_version, 0); - - /* Ask for a correctly-sized block of API message decode slots */ - am->msg_id_base = vl_msg_api_get_msg_ids ((char *) name, - VL_MSG_FIRST_AVAILABLE); - - error = acl_plugin_api_hookup (vm); - acl_setup_nodes (); - - /* Add our API messages to the global name_crc hash table */ - setup_message_id_table (am, &api_main); - - vec_free (name); - - return error; -} - -VLIB_INIT_FUNCTION (acl_init); diff --git a/plugins/acl-plugin/acl/acl.h b/plugins/acl-plugin/acl/acl.h deleted file mode 100644 index afc9b289..00000000 --- a/plugins/acl-plugin/acl/acl.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * 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. - */ -#ifndef included_acl_h -#define included_acl_h - -#include -#include -#include -#include - - -#include -#include -#include - -#define ACL_PLUGIN_VERSION_MAJOR 1 -#define ACL_PLUGIN_VERSION_MINOR 1 - -extern vlib_node_registration_t acl_in_node; -extern vlib_node_registration_t acl_out_node; - -void input_acl_packet_match(u32 sw_if_index, vlib_buffer_t * b0, u32 *nextp, u32 *acl_match_p, u32 *rule_match_p, u32 *trace_bitmap); -void output_acl_packet_match(u32 sw_if_index, vlib_buffer_t * b0, u32 *nextp, u32 *acl_match_p, u32 *rule_match_p, u32 *trace_bitmap); - -enum address_e { IP4, IP6 }; -typedef struct -{ - enum address_e type; - union { - ip6_address_t ip6; - ip4_address_t ip4; - } addr; -} address_t; - -/* - * ACL rules - */ -typedef struct -{ - u8 is_permit; - u8 is_ipv6; - ip46_address_t src; - u8 src_prefixlen; - ip46_address_t dst; - u8 dst_prefixlen; - u8 proto; - u16 src_port_or_type_first; - u16 src_port_or_type_last; - u16 dst_port_or_code_first; - u16 dst_port_or_code_last; - u8 tcp_flags_value; - u8 tcp_flags_mask; -} acl_rule_t; - -typedef struct -{ - u8 is_permit; - u8 is_ipv6; - u8 src_mac[6]; - u8 src_mac_mask[6]; - ip46_address_t src_ip_addr; - u8 src_prefixlen; -} macip_acl_rule_t; - -/* - * ACL - */ -typedef struct -{ - u8 tag[64]; - u32 count; - acl_rule_t *rules; -} acl_list_t; - -typedef struct -{ - u8 tag[64]; - u32 count; - macip_acl_rule_t *rules; - /* References to the classifier tables that will enforce the rules */ - u32 ip4_table_index; - u32 ip6_table_index; - u32 l2_table_index; -} macip_acl_list_t; - -typedef struct { - /* API message ID base */ - u16 msg_id_base; - - acl_list_t *acls; /* Pool of ACLs */ - macip_acl_list_t *macip_acls; /* Pool of MAC-IP ACLs */ - - /* ACLs associated with interfaces */ - u32 **input_acl_vec_by_sw_if_index; - u32 **output_acl_vec_by_sw_if_index; - - /* - * Classify tables used to grab the packets for the ACL check, - * and serving as the 5-tuple session tables at the same time - */ - u32 *acl_ip4_input_classify_table_by_sw_if_index; - u32 *acl_ip6_input_classify_table_by_sw_if_index; - u32 *acl_ip4_output_classify_table_by_sw_if_index; - u32 *acl_ip6_output_classify_table_by_sw_if_index; - - /* MACIP (input) ACLs associated with the interfaces */ - u32 *macip_acl_by_sw_if_index; - - /* next indices for our nodes in the l2-classify tables */ - u32 l2_input_classify_next_acl; - u32 l2_output_classify_next_acl; - - /* next node indices for feature bitmap */ - u32 acl_in_node_input_next_node_index[32]; - /* the respective thing for the output feature */ - l2_output_next_nodes_st acl_out_output_next_nodes; - - /* ACL match actions (must be coherent across in/out ACLs to next indices (can differ) */ - - u32 acl_in_ip4_match_next[256]; - u32 acl_in_ip6_match_next[256]; - u32 acl_out_ip4_match_next[256]; - u32 acl_out_ip6_match_next[256]; - u32 n_match_actions; - - - /* convenience */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; - ethernet_main_t * ethernet_main; -} acl_main_t; - -extern acl_main_t acl_main; - - -#endif diff --git a/plugins/acl-plugin/acl/acl_all_api_h.h b/plugins/acl-plugin/acl/acl_all_api_h.h deleted file mode 100644 index 96eca56d..00000000 --- a/plugins/acl-plugin/acl/acl_all_api_h.h +++ /dev/null @@ -1,321 +0,0 @@ -/* - * 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. - */ -/* Include the generated file, see BUILT_SOURCES in Makefile.am */ -#include - -#ifdef vl_printfun - -#ifdef LP64 -#define _uword_fmt "%lld" -#define _uword_cast (long long) -#else -#define _uword_fmt "%ld" -#define _uword_cast long -#endif - -static inline void * -vl_api_acl_rule_t_print (vl_api_acl_rule_t * a, void *handle) -{ - vl_print (handle, "vl_api_acl_rule_t:\n"); - vl_print (handle, "is_permit: %u\n", (unsigned) a->is_permit); - vl_print (handle, "is_ipv6: %u\n", (unsigned) a->is_ipv6); - { - int _i; - for (_i = 0; _i < 16; _i++) - { - vl_print (handle, "src_ip_addr[%d]: %u\n", _i, a->src_ip_addr[_i]); - } - } - vl_print (handle, "src_ip_prefix_len: %u\n", - (unsigned) a->src_ip_prefix_len); - { - int _i; - for (_i = 0; _i < 16; _i++) - { - vl_print (handle, "dst_ip_addr[%d]: %u\n", _i, a->dst_ip_addr[_i]); - } - } - vl_print (handle, "dst_ip_prefix_len: %u\n", - (unsigned) a->dst_ip_prefix_len); - vl_print (handle, "proto: %u\n", (unsigned) a->proto); - vl_print (handle, "srcport_or_icmptype_first: %u\n", - (unsigned) a->srcport_or_icmptype_first); - vl_print (handle, "srcport_or_icmptype_last: %u\n", - (unsigned) a->srcport_or_icmptype_last); - vl_print (handle, "dstport_or_icmpcode_first: %u\n", - (unsigned) a->dstport_or_icmpcode_first); - vl_print (handle, "dstport_or_icmpcode_last: %u\n", - (unsigned) a->dstport_or_icmpcode_last); - vl_print (handle, "tcp_flags_mask: %u\n", (unsigned) a->tcp_flags_mask); - vl_print (handle, "tcp_flags_value: %u\n", (unsigned) a->tcp_flags_value); - return handle; -} - -static inline void * -vl_api_acl_add_replace_t_print (vl_api_acl_add_replace_t * a, void *handle) -{ - int i; - vl_print (handle, "vl_api_acl_add_replace_t:\n"); - vl_print (handle, "_vl_msg_id: %u\n", (unsigned) a->_vl_msg_id); - vl_print (handle, "client_index: %u\n", (unsigned) a->client_index); - vl_print (handle, "context: %u\n", (unsigned) a->context); - vl_print (handle, "acl_index: %u\n", (unsigned) a->acl_index); - vl_print (handle, "count: %u\n", (unsigned) a->count); - vl_print (handle, "r ----- \n"); - for (i = 0; i < a->count; i++) - { - vl_print (handle, " r[%d]:\n", i); - vl_api_acl_rule_t_print (&a->r[i], handle); - } - vl_print (handle, "r ----- END \n"); - return handle; -} - - -static inline void *vl_api_acl_details_t_print (vl_api_acl_details_t *a,void *handle) -{ - vl_print(handle, "vl_api_acl_details_t:\n"); - vl_print(handle, "_vl_msg_id: %u\n", (unsigned) a->_vl_msg_id); - vl_print(handle, "context: %u\n", (unsigned) a->context); - vl_print(handle, "acl_index: %u\n", (unsigned) a->acl_index); - { - int _i; - for (_i = 0; _i < 64; _i++) { - vl_print(handle, "tag[%d]: %u\n", _i, a->tag[_i]); - } - } - vl_print(handle, "count: %u\n", (unsigned) a->count); - vl_print(handle, "r ----- \n"); - // FIXME vl_api_acl_rule_t_print(&a->r, handle); - vl_print(handle, "r ----- END \n"); - return handle; -} - -static inline void * -vl_api_macip_acl_rule_t_print (vl_api_macip_acl_rule_t * a, void *handle) -{ - vl_print (handle, "vl_api_macip_acl_rule_t:\n"); - vl_print (handle, "is_permit: %u\n", (unsigned) a->is_permit); - vl_print (handle, "is_ipv6: %u\n", (unsigned) a->is_ipv6); - { - int _i; - for (_i = 0; _i < 6; _i++) - { - vl_print (handle, "src_mac[%d]: %u\n", _i, a->src_mac[_i]); - } - } - { - int _i; - for (_i = 0; _i < 6; _i++) - { - vl_print (handle, "src_mac_mask[%d]: %u\n", _i, a->src_mac_mask[_i]); - } - } - { - int _i; - for (_i = 0; _i < 16; _i++) - { - vl_print (handle, "src_ip_addr[%d]: %u\n", _i, a->src_ip_addr[_i]); - } - } - vl_print (handle, "src_ip_prefix_len: %u\n", - (unsigned) a->src_ip_prefix_len); - return handle; -} - -static inline void * -vl_api_macip_acl_add_t_print (vl_api_macip_acl_add_t * a, void *handle) -{ - int i; - vl_print (handle, "vl_api_macip_acl_add_t:\n"); - vl_print (handle, "_vl_msg_id: %u\n", (unsigned) a->_vl_msg_id); - vl_print (handle, "client_index: %u\n", (unsigned) a->client_index); - vl_print (handle, "context: %u\n", (unsigned) a->context); - vl_print (handle, "count: %u\n", (unsigned) a->count); - vl_print (handle, "r ----- \n"); - for (i = 0; i < a->count; i++) - { - vl_print (handle, " r[%d]:\n", i); - vl_api_macip_acl_rule_t_print (&a->r[i], handle); - } - vl_print (handle, "r ----- END \n"); - return handle; -} - -static inline void *vl_api_macip_acl_details_t_print (vl_api_macip_acl_details_t *a,void *handle) -{ - int i; - vl_print(handle, "vl_api_macip_acl_details_t:\n"); - vl_print(handle, "_vl_msg_id: %u\n", (unsigned) a->_vl_msg_id); - vl_print(handle, "context: %u\n", (unsigned) a->context); - vl_print(handle, "acl_index: %u\n", (unsigned) a->acl_index); - { - int _i; - for (_i = 0; _i < 64; _i++) { - vl_print(handle, "tag[%d]: %u\n", _i, a->tag[_i]); - } - } - vl_print(handle, "count: %u\n", (unsigned) a->count); - vl_print(handle, "r ----- \n"); - for (i = 0; i < a->count; i++) - { - vl_print (handle, " r[%d]:\n", i); - vl_api_macip_acl_rule_t_print (&a->r[i], handle); - } - vl_print(handle, "r ----- END \n"); - return handle; -} - -#endif /* vl_printfun */ - - -#ifdef vl_endianfun - -#undef clib_net_to_host_uword -#ifdef LP64 -#define clib_net_to_host_uword clib_net_to_host_u64 -#else -#define clib_net_to_host_uword clib_net_to_host_u32 -#endif - -/* - * Manual endian/print functions created by copypasting the automatically - * generated ones with small required adjustments. Appears the codegen - * can't make code to print the contents of custom-type array. - */ - -static inline void -vl_api_acl_rule_t_endian (vl_api_acl_rule_t * a) -{ - /* a->is_permit = a->is_permit (no-op) */ - /* a->is_ipv6 = a->is_ipv6 (no-op) */ - /* a->src_ip_addr[0..15] = a->src_ip_addr[0..15] (no-op) */ - /* a->src_ip_prefix_len = a->src_ip_prefix_len (no-op) */ - /* a->dst_ip_addr[0..15] = a->dst_ip_addr[0..15] (no-op) */ - /* a->dst_ip_prefix_len = a->dst_ip_prefix_len (no-op) */ - /* a->proto = a->proto (no-op) */ - a->srcport_or_icmptype_first = - clib_net_to_host_u16 (a->srcport_or_icmptype_first); - a->srcport_or_icmptype_last = - clib_net_to_host_u16 (a->srcport_or_icmptype_last); - a->dstport_or_icmpcode_first = - clib_net_to_host_u16 (a->dstport_or_icmpcode_first); - a->dstport_or_icmpcode_last = - clib_net_to_host_u16 (a->dstport_or_icmpcode_last); - /* a->tcp_flags_mask = a->tcp_flags_mask (no-op) */ - /* a->tcp_flags_value = a->tcp_flags_value (no-op) */ -} - -static inline void -vl_api_acl_add_replace_t_endian (vl_api_acl_add_replace_t * a) -{ - int i; - a->_vl_msg_id = clib_net_to_host_u16 (a->_vl_msg_id); - a->client_index = clib_net_to_host_u32 (a->client_index); - a->context = clib_net_to_host_u32 (a->context); - a->acl_index = clib_net_to_host_u32 (a->acl_index); - a->count = clib_net_to_host_u32 (a->count); - for (i = 0; i < a->count; i++) - { - vl_api_acl_rule_t_endian (&a->r[i]); - } -} - -static inline void vl_api_acl_details_t_endian (vl_api_acl_details_t *a) -{ - int i; - a->_vl_msg_id = clib_net_to_host_u16(a->_vl_msg_id); - a->context = clib_net_to_host_u32(a->context); - a->acl_index = clib_net_to_host_u32(a->acl_index); - /* a->tag[0..63] = a->tag[0..63] (no-op) */ - a->count = clib_net_to_host_u32(a->count); - for (i = 0; i < a->count; i++) - { - vl_api_acl_rule_t_endian (&a->r[i]); - } -} - -static inline void vl_api_acl_interface_list_details_t_endian (vl_api_acl_interface_list_details_t *a) -{ - int i; - a->_vl_msg_id = clib_net_to_host_u16(a->_vl_msg_id); - a->context = clib_net_to_host_u32(a->context); - a->sw_if_index = clib_net_to_host_u32(a->sw_if_index); - /* a->count = a->count (no-op) */ - /* a->n_input = a->n_input (no-op) */ - for(i=0; icount; i++) { - a->acls[i] = clib_net_to_host_u32(a->acls[i]); - } -} - -static inline void vl_api_acl_interface_set_acl_list_t_endian (vl_api_acl_interface_set_acl_list_t *a) -{ - int i; - a->_vl_msg_id = clib_net_to_host_u16(a->_vl_msg_id); - a->client_index = clib_net_to_host_u32(a->client_index); - a->context = clib_net_to_host_u32(a->context); - a->sw_if_index = clib_net_to_host_u32(a->sw_if_index); - /* a->count = a->count (no-op) */ - /* a->n_input = a->n_input (no-op) */ - for(i=0; icount; i++) { - a->acls[i] = clib_net_to_host_u32(a->acls[i]); - } -} - -static inline void -vl_api_macip_acl_rule_t_endian (vl_api_macip_acl_rule_t * a) -{ - /* a->is_permit = a->is_permit (no-op) */ - /* a->is_ipv6 = a->is_ipv6 (no-op) */ - /* a->src_mac[0..5] = a->src_mac[0..5] (no-op) */ - /* a->src_mac_mask[0..5] = a->src_mac_mask[0..5] (no-op) */ - /* a->src_ip_addr[0..15] = a->src_ip_addr[0..15] (no-op) */ - /* a->src_ip_prefix_len = a->src_ip_prefix_len (no-op) */ -} - -static inline void -vl_api_macip_acl_add_t_endian (vl_api_macip_acl_add_t * a) -{ - int i; - a->_vl_msg_id = clib_net_to_host_u16 (a->_vl_msg_id); - a->client_index = clib_net_to_host_u32 (a->client_index); - a->context = clib_net_to_host_u32 (a->context); - a->count = clib_net_to_host_u32 (a->count); - for (i = 0; i < a->count; i++) - { - vl_api_macip_acl_rule_t_endian (&a->r[i]); - } -} - -static inline void vl_api_macip_acl_details_t_endian (vl_api_macip_acl_details_t *a) -{ - int i; - a->_vl_msg_id = clib_net_to_host_u16(a->_vl_msg_id); - a->context = clib_net_to_host_u32(a->context); - a->acl_index = clib_net_to_host_u32(a->acl_index); - /* a->tag[0..63] = a->tag[0..63] (no-op) */ - a->count = clib_net_to_host_u32(a->count); - for (i = 0; i < a->count; i++) - { - vl_api_macip_acl_rule_t_endian (&a->r[i]); - } -} - - - - -#endif /* vl_printfun */ - - diff --git a/plugins/acl-plugin/acl/acl_msg_enum.h b/plugins/acl-plugin/acl/acl_msg_enum.h deleted file mode 100644 index 14d8b48c..00000000 --- a/plugins/acl-plugin/acl/acl_msg_enum.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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. - */ -#ifndef included_acl_msg_enum_h -#define included_acl_msg_enum_h - -#include - -#define vl_msg_id(n,h) n, -typedef enum { -#include - /* We'll want to know how many messages IDs we need... */ - VL_MSG_FIRST_AVAILABLE, -} vl_msg_id_t; -#undef vl_msg_id - -#endif diff --git a/plugins/acl-plugin/acl/acl_test.c b/plugins/acl-plugin/acl/acl_test.c deleted file mode 100644 index a0e413e1..00000000 --- a/plugins/acl-plugin/acl/acl_test.c +++ /dev/null @@ -1,1024 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - *------------------------------------------------------------------ - * acl_test.c - test harness plugin - *------------------------------------------------------------------ - */ - -#include -#include -#include -#include -#include -#include -#include - -uword unformat_sw_if_index (unformat_input_t * input, va_list * args); - -/* Declare message IDs */ -#include - -/* define message structures */ -#define vl_typedefs -#include -#undef vl_typedefs - -/* define message structures */ -#define vl_endianfun -#include -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) -#define vl_printfun -#include -#undef vl_printfun - -/* Get the API version number. */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#undef vl_api_version - -typedef struct { - /* API message ID base */ - u16 msg_id_base; - vat_main_t *vat_main; -} acl_test_main_t; - -acl_test_main_t acl_test_main; - -#define foreach_standard_reply_retval_handler \ -_(acl_del_reply) \ -_(acl_interface_add_del_reply) \ -_(macip_acl_interface_add_del_reply) \ -_(acl_interface_set_acl_list_reply) \ -_(macip_acl_del_reply) - -#define foreach_reply_retval_aclindex_handler \ -_(acl_add_replace_reply) \ -_(macip_acl_add_reply) - -#define _(n) \ - static void vl_api_##n##_t_handler \ - (vl_api_##n##_t * mp) \ - { \ - vat_main_t * vam = acl_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 _ - -#define _(n) \ - static void vl_api_##n##_t_handler \ - (vl_api_##n##_t * mp) \ - { \ - vat_main_t * vam = acl_test_main.vat_main; \ - i32 retval = ntohl(mp->retval); \ - if (vam->async_mode) { \ - vam->async_errors += (retval < 0); \ - } else { \ - clib_warning("ACL index: %d", ntohl(mp->acl_index)); \ - vam->retval = retval; \ - vam->result_ready = 1; \ - } \ - } -foreach_reply_retval_aclindex_handler; -#undef _ - -/* These two ought to be in a library somewhere but they aren't */ -static uword -my_unformat_mac_address (unformat_input_t * input, va_list * args) -{ - u8 *a = va_arg (*args, u8 *); - return unformat (input, "%x:%x:%x:%x:%x:%x", &a[0], &a[1], &a[2], &a[3], - &a[4], &a[5]); -} - -static u8 * -my_format_mac_address (u8 * s, va_list * args) -{ - u8 *a = va_arg (*args, u8 *); - return format (s, "%02x:%02x:%02x:%02x:%02x:%02x", - a[0], a[1], a[2], a[3], a[4], a[5]); -} - - - -static void vl_api_acl_plugin_get_version_reply_t_handler - (vl_api_acl_plugin_get_version_reply_t * mp) - { - vat_main_t * vam = acl_test_main.vat_main; - clib_warning("ACL plugin version: %d.%d", ntohl(mp->major), ntohl(mp->minor)); - vam->result_ready = 1; - } - -static void vl_api_acl_interface_list_details_t_handler - (vl_api_acl_interface_list_details_t * mp) - { - int i; - vat_main_t * vam = acl_test_main.vat_main; - u8 *out = 0; - vl_api_acl_interface_list_details_t_endian(mp); - out = format(out, "sw_if_index: %d, count: %d, n_input: %d\n", mp->sw_if_index, mp->count, mp->n_input); - out = format(out, " input "); - for(i=0; icount; i++) { - out = format(out, "%d ", mp->acls[i]); - if (i == mp->n_input-1) - out = format(out, "\n output "); - } - out = format(out, "\n"); - clib_warning("%s", out); - vec_free(out); - vam->result_ready = 1; - } - - -static inline u8 * -vl_api_acl_rule_t_pretty_format (u8 *out, vl_api_acl_rule_t * a) -{ - int af = a->is_ipv6 ? AF_INET6 : AF_INET; - u8 src[INET6_ADDRSTRLEN]; - u8 dst[INET6_ADDRSTRLEN]; - inet_ntop(af, a->src_ip_addr, (void *)src, sizeof(src)); - inet_ntop(af, a->dst_ip_addr, (void *)dst, sizeof(dst)); - - out = format(out, "%s action %d src %s/%d dst %s/%d proto %d sport %d-%d dport %d-%d tcpflags %d %d", - a->is_ipv6 ? "ipv6" : "ipv4", a->is_permit, - src, a->src_ip_prefix_len, - dst, a->dst_ip_prefix_len, - a->proto, - a->srcport_or_icmptype_first, a->srcport_or_icmptype_last, - a->dstport_or_icmpcode_first, a->dstport_or_icmpcode_last, - a->tcp_flags_mask, a->tcp_flags_value); - return(out); -} - - - -static void vl_api_acl_details_t_handler - (vl_api_acl_details_t * mp) - { - int i; - vat_main_t * vam = acl_test_main.vat_main; - vl_api_acl_details_t_endian(mp); - u8 *out = 0; - out = format(0, "acl_index: %d, count: %d\n tag {%s}\n", mp->acl_index, mp->count, mp->tag); - for(i=0; icount; i++) { - out = format(out, " "); - out = vl_api_acl_rule_t_pretty_format(out, &mp->r[i]); - out = format(out, "%s\n", icount-1 ? "," : ""); - } - clib_warning("%s", out); - vec_free(out); - vam->result_ready = 1; - } - -static inline u8 * -vl_api_macip_acl_rule_t_pretty_format (u8 *out, vl_api_macip_acl_rule_t * a) -{ - int af = a->is_ipv6 ? AF_INET6 : AF_INET; - u8 src[INET6_ADDRSTRLEN]; - inet_ntop(af, a->src_ip_addr, (void *)src, sizeof(src)); - - out = format(out, "%s action %d ip %s/%d mac %U mask %U", - a->is_ipv6 ? "ipv6" : "ipv4", a->is_permit, - src, a->src_ip_prefix_len, - my_format_mac_address, a->src_mac, - my_format_mac_address, a->src_mac_mask); - return(out); -} - - -static void vl_api_macip_acl_details_t_handler - (vl_api_macip_acl_details_t * mp) - { - int i; - vat_main_t * vam = acl_test_main.vat_main; - vl_api_macip_acl_details_t_endian(mp); - u8 *out = format(0,"MACIP acl_index: %d, count: %d\n tag {%s}\n", mp->acl_index, mp->count, mp->tag); - for(i=0; icount; i++) { - out = format(out, " "); - out = vl_api_macip_acl_rule_t_pretty_format(out, &mp->r[i]); - out = format(out, "%s\n", icount-1 ? "," : ""); - } - clib_warning("%s", out); - vec_free(out); - vam->result_ready = 1; - } - -static void vl_api_macip_acl_interface_get_reply_t_handler - (vl_api_macip_acl_interface_get_reply_t * mp) - { - int i; - vat_main_t * vam = acl_test_main.vat_main; - u8 *out = format(0, "sw_if_index with MACIP ACL count: %d\n", ntohl(mp->count)); - for(i=0; icount); i++) { - out = format(out, " macip_acl_interface_add_del sw_if_index %d add acl %d\n", i, ntohl(mp->acls[i])); - } - out = format(out, "\n"); - clib_warning("%s", out); - vec_free(out); - vam->result_ready = 1; - } - - -/* - * Table of message reply handlers, must include boilerplate handlers - * we just generated - */ -#define foreach_vpe_api_reply_msg \ -_(ACL_ADD_REPLACE_REPLY, acl_add_replace_reply) \ -_(ACL_DEL_REPLY, acl_del_reply) \ -_(ACL_INTERFACE_ADD_DEL_REPLY, acl_interface_add_del_reply) \ -_(ACL_INTERFACE_SET_ACL_LIST_REPLY, acl_interface_set_acl_list_reply) \ -_(ACL_INTERFACE_LIST_DETAILS, acl_interface_list_details) \ -_(ACL_DETAILS, acl_details) \ -_(MACIP_ACL_ADD_REPLY, macip_acl_add_reply) \ -_(MACIP_ACL_DEL_REPLY, macip_acl_del_reply) \ -_(MACIP_ACL_DETAILS, macip_acl_details) \ -_(MACIP_ACL_INTERFACE_ADD_DEL_REPLY, macip_acl_interface_add_del_reply) \ -_(MACIP_ACL_INTERFACE_GET_REPLY, macip_acl_interface_get_reply) \ -_(ACL_PLUGIN_GET_VERSION_REPLY, acl_plugin_get_version_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_acl_plugin_get_version (vat_main_t * vam) -{ - acl_test_main_t * sm = &acl_test_main; - vl_api_acl_plugin_get_version_t * mp; - u32 msg_size = sizeof(*mp); - f64 timeout; - - vam->result_ready = 0; - mp = vl_msg_api_alloc_as_if_client(msg_size); - memset (mp, 0, msg_size); - mp->_vl_msg_id = ntohs (VL_API_ACL_PLUGIN_GET_VERSION + sm->msg_id_base); - mp->client_index = vam->my_client_index; - - /* send it... */ - S; - - /* Wait for a reply... */ - W; - - return 0; -} - -static int api_macip_acl_interface_get (vat_main_t * vam) -{ - acl_test_main_t * sm = &acl_test_main; - vl_api_acl_plugin_get_version_t * mp; - u32 msg_size = sizeof(*mp); - f64 timeout; - - vam->result_ready = 0; - mp = vl_msg_api_alloc_as_if_client(msg_size); - memset (mp, 0, msg_size); - mp->_vl_msg_id = ntohs (VL_API_MACIP_ACL_INTERFACE_GET + sm->msg_id_base); - mp->client_index = vam->my_client_index; - - /* send it... */ - S; - - /* Wait for a reply... */ - W; - - return 0; -} - -#define vec_validate_acl_rules(v, idx) \ - do { \ - if (vec_len(v) < idx+1) { \ - vec_validate(v, idx); \ - v[idx].is_permit = 0x1; \ - v[idx].srcport_or_icmptype_last = 0xffff; \ - v[idx].dstport_or_icmpcode_last = 0xffff; \ - } \ - } while (0) - - -static int api_acl_add_replace (vat_main_t * vam) -{ - acl_test_main_t * sm = &acl_test_main; - unformat_input_t * i = vam->input; - f64 timeout; - vl_api_acl_add_replace_t * mp; - u32 acl_index = ~0; - u32 msg_size = sizeof (*mp); /* without the rules */ - - vl_api_acl_rule_t *rules = 0; - int rule_idx = 0; - int n_rules = 0; - u32 proto = 0; - u32 port1 = 0; - u32 port2 = 0; - u32 action = 0; - u32 tcpflags, tcpmask; - u32 src_prefix_length = 0, dst_prefix_length = 0; - ip4_address_t src_v4address, dst_v4address; - ip6_address_t src_v6address, dst_v6address; - u8 *tag = 0; - - if (!unformat (i, "%d", &acl_index)) { - /* Just assume -1 */ - } - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "ipv6")) - { - vec_validate_acl_rules(rules, rule_idx); - rules[rule_idx].is_ipv6 = 1; - } - else if (unformat (i, "ipv4")) - { - vec_validate_acl_rules(rules, rule_idx); - rules[rule_idx].is_ipv6 = 0; - } - else if (unformat (i, "permit+reflect")) - { - vec_validate_acl_rules(rules, rule_idx); - rules[rule_idx].is_permit = 2; - } - else if (unformat (i, "permit")) - { - vec_validate_acl_rules(rules, rule_idx); - rules[rule_idx].is_permit = 1; - } - else if (unformat (i, "action %d", &action)) - { - vec_validate_acl_rules(rules, rule_idx); - rules[rule_idx].is_permit = action; - } - else if (unformat (i, "src %U/%d", - unformat_ip4_address, &src_v4address, &src_prefix_length)) - { - vec_validate_acl_rules(rules, rule_idx); - memcpy (rules[rule_idx].src_ip_addr, &src_v4address, 4); - rules[rule_idx].src_ip_prefix_len = src_prefix_length; - rules[rule_idx].is_ipv6 = 0; - } - else if (unformat (i, "src %U/%d", - unformat_ip6_address, &src_v6address, &src_prefix_length)) - { - vec_validate_acl_rules(rules, rule_idx); - memcpy (rules[rule_idx].src_ip_addr, &src_v6address, 16); - rules[rule_idx].src_ip_prefix_len = src_prefix_length; - rules[rule_idx].is_ipv6 = 1; - } - else if (unformat (i, "dst %U/%d", - unformat_ip4_address, &dst_v4address, &dst_prefix_length)) - { - vec_validate_acl_rules(rules, rule_idx); - memcpy (rules[rule_idx].dst_ip_addr, &dst_v4address, 4); - rules[rule_idx].dst_ip_prefix_len = dst_prefix_length; - rules[rule_idx].is_ipv6 = 0; - } - else if (unformat (i, "dst %U/%d", - unformat_ip6_address, &dst_v6address, &dst_prefix_length)) - { - vec_validate_acl_rules(rules, rule_idx); - memcpy (rules[rule_idx].dst_ip_addr, &dst_v6address, 16); - rules[rule_idx].dst_ip_prefix_len = dst_prefix_length; - rules[rule_idx].is_ipv6 = 1; - } - else if (unformat (i, "sport %d-%d", &port1, &port2)) - { - vec_validate_acl_rules(rules, rule_idx); - rules[rule_idx].srcport_or_icmptype_first = htons(port1); - rules[rule_idx].srcport_or_icmptype_last = htons(port2); - } - else if (unformat (i, "sport %d", &port1)) - { - vec_validate_acl_rules(rules, rule_idx); - rules[rule_idx].srcport_or_icmptype_first = htons(port1); - rules[rule_idx].srcport_or_icmptype_last = htons(port1); - } - else if (unformat (i, "dport %d-%d", &port1, &port2)) - { - vec_validate_acl_rules(rules, rule_idx); - rules[rule_idx].dstport_or_icmpcode_first = htons(port1); - rules[rule_idx].dstport_or_icmpcode_last = htons(port2); - } - else if (unformat (i, "dport %d", &port1)) - { - vec_validate_acl_rules(rules, rule_idx); - rules[rule_idx].dstport_or_icmpcode_first = htons(port1); - rules[rule_idx].dstport_or_icmpcode_last = htons(port1); - } - else if (unformat (i, "tcpflags %d %d", &tcpflags, &tcpmask)) - { - vec_validate_acl_rules(rules, rule_idx); - rules[rule_idx].tcp_flags_value = tcpflags; - rules[rule_idx].tcp_flags_mask = tcpmask; - } - else if (unformat (i, "proto %d", &proto)) - { - vec_validate_acl_rules(rules, rule_idx); - rules[rule_idx].proto = proto; - } - else if (unformat (i, "tag %s", &tag)) - { - } - else if (unformat (i, ",")) - { - rule_idx++; - vec_validate_acl_rules(rules, rule_idx); - } - else - break; - } - - /* Construct the API message */ - vam->result_ready = 0; - - if(rules) - n_rules = vec_len(rules); - else - n_rules = 0; - - msg_size += n_rules*sizeof(rules[0]); - - mp = vl_msg_api_alloc_as_if_client(msg_size); - memset (mp, 0, msg_size); - mp->_vl_msg_id = ntohs (VL_API_ACL_ADD_REPLACE + sm->msg_id_base); - mp->client_index = vam->my_client_index; - if (n_rules > 0) - clib_memcpy(mp->r, rules, n_rules*sizeof (vl_api_acl_rule_t)); - if (tag) - { - if (vec_len(tag) >= sizeof(mp->tag)) - { - tag[sizeof(mp->tag)-1] = 0; - _vec_len(tag) = sizeof(mp->tag); - } - clib_memcpy(mp->tag, tag, vec_len(tag)); - vec_free(tag); - } - mp->acl_index = ntohl(acl_index); - mp->count = htonl(n_rules); - - /* send it... */ - S; - - /* Wait for a reply... */ - W; -} - -static int api_acl_del (vat_main_t * vam) -{ - acl_test_main_t * sm = &acl_test_main; - unformat_input_t * i = vam->input; - f64 timeout; - vl_api_acl_del_t * mp; - u32 acl_index = ~0; - - if (!unformat (i, "%d", &acl_index)) { - errmsg ("missing acl index\n"); - return -99; - } - - /* Construct the API message */ - M(ACL_DEL, acl_del); - mp->acl_index = ntohl(acl_index); - - /* send it... */ - S; - - /* Wait for a reply... */ - W; -} - -static int api_macip_acl_del (vat_main_t * vam) -{ - acl_test_main_t * sm = &acl_test_main; - unformat_input_t * i = vam->input; - f64 timeout; - vl_api_acl_del_t * mp; - u32 acl_index = ~0; - - if (!unformat (i, "%d", &acl_index)) { - errmsg ("missing acl index\n"); - return -99; - } - - /* Construct the API message */ - M(MACIP_ACL_DEL, acl_del); - mp->acl_index = ntohl(acl_index); - - /* send it... */ - S; - - /* Wait for a reply... */ - W; -} - -static int api_acl_interface_add_del (vat_main_t * vam) -{ - acl_test_main_t * sm = &acl_test_main; - unformat_input_t * i = vam->input; - f64 timeout; - vl_api_acl_interface_add_del_t * mp; - u32 sw_if_index = ~0; - u32 acl_index = ~0; - u8 is_input = 0; - u8 is_add = 0; - -// acl_interface_add_del | sw_if_index acl_index [out] [del] - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "%d", &acl_index)) - ; - else - break; - } - - - /* 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, "add")) - is_add = 1; - else if (unformat (i, "del")) - is_add = 0; - else if (unformat (i, "acl %d", &acl_index)) - ; - else if (unformat (i, "input")) - is_input = 1; - else if (unformat (i, "output")) - is_input = 0; - else - break; - } - - if (sw_if_index == ~0) { - errmsg ("missing interface name / explicit sw_if_index number \n"); - return -99; - } - - if (acl_index == ~0) { - errmsg ("missing ACL index\n"); - return -99; - } - - - - /* Construct the API message */ - M(ACL_INTERFACE_ADD_DEL, acl_interface_add_del); - mp->acl_index = ntohl(acl_index); - mp->sw_if_index = ntohl(sw_if_index); - mp->is_add = is_add; - mp->is_input = is_input; - - /* send it... */ - S; - - /* Wait for a reply... */ - W; -} - -static int api_macip_acl_interface_add_del (vat_main_t * vam) -{ - acl_test_main_t * sm = &acl_test_main; - unformat_input_t * i = vam->input; - f64 timeout; - vl_api_macip_acl_interface_add_del_t * mp; - u32 sw_if_index = ~0; - u32 acl_index = ~0; - u8 is_add = 0; - - /* 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, "add")) - is_add = 1; - else if (unformat (i, "del")) - is_add = 0; - else if (unformat (i, "acl %d", &acl_index)) - ; - else - break; - } - - if (sw_if_index == ~0) { - errmsg ("missing interface name / explicit sw_if_index number \n"); - return -99; - } - - if (acl_index == ~0) { - errmsg ("missing ACL index\n"); - return -99; - } - - - - /* Construct the API message */ - M(MACIP_ACL_INTERFACE_ADD_DEL, macip_acl_interface_add_del); - mp->acl_index = ntohl(acl_index); - mp->sw_if_index = ntohl(sw_if_index); - mp->is_add = is_add; - - /* send it... */ - S; - - /* Wait for a reply... */ - W; -} - -static int api_acl_interface_set_acl_list (vat_main_t * vam) -{ - acl_test_main_t * sm = &acl_test_main; - unformat_input_t * i = vam->input; - f64 timeout; - vl_api_acl_interface_set_acl_list_t * mp; - u32 sw_if_index = ~0; - u32 acl_index = ~0; - u32 *inacls = 0; - u32 *outacls = 0; - u8 is_input = 0; - -// acl_interface_set_acl_list | sw_if_index input [acl-idx list] output [acl-idx list] - - /* 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, "%d", &acl_index)) - { - if(is_input) - vec_add1(inacls, htonl(acl_index)); - else - vec_add1(outacls, htonl(acl_index)); - } - else if (unformat (i, "acl %d", &acl_index)) - ; - else if (unformat (i, "input")) - is_input = 1; - else if (unformat (i, "output")) - is_input = 0; - else - break; - } - - if (sw_if_index == ~0) { - errmsg ("missing interface name / explicit sw_if_index number \n"); - return -99; - } - - /* Construct the API message */ - M2(ACL_INTERFACE_SET_ACL_LIST, acl_interface_set_acl_list, sizeof(u32) * (vec_len(inacls) + vec_len(outacls))); - mp->sw_if_index = ntohl(sw_if_index); - mp->n_input = vec_len(inacls); - mp->count = vec_len(inacls) + vec_len(outacls); - vec_append(inacls, outacls); - if (vec_len(inacls) > 0) - clib_memcpy(mp->acls, inacls, vec_len(inacls)*sizeof(u32)); - - /* send it... */ - S; - - /* Wait for a reply... */ - W; -} - - -static int api_acl_interface_list_dump (vat_main_t * vam) -{ - acl_test_main_t * sm = &acl_test_main; - unformat_input_t * i = vam->input; - f64 timeout; - u32 sw_if_index = ~0; - vl_api_acl_interface_list_dump_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 - break; - } - - /* Construct the API message */ - M(ACL_INTERFACE_LIST_DUMP, acl_interface_list_dump); - mp->sw_if_index = ntohl (sw_if_index); - - /* send it... */ - S; - - /* Wait for a reply... */ - W; -} - -static int api_acl_dump (vat_main_t * vam) -{ - acl_test_main_t * sm = &acl_test_main; - unformat_input_t * i = vam->input; - f64 timeout; - u32 acl_index = ~0; - vl_api_acl_dump_t * mp; - - /* Parse args required to build the message */ - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) { - if (unformat (i, "%d", &acl_index)) - ; - else - break; - } - - /* Construct the API message */ - M(ACL_DUMP, acl_dump); - mp->acl_index = ntohl (acl_index); - - /* send it... */ - S; - - /* Wait for a reply... */ - W; -} - -static int api_macip_acl_dump (vat_main_t * vam) -{ - acl_test_main_t * sm = &acl_test_main; - unformat_input_t * i = vam->input; - f64 timeout; - u32 acl_index = ~0; - vl_api_acl_dump_t * mp; - - /* Parse args required to build the message */ - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) { - if (unformat (i, "%d", &acl_index)) - ; - else - break; - } - - /* Construct the API message */ - M(MACIP_ACL_DUMP, macip_acl_dump); - mp->acl_index = ntohl (acl_index); - - /* send it... */ - S; - - /* Wait for a reply... */ - W; -} - -#define vec_validate_macip_acl_rules(v, idx) \ - do { \ - if (vec_len(v) < idx+1) { \ - vec_validate(v, idx); \ - v[idx].is_permit = 0x1; \ - } \ - } while (0) - - -static int api_macip_acl_add (vat_main_t * vam) -{ - acl_test_main_t * sm = &acl_test_main; - unformat_input_t * i = vam->input; - f64 timeout; - vl_api_macip_acl_add_t * mp; - u32 msg_size = sizeof (*mp); /* without the rules */ - - vl_api_macip_acl_rule_t *rules = 0; - int rule_idx = 0; - int n_rules = 0; - u32 src_prefix_length = 0; - u32 action = 0; - ip4_address_t src_v4address; - ip6_address_t src_v6address; - u8 src_mac[6]; - u8 *tag = 0; - u8 mac_mask_all_1[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "ipv6")) - { - vec_validate_macip_acl_rules(rules, rule_idx); - rules[rule_idx].is_ipv6 = 1; - } - else if (unformat (i, "ipv4")) - { - vec_validate_macip_acl_rules(rules, rule_idx); - rules[rule_idx].is_ipv6 = 1; - } - else if (unformat (i, "permit")) - { - vec_validate_macip_acl_rules(rules, rule_idx); - rules[rule_idx].is_permit = 1; - } - else if (unformat (i, "deny")) - { - vec_validate_macip_acl_rules(rules, rule_idx); - rules[rule_idx].is_permit = 0; - } - else if (unformat (i, "action %d", &action)) - { - vec_validate_macip_acl_rules(rules, rule_idx); - rules[rule_idx].is_permit = action; - } - else if (unformat (i, "ip %U/%d", - unformat_ip4_address, &src_v4address, &src_prefix_length)) - { - vec_validate_macip_acl_rules(rules, rule_idx); - memcpy (rules[rule_idx].src_ip_addr, &src_v4address, 4); - rules[rule_idx].src_ip_prefix_len = src_prefix_length; - rules[rule_idx].is_ipv6 = 0; - } - else if (unformat (i, "ip %U/%d", - unformat_ip6_address, &src_v6address, &src_prefix_length)) - { - vec_validate_macip_acl_rules(rules, rule_idx); - memcpy (rules[rule_idx].src_ip_addr, &src_v6address, 16); - rules[rule_idx].src_ip_prefix_len = src_prefix_length; - rules[rule_idx].is_ipv6 = 1; - } - else if (unformat (i, "mac %U", - my_unformat_mac_address, &src_mac)) - { - vec_validate_macip_acl_rules(rules, rule_idx); - memcpy (rules[rule_idx].src_mac, &src_mac, 6); - memcpy (rules[rule_idx].src_mac_mask, &mac_mask_all_1, 6); - } - else if (unformat (i, "mask %U", - my_unformat_mac_address, &src_mac)) - { - vec_validate_macip_acl_rules(rules, rule_idx); - memcpy (rules[rule_idx].src_mac_mask, &src_mac, 6); - } - else if (unformat (i, "tag %s", &tag)) - { - } - else if (unformat (i, ",")) - { - rule_idx++; - vec_validate_macip_acl_rules(rules, rule_idx); - } - else - break; - } - - /* Construct the API message */ - vam->result_ready = 0; - - if(rules) - n_rules = vec_len(rules); - else - n_rules = 0; - - msg_size += n_rules*sizeof(rules[0]); - - mp = vl_msg_api_alloc_as_if_client(msg_size); - memset (mp, 0, msg_size); - mp->_vl_msg_id = ntohs (VL_API_MACIP_ACL_ADD + sm->msg_id_base); - mp->client_index = vam->my_client_index; - if (n_rules > 0) - clib_memcpy(mp->r, rules, n_rules*sizeof (mp->r[0])); - if (tag) - { - if (vec_len(tag) >= sizeof(mp->tag)) - { - tag[sizeof(mp->tag)-1] = 0; - _vec_len(tag) = sizeof(mp->tag); - } - clib_memcpy(mp->tag, tag, vec_len(tag)); - vec_free(tag); - } - - mp->count = htonl(n_rules); - - /* 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 \ -_(acl_plugin_get_version, "") \ -_(acl_add_replace, " [ [src IP/plen] [dst IP/plen] [sport X-Y] [dport X-Y] [proto P] [tcpflags FL MASK], ... , ...") \ -_(acl_del, "") \ -_(acl_dump, "[]") \ -_(acl_interface_add_del, " | sw_if_index [add|del] [input|output] acl ") \ -_(acl_interface_set_acl_list, " | sw_if_index input [acl-idx list] output [acl-idx list]") \ -_(acl_interface_list_dump, "[ | sw_if_index ]") \ -_(macip_acl_add, "...") \ -_(macip_acl_del, "")\ -_(macip_acl_dump, "[]") \ -_(macip_acl_interface_add_del, " | sw_if_index [add|del] acl ") \ -_(macip_acl_interface_get, "") - - - -void vat_api_hookup (vat_main_t *vam) -{ - acl_test_main_t * sm = &acl_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) -{ - acl_test_main_t * sm = &acl_test_main; - u8 * name; - - sm->vat_main = vam; - - name = format (0, "acl_%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/plugins/acl-plugin/acl/jvpp/io/fd/vpp/jvpp/acl/test/AclExpectedDumpData.java b/plugins/acl-plugin/acl/jvpp/io/fd/vpp/jvpp/acl/test/AclExpectedDumpData.java deleted file mode 100644 index 979edbc4..00000000 --- a/plugins/acl-plugin/acl/jvpp/io/fd/vpp/jvpp/acl/test/AclExpectedDumpData.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.acl.test; - - -import static io.fd.vpp.jvpp.acl.test.AclTestData.FIRST_RULE_ADDRESS_2_AS_ARRAY; -import static io.fd.vpp.jvpp.acl.test.AclTestData.FIRST_RULE_ADDRESS_AS_ARRAY; -import static io.fd.vpp.jvpp.acl.test.AclTestData.FIRST_RULE_DST_ICMP_TYPE_END; -import static io.fd.vpp.jvpp.acl.test.AclTestData.FIRST_RULE_DST_ICMP_TYPE_START; -import static io.fd.vpp.jvpp.acl.test.AclTestData.FIRST_RULE_MAC; -import static io.fd.vpp.jvpp.acl.test.AclTestData.FIRST_RULE_MAC_MASK; -import static io.fd.vpp.jvpp.acl.test.AclTestData.FIRST_RULE_PREFIX; -import static io.fd.vpp.jvpp.acl.test.AclTestData.FIRST_RULE_PREFIX_2; -import static io.fd.vpp.jvpp.acl.test.AclTestData.FIRST_RULE_SRC_ICMP_TYPE_END; -import static io.fd.vpp.jvpp.acl.test.AclTestData.FIRST_RULE_SRC_ICMP_TYPE_START; -import static io.fd.vpp.jvpp.acl.test.AclTestData.ICMP_PROTOCOL; -import static io.fd.vpp.jvpp.acl.test.AclTestData.SECOND_RULE_ADDRESS_2_AS_ARRAY; -import static io.fd.vpp.jvpp.acl.test.AclTestData.SECOND_RULE_ADDRESS_AS_ARRAY; -import static io.fd.vpp.jvpp.acl.test.AclTestData.SECOND_RULE_DST_PORT_RANGE_END; -import static io.fd.vpp.jvpp.acl.test.AclTestData.SECOND_RULE_DST_PORT_RANGE_START; -import static io.fd.vpp.jvpp.acl.test.AclTestData.SECOND_RULE_MAC; -import static io.fd.vpp.jvpp.acl.test.AclTestData.SECOND_RULE_MAC_MASK; -import static io.fd.vpp.jvpp.acl.test.AclTestData.SECOND_RULE_PREFIX; -import static io.fd.vpp.jvpp.acl.test.AclTestData.SECOND_RULE_PREFIX_2; -import static io.fd.vpp.jvpp.acl.test.AclTestData.SECOND_RULE_SRC_PORT_RANGE_END; -import static io.fd.vpp.jvpp.acl.test.AclTestData.SECOND_RULE_SRC_PORT_RANGE_START; -import static io.fd.vpp.jvpp.acl.test.AclTestData.UDP_PROTOCOL; - -import io.fd.vpp.jvpp.acl.dto.AclDetails; -import io.fd.vpp.jvpp.acl.dto.AclInterfaceListDetails; -import io.fd.vpp.jvpp.acl.dto.MacipAclDetails; -import io.fd.vpp.jvpp.acl.types.AclRule; -import io.fd.vpp.jvpp.acl.types.MacipAclRule; -import java.util.Arrays; - -class AclExpectedDumpData { - - static void verifyMacIpDump(final MacipAclDetails macipAclDetails) { - // asserting data create by previous call - assertEquals(0, macipAclDetails.aclIndex); - assertEquals(2, macipAclDetails.count); - - final MacipAclRule currentIpv4Rule = macipAclDetails.r[0]; - final MacipAclRule currentIpv6Rule = macipAclDetails.r[1]; - - // Comparing one property at the time to better pointer if something is wrong - //Ipv4 rule - assertEquals(0, currentIpv4Rule.isIpv6); - assertEquals(1, currentIpv4Rule.isPermit); - - // cutting expected ipv4 to 4 bytes,vpp sends it as 16 always - assertArrays(FIRST_RULE_ADDRESS_AS_ARRAY, Arrays.copyOfRange(currentIpv4Rule.srcIpAddr, 0, 4)); - assertEquals(FIRST_RULE_PREFIX, currentIpv4Rule.srcIpPrefixLen); - assertArrays(FIRST_RULE_MAC, currentIpv4Rule.srcMac); - assertArrays(FIRST_RULE_MAC_MASK, currentIpv4Rule.srcMacMask); - - //Ipv6 rule - assertEquals(1, currentIpv6Rule.isIpv6); - assertEquals(0, currentIpv6Rule.isPermit); - assertArrays(SECOND_RULE_ADDRESS_AS_ARRAY, currentIpv6Rule.srcIpAddr); - assertEquals(SECOND_RULE_PREFIX, currentIpv6Rule.srcIpPrefixLen); - assertArrays(SECOND_RULE_MAC, currentIpv6Rule.srcMac); - assertArrays(SECOND_RULE_MAC_MASK, currentIpv6Rule.srcMacMask); - } - - static void verifyAclDump(final AclDetails aclDetails) { - assertEquals(0, aclDetails.aclIndex); - assertEquals(2, aclDetails.count); - - final AclRule currentIpv4Rule = aclDetails.r[0]; - final AclRule currentIpv6Rule = aclDetails.r[1]; - - // Comparing one property at the time to better pointer if something is wrong - //Ipv4 rule - assertEquals(0, currentIpv4Rule.isIpv6); - assertEquals(1, currentIpv4Rule.isPermit); - - // cutting expected ipv4 to 4 bytes,vpp sends it as 16 always - assertArrays(FIRST_RULE_ADDRESS_AS_ARRAY, Arrays.copyOfRange(currentIpv4Rule.srcIpAddr, 0, 4)); - assertEquals(FIRST_RULE_PREFIX, currentIpv4Rule.srcIpPrefixLen); - assertArrays(FIRST_RULE_ADDRESS_2_AS_ARRAY, Arrays.copyOfRange(currentIpv4Rule.dstIpAddr, 0, 4)); - assertEquals(FIRST_RULE_PREFIX_2, currentIpv4Rule.dstIpPrefixLen); - - assertEquals(ICMP_PROTOCOL, currentIpv4Rule.proto); - assertEquals(FIRST_RULE_SRC_ICMP_TYPE_START, currentIpv4Rule.srcportOrIcmptypeFirst); - assertEquals(FIRST_RULE_SRC_ICMP_TYPE_END, currentIpv4Rule.srcportOrIcmptypeLast); - assertEquals(FIRST_RULE_DST_ICMP_TYPE_START, currentIpv4Rule.dstportOrIcmpcodeFirst); - assertEquals(FIRST_RULE_DST_ICMP_TYPE_END, currentIpv4Rule.dstportOrIcmpcodeLast); - - assertArrays(SECOND_RULE_ADDRESS_AS_ARRAY, currentIpv6Rule.srcIpAddr); - assertEquals(SECOND_RULE_PREFIX, currentIpv6Rule.srcIpPrefixLen); - assertArrays(SECOND_RULE_ADDRESS_2_AS_ARRAY, currentIpv6Rule.dstIpAddr); - assertEquals(SECOND_RULE_PREFIX_2, currentIpv6Rule.dstIpPrefixLen); - - assertEquals(UDP_PROTOCOL, currentIpv6Rule.proto); - assertEquals(SECOND_RULE_SRC_PORT_RANGE_START, currentIpv6Rule.srcportOrIcmptypeFirst); - assertEquals(SECOND_RULE_SRC_PORT_RANGE_END, currentIpv6Rule.srcportOrIcmptypeLast); - assertEquals(SECOND_RULE_DST_PORT_RANGE_START, currentIpv6Rule.dstportOrIcmpcodeFirst); - assertEquals(SECOND_RULE_DST_PORT_RANGE_END, currentIpv6Rule.dstportOrIcmpcodeLast); - } - - static void verifyAclInterfaceList(final AclInterfaceListDetails aclInterfaceListDetails) { - assertEquals(1, aclInterfaceListDetails.count); - assertEquals(1, aclInterfaceListDetails.acls[0]); - assertEquals(0, aclInterfaceListDetails.nInput); - assertEquals(0, aclInterfaceListDetails.swIfIndex); - } - - private static void assertArrays(final byte[] expected, final byte[] actual) { - if (!Arrays.equals(expected, actual)) { - throw new IllegalArgumentException( - String.format("Expected[%s]/Actual[%s]", Arrays.toString(expected), Arrays.toString(actual))); - } - } - - private static void assertEquals(final int expected, final int actual) { - if (expected != actual) { - throw new IllegalArgumentException(String.format("Expected[%s]/Actual[%s]", expected, actual)); - } - } -} diff --git a/plugins/acl-plugin/acl/jvpp/io/fd/vpp/jvpp/acl/test/AclTestData.java b/plugins/acl-plugin/acl/jvpp/io/fd/vpp/jvpp/acl/test/AclTestData.java deleted file mode 100644 index 5d228eea..00000000 --- a/plugins/acl-plugin/acl/jvpp/io/fd/vpp/jvpp/acl/test/AclTestData.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.acl.test; - - -import io.fd.vpp.jvpp.acl.types.AclRule; -import io.fd.vpp.jvpp.acl.types.MacipAclRule; - -class AclTestData { - - static final byte[] FIRST_RULE_ADDRESS_AS_ARRAY = {-64, -88, 2, 1}; - static final byte[] FIRST_RULE_ADDRESS_2_AS_ARRAY = {-64, -88, 2, 3}; - static final byte[] SECOND_RULE_ADDRESS_AS_ARRAY = - {32, 1, 13, -72, 10, 11, 18, -16, 0, 0, 0, 0, 0, 0, 0, 1}; - static final byte[] SECOND_RULE_ADDRESS_2_AS_ARRAY = - {32, 1, 13, -72, 10, 11, 18, -16, 0, 0, 0, 0, 0, 0, 0, 1}; - static final byte[] FIRST_RULE_MAC = {11, 11, 11, 11, 11, 11}; - static final byte[] FIRST_RULE_MAC_MASK = {0, 0, 0, 0, 0, 0}; - static final byte[] SECOND_RULE_MAC = {11, 12, 11, 11, 12, 11}; - static final byte[] SECOND_RULE_MAC_MASK = {(byte) 170, 0, 0, 0, 0, 0}; - static final int FIRST_RULE_PREFIX = 32; - static final int FIRST_RULE_PREFIX_2 = 24; - static final int SECOND_RULE_PREFIX = 64; - static final int SECOND_RULE_PREFIX_2 = 62; - static final int FIRST_RULE_DST_ICMP_TYPE_START = 0; - static final int FIRST_RULE_DST_ICMP_TYPE_END = 8; - static final int FIRST_RULE_SRC_ICMP_TYPE_START = 1; - static final int FIRST_RULE_SRC_ICMP_TYPE_END = 7; - static final int ICMP_PROTOCOL = 1; - static final int SECOND_RULE_DST_PORT_RANGE_START = 2000; - static final int SECOND_RULE_DST_PORT_RANGE_END = 6000; - static final int SECOND_RULE_SRC_PORT_RANGE_START = 400; - static final int SECOND_RULE_SRC_PORT_RANGE_END = 2047; - static final int UDP_PROTOCOL = 17; - - - static MacipAclRule[] createMacipRules() { - MacipAclRule ruleOne = new MacipAclRule(); - ruleOne.isIpv6 = 0; - ruleOne.isPermit = 1; - ruleOne.srcIpAddr = FIRST_RULE_ADDRESS_AS_ARRAY; - ruleOne.srcIpPrefixLen = FIRST_RULE_PREFIX; - ruleOne.srcMac = FIRST_RULE_MAC; - ruleOne.srcMacMask = FIRST_RULE_MAC_MASK;// no mask - - MacipAclRule ruleTwo = new MacipAclRule(); - ruleTwo.isIpv6 = 1; - ruleTwo.isPermit = 0; - ruleTwo.srcIpAddr = SECOND_RULE_ADDRESS_AS_ARRAY; - ruleTwo.srcIpPrefixLen = SECOND_RULE_PREFIX; - ruleTwo.srcMac = SECOND_RULE_MAC; - ruleTwo.srcMacMask = SECOND_RULE_MAC_MASK; - - return new MacipAclRule[]{ruleOne, ruleTwo}; - } - - static AclRule[] createAclRules() { - AclRule ruleOne = new AclRule(); - - ruleOne.isIpv6 = 0; - ruleOne.isPermit = 1; - ruleOne.srcIpAddr = FIRST_RULE_ADDRESS_AS_ARRAY; - ruleOne.srcIpPrefixLen = FIRST_RULE_PREFIX; - ruleOne.dstIpAddr = FIRST_RULE_ADDRESS_2_AS_ARRAY; - ruleOne.dstIpPrefixLen = FIRST_RULE_PREFIX_2; - ruleOne.dstportOrIcmpcodeFirst = FIRST_RULE_DST_ICMP_TYPE_START; - ruleOne.dstportOrIcmpcodeLast = FIRST_RULE_DST_ICMP_TYPE_END; - ruleOne.srcportOrIcmptypeFirst = FIRST_RULE_SRC_ICMP_TYPE_START; - ruleOne.srcportOrIcmptypeLast = FIRST_RULE_SRC_ICMP_TYPE_END; - ruleOne.proto = ICMP_PROTOCOL; //ICMP - - AclRule ruleTwo = new AclRule(); - ruleTwo.isIpv6 = 1; - ruleTwo.isPermit = 0; - ruleTwo.srcIpAddr = SECOND_RULE_ADDRESS_AS_ARRAY; - ruleTwo.srcIpPrefixLen = SECOND_RULE_PREFIX; - ruleTwo.dstIpAddr = SECOND_RULE_ADDRESS_2_AS_ARRAY; - ruleTwo.dstIpPrefixLen = SECOND_RULE_PREFIX_2; - ruleTwo.dstportOrIcmpcodeFirst = SECOND_RULE_DST_PORT_RANGE_START; - ruleTwo.dstportOrIcmpcodeLast = SECOND_RULE_DST_PORT_RANGE_END; - ruleTwo.srcportOrIcmptypeFirst = SECOND_RULE_SRC_PORT_RANGE_START; - ruleTwo.srcportOrIcmptypeLast = SECOND_RULE_SRC_PORT_RANGE_END; - ruleTwo.proto = UDP_PROTOCOL; //UDP - - return new AclRule[]{ruleOne, ruleTwo}; - } -} diff --git a/plugins/acl-plugin/acl/jvpp/io/fd/vpp/jvpp/acl/test/AclTestRequests.java b/plugins/acl-plugin/acl/jvpp/io/fd/vpp/jvpp/acl/test/AclTestRequests.java deleted file mode 100644 index b580ee8c..00000000 --- a/plugins/acl-plugin/acl/jvpp/io/fd/vpp/jvpp/acl/test/AclTestRequests.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.acl.test; - -import static io.fd.vpp.jvpp.acl.test.AclTestData.createAclRules; -import static io.fd.vpp.jvpp.acl.test.AclTestData.createMacipRules; - -import io.fd.vpp.jvpp.VppInvocationException; -import io.fd.vpp.jvpp.acl.dto.AclAddReplace; -import io.fd.vpp.jvpp.acl.dto.AclAddReplaceReply; -import io.fd.vpp.jvpp.acl.dto.AclDel; -import io.fd.vpp.jvpp.acl.dto.AclDelReply; -import io.fd.vpp.jvpp.acl.dto.AclDetailsReplyDump; -import io.fd.vpp.jvpp.acl.dto.AclDump; -import io.fd.vpp.jvpp.acl.dto.AclInterfaceListDetailsReplyDump; -import io.fd.vpp.jvpp.acl.dto.AclInterfaceListDump; -import io.fd.vpp.jvpp.acl.dto.AclInterfaceSetAclList; -import io.fd.vpp.jvpp.acl.dto.AclInterfaceSetAclListReply; -import io.fd.vpp.jvpp.acl.dto.MacipAclAdd; -import io.fd.vpp.jvpp.acl.dto.MacipAclAddReply; -import io.fd.vpp.jvpp.acl.dto.MacipAclDel; -import io.fd.vpp.jvpp.acl.dto.MacipAclDelReply; -import io.fd.vpp.jvpp.acl.dto.MacipAclDetailsReplyDump; -import io.fd.vpp.jvpp.acl.dto.MacipAclDump; -import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; -import java.util.concurrent.ExecutionException; - -class AclTestRequests { - - static MacipAclDetailsReplyDump sendMacIpDumpRequest(final FutureJVppAclFacade jvpp) - throws ExecutionException, InterruptedException { - System.out.println("Sending MacipAclDump request..."); - MacipAclDetailsReplyDump dump = jvpp.macipAclDump(new MacipAclDump()).toCompletableFuture().get(); - System.out.println("MacipAclDump returned"); - return dump; - } - - static void sendMacIpAddRequest(final FutureJVppAclFacade jvpp) throws InterruptedException, ExecutionException { - final MacipAclAdd request = createMacIpAddRequest(); - System.out.printf("Sending MacipAclAdd request %s%n", request.toString()); - final MacipAclAddReply reply = jvpp.macipAclAdd(createMacIpAddRequest()).toCompletableFuture().get(); - System.out.printf("MacipAclAdd send result = %s%n", reply); - } - - static void sendMacIpDelRequest(final FutureJVppAclFacade jvpp) throws InterruptedException, ExecutionException { - final MacipAclDel request = new MacipAclDel(); - request.aclIndex = 0; - System.out.printf("Sending MacipAclDel request %s%n", request.toString()); - final MacipAclDelReply reply = jvpp.macipAclDel(request).toCompletableFuture().get(); - System.out.printf("MacipAclDel send result = %s%n", reply); - } - - static void sendAclAddRequest(final FutureJVppAclFacade jvpp) throws InterruptedException, ExecutionException { - final AclAddReplace request = createAclAddRequest(); - System.out.printf("Sending AclAddReplace request %s%n", request.toString()); - final AclAddReplaceReply reply = jvpp.aclAddReplace(request).toCompletableFuture().get(); - System.out.printf("AclAddReplace send result = %s%n", reply); - } - - static AclDetailsReplyDump sendAclDumpRequest(final FutureJVppAclFacade jvpp) - throws InterruptedException, VppInvocationException, ExecutionException { - System.out.println("Sending AclDump request..."); - final AclDetailsReplyDump dump = jvpp.aclDump(new AclDump()).toCompletableFuture().get(); - System.out.printf("AclDump send result = %s%n", dump); - return dump; - } - - static void sendAclDelRequest(final FutureJVppAclFacade jvpp) throws InterruptedException, ExecutionException { - final AclDel request = new AclDel(); - request.aclIndex = 0; - System.out.printf("Sending AclDel request %s%n", request.toString()); - final AclDelReply reply = jvpp.aclDel(request).toCompletableFuture().get(); - System.out.printf("AclDel send result = %s%n", reply); - } - - static AclInterfaceListDetailsReplyDump sendAclInterfaceListDumpRequest(final FutureJVppAclFacade jvpp) - throws InterruptedException, ExecutionException { - final AclInterfaceListDump request = new AclInterfaceListDump(); - request.swIfIndex = 0; - System.out.printf("Sending AclInterfaceListDump request %s%n", request.toString()); - final AclInterfaceListDetailsReplyDump dump = jvpp.aclInterfaceListDump(request).toCompletableFuture().get(); - System.out.printf("AclInterfaceListDump send result = %s%n", dump); - return dump; - } - - static void sendAclInterfaceSetAclList(final FutureJVppAclFacade jvpp) - throws InterruptedException, ExecutionException { - final AclInterfaceSetAclList request = new AclInterfaceSetAclList(); - request.count = 1; - request.acls = new int[]{1}; - request.swIfIndex = 0; - request.nInput = 0; - System.out.printf("Sending AclInterfaceSetAclList request %s%n", request.toString()); - final AclInterfaceSetAclListReply reply = jvpp.aclInterfaceSetAclList(request).toCompletableFuture().get(); - System.out.printf("AclInterfaceSetAclList send result = %s%n", reply); - } - - static void sendAclInterfaceDeleteList(final FutureJVppAclFacade jvpp) - throws InterruptedException, ExecutionException { - // uses same api but sets list to empty - final AclInterfaceSetAclList request = new AclInterfaceSetAclList(); - request.count = 0; - request.acls = new int[]{}; - request.swIfIndex = 0; - request.nInput = 0; - System.out.printf("Sending AclInterfaceSetAclList(Delete) request %s%n", request.toString()); - final AclInterfaceSetAclListReply reply = jvpp.aclInterfaceSetAclList(request).toCompletableFuture().get(); - System.out.printf("AclInterfaceSetAclList(Delete) send result = %s%n", reply); - } - - private static MacipAclAdd createMacIpAddRequest() { - MacipAclAdd request = new MacipAclAdd(); - - request.count = 2; - request.r = createMacipRules(); - return request; - } - - private static AclAddReplace createAclAddRequest() { - AclAddReplace request = new AclAddReplace(); - - request.aclIndex = -1;// to define new one - request.count = 2; - request.r = createAclRules(); - return request; - } -} diff --git a/plugins/acl-plugin/acl/jvpp/io/fd/vpp/jvpp/acl/test/FutureApiTest.java b/plugins/acl-plugin/acl/jvpp/io/fd/vpp/jvpp/acl/test/FutureApiTest.java deleted file mode 100644 index 94490193..00000000 --- a/plugins/acl-plugin/acl/jvpp/io/fd/vpp/jvpp/acl/test/FutureApiTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.acl.test; - -import static io.fd.vpp.jvpp.acl.test.AclExpectedDumpData.verifyAclDump; -import static io.fd.vpp.jvpp.acl.test.AclExpectedDumpData.verifyAclInterfaceList; -import static io.fd.vpp.jvpp.acl.test.AclExpectedDumpData.verifyMacIpDump; -import static io.fd.vpp.jvpp.acl.test.AclTestRequests.sendAclAddRequest; -import static io.fd.vpp.jvpp.acl.test.AclTestRequests.sendAclDelRequest; -import static io.fd.vpp.jvpp.acl.test.AclTestRequests.sendAclDumpRequest; -import static io.fd.vpp.jvpp.acl.test.AclTestRequests.sendAclInterfaceDeleteList; -import static io.fd.vpp.jvpp.acl.test.AclTestRequests.sendAclInterfaceListDumpRequest; -import static io.fd.vpp.jvpp.acl.test.AclTestRequests.sendAclInterfaceSetAclList; -import static io.fd.vpp.jvpp.acl.test.AclTestRequests.sendMacIpAddRequest; -import static io.fd.vpp.jvpp.acl.test.AclTestRequests.sendMacIpDelRequest; -import static io.fd.vpp.jvpp.acl.test.AclTestRequests.sendMacIpDumpRequest; - -import io.fd.vpp.jvpp.JVppRegistry; -import io.fd.vpp.jvpp.JVppRegistryImpl; -import io.fd.vpp.jvpp.acl.JVppAclImpl; -import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; - -public class FutureApiTest { - - public static void main(String[] args) throws Exception { - testCallbackApi(); - } - - private static void testCallbackApi() throws Exception { - System.out.println("Testing Java callback API for acl plugin"); - try (final JVppRegistry registry = new JVppRegistryImpl("macipAclAddTest"); - final FutureJVppAclFacade jvpp = new FutureJVppAclFacade(registry, new JVppAclImpl())) { - - // adds,dump and verifies Mac-Ip acl - sendMacIpAddRequest(jvpp); - verifyMacIpDump(sendMacIpDumpRequest(jvpp).macipAclDetails.get(0)); - - // adds,dumps and verifies Acl acl - sendAclAddRequest(jvpp); - verifyAclDump(sendAclDumpRequest(jvpp).aclDetails.get(0)); - - // adds,dumps and verifies Interface for acl - sendAclInterfaceSetAclList(jvpp); - verifyAclInterfaceList(sendAclInterfaceListDumpRequest(jvpp).aclInterfaceListDetails.get(0)); - - // deletes all created data - sendAclInterfaceDeleteList(jvpp); - sendAclDelRequest(jvpp); - sendMacIpDelRequest(jvpp); - - System.out.println("Disconnecting..."); - } - } -} diff --git a/plugins/acl-plugin/acl/jvpp/io/fd/vpp/jvpp/acl/test/Readme.txt b/plugins/acl-plugin/acl/jvpp/io/fd/vpp/jvpp/acl/test/Readme.txt deleted file mode 100644 index f68e7aba..00000000 --- a/plugins/acl-plugin/acl/jvpp/io/fd/vpp/jvpp/acl/test/Readme.txt +++ /dev/null @@ -1 +0,0 @@ -sudo java -cp build-vpp-native/vpp-api/java/jvpp-registry-17.01.jar:build-vpp-native/plugins/acl-plugin/jvpp-acl-1.0.jar io.fd.vpp.jvpp.acl.test.FutureApiTest diff --git a/plugins/acl-plugin/acl/jvpp_acl.c b/plugins/acl-plugin/acl/jvpp_acl.c deleted file mode 100644 index 0af53bc9..00000000 --- a/plugins/acl-plugin/acl/jvpp_acl.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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. - */ - -#include - -#include -#define vl_typedefs /* define message structures */ -#include -#undef vl_typedefs - -#define vl_endianfun -#include -#undef vl_endianfun - -#define vl_print(handle, ...) -#define vl_printfun -#include -#undef vl_printfun - -/* Get the API version number */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#undef vl_api_version - -#include -#include -#include - -#if VPPJNI_DEBUG == 1 - #define DEBUG_LOG(...) clib_warning(__VA_ARGS__) -#else - #define DEBUG_LOG(...) -#endif - -#include - -#include "acl/jvpp/io_fd_vpp_jvpp_acl_JVppAclImpl.h" -#include "jvpp_acl.h" -#include "acl/jvpp/jvpp_acl_gen.h" - -/* - * Class: io_fd_vpp_jvpp_acl_JVppaclImpl - * Method: init0 - * Signature: (JI)V - */ -JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_acl_JVppAclImpl_init0 - (JNIEnv *env, jclass clazz, jobject callback, jlong queue_address, jint my_client_index) { - acl_main_t * plugin_main = &acl_main; - u8 * name; - clib_warning ("Java_io_fd_vpp_jvpp_acl_JVppAclImpl_init0"); - - plugin_main->my_client_index = my_client_index; - plugin_main->vl_input_queue = (unix_shared_memory_queue_t *)queue_address; - - name = format (0, "acl_%08x%c", api_version, 0); - plugin_main->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name); - - if (plugin_main->msg_id_base == (u16) ~0) { - jclass exClass = (*env)->FindClass(env, "java/lang/IllegalStateException"); - (*env)->ThrowNew(env, exClass, "acl plugin is not loaded in VPP"); - } else { - plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback); - plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback)); - - #define _(N,n) \ - vl_msg_api_set_handlers(VL_API_##N + plugin_main->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_api_reply_handler; - #undef _ - } -} - -JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_acl_JVppAclImpl_close0 -(JNIEnv *env, jclass clazz) { - acl_main_t * plugin_main = &acl_main; - - // cleanup: - (*env)->DeleteGlobalRef(env, plugin_main->callbackClass); - (*env)->DeleteGlobalRef(env, plugin_main->callbackObject); - - plugin_main->callbackClass = NULL; - plugin_main->callbackObject = NULL; -} - -/* Attach thread to JVM and cache class references when initiating JVPP ACL */ -jint JNI_OnLoad(JavaVM *vm, void *reserved) { - JNIEnv* env; - - if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { - return JNI_EVERSION; - } - - if (cache_class_references(env) != 0) { - clib_warning ("Failed to cache class references\n"); - return JNI_ERR; - } - - return JNI_VERSION_1_8; -} - -/* Clean up cached references when disposing JVPP ACL */ -void JNI_OnUnload(JavaVM *vm, void *reserved) { - JNIEnv* env; - if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { - return; - } - delete_class_references(env); -} diff --git a/plugins/acl-plugin/acl/jvpp_acl.h b/plugins/acl-plugin/acl/jvpp_acl.h deleted file mode 100644 index 2b73d672..00000000 --- a/plugins/acl-plugin/acl/jvpp_acl.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - */ -#ifndef __included_jvpp_acl_h__ -#define __included_jvpp_acl_h__ - -#include -#include -#include -#include -#include -#include - -/* Global state for JVPP-acl */ -typedef struct { - /* Base message index for the acl plugin */ - u16 msg_id_base; - - /* Pointer to shared memory queue */ - unix_shared_memory_queue_t * vl_input_queue; - - /* VPP api client index */ - u32 my_client_index; - - /* Callback object and class references enabling asynchronous Java calls */ - jobject callbackObject; - jclass callbackClass; - -} acl_main_t; - -acl_main_t acl_main __attribute__((aligned (64))); - - -#endif /* __included_jvpp_acl_h__ */ diff --git a/plugins/acl-plugin/acl/l2sess.c b/plugins/acl-plugin/acl/l2sess.c deleted file mode 100644 index cc9bde44..00000000 --- a/plugins/acl-plugin/acl/l2sess.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * 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. - */ -/* - *------------------------------------------------------------------ - * l2sess.c - simple MAC-swap API / debug CLI handling - *------------------------------------------------------------------ - */ - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -void -l2sess_vlib_plugin_register (vlib_main_t * vm, void* hh, - int from_early_init) -{ - l2sess_main_t *sm = &l2sess_main; - vnet_plugin_handoff_t * h = hh; - memset (sm, 0, sizeof (*sm)); - - sm->vlib_main = vm; - sm->vnet_main = h->vnet_main; - sm->ethernet_main = h->ethernet_main; -} - -void -l2sess_init_next_features_input (vlib_main_t * vm, l2sess_main_t * sm) -{ -#define _(node_name, node_var, is_out, is_ip6, is_track) \ - if (!is_out) feat_bitmap_init_next_nodes(vm, node_var.index, L2INPUT_N_FEAT, l2input_get_feat_names (), sm->node_var ## _input_next_node_index); - foreach_l2sess_node -#undef _ -} - -void -l2sess_add_our_next_nodes (vlib_main_t * vm, l2sess_main_t * sm, - u8 * prev_node_name, int add_output_nodes) -{ - vlib_node_t *n; - n = vlib_get_node_by_name (vm, prev_node_name); -#define _(node_name, node_var, is_out, is_ip6, is_track) \ - if (is_out == add_output_nodes) { \ - u32 idx = vlib_node_add_next_with_slot(vm, n->index, node_var.index, ~0); \ - if (is_track) { \ - sm->next_slot_track_node_by_is_ip6_is_out[is_ip6][is_out] = idx; \ - } \ - } - foreach_l2sess_node -#undef _ -} - -void -l2sess_setup_nodes (void) -{ - vlib_main_t *vm = vlib_get_main (); - l2sess_main_t *sm = &l2sess_main; - - l2sess_init_next_features_input (vm, sm); - - l2sess_add_our_next_nodes (vm, sm, (u8 *) "l2-input-classify", 0); - l2sess_add_our_next_nodes (vm, sm, (u8 *) "l2-output-classify", 1); - -} - -static char * -get_l4_proto_str (int is_ip6, uint8_t l4_proto) -{ - switch (l4_proto) - { - case 6: - return "tcp"; - case 17: - return "udp"; - case 1: - return "icmp"; - case 58: - return "icmp6"; - default: - return ""; - } -} - -static clib_error_t * -l2sess_show_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - l2sess_main_t *sm = &l2sess_main; - clib_time_t *ct = &vm->clib_time; - l2s_session_t *s; - u64 now = clib_cpu_time_now (); - - vlib_cli_output (vm, "Timing wheel info: \n%U", format_timing_wheel, - &sm->timing_wheel, 255); - - pool_foreach (s, sm->sessions, ( - { - f64 ctime = - (now - - s->create_time) * ct->seconds_per_clock; - f64 atime0 = - (now - - s->side[0].active_time) * - ct->seconds_per_clock; - f64 atime1 = - (now - - s->side[1].active_time) * - ct->seconds_per_clock; -/* - f64 ctime = (s->create_time - vm->cpu_time_main_loop_start) * ct->seconds_per_clock; - f64 atime0 = (s->side[0].active_time - vm->cpu_time_main_loop_start) * ct->seconds_per_clock; - f64 atime1 = (s->side[1].active_time - vm->cpu_time_main_loop_start) * ct->seconds_per_clock; -*/ - u8 * out0 = - format (0, - "%5d: create time: %U pkts/bytes/active time: [ %ld %ld %U : %ld %ld %U ]\n", - (s - sm->sessions), - format_time_interval, "h:m:s:u", - ctime, s->side[0].n_packets, - s->side[0].n_bytes, - format_time_interval, "h:m:s:u", - atime0, s->side[1].n_packets, - s->side[1].n_bytes, - format_time_interval, "h:m:s:u", - atime1); u8 * out1 = 0; - if (s->is_ip6) - { - out1 = - format (0, "%s %U :%u <-> %U :%u", - get_l4_proto_str (s->is_ip6, - s->l4_proto), - format_ip6_address, - &s->side[0].addr.ip6, - s->side[0].port, - format_ip6_address, - &s->side[1].addr.ip6, - s->side[1].port);} - else - { - out1 = - format (0, "%s %U :%u <-> %U :%u", - get_l4_proto_str (s->is_ip6, - s->l4_proto), - format_ip4_address, - &s->side[0].addr.ip4, - s->side[0].port, - format_ip4_address, - &s->side[1].addr.ip4, - s->side[1].port);} - vlib_cli_output (vm, "%s %s", out0, - out1); vec_free (out0); - vec_free (out1);} - )); - return 0; -} - -static clib_error_t * -l2sess_show_count_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - l2sess_main_t *sm = &l2sess_main; - - vlib_cli_output (vm, "Timing wheel info: \n%U", format_timing_wheel, - &sm->timing_wheel, 255); - vlib_cli_output (vm, "session pool len: %d, pool elts: %d", - pool_len (sm->sessions), pool_elts (sm->sessions)); - vlib_cli_output (vm, - "attempted to delete sessions which were already free: %d", - sm->counter_attempted_delete_free_session); - return 0; -} - - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (l2sess_show_command, static) = { - .path = "show l2sess", - .short_help = "show l2sess", - .function = l2sess_show_command_fn, -}; - -VLIB_CLI_COMMAND (l2sess_show_count_command, static) = { - .path = "show l2sess count", - .short_help = "show l2sess count", - .function = l2sess_show_count_command_fn, -}; -/* *INDENT-OFF* */ - -static inline u64 -time_sec_to_clock( clib_time_t *ct, f64 sec) -{ - return (u64)(((f64)sec)/ct->seconds_per_clock); -} - -static clib_error_t * l2sess_init (vlib_main_t * vm) -{ - l2sess_main_t * sm = &l2sess_main; - clib_error_t * error = 0; - u64 cpu_time_now = clib_cpu_time_now(); - - - clib_time_t *ct = &vm->clib_time; - sm->udp_session_idle_timeout = time_sec_to_clock(ct, UDP_SESSION_IDLE_TIMEOUT_SEC); - sm->tcp_session_idle_timeout = time_sec_to_clock(ct, TCP_SESSION_IDLE_TIMEOUT_SEC); - sm->tcp_session_transient_timeout = time_sec_to_clock(ct, TCP_SESSION_TRANSIENT_TIMEOUT_SEC); - - /* The min sched time of 10e-1 causes erroneous behavior... */ - sm->timing_wheel.min_sched_time = 10e-2; - sm->timing_wheel.max_sched_time = 3600.0*48.0; - timing_wheel_init (&sm->timing_wheel, cpu_time_now, vm->clib_time.clocks_per_second); - sm->timer_wheel_next_expiring_time = 0; - sm->timer_wheel_tick = time_sec_to_clock(ct, sm->timing_wheel.min_sched_time); - /* Pre-allocate expired nodes. */ - vec_alloc (sm->data_from_advancing_timing_wheel, 32); - - l2sess_setup_nodes(); - l2output_init_output_node_vec (&sm->output_next_nodes.output_node_index_vec); - - return error; -} - -VLIB_INIT_FUNCTION (l2sess_init); - - diff --git a/plugins/acl-plugin/acl/l2sess.h b/plugins/acl-plugin/acl/l2sess.h deleted file mode 100644 index db899917..00000000 --- a/plugins/acl-plugin/acl/l2sess.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * 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. - */ -#ifndef __included_l2sess_h__ -#define __included_l2sess_h__ - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#define _(node_name, node_var, is_out, is_ip6, is_track) -#undef _ -#define foreach_l2sess_node \ - _("aclp-l2s-input-ip4-add", l2sess_in_ip4_add, 0, 0, 0) \ - _("aclp-l2s-input-ip6-add", l2sess_in_ip6_add, 0, 1, 0) \ - _("aclp-l2s-output-ip4-add", l2sess_out_ip4_add, 1, 0, 0) \ - _("aclp-l2s-output-ip6-add", l2sess_out_ip6_add, 1, 1, 0) \ - _("aclp-l2s-input-ip4-track", l2sess_in_ip4_track, 0, 0, 1) \ - _("aclp-l2s-input-ip6-track", l2sess_in_ip6_track, 0, 1, 1) \ - _("aclp-l2s-output-ip4-track",l2sess_out_ip4_track, 1, 0, 1) \ - _("aclp-l2s-output-ip6-track", l2sess_out_ip6_track, 1, 1, 1) - -#define _(node_name, node_var, is_out, is_ip6, is_track) \ - extern vlib_node_registration_t node_var; -foreach_l2sess_node -#undef _ - -#define TCP_FLAG_FIN 0x01 -#define TCP_FLAG_SYN 0x02 -#define TCP_FLAG_RST 0x04 -#define TCP_FLAG_PUSH 0x08 -#define TCP_FLAG_ACK 0x10 -#define TCP_FLAG_URG 0x20 -#define TCP_FLAG_ECE 0x40 -#define TCP_FLAG_CWR 0x80 -#define TCP_FLAGS_RSTFINACKSYN (TCP_FLAG_RST + TCP_FLAG_FIN + TCP_FLAG_SYN + TCP_FLAG_ACK) -#define TCP_FLAGS_ACKSYN (TCP_FLAG_SYN + TCP_FLAG_ACK) - -typedef struct { - ip46_address_t addr; - u64 active_time; - u64 n_packets; - u64 n_bytes; - u16 port; -} l2s_session_side_t; - -enum { - L2S_SESSION_SIDE_IN = 0, - L2S_SESSION_SIDE_OUT, - L2S_N_SESSION_SIDES -}; - -typedef struct { - u64 create_time; - l2s_session_side_t side[L2S_N_SESSION_SIDES]; - u8 l4_proto; - u8 is_ip6; - u16 tcp_flags_seen; /* u16 because of two sides */ -} l2s_session_t; - -#define PROD -#ifdef PROD -#define UDP_SESSION_IDLE_TIMEOUT_SEC 600 -#define TCP_SESSION_IDLE_TIMEOUT_SEC (3600*24) -#define TCP_SESSION_TRANSIENT_TIMEOUT_SEC 120 -#else -#define UDP_SESSION_IDLE_TIMEOUT_SEC 15 -#define TCP_SESSION_IDLE_TIMEOUT_SEC 15 -#define TCP_SESSION_TRANSIENT_TIMEOUT_SEC 5 -#endif - -typedef struct { - /* - * the next two fields are present for all nodes, but - * only one of them is used per node - depending - * on whether the node is an input or output one. - */ -#define _(node_name, node_var, is_out, is_ip6, is_track) \ - u32 node_var ## _input_next_node_index[32]; \ - l2_output_next_nodes_st node_var ## _next_nodes; -foreach_l2sess_node -#undef _ - l2_output_next_nodes_st output_next_nodes; - - /* Next indices of the tracker nodes */ - u32 next_slot_track_node_by_is_ip6_is_out[2][2]; - - /* - * Pairing of "forward" and "reverse" tables by table index. - * Each relationship has two entries - for one and the other table, - * so it is bidirectional. - */ - - u32 *fwd_to_rev_by_table_index; - - /* - * The vector of per-interface session pools - */ - - l2s_session_t *sessions; - - /* The session timeouts */ - u64 tcp_session_transient_timeout; - u64 tcp_session_idle_timeout; - u64 udp_session_idle_timeout; - - /* Timing wheel to time out the idle sessions */ - timing_wheel_t timing_wheel; - u32 *data_from_advancing_timing_wheel; - u64 timer_wheel_next_expiring_time; - u64 timer_wheel_tick; - - /* convenience */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; - ethernet_main_t * ethernet_main; - - /* Counter(s) */ - u64 counter_attempted_delete_free_session; -} l2sess_main_t; - -l2sess_main_t l2sess_main; - -/* Just exposed for acl.c */ - -void -l2sess_vlib_plugin_register (vlib_main_t * vm, void * hh, - int from_early_init); - - -#endif /* __included_l2sess_h__ */ diff --git a/plugins/acl-plugin/acl/l2sess_node.c b/plugins/acl-plugin/acl/l2sess_node.c deleted file mode 100644 index 520e5929..00000000 --- a/plugins/acl-plugin/acl/l2sess_node.c +++ /dev/null @@ -1,816 +0,0 @@ -/* - * 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. - */ -#include -#include -#include -#include -#include -#include -#include - - -typedef struct -{ - u32 next_index; - u32 sw_if_index; - u32 trace_flags; - u32 session_tables[2]; - u32 session_nexts[2]; - u8 l4_proto; -} l2sess_trace_t; - -/* packet trace format function */ - -#define _(node_name, node_var, is_out, is_ip6, is_track) \ -static u8 * format_## node_var ##_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 *); \ - l2sess_trace_t * t = va_arg (*args, l2sess_trace_t *); \ - \ - s = format (s, node_name ": sw_if_index %d, next index %d trace_flags %08x L4 proto %d\n" \ - " tables [ %d, %d ] nexts [ %d, %d ]", \ - t->sw_if_index, t->next_index, t->trace_flags, t->l4_proto, \ - t->session_tables[0], t->session_tables[1], \ - t->session_nexts[0], t->session_nexts[1]); \ - return s; \ -} -foreach_l2sess_node -#undef _ -#define foreach_l2sess_error \ -_(SWAPPED, "Mac swap packets processed") - typedef enum -{ -#define _(sym,str) L2SESS_ERROR_##sym, - foreach_l2sess_error -#undef _ - L2SESS_N_ERROR, -} l2sess_error_t; - -static char *l2sess_error_strings[] = { -#define _(sym,string) string, - foreach_l2sess_error -#undef _ -}; - -typedef enum -{ - L2SESS_NEXT_DROP, - L2SESS_N_NEXT, -} l2sess_next_t; - -u8 -l2sess_get_l4_proto (vlib_buffer_t * b0, int node_is_ip6) -{ - u8 proto; - int proto_offset; - if (node_is_ip6) - { - proto_offset = 20; - } - else - { - proto_offset = 23; - } - proto = *((u8 *) vlib_buffer_get_current (b0) + proto_offset); - return proto; -} - - -u8 -l2sess_get_tcp_flags (vlib_buffer_t * b0, int node_is_ip6) -{ - u8 flags; - int flags_offset; - if (node_is_ip6) - { - flags_offset = 14 + 40 + 13; /* FIXME: no extension headers assumed */ - } - else - { - flags_offset = 14 + 20 + 13; - } - flags = *((u8 *) vlib_buffer_get_current (b0) + flags_offset); - return flags; -} - -static inline int -l4_tcp_or_udp (u8 proto) -{ - return ((proto == 6) || (proto == 17)); -} - -void -l2sess_get_session_tables (l2sess_main_t * sm, u32 sw_if_index, - int node_is_out, int node_is_ip6, u8 l4_proto, - u32 * session_tables) -{ -/* - * Based on the direction, l3 and l4 protocol, fill a u32[2] array: - * [0] is index for the "direct match" path, [1] is for "mirrored match". - * Store the indices of the tables to add the session to in session_tables[] - */ - l2_output_classify_main_t *l2om = &l2_output_classify_main; - l2_input_classify_main_t *l2im = &l2_input_classify_main; - - u32 output_table_index; - u32 input_table_index; - - if (!l4_tcp_or_udp (l4_proto)) - { - return; - } - - if (node_is_ip6) - { - vec_validate_init_empty (l2im-> - classify_table_index_by_sw_if_index - [L2_INPUT_CLASSIFY_TABLE_IP6], sw_if_index, - ~0); - input_table_index = - l2im-> - classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP6] - [sw_if_index]; - vec_validate_init_empty (l2om-> - classify_table_index_by_sw_if_index - [L2_OUTPUT_CLASSIFY_TABLE_IP6], sw_if_index, - ~0); - output_table_index = - l2om-> - classify_table_index_by_sw_if_index[L2_OUTPUT_CLASSIFY_TABLE_IP6] - [sw_if_index]; - } - else - { - vec_validate_init_empty (l2im-> - classify_table_index_by_sw_if_index - [L2_INPUT_CLASSIFY_TABLE_IP4], sw_if_index, - ~0); - input_table_index = - l2im-> - classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP4] - [sw_if_index]; - vec_validate_init_empty (l2om-> - classify_table_index_by_sw_if_index - [L2_OUTPUT_CLASSIFY_TABLE_IP4], sw_if_index, - ~0); - output_table_index = - l2om-> - classify_table_index_by_sw_if_index[L2_OUTPUT_CLASSIFY_TABLE_IP4] - [sw_if_index]; - } - - if (node_is_out) - { - session_tables[0] = output_table_index; - session_tables[1] = input_table_index; - } - else - { - session_tables[0] = input_table_index; - session_tables[1] = output_table_index; - } -} - -void -l2sess_get_session_nexts (l2sess_main_t * sm, u32 sw_if_index, - int node_is_out, int node_is_ip6, u8 l4_proto, - u32 * session_nexts) -{ -/* - * Based on the direction, l3 and l4 protocol, fill a u32[2] array: - * [0] is the index for the "direct match" path, [1] is for "mirrored match". - * Store the match_next_index in session_nexts[] for a new session entry which is being added to session tables. - */ - u32 input_node_index; - u32 output_node_index; - - if (!l4_tcp_or_udp (l4_proto)) - { - return; - } - - input_node_index = - sm->next_slot_track_node_by_is_ip6_is_out[node_is_ip6][0]; - output_node_index = - sm->next_slot_track_node_by_is_ip6_is_out[node_is_ip6][1]; - - if (node_is_out) - { - session_nexts[0] = output_node_index; - session_nexts[1] = input_node_index; - } - else - { - session_nexts[0] = input_node_index; - session_nexts[1] = output_node_index; - } -} - - -static inline void -swap_bytes (vlib_buffer_t * b0, int off_a, int off_b, int nbytes) -{ - u8 tmp; - u8 *pa = vlib_buffer_get_current (b0) + off_a; - u8 *pb = vlib_buffer_get_current (b0) + off_b; - while (nbytes--) - { - tmp = *pa; - *pa++ = *pb; - *pb++ = tmp; - } -} - -/* - * This quite pro[bv]ably is a terrible idea performance wise. Moreso doing it twice. - * Would having a long (ish) chunk of memory work better for this ? - * We will see when we get to the performance of this. - */ -void -l2sess_flip_l3l4_fields (vlib_buffer_t * b0, int node_is_ip6, u8 l4_proto) -{ - if (!l4_tcp_or_udp (l4_proto)) - { - return; - } - if (node_is_ip6) - { - swap_bytes (b0, 22, 38, 16); /* L3 */ - swap_bytes (b0, 54, 56, 2); /* L4 (when no EH!) */ - } - else - { - swap_bytes (b0, 26, 30, 4); /* L3 */ - swap_bytes (b0, 34, 36, 2); /* L4 */ - } -} - -void -l2sess_add_session (vlib_buffer_t * b0, int node_is_out, int node_is_ip6, - u32 session_table, u32 session_match_next, - u32 opaque_index) -{ - vnet_classify_main_t *cm = &vnet_classify_main; - u32 action = 0; - u32 metadata = 0; - -#ifdef DEBUG_SESSIONS - printf ("Adding session to table %d with next %d\n", session_table, - session_match_next); -#endif - vnet_classify_add_del_session (cm, session_table, - vlib_buffer_get_current (b0), - session_match_next, opaque_index, 0, action, - metadata, 1); -} - - - -static void * -get_ptr_to_offset (vlib_buffer_t * b0, int offset) -{ - u8 *p = vlib_buffer_get_current (b0) + offset; - return p; -} - - -/* - * FIXME: Hardcoded offsets are ugly, although if casting to structs one - * would need to take care about alignment.. So let's for now be naive and simple. - */ - -void -session_store_ip4_l3l4_info (vlib_buffer_t * b0, l2s_session_t * sess, - int node_is_out) -{ - clib_memcpy (&sess->side[1 - node_is_out].addr.ip4, - get_ptr_to_offset (b0, 26), 4); - clib_memcpy (&sess->side[node_is_out].addr.ip4, get_ptr_to_offset (b0, 30), - 4); - sess->side[1 - node_is_out].port = - ntohs (*(u16 *) get_ptr_to_offset (b0, 34)); - sess->side[node_is_out].port = ntohs (*(u16 *) get_ptr_to_offset (b0, 36)); -} - -void -session_store_ip6_l3l4_info (vlib_buffer_t * b0, l2s_session_t * sess, - int node_is_out) -{ - clib_memcpy (&sess->side[1 - node_is_out].addr.ip6, - get_ptr_to_offset (b0, 22), 16); - clib_memcpy (&sess->side[node_is_out].addr.ip4, get_ptr_to_offset (b0, 38), - 16); - sess->side[1 - node_is_out].port = - ntohs (*(u16 *) get_ptr_to_offset (b0, 54)); - sess->side[node_is_out].port = ntohs (*(u16 *) get_ptr_to_offset (b0, 56)); -} - -static void -build_match_from_session (l2sess_main_t * sm, u8 * match, - l2s_session_t * sess, int is_out) -{ - if (sess->is_ip6) - { - match[20] = sess->l4_proto; - clib_memcpy (&match[22], &sess->side[1 - is_out].addr.ip6, 16); - clib_memcpy (&match[38], &sess->side[is_out].addr.ip4, 16); - *(u16 *) & match[54] = htons (sess->side[1 - is_out].port); - *(u16 *) & match[56] = htons (sess->side[is_out].port); - } - else - { - match[23] = sess->l4_proto; - clib_memcpy (&match[26], &sess->side[1 - is_out].addr.ip6, 4); - clib_memcpy (&match[30], &sess->side[is_out].addr.ip4, 4); - *(u16 *) & match[34] = htons (sess->side[1 - is_out].port); - *(u16 *) & match[36] = htons (sess->side[is_out].port); - } -} - -static void -delete_session (l2sess_main_t * sm, u32 sw_if_index, u32 session_index) -{ - vnet_classify_main_t *cm = &vnet_classify_main; - u8 match[5 * 16]; /* For building the mock of the packet to delete the classifier session */ - u32 session_tables[2] = { ~0, ~0 }; - l2s_session_t *sess = sm->sessions + session_index; - if (pool_is_free (sm->sessions, sess)) - { - sm->counter_attempted_delete_free_session++; - return; - } - l2sess_get_session_tables (sm, sw_if_index, 0, sess->is_ip6, sess->l4_proto, - session_tables); - if (session_tables[1] != ~0) - { - build_match_from_session (sm, match, sess, 1); - vnet_classify_add_del_session (cm, session_tables[1], match, 0, 0, 0, 0, - 0, 0); - } - if (session_tables[1] != ~0) - { - build_match_from_session (sm, match, sess, 1); - vnet_classify_add_del_session (cm, session_tables[1], match, 0, 0, 0, 0, - 0, 0); - } - pool_put (sm->sessions, sess); -} - -static void -udp_session_account_buffer (vlib_buffer_t * b0, l2s_session_t * s, - int which_side, u64 now) -{ - l2s_session_side_t *ss = &s->side[which_side]; - ss->active_time = now; - ss->n_packets++; - ss->n_bytes += b0->current_data + b0->current_length; -} - -static inline u64 -udp_session_get_timeout (l2sess_main_t * sm, l2s_session_t * sess, u64 now) -{ - return (sm->udp_session_idle_timeout); -} - -static void -tcp_session_account_buffer (vlib_buffer_t * b0, l2s_session_t * s, - int which_side, u64 now) -{ - l2s_session_side_t *ss = &s->side[which_side]; - ss->active_time = now; - ss->n_packets++; - ss->n_bytes += b0->current_data + b0->current_length; - /* Very very lightweight TCP state tracking: just record which flags were seen */ - s->tcp_flags_seen |= - l2sess_get_tcp_flags (b0, s->is_ip6) << (8 * which_side); -} - -/* - * Since we are tracking for the purposes of timing the sessions out, - * we mostly care about two states: established (maximize the idle timeouts) - * and transient (halfopen/halfclosed/reset) - we need to have a reasonably short timeout to - * quickly get rid of sessions but not short enough to violate the TCP specs. - */ - -static inline u64 -tcp_session_get_timeout (l2sess_main_t * sm, l2s_session_t * sess, u64 now) -{ - /* seen both SYNs and ACKs but not FINs means we are in establshed state */ - u16 masked_flags = - sess->tcp_flags_seen & ((TCP_FLAGS_RSTFINACKSYN << 8) + - TCP_FLAGS_RSTFINACKSYN); - if (((TCP_FLAGS_ACKSYN << 8) + TCP_FLAGS_ACKSYN) == masked_flags) - { - return (sm->tcp_session_idle_timeout); - } - else - { - return (sm->tcp_session_transient_timeout); - } -} - -static inline u64 -session_get_timeout (l2sess_main_t * sm, l2s_session_t * sess, u64 now) -{ - u64 timeout; - - switch (sess->l4_proto) - { - case 6: - timeout = tcp_session_get_timeout (sm, sess, now); - break; - case 17: - timeout = udp_session_get_timeout (sm, sess, now); - break; - default: - timeout = 0; - } - - return timeout; -} - -static inline u64 -get_session_last_active_time(l2s_session_t * sess) -{ - u64 last_active = - sess->side[0].active_time > - sess->side[1].active_time ? sess->side[0].active_time : sess->side[1]. - active_time; - return last_active; -} - -static int -session_is_alive (l2sess_main_t * sm, l2s_session_t * sess, u64 now, u64 *last_active_cache) -{ - u64 last_active = get_session_last_active_time(sess); - u64 timeout = session_get_timeout (sm, sess, now); - int is_alive = ((now - last_active) < timeout); - if (last_active_cache) - *last_active_cache = last_active; - return is_alive; -} - -static void -check_idle_sessions (l2sess_main_t * sm, u32 sw_if_index, u64 now) -{ - sm->timer_wheel_next_expiring_time = 0; - sm->data_from_advancing_timing_wheel - = - timing_wheel_advance (&sm->timing_wheel, now, - sm->data_from_advancing_timing_wheel, - &sm->timer_wheel_next_expiring_time); -#ifdef DEBUG_SESSIONS_VERBOSE - { - clib_time_t *ct = &sm->vlib_main->clib_time; - f64 ctime; - ctime = now * ct->seconds_per_clock; - clib_warning ("Now : %U", format_time_interval, "h:m:s:u", ctime); - ctime = sm->timer_wheel_next_expiring_time * ct->seconds_per_clock; - clib_warning ("Next expire: %U", format_time_interval, "h:m:s:u", ctime); - clib_warning ("Expired items: %d", - (int) vec_len (sm->data_from_advancing_timing_wheel)); - } -#endif - - sm->timer_wheel_next_expiring_time = now + sm->timer_wheel_tick; - if (PREDICT_FALSE ( 0 == sm->data_from_advancing_timing_wheel )) { - return; - } - - if (PREDICT_FALSE (_vec_len (sm->data_from_advancing_timing_wheel) > 0)) - { - uword i; - for (i = 0; i < _vec_len (sm->data_from_advancing_timing_wheel); i++) - { - u32 session_index = sm->data_from_advancing_timing_wheel[i]; - if (!pool_is_free_index (sm->sessions, session_index)) - { - l2s_session_t *sess = sm->sessions + session_index; - u64 last_active; - if (session_is_alive (sm, sess, now, &last_active)) - { -#ifdef DEBUG_SESSIONS - clib_warning ("Restarting timer for session %d", (int) session_index); -#endif - /* Pretend we did this in the past, at last_active moment */ - timing_wheel_insert (&sm->timing_wheel, - last_active + session_get_timeout (sm, sess, - last_active), - session_index); - } - else - { -#ifdef DEBUG_SESSIONS - clib_warning ("Deleting session %d", (int) session_index); -#endif - delete_session (sm, sw_if_index, session_index); - } - } - } - _vec_len (sm->data_from_advancing_timing_wheel) = 0; - } -} - -static uword -l2sess_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) -{ - u32 n_left_from, *from, *to_next; - l2sess_next_t next_index; - u32 pkts_swapped = 0; - u32 cached_sw_if_index = (u32) ~ 0; - u32 cached_next_index = (u32) ~ 0; - u32 feature_bitmap0; - u32 trace_flags0; - - l2sess_main_t *sm = &l2sess_main; - - 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); - - /* Only a single loop for now for simplicity */ - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t *b0; - u32 next0 = L2SESS_NEXT_DROP; - u32 sw_if_index0; - //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); - //en0 = vlib_buffer_get_current (b0); - -/* - * The non-boilerplate is in the block below. - * Note first a magic macro block that sets up the behavior qualifiers: - * node_is_out : 1 = is output, 0 = is input - * node_is_ip6 : 1 = is ip6, 0 = is ip4 - * node_is_track : 1 = is a state tracking node, 0 - is a session addition node - * - * Subsequently the code adjusts its behavior depending on these variables. - * It's most probably not great performance wise but much easier to work with. - * - */ - { - int node_is_out = -1; - CLIB_UNUSED (int node_is_ip6) = -1; - CLIB_UNUSED (int node_is_track) = -1; - u32 node_index = 0; - u32 session_tables[2] = { ~0, ~0 }; - u32 session_nexts[2] = { ~0, ~0 }; - l2_output_next_nodes_st *next_nodes = 0; - u32 *input_feat_next_node_index; - u8 l4_proto; - u64 now = clib_cpu_time_now (); - -/* - * Set the variables according to which of the 8 nodes we are. - * Hopefully the compiler is smart enough to eliminate the extraneous. - */ -#define _(node_name, node_var, is_out, is_ip6, is_track) \ -if(node_var.index == node->node_index) \ - { \ - node_is_out = is_out; \ - node_is_ip6 = is_ip6; \ - node_is_track = is_track; \ - node_index = node_var.index; \ - next_nodes = &sm->node_var ## _next_nodes; \ - input_feat_next_node_index = sm->node_var ## _input_next_node_index; \ - } - foreach_l2sess_node -#undef _ - trace_flags0 = 0; - if (node_is_out) - { - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - } - else - { - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - } - /* potentially also remove the nodes here */ - feature_bitmap0 = vnet_buffer (b0)->l2.feature_bitmap; - - if (node_is_track) - { - u32 sess_index = vnet_buffer (b0)->l2_classify.opaque_index; - l2s_session_t *sess = sm->sessions + sess_index; - l4_proto = sess->l4_proto; - - if (session_is_alive (sm, sess, now, 0)) - { - if (6 == l4_proto) - { - tcp_session_account_buffer (b0, sess, node_is_out, - now); - } - else - { - udp_session_account_buffer (b0, sess, node_is_out, - now); - } - } - else - { - timing_wheel_delete (&sm->timing_wheel, sess_index); - delete_session (sm, sw_if_index0, sess_index); - /* FIXME: drop the packet that hit the obsolete node, for now. We really ought to recycle it. */ - next0 = 0; - } - } - else - { - /* - * "-add" node: take l2opaque which arrived to us, and deduce - * the tables out of that. ~0 means the topmost classifier table - * applied for this AF on the RX(for input)/TX(for output)) sw_if_index. - * Also add the mirrored session to the paired table. - */ - l2s_session_t *sess; - u32 sess_index; - - l4_proto = l2sess_get_l4_proto (b0, node_is_ip6); - - pool_get (sm->sessions, sess); - sess_index = sess - sm->sessions; - sess->create_time = now; - sess->side[node_is_out].active_time = now; - sess->side[1 - node_is_out].active_time = now; - sess->l4_proto = l4_proto; - sess->is_ip6 = node_is_ip6; - if (node_is_ip6) - { - session_store_ip6_l3l4_info (b0, sess, node_is_out); - } - else - { - session_store_ip4_l3l4_info (b0, sess, node_is_out); - } - - l2sess_get_session_tables (sm, sw_if_index0, node_is_out, - node_is_ip6, l4_proto, - session_tables); - l2sess_get_session_nexts (sm, sw_if_index0, node_is_out, - node_is_ip6, l4_proto, - session_nexts); - l2sess_flip_l3l4_fields (b0, node_is_ip6, l4_proto); - if (session_tables[1] != ~0) - { - l2sess_add_session (b0, node_is_out, node_is_ip6, - session_tables[1], session_nexts[1], - sess_index); - } - l2sess_flip_l3l4_fields (b0, node_is_ip6, l4_proto); - if (session_tables[0] != ~0) - { - l2sess_add_session (b0, node_is_out, node_is_ip6, - session_tables[0], session_nexts[0], - sess_index); - } - if (6 == sess->l4_proto) - { - tcp_session_account_buffer (b0, sess, node_is_out, now); - } - else - { - udp_session_account_buffer (b0, sess, node_is_out, now); - } - timing_wheel_insert (&sm->timing_wheel, - now + session_get_timeout (sm, sess, - now), - sess_index); - } - - if (now >= sm->timer_wheel_next_expiring_time) - { - check_idle_sessions (sm, sw_if_index0, now); - } - - if (node_is_out) - { - if (feature_bitmap0) - { - trace_flags0 |= 0x10; - } - if (sw_if_index0 == cached_sw_if_index) - { - trace_flags0 |= 0x20; - } - l2_output_dispatch (sm->vlib_main, - sm->vnet_main, - node, - node_index, - &cached_sw_if_index, - &cached_next_index, - next_nodes, - b0, sw_if_index0, feature_bitmap0, - &next0); - trace_flags0 |= 2; - - } - else - { - next0 = - feat_bitmap_get_next_node_index (input_feat_next_node_index, - feature_bitmap0); - trace_flags0 |= 4; - - } - - - - if (next0 >= node->n_next_nodes) - { - trace_flags0 |= 1; - } - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - l2sess_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - t->next_index = next0; - t->trace_flags = trace_flags0; - t->l4_proto = l4_proto; - t->session_tables[0] = session_tables[0]; - t->session_tables[1] = session_tables[1]; - t->session_nexts[0] = session_nexts[0]; - t->session_nexts[1] = session_nexts[1]; - } - - } - pkts_swapped += 1; - if (next0 >= node->n_next_nodes) - { - next0 = 0; - } - - /* 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, node->node_index, - L2SESS_ERROR_SWAPPED, pkts_swapped); - return frame->n_vectors; -} - - -#define _(node_name, node_var, is_out, is_ip6, is_track) \ -static uword \ -node_var ## node_fn (vlib_main_t * vm, \ - vlib_node_runtime_t * node, \ - vlib_frame_t * frame) \ -{ \ - return l2sess_node_fn(vm, node, frame); \ -} \ -VLIB_REGISTER_NODE (node_var) = { \ - .function = node_var ## node_fn, \ - .name = node_name, \ - .vector_size = sizeof (u32), \ - .format_trace = format_ ## node_var ## _trace, \ - .type = VLIB_NODE_TYPE_INTERNAL, \ - \ - .n_errors = ARRAY_LEN(l2sess_error_strings), \ - .error_strings = l2sess_error_strings, \ - \ - .n_next_nodes = L2SESS_N_NEXT, \ - .next_nodes = { \ - [L2SESS_NEXT_DROP] = "error-drop", \ - }, \ -}; -foreach_l2sess_node -#undef _ diff --git a/plugins/acl-plugin/acl/node_in.c b/plugins/acl-plugin/acl/node_in.c deleted file mode 100644 index 2a5199a9..00000000 --- a/plugins/acl-plugin/acl/node_in.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * 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. - */ -#include -#include -#include -#include -#include -#include "node_in.h" - -typedef struct -{ - u32 next_index; - u32 sw_if_index; - u32 match_acl_index; - u32 match_rule_index; - u32 trace_bitmap; -} acl_in_trace_t; - -/* packet trace format function */ -static u8 * -format_acl_in_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 *); - acl_in_trace_t *t = va_arg (*args, acl_in_trace_t *); - - s = - format (s, - "ACL_IN: sw_if_index %d, next index %d, match: inacl %d rule %d trace_bits %08x", - t->sw_if_index, t->next_index, t->match_acl_index, - t->match_rule_index, t->trace_bitmap); - return s; -} - -vlib_node_registration_t acl_in_node; - -#define foreach_acl_in_error \ -_(ACL_CHECK, "InACL check packets processed") - -typedef enum -{ -#define _(sym,str) ACL_IN_ERROR_##sym, - foreach_acl_in_error -#undef _ - ACL_IN_N_ERROR, -} acl_in_error_t; - -static char *acl_in_error_strings[] = { -#define _(sym,string) string, - foreach_acl_in_error -#undef _ -}; - -static uword -acl_in_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) -{ - u32 n_left_from, *from, *to_next; - acl_in_next_t next_index; - u32 pkts_acl_checked = 0; - u32 feature_bitmap0; - u32 trace_bitmap = 0; - u32 *input_feat_next_node_index = - acl_main.acl_in_node_input_next_node_index; - - 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 > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t *b0; - u32 next0 = ~0; - u32 sw_if_index0; - u32 next = ~0; - u32 match_acl_index = ~0; - u32 match_rule_index = ~0; - - /* 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); - - - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - feature_bitmap0 = vnet_buffer (b0)->l2.feature_bitmap; - - input_acl_packet_match (sw_if_index0, b0, &next, &match_acl_index, - &match_rule_index, &trace_bitmap); - if (next != ~0) - { - next0 = next; - } - if (next0 == ~0) - { - next0 = - feat_bitmap_get_next_node_index (input_feat_next_node_index, - feature_bitmap0); - } - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - acl_in_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - t->next_index = next0; - t->match_acl_index = match_acl_index; - t->match_rule_index = match_rule_index; - t->trace_bitmap = trace_bitmap; - } - - next0 = next0 < node->n_next_nodes ? next0 : 0; - - pkts_acl_checked += 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, acl_in_node.index, - ACL_IN_ERROR_ACL_CHECK, pkts_acl_checked); - return frame->n_vectors; -} - -VLIB_REGISTER_NODE (acl_in_node) = -{ - .function = acl_in_node_fn,.name = "acl-plugin-in",.vector_size = - sizeof (u32),.format_trace = format_acl_in_trace,.type = - VLIB_NODE_TYPE_INTERNAL,.n_errors = - ARRAY_LEN (acl_in_error_strings),.error_strings = - acl_in_error_strings,.n_next_nodes = ACL_IN_N_NEXT, - /* edit / add dispositions here */ - .next_nodes = - { - [ACL_IN_ERROR_DROP] = "error-drop", - [ACL_IN_ETHERNET_INPUT] = "ethernet-input", - [ACL_IN_L2S_INPUT_IP4_ADD] = "aclp-l2s-input-ip4-add", - [ACL_IN_L2S_INPUT_IP6_ADD] = "aclp-l2s-input-ip6-add",} -,}; diff --git a/plugins/acl-plugin/acl/node_in.h b/plugins/acl-plugin/acl/node_in.h deleted file mode 100644 index 502bbf8d..00000000 --- a/plugins/acl-plugin/acl/node_in.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _NODE_IN_H_ -#define _NODE_IN_H_ - -typedef enum { - ACL_IN_ERROR_DROP, - ACL_IN_ETHERNET_INPUT, - ACL_IN_L2S_INPUT_IP4_ADD, - ACL_IN_L2S_INPUT_IP6_ADD, - ACL_IN_N_NEXT, -} acl_in_next_t; - -#endif diff --git a/plugins/acl-plugin/acl/node_out.c b/plugins/acl-plugin/acl/node_out.c deleted file mode 100644 index 50af3679..00000000 --- a/plugins/acl-plugin/acl/node_out.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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. - */ -#include -#include -#include -#include -#include - -#include "node_out.h" - -typedef struct -{ - u32 next_index; - u32 sw_if_index; - u32 match_acl_index; - u32 match_rule_index; - u32 trace_bitmap; -} acl_out_trace_t; - -/* packet trace format function */ -static u8 * -format_acl_out_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 *); - acl_out_trace_t *t = va_arg (*args, acl_out_trace_t *); - s = - format (s, - "ACL_OUT: sw_if_index %d, next index %d, match: outacl %d rule %d trace_bits %08x", - t->sw_if_index, t->next_index, t->match_acl_index, - t->match_rule_index, t->trace_bitmap); - return s; -} - -vlib_node_registration_t acl_out_node; - -#define foreach_acl_out_error \ -_(ACL_CHECK, "OutACL check packets processed") - -typedef enum -{ -#define _(sym,str) ACL_OUT_ERROR_##sym, - foreach_acl_out_error -#undef _ - ACL_OUT_N_ERROR, -} acl_out_error_t; - -static char *acl_out_error_strings[] = { -#define _(sym,string) string, - foreach_acl_out_error -#undef _ -}; - -static uword -acl_out_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) -{ - acl_main_t *am = &acl_main; - l2_output_next_nodes_st *next_nodes = &am->acl_out_output_next_nodes; - u32 n_left_from, *from, *to_next; - acl_out_next_t next_index; - u32 pkts_acl_checked = 0; - u32 feature_bitmap0; - u32 cached_sw_if_index = (u32) ~ 0; - u32 cached_next_index = (u32) ~ 0; - u32 match_acl_index = ~0; - u32 match_rule_index = ~0; - u32 trace_bitmap = 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 > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t *b0; - u32 next0 = ~0; - u32 next = 0; - u32 sw_if_index0; - - /* 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); - - - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - feature_bitmap0 = vnet_buffer (b0)->l2.feature_bitmap; - - output_acl_packet_match (sw_if_index0, b0, &next, &match_acl_index, - &match_rule_index, &trace_bitmap); - if (next != ~0) - { - next0 = next; - } - if (next0 == ~0) - { - l2_output_dispatch (vm, - am->vnet_main, - node, - acl_out_node.index, - &cached_sw_if_index, - &cached_next_index, - next_nodes, - b0, sw_if_index0, feature_bitmap0, &next0); - } - - - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - acl_out_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - t->next_index = next0; - t->match_acl_index = match_acl_index; - t->match_rule_index = match_rule_index; - t->trace_bitmap = trace_bitmap; - } - - pkts_acl_checked += 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, acl_out_node.index, - ACL_OUT_ERROR_ACL_CHECK, pkts_acl_checked); - return frame->n_vectors; -} - -VLIB_REGISTER_NODE (acl_out_node) = -{ - .function = acl_out_node_fn,.name = "acl-plugin-out",.vector_size = - sizeof (u32),.format_trace = format_acl_out_trace,.type = - VLIB_NODE_TYPE_INTERNAL,.n_errors = - ARRAY_LEN (acl_out_error_strings),.error_strings = - acl_out_error_strings,.n_next_nodes = ACL_OUT_N_NEXT, - /* edit / add dispositions here */ - .next_nodes = - { - [ACL_OUT_ERROR_DROP] = "error-drop", - [ACL_OUT_INTERFACE_OUTPUT] = "interface-output", - [ACL_OUT_L2S_OUTPUT_IP4_ADD] = "aclp-l2s-output-ip4-add", - [ACL_OUT_L2S_OUTPUT_IP6_ADD] = "aclp-l2s-output-ip6-add",} -,}; diff --git a/plugins/acl-plugin/acl/node_out.h b/plugins/acl-plugin/acl/node_out.h deleted file mode 100644 index c919f3b7..00000000 --- a/plugins/acl-plugin/acl/node_out.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _NODE_OUT_H_ -#define _NODE_OUT_H_ - -typedef enum { - ACL_OUT_ERROR_DROP, - ACL_OUT_INTERFACE_OUTPUT, - ACL_OUT_L2S_OUTPUT_IP4_ADD, - ACL_OUT_L2S_OUTPUT_IP6_ADD, - ACL_OUT_N_NEXT, -} acl_out_next_t; - -#endif diff --git a/plugins/acl-plugin/configure.ac b/plugins/acl-plugin/configure.ac deleted file mode 100644 index 204f4e4d..00000000 --- a/plugins/acl-plugin/configure.ac +++ /dev/null @@ -1,24 +0,0 @@ -AC_INIT(acl_plugin, 1.0) -AC_CONFIG_MACRO_DIR([../../vpp-api/java/m4]) -LT_INIT -AM_INIT_AUTOMAKE -AM_SILENT_RULES([yes]) -AC_PREFIX_DEFAULT([/usr]) - -AC_PROG_CC - -if test -f /usr/bin/lsb_release && test `lsb_release -si` == "Ubuntu" && test `lsb_release -sr` == "14.04" && test -d /usr/lib/jvm/java-8-openjdk-amd64/ ; then - JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/ - JAVAC=${JAVA_HOME}/bin/javac - PATH=${JAVA_HOME}/bin/:${PATH} - break -fi - -AX_CHECK_JAVA_HOME -AX_PROG_JAVAC -AX_PROG_JAVAH -AX_PROG_JAR -AX_PROG_JAVADOC -AX_PROG_JAVA - -AC_OUTPUT([Makefile]) diff --git a/plugins/acl-plugin/test/run-python b/plugins/acl-plugin/test/run-python deleted file mode 100755 index 215eb17a..00000000 --- a/plugins/acl-plugin/test/run-python +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# Do all the legwork to run a scapy shell with APIs available for load -# -CURR_DIR=`pwd` -ROOT_DIR=`git rev-parse --show-toplevel` -cd $ROOT_DIR -sudo apt-get install -y python-virtualenv -# uncomment the line below to enable build of plugins and api each time -# make plugins && make build-vpp-api || exit -virtualenv virtualenv -virtualenv/bin/pip install ipaddress -virtualenv/bin/pip install scapy -# install the python API into the virtualenv -cd $ROOT_DIR/vpp-api/python/ -$ROOT_DIR/virtualenv/bin/python setup.py install -# install the python ACL plugin API into the virtualenv -ACL_PLUGIN_SETUP_DIR=`find $ROOT_DIR/build-root -name acl-plugin` -cd $ACL_PLUGIN_SETUP_DIR; -$ROOT_DIR/virtualenv/bin/python setup.py install -cd $ROOT_DIR -# figure out the shared library path and start scapy -export LD_LIBRARY_PATH=`pwd`/`find . -name "libpneum.so" -exec dirname {} \; | grep lib64 | head -n 1` -cd $CURR_DIR -sudo LD_LIBRARY_PATH=$LD_LIBRARY_PATH $ROOT_DIR/virtualenv/bin/python $1 $2 $3 $4 $5 $6 $7 $8 $9 - - - diff --git a/plugins/acl-plugin/test/run-scapy b/plugins/acl-plugin/test/run-scapy deleted file mode 100755 index 266f07d1..00000000 --- a/plugins/acl-plugin/test/run-scapy +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh -# -# Do all the legwork to run a scapy shell with APIs available for load -# -ROOT_DIR=`git rev-parse --show-toplevel` -cd $ROOT_DIR -sudo apt-get install -y python-virtualenv -# uncomment the line below to enable the build of plugins and API each time.. -# make plugins && make build-vpp-api || exit -virtualenv virtualenv -virtualenv/bin/pip install ipaddress -virtualenv/bin/pip install scapy -# install the python API into the virtualenv -cd $ROOT_DIR/vpp-api/python/ -$ROOT_DIR/virtualenv/bin/python setup.py install -# install the python ACL plugin API into the virtualenv -ACL_PLUGIN_SETUP_DIR=`find $ROOT_DIR/build-root -name acl-plugin` -cd $ACL_PLUGIN_SETUP_DIR; -$ROOT_DIR/virtualenv/bin/python setup.py install -cd $ROOT_DIR -# figure out the shared library path and start scapy -export LD_LIBRARY_PATH=`pwd`/`find . -name "libpneum.so" -exec dirname {} \; | grep lib64 | head -n 1` -sudo LD_LIBRARY_PATH=$LD_LIBRARY_PATH virtualenv/bin/scapy - - - diff --git a/plugins/acl-plugin/test/test_acl_plugin.py b/plugins/acl-plugin/test/test_acl_plugin.py deleted file mode 100644 index 7fc72d67..00000000 --- a/plugins/acl-plugin/test/test_acl_plugin.py +++ /dev/null @@ -1,118 +0,0 @@ -from __future__ import print_function -import unittest, sys, time, threading, struct, logging, os -import vpp_papi -# import vpp_papi_plugins.acl -from ipaddress import * -papi_event = threading.Event() -print(vpp_papi.vpe.VL_API_SW_INTERFACE_SET_FLAGS) -def papi_event_handler(result): - if result.vl_msg_id == vpp_papi.vpe.VL_API_SW_INTERFACE_SET_FLAGS: - return - if result.vl_msg_id == vpp_papi.vpe.VL_API_VNET_INTERFACE_COUNTERS: - print('Interface counters', result) - return - if result.vl_msg_id == vpp_papi.vpe.VL_API_VNET_IP6_FIB_COUNTERS: - print('IPv6 FIB counters', result) - papi_event.set() - return - - print('Unknown message id:', result.vl_msg_id) - -import glob, subprocess -class TestAclPlugin(unittest.TestCase): - @classmethod - def setUpClass(cls): - print("Setup") - @classmethod - def tearDownClass(cls): - print("Teardown") - - def setUp(self): - print("Connecting API") - r = vpp_papi.connect("test_papi") - self.assertEqual(r, 0) - - def tearDown(self): - r = vpp_papi.disconnect() - self.assertEqual(r, 0) - - # - # The tests themselves - # - - # - # Basic request / reply - # - def test_show_version(self): - t = vpp_papi.show_version() - print('T', t); - program = t.program.decode().rstrip('\x00') - self.assertEqual('vpe', program) - - def x_test_acl_add(self): - print("Test ACL add") - self.assertEqual(1, 1) - - # - # Details / Dump - # - def x_test_details_dump(self): - t = vpp_papi.sw_interface_dump(0, b'') - print('Dump/details T', t) - - # - # Arrays - # - def x_test_arrays(self): - t = vpp_papi.vnet_get_summary_stats() - print('Summary stats', t) - print('Packets:', t.total_pkts[0]) - print('Packets:', t.total_pkts[1]) - # - # Variable sized arrays and counters - # - #@unittest.skip("stats") - def x_test_want_stats(self): - pid = 123 - vpp_papi.register_event_callback(papi_event_handler) - papi_event.clear() - - # Need to configure IPv6 to get som IPv6 FIB stats - t = vpp_papi.create_loopback('') - print(t) - self.assertEqual(t.retval, 0) - - ifindex = t.sw_if_index - addr = str(IPv6Address(u'1::1').packed) - t = vpp_papi.sw_interface_add_del_address(ifindex, 1, 1, 0, 16, addr) - print(t) - self.assertEqual(t.retval, 0) - - # Check if interface is up - # XXX: Add new API to query interface state based on ifindex, instead of dump all. - t = vpp_papi.sw_interface_set_flags(ifindex, 1, 1, 0) - self.assertEqual(t.retval, 0) - - t = vpp_papi.want_stats(True, pid) - - print (t) - - # - # Wait for some stats - # - self.assertEqual(papi_event.wait(15), True) - t = vpp_papi.want_stats(False, pid) - print (t) - - - # - # Plugins? - # - -if __name__ == '__main__' or __name__ == '__builtin__': - print("This is main") - suite = unittest.TestLoader().loadTestsFromTestCase(TestAclPlugin) - unittest.TextTestRunner(verbosity=2).run(suite) - #logging.basicConfig(level=logging.DEBUG) - # unittest.main() - diff --git a/plugins/configure.ac b/plugins/configure.ac index 9c631634..b6ba4152 100644 --- a/plugins/configure.ac +++ b/plugins/configure.ac @@ -53,11 +53,6 @@ AM_CONDITIONAL(ENABLE_$1_PLUGIN, test "$enable_the_plugin" = "1") # SUBDIRS += new-plugin # endif -PLUGIN_ENABLED(ioam) -PLUGIN_ENABLED(snat) -PLUGIN_ENABLED(lb) -PLUGIN_ENABLED(acl) - # Disabled plugins, require --enable-XXX-plugin PLUGIN_DISABLED(vcgn) PLUGIN_DISABLED(sample) diff --git a/plugins/ioam-plugin/Makefile.am b/plugins/ioam-plugin/Makefile.am deleted file mode 100644 index b00b088c..00000000 --- a/plugins/ioam-plugin/Makefile.am +++ /dev/null @@ -1,338 +0,0 @@ -# Copyright (c) 2015 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -AUTOMAKE_OPTIONS = foreign subdir-objects - -AM_CFLAGS = -Wall -AM_LDFLAGS = -module -shared -avoid-version - -######################################## -# iOAM Proof of Transit -######################################## - -ioam_pot_plugin_la_SOURCES = \ - ioam/lib-pot/pot_util.c \ - ioam/encap/ip6_ioam_pot.c \ - ioam/lib-pot/pot_util.h \ - ioam/lib-pot/math64.h \ - ioam/lib-pot/pot_api.c - -BUILT_SOURCES = \ - ioam/lib-pot/pot.api.h \ - ioam/lib-pot/pot.api.json - -SUFFIXES = .api.h .api - -%.api.h: %.api - mkdir -p `dirname $@` ; \ - $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ - | vppapigen --input - --output $@ --show-name $@ - -%.api.json: %.api - @echo " JSON APIGEN " $@ ; \ - mkdir -p `dirname $@` ; \ - $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ - | vppapigen --input - --json $@ - -apidir = $(prefix)/ioam/ -api_DATA = \ - ioam/lib-pot/pot.api.json \ - ioam/lib-trace/trace.api.json \ - ioam/export/ioam_export.api.json - -noinst_HEADERS = \ - ioam/lib-pot/pot_all_api_h.h \ - ioam/lib-pot/pot_msg_enum.h \ - ioam/lib-pot/pot.api.h \ - ioam/lib-pot/pot_util.h \ - ioam/lib-pot/math64.h - -ioam_pot_test_plugin_la_SOURCES = \ - ioam/lib-pot/pot_test.c \ - ioam/lib-pot/pot_plugin.api.h - -vppapitestpluginsdir = ${libdir}/vpp_api_test_plugins -vpppluginsdir = ${libdir}/vpp_plugins - -vppapitestplugins_LTLIBRARIES = ioam_pot_test_plugin.la -vppplugins_LTLIBRARIES = ioam_pot_plugin.la - -######################################## -# iOAM trace export for IPv6 -######################################## - -ioam_export_plugin_la_SOURCES = \ -ioam/export/ioam_export.c \ -ioam/export/node.c \ -ioam/export/ioam_export.api.h \ -ioam/export/ioam_export_thread.c - -BUILT_SOURCES += \ - ioam/export/ioam_export.api.h \ - ioam/export/ioam_export.api.json - -noinst_HEADERS += \ - ioam/export/ioam_export_all_api_h.h \ - ioam/export/ioam_export_msg_enum.h \ - ioam/export/ioam_export.api.h - -ioam_export_test_plugin_la_SOURCES = \ - ioam/export/ioam_export_test.c \ - ioam/export/ioam_export_plugin.api.h - -vppapitestplugins_LTLIBRARIES += ioam_export_test_plugin.la -vppplugins_LTLIBRARIES += ioam_export_plugin.la - -######################################## -# iOAM Trace -######################################## -libioam_trace_plugin_la_SOURCES = \ - ioam/lib-trace/trace_util.c \ - ioam/encap/ip6_ioam_trace.c \ - ioam/lib-trace/trace_util.h \ - ioam/lib-trace/trace_api.c - -BUILT_SOURCES += \ - ioam/lib-trace/trace.api.h \ - ioam/lib-trace/trace.api.json - -noinst_HEADERS += \ - ioam/export/ioam_export_all_api_h.h \ - ioam/lib-trace/trace_all_api_h.h \ - ioam/lib-trace/trace_msg_enum.h \ - ioam/lib-trace/trace.api.h \ - ioam/lib-trace/trace_util.h - -ioam_trace_test_plugin_la_SOURCES = \ - ioam/lib-trace/trace_test.c \ - ioam/lib-trace/trace_plugin.api.h - -vppapitestplugins_LTLIBRARIES += ioam_trace_test_plugin.la -vppplugins_LTLIBRARIES += libioam_trace_plugin.la - -######################################## -# VxLAN-GPE -######################################## -libioam_vxlan_gpe_plugin_la_SOURCES = \ - ioam/lib-vxlan-gpe/ioam_encap.c \ - ioam/lib-vxlan-gpe/ioam_decap.c \ - ioam/lib-vxlan-gpe/ioam_transit.c \ - ioam/lib-vxlan-gpe/ioam_pop.c \ - ioam/lib-vxlan-gpe/vxlan_gpe_api.c \ - ioam/lib-vxlan-gpe/vxlan_gpe_ioam_trace.c \ - ioam/lib-vxlan-gpe/vxlan_gpe_ioam.c \ - ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.c \ - ioam/export-vxlan-gpe/vxlan_gpe_node.c \ - ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.api.h\ - ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_thread.c - -BUILT_SOURCES += \ - ioam/lib-vxlan-gpe/vxlan_gpe.api.h \ - ioam/lib-vxlan-gpe/vxlan_gpe.api.json \ - ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.api.h \ - ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.api.json - -noinst_HEADERS += \ - ioam/export/ioam_export_all_api_h.h \ - ioam/lib-vxlan-gpe/vxlan_gpe_all_api_h.h \ - ioam/lib-vxlan-gpe/vxlan_gpe_msg_enum.h \ - ioam/lib-vxlan-gpe/vxlan_gpe.api.h \ - ioam/lib-vxlan-gpe/vxlan_gpe_ioam_util.h \ - ioam/lib-vxlan-gpe/vxlan_gpe_ioam_packet.h \ - ioam/lib-vxlan-gpe/vxlan_gpe_ioam.h \ - ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_all_api_h.h \ - ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_msg_enum.h \ - ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.api.h - -ioam_vxlan_gpe_test_plugin_la_SOURCES = \ - ioam/lib-vxlan-gpe/vxlan_gpe_test.c \ - ioam/lib-vxlan-gpe/vxlan_gpe_plugin.api.h - -libioam_vxlan_gpe_plugin_la_LIBADD = libioam_trace_plugin.la - -vppapitestplugins_LTLIBRARIES += ioam_vxlan_gpe_test_plugin.la -vppplugins_LTLIBRARIES += libioam_vxlan_gpe_plugin.la - -vxlan_gpe_ioam_export_test_plugin_la_SOURCES = \ - ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_test.c \ - ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_plugin.api.h - -vppapitestplugins_LTLIBRARIES += vxlan_gpe_ioam_export_test_plugin.la - -######################################## -# iOAM E2E plugin -######################################## - -ioam_e2e_plugin_la_SOURCES = \ - ioam/encap/ip6_ioam_e2e.c \ - ioam/encap/ip6_ioam_seqno.c \ - ioam/encap/ip6_ioam_seqno_analyse.c - -noinst_HEADERS += \ - ioam/encap/ip6_ioam_e2e.h \ - ioam/encap/ip6_ioam_seqno.h - -vppplugins_LTLIBRARIES += ioam_e2e_plugin.la - -# Remove *.la files -install-data-hook: - @(cd $(vpppluginsdir) && $(RM) $(vppplugins_LTLIBRARIES)) - @(cd $(vppapitestpluginsdir) && $(RM) $(vppapitestplugins_LTLIBRARIES)) - - -# -# Java code generation -# -jvpp_registry_root = ../../vpp-api/java -jvpp_registry_version = 17.04 -jioam_trace_jarfile = jvpp-ioam-trace-$(PACKAGE_VERSION).jar -jvpp_trace_package_dir = io/fd/vpp/jvpp/ioamtrace -jvpp_root = ioam/jvpp -jvpp_target_dir = target -jvpp_target = $(jvpp_root)/$(jvpp_target_dir) -trace_api_file=$(srcdir)/ioam/lib-trace/trace.api - - -lib_LTLIBRARIES = libjvpp_ioamtrace.la -libjvpp_ioamtrace_la_SOURCES = ioam/lib-trace/trace.api.h ioam/lib-trace/jvpp_ioam_trace.c ioam/jvpp/io_fd_vpp_jvpp_ioam_trace_JVppIoamTraceImpl.h -libjvpp_ioamtrace_la_LIBADD = -lvlibmemoryclient -lvlibapi -lvppinfra \ - -lpthread -lm -lrt -L$(jvpp_registry_root)/.libs -ljvpp_common -libjvpp_ioamtrace_la_LDFLAGS = -module -libjvpp_ioamtrace_la_CPPFLAGS = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -I../ -I$(srcdir)/../ - -BUILT_SOURCES += $(jvpp_root)/io_fd_vpp_jvpp_ioamtrace_JVppIoamtraceImpl.h - -$(jvpp_root)/io_fd_vpp_jvpp_ioamtrace_JVppIoamtraceImpl.h: ioam_trace.api.json - dir=`pwd`; \ - mkdir -p $(jvpp_target); \ - mkdir -p $(jvpp_root)/$(jvpp_trace_package_dir); \ - cd $(jvpp_root)/$(jvpp_trace_package_dir); \ - mkdir -p dto future callfacade callback notification test; \ - @srcdir@/$(jvpp_registry_root)/jvpp/gen/jvpp_gen.py -i $${dir}/ioam_trace.api.json --plugin_name ioamtrace; \ - cd -; \ - mv -f $(jvpp_root)/$(jvpp_trace_package_dir)/jvpp_ioamtrace_gen.h $(jvpp_root)/jvpp_ioam_trace_gen.h; \ - cp $(srcdir)/$(jvpp_root)/$(jvpp_trace_package_dir)/test/*.java $(jvpp_root)/$(jvpp_trace_package_dir)/test/; \ - cd $(jvpp_root); \ - $(JAVAC) -classpath .:$(jvpp_target_dir):../../$(jvpp_registry_root)/jvpp-registry-$(jvpp_registry_version).jar -d $(jvpp_target_dir) $(jvpp_trace_package_dir)/*.java \ - $(jvpp_trace_package_dir)/dto/*.java \ - $(jvpp_trace_package_dir)/callback/*.java \ - $(jvpp_trace_package_dir)/notification/*.java \ - $(jvpp_trace_package_dir)/future/*.java \ - $(jvpp_trace_package_dir)/callfacade/*.java \ - $(jvpp_trace_package_dir)/test/*.java \ - || (echo "ioam trace jvpp compilation failed: $$?"; exit 1); \ - $(JAVAH) -classpath .:$(jvpp_target_dir):../../$(jvpp_registry_root)/jvpp-registry-$(jvpp_registry_version).jar -d . io.fd.vpp.jvpp.ioamtrace.JVppIoamtraceImpl ; - -$(jioam_trace_jarfile): libjvpp_ioamtrace.la - cp .libs/libjvpp_ioamtrace.so.0.0.0 $(jvpp_target); \ - cd $(jvpp_target); \ - $(JAR) cfv $(JARFLAGS) ../../../$@ libjvpp_ioamtrace.so.0.0.0 $(jvpp_trace_package_dir)/* ; cd ..; - -ioam_trace.api.json: - @echo " jIoam_trace API"; \ - vppapigen --input $(trace_api_file) --json ioam_trace.api.json; - -all-local: $(jioam_trace_jarfile) - - -jioam_pot_jarfile = jvpp-ioam-pot-$(PACKAGE_VERSION).jar -jvpp_pot_package_dir = io/fd/vpp/jvpp/ioampot -pot_api_file=$(srcdir)/ioam/lib-pot/pot.api - - -lib_LTLIBRARIES += libjvpp_ioampot.la -libjvpp_ioampot_la_SOURCES = ioam/lib-pot/pot.api.h ioam/lib-pot/jvpp_ioam_pot.c ioam/jvpp/io_fd_vpp_jvpp_ioam_pot_JVppIoamPotImpl.h -libjvpp_ioampot_la_LIBADD = -lvlibmemoryclient -lvlibapi -lvppinfra \ - -lpthread -lm -lrt -L$(jvpp_registry_root)/.libs -ljvpp_common -libjvpp_ioampot_la_LDFLAGS = -module -libjvpp_ioampot_la_CPPFLAGS = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -I../ -I$(srcdir)/../ - -BUILT_SOURCES += $(jvpp_root)/io_fd_vpp_jvpp_ioampot_JVppIoampotImpl.h - -$(jvpp_root)/io_fd_vpp_jvpp_ioampot_JVppIoampotImpl.h: ioam_pot.api.json - dir=`pwd`; \ - mkdir -p $(jvpp_target); \ - mkdir -p $(jvpp_root)/$(jvpp_pot_package_dir); \ - cd $(jvpp_root)/$(jvpp_pot_package_dir); \ - mkdir -p dto future callfacade callback notification test; \ - @srcdir@/$(jvpp_registry_root)/jvpp/gen/jvpp_gen.py -i $${dir}/ioam_pot.api.json --plugin_name ioampot; \ - cd -; \ - mv -f $(jvpp_root)/$(jvpp_pot_package_dir)/jvpp_ioampot_gen.h $(jvpp_root)/jvpp_ioam_pot_gen.h; \ - cp $(srcdir)/$(jvpp_root)/$(jvpp_pot_package_dir)/test/*.java $(jvpp_root)/$(jvpp_pot_package_dir)/test/; \ - cd $(jvpp_root); \ - $(JAVAC) -classpath .:$(jvpp_target_dir):../../$(jvpp_registry_root)/jvpp-registry-$(jvpp_registry_version).jar -d $(jvpp_target_dir) $(jvpp_pot_package_dir)/*.java \ - $(jvpp_pot_package_dir)/dto/*.java \ - $(jvpp_pot_package_dir)/callback/*.java \ - $(jvpp_pot_package_dir)/notification/*.java \ - $(jvpp_pot_package_dir)/future/*.java \ - $(jvpp_pot_package_dir)/callfacade/*.java \ - $(jvpp_pot_package_dir)/test/*.java \ - || (echo "ioam pot jvpp compilation failed: $$?"; exit 1); \ - $(JAVAH) -classpath .:$(jvpp_target_dir):../../$(jvpp_registry_root)/jvpp-registry-$(jvpp_registry_version).jar -d . io.fd.vpp.jvpp.ioampot.JVppIoampotImpl ; - -$(jioam_pot_jarfile): libjvpp_ioampot.la - cp .libs/libjvpp_ioampot.so.0.0.0 $(jvpp_target); \ - cd $(jvpp_target); \ - $(JAR) cfv $(JARFLAGS) ../../../$@ libjvpp_ioampot.so.0.0.0 $(jvpp_pot_package_dir)/* ; cd ..; - -ioam_pot.api.json: - @echo " jIoam_pot API"; \ - vppapigen --input $(pot_api_file) --json ioam_pot.api.json; - -all-local: $(jioam_pot_jarfile) - -jioam_export_jarfile = jvpp-ioam-export-$(PACKAGE_VERSION).jar -jvpp_export_package_dir = io/fd/vpp/jvpp/ioamexport -export_api_file=$(srcdir)/ioam/export/ioam_export.api - - -lib_LTLIBRARIES += libjvpp_ioamexport.la -libjvpp_ioamexport_la_SOURCES = ioam/export/export.api.h ioam/export/jvpp_ioam_export.c ioam/jvpp/io_fd_vpp_jvpp_ioam_export_JVppIoamexportImpl.h -libjvpp_ioamexport_la_LIBADD = -lvlibmemoryclient -lvlibapi -lvppinfra \ - -lpthread -lm -lrt -L$(jvpp_registry_root)/.libs -ljvpp_common -libjvpp_ioamexport_la_LDFLAGS = -module -libjvpp_ioamexport_la_CPPFLAGS = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -I../ -I$(srcdir)/../ - -BUILT_SOURCES += $(jvpp_root)/io_fd_vpp_jvpp_ioamexport_JVppIoamexportImpl.h - -$(jvpp_root)/io_fd_vpp_jvpp_ioamexport_JVppIoamexportImpl.h: ioam_export.api.json - dir=`pwd`; \ - mkdir -p $(jvpp_target); \ - mkdir -p $(jvpp_root)/$(jvpp_export_package_dir); \ - cd $(jvpp_root)/$(jvpp_export_package_dir); \ - mkdir -p dto future callfacade callback notification test; \ - @srcdir@/$(jvpp_registry_root)/jvpp/gen/jvpp_gen.py -i $${dir}/ioam_export.api.json --plugin_name ioamexport; \ - cd -; \ - mv -f $(jvpp_root)/$(jvpp_export_package_dir)/jvpp_ioamexport_gen.h $(jvpp_root)/jvpp_ioam_export_gen.h; \ - cp $(srcdir)/$(jvpp_root)/$(jvpp_export_package_dir)/test/*.java $(jvpp_root)/$(jvpp_export_package_dir)/test/; \ - cd $(jvpp_root); \ - $(JAVAC) -classpath .:$(jvpp_target_dir):../../$(jvpp_registry_root)/jvpp-registry-$(jvpp_registry_version).jar -d $(jvpp_target_dir) $(jvpp_export_package_dir)/*.java \ - $(jvpp_export_package_dir)/dto/*.java \ - $(jvpp_export_package_dir)/callback/*.java \ - $(jvpp_export_package_dir)/notification/*.java \ - $(jvpp_export_package_dir)/future/*.java \ - $(jvpp_export_package_dir)/callfacade/*.java \ - $(jvpp_export_package_dir)/test/*.java \ - || (echo "ioam export jvpp compilation failed: $$?"; exit 1); \ - $(JAVAH) -classpath .:$(jvpp_target_dir):../../$(jvpp_registry_root)/jvpp-registry-$(jvpp_registry_version).jar -d . io.fd.vpp.jvpp.ioamexport.JVppIoamexportImpl ; - -$(jioam_export_jarfile): libjvpp_ioamexport.la - cp .libs/libjvpp_ioamexport.so.0.0.0 $(jvpp_target); \ - cd $(jvpp_target); \ - $(JAR) cfv $(JARFLAGS) ../../../$@ libjvpp_ioamexport.so.0.0.0 $(jvpp_export_package_dir)/* ; cd ..; - -ioam_export.api.json: - @echo " jIoam_export API"; \ - vppapigen --input $(export_api_file) --json ioam_export.api.json; - -all-local: $(jioam_export_jarfile) diff --git a/plugins/ioam-plugin/configure.ac b/plugins/ioam-plugin/configure.ac deleted file mode 100644 index 287bcaab..00000000 --- a/plugins/ioam-plugin/configure.ac +++ /dev/null @@ -1,25 +0,0 @@ -AC_INIT(ioam_plugin, 1.0) -LT_INIT -AC_CONFIG_MACRO_DIR([../../vpp-api/java/m4]) -AM_INIT_AUTOMAKE -AC_PREFIX_DEFAULT([/usr]) -AM_SILENT_RULES([yes]) - -AC_PROG_CC - -if test -f /usr/bin/lsb_release && test `lsb_release -si` == "Ubuntu" && test `lsb_release -sr` == "14.04" && test -d /usr/lib/jvm/java-8-openjdk-amd64/ ; then - JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/ - JAVAC=${JAVA_HOME}/bin/javac - PATH=${JAVA_HOME}/bin/:${PATH} - break -fi - -AX_CHECK_JAVA_HOME -AX_PROG_JAVAC -AX_PROG_JAVAH -AX_PROG_JAR -AX_PROG_JAVADOC -AX_PROG_JAVA - - -AC_OUTPUT([Makefile]) diff --git a/plugins/ioam-plugin/ioam/dir.dox b/plugins/ioam-plugin/ioam/dir.dox deleted file mode 100644 index f3389b52..00000000 --- a/plugins/ioam-plugin/ioam/dir.dox +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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. - */ -/** - @dir - @brief Inband OAM (iOAM) implementation -*/ diff --git a/plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.c b/plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.c deleted file mode 100644 index 0839cdce..00000000 --- a/plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include - -#include "ip6_ioam_e2e.h" - -ioam_e2e_main_t ioam_e2e_main; - -static u8 * ioam_e2e_trace_handler (u8 * s, - ip6_hop_by_hop_option_t *opt) -{ - ioam_e2e_option_t * e2e = (ioam_e2e_option_t *)opt; - u32 seqno = 0; - - if (e2e) - { - seqno = clib_net_to_host_u32 (e2e->e2e_data); - } - - s = format (s, "SeqNo = 0x%Lx", seqno); - return s; -} - -int -ioam_e2e_config_handler (void *data, u8 disable) -{ - int *analyse = data; - - /* Register hanlders if enabled */ - if (!disable) - { - /* If encap node register for encap handler */ - if (0 == *analyse) - { - if (ip6_hbh_register_option(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE, - ioam_seqno_encap_handler, - ioam_e2e_trace_handler) < 0) - { - return (-1); - } - } - /* If analyze node then register for decap handler */ - else - { - if (ip6_hbh_pop_register_option(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE, - ioam_seqno_decap_handler) < 0) - { - return (-1); - } - } - return 0; - } - - /* UnRegister handlers */ - (void) ip6_hbh_unregister_option(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE); - (void) ip6_hbh_pop_unregister_option(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE); - return 0; -} - -int -ioam_e2e_rewrite_handler (u8 *rewrite_string, - u8 *rewrite_size) -{ - ioam_e2e_option_t *e2e_option; - - if (rewrite_string && *rewrite_size == sizeof(ioam_e2e_option_t)) - { - e2e_option = (ioam_e2e_option_t *)rewrite_string; - e2e_option->hdr.type = HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE - | HBH_OPTION_TYPE_SKIP_UNKNOWN; - e2e_option->hdr.length = sizeof (ioam_e2e_option_t) - - sizeof (ip6_hop_by_hop_option_t); - return(0); - } - return(-1); -} - -u32 -ioam_e2e_flow_handler (u32 ctx, u8 add) -{ - ioam_e2e_data_t *data; - u16 i; - - if (add) - { - pool_get(ioam_e2e_main.e2e_data, data); - data->flow_ctx = ctx; - ioam_seqno_init_bitmap(&data->seqno_data); - return ((u32) (data - ioam_e2e_main.e2e_data)); - } - - /* Delete case */ - for (i = 0; i < vec_len(ioam_e2e_main.e2e_data); i++) - { - if (pool_is_free_index(ioam_e2e_main.e2e_data, i)) - continue; - - data = pool_elt_at_index(ioam_e2e_main.e2e_data, i); - if (data && (data->flow_ctx == ctx)) - { - pool_put_index(ioam_e2e_main.e2e_data, i); - return (0); - } - } - return 0; -} - -static clib_error_t * -ioam_show_e2e_cmd_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - ioam_e2e_data_t *e2e_data; - u8 *s = 0; - int i; - - vec_reset_length(s); - - s = format(0, "IOAM E2E information: \n"); - for (i = 0; i < vec_len(ioam_e2e_main.e2e_data); i++) - { - if (pool_is_free_index(ioam_e2e_main.e2e_data, i)) - continue; - - e2e_data = pool_elt_at_index(ioam_e2e_main.e2e_data, i); - s = format(s, "Flow name: %s\n", get_flow_name_from_flow_ctx(e2e_data->flow_ctx)); - - s = show_ioam_seqno_cmd_fn(s, - &e2e_data->seqno_data, - !IOAM_DEAP_ENABLED(e2e_data->flow_ctx)); - } - - vlib_cli_output(vm, "%v", s); - return 0; -} - - -VLIB_CLI_COMMAND (ioam_show_e2e_cmd, static) = { - .path = "show ioam e2e ", - .short_help = "show ioam e2e information", - .function = ioam_show_e2e_cmd_fn, -}; - -/* - * 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) -{ - clib_error_t * error = 0; - - ioam_e2e_main.vlib_main = vm; - ioam_e2e_main.vnet_main = h->vnet_main; - return error; -} - -/* - * Init handler E2E headet handling. - * Init hanlder registers encap, decap, trace and Rewrite handlers. - */ -static clib_error_t * -ioam_e2e_init (vlib_main_t * vm) -{ - clib_error_t * error; - - if ((error = vlib_call_init_function (vm, ip6_hop_by_hop_ioam_init))) - { - return(error); - } - - /* - * As of now we have only PPC under E2E header. - */ - if (ip6_hbh_config_handler_register(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE, - ioam_e2e_config_handler) < 0) - { - return (clib_error_create("Registration of " - "HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE for rewrite failed")); - } - - if (ip6_hbh_add_register_option(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE, - sizeof(ioam_e2e_option_t), - ioam_e2e_rewrite_handler) < 0) - { - return (clib_error_create("Registration of " - "HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE for rewrite failed")); - } - - if (ip6_hbh_flow_handler_register(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE, - ioam_e2e_flow_handler) < 0) - { - return (clib_error_create("Registration of " - "HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE Flow handler failed")); - } - - return (0); -} - -/* - * Init function for the E2E lib. - * ip6_hop_by_hop_ioam_e2e_init gets called during init. - */ -VLIB_INIT_FUNCTION (ioam_e2e_init); diff --git a/plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.h b/plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.h deleted file mode 100644 index 18f35f80..00000000 --- a/plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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. - */ - -#ifndef __included_ip6_ioam_e2e_h__ -#define __included_ip6_ioam_e2e_h__ - -#include "ip6_ioam_seqno.h" - -typedef struct ioam_e2e_data_t_ { - u32 flow_ctx; - u32 pad; - ioam_seqno_data seqno_data; -} ioam_e2e_data_t; - -typedef struct { - ioam_e2e_data_t *e2e_data; - vlib_main_t *vlib_main; - vnet_main_t *vnet_main; -} ioam_e2e_main_t; - -extern ioam_e2e_main_t ioam_e2e_main; - -static inline ioam_seqno_data * -ioam_e2ec_get_seqno_data_from_flow_ctx (u32 flow_ctx) -{ - ioam_e2e_data_t *data = NULL; - u32 index; - - index = get_flow_data_from_flow_ctx(flow_ctx, - HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE); - data = &ioam_e2e_main.e2e_data[index]; - return &(data->seqno_data); -} - -#endif /* __included_ioam_e2e_h__ */ diff --git a/plugins/ioam-plugin/ioam/encap/ip6_ioam_pot.c b/plugins/ioam-plugin/ioam/encap/ip6_ioam_pot.c deleted file mode 100644 index 05f42c91..00000000 --- a/plugins/ioam-plugin/ioam/encap/ip6_ioam_pot.c +++ /dev/null @@ -1,276 +0,0 @@ -/* - * 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. - */ -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include - -typedef CLIB_PACKED(struct { - ip6_hop_by_hop_option_t hdr; - u8 pot_type; -#define PROFILE_ID_MASK 0xF - u8 reserved_profile_id; /* 4 bits reserved, 4 bits to carry profile id */ - u64 random; - u64 cumulative; -}) ioam_pot_option_t; - -#define foreach_ip6_hop_by_hop_ioam_pot_stats \ - _(PROCESSED, "Pkts with ip6 hop-by-hop pot options") \ - _(PROFILE_MISS, "Pkts with ip6 hop-by-hop pot options but no profile set") \ - _(PASSED, "Pkts with POT in Policy") \ - _(FAILED, "Pkts with POT out of Policy") - -static char * ip6_hop_by_hop_ioam_pot_stats_strings[] = { -#define _(sym,string) string, - foreach_ip6_hop_by_hop_ioam_pot_stats -#undef _ -}; - -typedef enum { -#define _(sym,str) IP6_IOAM_POT_##sym, - foreach_ip6_hop_by_hop_ioam_pot_stats -#undef _ - IP6_IOAM_POT_N_STATS, -} ip6_ioam_pot_stats_t; - -typedef struct { - /* stats */ - u64 counters[ARRAY_LEN(ip6_hop_by_hop_ioam_pot_stats_strings)]; - - /* convenience */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; -} ip6_hop_by_hop_ioam_pot_main_t; - -ip6_hop_by_hop_ioam_pot_main_t ip6_hop_by_hop_ioam_pot_main; - -always_inline void -ip6_ioam_stats_increment_counter (u32 counter_index, u64 increment) -{ - ip6_hop_by_hop_ioam_pot_main_t *hm = &ip6_hop_by_hop_ioam_pot_main; - - hm->counters[counter_index] += increment; -} - - -static u8 * format_ioam_pot (u8 * s, va_list * args) -{ - ioam_pot_option_t * pot0 = va_arg (*args, ioam_pot_option_t *); - u64 random, cumulative; - random = cumulative = 0; - if (pot0) - { - random = clib_net_to_host_u64 (pot0->random); - cumulative = clib_net_to_host_u64 (pot0->cumulative); - } - - s = format (s, "random = 0x%Lx, Cumulative = 0x%Lx, Index = 0x%x", - random, cumulative, pot0 ? pot0->reserved_profile_id : ~0); - return s; -} - -u8 * -ip6_hbh_ioam_proof_of_transit_trace_handler (u8 *s, ip6_hop_by_hop_option_t *opt) -{ - ioam_pot_option_t *pot; - - s = format (s, " POT opt present\n"); - pot = (ioam_pot_option_t *) opt; - s = format (s, " %U\n", format_ioam_pot, pot); - return (s); -} - -int -ip6_hbh_ioam_proof_of_transit_handler (vlib_buffer_t *b, - ip6_header_t *ip, - ip6_hop_by_hop_option_t *opt0) -{ - ioam_pot_option_t * pot0; - u64 random = 0, cumulative = 0; - int rv = 0; - u8 pot_profile_index; - pot_profile *pot_profile = 0, *new_profile = 0; - u8 pot_encap = 0; - - pot0 = (ioam_pot_option_t *) opt0; - pot_encap = (pot0->random == 0); - pot_profile_index = pot_profile_get_active_id(); - pot_profile = pot_profile_get_active(); - if (pot_encap && PREDICT_FALSE(!pot_profile)) - { - ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PROFILE_MISS, 1); - return(-1); - } - if (pot_encap) - { - pot0->reserved_profile_id = - pot_profile_index & PROFILE_ID_MASK; - pot_profile_incr_usage_stats(pot_profile); - } - else - { /* Non encap node */ - if (PREDICT_FALSE(pot0->reserved_profile_id != - pot_profile_index || pot_profile == 0)) - { - /* New profile announced by encap node. */ - new_profile = - pot_profile_find(pot0->reserved_profile_id); - if (PREDICT_FALSE(new_profile == 0 || - new_profile->valid == 0)) - { - ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PROFILE_MISS, 1); - return(-1); - } - else - { - pot_profile_index = pot0->reserved_profile_id; - pot_profile = new_profile; - pot_profile_set_active(pot_profile_index); - pot_profile_reset_usage_stats(pot_profile); - } - } - pot_profile_incr_usage_stats(pot_profile); - } - - if (pot0->random == 0) - { - pot0->random = clib_host_to_net_u64(pot_generate_random(pot_profile)); - pot0->cumulative = 0; - } - random = clib_net_to_host_u64(pot0->random); - cumulative = clib_net_to_host_u64(pot0->cumulative); - pot0->cumulative = clib_host_to_net_u64( - pot_update_cumulative(pot_profile, - cumulative, - random)); - ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PROCESSED, 1); - - return (rv); -} - -int -ip6_hbh_ioam_proof_of_transit_pop_handler (vlib_buffer_t *b, ip6_header_t *ip, - ip6_hop_by_hop_option_t *opt0) -{ - ioam_pot_option_t * pot0; - u64 random = 0; - u64 cumulative = 0; - int rv = 0; - pot_profile *pot_profile = 0; - u8 result = 0; - - pot0 = (ioam_pot_option_t *) opt0; - random = clib_net_to_host_u64(pot0->random); - cumulative = clib_net_to_host_u64(pot0->cumulative); - pot_profile = pot_profile_get_active(); - result = pot_validate (pot_profile, - cumulative, random); - - if (result == 1) - { - ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PASSED, 1); - } - else - { - ip6_ioam_stats_increment_counter (IP6_IOAM_POT_FAILED, 1); - } - return (rv); -} - -int ip6_hop_by_hop_ioam_pot_rewrite_handler (u8 *rewrite_string, u8 *rewrite_size) -{ - ioam_pot_option_t * pot_option; - if (rewrite_string && *rewrite_size == sizeof(ioam_pot_option_t)) - { - pot_option = (ioam_pot_option_t *)rewrite_string; - pot_option->hdr.type = HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT - | HBH_OPTION_TYPE_DATA_CHANGE_ENROUTE; - pot_option->hdr.length = sizeof (ioam_pot_option_t) - - sizeof (ip6_hop_by_hop_option_t); - return(0); - } - return(-1); -} - -static clib_error_t * -ip6_show_ioam_pot_cmd_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - ip6_hop_by_hop_ioam_pot_main_t *hm = &ip6_hop_by_hop_ioam_pot_main; - u8 *s = 0; - int i = 0; - - for ( i = 0; i < IP6_IOAM_POT_N_STATS; i++) - { - s = format(s, " %s - %lu\n", ip6_hop_by_hop_ioam_pot_stats_strings[i], - hm->counters[i]); - } - - vlib_cli_output(vm, "%v", s); - vec_free(s); - return 0; -} - - -VLIB_CLI_COMMAND (ip6_show_ioam_pot_cmd, static) = { - .path = "show ioam pot", - .short_help = "iOAM pot statistics", - .function = ip6_show_ioam_pot_cmd_fn, -}; - - -static clib_error_t * -ip6_hop_by_hop_ioam_pot_init (vlib_main_t * vm) -{ - ip6_hop_by_hop_ioam_pot_main_t * hm = &ip6_hop_by_hop_ioam_pot_main; - clib_error_t * error; - - if ((error = vlib_call_init_function (vm, ip6_hop_by_hop_ioam_init))) - return(error); - - hm->vlib_main = vm; - hm->vnet_main = vnet_get_main(); - memset(hm->counters, 0, sizeof(hm->counters)); - - if (ip6_hbh_register_option(HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT, ip6_hbh_ioam_proof_of_transit_handler, - ip6_hbh_ioam_proof_of_transit_trace_handler) < 0) - return (clib_error_create("registration of HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT failed")); - - if (ip6_hbh_add_register_option(HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT, - sizeof(ioam_pot_option_t), - ip6_hop_by_hop_ioam_pot_rewrite_handler) < 0) - return (clib_error_create("registration of HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT for rewrite failed")); - - if (ip6_hbh_pop_register_option(HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT, - ip6_hbh_ioam_proof_of_transit_pop_handler) < 0) - return (clib_error_create("registration of HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT POP failed")); - - return (0); -} - -VLIB_INIT_FUNCTION (ip6_hop_by_hop_ioam_pot_init); - - diff --git a/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.c b/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.c deleted file mode 100644 index 0b4d4192..00000000 --- a/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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. - */ - - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "ip6_ioam_seqno.h" -#include "ip6_ioam_e2e.h" - -ioam_seqno_data_main_t ioam_seqno_main; - -void ioam_seqno_init_bitmap (ioam_seqno_data *data) -{ - seqno_bitmap *bitmap = &data->seqno_rx.bitmap; - bitmap->window_size = SEQNO_WINDOW_SIZE; - bitmap->array_size = SEQNO_WINDOW_ARRAY_SIZE; - bitmap->mask = 32 * SEQNO_WINDOW_ARRAY_SIZE - 1; - bitmap->array[0] = 0x00000000;/* pretend we haven seen sequence numbers 0*/ - bitmap->highest = 0; - - data->seq_num = 0; - return ; -} - -/* - * This Routine gets called from IPv6 hop-by-hop option handling. - * Only if we are encap node, then add PPC data. - * On a Transit(MID) node we dont do anything with E2E headers. - * On decap node decap is handled by seperate function. - */ -int -ioam_seqno_encap_handler (vlib_buffer_t *b, ip6_header_t *ip, - ip6_hop_by_hop_option_t *opt) -{ - u32 opaque_index = vnet_buffer(b)->l2_classify.opaque_index; - ioam_e2e_option_t * e2e; - int rv = 0; - ioam_seqno_data *data; - - data = ioam_e2ec_get_seqno_data_from_flow_ctx(opaque_index); - e2e = (ioam_e2e_option_t *) opt; - e2e->e2e_data = clib_host_to_net_u32(++data->seq_num); - - return (rv); -} - -/* - * This Routine gets called on POP/Decap node. - */ -int -ioam_seqno_decap_handler (vlib_buffer_t *b, ip6_header_t *ip, - ip6_hop_by_hop_option_t *opt) -{ - u32 opaque_index = vnet_buffer(b)->l2_classify.opaque_index; - ioam_e2e_option_t * e2e; - int rv = 0; - ioam_seqno_data *data; - - data = ioam_e2ec_get_seqno_data_from_flow_ctx(opaque_index); - e2e = (ioam_e2e_option_t *) opt; - ioam_analyze_seqno(&data->seqno_rx, (u64) clib_net_to_host_u32(e2e->e2e_data)); - - return (rv); -} - -u8 * -show_ioam_seqno_cmd_fn (u8 *s, ioam_seqno_data *seqno_data, u8 enc) -{ - seqno_rx_info *rx; - - s = format(s, "SeqNo Data:\n"); - if (enc) - { - s = format(s, " Current Seq. Number : %llu\n", seqno_data->seq_num); - } - else - { - rx = &seqno_data->seqno_rx; - s = format(s, " Highest Seq. Number : %llu\n", rx->bitmap.highest); - s = format(s, " Packets received : %llu\n", rx->rx_packets); - s = format(s, " Lost packets : %llu\n", rx->lost_packets); - s = format(s, " Reordered packets : %llu\n", rx->reordered_packets); - s = format(s, " Duplicate packets : %llu\n", rx->dup_packets); - } - - format(s, "\n"); - return s; -} diff --git a/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.h b/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.h deleted file mode 100644 index 13a84db0..00000000 --- a/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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. - */ - -#ifndef __included_ip6_ioam_seqno_h__ -#define __included_ip6_ioam_seqno_h__ - -#include -#include - -#define SEQ_CHECK_VALUE 0x80000000 /* for seq number wraparound detection */ - -#define SEQNO_WINDOW_SIZE 2048 -#define SEQNO_WINDOW_ARRAY_SIZE 64 - -typedef struct seqno_bitmap_ { - u32 window_size; - u32 array_size; - u32 mask; - u32 pad; - u64 highest; - u64 array[SEQNO_WINDOW_ARRAY_SIZE]; /* Will be alloc to array_size */ -} seqno_bitmap; - -typedef struct seqno_rx_info_ { - u64 rx_packets; - u64 lost_packets; - u64 reordered_packets; - u64 dup_packets; - seqno_bitmap bitmap; -} seqno_rx_info; - -/* This structure is 64-byte aligned */ -typedef struct ioam_seqno_data_ { - union { - u32 seq_num; /* Useful only for encap node */ - seqno_rx_info seqno_rx; - }; -} ioam_seqno_data; - -typedef struct ioam_seqno_data_main_t_ { - ioam_seqno_data *seqno_data; -} ioam_seqno_data_main_t; - -void ioam_seqno_init_bitmap(ioam_seqno_data *data); - -int ioam_seqno_encap_handler(vlib_buffer_t *b, ip6_header_t *ip, - ip6_hop_by_hop_option_t *opt); - -int -ioam_seqno_decap_handler(vlib_buffer_t *b, ip6_header_t *ip, - ip6_hop_by_hop_option_t *opt); - -void ioam_analyze_seqno(seqno_rx_info *ppc_rx, u64 seqno); - -u8 * -show_ioam_seqno_cmd_fn(u8 *s, ioam_seqno_data *seqno_data, u8 enc); - -#endif diff --git a/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno_analyse.c b/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno_analyse.c deleted file mode 100644 index 4638871c..00000000 --- a/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno_analyse.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * 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. - */ - -#include -#include "ip6_ioam_seqno.h" - -static inline void BIT_SET (u64 *p, u32 n) -{ - p[ n>>5 ] |= (1 << (n&31)); -} - -static inline int BIT_TEST (u64 *p, u32 n) -{ - return p[ n>>5 ] & (1 << (n&31)); -} - -static void BIT_CLEAR (u64 *p, u64 start, int num_bits, u32 mask) -{ - int n, t; - int start_index = (start >> 5); - int mask_index = (mask >> 5); - - start_index &= mask_index; - if (start & 0x1f) - { - int start_bit = (start & 0x1f); - - n = (1 << start_bit)-1; - t = start_bit + num_bits; - if (t < 32) - { - n |= ~((1 << t)-1); - p[ start_index ] &= n; - return; - } - p[ start_index ] &= n; - start_index = (start_index + 1) & mask_index; - num_bits -= (32 - start_bit); - } - while (num_bits >= 32) - { - p[ start_index ] = 0; - start_index = (start_index + 1) & mask_index; - num_bits -= 32; - } - n = ~((1 << num_bits) - 1); - p[ start_index ] &= n; -} - -static inline u8 seqno_check_wraparound(u32 a, u32 b) -{ - if ((a != b) && (a > b) && ((a - b) > SEQ_CHECK_VALUE)) - { - return 1; - } - return 0; -} - -/* - * Function to analyze the PPC value recevied. - * - Updates the bitmap with received sequence number - * - counts the received/lost/duplicate/reordered packets - */ -void ioam_analyze_seqno (seqno_rx_info *seqno_rx, u64 seqno) -{ - int diff; - static int peer_dead_count; - seqno_bitmap *bitmap = &seqno_rx->bitmap; - - seqno_rx->rx_packets++; - - if (seqno > bitmap->highest) - { /* new larger sequence number */ - peer_dead_count = 0; - diff = seqno - bitmap->highest; - if (diff < bitmap->window_size) - { - if (diff > 1) - { /* diff==1 is *such* a common case it's a win to optimize it */ - BIT_CLEAR(bitmap->array, bitmap->highest+1, diff-1, bitmap->mask); - seqno_rx->lost_packets += diff -1; - } - } - else - { - seqno_rx->lost_packets += diff -1; - memset( bitmap->array, 0, bitmap->array_size * sizeof(u64) ); - } - BIT_SET(bitmap->array, seqno & bitmap->mask); - bitmap->highest = seqno; - return; - } - - /* we've seen a bigger seq number before */ - diff = bitmap->highest - seqno; - if (diff >= bitmap->window_size) - { - if (seqno_check_wraparound(bitmap->highest, seqno)) - { - memset( bitmap->array, 0, bitmap->array_size * sizeof(u64)); - BIT_SET(bitmap->array, seqno & bitmap->mask); - bitmap->highest = seqno; - return; - } - else - { - peer_dead_count++; - if (peer_dead_count > 25) - { - peer_dead_count = 0; - memset( bitmap->array, 0, bitmap->array_size * sizeof(u64) ); - BIT_SET(bitmap->array, seqno & bitmap->mask); - bitmap->highest = seqno; - } - //ppc_rx->reordered_packets++; - } - return; - } - - if (BIT_TEST(bitmap->array, seqno & bitmap->mask)) - { - seqno_rx->dup_packets++; - return; /* Already seen */ - } - seqno_rx->reordered_packets++; - seqno_rx->lost_packets--; - BIT_SET(bitmap->array, seqno & bitmap->mask); - return; -} diff --git a/plugins/ioam-plugin/ioam/encap/ip6_ioam_trace.c b/plugins/ioam-plugin/ioam/encap/ip6_ioam_trace.c deleted file mode 100644 index e63db6e4..00000000 --- a/plugins/ioam-plugin/ioam/encap/ip6_ioam_trace.c +++ /dev/null @@ -1,438 +0,0 @@ -/* - * 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. - */ -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include - -/* Timestamp precision multipliers for seconds, milliseconds, microseconds - * and nanoseconds respectively. - */ -static f64 trace_tsp_mul[4] = { 1, 1e3, 1e6, 1e9 }; - -typedef union -{ - u64 as_u64; - u32 as_u32[2]; -} time_u64_t; - -/* *INDENT-OFF* */ -typedef CLIB_PACKED(struct { - ip6_hop_by_hop_option_t hdr; - u8 ioam_trace_type; - u8 data_list_elts_left; - u32 elts[0]; /* Variable type. So keep it generic */ -}) ioam_trace_option_t; -/* *INDENT-ON* */ - - -extern ip6_hop_by_hop_ioam_main_t ip6_hop_by_hop_ioam_main; -extern ip6_main_t ip6_main; - -#define foreach_ip6_hop_by_hop_ioam_trace_stats \ - _(PROCESSED, "Pkts with ip6 hop-by-hop trace options") \ - _(PROFILE_MISS, "Pkts with ip6 hop-by-hop trace options but no profile set") \ - _(UPDATED, "Pkts with trace updated") \ - _(FULL, "Pkts with trace options but no space") - -static char *ip6_hop_by_hop_ioam_trace_stats_strings[] = { -#define _(sym,string) string, - foreach_ip6_hop_by_hop_ioam_trace_stats -#undef _ -}; - -typedef enum -{ -#define _(sym,str) IP6_IOAM_TRACE_##sym, - foreach_ip6_hop_by_hop_ioam_trace_stats -#undef _ - IP6_IOAM_TRACE_N_STATS, -} ip6_ioam_trace_stats_t; - - -typedef struct -{ - /* stats */ - u64 counters[ARRAY_LEN (ip6_hop_by_hop_ioam_trace_stats_strings)]; - - /* convenience */ - vlib_main_t *vlib_main; - vnet_main_t *vnet_main; -} ip6_hop_by_hop_ioam_trace_main_t; - -ip6_hop_by_hop_ioam_trace_main_t ip6_hop_by_hop_ioam_trace_main; - -always_inline void -ip6_ioam_trace_stats_increment_counter (u32 counter_index, u64 increment) -{ - ip6_hop_by_hop_ioam_trace_main_t *hm = &ip6_hop_by_hop_ioam_trace_main; - - hm->counters[counter_index] += increment; -} - - -static u8 * -format_ioam_data_list_element (u8 * s, va_list * args) -{ - u32 *elt = va_arg (*args, u32 *); - u8 *trace_type_p = va_arg (*args, u8 *); - u8 trace_type = *trace_type_p; - - - if (trace_type & BIT_TTL_NODEID) - { - u32 ttl_node_id_host_byte_order = clib_net_to_host_u32 (*elt); - s = format (s, "ttl 0x%x node id 0x%x ", - ttl_node_id_host_byte_order >> 24, - ttl_node_id_host_byte_order & 0x00FFFFFF); - - elt++; - } - - if (trace_type & BIT_ING_INTERFACE && trace_type & BIT_ING_INTERFACE) - { - u32 ingress_host_byte_order = clib_net_to_host_u32 (*elt); - s = format (s, "ingress 0x%x egress 0x%x ", - ingress_host_byte_order >> 16, - ingress_host_byte_order & 0xFFFF); - elt++; - } - - if (trace_type & BIT_TIMESTAMP) - { - u32 ts_in_host_byte_order = clib_net_to_host_u32 (*elt); - s = format (s, "ts 0x%x \n", ts_in_host_byte_order); - elt++; - } - - if (trace_type & BIT_APPDATA) - { - u32 appdata_in_host_byte_order = clib_net_to_host_u32 (*elt); - s = format (s, "app 0x%x ", appdata_in_host_byte_order); - elt++; - } - - return s; -} - - -int -ip6_ioam_trace_get_sizeof_handler (u32 * result) -{ - u16 size = 0; - u8 trace_data_size = 0; - trace_profile *profile = NULL; - - *result = 0; - - profile = trace_profile_find (); - - if (PREDICT_FALSE (!profile)) - { - ip6_ioam_trace_stats_increment_counter (IP6_IOAM_TRACE_PROFILE_MISS, 1); - return (-1); - } - - trace_data_size = fetch_trace_data_size (profile->trace_type); - if (PREDICT_FALSE (trace_data_size == 0)) - return VNET_API_ERROR_INVALID_VALUE; - - if (PREDICT_FALSE (profile->num_elts * trace_data_size > 254)) - return VNET_API_ERROR_INVALID_VALUE; - - size += - sizeof (ioam_trace_option_t) + (profile->num_elts * trace_data_size); - *result = size; - - return 0; -} - - - -int -ip6_hop_by_hop_ioam_trace_rewrite_handler (u8 * rewrite_string, - u8 * rewrite_size) -{ - ioam_trace_option_t *trace_option = NULL; - u8 trace_data_size = 0; - u8 trace_option_elts = 0; - trace_profile *profile = NULL; - - - profile = trace_profile_find (); - - if (PREDICT_FALSE (!profile)) - { - ip6_ioam_trace_stats_increment_counter (IP6_IOAM_TRACE_PROFILE_MISS, 1); - return (-1); - } - - if (PREDICT_FALSE (!rewrite_string)) - return -1; - - trace_option_elts = profile->num_elts; - trace_data_size = fetch_trace_data_size (profile->trace_type); - trace_option = (ioam_trace_option_t *) rewrite_string; - trace_option->hdr.type = HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST | - HBH_OPTION_TYPE_DATA_CHANGE_ENROUTE; - trace_option->hdr.length = 2 /*ioam_trace_type,data_list_elts_left */ + - trace_option_elts * trace_data_size; - trace_option->ioam_trace_type = profile->trace_type & TRACE_TYPE_MASK; - trace_option->data_list_elts_left = trace_option_elts; - *rewrite_size = - sizeof (ioam_trace_option_t) + (trace_option_elts * trace_data_size); - - return 0; -} - - -int -ip6_hbh_ioam_trace_data_list_handler (vlib_buffer_t * b, ip6_header_t * ip, - ip6_hop_by_hop_option_t * opt) -{ - ip6_main_t *im = &ip6_main; - ip_lookup_main_t *lm = &im->lookup_main; - ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; - u8 elt_index = 0; - ioam_trace_option_t *trace = (ioam_trace_option_t *) opt; - u32 adj_index = vnet_buffer (b)->ip.adj_index[VLIB_TX]; - ip_adjacency_t *adj = ip_get_adjacency (lm, adj_index); - time_u64_t time_u64; - u32 *elt; - int rv = 0; - trace_profile *profile = NULL; - - - profile = trace_profile_find (); - - if (PREDICT_FALSE (!profile)) - { - ip6_ioam_trace_stats_increment_counter (IP6_IOAM_TRACE_PROFILE_MISS, 1); - return (-1); - } - - - time_u64.as_u64 = 0; - - if (PREDICT_TRUE (trace->data_list_elts_left)) - { - trace->data_list_elts_left--; - /* fetch_trace_data_size returns in bytes. Convert it to 4-bytes - * to skip to this node's location. - */ - elt_index = - trace->data_list_elts_left * - fetch_trace_data_size (trace->ioam_trace_type) / 4; - elt = &trace->elts[elt_index]; - if (trace->ioam_trace_type & BIT_TTL_NODEID) - { - *elt = - clib_host_to_net_u32 ((ip->hop_limit << 24) | profile->node_id); - elt++; - } - - if (trace->ioam_trace_type & BIT_ING_INTERFACE) - { - *elt = - (vnet_buffer (b)->sw_if_index[VLIB_RX] & 0xFFFF) << 16 | - (adj->rewrite_header.sw_if_index & 0xFFFF); - *elt = clib_host_to_net_u32 (*elt); - elt++; - } - - if (trace->ioam_trace_type & BIT_TIMESTAMP) - { - /* Send least significant 32 bits */ - f64 time_f64 = - (f64) (((f64) hm->unix_time_0) + - (vlib_time_now (hm->vlib_main) - hm->vlib_time_0)); - - time_u64.as_u64 = time_f64 * trace_tsp_mul[profile->trace_tsp]; - *elt = clib_host_to_net_u32 (time_u64.as_u32[0]); - elt++; - } - - if (trace->ioam_trace_type & BIT_APPDATA) - { - /* $$$ set elt0->app_data */ - *elt = clib_host_to_net_u32 (profile->app_data); - elt++; - } - ip6_ioam_trace_stats_increment_counter (IP6_IOAM_TRACE_UPDATED, 1); - } - else - { - ip6_ioam_trace_stats_increment_counter (IP6_IOAM_TRACE_FULL, 1); - } - return (rv); -} - -u8 * -ip6_hbh_ioam_trace_data_list_trace_handler (u8 * s, - ip6_hop_by_hop_option_t * opt) -{ - ioam_trace_option_t *trace; - u8 trace_data_size_in_words = 0; - u32 *elt; - int elt_index = 0; - - trace = (ioam_trace_option_t *) opt; - s = - format (s, " Trace Type 0x%x , %d elts left\n", trace->ioam_trace_type, - trace->data_list_elts_left); - trace_data_size_in_words = - fetch_trace_data_size (trace->ioam_trace_type) / 4; - elt = &trace->elts[0]; - while ((u8 *) elt < ((u8 *) (&trace->elts[0]) + trace->hdr.length - 2 - /* -2 accounts for ioam_trace_type,elts_left */ )) - { - s = format (s, " [%d] %U\n", elt_index, - format_ioam_data_list_element, - elt, &trace->ioam_trace_type); - elt_index++; - elt += trace_data_size_in_words; - } - return (s); -} - - -static clib_error_t * -ip6_show_ioam_trace_cmd_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - ip6_hop_by_hop_ioam_trace_main_t *hm = &ip6_hop_by_hop_ioam_trace_main; - u8 *s = 0; - int i = 0; - - for (i = 0; i < IP6_IOAM_TRACE_N_STATS; i++) - { - s = - format (s, " %s - %lu\n", ip6_hop_by_hop_ioam_trace_stats_strings[i], - hm->counters[i]); - } - - vlib_cli_output (vm, "%v", s); - vec_free (s); - return 0; -} - - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (ip6_show_ioam_trace_cmd, static) = { - .path = "show ioam trace", - .short_help = "iOAM trace statistics", - .function = ip6_show_ioam_trace_cmd_fn, -}; -/* *INDENT-ON* */ - - -static clib_error_t * -ip6_hop_by_hop_ioam_trace_init (vlib_main_t * vm) -{ - ip6_hop_by_hop_ioam_trace_main_t *hm = &ip6_hop_by_hop_ioam_trace_main; - clib_error_t *error; - - if ((error = vlib_call_init_function (vm, ip_main_init))) - return (error); - - if ((error = vlib_call_init_function (vm, ip6_lookup_init))) - return error; - - if ((error = vlib_call_init_function (vm, ip6_hop_by_hop_ioam_init))) - return (error); - - hm->vlib_main = vm; - hm->vnet_main = vnet_get_main (); - memset (hm->counters, 0, sizeof (hm->counters)); - - - if (ip6_hbh_register_option - (HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST, - ip6_hbh_ioam_trace_data_list_handler, - ip6_hbh_ioam_trace_data_list_trace_handler) < 0) - return (clib_error_create - ("registration of HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST failed")); - - - if (ip6_hbh_add_register_option (HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST, - sizeof (ioam_trace_option_t), - ip6_hop_by_hop_ioam_trace_rewrite_handler) - < 0) - return (clib_error_create - ("registration of HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST for rewrite failed")); - - - return (0); -} - -int -ip6_trace_profile_cleanup (void) -{ - ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; - - hm->options_size[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST] = 0; - - return 0; - -} - - -int -ip6_trace_profile_setup (void) -{ - u32 trace_size = 0; - ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; - - trace_profile *profile = NULL; - - - profile = trace_profile_find (); - - if (PREDICT_FALSE (!profile)) - { - ip6_ioam_trace_stats_increment_counter (IP6_IOAM_TRACE_PROFILE_MISS, 1); - return (-1); - } - - - if (ip6_ioam_trace_get_sizeof_handler (&trace_size) < 0) - return (-1); - - hm->options_size[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST] = trace_size; - - return (0); -} - - -VLIB_INIT_FUNCTION (ip6_hop_by_hop_ioam_trace_init); - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/ioam-plugin/ioam/export-common/ioam_export.h b/plugins/ioam-plugin/ioam/export-common/ioam_export.h deleted file mode 100644 index a9ec8d00..00000000 --- a/plugins/ioam-plugin/ioam/export-common/ioam_export.h +++ /dev/null @@ -1,616 +0,0 @@ -/* - * 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. - */ -#ifndef __included_ioam_export_h__ -#define __included_ioam_export_h__ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -typedef struct ioam_export_buffer -{ - /* Allocated buffer */ - u32 buffer_index; - u64 touched_at; - u8 records_in_this_buffer; -} ioam_export_buffer_t; - - -typedef struct -{ - /* API message ID base */ - u16 msg_id_base; - - /* TODO: to support multiple collectors all this has to be grouped and create a vector here */ - u8 *record_header; - u32 sequence_number; - u32 domain_id; - - /* ipfix collector, our ip address */ - ip4_address_t ipfix_collector; - ip4_address_t src_address; - - /* Pool of ioam_export_buffer_t */ - ioam_export_buffer_t *buffer_pool; - /* Vector of per thread ioam_export_buffer_t to buffer pool index */ - u32 *buffer_per_thread; - /* Lock per thread to swap buffers between worker and timer process */ - volatile u32 **lockp; - - /* time scale transform */ - u32 unix_time_0; - f64 vlib_time_0; - - /* convenience */ - vlib_main_t *vlib_main; - vnet_main_t *vnet_main; - u32 ip4_lookup_node_index; - - uword my_hbh_slot; - u32 export_process_node_index; -} ioam_export_main_t; - -ioam_export_main_t ioam_export_main; -ioam_export_main_t vxlan_gpe_ioam_export_main; - -vlib_node_registration_t export_node; - -#define DEFAULT_EXPORT_SIZE (3 * CLIB_CACHE_LINE_BYTES) -/* - * Number of records in a buffer - * ~(MTU (1500) - [ip hdr(40) + UDP(8) + ipfix (24)]) / DEFAULT_EXPORT_SIZE - */ -#define DEFAULT_EXPORT_RECORDS 7 - -always_inline ioam_export_buffer_t * -ioam_export_get_my_buffer (ioam_export_main_t * em, u32 thread_id) -{ - - if (vec_len (em->buffer_per_thread) > thread_id) - return (pool_elt_at_index - (em->buffer_pool, em->buffer_per_thread[thread_id])); - return (0); -} - -inline static int -ioam_export_buffer_add_header (ioam_export_main_t * em, vlib_buffer_t * b0) -{ - clib_memcpy (b0->data, em->record_header, vec_len (em->record_header)); - b0->current_data = 0; - b0->current_length = vec_len (em->record_header); - b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID; - return (1); -} - -inline static int -ioam_export_init_buffer (ioam_export_main_t * em, vlib_main_t * vm, - ioam_export_buffer_t * eb) -{ - vlib_buffer_t *b = 0; - - if (!eb) - return (-1); - /* TODO: Perhaps buffer init from template here */ - if (vlib_buffer_alloc (vm, &(eb->buffer_index), 1) != 1) - return (-2); - eb->records_in_this_buffer = 0; - eb->touched_at = vlib_time_now (vm); - b = vlib_get_buffer (vm, eb->buffer_index); - (void) ioam_export_buffer_add_header (em, b); - vnet_buffer (b)->sw_if_index[VLIB_RX] = 0; - vnet_buffer (b)->sw_if_index[VLIB_TX] = ~0; - return (1); -} - -inline static void -ioam_export_thread_buffer_free (ioam_export_main_t * em) -{ - vlib_main_t *vm = em->vlib_main; - ioam_export_buffer_t *eb = 0; - int i; - for (i = 0; i < vec_len (em->buffer_per_thread); i++) - { - eb = pool_elt_at_index (em->buffer_pool, em->buffer_per_thread[i]); - if (eb) - vlib_buffer_free (vm, &(eb->buffer_index), 1); - } - for (i = 0; i < vec_len (em->lockp); i++) - clib_mem_free ((void *) em->lockp[i]); - vec_free (em->buffer_per_thread); - pool_free (em->buffer_pool); - vec_free (em->lockp); - em->buffer_per_thread = 0; - em->buffer_pool = 0; - em->lockp = 0; -} - -inline static int -ioam_export_thread_buffer_init (ioam_export_main_t * em, vlib_main_t * vm) -{ - int no_of_threads = vec_len (vlib_worker_threads); - int i; - ioam_export_buffer_t *eb = 0; - vlib_node_t *ip4_lookup_node; - - pool_alloc_aligned (em->buffer_pool, - no_of_threads - 1, CLIB_CACHE_LINE_BYTES); - vec_validate_aligned (em->buffer_per_thread, - no_of_threads - 1, CLIB_CACHE_LINE_BYTES); - vec_validate_aligned (em->lockp, no_of_threads - 1, CLIB_CACHE_LINE_BYTES); - ip4_lookup_node = vlib_get_node_by_name (vm, (u8 *) "ip4-lookup"); - em->ip4_lookup_node_index = ip4_lookup_node->index; - if (!em->buffer_per_thread || !em->buffer_pool || !em->lockp) - { - return (-1); - } - for (i = 0; i < no_of_threads; i++) - { - eb = 0; - pool_get_aligned (em->buffer_pool, eb, CLIB_CACHE_LINE_BYTES); - memset (eb, 0, sizeof (*eb)); - em->buffer_per_thread[i] = eb - em->buffer_pool; - if (ioam_export_init_buffer (em, vm, eb) != 1) - { - ioam_export_thread_buffer_free (em); - return (-2); - } - em->lockp[i] = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, - CLIB_CACHE_LINE_BYTES); - memset ((void *) em->lockp[i], 0, CLIB_CACHE_LINE_BYTES); - } - return (1); -} - -#define IPFIX_IOAM_EXPORT_ID 272 - -/* Used to build the rewrite */ -/* data set packet */ -typedef struct -{ - ipfix_message_header_t h; - ipfix_set_header_t s; -} ipfix_data_packet_t; - -typedef struct -{ - ip4_header_t ip4; - udp_header_t udp; - ipfix_data_packet_t ipfix; -} ip4_ipfix_data_packet_t; - - -inline static void -ioam_export_header_cleanup (ioam_export_main_t * em, - ip4_address_t * collector_address, - ip4_address_t * src_address) -{ - vec_free (em->record_header); - em->record_header = 0; -} - -inline static int -ioam_export_header_create (ioam_export_main_t * em, - ip4_address_t * collector_address, - ip4_address_t * src_address) -{ - ip4_header_t *ip; - udp_header_t *udp; - ipfix_message_header_t *h; - ipfix_set_header_t *s; - u8 *rewrite = 0; - ip4_ipfix_data_packet_t *tp; - - - /* allocate rewrite space */ - vec_validate_aligned (rewrite, - sizeof (ip4_ipfix_data_packet_t) - 1, - CLIB_CACHE_LINE_BYTES); - - tp = (ip4_ipfix_data_packet_t *) rewrite; - ip = (ip4_header_t *) & tp->ip4; - udp = (udp_header_t *) (ip + 1); - h = (ipfix_message_header_t *) (udp + 1); - s = (ipfix_set_header_t *) (h + 1); - - ip->ip_version_and_header_length = 0x45; - ip->ttl = 254; - ip->protocol = IP_PROTOCOL_UDP; - ip->src_address.as_u32 = src_address->as_u32; - ip->dst_address.as_u32 = collector_address->as_u32; - udp->src_port = clib_host_to_net_u16 (4939 /* $$FIXME */ ); - udp->dst_port = clib_host_to_net_u16 (4939); - /* FIXUP: UDP length */ - udp->length = clib_host_to_net_u16 (vec_len (rewrite) + - (DEFAULT_EXPORT_RECORDS * - DEFAULT_EXPORT_SIZE) - sizeof (*ip)); - - /* FIXUP: message header export_time */ - /* FIXUP: message header sequence_number */ - h->domain_id = clib_host_to_net_u32 (em->domain_id); - - /*FIXUP: Setid length in octets if records exported are not default */ - s->set_id_length = ipfix_set_id_length (IPFIX_IOAM_EXPORT_ID, - (sizeof (*s) + - (DEFAULT_EXPORT_RECORDS * - DEFAULT_EXPORT_SIZE))); - - /* FIXUP: h version and length length in octets if records exported are not default */ - h->version_length = version_length (sizeof (*h) + - (sizeof (*s) + - (DEFAULT_EXPORT_RECORDS * - DEFAULT_EXPORT_SIZE))); - - /* FIXUP: ip length if records exported are not default */ - /* FIXUP: ip checksum if records exported are not default */ - ip->length = clib_host_to_net_u16 (vec_len (rewrite) + - (DEFAULT_EXPORT_RECORDS * - DEFAULT_EXPORT_SIZE)); - ip->checksum = ip4_header_checksum (ip); - _vec_len (rewrite) = sizeof (ip4_ipfix_data_packet_t); - em->record_header = rewrite; - return (1); -} - -inline static int -ioam_export_send_buffer (ioam_export_main_t * em, vlib_main_t * vm, - ioam_export_buffer_t * eb) -{ - ip4_header_t *ip; - udp_header_t *udp; - ipfix_message_header_t *h; - ipfix_set_header_t *s; - ip4_ipfix_data_packet_t *tp; - vlib_buffer_t *b0; - u16 new_l0, old_l0; - ip_csum_t sum0; - vlib_frame_t *nf = 0; - u32 *to_next; - - b0 = vlib_get_buffer (vm, eb->buffer_index); - tp = vlib_buffer_get_current (b0); - ip = (ip4_header_t *) & tp->ip4; - udp = (udp_header_t *) (ip + 1); - h = (ipfix_message_header_t *) (udp + 1); - s = (ipfix_set_header_t *) (h + 1); - - /* FIXUP: message header export_time */ - h->export_time = clib_host_to_net_u32 ((u32) - (((f64) em->unix_time_0) + - (vlib_time_now (em->vlib_main) - - em->vlib_time_0))); - - /* FIXUP: message header sequence_number */ - h->sequence_number = clib_host_to_net_u32 (em->sequence_number++); - - /* FIXUP: lengths if different from default */ - if (PREDICT_FALSE (eb->records_in_this_buffer != DEFAULT_EXPORT_RECORDS)) - { - s->set_id_length = - ipfix_set_id_length (IPFIX_IOAM_EXPORT_ID /* set_id */ , - b0->current_length - (sizeof (*ip) + - sizeof (*udp) + - sizeof (*h))); - h->version_length = - version_length (b0->current_length - (sizeof (*ip) + sizeof (*udp))); - sum0 = ip->checksum; - old_l0 = ip->length; - new_l0 = clib_host_to_net_u16 ((u16) b0->current_length); - sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t, - length /* changed member */ ); - ip->checksum = ip_csum_fold (sum0); - ip->length = new_l0; - udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip)); - } - - /* Enqueue pkts to ip4-lookup */ - - nf = vlib_get_frame_to_node (vm, em->ip4_lookup_node_index); - nf->n_vectors = 0; - to_next = vlib_frame_vector_args (nf); - nf->n_vectors = 1; - to_next[0] = eb->buffer_index; - vlib_put_frame_to_node (vm, em->ip4_lookup_node_index, nf); - return (1); - -} - -#define EXPORT_TIMEOUT (20.0) -#define THREAD_PERIOD (30.0) -inline static uword -ioam_export_process_common (ioam_export_main_t * em, vlib_main_t * vm, - vlib_node_runtime_t * rt, vlib_frame_t * f, - u32 index) -{ - f64 now; - f64 timeout = 30.0; - uword event_type; - uword *event_data = 0; - int i; - ioam_export_buffer_t *eb = 0, *new_eb = 0; - u32 *vec_buffer_indices = 0; - u32 *vec_buffer_to_be_sent = 0; - u32 *thread_index = 0; - u32 new_pool_index = 0; - - em->export_process_node_index = index; - /* Wait for Godot... */ - vlib_process_wait_for_event_or_clock (vm, 1e9); - event_type = vlib_process_get_events (vm, &event_data); - if (event_type != 1) - clib_warning ("bogus kickoff event received, %d", event_type); - vec_reset_length (event_data); - - while (1) - { - vlib_process_wait_for_event_or_clock (vm, timeout); - event_type = vlib_process_get_events (vm, &event_data); - switch (event_type) - { - case 2: /* Stop and Wait for kickoff again */ - timeout = 1e9; - break; - case 1: /* kickoff : Check for unsent buffers */ - timeout = THREAD_PERIOD; - break; - case ~0: /* timeout */ - break; - } - vec_reset_length (event_data); - now = vlib_time_now (vm); - /* - * Create buffers for threads that are not active enough - * to send out the export records - */ - for (i = 0; i < vec_len (em->buffer_per_thread); i++) - { - /* If the worker thread is processing export records ignore further checks */ - if (*em->lockp[i] == 1) - continue; - eb = pool_elt_at_index (em->buffer_pool, em->buffer_per_thread[i]); - if (eb->records_in_this_buffer > 0 - && now > (eb->touched_at + EXPORT_TIMEOUT)) - { - pool_get_aligned (em->buffer_pool, new_eb, - CLIB_CACHE_LINE_BYTES); - memset (new_eb, 0, sizeof (*new_eb)); - if (ioam_export_init_buffer (em, vm, new_eb) == 1) - { - new_pool_index = new_eb - em->buffer_pool; - vec_add (vec_buffer_indices, &new_pool_index, 1); - vec_add (vec_buffer_to_be_sent, &em->buffer_per_thread[i], - 1); - vec_add (thread_index, &i, 1); - } - else - { - pool_put (em->buffer_pool, new_eb); - /*Give up */ - goto CLEANUP; - } - } - } - if (vec_len (thread_index) != 0) - { - /* - * Now swap the buffers out - */ - for (i = 0; i < vec_len (thread_index); i++) - { - while (__sync_lock_test_and_set (em->lockp[thread_index[i]], 1)) - ; - em->buffer_per_thread[thread_index[i]] = - vec_pop (vec_buffer_indices); - *em->lockp[thread_index[i]] = 0; - } - - /* Send the buffers */ - for (i = 0; i < vec_len (vec_buffer_to_be_sent); i++) - { - eb = - pool_elt_at_index (em->buffer_pool, vec_buffer_to_be_sent[i]); - ioam_export_send_buffer (em, vm, eb); - pool_put (em->buffer_pool, eb); - } - } - - CLEANUP: - /* Free any leftover/unused buffers and everything that was allocated */ - for (i = 0; i < vec_len (vec_buffer_indices); i++) - { - new_eb = pool_elt_at_index (em->buffer_pool, vec_buffer_indices[i]); - vlib_buffer_free (vm, &new_eb->buffer_index, 1); - pool_put (em->buffer_pool, new_eb); - } - vec_free (vec_buffer_indices); - vec_free (vec_buffer_to_be_sent); - vec_free (thread_index); - } - return 0; /* not so much */ -} - -#define ioam_export_node_common(EM, VM, N, F, HTYPE, L, V, NEXT) \ -do { \ - u32 n_left_from, *from, *to_next; \ - export_next_t next_index; \ - u32 pkts_recorded = 0; \ - ioam_export_buffer_t *my_buf = 0; \ - vlib_buffer_t *eb0 = 0; \ - u32 ebi0 = 0; \ - from = vlib_frame_vector_args (F); \ - n_left_from = (F)->n_vectors; \ - next_index = (N)->cached_next_index; \ - while (__sync_lock_test_and_set ((EM)->lockp[(VM)->cpu_index], 1)); \ - my_buf = ioam_export_get_my_buffer (EM, (VM)->cpu_index); \ - my_buf->touched_at = vlib_time_now (VM); \ - while (n_left_from > 0) \ - { \ - u32 n_left_to_next; \ - vlib_get_next_frame (VM, N, next_index, to_next, n_left_to_next); \ - while (n_left_from >= 4 && n_left_to_next >= 2) \ - { \ - u32 next0 = NEXT; \ - u32 next1 = NEXT; \ - u32 bi0, bi1; \ - HTYPE *ip0, *ip1; \ - vlib_buffer_t *p0, *p1; \ - u32 ip_len0, ip_len1; \ - { \ - 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, 3 * CLIB_CACHE_LINE_BYTES, LOAD); \ - CLIB_PREFETCH (p3->data, 3 * CLIB_CACHE_LINE_BYTES, LOAD); \ - } \ - 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; \ - p0 = vlib_get_buffer (VM, bi0); \ - p1 = vlib_get_buffer (VM, bi1); \ - ip0 = vlib_buffer_get_current (p0); \ - ip1 = vlib_buffer_get_current (p1); \ - ip_len0 = \ - clib_net_to_host_u16 (ip0->L) + sizeof (HTYPE); \ - ip_len1 = \ - clib_net_to_host_u16 (ip1->L) + sizeof (HTYPE); \ - ebi0 = my_buf->buffer_index; \ - eb0 = vlib_get_buffer (VM, ebi0); \ - if (PREDICT_FALSE (eb0 == 0)) \ - goto NO_BUFFER1; \ - ip_len0 = \ - ip_len0 > DEFAULT_EXPORT_SIZE ? DEFAULT_EXPORT_SIZE : ip_len0; \ - ip_len1 = \ - ip_len1 > DEFAULT_EXPORT_SIZE ? DEFAULT_EXPORT_SIZE : ip_len1; \ - copy3cachelines (eb0->data + eb0->current_length, ip0, ip_len0); \ - eb0->current_length += DEFAULT_EXPORT_SIZE; \ - my_buf->records_in_this_buffer++; \ - if (my_buf->records_in_this_buffer >= DEFAULT_EXPORT_RECORDS) \ - { \ - ioam_export_send_buffer (EM, VM, my_buf); \ - ioam_export_init_buffer (EM, VM, my_buf); \ - } \ - ebi0 = my_buf->buffer_index; \ - eb0 = vlib_get_buffer (VM, ebi0); \ - if (PREDICT_FALSE (eb0 == 0)) \ - goto NO_BUFFER1; \ - copy3cachelines (eb0->data + eb0->current_length, ip1, ip_len1); \ - eb0->current_length += DEFAULT_EXPORT_SIZE; \ - my_buf->records_in_this_buffer++; \ - if (my_buf->records_in_this_buffer >= DEFAULT_EXPORT_RECORDS) \ - { \ - ioam_export_send_buffer (EM, VM, my_buf); \ - ioam_export_init_buffer (EM, VM, my_buf); \ - } \ - pkts_recorded += 2; \ - if (PREDICT_FALSE (((node)->flags & VLIB_NODE_FLAG_TRACE))) \ - { \ - if (p0->flags & VLIB_BUFFER_IS_TRACED) \ - { \ - export_trace_t *t = \ - vlib_add_trace (VM, node, p0, sizeof (*t)); \ - t->flow_label = \ - clib_net_to_host_u32 (ip0->V); \ - t->next_index = next0; \ - } \ - if (p1->flags & VLIB_BUFFER_IS_TRACED) \ - { \ - export_trace_t *t = \ - vlib_add_trace (VM, N, p1, sizeof (*t)); \ - t->flow_label = \ - clib_net_to_host_u32 (ip1->V); \ - t->next_index = next1; \ - } \ - } \ - NO_BUFFER1: \ - vlib_validate_buffer_enqueue_x2 (VM, N, 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 *p0; \ - u32 next0 = NEXT; \ - HTYPE *ip0; \ - u32 ip_len0; \ - bi0 = from[0]; \ - to_next[0] = bi0; \ - from += 1; \ - to_next += 1; \ - n_left_from -= 1; \ - n_left_to_next -= 1; \ - p0 = vlib_get_buffer (VM, bi0); \ - ip0 = vlib_buffer_get_current (p0); \ - ip_len0 = \ - clib_net_to_host_u16 (ip0->L) + sizeof (HTYPE); \ - ebi0 = my_buf->buffer_index; \ - eb0 = vlib_get_buffer (VM, ebi0); \ - if (PREDICT_FALSE (eb0 == 0)) \ - goto NO_BUFFER; \ - ip_len0 = \ - ip_len0 > DEFAULT_EXPORT_SIZE ? DEFAULT_EXPORT_SIZE : ip_len0; \ - copy3cachelines (eb0->data + eb0->current_length, ip0, ip_len0); \ - eb0->current_length += DEFAULT_EXPORT_SIZE; \ - my_buf->records_in_this_buffer++; \ - if (my_buf->records_in_this_buffer >= DEFAULT_EXPORT_RECORDS) \ - { \ - ioam_export_send_buffer (EM, VM, my_buf); \ - ioam_export_init_buffer (EM, VM, my_buf); \ - } \ - if (PREDICT_FALSE (((N)->flags & VLIB_NODE_FLAG_TRACE) \ - && (p0->flags & VLIB_BUFFER_IS_TRACED))) \ - { \ - export_trace_t *t = vlib_add_trace (VM, (N), p0, sizeof (*t)); \ - t->flow_label = \ - clib_net_to_host_u32 (ip0->V); \ - t->next_index = next0; \ - } \ - pkts_recorded += 1; \ - NO_BUFFER: \ - vlib_validate_buffer_enqueue_x1 (VM, N, next_index, \ - to_next, n_left_to_next, \ - bi0, next0); \ - } \ - vlib_put_next_frame (VM, N, next_index, n_left_to_next); \ - } \ - vlib_node_increment_counter (VM, export_node.index, \ - EXPORT_ERROR_RECORDED, pkts_recorded); \ - *(EM)->lockp[(VM)->cpu_index] = 0; \ -} while(0) - -#endif /* __included_ioam_export_h__ */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.api b/plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.api deleted file mode 100644 index 7b17c3f7..00000000 --- a/plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.api +++ /dev/null @@ -1,42 +0,0 @@ -/* Hey Emacs use -*- mode: C -*- */ -/* - * 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. - */ - -/* Define a simple binary API to control the feature */ - -define vxlan_gpe_ioam_export_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 is_disable; - - /* Collector ip address */ - u8 collector_address[4]; - u8 src_address[4]; - - /* Src ip address */ -}; - -define vxlan_gpe_ioam_export_enable_disable_reply { - /* From the request */ - u32 context; - - /* Return value, zero means all OK */ - i32 retval; -}; \ No newline at end of file diff --git a/plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.c b/plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.c deleted file mode 100644 index bab8d977..00000000 --- a/plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * 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. - */ -/* - *------------------------------------------------------------------ - * vxlan_gpe_ioam_export.c - ioam export API / debug CLI handling - *------------------------------------------------------------------ - */ - -#include -#include -#include -#include - -#include -#include -#include - -#include - -/* define message IDs */ -#include - -/* define message structures */ -#define vl_typedefs -#include -#undef vl_typedefs - -/* define generated endian-swappers */ -#define vl_endianfun -#include -#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 -#undef vl_printfun - -/* Get the API version number */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#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_vxlan_gpe_ioam_export_plugin_api_msg \ -_(VXLAN_GPE_IOAM_EXPORT_ENABLE_DISABLE, vxlan_gpe_ioam_export_enable_disable) - -extern void vxlan_gpe_set_next_override (uword next); -/* Action function shared between message handler and debug CLI */ -int -vxlan_gpe_ioam_export_enable_disable (ioam_export_main_t * em, - u8 is_disable, - ip4_address_t * collector_address, - ip4_address_t * src_address) -{ - vlib_main_t *vm = em->vlib_main; - u32 node_index = export_node.index; - vlib_node_t *vxlan_gpe_decap_ioam_node = NULL; - - if (is_disable == 0) - { - if (em->my_hbh_slot == ~0) - { - /* Hook this export node to vxlan-gpe-decap-ioam-v4 */ - vxlan_gpe_decap_ioam_node = - vlib_get_node_by_name (vm, (u8 *) "vxlan-gpe-decap-ioam-v4"); - if (!vxlan_gpe_decap_ioam_node) - { - /* node does not exist give up */ - return (-1); - } - em->my_hbh_slot = - vlib_node_add_next (vm, vxlan_gpe_decap_ioam_node->index, - node_index); - } - if (1 == ioam_export_header_create (em, collector_address, src_address)) - { - ioam_export_thread_buffer_init (em, vm); - vxlan_gpe_set_next_override (em->my_hbh_slot); - /* Turn on the export buffer check process */ - vlib_process_signal_event (vm, em->export_process_node_index, 1, 0); - - } - else - { - return (-2); - } - } - else - { - vxlan_gpe_set_next_override (VXLAN_GPE_DECAP_IOAM_V4_NEXT_POP); - ioam_export_header_cleanup (em, collector_address, src_address); - ioam_export_thread_buffer_free (em); - /* Turn off the export buffer check process */ - vlib_process_signal_event (vm, em->export_process_node_index, 2, 0); - - } - - return 0; -} - -/* API message handler */ -static void vl_api_vxlan_gpe_ioam_export_enable_disable_t_handler - (vl_api_vxlan_gpe_ioam_export_enable_disable_t * mp) -{ - vl_api_vxlan_gpe_ioam_export_enable_disable_reply_t *rmp; - ioam_export_main_t *sm = &vxlan_gpe_ioam_export_main; - int rv; - - rv = vxlan_gpe_ioam_export_enable_disable (sm, (int) (mp->is_disable), - (ip4_address_t *) - mp->collector_address, - (ip4_address_t *) - mp->src_address); - - REPLY_MACRO (VL_API_VXLAN_GPE_IOAM_EXPORT_ENABLE_DISABLE_REPLY); -} /* API message handler */ - - - -/* Set up the API message handling tables */ -static clib_error_t * -vxlan_gpe_ioam_export_plugin_api_hookup (vlib_main_t * vm) -{ - ioam_export_main_t *sm = &vxlan_gpe_ioam_export_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_vxlan_gpe_ioam_export_plugin_api_msg; -#undef _ - - return 0; -} - - -static clib_error_t * -set_vxlan_gpe_ioam_export_ipfix_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - ioam_export_main_t *em = &vxlan_gpe_ioam_export_main; - ip4_address_t collector, src; - u8 is_disable = 0; - - collector.as_u32 = 0; - src.as_u32 = 0; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "collector %U", unformat_ip4_address, &collector)) - ; - else if (unformat (input, "src %U", unformat_ip4_address, &src)) - ; - else if (unformat (input, "disable")) - is_disable = 1; - else - break; - } - - if (collector.as_u32 == 0) - return clib_error_return (0, "collector address required"); - - if (src.as_u32 == 0) - return clib_error_return (0, "src address required"); - - em->ipfix_collector.as_u32 = collector.as_u32; - em->src_address.as_u32 = src.as_u32; - - vlib_cli_output (vm, "Collector %U, src address %U", - format_ip4_address, &em->ipfix_collector, - format_ip4_address, &em->src_address); - - /* Turn on the export timer process */ - // vlib_process_signal_event (vm, flow_report_process_node.index, - //1, 0); - if (0 != - vxlan_gpe_ioam_export_enable_disable (em, is_disable, &collector, &src)) - { - return clib_error_return (0, "Unable to set ioam vxlan-gpe export"); - } - - return 0; -} - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (set_vxlan_gpe_ioam_ipfix_command, static) = -{ -.path = "set vxlan-gpe-ioam export ipfix", -.short_help = "set vxlan-gpe-ioam export ipfix collector src ", -.function = set_vxlan_gpe_ioam_export_ipfix_command_fn, -}; -/* *INDENT-ON* */ - - -static clib_error_t * -vxlan_gpe_ioam_export_init (vlib_main_t * vm) -{ - ioam_export_main_t *em = &vxlan_gpe_ioam_export_main; - clib_error_t *error = 0; - u8 *name; - - name = format (0, "vxlan_gpe_ioam_export_%08x%c", api_version, 0); - - /* Ask for a correctly-sized block of API message decode slots */ - em->msg_id_base = vl_msg_api_get_msg_ids - ((char *) name, VL_MSG_FIRST_AVAILABLE); - em->unix_time_0 = (u32) time (0); /* Store starting time */ - em->vlib_time_0 = vlib_time_now (vm); - - error = vxlan_gpe_ioam_export_plugin_api_hookup (vm); - em->my_hbh_slot = ~0; - em->vlib_main = vm; - em->vnet_main = vnet_get_main (); - vec_free (name); - - return error; -} - -VLIB_INIT_FUNCTION (vxlan_gpe_ioam_export_init); - - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_all_api_h.h b/plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_all_api_h.h deleted file mode 100644 index 6d93f093..00000000 --- a/plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_all_api_h.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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. - */ -/* Include the generated file, see BUILT_SOURCES in Makefile.am */ -#include diff --git a/plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_msg_enum.h b/plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_msg_enum.h deleted file mode 100644 index cc5698de..00000000 --- a/plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_msg_enum.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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. - */ -#ifndef included_vxlan_gpe_ioam_export_msg_enum_h -#define included_vxlan_gpe_ioam_export_msg_enum_h - -#include - -#define vl_msg_id(n,h) n, -typedef enum { -#include - /* 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_vxlan_gpe_ioam_export_msg_enum_h */ diff --git a/plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_test.c b/plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_test.c deleted file mode 100644 index 494263d9..00000000 --- a/plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_test.c +++ /dev/null @@ -1,215 +0,0 @@ -/* - * 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. - */ -/* - *------------------------------------------------------------------ - * vxlan_gpe_ioam_export_test.c - test harness plugin - *------------------------------------------------------------------ - */ - -#include -#include -#include -#include -#include - - -/* Declare message IDs */ -#include - -/* define message structures */ -#define vl_typedefs -#include -#undef vl_typedefs - -/* declare message handlers for each api */ - -#define vl_endianfun /* define message structures */ -#include -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) -#define vl_printfun -#include -#undef vl_printfun - -/* Get the API version number. */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#undef vl_api_version - - -typedef struct -{ - /* API message ID base */ - u16 msg_id_base; - vat_main_t *vat_main; -} export_test_main_t; - -export_test_main_t export_test_main; - -#define foreach_standard_reply_retval_handler \ -_(vxlan_gpe_ioam_export_enable_disable_reply) - -#define _(n) \ - static void vl_api_##n##_t_handler \ - (vl_api_##n##_t * mp) \ - { \ - vat_main_t * vam = export_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 \ -_(VXLAN_GPE_IOAM_EXPORT_ENABLE_DISABLE_REPLY, vxlan_gpe_ioam_export_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_vxlan_gpe_ioam_export_enable_disable (vat_main_t * vam) -{ - export_test_main_t *sm = &export_test_main; - unformat_input_t *i = vam->input; - f64 timeout; - int is_disable = 0; - vl_api_vxlan_gpe_ioam_export_enable_disable_t *mp; - - /* Parse args required to build the message */ - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "disable")) - is_disable = 1; - else - break; - } - - /* Construct the API message */ - M (VXLAN_GPE_IOAM_EXPORT_ENABLE_DISABLE, - vxlan_gpe_ioam_export_enable_disable); - mp->is_disable = is_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 \ -_(vxlan_gpe_ioam_export_enable_disable, " [disable]") - -void -vat_api_hookup (vat_main_t * vam) -{ - export_test_main_t *sm = &export_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) -{ - export_test_main_t *sm = &export_test_main; - u8 *name; - - sm->vat_main = vam; - - name = format (0, "vxlan_gpe_ioam_export_%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; -} - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_thread.c b/plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_thread.c deleted file mode 100644 index 58508ebf..00000000 --- a/plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_thread.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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. - */ -/* - * ioam_export_thread.c - */ -#include -#include -#include - -static vlib_node_registration_t vxlan_gpe_ioam_export_process_node; - -static uword -vxlan_gpe_ioam_export_process (vlib_main_t * vm, - vlib_node_runtime_t * rt, vlib_frame_t * f) -{ - return (ioam_export_process_common (&vxlan_gpe_ioam_export_main, - vm, rt, f, - vxlan_gpe_ioam_export_process_node.index)); -} - - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (vxlan_gpe_ioam_export_process_node, static) = -{ - .function = vxlan_gpe_ioam_export_process, - .type = VLIB_NODE_TYPE_PROCESS, - .name = "vxlan-gpe-ioam-export-process", -}; -/* *INDENT-ON* */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_node.c b/plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_node.c deleted file mode 100644 index 722c2b06..00000000 --- a/plugins/ioam-plugin/ioam/export-vxlan-gpe/vxlan_gpe_node.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -typedef struct -{ - u32 next_index; - u32 flow_label; -} export_trace_t; - -/* packet trace format function */ -static u8 * -format_export_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 *); - export_trace_t *t = va_arg (*args, export_trace_t *); - - s = format (s, "EXPORT: flow_label %d, next index %d", - t->flow_label, t->next_index); - return s; -} - -vlib_node_registration_t export_node; - -#define foreach_export_error \ -_(RECORDED, "Packets recorded for export") - -typedef enum -{ -#define _(sym,str) EXPORT_ERROR_##sym, - foreach_export_error -#undef _ - EXPORT_N_ERROR, -} export_error_t; - -static char *export_error_strings[] = { -#define _(sym,string) string, - foreach_export_error -#undef _ -}; - -typedef enum -{ - EXPORT_NEXT_VXLAN_GPE_INPUT, - EXPORT_N_NEXT, -} export_next_t; - -always_inline void -copy3cachelines (void *dst, const void *src, size_t n) -{ -#if 0 - if (PREDICT_FALSE (n < DEFAULT_EXPORT_SIZE)) - { - /* Copy only the first 1/2 cache lines whatever is available */ - if (n >= 64) - clib_mov64 ((u8 *) dst, (const u8 *) src); - if (n >= 128) - clib_mov64 ((u8 *) dst + 64, (const u8 *) src + 64); - return; - } - clib_mov64 ((u8 *) dst, (const u8 *) src); - clib_mov64 ((u8 *) dst + 64, (const u8 *) src + 64); - clib_mov64 ((u8 *) dst + 128, (const u8 *) src + 128); -#endif -#if 1 - - u64 *copy_dst, *copy_src; - int i; - copy_dst = (u64 *) dst; - copy_src = (u64 *) src; - if (PREDICT_FALSE (n < DEFAULT_EXPORT_SIZE)) - { - for (i = 0; i < n / 64; i++) - { - copy_dst[0] = copy_src[0]; - copy_dst[1] = copy_src[1]; - copy_dst[2] = copy_src[2]; - copy_dst[3] = copy_src[3]; - copy_dst[4] = copy_src[4]; - copy_dst[5] = copy_src[5]; - copy_dst[6] = copy_src[6]; - copy_dst[7] = copy_src[7]; - copy_dst += 8; - copy_src += 8; - } - return; - } - for (i = 0; i < 3; i++) - { - copy_dst[0] = copy_src[0]; - copy_dst[1] = copy_src[1]; - copy_dst[2] = copy_src[2]; - copy_dst[3] = copy_src[3]; - copy_dst[4] = copy_src[4]; - copy_dst[5] = copy_src[5]; - copy_dst[6] = copy_src[6]; - copy_dst[7] = copy_src[7]; - copy_dst += 8; - copy_src += 8; - } -#endif -} - - -static uword -vxlan_gpe_export_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) -{ - ioam_export_main_t *em = &vxlan_gpe_ioam_export_main; - ioam_export_node_common (em, vm, node, frame, ip4_header_t, length, - ip_version_and_header_length, - EXPORT_NEXT_VXLAN_GPE_INPUT); - return frame->n_vectors; -} - -/* - * Node for VXLAN-GPE export - */ -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (export_node) = -{ - .function = vxlan_gpe_export_node_fn, - .name = "vxlan-gpe-ioam-export", - .vector_size = sizeof (u32), - .format_trace = format_export_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN (export_error_strings), - .error_strings = export_error_strings, - .n_next_nodes = EXPORT_N_NEXT, - /* edit / add dispositions here */ - .next_nodes = - {[EXPORT_NEXT_VXLAN_GPE_INPUT] = "vxlan-gpe-pop-ioam-v4"}, -}; -/* *INDENT-ON* */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/ioam-plugin/ioam/export/ioam_export.api b/plugins/ioam-plugin/ioam/export/ioam_export.api deleted file mode 100644 index f22d9fc8..00000000 --- a/plugins/ioam-plugin/ioam/export/ioam_export.api +++ /dev/null @@ -1,42 +0,0 @@ -/* Hey Emacs use -*- mode: C -*- */ -/* - * 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. - */ - -/* Define a simple binary API to control the feature */ - -define ioam_export_ip6_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 is_disable; - - /* Collector ip address */ - u8 collector_address[4]; - u8 src_address[4]; - - /* Src ip address */ -}; - -define ioam_export_ip6_enable_disable_reply { - /* From the request */ - u32 context; - - /* Return value, zero means all OK */ - i32 retval; -}; diff --git a/plugins/ioam-plugin/ioam/export/ioam_export.c b/plugins/ioam-plugin/ioam/export/ioam_export.c deleted file mode 100644 index b122e445..00000000 --- a/plugins/ioam-plugin/ioam/export/ioam_export.c +++ /dev/null @@ -1,282 +0,0 @@ -/* - * 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. - */ -/* - *------------------------------------------------------------------ - * ioam_export.c - ioam export API / debug CLI handling - *------------------------------------------------------------------ - */ - -#include -#include -#include - -#include -#include -#include -#include - - -/* define message IDs */ -#include - -/* define message structures */ -#define vl_typedefs -#include -#undef vl_typedefs - -/* define generated endian-swappers */ -#define vl_endianfun -#include -#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 -#undef vl_printfun - -/* Get the API version number */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#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_ioam_export_plugin_api_msg \ -_(IOAM_EXPORT_IP6_ENABLE_DISABLE, ioam_export_ip6_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) -{ - ioam_export_main_t *em = &ioam_export_main; - clib_error_t *error = 0; - - em->vlib_main = vm; - em->vnet_main = h->vnet_main; - - return error; -} - -/* Action function shared between message handler and debug CLI */ - -int -ioam_export_ip6_enable_disable (ioam_export_main_t * em, - u8 is_disable, - ip4_address_t * collector_address, - ip4_address_t * src_address) -{ - vlib_main_t *vm = em->vlib_main; - - if (is_disable == 0) - { - if (1 == ioam_export_header_create (em, collector_address, src_address)) - { - ioam_export_thread_buffer_init (em, vm); - ip6_hbh_set_next_override (em->my_hbh_slot); - /* Turn on the export buffer check process */ - vlib_process_signal_event (vm, em->export_process_node_index, 1, 0); - - } - else - { - return (-2); - } - } - else - { - ip6_hbh_set_next_override (IP6_LOOKUP_NEXT_POP_HOP_BY_HOP); - ioam_export_header_cleanup (em, collector_address, src_address); - ioam_export_thread_buffer_free (em); - /* Turn off the export buffer check process */ - vlib_process_signal_event (vm, em->export_process_node_index, 2, 0); - - } - - return 0; -} - -/* API message handler */ -static void vl_api_ioam_export_ip6_enable_disable_t_handler - (vl_api_ioam_export_ip6_enable_disable_t * mp) -{ - vl_api_ioam_export_ip6_enable_disable_reply_t *rmp; - ioam_export_main_t *sm = &ioam_export_main; - int rv; - - rv = ioam_export_ip6_enable_disable (sm, (int) (mp->is_disable), - (ip4_address_t *) - mp->collector_address, - (ip4_address_t *) mp->src_address); - - REPLY_MACRO (VL_API_IOAM_EXPORT_IP6_ENABLE_DISABLE_REPLY); -} - -/* Set up the API message handling tables */ -static clib_error_t * -ioam_export_plugin_api_hookup (vlib_main_t * vm) -{ - ioam_export_main_t *sm = &ioam_export_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_ioam_export_plugin_api_msg; -#undef _ - - return 0; -} - -#define vl_msg_name_crc_list -#include -#undef vl_msg_name_crc_list - -static void -setup_message_id_table (ioam_export_main_t * sm, api_main_t * am) -{ -#define _(id,n,crc) \ - vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base); - foreach_vl_msg_name_crc_ioam_export; -#undef _ -} - -static clib_error_t * -set_ioam_export_ipfix_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - ioam_export_main_t *em = &ioam_export_main; - ip4_address_t collector, src; - u8 is_disable = 0; - - collector.as_u32 = 0; - src.as_u32 = 0; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "collector %U", unformat_ip4_address, &collector)) - ; - else if (unformat (input, "src %U", unformat_ip4_address, &src)) - ; - else if (unformat (input, "disable")) - is_disable = 1; - else - break; - } - - if (collector.as_u32 == 0) - return clib_error_return (0, "collector address required"); - - if (src.as_u32 == 0) - return clib_error_return (0, "src address required"); - - em->ipfix_collector.as_u32 = collector.as_u32; - em->src_address.as_u32 = src.as_u32; - - vlib_cli_output (vm, "Collector %U, src address %U", - format_ip4_address, &em->ipfix_collector, - format_ip4_address, &em->src_address); - - /* Turn on the export timer process */ - // vlib_process_signal_event (vm, flow_report_process_node.index, - //1, 0); - ioam_export_ip6_enable_disable (em, is_disable, &collector, &src); - - return 0; -} - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (set_ipfix_command, static) = -{ -.path = "set ioam export ipfix",.short_help = - "set ioam export ipfix collector src ",. - function = set_ioam_export_ipfix_command_fn,}; -/* *INDENT-ON* */ - - -static clib_error_t * -ioam_export_init (vlib_main_t * vm) -{ - ioam_export_main_t *em = &ioam_export_main; - clib_error_t *error = 0; - u8 *name; - u32 node_index = export_node.index; - vlib_node_t *ip6_hbyh_node = NULL; - - name = format (0, "ioam_export_%08x%c", api_version, 0); - - /* Ask for a correctly-sized block of API message decode slots */ - em->msg_id_base = vl_msg_api_get_msg_ids - ((char *) name, VL_MSG_FIRST_AVAILABLE); - em->unix_time_0 = (u32) time (0); /* Store starting time */ - em->vlib_time_0 = vlib_time_now (vm); - - error = ioam_export_plugin_api_hookup (vm); - - /* Add our API messages to the global name_crc hash table */ - setup_message_id_table (em, &api_main); - - /* Hook this export node to ip6-hop-by-hop */ - ip6_hbyh_node = vlib_get_node_by_name (vm, (u8 *) "ip6-hop-by-hop"); - em->my_hbh_slot = vlib_node_add_next (vm, ip6_hbyh_node->index, node_index); - vec_free (name); - - return error; -} - -VLIB_INIT_FUNCTION (ioam_export_init); - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/ioam-plugin/ioam/export/ioam_export_all_api_h.h b/plugins/ioam-plugin/ioam/export/ioam_export_all_api_h.h deleted file mode 100644 index bc4368f2..00000000 --- a/plugins/ioam-plugin/ioam/export/ioam_export_all_api_h.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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. - */ -/* Include the generated file, see BUILT_SOURCES in Makefile.am */ -#include diff --git a/plugins/ioam-plugin/ioam/export/ioam_export_msg_enum.h b/plugins/ioam-plugin/ioam/export/ioam_export_msg_enum.h deleted file mode 100644 index c2de7988..00000000 --- a/plugins/ioam-plugin/ioam/export/ioam_export_msg_enum.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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. - */ -#ifndef included_ioam_export_msg_enum_h -#define included_ioam_export_msg_enum_h - -#include - -#define vl_msg_id(n,h) n, -typedef enum { -#include - /* 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_ioam_export_msg_enum_h */ diff --git a/plugins/ioam-plugin/ioam/export/ioam_export_test.c b/plugins/ioam-plugin/ioam/export/ioam_export_test.c deleted file mode 100644 index f991fc0c..00000000 --- a/plugins/ioam-plugin/ioam/export/ioam_export_test.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * 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. - */ -/* - *------------------------------------------------------------------ - * ioam_export_test.c - test harness plugin - *------------------------------------------------------------------ - */ - -#include -#include -#include -#include -#include - - -/* Declare message IDs */ -#include - -/* define message structures */ -#define vl_typedefs -#include -#undef vl_typedefs - -/* declare message handlers for each api */ - -#define vl_endianfun /* define message structures */ -#include -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) -#define vl_printfun -#include -#undef vl_printfun - -/* Get the API version number. */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#undef vl_api_version - - -typedef struct -{ - /* API message ID base */ - u16 msg_id_base; - vat_main_t *vat_main; -} export_test_main_t; - -export_test_main_t export_test_main; - -#define foreach_standard_reply_retval_handler \ -_(ioam_export_ip6_enable_disable_reply) - -#define _(n) \ - static void vl_api_##n##_t_handler \ - (vl_api_##n##_t * mp) \ - { \ - vat_main_t * vam = export_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 \ -_(IOAM_EXPORT_IP6_ENABLE_DISABLE_REPLY, ioam_export_ip6_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_ioam_export_ip6_enable_disable (vat_main_t * vam) -{ - export_test_main_t *sm = &export_test_main; - unformat_input_t *i = vam->input; - f64 timeout; - int is_disable = 0; - vl_api_ioam_export_ip6_enable_disable_t *mp; - - /* Parse args required to build the message */ - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "disable")) - is_disable = 1; - else - break; - } - - /* Construct the API message */ - M (IOAM_EXPORT_IP6_ENABLE_DISABLE, ioam_export_ip6_enable_disable); - mp->is_disable = is_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 \ -_(ioam_export_ip6_enable_disable, " [disable]") - -void -vat_api_hookup (vat_main_t * vam) -{ - export_test_main_t *sm = &export_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) -{ - export_test_main_t *sm = &export_test_main; - u8 *name; - - sm->vat_main = vam; - - name = format (0, "ioam_export_%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/plugins/ioam-plugin/ioam/export/ioam_export_thread.c b/plugins/ioam-plugin/ioam/export/ioam_export_thread.c deleted file mode 100644 index d2eb2009..00000000 --- a/plugins/ioam-plugin/ioam/export/ioam_export_thread.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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. - */ -/* - * ioam_export_thread.c - */ -#include -#include -#include - -static vlib_node_registration_t ioam_export_process_node; - -static uword -ioam_export_process (vlib_main_t * vm, - vlib_node_runtime_t * rt, vlib_frame_t * f) -{ - return (ioam_export_process_common(&ioam_export_main, - vm, rt, f, - ioam_export_process_node.index)); -} - -VLIB_REGISTER_NODE (ioam_export_process_node, static) = -{ - .function = ioam_export_process, - .type = VLIB_NODE_TYPE_PROCESS, - .name = "ioam-export-process", -}; diff --git a/plugins/ioam-plugin/ioam/export/jvpp_ioam_export.c b/plugins/ioam-plugin/ioam/export/jvpp_ioam_export.c deleted file mode 100644 index 27d3e214..00000000 --- a/plugins/ioam-plugin/ioam/export/jvpp_ioam_export.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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. - */ - -#include - -#include -#define vl_typedefs /* define message structures */ -#include -#undef vl_typedefs - -#define vl_endianfun -#include -#undef vl_endianfun - -#define vl_print(handle, ...) -#define vl_printfun -#include -#undef vl_printfun - -/* Get the API version number */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#undef vl_api_version - -#include -#include -#include - -#if VPPJNI_DEBUG == 1 - #define DEBUG_LOG(...) clib_warning(__VA_ARGS__) -#else - #define DEBUG_LOG(...) -#endif - -#include - -#include "ioam/jvpp/io_fd_vpp_jvpp_ioamexport_JVppIoamexportImpl.h" -#include "jvpp_ioam_export.h" -#include "ioam/jvpp/jvpp_ioam_export_gen.h" - -/* - * Class: io_fd_vpp_jvpp_ioamexport_JVppIoamexportImpl - * Method: init0 - * Signature: (JI)V - */ -JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_ioamexport_JVppIoamexportImpl_init0 - (JNIEnv *env, jclass clazz, jobject callback, jlong queue_address, jint my_client_index) { - ioamexport_main_t * plugin_main = &ioamexport_main; - u8 * name; - clib_warning ("Java_io_fd_vpp_jvpp_ioamexport_JVppIoamexportImpl_init0"); - - plugin_main->my_client_index = my_client_index; - plugin_main->vl_input_queue = (unix_shared_memory_queue_t *)queue_address; - - name = format (0, "ioam_export_%08x%c", api_version, 0); - plugin_main->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name); - - if (plugin_main->msg_id_base == (u16) ~0) { - jclass exClass = (*env)->FindClass(env, "java/lang/IllegalStateException"); - (*env)->ThrowNew(env, exClass, "ioam_export plugin is not loaded in VPP"); - } else { - plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback); - plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback)); - - #define _(N,n) \ - vl_msg_api_set_handlers(VL_API_##N + plugin_main->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_api_reply_handler; - #undef _ - } -} - -JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_ioamexport_JVppIoamexportImpl_close0 -(JNIEnv *env, jclass clazz) { - ioamexport_main_t * plugin_main = &ioamexport_main; - - // cleanup: - (*env)->DeleteGlobalRef(env, plugin_main->callbackClass); - (*env)->DeleteGlobalRef(env, plugin_main->callbackObject); - - plugin_main->callbackClass = NULL; - plugin_main->callbackObject = NULL; -} - -/* Attach thread to JVM and cache class references when initiating JVPP iOAM EXPORT */ -jint JNI_OnLoad(JavaVM *vm, void *reserved) { - JNIEnv* env; - - if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { - return JNI_EVERSION; - } - - if (cache_class_references(env) != 0) { - clib_warning ("Failed to cache class references\n"); - return JNI_ERR; - } - - return JNI_VERSION_1_8; -} - -/* Clean up cached references when disposing JVPP iOAM EXPORT */ -void JNI_OnUnload(JavaVM *vm, void *reserved) { - JNIEnv* env; - if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { - return; - } - delete_class_references(env); -} diff --git a/plugins/ioam-plugin/ioam/export/jvpp_ioam_export.h b/plugins/ioam-plugin/ioam/export/jvpp_ioam_export.h deleted file mode 100644 index b6c0c16e..00000000 --- a/plugins/ioam-plugin/ioam/export/jvpp_ioam_export.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - */ -#ifndef __included_jvpp_ioam_export_h__ -#define __included_jvpp_ioam_export_h__ - -#include -#include -#include -#include -#include -#include - -/* Global state for JVPP-IOAM-EXPORT */ -typedef struct { - /* Base message index for the export plugin */ - u16 msg_id_base; - - /* Pointer to shared memory queue */ - unix_shared_memory_queue_t * vl_input_queue; - - /* VPP api client index */ - u32 my_client_index; - - /* Callback object and class references enabling asynchronous Java calls */ - jobject callbackObject; - jclass callbackClass; - -} ioamexport_main_t; - -ioamexport_main_t ioamexport_main __attribute__((aligned (64))); - - -#endif /* __included_jvpp_ioam_export_h__ */ diff --git a/plugins/ioam-plugin/ioam/export/node.c b/plugins/ioam-plugin/ioam/export/node.c deleted file mode 100644 index 19f143df..00000000 --- a/plugins/ioam-plugin/ioam/export/node.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * 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. - */ -#include -#include -#include -#include -#include -#include - -typedef struct -{ - u32 next_index; - u32 flow_label; -} export_trace_t; - -/* packet trace format function */ -static u8 * -format_export_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 *); - export_trace_t *t = va_arg (*args, export_trace_t *); - - s = format (s, "EXPORT: flow_label %d, next index %d", - t->flow_label, t->next_index); - return s; -} - -vlib_node_registration_t export_node; - -#define foreach_export_error \ -_(RECORDED, "Packets recorded for export") - -typedef enum -{ -#define _(sym,str) EXPORT_ERROR_##sym, - foreach_export_error -#undef _ - EXPORT_N_ERROR, -} export_error_t; - -static char *export_error_strings[] = { -#define _(sym,string) string, - foreach_export_error -#undef _ -}; - -typedef enum -{ - EXPORT_NEXT_POP_HBYH, - EXPORT_N_NEXT, -} export_next_t; - -always_inline void -copy3cachelines (void *dst, const void *src, size_t n) -{ -#if 0 - if (PREDICT_FALSE (n < DEFAULT_EXPORT_SIZE)) - { - /* Copy only the first 1/2 cache lines whatever is available */ - if (n >= 64) - clib_mov64 ((u8 *) dst, (const u8 *) src); - if (n >= 128) - clib_mov64 ((u8 *) dst + 64, (const u8 *) src + 64); - return; - } - clib_mov64 ((u8 *) dst, (const u8 *) src); - clib_mov64 ((u8 *) dst + 64, (const u8 *) src + 64); - clib_mov64 ((u8 *) dst + 128, (const u8 *) src + 128); -#endif -#if 1 - - u64 *copy_dst, *copy_src; - int i; - copy_dst = (u64 *) dst; - copy_src = (u64 *) src; - if (PREDICT_FALSE (n < DEFAULT_EXPORT_SIZE)) - { - for (i = 0; i < n / 64; i++) - { - copy_dst[0] = copy_src[0]; - copy_dst[1] = copy_src[1]; - copy_dst[2] = copy_src[2]; - copy_dst[3] = copy_src[3]; - copy_dst[4] = copy_src[4]; - copy_dst[5] = copy_src[5]; - copy_dst[6] = copy_src[6]; - copy_dst[7] = copy_src[7]; - copy_dst += 8; - copy_src += 8; - } - return; - } - for (i = 0; i < 3; i++) - { - copy_dst[0] = copy_src[0]; - copy_dst[1] = copy_src[1]; - copy_dst[2] = copy_src[2]; - copy_dst[3] = copy_src[3]; - copy_dst[4] = copy_src[4]; - copy_dst[5] = copy_src[5]; - copy_dst[6] = copy_src[6]; - copy_dst[7] = copy_src[7]; - copy_dst += 8; - copy_src += 8; - } -#endif -} - -static uword -ip6_export_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) -{ - ioam_export_main_t *em = &ioam_export_main; - ioam_export_node_common(em, vm, node, frame, ip6_header_t, payload_length, - ip_version_traffic_class_and_flow_label, - EXPORT_NEXT_POP_HBYH); - return frame->n_vectors; -} - -/* - * Node for IP6 export - */ -VLIB_REGISTER_NODE (export_node) = -{ - .function = ip6_export_node_fn, - .name = "ip6-export", - .vector_size = sizeof (u32), - .format_trace = format_export_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN (export_error_strings), - .error_strings = export_error_strings, - .n_next_nodes = EXPORT_N_NEXT, - /* edit / add dispositions here */ - .next_nodes = - { - [EXPORT_NEXT_POP_HBYH] = "ip6-pop-hop-by-hop" - }, -}; diff --git a/plugins/ioam-plugin/ioam/ioam_plugin_doc.md b/plugins/ioam-plugin/ioam/ioam_plugin_doc.md deleted file mode 100644 index 343abcf7..00000000 --- a/plugins/ioam-plugin/ioam/ioam_plugin_doc.md +++ /dev/null @@ -1,464 +0,0 @@ -## VPP Inband OAM (iOAM) {#ioam_plugin_doc} - -In-band OAM (iOAM) is an implementation study to record operational -information in the packet while the packet traverses a path between -two points in the network. - -Overview of iOAM can be found in [iOAM-Devnet] page. -The following IETF drafts detail the motivation and mechanism for -recording operational information: - - [iOAM-ietf-requirements] - Describes motivation and usecases for iOAM - - [iOAM-ietf-data] - Describes data records that can be collected using iOAM - - [iOAM-ietf-transport] - Lists out the transport protocols - and mechanism to carry iOAM data records - - [iOAM-ietf-proof-of-transit] - Describes the idea of Proof of Transit (POT) - and mechanisms to operationalize the idea - -## Terminology -In-band OAM is expected to be deployed in a specific domain rather -than on the overall Internet. The part of the network which employs in-band OAM -is referred to as **"in-band OAM-domain"**. - -In-band OAM data is added to a packet on entering the in-band OAM-domain -and is removed from the packet when exiting the domain. -Within the in-band OAM-domain, network nodes that the packet traverses -may update the in-band OAM data records. - -- The node which adds in-band OAM data to the packet is called the -**"in-band OAM encapsulating node"**. - -- The node which removes the in-band OAM data is referred to as the -**"in-band OAM decapsulating node"**. - -- Nodes within the domain which are aware of in-band OAM data and read -and/or write or process the in-band OAM data are called -**"in-band OAM transit nodes"**. - -## Features supported in the current release -VPP can function as in-band OAM encapsulating, transit and decapsulating node. -In this version of VPP in-band OAM data is transported as options in an -IPv6 hop-by-hop extension header. Hence in-band OAM can be enabled -for IPv6 traffic. - -The following iOAM features are supported: - -- **In-band OAM Tracing** : In-band OAM supports multiple data records to be -recorded in the packet as the packet traverses the network. -These data records offer insights into the operational behavior of the network. -The following information can be collected in the tracing -data from the nodes a packet traverses: - - Node ID - - Ingress interface ID - - Egress interface ID - - Timestamp - - Pre-configured application data - -- **In-band OAM Proof of Transit (POT)**: Proof of transit iOAM data is -added to every packet for verifying that a packet traverses a specific -set of nodes. -In-band OAM data is updated at every node that is enabled with iOAM -proof of transit and is used to verify whether a packet traversed -all the specified nodes. When the verifier receives each packet, -it can validate whether the packet traversed the specified nodes. - - -## Configuration -Configuring iOAM involves: -- Selecting the packets for which iOAM data must be inserted, updated or removed - - Selection of packets for iOAM data insertion on iOAM encapsulating node. - Selection of packets is done by 5-tuple based classification - - Selection of packets for updating iOAM data is implicitly done on the - presence of iOAM options in the packet - - Selection of packets for removing the iOAM data is done on 5-tuple - based classification -- The kind of data to be collected - - Tracing data - - Proof of transit -- Additional details for processing iOAM data to be collected - - For trace data - trace type, number of nodes to be recorded in the trace, - time stamp precision, etc. - - For POT data - configuration of POT profile required to process the POT data - -The CLI for configuring iOAM is explained here followed by detailed steps -and examples to deploy iOAM on VPP as an encapsulating, transit or -decapsulating iOAM node in the subsequent sub-sections. - -VPP iOAM configuration for enabling trace and POT is as follows: - - set ioam rewrite trace-type <0x1f|0x7|0x9|0x11|0x19> - trace-elts trace-tsp <0|1|2|3> - node-id app-data [pot] - -A description of each of the options of the CLI follows: -- trace-type : An entry in the "Node data List" array of the trace option -can have different formats, following the needs of the a deployment. -For example: Some deployments might only be interested -in recording the node identifiers, whereas others might be interested -in recording node identifier and timestamp. -The following types are currently supported: - - 0x1f : Node data to include hop limit (8 bits), node ID (24 bits), - ingress and egress interface IDs (16 bits each), timestamp (32 bits), - application data (32 bits) - - 0x7 : Node data to include hop limit (8 bits), node ID (24 bits), - ingress and egress interface IDs (16 bits each) - - 0x9 : Node data to include hop limit (8 bits), node ID (24 bits), - timestamp (32 bits) - - 0x11: Node data to include hop limit (8 bits), node ID (24 bits), - application data (32 bits) - - 0x19: Node data to include hop limit (8 bits), node ID (24 bits), - timestamp (32 bits), application data (32 bits) -- trace-elts : Defines the length of the node data array in the trace option. -- trace-tsp : Defines the timestamp precision to use with the enumerated value - for precision as follows: - - 0 : 32bits timestamp in seconds - - 1 : 32bits timestamp in milliseconds - - 2 : 32bits timestamp in microseconds - - 3 : 32bits timestamp in nanoseconds -- node-id : Unique identifier for the node, included in the node ID - field of the node data in trace option. -- app-data : The value configured here is included as is in -application data field of node data in trace option. -- pot : Enables POT option to be included in the iOAM options. - -### Trace configuration - -#### On in-band OAM encapsulating node - - **Configure classifier and apply ACL** to select packets for - iOAM data insertion - - Example to enable iOAM data insertion for all the packets - towards IPv6 address db06::06: - - vpp# classify table miss-next node ip6-lookup mask l3 ip6 dst - - vpp# classify session acl-hit-next node ip6-add-hop-by-hop - table-index 0 match l3 ip6 dst db06::06 - - vpp# set int input acl intfc GigabitEthernet0/0/0 ip6-table 0 - - - **Enable tracing** : Specify node ID, maximum number of nodes for which - trace data should be recorded, type of data to be included for recording, - optionally application data to be included - - Example to enable tracing with a maximum of 4 nodes recorded - and the data to be recorded to include - hop limit, node id, - ingress and egress interface IDs, timestamp (millisecond precision), - application data (0x1234): - - - vpp# set ioam rewrite trace-type 0x1f trace-elts 4 trace-tsp 1 - node-id 0x1 app-data 0x1234 - - - -#### On in-band OAM transit node -- The transit node requires trace type, timestamp precision, node ID and -optionally application data to be configured, -to update its node data in the trace option. - -Example: - - vpp# set ioam rewrite trace-type 0x1f trace-elts 4 trace-tsp 1 - node-id 0x2 app-data 0x1234 - -#### On the In-band OAM decapsulating node -- The decapsulating node similar to encapsulating node requires -**classification** of the packets to remove iOAM data from. - - Example to decapsulate iOAM data for packets towards - db06::06, configure classifier and enable it as an ACL as follows: - - - vpp# classify table miss-next node ip6-lookup mask l3 ip6 dst - - vpp# classify session acl-hit-next node ip6-lookup table-index 0 - match l3 ip6 dst db06::06 opaque-index 100 - - vpp# set int input acl intfc GigabitEthernet0/0/0 ip6-table 0 - - -- Decapsulating node requires trace type, timestamp precision, -node ID and optionally application data to be configured, -to update its node data in the trace option before it is decapsulated. - -Example: - - vpp# set ioam rewrite trace-type 0x1f trace-elts 4 - trace-tsp 1 node-id 0x3 app-data 0x1234 - - -### Proof of Transit configuration - -For details on proof-of-transit, -see the IETF draft [iOAM-ietf-proof-of-transit]. -To enable Proof of Transit all the nodes that participate -and hence are verified for transit need a proof of transit profile. -A script to generate a proof of transit profile as per the mechanism -described in [iOAM-ietf-proof-of-transit] will be available at [iOAM-Devnet]. - -The Proof of transit mechanism implemented here is based on -Shamir's Secret Sharing algorithm. -The overall algorithm uses two polynomials -POLY-1 and POLY-2. The degree of polynomials depends on number of nodes -to be verified for transit. -POLY-1 is secret and constant. Each node gets a point on POLY-1 -at setup-time and keeps it secret. -POLY-2 is public, random and per packet. -Each node is assigned a point on POLY-1 and POLY-2 with the same x index. -Each node derives its point on POLY-2 each time a packet arrives at it. -A node then contributes its points on POLY-1 and POLY-2 to construct -POLY-3 (POLY-3 = POLY-1 + POLY-2) using lagrange extrapolation and -forwards it towards the verifier by updating POT data in the packet. -The verifier constructs POLY-3 from the accumulated value from all the nodes -and its own points on POLY-1 and POLY-2 and verifies whether -POLY-3 = POLY-1 + POLY-2. Only the verifier knows POLY-1. -The solution leverages finite field arithmetic in a field of size "prime number" -for reasons explained in description of Shamir's secret sharing algorithm. - -Here is an explanation of POT profile list and profile configuration CLI to -realize the above mechanism. -It is best to use the script provided at [iOAM-Devnet] to generate -this configuration. -- **Create POT profile** : set pot profile name id [0-1] -[validator-key 0xu64] prime-number 0xu64 secret_share 0xu64 -lpc 0xu64 polynomial2 0xu64 bits-in-random [0-64] - - name : Profile list name. - - id : Profile id, it can be 0 or 1. - A maximum of two profiles can be configured per profile list. - - validator-key : Secret key configured only on the - verifier/decapsulating node used to compare and verify proof of transit. - - prime-number : Prime number for finite field arithmetic as required by the - proof of transit mechanism. - - secret_share : Unique point for each node on the secret polynomial POLY-1. - - lpc : Lagrange Polynomial Constant(LPC) calculated per node based on - its point (x value used for evaluating the points on the polynomial) - on the polynomial used in lagrange extrapolation - for reconstructing polynomial (POLY-3). - - polynomial2 : Is the pre-evaluated value of the point on - 2nd polynomial(POLY-2). This is unique for each node. - It is pre-evaluated for all the coefficients of POLY-2 except - for the constant part of the polynomial that changes per packet - and is received as part of the POT data in the packet. - - bits-in-random : To control the size of the random number to be - generated. This number has to match the other numbers generated and used - in the profile as per the algorithm. - -- **Set a configured profile as active/in-use** : -set pot profile-active name ID [0-1] - - name : Name of the profile list to be used for computing - POT data per packet. - - ID : Identifier of the profile within the list to be used. - -#### On In-band OAM encapsulating node - - Configure the classifier and apply ACL to select packets for iOAM data insertion. - - Example to enable iOAM data insertion for all the packet towards - IPv6 address db06::06 - - - - vpp# classify table miss-next node ip6-lookup mask l3 ip6 dst - - vpp# classify session acl-hit-next node - ip6-add-hop-by-hop table-index 0 match l3 ip6 dst db06::06 - - vpp# set int input acl intfc GigabitEthernet0/0/0 ip6-table 0 - - - - Configure the proof of transit profile list with profiles. -Each profile list referred to by a name can contain 2 profiles, -only one is in use for updating proof of transit data at any time. - - Example profile list example with a profile generated from the - script to verify transit through 3 nodes is: - - - vpp# set pot profile name example id 0 prime-number 0x7fff0000fa884685 - secret_share 0x6c22eff0f45ec56d lpc 0x7fff0000fa884682 - polynomial2 0xffb543d4a9c bits-in-random 63 - - - Enable one of the profiles from the configured profile list as active - so that is will be used for calculating proof of transit - -Example enable profile ID 0 from profile list example configured above: - - - vpp# set pot profile-active name example ID 0 - - - - Enable POT option to be inserted - - - vpp# set ioam rewrite pot - - -#### On in-band OAM transit node - - Configure the proof of transit profile list with profiles for transit node. -Example: - - - vpp# set pot profile name example id 0 prime-number 0x7fff0000fa884685 - secret_share 0x564cdbdec4eb625d lpc 0x1 - polynomial2 0x23f3a227186a bits-in-random 63 - -#### On in-band OAM decapsulating node / verifier -- The decapsulating node, similar to the encapsulating node requires -classification of the packets to remove iOAM data from. - - Example to decapsulate iOAM data for packets towards db06::06 - configure classifier and enable it as an ACL as follows: - - - vpp# classify table miss-next node ip6-lookup mask l3 ip6 dst - - vpp# classify session acl-hit-next node ip6-lookup table-index 0 - match l3 ip6 dst db06::06 opaque-index 100 - - vpp# set int input acl intfc GigabitEthernet0/0/0 ip6-table 0 - -- To update and verify the proof of transit, POT profile list should be configured. - - Example POT profile list configured as follows: - - vpp# set pot profile name example id 0 validate-key 0x7fff0000fa88465d - prime-number 0x7fff0000fa884685 secret_share 0x7a08fbfc5b93116d lpc 0x3 - polynomial2 0x3ff738597ce bits-in-random 63 - -## Operational data - -Following CLIs are available to check iOAM operation: -- To check iOAM configuration that are effective use "show ioam summary" - -Example: - - vpp# show ioam summary - REWRITE FLOW CONFIGS - Not configured - HOP BY HOP OPTIONS - TRACE CONFIG - - Trace Type : 0x1f (31) - Trace timestamp precision : 1 (Milliseconds) - Num of trace nodes : 4 - Node-id : 0x2 (2) - App Data : 0x1234 (4660) - POT OPTION - 1 (Enabled) - Try 'show ioam pot and show pot profile' for more information - -- To find statistics about packets for which iOAM options were -added (encapsulating node) and removed (decapsulating node) execute -*show errors* - -Example on encapsulating node: - - - vpp# show error - Count Node Reason - 1208804706 ip6-inacl input ACL hits - 1208804706 ip6-add-hop-by-hop Pkts w/ added ip6 hop-by-hop options - -Example on decapsulating node: - - vpp# show error - Count Node Reason - 69508569 ip6-inacl input ACL hits - 69508569 ip6-pop-hop-by-hop Pkts w/ removed ip6 hop-by-hop options - -- To check the POT profiles use "show pot profile" - -Example: - - vpp# show pot profile - Profile list in use : example - POT Profile at index: 0 - ID : 0 - Validator : False (0) - Secret share : 0x564cdbdec4eb625d (6218586935324795485) - Prime number : 0x7fff0000fa884685 (9223090566081300101) - 2nd polynomial(eval) : 0x23f3a227186a (39529304496234) - LPC : 0x1 (1) - Bit mask : 0x7fffffffffffffff (9223372036854775807) - Profile index in use: 0 - Pkts passed : 0x36 (54) - -- To get statistics of POT for packets use "show ioam pot" - -Example at encapsulating or transit node: - - vpp# show ioam pot - Pkts with ip6 hop-by-hop POT options - 54 - Pkts with ip6 hop-by-hop POT options but no profile set - 0 - Pkts with POT in Policy - 0 - Pkts with POT out of Policy - 0 - - -Example at decapsulating/verification node: - - - vpp# show ioam pot - Pkts with ip6 hop-by-hop POT options - 54 - Pkts with ip6 hop-by-hop POT options but no profile set - 0 - Pkts with POT in Policy - 54 - Pkts with POT out of Policy - 0 - -- Tracing - enable trace of IPv6 packets to view the data inserted and -collected. - -Example when the nodes are receiving data over a DPDK interface: -Enable tracing using "trace add dpdk-input 20" and -execute "show trace" to view the iOAM data collected: - - - vpp# trace add dpdk-input 20 - - vpp# show trace - - ------------------- Start of thread 0 vpp_main ------------------- - - Packet 1 - - 00:00:19:294697: dpdk-input - GigabitEthernetb/0/0 rx queue 0 - buffer 0x10e6b: current data 0, length 214, free-list 0, totlen-nifb 0, trace 0x0 - PKT MBUF: port 0, nb_segs 1, pkt_len 214 - buf_len 2176, data_len 214, ol_flags 0x0, data_off 128, phys_addr 0xe9a35a00 - packet_type 0x0 - IP6: 00:50:56:9c:df:72 -> 00:50:56:9c:be:55 - IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 - tos 0x00, flow label 0x0, hop limit 63, payload length 160 - 00:00:19:294737: ethernet-input - IP6: 00:50:56:9c:df:72 -> 00:50:56:9c:be:55 - 00:00:19:294753: ip6-input - IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 - tos 0x00, flow label 0x0, hop limit 63, payload length 160 - 00:00:19:294757: ip6-lookup - fib 0 adj-idx 15 : indirect via db05::2 flow hash: 0x00000000 - IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 - tos 0x00, flow label 0x0, hop limit 63, payload length 160 - 00:00:19:294802: ip6-hop-by-hop - IP6_HOP_BY_HOP: next index 5 len 96 traced 96 Trace Type 0x1f , 1 elts left - [0] ttl 0x0 node ID 0x0 ingress 0x0 egress 0x0 ts 0x0 - app 0x0 - [1] ttl 0x3e node ID 0x3 ingress 0x1 egress 0x2 ts 0xb68c2213 - app 0x1234 - [2] ttl 0x3f node ID 0x2 ingress 0x1 egress 0x2 ts 0xb68c2204 - app 0x1234 - [3] ttl 0x40 node ID 0x1 ingress 0x5 egress 0x6 ts 0xb68c2200 - app 0x1234 - POT opt present - random = 0x577a916946071950, Cumulative = 0x10b46e78a35a392d, Index = 0x0 - 00:00:19:294810: ip6-rewrite - tx_sw_if_index 1 adj-idx 14 : GigabitEthernetb/0/0 - IP6: 00:50:56:9c:be:55 -> 00:50:56:9c:df:72 flow hash: 0x00000000 - IP6: 00:50:56:9c:be:55 -> 00:50:56:9c:df:72 - IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 - tos 0x00, flow label 0x0, hop limit 62, payload length 160 - 00:00:19:294814: GigabitEthernetb/0/0-output - GigabitEthernetb/0/0 - IP6: 00:50:56:9c:be:55 -> 00:50:56:9c:df:72 - IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 - tos 0x00, flow label 0x0, hop limit 62, payload length 160 - 00:00:19:294820: GigabitEthernetb/0/0-tx - GigabitEthernetb/0/0 tx queue 0 - buffer 0x10e6b: current data 0, length 214, free-list 0, totlen-nifb 0, trace 0x0 - IP6: 00:50:56:9c:be:55 -> 00:50:56:9c:df:72 - - IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 - - tos 0x00, flow label 0x0, hop limit 62, payload length 160 - - -[iOAM-Devnet]: -[iOAM-ietf-requirements]: -[iOAM-ietf-transport]: -[iOAM-ietf-data]: -[iOAM-ietf-proof-of-transit]: diff --git a/plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioamexport/test/IoamExportApiTest.java b/plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioamexport/test/IoamExportApiTest.java deleted file mode 100644 index cb85f005..00000000 --- a/plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioamexport/test/IoamExportApiTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.ioamexport.test; - -import java.net.InetAddress; - -import io.fd.vpp.jvpp.JVpp; -import io.fd.vpp.jvpp.JVppRegistry; -import io.fd.vpp.jvpp.JVppRegistryImpl; -import io.fd.vpp.jvpp.VppCallbackException; -import io.fd.vpp.jvpp.ioamexport.JVppIoamexportImpl; -import io.fd.vpp.jvpp.ioamexport.future.FutureJVppIoamexportFacade; -import io.fd.vpp.jvpp.ioamexport.dto.IoamExportIp6EnableDisable; -import io.fd.vpp.jvpp.ioamexport.dto.IoamExportIp6EnableDisableReply; - -public class IoamExportApiTest { - - public static void main(String[] args) throws Exception { - ioamExportTestApi(); - } - - private static void ioamExportTestApi() throws Exception { - System.out.println("Testing Java API for ioam export plugin"); - try (final JVppRegistry registry = new JVppRegistryImpl("ioamExportApiTest"); - final JVpp jvpp = new JVppIoamexportImpl()) { - FutureJVppIoamexportFacade ioamexportJvpp = new FutureJVppIoamexportFacade(registry,jvpp); - System.out.println("Sending ioam export request..."); - IoamExportIp6EnableDisable request = new IoamExportIp6EnableDisable(); - request.isDisable = 0; - InetAddress collectorAddress = InetAddress.getByName("2001:0DB8:AC10:FE01:0000:0000:0000:0000"); - InetAddress srcAddress = InetAddress.getByName("2001:0DB8:AC10:FE01:0000:0000:0000:0001"); - request.collectorAddress = collectorAddress.getAddress(); - request.srcAddress = srcAddress.getAddress(); - IoamExportIp6EnableDisableReply reply = ioamexportJvpp.ioamExportIp6EnableDisable(request).toCompletableFuture().get(); - System.out.printf("IoamExportIp6EnableDisableReply = "+reply.toString()+"%n"); - - Thread.sleep(1000); - - System.out.println("Disconnecting..."); - } - } -} diff --git a/plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioamexport/test/Readme.txt b/plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioamexport/test/Readme.txt deleted file mode 100644 index 1b38c285..00000000 --- a/plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioamexport/test/Readme.txt +++ /dev/null @@ -1 +0,0 @@ -sudo java -cp build-vpp_debug-native/vpp-api/java/jvpp-registry-17.01.jar:build-vpp_debug-native/plugins/ioam-plugin/jvpp-ioam-export-1.0.jar io.fd.vpp.jvpp.ioamexport.test.IoamExportApiTest diff --git a/plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioampot/test/IoamPotApiTest.java b/plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioampot/test/IoamPotApiTest.java deleted file mode 100644 index 74eb86a1..00000000 --- a/plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioampot/test/IoamPotApiTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.ioampot.test; - -import io.fd.vpp.jvpp.JVpp; -import io.fd.vpp.jvpp.JVppRegistry; -import io.fd.vpp.jvpp.JVppRegistryImpl; -import io.fd.vpp.jvpp.VppCallbackException; -import io.fd.vpp.jvpp.ioampot.JVppIoampotImpl; -import io.fd.vpp.jvpp.ioampot.callback.PotProfileAddCallback; -import io.fd.vpp.jvpp.ioampot.dto.PotProfileAdd; -import io.fd.vpp.jvpp.ioampot.dto.PotProfileAddReply; - -public class IoamPotApiTest { - - static class IoamPotTestCallback implements PotProfileAddCallback { - - @Override - public void onPotProfileAddReply(final PotProfileAddReply reply) { - System.out.printf("Received PotProfileAddReply reply: context=%d%n", - reply.context); - } - - @Override - public void onError(VppCallbackException ex) { - System.out.printf("Received onError exception: call=%s, context=%d, retval=%d%n", ex.getMethodName(), - ex.getCtxId(), ex.getErrorCode()); - } - } - - public static void main(String[] args) throws Exception { - ioamPotTestApi(); - } - - private static void ioamPotTestApi() throws Exception { - System.out.println("Testing Java API for ioam pot plugin"); - try (final JVppRegistry registry = new JVppRegistryImpl("ioamPotApiTest"); - final JVpp jvpp = new JVppIoampotImpl()) { - registry.register(jvpp, new IoamPotTestCallback()); - - System.out.println("Sending ioam pot profile add request..."); - PotProfileAdd request = new PotProfileAdd(); - request.id = 0; - request.validator = 4; - request.secretKey = 1; - request.secretShare = 2; - request.prime = 1234; - request.maxBits = 53; - request.lpc = 1234; - request.polynomialPublic = 1234; - request.listNameLen = (byte)"test pot profile".getBytes().length; - request.listName = "test pot profile".getBytes(); - final int result = jvpp.send(request); - System.out.printf("PotProfileAdd send result = %d%n", result); - - Thread.sleep(1000); - - System.out.println("Disconnecting..."); - } - } -} diff --git a/plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioampot/test/Readme.txt b/plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioampot/test/Readme.txt deleted file mode 100644 index 2323494d..00000000 --- a/plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioampot/test/Readme.txt +++ /dev/null @@ -1 +0,0 @@ -sudo java -cp build-vpp_debug-native/vpp-api/java/jvpp-registry-16.12.jar:build-vpp_debug-native/plugins/ioam-plugin/jvpp-ioam-pot-1.0.jar io.fd.vpp.jvpp.ioampot.test.IoamPotApiTest diff --git a/plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioamtrace/test/IoamTraceApiTest.java b/plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioamtrace/test/IoamTraceApiTest.java deleted file mode 100644 index bc8c1c3a..00000000 --- a/plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioamtrace/test/IoamTraceApiTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.ioamtrace.test; - -import io.fd.vpp.jvpp.JVpp; -import io.fd.vpp.jvpp.JVppRegistry; -import io.fd.vpp.jvpp.JVppRegistryImpl; -import io.fd.vpp.jvpp.VppCallbackException; -import io.fd.vpp.jvpp.ioamtrace.future.FutureJVppIoamtraceFacade; -import io.fd.vpp.jvpp.ioamtrace.JVppIoamtraceImpl; -import io.fd.vpp.jvpp.ioamtrace.callback.TraceProfileAddCallback; -import io.fd.vpp.jvpp.ioamtrace.dto.TraceProfileAdd; -import io.fd.vpp.jvpp.ioamtrace.dto.TraceProfileAddReply; -import io.fd.vpp.jvpp.ioamtrace.dto.TraceProfileShowConfig; -import io.fd.vpp.jvpp.ioamtrace.dto.TraceProfileShowConfigReply; - -public class IoamTraceApiTest { - - static class IoamTraceTestCallback implements TraceProfileAddCallback { - - @Override - public void onTraceProfileAddReply(final TraceProfileAddReply reply) { - System.out.printf("Received TraceProfileAddReply reply: context=%d%n", - reply.context); - } - - @Override - public void onError(VppCallbackException ex) { - System.out.printf("Received onError exception: call=%s, context=%d, retval=%d%n", ex.getMethodName(), - ex.getCtxId(), ex.getErrorCode()); - } - } - - public static void main(String[] args) throws Exception { - ioamTraceTestApi(); - } - - private static void ioamTraceTestApi() throws Exception { - System.out.println("Testing Java API for ioam trace plugin"); - try (final JVppRegistry registry = new JVppRegistryImpl("ioamTraceApiTest"); - final JVpp jvpp = new JVppIoamtraceImpl()) { - FutureJVppIoamtraceFacade ioamtraceJvpp = new FutureJVppIoamtraceFacade(registry,jvpp); - - System.out.println("Sending ioam trace profile add request..."); - TraceProfileAdd request = new TraceProfileAdd(); - request.traceType = 0x1f; - request.numElts = 4; - request.nodeId = 1; - request.traceTsp = 2; - request.appData = 1234; - final int result = jvpp.send(request); - System.out.printf("TraceProfileAdd send result = %d%n", result); - - Thread.sleep(1000); - - TraceProfileShowConfig showRequest = new TraceProfileShowConfig(); - TraceProfileShowConfigReply reply = ioamtraceJvpp.traceProfileShowConfig(showRequest).toCompletableFuture().get(); - System.out.printf("TraceProfileShowConfig result = "+ reply.toString()); - - System.out.println("Disconnecting..."); - } - } -} diff --git a/plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioamtrace/test/Readme.txt b/plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioamtrace/test/Readme.txt deleted file mode 100644 index 17e45a81..00000000 --- a/plugins/ioam-plugin/ioam/jvpp/io/fd/vpp/jvpp/ioamtrace/test/Readme.txt +++ /dev/null @@ -1 +0,0 @@ -sudo java -cp build-vpp-native/vpp-api/java/jvpp-registry-17.01.jar:build-vpp-native/plugins/ioam-plugin/jvpp-ioam-trace-1.0.jar io.fd.vpp.jvpp.ioamtrace.test.IoamTraceApiTest diff --git a/plugins/ioam-plugin/ioam/lib-pot/jvpp_ioam_pot.c b/plugins/ioam-plugin/ioam/lib-pot/jvpp_ioam_pot.c deleted file mode 100644 index a60ae60f..00000000 --- a/plugins/ioam-plugin/ioam/lib-pot/jvpp_ioam_pot.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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. - */ - -#include - -#include -#define vl_typedefs /* define message structures */ -#include -#undef vl_typedefs - -#define vl_endianfun -#include -#undef vl_endianfun - -#define vl_print(handle, ...) -#define vl_printfun -#include -#undef vl_printfun - -/* Get the API version number */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#undef vl_api_version - -#include -#include -#include - -#if VPPJNI_DEBUG == 1 - #define DEBUG_LOG(...) clib_warning(__VA_ARGS__) -#else - #define DEBUG_LOG(...) -#endif - -#include - -#include "ioam/jvpp/io_fd_vpp_jvpp_ioampot_JVppIoampotImpl.h" -#include "jvpp_ioam_pot.h" -#include "ioam/jvpp/jvpp_ioam_pot_gen.h" - -/* - * Class: io_fd_vpp_jvpp_ioampot_JVppIoampotImpl - * Method: init0 - * Signature: (JI)V - */ -JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_ioampot_JVppIoampotImpl_init0 - (JNIEnv *env, jclass clazz, jobject callback, jlong queue_address, jint my_client_index) { - ioampot_main_t * plugin_main = &ioampot_main; - u8 * name; - clib_warning ("Java_io_fd_vpp_jvpp_ioampot_JVppIoampotImpl_init0"); - - plugin_main->my_client_index = my_client_index; - plugin_main->vl_input_queue = (unix_shared_memory_queue_t *)queue_address; - - name = format (0, "ioam_pot_%08x%c", api_version, 0); - plugin_main->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name); - - if (plugin_main->msg_id_base == (u16) ~0) { - jclass exClass = (*env)->FindClass(env, "java/lang/IllegalStateException"); - (*env)->ThrowNew(env, exClass, "ioam_pot plugin is not loaded in VPP"); - } else { - plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback); - plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback)); - - #define _(N,n) \ - vl_msg_api_set_handlers(VL_API_##N + plugin_main->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_api_reply_handler; - #undef _ - } -} - -JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_ioampot_JVppIoampotImpl_close0 -(JNIEnv *env, jclass clazz) { - ioampot_main_t * plugin_main = &ioampot_main; - - // cleanup: - (*env)->DeleteGlobalRef(env, plugin_main->callbackClass); - (*env)->DeleteGlobalRef(env, plugin_main->callbackObject); - - plugin_main->callbackClass = NULL; - plugin_main->callbackObject = NULL; -} - -/* Attach thread to JVM and cache class references when initiating JVPP iOAM POT */ -jint JNI_OnLoad(JavaVM *vm, void *reserved) { - JNIEnv* env; - - if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { - return JNI_EVERSION; - } - - if (cache_class_references(env) != 0) { - clib_warning ("Failed to cache class references\n"); - return JNI_ERR; - } - - return JNI_VERSION_1_8; -} - -/* Clean up cached references when disposing JVPP iOAM POT */ -void JNI_OnUnload(JavaVM *vm, void *reserved) { - JNIEnv* env; - if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { - return; - } - delete_class_references(env); -} diff --git a/plugins/ioam-plugin/ioam/lib-pot/jvpp_ioam_pot.h b/plugins/ioam-plugin/ioam/lib-pot/jvpp_ioam_pot.h deleted file mode 100644 index 00aa51db..00000000 --- a/plugins/ioam-plugin/ioam/lib-pot/jvpp_ioam_pot.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - */ -#ifndef __included_jvpp_ioam_pot_h__ -#define __included_jvpp_ioam_pot_h__ - -#include -#include -#include -#include -#include -#include - -/* Global state for JVPP-IOAM-POT */ -typedef struct { - /* Base message index for the pot plugin */ - u16 msg_id_base; - - /* Pointer to shared memory queue */ - unix_shared_memory_queue_t * vl_input_queue; - - /* VPP api client index */ - u32 my_client_index; - - /* Callback object and class references enabling asynchronous Java calls */ - jobject callbackObject; - jclass callbackClass; - -} ioampot_main_t; - -ioampot_main_t ioampot_main __attribute__((aligned (64))); - - -#endif /* __included_jvpp_ioam_pot_h__ */ diff --git a/plugins/ioam-plugin/ioam/lib-pot/math64.h b/plugins/ioam-plugin/ioam/lib-pot/math64.h deleted file mode 100644 index 4c608a37..00000000 --- a/plugins/ioam-plugin/ioam/lib-pot/math64.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * math64.h provides the 64 bit unsigned integer add, multiply followed by modulo operation - * The linux/math64.h provides divide and multiply 64 bit integers but: - * 1. multiply: mul_u64_u64_shr - only returns 64 bits of the result and has to be called - * twice to get the complete 128 bits of the result. - * 2. Modulo operation of the result of addition and multiplication of u64 that may result - * in integers > 64 bits is not supported - * Hence this header to combine add/multiply followed by modulo of u64 integrers - * always resulting in u64. - * - * 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. - */ -#ifndef include_vnet_math64_h -#define include_vnet_math64_h -#include - -/* - * multiplies and returns result in hi and lo - */ -static inline void mul64by64(u64 a, u64 b, u64 * hi, u64 * lo) -{ - u64 a_lo = (u64) (uint32_t) a; - u64 a_hi = a >> 32; - u64 b_lo = (u64) (u32) b; - u64 b_hi = b >> 32; - - u64 p0 = a_lo * b_lo; - u64 p1 = a_lo * b_hi; - u64 p2 = a_hi * b_lo; - u64 p3 = a_hi * b_hi; - - u32 cy = (u32) (((p0 >> 32) + (u32) p1 + (u32) p2) >> 32); - - *lo = p0 + (p1 << 32) + (p2 << 32); - *hi = p3 + (p1 >> 32) + (p2 >> 32) + cy; - return; -} - -#define TWO64 18446744073709551616.0 - -static inline u64 mod128by64(u64 x, u64 y, u64 m, double di) -{ - u64 q1, q2, q; - u64 p1, p0; - double dq; - - /* calculate quotient first pass 53 bits */ - dq = (TWO64 * (double)x + (double)y) * di; - - if (dq >= TWO64) - q1 = 0xfffffffffffff800L; - else - q1 = dq; - - /* q1 * m to compare the product to the dividend. */ - mul64by64(q1, m, &p1, &p0); - - /* Adjust quotient. is it > actual result: */ - if (x < p1 || (x == p1 && y < p0)) - { - /* q1 > quotient. calculate abs remainder */ - x = p1 - (x + (p0 < y)); - y = p0 - y; - - /* use the remainder as new dividend to adjust quotient */ - q2 = (u64) ((TWO64 * (double)x + (double)y) * di); - mul64by64(q2, m, &p1, &p0); - - q = q1 - q2; - if (x < p1 || (x == p1 && y <= p0)) - { - y = p0 - y; - } - else - { - y = p0 - y; - y += m; - q--; - } - } - else - { - x = x - (p1 + (y < p0)); - y = y - p0; - - q2 = (u64) ((TWO64 * (double)x + (double)y) * di); - mul64by64(q2, m, &p1, &p0); - - q = q1 + q2; - if (x < p1 || (x == p1 && y < p0)) - { - y = y - p0; - y += m; - q--; - } - else - { - y = y - p0; - if (y >= m) - { - y -= m; - q++; - } - } - } - - return y; -} - -/* - * returns a % p - */ -static inline u64 mod64by64(u64 a, u64 p, u64 primeinv) -{ - return (mod128by64(0, a, p, primeinv)); -} - -static inline void add64(u64 a, u64 b, u64 * whi, u64 * wlo) -{ - *wlo = a + b; - if (*wlo < a) - *whi = 1; - -} - -/* - * returns (a + b)%p - */ -static inline u64 add64_mod(u64 a, u64 b, u64 p, double pi) -{ - u64 shi = 0, slo = 0; - - add64(a, b, &shi, &slo); - return (mod128by64(shi, slo, p, pi)); -} - -/* - * returns (ab) % p - */ -static inline u64 mul64_mod(u64 a, u64 b, u64 p, double pi) -{ - u64 phi = 0, plo = 0; - - mul64by64(a, b, &phi, &plo); - return (mod128by64(phi, plo, p, pi)); -} - -#endif diff --git a/plugins/ioam-plugin/ioam/lib-pot/pot.api b/plugins/ioam-plugin/ioam/lib-pot/pot.api deleted file mode 100644 index fa2fc126..00000000 --- a/plugins/ioam-plugin/ioam/lib-pot/pot.api +++ /dev/null @@ -1,133 +0,0 @@ -/* Hey Emacs use -*- mode: C -*- */ -/* - * 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. - */ - - -/** \brief Proof of Transit(POT): Set POT profile - @param id - id of the profile - @param validator - True/False to indicate if this is verifier - @param secret_key - Verification key - @param secret_share - Share of the 1st polynomial - @param prime - Prime number used for modulo operation - @param max_bits - Max bits to be used for Random number generation - @param lpc - Lagrange basis polynomial - @param polynomial_public - pre-evaluated public polynomial - @param list_name_len - length of the name of this profile list - @param list_name - name of this profile list -*/ -define pot_profile_add { - u32 client_index; - u32 context; - u8 id; - u8 validator; - u64 secret_key; - u64 secret_share; - u64 prime; - u8 max_bits; - u64 lpc; - u64 polynomial_public; - u8 list_name_len; - u8 list_name[0]; -}; - -/** \brief Proof of Transit profile add / del response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define pot_profile_add_reply { - u32 context; - i32 retval; -}; - - -/** \brief Proof of Transit(POT): Activate POT profile in the list - @param id - id of the profile - @param list_name_len - length of the name of this profile list - @param list_name - name of this profile list -*/ -define pot_profile_activate { - u32 client_index; - u32 context; - u8 id; - u8 list_name_len; - u8 list_name[0]; -}; - -/** \brief Proof of Transit profile activate response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define pot_profile_activate_reply { - u32 context; - i32 retval; -}; - -/** \brief Delete POT Profile - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param list_name_len - length of the name of the profile list - @param list_name - name of profile list to delete -*/ -define pot_profile_del { - u32 client_index; - u32 context; - u8 list_name_len; - u8 list_name[0]; -}; - -/** \brief Proof of Transit profile add / del response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define pot_profile_del_reply { - u32 context; - i32 retval; -}; - -/** \brief Show POT Profiles - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param id - id of the profile -*/ -define pot_profile_show_config_dump { - u32 client_index; - u32 context; - u8 id; -}; - -/** \brief Show POT profile reply - @param id - id of the profile - @param validator - True/False to indicate if this is verifier - @param secret_key - Verification key - @param secret_share - Share of the 1st polynomial - @param prime - Prime number used for modulo operation - @param max_bits - Max bits to be used for Random number generation - @param lpc - Lagrange basis polynomial - @param polynomial_public - pre-evaluated public polynomial - @param list_name_len - length of the name of this profile list - @param list_name - name of this profile list -*/ -define pot_profile_show_config_details { - u32 context; - i32 retval; - u8 id; - u8 validator; - u64 secret_key; - u64 secret_share; - u64 prime; - u64 bit_mask; - u64 lpc; - u64 polynomial_public; -}; diff --git a/plugins/ioam-plugin/ioam/lib-pot/pot_all_api_h.h b/plugins/ioam-plugin/ioam/lib-pot/pot_all_api_h.h deleted file mode 100644 index 63967c45..00000000 --- a/plugins/ioam-plugin/ioam/lib-pot/pot_all_api_h.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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. - */ -/* Include the generated file, see BUILT_SOURCES in Makefile.am */ -#include diff --git a/plugins/ioam-plugin/ioam/lib-pot/pot_api.c b/plugins/ioam-plugin/ioam/lib-pot/pot_api.c deleted file mode 100644 index d3af7b40..00000000 --- a/plugins/ioam-plugin/ioam/lib-pot/pot_api.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - * 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. - */ -/* - *------------------------------------------------------------------ - * pot_api.c - Proof of Transit related APIs to create - * and maintain profiles - *------------------------------------------------------------------ - */ - -#include -#include -#include - -#include -#include -#include - -/* define message IDs */ -#include - -/* define message structures */ -#define vl_typedefs -#include -#undef vl_typedefs - -/* define generated endian-swappers */ -#define vl_endianfun -#include -#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 -#undef vl_printfun - -/* Get the API version number */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#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); - -#define REPLY_MACRO2(t, body) \ -do { \ - unix_shared_memory_queue_t * q; \ - rv = vl_msg_api_pd_handler (mp, rv); \ - 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); \ - do {body;} while (0); \ - vl_msg_api_send_shmem (q, (u8 *)&rmp); \ -} while(0); - -/* List of message types that this plugin understands */ - -#define foreach_pot_plugin_api_msg \ -_(POT_PROFILE_ADD, pot_profile_add) \ -_(POT_PROFILE_ACTIVATE, pot_profile_activate) \ -_(POT_PROFILE_DEL, pot_profile_del) \ -_(POT_PROFILE_SHOW_CONFIG_DUMP, pot_profile_show_config_dump) \ - -static void vl_api_pot_profile_add_t_handler -(vl_api_pot_profile_add_t *mp) -{ - pot_main_t * sm = &pot_main; - int rv = 0; - vl_api_pot_profile_add_reply_t * rmp; - u8 id; - pot_profile *profile = NULL; - u8 *name = 0; - - if (mp->list_name_len) - name = format(0, "%s", mp->list_name); - - pot_profile_list_init(name); - id = mp->id; - profile = pot_profile_find(id); - if (profile) { - rv = pot_profile_create(profile, - clib_net_to_host_u64(mp->prime), - clib_net_to_host_u64(mp->polynomial_public), - clib_net_to_host_u64(mp->lpc), - clib_net_to_host_u64(mp->secret_share)); - if (rv != 0) - goto ERROROUT; - if (1 == mp->validator) - (void)pot_set_validator(profile, clib_net_to_host_u64(mp->secret_key)); - (void)pot_profile_set_bit_mask(profile, mp->max_bits); - } else { - rv = -3; - } - ERROROUT: - vec_free(name); - REPLY_MACRO(VL_API_POT_PROFILE_ADD_REPLY); -} - -static void send_pot_profile_details(vl_api_pot_profile_show_config_dump_t *mp, u8 id) -{ - vl_api_pot_profile_show_config_details_t * rmp; - pot_main_t * sm = &pot_main; - pot_profile *profile = pot_profile_find(id); - int rv = 0; - if(profile){ - REPLY_MACRO2(VL_API_POT_PROFILE_SHOW_CONFIG_DETAILS, - rmp->id=id; - rmp->validator=profile->validator; - rmp->secret_key=clib_host_to_net_u64(profile->secret_key); - rmp->secret_share=clib_host_to_net_u64(profile->secret_share); - rmp->prime=clib_host_to_net_u64(profile->prime); - rmp->bit_mask=clib_host_to_net_u64(profile->bit_mask); - rmp->lpc=clib_host_to_net_u64(profile->lpc); - rmp->polynomial_public=clib_host_to_net_u64(profile->poly_pre_eval); - ); - } - else{ - REPLY_MACRO2(VL_API_POT_PROFILE_SHOW_CONFIG_DETAILS, - rmp->id=id; - rmp->validator=0; - rmp->secret_key=0; - rmp->secret_share=0; - rmp->prime=0; - rmp->bit_mask=0; - rmp->lpc=0; - rmp->polynomial_public=0; - ); - } -} - -static void vl_api_pot_profile_show_config_dump_t_handler -(vl_api_pot_profile_show_config_dump_t *mp) -{ - u8 id = mp->id; - u8 dump_call_id = ~0; - if(dump_call_id==id){ - for(id=0;idlist_name_len) - name = format(0, "%s", mp->list_name); - if (!pot_profile_list_is_enabled(name)) { - rv = -1; - } else { - id = mp->id; - rv = pot_profile_set_active(id); - } - - vec_free(name); - REPLY_MACRO(VL_API_POT_PROFILE_ACTIVATE_REPLY); -} - - -static void vl_api_pot_profile_del_t_handler -(vl_api_pot_profile_del_t *mp) -{ - pot_main_t * sm = &pot_main; - int rv = 0; - vl_api_pot_profile_del_reply_t * rmp; - - clear_pot_profiles(); - - REPLY_MACRO(VL_API_POT_PROFILE_DEL_REPLY); -} - - -/* - * 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) -{ - pot_main_t * sm = &pot_main; - clib_error_t * error = 0; - - sm->vlib_main = vm; - sm->vnet_main = h->vnet_main; - return error; -} - -/* Set up the API message handling tables */ -static clib_error_t * -pot_plugin_api_hookup (vlib_main_t *vm) -{ - pot_main_t * sm = &pot_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_pot_plugin_api_msg; -#undef _ - - return 0; -} - -#define vl_msg_name_crc_list -#include -#undef vl_msg_name_crc_list - -static void -setup_message_id_table (pot_main_t * sm, api_main_t * am) -{ -#define _(id,n,crc) \ - vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base); - foreach_vl_msg_name_crc_pot; -#undef _ -} - -static clib_error_t * pot_init (vlib_main_t * vm) -{ - pot_main_t * sm = &pot_main; - clib_error_t * error = 0; - u8 * name; - - bzero(sm, sizeof(pot_main)); - (void)pot_util_init(); - name = format (0, "ioam_pot_%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 = pot_plugin_api_hookup (vm); - - /* Add our API messages to the global name_crc hash table */ - setup_message_id_table (sm, &api_main); - - vec_free(name); - - return error; -} - -VLIB_INIT_FUNCTION (pot_init); diff --git a/plugins/ioam-plugin/ioam/lib-pot/pot_msg_enum.h b/plugins/ioam-plugin/ioam/lib-pot/pot_msg_enum.h deleted file mode 100644 index a4a88bed..00000000 --- a/plugins/ioam-plugin/ioam/lib-pot/pot_msg_enum.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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. - */ -#ifndef included_pot_msg_enum_h -#define included_pot_msg_enum_h - -#include - -#define vl_msg_id(n,h) n, -typedef enum { -#include - /* 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_pot_msg_enum_h */ diff --git a/plugins/ioam-plugin/ioam/lib-pot/pot_test.c b/plugins/ioam-plugin/ioam/lib-pot/pot_test.c deleted file mode 100644 index 2e870238..00000000 --- a/plugins/ioam-plugin/ioam/lib-pot/pot_test.c +++ /dev/null @@ -1,365 +0,0 @@ -/* - * 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. - */ -/* - *------------------------------------------------------------------ - * pot_test.c - test harness for pot plugin - *------------------------------------------------------------------ - */ - -#include -#include -#include -#include -#include - -/* Declare message IDs */ -#include - -/* define message structures */ -#define vl_typedefs -#include -#undef vl_typedefs - -/* declare message handlers for each api */ - -#define vl_endianfun /* define message structures */ -#include -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) -#define vl_printfun -#include -#undef vl_printfun - -/* Get the API version number. */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#undef vl_api_version - - -typedef struct { - /* API message ID base */ - u16 msg_id_base; - vat_main_t *vat_main; -} pot_test_main_t; - -pot_test_main_t pot_test_main; - -#define foreach_standard_reply_retval_handler \ -_(pot_profile_add_reply) \ -_(pot_profile_activate_reply) \ -_(pot_profile_del_reply) - -#define foreach_custom_reply_retval_handler \ -_(pot_profile_show_config_details, \ - errmsg(" ID:%d\n",mp->id); \ - errmsg(" Validator:%d\n",mp->validator); \ - errmsg(" secret_key:%Lx\n",clib_net_to_host_u64(mp->secret_key)); \ - errmsg(" secret_share:%Lx\n",clib_net_to_host_u64(mp->secret_share)); \ - errmsg(" prime:%Lx\n",clib_net_to_host_u64(mp->prime)); \ - errmsg(" bitmask:%Lx\n",clib_net_to_host_u64(mp->bit_mask)); \ - errmsg(" lpc:%Lx\n",clib_net_to_host_u64(mp->lpc)); \ - errmsg(" public poly:%Lx\n",clib_net_to_host_u64(mp->polynomial_public)); \ - ) - -#define _(n) \ - static void vl_api_##n##_t_handler \ - (vl_api_##n##_t * mp) \ - { \ - vat_main_t * vam = pot_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 _ - -#define _(n,body) \ - static void vl_api_##n##_t_handler \ - (vl_api_##n##_t * mp) \ - { \ - vat_main_t * vam = pot_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; \ - } \ - do{body;}while(0); \ - } -foreach_custom_reply_retval_handler; -#undef _ - -/* - * Table of message reply handlers, must include boilerplate handlers - * we just generated - */ -#define foreach_vpe_api_reply_msg \ -_(POT_PROFILE_ADD_REPLY, pot_profile_add_reply) \ -_(POT_PROFILE_ACTIVATE_REPLY, pot_profile_activate_reply) \ -_(POT_PROFILE_DEL_REPLY, pot_profile_del_reply) \ -_(POT_PROFILE_SHOW_CONFIG_DETAILS, pot_profile_show_config_details) - - -/* 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_pot_profile_add (vat_main_t *vam) -{ -#define MAX_BITS 64 - pot_test_main_t * sm = &pot_test_main; - unformat_input_t *input = vam->input; - vl_api_pot_profile_add_t *mp; - u8 *name = NULL; - u64 prime = 0; - u64 secret_share = 0; - u64 secret_key = 0; - u32 bits = MAX_BITS; - u64 lpc = 0, poly2 = 0; - f64 timeout; - u8 id = 0; - int rv = 0; - - while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) - { - if (unformat(input, "name %s", &name)) - ; - else if(unformat(input, "id %d", &id)) - ; - else if (unformat(input, "validator-key 0x%Lx", &secret_key)) - ; - else if (unformat(input, "prime-number 0x%Lx", &prime)) - ; - else if (unformat(input, "secret-share 0x%Lx", &secret_share)) - ; - else if (unformat(input, "polynomial-public 0x%Lx", &poly2)) - ; - else if (unformat(input, "lpc 0x%Lx", &lpc)) - ; - else if (unformat(input, "bits-in-random %u", &bits)) - { - if (bits > MAX_BITS) - bits = MAX_BITS; - } - else - break; - } - - if (!name) - { - errmsg ("name required\n"); - rv = -99; - goto OUT; - } - - M2(POT_PROFILE_ADD, pot_profile_add, vec_len(name)); - - mp->list_name_len = vec_len(name); - clib_memcpy(mp->list_name, name, mp->list_name_len); - mp->secret_share = clib_host_to_net_u64(secret_share); - mp->polynomial_public = clib_host_to_net_u64(poly2); - mp->lpc = clib_host_to_net_u64(lpc); - mp->prime = clib_host_to_net_u64(prime); - if (secret_key != 0) - { - mp->secret_key = clib_host_to_net_u64(secret_key); - mp->validator = 1; - } - else - { - mp->validator = 0; - } - mp->id = id; - mp->max_bits = bits; - - S; W; - -OUT: - vec_free(name); - return(rv); -} - -static int api_pot_profile_activate (vat_main_t *vam) -{ -#define MAX_BITS 64 - pot_test_main_t * sm = &pot_test_main; - unformat_input_t *input = vam->input; - vl_api_pot_profile_activate_t *mp; - u8 *name = NULL; - u8 id = 0; - int rv = 0; - f64 timeout; - - while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) - { - if (unformat(input, "name %s", &name)) - ; - else if(unformat(input, "id %d", &id)) - ; - else - break; - } - - if (!name) - { - errmsg ("name required\n"); - rv = -99; - goto OUT; - } - - M2(POT_PROFILE_ACTIVATE, pot_profile_activate, vec_len(name)); - - mp->list_name_len = vec_len(name); - clib_memcpy(mp->list_name, name, mp->list_name_len); - mp->id = id; - - S; W; - -OUT: - vec_free(name); - return(rv); -} - - -static int api_pot_profile_del (vat_main_t *vam) -{ - pot_test_main_t * sm = &pot_test_main; - vl_api_pot_profile_del_t *mp; - f64 timeout; - - M(POT_PROFILE_DEL, pot_profile_del); - mp->list_name_len = 0; - S; W; - return 0; -} - -static int api_pot_profile_show_config_dump (vat_main_t *vam) -{ - pot_test_main_t * sm = &pot_test_main; - unformat_input_t *input = vam->input; - vl_api_pot_profile_show_config_dump_t *mp; - f64 timeout; - u8 id = 0; - - while(unformat_check_input(input) != UNFORMAT_END_OF_INPUT) - { - if(unformat(input,"id %d",&id)); - else - break; - } - M(POT_PROFILE_SHOW_CONFIG_DUMP, pot_profile_show_config_dump); - - mp->id = id; - - S; W; - return 0; -} - -/* - * List of messages that the api test plugin sends, - * and that the data plane plugin processes - */ -#define foreach_vpe_api_msg \ -_(pot_profile_add, "name id [0-1] " \ - "prime-number <0xu64> bits-in-random [0-64] " \ - "secret-share <0xu64> lpc <0xu64> polynomial-public <0xu64> " \ - "[validator-key <0xu64>] [validity <0xu64>]") \ -_(pot_profile_activate, "name id [0-1] ") \ -_(pot_profile_del, "[id ]") \ -_(pot_profile_show_config_dump, "id [0-1]") - -void vat_api_hookup (vat_main_t *vam) -{ - pot_test_main_t * sm = &pot_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) -{ - pot_test_main_t * sm = &pot_test_main; - u8 * name; - - sm->vat_main = vam; - - name = format (0, "ioam_pot_%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/plugins/ioam-plugin/ioam/lib-pot/pot_util.c b/plugins/ioam-plugin/ioam/lib-pot/pot_util.c deleted file mode 100644 index a253ad41..00000000 --- a/plugins/ioam-plugin/ioam/lib-pot/pot_util.c +++ /dev/null @@ -1,445 +0,0 @@ -/* - * 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. - */ -#include -#include -#include -#include -#include -#include "math64.h" -#include "pot_util.h" - -pot_main_t pot_main; - -static void pot_profile_cleanup(pot_profile *profile); - -static void pot_main_profiles_reset (void) -{ - pot_main_t *sm = &pot_main; - int i = 0; - - for (i = 0; i < MAX_POT_PROFILES; i++) - { - pot_profile_cleanup(&(sm->profile_list[i])); - } - sm->active_profile_id = 0; - if (sm->profile_list_name) - vec_free(sm->profile_list_name); - sm->profile_list_name = NULL; -} - -int pot_util_init (void) -{ - pot_main_profiles_reset(); - - return(0); -} - -static void pot_profile_init(pot_profile * new, u8 id) -{ - if (new) - { - memset(new, 0, sizeof(pot_profile)); - new->id = id; - } -} - -pot_profile *pot_profile_find(u8 id) -{ - pot_main_t *sm = &pot_main; - - if (id < MAX_POT_PROFILES) - { - return (&(sm->profile_list[id])); - } - return (NULL); -} -static int pot_profile_name_equal (u8 *name0, u8 *name1) -{ - int len0, len1; - - len0 = vec_len (name0); - len1 = vec_len (name1); - if (len0 != len1) - return(0); - return (0==strncmp ((char *) name0, (char *)name1, len0)); -} - -int pot_profile_list_is_enabled (u8 *name) -{ - pot_main_t *sm = &pot_main; - return (pot_profile_name_equal(sm->profile_list_name, name)); -} - -void pot_profile_list_init(u8 * profile_list_name) -{ - pot_main_t *sm = &pot_main; - int i = 0; - - /* If it is the same profile list skip reset */ - if (pot_profile_name_equal(sm->profile_list_name, profile_list_name)) - { - return; - } - - pot_main_profiles_reset(); - if (vec_len(profile_list_name)) - sm->profile_list_name = (u8 *)vec_dup(profile_list_name); - else - sm->profile_list_name = 0; - sm->active_profile_id = 0; - - for (i = 0; i < MAX_POT_PROFILES; i++) - { - pot_profile_init(&(sm->profile_list[i]), i); - } -} - -static void pot_profile_cleanup(pot_profile * profile) -{ - u16 id = profile->id; - - memset(profile, 0, sizeof(pot_profile)); - profile->id = id; /* Restore id alone */ -} - -int pot_profile_create(pot_profile * profile, u64 prime, - u64 poly2, u64 lpc, u64 secret_share) -{ - if (profile && !profile->in_use) - { - pot_profile_cleanup(profile); - profile->prime = prime; - profile->primeinv = 1.0 / prime; - profile->lpc = lpc; - profile->poly_pre_eval = poly2; - profile->secret_share = secret_share; - profile->total_pkts_using_this_profile = 0; - profile->valid = 1; - return(0); - } - - return(-1); -} - -int pot_set_validator(pot_profile * profile, u64 key) -{ - if (profile && !profile->in_use) - { - profile->validator = 1; - profile->secret_key = key; - return(0); - } - return(-1); -} - -always_inline u64 pot_update_cumulative_inline(u64 cumulative, u64 random, - u64 secret_share, u64 prime, u64 lpc, u64 pre_split, double prime_inv) -{ - u64 share_random = 0; - u64 cumulative_new = 0; - - /* - * calculate split share for random - */ - share_random = add64_mod(pre_split, random, prime, prime_inv); - - /* - * lpc * (share_secret + share_random) - */ - share_random = add64_mod(share_random, secret_share, prime, prime_inv); - share_random = mul64_mod(share_random, lpc, prime, prime_inv); - - cumulative_new = add64_mod(cumulative, share_random, prime, prime_inv); - - return (cumulative_new); -} - -u64 pot_update_cumulative(pot_profile * profile, u64 cumulative, u64 random) -{ - if (profile && profile->valid != 0) - { - return (pot_update_cumulative_inline(cumulative, random, profile->secret_share, - profile->prime, profile->lpc, profile->poly_pre_eval, - profile->primeinv)); - } - return (0); -} - -always_inline u8 pot_validate_inline(u64 secret, u64 prime, double prime_inv, - u64 cumulative, u64 random) -{ - if (cumulative == (random + secret)) - { - return (1); - } - else if (cumulative == add64_mod(random, secret, prime, prime_inv)) - { - return (1); - } - return (0); -} - -/* - * return True if the cumulative matches secret from a profile - */ -u8 pot_validate(pot_profile * profile, u64 cumulative, u64 random) -{ - if (profile && profile->validator) - { - return (pot_validate_inline(profile->secret_key, profile->prime, - profile->primeinv, cumulative, random)); - } - return (0); -} - -/* - * Utility function to get random number per pack - */ -u64 pot_generate_random(pot_profile * profile) -{ - u64 random = 0; - int32_t second_half; - static u32 seed = 0; - - if (PREDICT_FALSE(!seed)) - seed = random_default_seed(); - - /* - * Upper 4 bytes seconds - */ - random = (u64) time(NULL); - - random &= 0xffffffff; - random = random << 32; - /* - * Lower 4 bytes random number - */ - second_half = random_u32(&seed); - - random |= second_half; - - if (PREDICT_TRUE(profile != NULL)) - { - random &= profile->bit_mask; - } - return (random); -} - -int pot_profile_set_bit_mask(pot_profile * profile, u16 bits) -{ - int sizeInBits; - - if (profile && !profile->in_use) - { - sizeInBits = sizeof(profile->bit_mask) * 8; - profile->bit_mask = - (bits >= - sizeInBits ? (u64) - 1 : (u64) ((u64) 1 << (u64) bits) - 1); - return(0); - } - return(-1); -} - -clib_error_t *clear_pot_profile_command_fn(vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - - pot_main_profiles_reset(); - - return 0; -} - -void clear_pot_profiles() -{ - clear_pot_profile_command_fn(0, 0, 0); -} - -VLIB_CLI_COMMAND(clear_pot_profile_command) = -{ -.path = "clear pot profile", -.short_help = "clear pot profile [|all]", -.function = clear_pot_profile_command_fn, -}; - -static clib_error_t *set_pot_profile_command_fn(vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - u64 prime; - u64 secret_share; - u64 secret_key; - u8 validator = 0; - u32 profile_id = ~0; - u32 bits; - u64 lpc = 0, poly2 = 0; - pot_profile *profile = NULL; - u8 *profile_list_name = NULL; - - bits = MAX_BITS; - - while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) - { - if (unformat(input, "name %s", - &profile_list_name)); - else if (unformat(input, "id %d", &profile_id)) - ; - else if (unformat(input, "validate-key 0x%Lx", &secret_key)) - validator = 1; - else if (unformat(input, "prime-number 0x%Lx", &prime)) - ; - else if (unformat(input, "secret_share 0x%Lx", &secret_share)) - ; - else if (unformat(input, "polynomial2 0x%Lx", &poly2)) - ; - else if (unformat(input, "lpc 0x%Lx", &lpc)) - ; - else if (unformat(input, "bits-in-random %d", &bits)) - { - if (bits > MAX_BITS) - bits = MAX_BITS; - } - else - break; - } - if (profile_list_name == 0) - { - return clib_error_return(0, "Name cannot be null"); - } - pot_profile_list_init(profile_list_name); - profile = pot_profile_find(profile_id); - - if (profile) - { - pot_profile_create(profile, prime, poly2, lpc, secret_share); - if (validator) - pot_set_validator(profile, secret_key); - pot_profile_set_bit_mask(profile, bits); - } - vec_free(profile_list_name); - return 0; -} - -VLIB_CLI_COMMAND(set_pot_profile_command) = -{ -.path = "set pot profile", -.short_help = "set pot profile name id [0-1] [validator-key 0xu64] \ - prime-number 0xu64 secret_share 0xu64 lpc 0xu64 \ - polynomial2 0xu64 bits-in-random [0-64] ", -.function = set_pot_profile_command_fn, -}; - -static clib_error_t *set_pot_profile_activate_command_fn(vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - pot_main_t *sm = &pot_main; - u8 *profile_list_name = NULL; - u32 id = 0; - clib_error_t *result = NULL; - - while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) - { - if (unformat(input, "name %s", - &profile_list_name)); - else if (unformat(input, "id %d", &id)) - ; - else - return clib_error_return(0, "unknown input `%U'", - format_unformat_error, input); - } - if (profile_list_name == 0) - { - return clib_error_return(0, "Name cannot be null"); - } - - if (!pot_profile_list_is_enabled(profile_list_name)) { - result = clib_error_return(0, "%s list is not enabled, profile in use %s", - profile_list_name, sm->profile_list_name); - } else if (0 != pot_profile_set_active((u8)id)) { - result = clib_error_return(0, "Profile %d not defined in %s", - id, sm->profile_list_name); - } - vec_free(profile_list_name); - return result; -} - -VLIB_CLI_COMMAND(set_pot_profile_activate_command) = -{ -.path = "set pot profile-active", -.short_help = "set pot profile-active name id [0-1]", -.function = set_pot_profile_activate_command_fn, -}; - -static clib_error_t *show_pot_profile_command_fn(vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - pot_main_t *sm = &pot_main; - pot_profile *p = NULL; - u16 i; - u8 *s = 0; - - if (vec_len(sm->profile_list_name) == 0) - { - s = format(s, "POT Profiles not configured\n"); - vlib_cli_output(vm, "%v", s); - return 0; - } - s = format(s, "Profile list in use : %s\n",sm->profile_list_name); - for (i = 0; i < MAX_POT_PROFILES; i++) - { - p = pot_profile_find(i); - if (p->valid == 0) - continue; - s = format(s, "POT Profile at index: %d\n", i); - s = format(s, " Id : %d\n", p->id); - s = format(s, " Validator : %s (%d)\n", - (p->validator) ? "True" : "False", p->validator); - if (p->validator == 1) - s = format(s, " Secret key : 0x%Lx (%Ld)\n", - p->secret_key, p->secret_key); - s = format(s, " Secret share : 0x%Lx (%Ld)\n", - p->secret_share, p->secret_share); - s = format(s, " Prime number : 0x%Lx (%Ld)\n", - p->prime, p->prime); - s = format(s, "2nd polynomial(eval) : 0x%Lx (%Ld)\n", - p->poly_pre_eval, p->poly_pre_eval); - s = format(s, " LPC : 0x%Lx (%Ld)\n", p->lpc, p->lpc); - - s = format(s, " Bit mask : 0x%Lx (%Ld)\n", - p->bit_mask, p->bit_mask); - } - - p = pot_profile_find(sm->active_profile_id); - - if (p && p->valid && p->in_use) { - s = format(s, "\nProfile index in use: %d\n", sm->active_profile_id); - s = format(s, "Pkts passed : 0x%Lx (%Ld)\n", - p->total_pkts_using_this_profile, - p->total_pkts_using_this_profile); - if (pot_is_decap(p)) - s = format(s, " This is Decap node. \n"); - } else { - s = format(s, "\nProfile index in use: None\n"); - } - vlib_cli_output(vm, "%v", s); - vec_free(s); - - return 0; -} - -VLIB_CLI_COMMAND(show_pot_profile_command) = -{ -.path = "show pot profile", -.short_help = "show pot profile", -.function = show_pot_profile_command_fn, -}; diff --git a/plugins/ioam-plugin/ioam/lib-pot/pot_util.h b/plugins/ioam-plugin/ioam/lib-pot/pot_util.h deleted file mode 100644 index 9df31fae..00000000 --- a/plugins/ioam-plugin/ioam/lib-pot/pot_util.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - * pot_util.h -- Proof Of Transit Utility Header - * - * 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. - */ - -#ifndef include_vnet_pot_util_h -#define include_vnet_pot_util_h - -#include -#define debug_ioam debug_ioam_fn -/* Dont change this size 256. This is there across multiple components */ -#define PATH_NAME_SIZE 256 - -/* Ring size. this should be same as the one in ODL. Do not change this - without change in ODL. */ -#define MAX_POT_PROFILES 2 - -/** - * Usage: - * - * On any node that participates in Proof of Transit: - * - * Step 1: Initialize this library by calling pot_init() - * Step 2: Setup a proof of transit profile that contains all the parameters needed to compute cumulative: - * Call these functions: - * pot_profile_find - * pot_profile_create - * pot_profile_set_bit_mask - To setup how large we want the numbers used in the computation and random number <= 64 bits - * Step 2a: For validator do this: - * pot_set_validator - * Step 2b: On initial node enable the profile to be used: - * pot_profile_set_active / pot_profile_get_active will return the profile - * Step 3a: At the initial node to generate Random number that will be read by all other nodes: - * pot_generate_random - * Step 3b: At all nodes including initial and verifier call this to compute cumulative: - * pot_update_cumulative - * Step 4: At the verifier: - * pot_validate - * - */ - -typedef struct pot_profile_ -{ - u8 id : 1; - u8 valid : 1; - u8 in_use : 1; - u64 random; - u8 validator; - u64 secret_key; - u64 secret_share; - u64 prime; - u64 lpc; - u64 poly_pre_eval; - u64 bit_mask; - u64 limit; - double primeinv; - u64 total_pkts_using_this_profile; -} pot_profile; - -typedef struct { - /* Name of the default profile list in use*/ - u8 *profile_list_name; - pot_profile profile_list[MAX_POT_PROFILES]; - /* number of profiles in the list */ - u8 active_profile_id : 1; - - /* API message ID base */ - u16 msg_id_base; - - /* convenience */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; -} pot_main_t; - -extern pot_main_t pot_main; - -/* - * Initialize proof of transit - */ -int pot_util_init(void); -void pot_profile_list_init(u8 * name); - - -/* - * Find a pot profile by ID - */ -pot_profile *pot_profile_find(u8 id); - -static inline u16 pot_profile_get_id(pot_profile * profile) -{ - if (profile) - { - return (profile->id); - } - return (0); -} - -/* setup and clean up profile */ -int pot_profile_create(pot_profile * profile, u64 prime, - u64 poly2, u64 lpc, u64 secret_share); -/* - * Setup profile as a validator - */ -int pot_set_validator(pot_profile * profile, u64 key); - -/* - * Setup max bits to be used for random number generation - */ -#define MAX_BITS 64 -int pot_profile_set_bit_mask(pot_profile * profile, u16 bits); - -/* - * Given a random and cumulative compute the new cumulative for a given profile - */ -u64 pot_update_cumulative(pot_profile * profile, u64 cumulative, u64 random); - -/* - * return True if the cumulative matches secret from a profile - */ -u8 pot_validate(pot_profile * profile, u64 cumulative, u64 random); - -/* - * Utility function to get random number per pack - */ -u64 pot_generate_random(pot_profile * profile); - - -extern void clear_pot_profiles(); -extern int pot_profile_list_is_enabled(u8 *name); - -static inline u8 pot_is_decap(pot_profile * p) -{ - return (p->validator == 1); -} - -static inline int pot_profile_set_active (u8 id) -{ - pot_main_t *sm = &pot_main; - pot_profile *profile = NULL; - pot_profile *current_active_prof = NULL; - - current_active_prof = pot_profile_find(sm->active_profile_id); - profile = pot_profile_find(id); - if (profile && profile->valid) { - sm->active_profile_id = id; - current_active_prof->in_use = 0; - profile->in_use = 1; - return(0); - } - return(-1); -} -static inline u8 pot_profile_get_active_id (void) -{ - pot_main_t *sm = &pot_main; - return (sm->active_profile_id); -} - -static inline pot_profile * pot_profile_get_active (void) -{ - pot_main_t *sm = &pot_main; - pot_profile *profile = NULL; - profile = pot_profile_find(sm->active_profile_id); - if (profile && profile->in_use) - return(profile); - return (NULL); -} - -static inline void pot_profile_reset_usage_stats (pot_profile *pow) -{ - if (pow) { - pow->total_pkts_using_this_profile = 0; - } -} - -static inline void pot_profile_incr_usage_stats (pot_profile *pow) -{ - if (pow) { - pow->total_pkts_using_this_profile++; - } -} - - -#endif diff --git a/plugins/ioam-plugin/ioam/lib-trace/jvpp_ioam_trace.c b/plugins/ioam-plugin/ioam/lib-trace/jvpp_ioam_trace.c deleted file mode 100644 index 1d878ea3..00000000 --- a/plugins/ioam-plugin/ioam/lib-trace/jvpp_ioam_trace.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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. - */ - -#include - -#include -#define vl_typedefs /* define message structures */ -#include -#undef vl_typedefs - -#define vl_endianfun -#include -#undef vl_endianfun - -#define vl_print(handle, ...) -#define vl_printfun -#include -#undef vl_printfun - -/* Get the API version number */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#undef vl_api_version - -#include -#include -#include - -#if VPPJNI_DEBUG == 1 - #define DEBUG_LOG(...) clib_warning(__VA_ARGS__) -#else - #define DEBUG_LOG(...) -#endif - -#include - -#include "ioam/jvpp/io_fd_vpp_jvpp_ioamtrace_JVppIoamtraceImpl.h" -#include "jvpp_ioam_trace.h" -#include "ioam/jvpp/jvpp_ioam_trace_gen.h" - -/* - * Class: io_fd_vpp_jvpp_ioamtrace_JVppIoamtraceImpl - * Method: init0 - * Signature: (JI)V - */ -JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_ioamtrace_JVppIoamtraceImpl_init0 - (JNIEnv *env, jclass clazz, jobject callback, jlong queue_address, jint my_client_index) { - ioamtrace_main_t * plugin_main = &ioamtrace_main; - u8 * name; - clib_warning ("Java_io_fd_vpp_jvpp_ioamtrace_JVppIoamtraceImpl_init0"); - - plugin_main->my_client_index = my_client_index; - plugin_main->vl_input_queue = (unix_shared_memory_queue_t *)queue_address; - - name = format (0, "ioam_trace_%08x%c", api_version, 0); - plugin_main->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name); - - if (plugin_main->msg_id_base == (u16) ~0) { - jclass exClass = (*env)->FindClass(env, "java/lang/IllegalStateException"); - (*env)->ThrowNew(env, exClass, "ioam_trace plugin is not loaded in VPP"); - } else { - plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback); - plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback)); - - #define _(N,n) \ - vl_msg_api_set_handlers(VL_API_##N + plugin_main->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_api_reply_handler; - #undef _ - } -} - -JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_ioamtrace_JVppIoamtraceImpl_close0 -(JNIEnv *env, jclass clazz) { - ioamtrace_main_t * plugin_main = &ioamtrace_main; - - // cleanup: - (*env)->DeleteGlobalRef(env, plugin_main->callbackClass); - (*env)->DeleteGlobalRef(env, plugin_main->callbackObject); - - plugin_main->callbackClass = NULL; - plugin_main->callbackObject = NULL; -} - -/* Attach thread to JVM and cache class references when initiating JVPP iOAM Trace */ -jint JNI_OnLoad(JavaVM *vm, void *reserved) { - JNIEnv* env; - - if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { - return JNI_EVERSION; - } - - if (cache_class_references(env) != 0) { - clib_warning ("Failed to cache class references\n"); - return JNI_ERR; - } - - return JNI_VERSION_1_8; -} - -/* Clean up cached references when disposing JVPP iOAM Trace */ -void JNI_OnUnload(JavaVM *vm, void *reserved) { - JNIEnv* env; - if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { - return; - } - delete_class_references(env); -} diff --git a/plugins/ioam-plugin/ioam/lib-trace/jvpp_ioam_trace.h b/plugins/ioam-plugin/ioam/lib-trace/jvpp_ioam_trace.h deleted file mode 100644 index 9fc16c15..00000000 --- a/plugins/ioam-plugin/ioam/lib-trace/jvpp_ioam_trace.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - */ -#ifndef __included_jvpp_ioam_trace_h__ -#define __included_jvpp_ioam_trace_h__ - -#include -#include -#include -#include -#include -#include - -/* Global state for JVPP-IOAM-TRACE */ -typedef struct { - /* Base message index for the trace plugin */ - u16 msg_id_base; - - /* Pointer to shared memory queue */ - unix_shared_memory_queue_t * vl_input_queue; - - /* VPP api client index */ - u32 my_client_index; - - /* Callback object and class references enabling asynchronous Java calls */ - jobject callbackObject; - jclass callbackClass; - -} ioamtrace_main_t; - -ioamtrace_main_t ioamtrace_main __attribute__((aligned (64))); - - -#endif /* __included_jvpp_ioam_trace_h__ */ diff --git a/plugins/ioam-plugin/ioam/lib-trace/trace.api b/plugins/ioam-plugin/ioam/lib-trace/trace.api deleted file mode 100644 index cb958325..00000000 --- a/plugins/ioam-plugin/ioam/lib-trace/trace.api +++ /dev/null @@ -1,92 +0,0 @@ -/* Hey Emacs use -*- mode: C -*- */ -/* - * 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. - */ - - -/** \brief iOAM6 Trace - Set the iOAM6 trace profile - @param trace_type - Type of trace requested - @param num_elts - Number of trace elements to be inserted - @param node_id - Trace Node ID - @param trace_tsp- Timestamp resolution - @param app_data - Application specific opaque -*/ -define trace_profile_add { - u32 client_index; - u32 context; - u8 trace_type; - u8 num_elts; - u8 trace_tsp; - u32 node_id; - u32 app_data; -}; - -/** \brief Trace profile add / del response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define trace_profile_add_reply { - u32 context; - i32 retval; -}; - - - -/** \brief Delete trace Profile - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define trace_profile_del { - u32 client_index; - u32 context; -}; - -/** \brief Trace profile add / del response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define trace_profile_del_reply { - u32 context; - i32 retval; -}; - - - -/** \brief Show trace Profile - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define trace_profile_show_config { - u32 client_index; - u32 context; -}; - -/** \brief Show trace config response - @param context - sender context, to match reply w/ request - @param retval - return value for request - @param trace_type - Type of trace requested - @param num_elts - Number of trace elements to be inserted - @param node_id - Trace Node ID - @param trace_tsp- Timestamp resolution - @param app_data - Application specific opaque -*/ -define trace_profile_show_config_reply { - u32 context; - i32 retval; - u8 trace_type; - u8 num_elts; - u8 trace_tsp; - u32 node_id; - u32 app_data; -}; diff --git a/plugins/ioam-plugin/ioam/lib-trace/trace_all_api_h.h b/plugins/ioam-plugin/ioam/lib-trace/trace_all_api_h.h deleted file mode 100644 index 223f9545..00000000 --- a/plugins/ioam-plugin/ioam/lib-trace/trace_all_api_h.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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. - */ -/* Include the generated file, see BUILT_SOURCES in Makefile.am */ -#include diff --git a/plugins/ioam-plugin/ioam/lib-trace/trace_api.c b/plugins/ioam-plugin/ioam/lib-trace/trace_api.c deleted file mode 100644 index 7e0d708e..00000000 --- a/plugins/ioam-plugin/ioam/lib-trace/trace_api.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * 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. - */ -/* - *------------------------------------------------------------------ - * trace_api.c - iOAM Trace related APIs to create - * and maintain profiles - *------------------------------------------------------------------ - */ - -#include -#include -#include - -#include -#include -#include - -/* define message IDs */ -#include - -/* define message structures */ -#define vl_typedefs -#include -#undef vl_typedefs - -/* define generated endian-swappers */ -#define vl_endianfun -#include -#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 -#undef vl_printfun - -/* Get the API version number */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#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 TRACE_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); - -/* *INDENT-OFF* */ -#define TRACE_REPLY_MACRO2(t, body) \ -do { \ - unix_shared_memory_queue_t * q; \ - rv = vl_msg_api_pd_handler (mp, rv); \ - 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); \ - do {body;} while (0); \ - vl_msg_api_send_shmem (q, (u8 *)&rmp); \ -} while(0); -/* *INDENT-ON* */ - -/* List of message types that this plugin understands */ - -#define foreach_trace_plugin_api_msg \ -_(TRACE_PROFILE_ADD, trace_profile_add) \ -_(TRACE_PROFILE_DEL, trace_profile_del) \ -_(TRACE_PROFILE_SHOW_CONFIG, trace_profile_show_config) - -static void vl_api_trace_profile_add_t_handler - (vl_api_trace_profile_add_t * mp) -{ - trace_main_t *sm = &trace_main; - int rv = 0; - vl_api_trace_profile_add_reply_t *rmp; - trace_profile *profile = NULL; - - profile = trace_profile_find (); - if (profile) - { - rv = - trace_profile_create (profile, mp->trace_type, mp->num_elts, - mp->trace_tsp, ntohl (mp->node_id), - ntohl (mp->app_data)); - if (rv != 0) - goto ERROROUT; - } - else - { - rv = -3; - } -ERROROUT: - TRACE_REPLY_MACRO (VL_API_TRACE_PROFILE_ADD_REPLY); -} - - -static void vl_api_trace_profile_del_t_handler - (vl_api_trace_profile_del_t * mp) -{ - trace_main_t *sm = &trace_main; - int rv = 0; - vl_api_trace_profile_del_reply_t *rmp; - - clear_trace_profiles (); - - TRACE_REPLY_MACRO (VL_API_TRACE_PROFILE_DEL_REPLY); -} - -static void vl_api_trace_profile_show_config_t_handler - (vl_api_trace_profile_show_config_t * mp) -{ - trace_main_t *sm = &trace_main; - vl_api_trace_profile_show_config_reply_t *rmp; - int rv = 0; - trace_profile *profile = trace_profile_find (); - if (profile->valid) - { - TRACE_REPLY_MACRO2 (VL_API_TRACE_PROFILE_SHOW_CONFIG_REPLY, - rmp->trace_type = profile->trace_type; - rmp->num_elts = profile->num_elts; - rmp->trace_tsp = profile->trace_tsp; - rmp->node_id = htonl (profile->node_id); - rmp->app_data = htonl (profile->app_data); - ); - } - else - { - TRACE_REPLY_MACRO2 (VL_API_TRACE_PROFILE_SHOW_CONFIG_REPLY, - rmp->trace_type = 0; - rmp->num_elts = 0; rmp->trace_tsp = 0; - rmp->node_id = 0; rmp->app_data = 0; - ); - } -} - -/* - * 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) -{ - trace_main_t *sm = &trace_main; - clib_error_t *error = 0; - - sm->vlib_main = vm; - sm->vnet_main = h->vnet_main; - return error; -} - -/* Set up the API message handling tables */ -static clib_error_t * -trace_plugin_api_hookup (vlib_main_t * vm) -{ - trace_main_t *sm = &trace_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_trace_plugin_api_msg; -#undef _ - - return 0; -} - -#define vl_msg_name_crc_list -#include -#undef vl_msg_name_crc_list - -static void -setup_message_id_table (trace_main_t * sm, api_main_t * am) -{ -#define _(id,n,crc) \ - vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base); - foreach_vl_msg_name_crc_trace; -#undef _ -} - -static clib_error_t * -trace_init (vlib_main_t * vm) -{ - trace_main_t *sm = &trace_main; - clib_error_t *error = 0; - u8 *name; - - bzero (sm, sizeof (trace_main)); - (void) trace_util_init (); - name = format (0, "ioam_trace_%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 = trace_plugin_api_hookup (vm); - - /* Add our API messages to the global name_crc hash table */ - setup_message_id_table (sm, &api_main); - - vec_free (name); - - return error; -} - -VLIB_INIT_FUNCTION (trace_init); - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/ioam-plugin/ioam/lib-trace/trace_msg_enum.h b/plugins/ioam-plugin/ioam/lib-trace/trace_msg_enum.h deleted file mode 100644 index 78c35665..00000000 --- a/plugins/ioam-plugin/ioam/lib-trace/trace_msg_enum.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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. - */ -#ifndef included_trace_msg_enum_h -#define included_trace_msg_enum_h - -#include - -#define vl_msg_id(n,h) n, -typedef enum { -#include - /* 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_trace_msg_enum_h */ diff --git a/plugins/ioam-plugin/ioam/lib-trace/trace_test.c b/plugins/ioam-plugin/ioam/lib-trace/trace_test.c deleted file mode 100644 index 111dd461..00000000 --- a/plugins/ioam-plugin/ioam/lib-trace/trace_test.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - * 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. - */ -/* - *------------------------------------------------------------------ - * trace_test.c - test harness for trace plugin - *------------------------------------------------------------------ - */ - -#include -#include -#include -#include -#include - -/* Declare message IDs */ -#include - -/* define message structures */ -#define vl_typedefs -#include -#undef vl_typedefs - -/* declare message handlers for each api */ - -#define vl_endianfun /* define message structures */ -#include -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) -#define vl_printfun -#include -#undef vl_printfun - -/* Get the API version number. */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#undef vl_api_version - - -typedef struct -{ - /* API message ID base */ - u16 msg_id_base; - vat_main_t *vat_main; -} trace_test_main_t; - -trace_test_main_t trace_test_main; - -#define foreach_standard_reply_retval_handler \ -_(trace_profile_add_reply) \ -_(trace_profile_del_reply) - -#define foreach_custom_reply_handler \ -_(trace_profile_show_config_reply, \ - if(mp->trace_type) \ - { \ - errmsg(" Trace Type : 0x%x (%d)\n",mp->trace_type, mp->trace_type); \ - errmsg(" Trace timestamp precision : %d \n",mp->trace_tsp); \ - errmsg(" Node Id : 0x%x (%d)\n",htonl(mp->node_id), htonl(mp->node_id)); \ - errmsg(" App Data : 0x%x (%d)\n",htonl(mp->app_data), htonl(mp->app_data)); \ - } \ - else errmsg("No valid trace profile configuration found\n");) -#define _(n) \ - static void vl_api_##n##_t_handler \ - (vl_api_##n##_t * mp) \ - { \ - vat_main_t * vam = trace_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 _ - -#define _(n,body) \ - static void vl_api_##n##_t_handler \ - (vl_api_##n##_t * mp) \ - { \ - vat_main_t * vam = trace_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; \ - } \ - if(retval>=0)do{body;} while(0); \ - else errmsg("Error, retval: %d",retval); \ - } -foreach_custom_reply_handler; -#undef _ -/* - * Table of message reply handlers, must include boilerplate handlers - * we just generated - */ -#define foreach_vpe_api_reply_msg \ -_(TRACE_PROFILE_ADD_REPLY, trace_profile_add_reply) \ -_(TRACE_PROFILE_DEL_REPLY, trace_profile_del_reply) \ -_(TRACE_PROFILE_SHOW_CONFIG_REPLY, trace_profile_show_config_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_trace_profile_add (vat_main_t * vam) -{ - trace_test_main_t *sm = &trace_test_main; - unformat_input_t *input = vam->input; - vl_api_trace_profile_add_t *mp; - u8 trace_type = 0; - u8 num_elts = 0; - int rv = 0; - u32 node_id = 0; - u32 app_data = 0; - u8 trace_tsp = 0; - f64 timeout; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "trace-type 0x%x", &trace_type)) - ; - else if (unformat (input, "trace-elts %d", &num_elts)) - ; - else if (unformat (input, "trace-tsp %d", &trace_tsp)) - ; - else if (unformat (input, "node-id 0x%x", &node_id)) - ; - else if (unformat (input, "app-data 0x%x", &app_data)) - ; - - else - break; - } - - - M (TRACE_PROFILE_ADD, trace_profile_add); - - mp->trace_type = trace_type; - mp->trace_tsp = trace_tsp; - mp->node_id = htonl (node_id); - mp->app_data = htonl (app_data); - mp->num_elts = num_elts; - - S; - W; - - return (rv); -} - - - -static int -api_trace_profile_del (vat_main_t * vam) -{ - trace_test_main_t *sm = &trace_test_main; - vl_api_trace_profile_del_t *mp; - f64 timeout; - - M (TRACE_PROFILE_DEL, trace_profile_del); - S; - W; - return 0; -} - -static int -api_trace_profile_show_config (vat_main_t * vam) -{ - trace_test_main_t *sm = &trace_test_main; - vl_api_trace_profile_show_config_t *mp; - f64 timeout; - M (TRACE_PROFILE_SHOW_CONFIG, trace_profile_show_config); - S; - W; - return 0; -} - -/* - * List of messages that the api test plugin sends, - * and that the data plane plugin processes - */ -#define foreach_vpe_api_msg \ -_(trace_profile_add, ""\ - "trace-type <0x1f|0x3|0x9|0x11|0x19> trace-elts trace-tsp <0|1|2|3> node-id app-data ") \ -_(trace_profile_del, "[id ]") \ -_(trace_profile_show_config, "[id ]") - - -void -vat_api_hookup (vat_main_t * vam) -{ - trace_test_main_t *sm = &trace_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) -{ - trace_test_main_t *sm = &trace_test_main; - u8 *name; - - sm->vat_main = vam; - - name = format (0, "ioam_trace_%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; -} - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/ioam-plugin/ioam/lib-trace/trace_util.c b/plugins/ioam-plugin/ioam/lib-trace/trace_util.c deleted file mode 100644 index 5c7f1eef..00000000 --- a/plugins/ioam-plugin/ioam/lib-trace/trace_util.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * 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. - */ -#include -#include -#include -#include -#include -#include "trace_util.h" - -trace_main_t trace_main; - -static int -trace_profile_cleanup (trace_profile * profile) -{ - - memset (profile, 0, sizeof (trace_profile)); - profile->trace_tsp = TSP_MICROSECONDS; /* Micro seconds */ - ip6_trace_profile_cleanup (); /* lib-trace_TODO: Remove this once IOAM-IPv6 transport is a plugin */ - return 0; - -} - -static int -trace_main_profiles_reset (void) -{ - int rv; - - trace_main_t *sm = &trace_main; - rv = trace_profile_cleanup (&(sm->profile)); - return (rv); -} - -int -trace_util_init (void) -{ - int rv; - - rv = trace_main_profiles_reset (); - return (rv); -} - - -int -trace_profile_create (trace_profile * profile, u8 trace_type, u8 num_elts, - u32 trace_tsp, u32 node_id, u32 app_data) -{ - - if (!trace_type || !num_elts || !(node_id)) - { - return (-1); - } - if (profile && !profile->valid) - { - //rv = trace_profile_cleanup (profile); - profile->trace_type = trace_type; - profile->num_elts = num_elts; - profile->trace_tsp = trace_tsp; - profile->node_id = node_id; - profile->app_data = app_data; - profile->valid = 1; - - /* lib-trace_TODO: Remove this once IOAM-IPv6 transport is a plugin */ - ip6_trace_profile_setup (); - return (0); - } - - return (-1); -} - - - -clib_error_t * -clear_trace_profile_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - - trace_main_profiles_reset (); - return 0; -} - -void -clear_trace_profiles (void) -{ - clear_trace_profile_command_fn (0, 0, 0); -} - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND(clear_trace_profile_command) = -{ -.path = "clear ioam-trace profile", -.short_help = "clear ioam-trace profile [|all]", -.function = clear_trace_profile_command_fn, -}; -/* *INDENT-ON* */ - -static clib_error_t * -set_trace_profile_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - u8 trace_type = 0; - u8 num_elts = 0; - u32 node_id = 0; - u32 app_data = 0; - u32 trace_tsp = 0; - trace_profile *profile = NULL; - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "trace-type 0x%x", &trace_type)); - else if (unformat (input, "trace-elts %d", &num_elts)); - else if (unformat (input, "trace-tsp %d", &trace_tsp)); - else if (unformat (input, "node-id 0x%x", &node_id)); - else if (unformat (input, "app-data 0x%x", &app_data)); - else - break; - } - profile = trace_profile_find (); - if (profile) - { - trace_profile_create (profile, trace_type, num_elts, trace_tsp, - node_id, app_data); - } - return 0; -} - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (set_trace_profile_command, static) = -{ -.path = "set ioam-trace profile", -.short_help = "set ioam-trace \ - trace-type <0x1f|0x3|0x9|0x11|0x19> trace-elts trace-tsp <0|1|2|3> \ - node-id app-data ", -.function = set_trace_profile_command_fn, -}; -/* *INDENT-ON* */ - -static clib_error_t * -show_trace_profile_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - trace_profile *p = NULL; - u8 *s = 0; - p = trace_profile_find (); - if (!(p && p->valid)) - { - s = format (s, "\nTrace configuration not valid\n"); - vlib_cli_output (vm, "%v", s); - vec_free (s); - return 0; - } - s = format (s, " HOP BY HOP OPTIONS - TRACE CONFIG - \n"); - s = format (s, " Trace Type : 0x%x (%d)\n", - p->trace_type, p->trace_type); - s = - format (s, " Trace timestamp precision : %d (%s)\n", - p->trace_tsp, - (p->trace_tsp == - TSP_SECONDS) ? "Seconds" : ((p->trace_tsp == - TSP_MILLISECONDS) ? - "Milliseconds" - : (((p->trace_tsp == - TSP_MICROSECONDS) ? - "Microseconds" : - "Nanoseconds")))); - s = format (s, " Num of trace nodes : %d\n", p->num_elts); - s = - format (s, " Node-id : 0x%x (%d)\n", - p->node_id, p->node_id); - s = - format (s, " App Data : 0x%x (%d)\n", - p->app_data, p->app_data); - vlib_cli_output (vm, "%v", s); - vec_free (s); - return 0; -} - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (show_trace_profile_command, static) = -{ -.path = "show ioam-trace profile", -.short_help = "show ioam-trace profile", -.function = show_trace_profile_command_fn, -}; -/* *INDENT-ON* */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/ioam-plugin/ioam/lib-trace/trace_util.h b/plugins/ioam-plugin/ioam/lib-trace/trace_util.h deleted file mode 100644 index 556f07ee..00000000 --- a/plugins/ioam-plugin/ioam/lib-trace/trace_util.h +++ /dev/null @@ -1,247 +0,0 @@ -/* - * trace_util.h -- Trace Profile Utility header - * - * 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. - */ - -#ifndef include_vnet_trace_util_h -#define include_vnet_trace_util_h - -#define debug_ioam debug_ioam_fn - - -/** - * Usage: - * - * On any node that participates in iOAM Trace. - * - * Step 1: Initialize this library by calling trace_init() - * Step 2: Setup a trace profile that contains all the parameters needed to compute cumulative: - * Call these functions: - * trace_profile_find - * trace_profile_create - * Step 2a: On initial node enable the profile to be used: - * trace_profile_set_active / trace_profile_get_active will return the profile - * Step 4: TBD - * trace_validate - * - */ - -typedef struct trace_profile_ -{ - u8 valid:1; - u8 trace_type; - u8 num_elts; - /* Configured node-id */ - u32 node_id; - u32 app_data; - u32 trace_tsp; -} trace_profile; - -typedef struct -{ - /* Name of the default profile list in use */ - trace_profile profile; - - /* API message ID base */ - u16 msg_id_base; - - /* convenience */ - vlib_main_t *vlib_main; - vnet_main_t *vnet_main; -} trace_main_t; - -extern trace_main_t trace_main; - -/* - * Initialize Trace profile - */ -int trace_util_init (void); - - -/* - * Find a trace profile - */ - -always_inline trace_profile * -trace_profile_find (void) -{ - trace_main_t *sm = &trace_main; - - return (&(sm->profile)); -} - - -/* setup and clean up profile */ -int trace_profile_create (trace_profile * profile, u8 trace_type, u8 num_elts, - u32 trace_tsp, u32 node_id, u32 app_data); - -void clear_trace_profiles (void); - - - -#define BIT_TTL_NODEID (1<<0) -#define BIT_ING_INTERFACE (1<<1) -#define BIT_EGR_INTERFACE (1<<2) -#define BIT_TIMESTAMP (1<<3) -#define BIT_APPDATA (1<<4) -#define TRACE_TYPE_MASK 0x1F /* Mask of all above bits */ - -/* - 0x00011111 iOAM-trace-type is 0x00011111 then the format of node - data is: - - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Hop_Lim | node_id | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | ingress_if_id | egress_if_id | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - + timestamp + - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | app_data | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -*/ -#define TRACE_TYPE_IF_TS_APP 0x1f -typedef struct -{ - u32 ttl_node_id; - u16 ingress_if; - u16 egress_if; - u32 timestamp; - u32 app_data; -} ioam_trace_if_ts_app_t; - -/* - 0x00000111 iOAM-trace-type is 0x00000111 then the format is: - - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Hop_Lim | node_id | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | ingress_if_id | egress_if_id | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -*/ - -#define TRACE_TYPE_IF 0x03 -typedef struct -{ - u32 ttl_node_id; - u16 ingress_if; - u16 egress_if; -} ioam_trace_if_t; - -/* - 0x00001001 iOAM-trace-type is 0x00001001 then the format is: - - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Hop_Lim | node_id | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - + timestamp + - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -*/ - -#define TRACE_TYPE_TS 0x09 -typedef struct -{ - u32 ttl_node_id; - u32 timestamp; -} ioam_trace_ts_t; - -/* - 0x00010001 iOAM-trace-type is 0x00010001 then the format is: - - - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Hop_Lim | node_id | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | app_data | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -*/ - - -#define TRACE_TYPE_APP 0x11 -typedef struct -{ - u32 ttl_node_id; - u32 app_data; -} ioam_trace_app_t; - -/* - - 0x00011001 iOAM-trace-type is 0x00011001 then the format is: - - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Hop_Lim | node_id | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - + timestamp + - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | app_data | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -*/ - -#define TRACE_TYPE_TS_APP 0x19 -typedef struct -{ - u32 ttl_node_id; - u32 timestamp; - u32 app_data; -} ioam_trace_ts_app_t; - - - -static inline u8 -fetch_trace_data_size (u8 trace_type) -{ - u8 trace_data_size = 0; - - if (trace_type == TRACE_TYPE_IF_TS_APP) - trace_data_size = sizeof (ioam_trace_if_ts_app_t); - else if (trace_type == TRACE_TYPE_IF) - trace_data_size = sizeof (ioam_trace_if_t); - else if (trace_type == TRACE_TYPE_TS) - trace_data_size = sizeof (ioam_trace_ts_t); - else if (trace_type == TRACE_TYPE_APP) - trace_data_size = sizeof (ioam_trace_app_t); - else if (trace_type == TRACE_TYPE_TS_APP) - trace_data_size = sizeof (ioam_trace_ts_app_t); - - return trace_data_size; -} - -int ioam_trace_get_sizeof_handler (u32 * result); -int ip6_trace_profile_setup (void); -int ip6_trace_profile_cleanup (void); - -#define TSP_SECONDS 0 -#define TSP_MILLISECONDS 1 -#define TSP_MICROSECONDS 2 -#define TSP_NANOSECONDS 3 - -#endif - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/ioam_decap.c b/plugins/ioam-plugin/ioam/lib-vxlan-gpe/ioam_decap.c deleted file mode 100644 index fd308657..00000000 --- a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/ioam_decap.c +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Statistics (not really errors) */ -#define foreach_vxlan_gpe_decap_ioam_v4_error \ -_(DECAPSULATED, "good packets decapsulated") - -static char *vxlan_gpe_decap_ioam_v4_error_strings[] = { -#define _(sym,string) string, - foreach_vxlan_gpe_decap_ioam_v4_error -#undef _ -}; - -typedef enum -{ -#define _(sym,str) VXLAN_GPE_DECAP_IOAM_V4_ERROR_##sym, - foreach_vxlan_gpe_decap_ioam_v4_error -#undef _ - VXLAN_GPE_DECAP_IOAM_V4_N_ERROR, -} vxlan_gpe_decap_ioam_v4_error_t; - - -always_inline void -vxlan_gpe_decap_ioam_v4_two_inline (vlib_main_t * vm, - vlib_node_runtime_t * node, - vxlan_gpe_main_t * ngm, - vlib_buffer_t * b0, vlib_buffer_t * b1, - u32 * next0, u32 * next1) -{ - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - - next0[0] = next1[0] = hm->decap_v4_next_override; - vxlan_gpe_encap_decap_ioam_v4_one_inline (vm, node, b0, &next0[0], - VXLAN_GPE_DECAP_IOAM_V4_NEXT_DROP, - 0 /* use_adj */ ); - vxlan_gpe_encap_decap_ioam_v4_one_inline (vm, node, b1, &next0[1], - VXLAN_GPE_DECAP_IOAM_V4_NEXT_DROP, - 0 /* use_adj */ ); -} - - - -static uword -vxlan_gpe_decap_ioam (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * from_frame, u8 is_ipv6) -{ - u32 n_left_from, next_index, *from, *to_next; - vxlan_gpe_main_t *ngm = &vxlan_gpe_main; - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - - from = vlib_frame_vector_args (from_frame); - n_left_from = 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 bi0, bi1; - vlib_buffer_t *b0, *b1; - u32 next0, next1; - - next0 = next1 = hm->decap_v4_next_override; - - /* 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, 2 * CLIB_CACHE_LINE_BYTES, LOAD); - CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD); - } - - bi0 = from[0]; - bi1 = from[1]; - to_next[0] = bi0; - to_next[1] = bi1; - from += 2; - to_next += 2; - n_left_to_next -= 2; - n_left_from -= 2; - - b0 = vlib_get_buffer (vm, bi0); - b1 = vlib_get_buffer (vm, bi1); - - - vlib_buffer_advance (b0, - -(word) (sizeof (udp_header_t) + - sizeof (ip4_header_t) + - sizeof (vxlan_gpe_header_t))); - vlib_buffer_advance (b1, - -(word) (sizeof (udp_header_t) + - sizeof (ip4_header_t) + - sizeof (vxlan_gpe_header_t))); - - vxlan_gpe_decap_ioam_v4_two_inline (vm, node, ngm, b0, b1, - &next0, &next1); - - - vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, - n_left_to_next, bi0, bi1, next0, - next1); - - if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) - { - vxlan_gpe_ioam_v4_trace_t *tr = vlib_add_trace (vm, node, b0, - sizeof (*tr)); - } - } - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t *b0; - u32 next0 = hm->decap_v4_next_override; - - 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); - - - vlib_buffer_advance (b0, - -(word) (sizeof (udp_header_t) + - sizeof (ip4_header_t) + - sizeof (vxlan_gpe_header_t))); - - next0 = hm->decap_v4_next_override; - vxlan_gpe_encap_decap_ioam_v4_one_inline (vm, node, b0, - &next0, - VXLAN_GPE_DECAP_IOAM_V4_NEXT_DROP, - 0 /* use_adj */ ); - - if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) - { - vxlan_gpe_ioam_v4_trace_t *tr = vlib_add_trace (vm, node, b0, - sizeof (*tr)); - } - 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); - } - - return from_frame->n_vectors; -} - - -static uword -vxlan_gpe_decap_ioam_v4 (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * from_frame) -{ - return vxlan_gpe_decap_ioam (vm, node, from_frame, 0); -} - - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (vxlan_gpe_decap_ioam_v4_node) = { - .function = vxlan_gpe_decap_ioam_v4, - .name = "vxlan-gpe-decap-ioam-v4", - .vector_size = sizeof (u32), - .format_trace = format_vxlan_gpe_ioam_v4_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(vxlan_gpe_decap_ioam_v4_error_strings), - .error_strings = vxlan_gpe_decap_ioam_v4_error_strings, - - .n_next_nodes = VXLAN_GPE_DECAP_IOAM_V4_N_NEXT, - - .next_nodes = { - [VXLAN_GPE_DECAP_IOAM_V4_NEXT_POP] = "vxlan-gpe-pop-ioam-v4", - [VXLAN_GPE_DECAP_IOAM_V4_NEXT_DROP] = "error-drop", - }, -}; -/* *INDENT-ON* */ - - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/ioam_encap.c b/plugins/ioam-plugin/ioam/lib-vxlan-gpe/ioam_encap.c deleted file mode 100644 index 4b18bfea..00000000 --- a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/ioam_encap.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Statistics (not really errors) */ -#define foreach_vxlan_gpe_encap_ioam_v4_error \ -_(ENCAPSULATED, "good packets encapsulated") - -static char *vxlan_gpe_encap_ioam_v4_error_strings[] = { -#define _(sym,string) string, - foreach_vxlan_gpe_encap_ioam_v4_error -#undef _ -}; - -typedef enum -{ -#define _(sym,str) VXLAN_GPE_ENCAP_IOAM_V4_ERROR_##sym, - foreach_vxlan_gpe_encap_ioam_v4_error -#undef _ - VXLAN_GPE_ENCAP_IOAM_V4_N_ERROR, -} vxlan_gpe_encap_ioam_v4_error_t; - -typedef enum -{ - VXLAN_GPE_ENCAP_IOAM_V4_NEXT_IP4_LOOKUP, - VXLAN_GPE_ENCAP_IOAM_V4_NEXT_DROP, - VXLAN_GPE_ENCAP_IOAM_V4_N_NEXT -} vxlan_gpe_encap_ioam_v4_next_t; - - -always_inline void -vxlan_gpe_encap_ioam_v4_two_inline (vlib_main_t * vm, - vlib_node_runtime_t * node, - vxlan_gpe_main_t * ngm, - vlib_buffer_t * b0, vlib_buffer_t * b1, - u32 * next0, u32 * next1) -{ - next0[0] = next1[0] = VXLAN_GPE_ENCAP_IOAM_V4_NEXT_IP4_LOOKUP; - vxlan_gpe_encap_decap_ioam_v4_one_inline (vm, node, b0, next0, - VXLAN_GPE_ENCAP_IOAM_V4_NEXT_DROP, - 0 /* use_adj */ ); - vxlan_gpe_encap_decap_ioam_v4_one_inline (vm, node, b1, next1, - VXLAN_GPE_ENCAP_IOAM_V4_NEXT_DROP, - 0 /* use_adj */ ); -} - - -static uword -vxlan_gpe_encap_ioam_v4 (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * from_frame) -{ - u32 n_left_from, next_index, *from, *to_next; - vxlan_gpe_main_t *ngm = &vxlan_gpe_main; - - from = vlib_frame_vector_args (from_frame); - n_left_from = 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 bi0, bi1; - vlib_buffer_t *b0, *b1; - u32 next0, next1; - - next0 = next1 = VXLAN_GPE_ENCAP_IOAM_V4_NEXT_IP4_LOOKUP; - - /* 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, 2 * CLIB_CACHE_LINE_BYTES, LOAD); - CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD); - } - - bi0 = from[0]; - bi1 = from[1]; - to_next[0] = bi0; - to_next[1] = bi1; - from += 2; - to_next += 2; - n_left_to_next -= 2; - n_left_from -= 2; - - b0 = vlib_get_buffer (vm, bi0); - b1 = vlib_get_buffer (vm, bi1); - - vxlan_gpe_encap_ioam_v4_two_inline (vm, node, ngm, b0, b1, - &next0, &next1); - - - 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 = VXLAN_GPE_ENCAP_IOAM_V4_NEXT_IP4_LOOKUP; - - 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); - - vxlan_gpe_encap_decap_ioam_v4_one_inline (vm, node, b0, - &next0, - VXLAN_GPE_ENCAP_IOAM_V4_NEXT_DROP, - 0 /* use_adj */ ); - - if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) - { - vxlan_gpe_ioam_v4_trace_t *tr = vlib_add_trace (vm, node, b0, - sizeof (*tr)); - } - 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); - } - - return from_frame->n_vectors; -} - - - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (vxlan_gpe_encap_ioam_v4_node) = { - .function = vxlan_gpe_encap_ioam_v4, - .name = "vxlan-gpe-encap-ioam-v4", - .vector_size = sizeof (u32), - .format_trace = format_vxlan_gpe_ioam_v4_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(vxlan_gpe_encap_ioam_v4_error_strings), - .error_strings = vxlan_gpe_encap_ioam_v4_error_strings, - - .n_next_nodes = VXLAN_GPE_ENCAP_IOAM_V4_N_NEXT, - - .next_nodes = { - [VXLAN_GPE_ENCAP_IOAM_V4_NEXT_IP4_LOOKUP] = "ip4-lookup", - [VXLAN_GPE_ENCAP_IOAM_V4_NEXT_DROP] = "error-drop", - }, -}; -/* *INDENT-ON* */ - - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/ioam_pop.c b/plugins/ioam-plugin/ioam/lib-vxlan-gpe/ioam_pop.c deleted file mode 100644 index 55c33b14..00000000 --- a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/ioam_pop.c +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include -#include -#include - -/* Statistics (not really errors) */ -#define foreach_vxlan_gpe_pop_ioam_v4_error \ -_(POPPED, "good packets popped") - -static char *vxlan_gpe_pop_ioam_v4_error_strings[] = { -#define _(sym,string) string, - foreach_vxlan_gpe_pop_ioam_v4_error -#undef _ -}; - -typedef enum -{ -#define _(sym,str) VXLAN_GPE_POP_IOAM_V4_ERROR_##sym, - foreach_vxlan_gpe_pop_ioam_v4_error -#undef _ - VXLAN_GPE_POP_IOAM_V4_N_ERROR, -} vxlan_gpe_pop_ioam_v4_error_t; - -typedef struct -{ - ioam_trace_t fmt_trace; -} vxlan_gpe_pop_ioam_v4_trace_t; - - -u8 * -format_vxlan_gpe_pop_ioam_v4_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 *); - vxlan_gpe_pop_ioam_v4_trace_t *t1 - = va_arg (*args, vxlan_gpe_pop_ioam_v4_trace_t *); - ioam_trace_t *t = &(t1->fmt_trace); - vxlan_gpe_ioam_option_t *fmt_trace0; - vxlan_gpe_ioam_option_t *opt0, *limit0; - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - - u8 type0; - - fmt_trace0 = (vxlan_gpe_ioam_option_t *) t->option_data; - - s = format (s, "VXLAN_GPE_IOAM_POP: next_index %d len %d traced %d", - t->next_index, fmt_trace0->length, t->trace_len); - - opt0 = (vxlan_gpe_ioam_option_t *) (fmt_trace0 + 1); - limit0 = (vxlan_gpe_ioam_option_t *) ((u8 *) fmt_trace0) + t->trace_len; - - while (opt0 < limit0) - { - type0 = opt0->type; - switch (type0) - { - case 0: /* Pad, just stop */ - opt0 = (vxlan_gpe_ioam_option_t *) ((u8 *) opt0) + 1; - break; - - default: - if (hm->trace[type0]) - { - s = (*hm->trace[type0]) (s, opt0); - } - else - { - s = - format (s, "\n unrecognized option %d length %d", type0, - opt0->length); - } - opt0 = - (vxlan_gpe_ioam_option_t *) (((u8 *) opt0) + opt0->length + - sizeof (vxlan_gpe_ioam_option_t)); - break; - } - } - - return s; -} - -always_inline void -vxlan_gpe_ioam_pop_v4 (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_buffer_t * b0) -{ - ip4_header_t *ip0; - udp_header_t *udp_hdr0; - vxlan_gpe_header_t *gpe_hdr0; - vxlan_gpe_ioam_hdr_t *gpe_ioam0; - - ip0 = vlib_buffer_get_current (b0); - - udp_hdr0 = (udp_header_t *) (ip0 + 1); - gpe_hdr0 = (vxlan_gpe_header_t *) (udp_hdr0 + 1); - gpe_ioam0 = (vxlan_gpe_ioam_hdr_t *) (gpe_hdr0 + 1); - - /* Pop the iOAM data */ - vlib_buffer_advance (b0, - (word) (sizeof (udp_header_t) + - sizeof (ip4_header_t) + - sizeof (vxlan_gpe_header_t) + - gpe_ioam0->length)); - - return; -} - - - -always_inline void -vxlan_gpe_pop_ioam_v4_one_inline (vlib_main_t * vm, - vlib_node_runtime_t * node, - vxlan_gpe_main_t * ngm, - vlib_buffer_t * b0, u32 * next0) -{ - CLIB_UNUSED (ip4_header_t * ip0); - CLIB_UNUSED (udp_header_t * udp_hdr0); - CLIB_UNUSED (vxlan_gpe_header_t * gpe_hdr0); - CLIB_UNUSED (vxlan_gpe_ioam_hdr_t * gpe_ioam0); - CLIB_UNUSED (vxlan_gpe_ioam_option_t * opt0); - CLIB_UNUSED (vxlan_gpe_ioam_option_t * limit0); - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - - - /* Pop the iOAM header */ - ip0 = vlib_buffer_get_current (b0); - udp_hdr0 = (udp_header_t *) (ip0 + 1); - gpe_hdr0 = (vxlan_gpe_header_t *) (udp_hdr0 + 1); - gpe_ioam0 = (vxlan_gpe_ioam_hdr_t *) (gpe_hdr0 + 1); - opt0 = (vxlan_gpe_ioam_option_t *) (gpe_ioam0 + 1); - limit0 = (vxlan_gpe_ioam_option_t *) ((u8 *) gpe_ioam0 + gpe_ioam0->length); - - /* - * Basic validity checks - */ - if (gpe_ioam0->length > clib_net_to_host_u16 (ip0->length)) - { - next0[0] = VXLAN_GPE_INPUT_NEXT_DROP; - goto trace00; - } - - /* Scan the set of h-b-h options, process ones that we understand */ - while (opt0 < limit0) - { - u8 type0; - type0 = opt0->type; - switch (type0) - { - case 0: /* Pad1 */ - opt0 = (vxlan_gpe_ioam_option_t *) ((u8 *) opt0) + 1; - continue; - case 1: /* PadN */ - break; - default: - if (hm->pop_options[type0]) - { - if ((*hm->pop_options[type0]) (ip0, opt0) < 0) - { - next0[0] = VXLAN_GPE_INPUT_NEXT_DROP; - goto trace00; - } - } - break; - } - opt0 = - (vxlan_gpe_ioam_option_t *) (((u8 *) opt0) + opt0->length + - sizeof (vxlan_gpe_ioam_hdr_t)); - } - - - next0[0] = - (gpe_ioam0->protocol < VXLAN_GPE_PROTOCOL_MAX) ? - ngm-> - decap_next_node_list[gpe_ioam0->protocol] : VXLAN_GPE_INPUT_NEXT_DROP; - -trace00: - if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) - { - vxlan_gpe_pop_ioam_v4_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - u32 trace_len = gpe_ioam0->length; - t->fmt_trace.next_index = next0[0]; - /* Capture the h-b-h option verbatim */ - trace_len = - trace_len < - ARRAY_LEN (t->fmt_trace. - option_data) ? trace_len : ARRAY_LEN (t->fmt_trace. - option_data); - t->fmt_trace.trace_len = trace_len; - clib_memcpy (&(t->fmt_trace.option_data), gpe_ioam0, trace_len); - } - - /* Remove the iOAM header inside the VxLAN-GPE header */ - vxlan_gpe_ioam_pop_v4 (vm, node, b0); - return; -} - -always_inline void -vxlan_gpe_pop_ioam_v4_two_inline (vlib_main_t * vm, - vlib_node_runtime_t * node, - vxlan_gpe_main_t * ngm, - vlib_buffer_t * b0, vlib_buffer_t * b1, - u32 * next0, u32 * next1) -{ - - vxlan_gpe_pop_ioam_v4_one_inline (vm, node, ngm, b0, next0); - vxlan_gpe_pop_ioam_v4_one_inline (vm, node, ngm, b1, next1); -} - - - -static uword -vxlan_gpe_pop_ioam (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * from_frame, u8 is_ipv6) -{ - u32 n_left_from, next_index, *from, *to_next; - vxlan_gpe_main_t *ngm = &vxlan_gpe_main; - - from = vlib_frame_vector_args (from_frame); - n_left_from = 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 bi0, bi1; - vlib_buffer_t *b0, *b1; - u32 next0, next1; - - /* 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, 2 * CLIB_CACHE_LINE_BYTES, LOAD); - CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD); - } - - bi0 = from[0]; - bi1 = from[1]; - to_next[0] = bi0; - to_next[1] = bi1; - from += 2; - to_next += 2; - n_left_to_next -= 2; - n_left_from -= 2; - - b0 = vlib_get_buffer (vm, bi0); - b1 = vlib_get_buffer (vm, bi1); - - vxlan_gpe_pop_ioam_v4_two_inline (vm, node, ngm, b0, b1, &next0, - &next1); - - - 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; - - 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); - - vxlan_gpe_pop_ioam_v4_one_inline (vm, node, ngm, b0, &next0); - - - 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); - } - - return from_frame->n_vectors; -} - - -static uword -vxlan_gpe_pop_ioam_v4 (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * from_frame) -{ - return vxlan_gpe_pop_ioam (vm, node, from_frame, 0); -} - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (vxlan_gpe_pop_ioam_v4_node) = { - .function = vxlan_gpe_pop_ioam_v4, - .name = "vxlan-gpe-pop-ioam-v4", - .vector_size = sizeof (u32), - .format_trace = format_vxlan_gpe_pop_ioam_v4_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(vxlan_gpe_pop_ioam_v4_error_strings), - .error_strings = vxlan_gpe_pop_ioam_v4_error_strings, - - .n_next_nodes = VXLAN_GPE_INPUT_N_NEXT, - - .next_nodes = { -#define _(s,n) [VXLAN_GPE_INPUT_NEXT_##s] = n, - foreach_vxlan_gpe_input_next -#undef _ - }, -}; -/* *INDENT-ON* */ - - - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/ioam_transit.c b/plugins/ioam-plugin/ioam/lib-vxlan-gpe/ioam_transit.c deleted file mode 100644 index b42c357c..00000000 --- a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/ioam_transit.c +++ /dev/null @@ -1,188 +0,0 @@ - /* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Statistics (not really errors) */ -#define foreach_vxlan_gpe_transit_ioam_error \ -_(ENCAPSULATED, "good packets encapsulated") - -static char *vxlan_gpe_transit_ioam_error_strings[] = { -#define _(sym,string) string, - foreach_vxlan_gpe_transit_ioam_error -#undef _ -}; - -typedef enum -{ -#define _(sym,str) VXLAN_GPE_TRANSIT_IOAM_ERROR_##sym, - foreach_vxlan_gpe_transit_ioam_error -#undef _ - VXLAN_GPE_TRANSIT_IOAM_N_ERROR, -} vxlan_gpe_transit_ioam_error_t; - -typedef enum -{ - VXLAN_GPE_TRANSIT_IOAM_NEXT_OUTPUT, - VXLAN_GPE_TRANSIT_IOAM_NEXT_DROP, - VXLAN_GPE_TRANSIT_IOAM_N_NEXT -} vxlan_gpe_transit_ioam_next_t; - - -/* *INDENT-OFF* */ -VNET_FEATURE_INIT (vxlan_gpe_transit_ioam, static) = -{ - .arc_name = "ip4-output", - .node_name = "vxlan-gpe-transit-ioam", - .runs_before = VNET_FEATURES ("interface-output"), -}; -/* *INDENT-ON* */ - -static uword -vxlan_gpe_transit_ioam (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * from_frame) -{ - u32 n_left_from, next_index, *from, *to_next; - - from = vlib_frame_vector_args (from_frame); - n_left_from = 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 > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t *b0; - u32 next0 = VXLAN_GPE_TRANSIT_IOAM_NEXT_OUTPUT; - - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - ip4_header_t *ip0; - u32 iph_offset = 0; - - b0 = vlib_get_buffer (vm, bi0); - iph_offset = vnet_buffer (b0)->ip.save_rewrite_length; - ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) - + iph_offset); - - /* just forward non ipv4 packets */ - if (PREDICT_FALSE - ((ip0->ip_version_and_header_length & 0xF0) == 0x40)) - { - /* ipv4 packets */ - udp_header_t *udp_hdr0 = (udp_header_t *) (ip0 + 1); - if (PREDICT_FALSE - ((ip0->protocol == IP_PROTOCOL_UDP) && - (clib_net_to_host_u16 (udp_hdr0->dst_port) == - UDP_DST_PORT_vxlan_gpe))) - { - - /* Check the iOAM header */ - vxlan_gpe_header_t *gpe_hdr0 = - (vxlan_gpe_header_t *) (udp_hdr0 + 1); - - if (PREDICT_FALSE - (gpe_hdr0->protocol == VXLAN_GPE_PROTOCOL_IOAM)) - { - uword *t = NULL; - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - fib_prefix_t key4; - memset (&key4, 0, sizeof (key4)); - key4.fp_proto = FIB_PROTOCOL_IP4; - key4.fp_addr.ip4.as_u32 = ip0->dst_address.as_u32; - t = hash_get_mem (hm->dst_by_ip4, &key4); - if (t) - { - - - vlib_buffer_advance (b0, - (word) (sizeof - (ethernet_header_t))); - vxlan_gpe_encap_decap_ioam_v4_one_inline (vm, node, - b0, - &next0, - VXLAN_GPE_TRANSIT_IOAM_NEXT_DROP, - 1 - /* use_adj */ - ); - vlib_buffer_advance (b0, - -(word) (sizeof - (ethernet_header_t))); - } - } - } - } - - 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); - } - - return from_frame->n_vectors; -} - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (vxlan_gpe_transit_ioam_node) = { - .function = vxlan_gpe_transit_ioam, - .name = "vxlan-gpe-transit-ioam", - .vector_size = sizeof (u32), - .format_trace = format_vxlan_gpe_ioam_v4_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(vxlan_gpe_transit_ioam_error_strings), - .error_strings = vxlan_gpe_transit_ioam_error_strings, - - .n_next_nodes = VXLAN_GPE_TRANSIT_IOAM_N_NEXT, - - .next_nodes = { - [VXLAN_GPE_TRANSIT_IOAM_NEXT_OUTPUT] = "interface-output", - [VXLAN_GPE_TRANSIT_IOAM_NEXT_DROP] = "error-drop", - }, - -}; -/* *INDENT-ON* */ - - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe.api b/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe.api deleted file mode 100644 index 056529a4..00000000 --- a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe.api +++ /dev/null @@ -1,181 +0,0 @@ -/* Hey Emacs use -*- mode: C -*- */ -/* - * 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. - */ - - -/** \brief iOAM Over VxLAN-GPE - Set iOAM transport for VxLAN-GPE - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param id - profile id - @param trace_ppc - Trace PPC (none/encap/decap) - @param pow_enable - Proof of Work enabled or not flag - @param trace_enable - iOAM Trace enabled or not flag - -*/ -define vxlan_gpe_ioam_enable { - u32 client_index; - u32 context; - u16 id; - u8 trace_ppc; - u8 pow_enable; - u8 trace_enable; -}; - -/** \brief iOAM Over VxLAN-GPE - Set iOAM transport for VXLAN-GPE reply - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define vxlan_gpe_ioam_enable_reply { - u32 context; - i32 retval; -}; - - -/** \brief iOAM for VxLAN-GPE disable - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param id - profile id -*/ -define vxlan_gpe_ioam_disable -{ - u32 client_index; - u32 context; - u16 id; -}; - -/** \brief vxlan_gpe_ioam disable response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define vxlan_gpe_ioam_disable_reply -{ - u32 context; - i32 retval; -}; - -/** \brief Enable iOAM for a VNI (VXLAN-GPE) - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param vni - VXLAN-GPE VNI - @param local - IPv4/6 Address of the local VTEP - @param remote - IPv4/6 Address of the remote VTEP - -*/ -define vxlan_gpe_ioam_vni_enable { - u32 client_index; - u32 context; - u32 vni; - u8 local[16]; - u8 remote[16]; - u8 is_ipv6; -}; - -/** \brief Reply to enable iOAM for a VNI (VXLAN-GPE) - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param retval - return value for request - -*/ -define vxlan_gpe_ioam_vni_enable_reply { - u32 client_index; - u32 context; - i32 retval; -}; - -/** \brief Disable iOAM for a VNI (VXLAN-GPE) - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param vni - VXLAN-GPE VNI - @param local - IPv4/6 Address of the local VTEP - @param remote - IPv4/6 Address of the remote VTEP - -*/ -define vxlan_gpe_ioam_vni_disable { - u32 client_index; - u32 context; - u32 vni; - u8 local[16]; - u8 remote[16]; - u8 is_ipv6; -}; - -/** \brief Reply to disable iOAM for a VNI (VXLAN-GPE) - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param retval - return value for request - -*/ -define vxlan_gpe_ioam_vni_disable_reply { - u32 client_index; - u32 context; - i32 retval; -}; - - -/** \brief Enable iOAM for a VXLAN-GPE transit - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param dst_addr - IPv4/6 Address of the local VTEP - @param outer_fib_index- FIB index - -*/ -define vxlan_gpe_ioam_transit_enable { - u32 client_index; - u32 context; - u32 outer_fib_index; - u8 dst_addr[16]; - u8 is_ipv6; -}; - -/** \brief Reply to enable iOAM for VXLAN-GPE transit - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param retval - return value for request - -*/ -define vxlan_gpe_ioam_transit_enable_reply { - u32 client_index; - u32 context; - i32 retval; -}; - -/** \brief Disable iOAM for VXLAN-GPE transit - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param dst_addr - IPv4/6 Address of the local VTEP - @param outer_fib_index- FIB index - -*/ -define vxlan_gpe_ioam_transit_disable { - u32 client_index; - u32 context; - u32 outer_fib_index; - u8 dst_addr[16]; - u8 is_ipv6; -}; - -/** \brief Reply to disable iOAM for VXLAN-GPE transit - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param retval - return value for request - -*/ -define vxlan_gpe_ioam_transit_disable_reply { - u32 client_index; - u32 context; - i32 retval; -}; - - diff --git a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_all_api_h.h b/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_all_api_h.h deleted file mode 100644 index bbf2c101..00000000 --- a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_all_api_h.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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. - */ -/* Include the generated file, see BUILT_SOURCES in Makefile.am */ -#include diff --git a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_api.c b/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_api.c deleted file mode 100644 index 68752365..00000000 --- a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_api.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - * 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. - */ -/* - *------------------------------------------------------------------ - * vxlan_gpe_api.c - iOAM VxLAN-GPE related APIs to create - * and maintain profiles - *------------------------------------------------------------------ - */ - -#include -#include -#include - -#include -#include -#include - -/* define message IDs */ -#include - -/* define message structures */ -#define vl_typedefs -#include -#undef vl_typedefs - -/* define generated endian-swappers */ -#define vl_endianfun -#include -#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 -#undef vl_printfun - -/* Get the API version number */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#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 VXLAN_GPE_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); - -/* *INDENT-OFF* */ -#define VXLAN_GPE_REPLY_MACRO2(t, body) \ -do { \ - unix_shared_memory_queue_t * q; \ - rv = vl_msg_api_pd_handler (mp, rv); \ - 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)); \ - rmp->context = mp->context; \ - rmp->retval = ntohl(rv); \ - do {body;} while (0); \ - vl_msg_api_send_shmem (q, (u8 *)&rmp); \ -} while(0); -/* *INDENT-ON* */ - -/* List of message types that this plugin understands */ - -#define foreach_vxlan_gpe_plugin_api_msg \ -_(VXLAN_GPE_IOAM_ENABLE, vxlan_gpe_ioam_enable) \ -_(VXLAN_GPE_IOAM_DISABLE, vxlan_gpe_ioam_disable) \ -_(VXLAN_GPE_IOAM_VNI_ENABLE, vxlan_gpe_ioam_vni_enable) \ -_(VXLAN_GPE_IOAM_VNI_DISABLE, vxlan_gpe_ioam_vni_disable) \ -_(VXLAN_GPE_IOAM_TRANSIT_ENABLE, vxlan_gpe_ioam_transit_enable) \ -_(VXLAN_GPE_IOAM_TRANSIT_DISABLE, vxlan_gpe_ioam_transit_disable) \ - - -static void vl_api_vxlan_gpe_ioam_enable_t_handler - (vl_api_vxlan_gpe_ioam_enable_t * mp) -{ - int rv = 0; - vl_api_vxlan_gpe_ioam_enable_reply_t *rmp; - clib_error_t *error; - vxlan_gpe_ioam_main_t *sm = &vxlan_gpe_ioam_main; - - /* Ignoring the profile id as currently a single profile - * is supported */ - error = - vxlan_gpe_ioam_enable (mp->trace_enable, mp->pow_enable, mp->trace_ppc); - if (error) - { - clib_error_report (error); - rv = clib_error_get_code (error); - } - - VXLAN_GPE_REPLY_MACRO (VL_API_VXLAN_GPE_IOAM_ENABLE_REPLY); -} - -static void vl_api_vxlan_gpe_ioam_disable_t_handler - (vl_api_vxlan_gpe_ioam_disable_t * mp) -{ - int rv = 0; - vl_api_vxlan_gpe_ioam_disable_reply_t *rmp; - clib_error_t *error; - vxlan_gpe_ioam_main_t *sm = &vxlan_gpe_ioam_main; - - /* Ignoring the profile id as currently a single profile - * is supported */ - error = vxlan_gpe_ioam_disable (0, 0, 0); - if (error) - { - clib_error_report (error); - rv = clib_error_get_code (error); - } - - VXLAN_GPE_REPLY_MACRO (VL_API_VXLAN_GPE_IOAM_DISABLE_REPLY); -} - -static void vl_api_vxlan_gpe_ioam_vni_enable_t_handler - (vl_api_vxlan_gpe_ioam_vni_enable_t * mp) -{ - int rv = 0; - vl_api_vxlan_gpe_ioam_vni_enable_reply_t *rmp; - clib_error_t *error; - vxlan_gpe_ioam_main_t *sm = &vxlan_gpe_ioam_main; - vxlan4_gpe_tunnel_key_t key4; - uword *p = NULL; - vxlan_gpe_main_t *gm = &vxlan_gpe_main; - vxlan_gpe_tunnel_t *t = 0; - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - u32 vni; - - - if (!mp->is_ipv6) - { - clib_memcpy (&key4.local, &mp->local, sizeof (key4.local)); - clib_memcpy (&key4.remote, &mp->remote, sizeof (key4.remote)); - vni = clib_net_to_host_u32 (mp->vni); - key4.vni = clib_host_to_net_u32 (vni << 8); - key4.pad = 0; - - p = hash_get_mem (gm->vxlan4_gpe_tunnel_by_key, &key4); - } - else - { - return; - } - - if (!p) - return; - - t = pool_elt_at_index (gm->tunnels, p[0]); - - error = vxlan_gpe_ioam_set (t, hm->has_trace_option, - hm->has_pot_option, - hm->has_ppc_option, mp->is_ipv6); - - - if (error) - { - clib_error_report (error); - rv = clib_error_get_code (error); - } - - VXLAN_GPE_REPLY_MACRO (VL_API_VXLAN_GPE_IOAM_VNI_ENABLE_REPLY); -} - - -static void vl_api_vxlan_gpe_ioam_vni_disable_t_handler - (vl_api_vxlan_gpe_ioam_vni_disable_t * mp) -{ - int rv = 0; - vl_api_vxlan_gpe_ioam_vni_enable_reply_t *rmp; - clib_error_t *error; - vxlan_gpe_ioam_main_t *sm = &vxlan_gpe_ioam_main; - vxlan4_gpe_tunnel_key_t key4; - uword *p = NULL; - vxlan_gpe_main_t *gm = &vxlan_gpe_main; - vxlan_gpe_tunnel_t *t = 0; - u32 vni; - - - if (!mp->is_ipv6) - { - clib_memcpy (&key4.local, &mp->local, sizeof (key4.local)); - clib_memcpy (&key4.remote, &mp->remote, sizeof (key4.remote)); - vni = clib_net_to_host_u32 (mp->vni); - key4.vni = clib_host_to_net_u32 (vni << 8); - key4.pad = 0; - - p = hash_get_mem (gm->vxlan4_gpe_tunnel_by_key, &key4); - } - else - { - return; - } - - if (!p) - return; - - t = pool_elt_at_index (gm->tunnels, p[0]); - - error = vxlan_gpe_ioam_clear (t, 0, 0, 0, 0); - - - if (error) - { - clib_error_report (error); - rv = clib_error_get_code (error); - } - - - VXLAN_GPE_REPLY_MACRO (VL_API_VXLAN_GPE_IOAM_VNI_DISABLE_REPLY); -} - -static void vl_api_vxlan_gpe_ioam_transit_enable_t_handler - (vl_api_vxlan_gpe_ioam_transit_enable_t * mp) -{ - int rv = 0; - vl_api_vxlan_gpe_ioam_transit_enable_reply_t *rmp; - vxlan_gpe_ioam_main_t *sm = &vxlan_gpe_ioam_main; - ip46_address_t dst_addr; - - memset (&dst_addr.ip4, 0, sizeof (dst_addr.ip4)); - if (!mp->is_ipv6) - { - clib_memcpy (&dst_addr.ip4, &mp->dst_addr, sizeof (dst_addr.ip4)); - } - rv = vxlan_gpe_enable_disable_ioam_for_dest (sm->vlib_main, - dst_addr, - ntohl (mp->outer_fib_index), - mp->is_ipv6 ? 0 : 1, - 1 /* is_add */ ); - - VXLAN_GPE_REPLY_MACRO (VL_API_VXLAN_GPE_IOAM_TRANSIT_ENABLE_REPLY); -} - -static void vl_api_vxlan_gpe_ioam_transit_disable_t_handler - (vl_api_vxlan_gpe_ioam_transit_disable_t * mp) -{ - int rv = 0; - vl_api_vxlan_gpe_ioam_transit_disable_reply_t *rmp; - vxlan_gpe_ioam_main_t *sm = &vxlan_gpe_ioam_main; - ip46_address_t dst_addr; - - memset (&dst_addr.ip4, 0, sizeof (dst_addr.ip4)); - if (!mp->is_ipv6) - { - clib_memcpy (&dst_addr.ip4, &mp->dst_addr, sizeof (dst_addr.ip4)); - } - - rv = vxlan_gpe_ioam_disable_for_dest (sm->vlib_main, - dst_addr, - ntohl (mp->outer_fib_index), - mp->is_ipv6 ? 0 : 1); - VXLAN_GPE_REPLY_MACRO (VL_API_VXLAN_GPE_IOAM_TRANSIT_DISABLE_REPLY); -} - - -/* - * 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) -{ - vxlan_gpe_ioam_main_t *sm = &vxlan_gpe_ioam_main; - clib_error_t *error = 0; - - sm->vlib_main = vm; - sm->vnet_main = h->vnet_main; - sm->unix_time_0 = (u32) time (0); /* Store starting time */ - sm->vlib_time_0 = vlib_time_now (vm); - return error; -} - -/* Set up the API message handling tables */ -static clib_error_t * -vxlan_gpe_plugin_api_hookup (vlib_main_t * vm) -{ - vxlan_gpe_ioam_main_t *sm = &vxlan_gpe_ioam_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_vxlan_gpe_plugin_api_msg; -#undef _ - - return 0; -} - -static clib_error_t * -vxlan_gpe_init (vlib_main_t * vm) -{ - vxlan_gpe_ioam_main_t *sm = &vxlan_gpe_ioam_main; - clib_error_t *error = 0; - u8 *name; - u32 encap_node_index = vxlan_gpe_encap_ioam_v4_node.index; - u32 decap_node_index = vxlan_gpe_decap_ioam_v4_node.index; - vlib_node_t *vxlan_gpe_encap_node = NULL; - vlib_node_t *vxlan_gpe_decap_node = NULL; - uword next_node = 0; - - name = format (0, "ioam_vxlan_gpe_%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 = vxlan_gpe_plugin_api_hookup (vm); - - /* Hook the ioam-encap node to vxlan-gpe-encap */ - vxlan_gpe_encap_node = vlib_get_node_by_name (vm, (u8 *) "vxlan-gpe-encap"); - sm->encap_v4_next_node = - vlib_node_add_next (vm, vxlan_gpe_encap_node->index, encap_node_index); - - vxlan_gpe_decap_node = - vlib_get_node_by_name (vm, (u8 *) "vxlan4-gpe-input"); - next_node = - vlib_node_add_next (vm, vxlan_gpe_decap_node->index, decap_node_index); - vxlan_gpe_register_decap_protocol (VXLAN_GPE_PROTOCOL_IOAM, next_node); - - vec_new (vxlan_gpe_ioam_sw_interface_t, pool_elts (sm->sw_interfaces)); - sm->dst_by_ip4 = hash_create_mem (0, sizeof (fib_prefix_t), sizeof (uword)); - - sm->dst_by_ip6 = hash_create_mem (0, sizeof (fib_prefix_t), sizeof (uword)); - - vxlan_gpe_ioam_interface_init (); - vec_free (name); - - return error; -} - -VLIB_INIT_FUNCTION (vxlan_gpe_init); - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.c b/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.c deleted file mode 100644 index 6c04d9af..00000000 --- a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.c +++ /dev/null @@ -1,773 +0,0 @@ -/* - * 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. - */ -#include -#include -#include -#include -#include -#include -#include - -vxlan_gpe_ioam_main_t vxlan_gpe_ioam_main; - -int -vxlan_gpe_ioam_set_rewrite (vxlan_gpe_tunnel_t * t, int has_trace_option, - int has_pot_option, int has_ppc_option, - u8 ipv6_set) -{ - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - u32 size; - vxlan_gpe_ioam_hdr_t *vxlan_gpe_ioam_hdr; - u8 *current; - u8 trace_data_size = 0; - u8 pot_data_size = 0; - - if (has_trace_option == 0 && has_pot_option == 0) - return -1; - - /* Work out how much space we need */ - size = sizeof (vxlan_gpe_ioam_hdr_t); - - if (has_trace_option - && hm->add_options[VXLAN_GPE_OPTION_TYPE_IOAM_TRACE] != 0) - { - size += sizeof (vxlan_gpe_ioam_option_t); - size += hm->options_size[VXLAN_GPE_OPTION_TYPE_IOAM_TRACE]; - } - if (has_pot_option - && hm->add_options[VXLAN_GPE_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT] != 0) - { - size += sizeof (vxlan_gpe_ioam_option_t); - size += hm->options_size[VXLAN_GPE_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT]; - } - - t->rewrite_size = size; - - if (!ipv6_set) - { - vxlan4_gpe_rewrite (t, size, VXLAN_GPE_PROTOCOL_IOAM, - hm->encap_v4_next_node); - vxlan_gpe_ioam_hdr = - (vxlan_gpe_ioam_hdr_t *) (t->rewrite + - sizeof (ip4_vxlan_gpe_header_t)); - } - else - { - vxlan6_gpe_rewrite (t, size, VXLAN_GPE_PROTOCOL_IOAM, - VXLAN_GPE_ENCAP_NEXT_IP6_LOOKUP); - vxlan_gpe_ioam_hdr = - (vxlan_gpe_ioam_hdr_t *) (t->rewrite + - sizeof (ip6_vxlan_gpe_header_t)); - } - - - vxlan_gpe_ioam_hdr->type = VXLAN_GPE_PROTOCOL_IOAM; - /* Length of the header in octets */ - vxlan_gpe_ioam_hdr->length = size; - vxlan_gpe_ioam_hdr->protocol = t->protocol; - current = (u8 *) vxlan_gpe_ioam_hdr + sizeof (vxlan_gpe_ioam_hdr_t); - - if (has_trace_option - && hm->add_options[VXLAN_GPE_OPTION_TYPE_IOAM_TRACE] != 0) - { - if (0 != hm->add_options[VXLAN_GPE_OPTION_TYPE_IOAM_TRACE] (current, - &trace_data_size)) - return -1; - current += trace_data_size; - } - if (has_pot_option - && hm->add_options[VXLAN_GPE_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT] != 0) - { - pot_data_size = - hm->options_size[VXLAN_GPE_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT]; - if (0 == - hm->add_options[VXLAN_GPE_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT] - (current, &pot_data_size)) - current += pot_data_size; - } - - return 0; -} - -int -vxlan_gpe_ioam_clear_rewrite (vxlan_gpe_tunnel_t * t, int has_trace_option, - int has_pot_option, int has_ppc_option, - u8 ipv6_set) -{ - - t->rewrite_size = 0; - - if (!ipv6_set) - { - vxlan4_gpe_rewrite (t, 0, 0, VXLAN_GPE_ENCAP_NEXT_IP4_LOOKUP); - } - else - { - vxlan6_gpe_rewrite (t, 0, 0, VXLAN_GPE_ENCAP_NEXT_IP6_LOOKUP); - } - - - return 0; -} - -clib_error_t * -vxlan_gpe_ioam_clear (vxlan_gpe_tunnel_t * t, - int has_trace_option, int has_pot_option, - int has_ppc_option, u8 ipv6_set) -{ - int rv; - rv = vxlan_gpe_ioam_clear_rewrite (t, 0, 0, 0, 0); - - if (rv == 0) - { - return (0); - } - else - { - return clib_error_return_code (0, rv, 0, - "vxlan_gpe_ioam_clear_rewrite returned %d", - rv); - } - -} - - -clib_error_t * -vxlan_gpe_ioam_set (vxlan_gpe_tunnel_t * t, - int has_trace_option, int has_pot_option, - int has_ppc_option, u8 ipv6_set) -{ - int rv; - rv = vxlan_gpe_ioam_set_rewrite (t, has_trace_option, - has_pot_option, has_ppc_option, ipv6_set); - - if (rv == 0) - { - return (0); - } - else - { - return clib_error_return_code (0, rv, 0, - "vxlan_gpe_ioam_set_rewrite returned %d", - rv); - } - -} - -static void -vxlan_gpe_set_clear_output_feature_on_intf (vlib_main_t * vm, - u32 sw_if_index0, u8 is_add) -{ - - - - vnet_feature_enable_disable ("ip4-output", "vxlan-gpe-transit-ioam", - sw_if_index0, is_add, - 0 /* void *feature_config */ , - 0 /* u32 n_feature_config_bytes */ ); - return; -} - -void -vxlan_gpe_clear_output_feature_on_all_intfs (vlib_main_t * vm) -{ - vnet_sw_interface_t *si = 0; - vnet_main_t *vnm = vnet_get_main (); - vnet_interface_main_t *im = &vnm->interface_main; - - pool_foreach (si, im->sw_interfaces, ( - { - vxlan_gpe_set_clear_output_feature_on_intf - (vm, si->sw_if_index, 0); - })); - return; -} - - -extern fib_forward_chain_type_t -fib_entry_get_default_chain_type (const fib_entry_t * fib_entry); - -int -vxlan_gpe_enable_disable_ioam_for_dest (vlib_main_t * vm, - ip46_address_t dst_addr, - u32 outer_fib_index, - u8 is_ipv4, u8 is_add) -{ - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - u32 fib_index0 = 0; - u32 sw_if_index0 = ~0; - - fib_node_index_t fei = ~0; - fib_entry_t *fib_entry; - u32 adj_index0; - ip_adjacency_t *adj0; - fib_prefix_t fib_prefix; - //fib_forward_chain_type_t fct; - load_balance_t *lb_m, *lb_b; - const dpo_id_t *dpo0, *dpo1; - u32 i, j; - //vnet_hw_interface_t *hw; - - if (is_ipv4) - { - memset (&fib_prefix, 0, sizeof (fib_prefix_t)); - fib_prefix.fp_len = 32; - fib_prefix.fp_proto = FIB_PROTOCOL_IP4; - fib_prefix.fp_addr = dst_addr; - } - else - { - return 0; - } - - fei = fib_table_lookup (fib_index0, &fib_prefix); - fib_entry = fib_entry_get (fei); - - //fct = fib_entry_get_default_chain_type (fib_entry); - - if (!dpo_id_is_valid (&fib_entry->fe_lb /*[fct] */ )) - { - return (-1); - } - - lb_m = load_balance_get (fib_entry->fe_lb /*[fct] */ .dpoi_index); - - for (i = 0; i < lb_m->lb_n_buckets; i++) - { - dpo0 = load_balance_get_bucket_i (lb_m, i); - - if (dpo0->dpoi_type == DPO_LOAD_BALANCE) - { - lb_b = load_balance_get (dpo0->dpoi_index); - - for (j = 0; j < lb_b->lb_n_buckets; j++) - { - dpo1 = load_balance_get_bucket_i (lb_b, j); - - if (dpo1->dpoi_type == DPO_ADJACENCY) - { - adj_index0 = dpo1->dpoi_index; - - if (ADJ_INDEX_INVALID == adj_index0) - { - continue; - } - - adj0 = - ip_get_adjacency (&(ip4_main.lookup_main), adj_index0); - sw_if_index0 = adj0->rewrite_header.sw_if_index; - - if (~0 == sw_if_index0) - { - continue; - } - - - if (is_add) - { - vnet_feature_enable_disable ("ip4-output", - "vxlan-gpe-transit-ioam", - sw_if_index0, is_add, 0 - /* void *feature_config */ - , 0 /* u32 n_feature_config_bytes */ - ); - - vec_validate_init_empty (hm->bool_ref_by_sw_if_index, - sw_if_index0, ~0); - hm->bool_ref_by_sw_if_index[sw_if_index0] = 1; - } - else - { - hm->bool_ref_by_sw_if_index[sw_if_index0] = ~0; - } - } - } - } - } - - if (is_ipv4) - { - - uword *t = NULL; - vxlan_gpe_ioam_dest_tunnels_t *t1; - fib_prefix_t key4, *key4_copy; - hash_pair_t *hp; - memset (&key4, 0, sizeof (key4)); - key4.fp_proto = FIB_PROTOCOL_IP4; - key4.fp_addr.ip4.as_u32 = fib_prefix.fp_addr.ip4.as_u32; - t = hash_get_mem (hm->dst_by_ip4, &key4); - if (is_add) - { - if (t) - { - return 0; - } - pool_get_aligned (hm->dst_tunnels, t1, CLIB_CACHE_LINE_BYTES); - memset (t1, 0, sizeof (*t1)); - t1->fp_proto = FIB_PROTOCOL_IP4; - t1->dst_addr.ip4.as_u32 = fib_prefix.fp_addr.ip4.as_u32; - key4_copy = clib_mem_alloc (sizeof (*key4_copy)); - clib_memcpy (key4_copy, &key4, sizeof (*key4_copy)); - hash_set_mem (hm->dst_by_ip4, key4_copy, t1 - hm->dst_tunnels); - /* - * Attach to the FIB entry for the VxLAN-GPE destination - * and become its child. The dest route will invoke a callback - * when the fib entry changes, it can be used to - * re-program the output feature on the egress interface. - */ - - const fib_prefix_t tun_dst_pfx = { - .fp_len = 32, - .fp_proto = FIB_PROTOCOL_IP4, - .fp_addr = {.ip4 = t1->dst_addr.ip4,} - }; - - t1->fib_entry_index = - fib_table_entry_special_add (outer_fib_index, - &tun_dst_pfx, - FIB_SOURCE_RR, - FIB_ENTRY_FLAG_NONE, - ADJ_INDEX_INVALID); - t1->sibling_index = - fib_entry_child_add (t1->fib_entry_index, - hm->fib_entry_type, t1 - hm->dst_tunnels); - t1->outer_fib_index = outer_fib_index; - - } - else - { - if (!t) - { - return 0; - } - t1 = pool_elt_at_index (hm->dst_tunnels, t[0]); - hp = hash_get_pair (hm->dst_by_ip4, &key4); - key4_copy = (void *) (hp->key); - hash_unset_mem (hm->dst_by_ip4, &key4); - clib_mem_free (key4_copy); - pool_put (hm->dst_tunnels, t1); - } - } - else - { - // TBD for IPv6 - } - - return 0; -} - -void -vxlan_gpe_refresh_output_feature_on_all_dest (void) -{ - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - vxlan_gpe_ioam_dest_tunnels_t *t; - u32 i; - if (pool_elts (hm->dst_tunnels) == 0) - return; - vxlan_gpe_clear_output_feature_on_all_intfs (hm->vlib_main); - i = vec_len (hm->bool_ref_by_sw_if_index); - vec_free (hm->bool_ref_by_sw_if_index); - vec_validate_init_empty (hm->bool_ref_by_sw_if_index, i, ~0); - pool_foreach (t, hm->dst_tunnels, ( - { - vxlan_gpe_enable_disable_ioam_for_dest - (hm->vlib_main, - t->dst_addr, - t->outer_fib_index, - (t->fp_proto == FIB_PROTOCOL_IP4), 1 - /* is_add */ - ); - } - )); - return; -} - -void -vxlan_gpe_clear_output_feature_on_select_intfs (void) -{ - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - u32 sw_if_index0 = 0; - for (sw_if_index0 = 0; - sw_if_index0 < vec_len (hm->bool_ref_by_sw_if_index); sw_if_index0++) - { - if (hm->bool_ref_by_sw_if_index[sw_if_index0] == 0xFF) - { - vxlan_gpe_set_clear_output_feature_on_intf - (hm->vlib_main, sw_if_index0, 0); - } - } - - return; -} - -static clib_error_t * -vxlan_gpe_set_ioam_rewrite_command_fn (vlib_main_t * - vm, - unformat_input_t - * input, vlib_cli_command_t * cmd) -{ - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - ip46_address_t local, remote; - u8 local_set = 0; - u8 remote_set = 0; - u8 ipv4_set = 0; - u8 ipv6_set = 0; - u32 vni; - u8 vni_set = 0; - u8 disable = 0; - clib_error_t *rv = 0; - vxlan4_gpe_tunnel_key_t key4; - vxlan6_gpe_tunnel_key_t key6; - uword *p; - vxlan_gpe_main_t *gm = &vxlan_gpe_main; - vxlan_gpe_tunnel_t *t = 0; - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "local %U", unformat_ip4_address, &local.ip4)) - { - local_set = 1; - ipv4_set = 1; - } - else - if (unformat (input, "remote %U", unformat_ip4_address, &remote.ip4)) - { - remote_set = 1; - ipv4_set = 1; - } - else if (unformat (input, "local %U", unformat_ip6_address, &local.ip6)) - { - local_set = 1; - ipv6_set = 1; - } - else - if (unformat (input, "remote %U", unformat_ip6_address, &remote.ip6)) - { - remote_set = 1; - ipv6_set = 1; - } - else if (unformat (input, "vni %d", &vni)) - vni_set = 1; - else if (unformat (input, "disable")) - disable = 1; - else - break; - } - - if (local_set == 0) - return clib_error_return (0, "tunnel local address not specified"); - if (remote_set == 0) - return clib_error_return (0, "tunnel remote address not specified"); - if (ipv4_set && ipv6_set) - return clib_error_return (0, "both IPv4 and IPv6 addresses specified"); - if ((ipv4_set - && memcmp (&local.ip4, &remote.ip4, - sizeof (local.ip4)) == 0) || (ipv6_set - && - memcmp - (&local.ip6, - &remote.ip6, - sizeof (local.ip6)) == 0)) - return clib_error_return (0, "src and dst addresses are identical"); - if (vni_set == 0) - return clib_error_return (0, "vni not specified"); - if (!ipv6_set) - { - key4.local = local.ip4.as_u32; - key4.remote = remote.ip4.as_u32; - key4.vni = clib_host_to_net_u32 (vni << 8); - key4.pad = 0; - p = hash_get_mem (gm->vxlan4_gpe_tunnel_by_key, &key4); - } - else - { - key6.local.as_u64[0] = local.ip6.as_u64[0]; - key6.local.as_u64[1] = local.ip6.as_u64[1]; - key6.remote.as_u64[0] = remote.ip6.as_u64[0]; - key6.remote.as_u64[1] = remote.ip6.as_u64[1]; - key6.vni = clib_host_to_net_u32 (vni << 8); - p = hash_get_mem (gm->vxlan6_gpe_tunnel_by_key, &key6); - } - - if (!p) - return clib_error_return (0, "VxLAN Tunnel not found"); - t = pool_elt_at_index (gm->tunnels, p[0]); - if (!disable) - { - rv = - vxlan_gpe_ioam_set (t, hm->has_trace_option, - hm->has_pot_option, hm->has_ppc_option, ipv6_set); - } - else - { - rv = vxlan_gpe_ioam_clear (t, 0, 0, 0, 0); - } - return rv; -} - - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (vxlan_gpe_set_ioam_rewrite_cmd, static) = { - .path = "set vxlan-gpe-ioam", - .short_help = "set vxlan-gpe-ioam vxlan [disable]", - .function = vxlan_gpe_set_ioam_rewrite_command_fn, -}; -/* *INDENT-ON* */ - - - -clib_error_t * -vxlan_gpe_ioam_enable (int has_trace_option, - int has_pot_option, int has_ppc_option) -{ - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - hm->has_trace_option = has_trace_option; - hm->has_pot_option = has_pot_option; - hm->has_ppc_option = has_ppc_option; - if (hm->has_trace_option) - { - vxlan_gpe_trace_profile_setup (); - } - - return 0; -} - -clib_error_t * -vxlan_gpe_ioam_disable (int - has_trace_option, - int has_pot_option, int has_ppc_option) -{ - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - hm->has_trace_option = has_trace_option; - hm->has_pot_option = has_pot_option; - hm->has_ppc_option = has_ppc_option; - if (!hm->has_trace_option) - { - vxlan_gpe_trace_profile_cleanup (); - } - - return 0; -} - -void -vxlan_gpe_set_next_override (uword next) -{ - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - hm->decap_v4_next_override = next; - return; -} - -static clib_error_t * -vxlan_gpe_set_ioam_flags_command_fn (vlib_main_t * vm, - unformat_input_t - * input, vlib_cli_command_t * cmd) -{ - int has_trace_option = 0; - int has_pot_option = 0; - int has_ppc_option = 0; - clib_error_t *rv = 0; - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "trace")) - has_trace_option = 1; - else if (unformat (input, "pot")) - has_pot_option = 1; - else if (unformat (input, "ppc encap")) - has_ppc_option = PPC_ENCAP; - else if (unformat (input, "ppc decap")) - has_ppc_option = PPC_DECAP; - else if (unformat (input, "ppc none")) - has_ppc_option = PPC_NONE; - else - break; - } - - - rv = - vxlan_gpe_ioam_enable (has_trace_option, has_pot_option, has_ppc_option); - return rv; -} - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (vxlan_gpe_set_ioam_flags_cmd, static) = -{ -.path = "set vxlan-gpe-ioam rewrite", -.short_help = "set vxlan-gpe-ioam [trace] [pot] [ppc ]", -.function = vxlan_gpe_set_ioam_flags_command_fn,}; -/* *INDENT-ON* */ - - -int vxlan_gpe_ioam_disable_for_dest - (vlib_main_t * vm, ip46_address_t dst_addr, u32 outer_fib_index, - u8 ipv4_set) -{ - vxlan_gpe_ioam_dest_tunnels_t *t; - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - - vxlan_gpe_enable_disable_ioam_for_dest (hm->vlib_main, - dst_addr, outer_fib_index, ipv4_set, - 0); - if (pool_elts (hm->dst_tunnels) == 0) - { - vxlan_gpe_clear_output_feature_on_select_intfs (); - return 0; - } - - pool_foreach (t, hm->dst_tunnels, ( - { - vxlan_gpe_enable_disable_ioam_for_dest - (hm->vlib_main, - t->dst_addr, - t->outer_fib_index, - (t->fp_proto == - FIB_PROTOCOL_IP4), 1 /* is_add */ ); - } - )); - vxlan_gpe_clear_output_feature_on_select_intfs (); - return (0); - -} - -static clib_error_t *vxlan_gpe_set_ioam_transit_rewrite_command_fn - (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) -{ - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - ip46_address_t dst_addr; - u8 dst_addr_set = 0; - u8 ipv4_set = 0; - u8 ipv6_set = 0; - u8 disable = 0; - clib_error_t *rv = 0; - u32 outer_fib_index = 0; - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "dst-ip %U", unformat_ip4_address, &dst_addr.ip4)) - { - dst_addr_set = 1; - ipv4_set = 1; - } - else - if (unformat - (input, "dst-ip %U", unformat_ip6_address, &dst_addr.ip6)) - { - dst_addr_set = 1; - ipv6_set = 1; - } - else if (unformat (input, "outer-fib-index %d", &outer_fib_index)) - { - } - - else if (unformat (input, "disable")) - disable = 1; - else - break; - } - - if (dst_addr_set == 0) - return clib_error_return (0, "tunnel destination address not specified"); - if (ipv4_set && ipv6_set) - return clib_error_return (0, "both IPv4 and IPv6 addresses specified"); - if (!disable) - { - vxlan_gpe_enable_disable_ioam_for_dest (hm->vlib_main, - dst_addr, outer_fib_index, - ipv4_set, 1); - } - else - { - vxlan_gpe_ioam_disable_for_dest - (vm, dst_addr, outer_fib_index, ipv4_set); - } - return rv; -} - - /* *INDENT-OFF* */ -VLIB_CLI_COMMAND (vxlan_gpe_set_ioam_transit_rewrite_cmd, static) = { - .path = "set vxlan-gpe-ioam-transit", - .short_help = "set vxlan-gpe-ioam-transit dst-ip [outer-fib-index ] [disable]", - .function = vxlan_gpe_set_ioam_transit_rewrite_command_fn, -}; -/* *INDENT-ON* */ - -clib_error_t *clear_vxlan_gpe_ioam_rewrite_command_fn - (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) -{ - return (vxlan_gpe_ioam_disable (0, 0, 0)); -} - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (vxlan_gpe_clear_ioam_flags_cmd, static) = -{ -.path = "clear vxlan-gpe-ioam rewrite", -.short_help = "clear vxlan-gpe-ioam rewrite", -.function = clear_vxlan_gpe_ioam_rewrite_command_fn, -}; -/* *INDENT-ON* */ - - -/** - * Function definition to backwalk a FIB node - */ -static fib_node_back_walk_rc_t -vxlan_gpe_ioam_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx) -{ - vxlan_gpe_refresh_output_feature_on_all_dest (); - return (FIB_NODE_BACK_WALK_CONTINUE); -} - -/** - * Function definition to get a FIB node from its index - */ -static fib_node_t * -vxlan_gpe_ioam_fib_node_get (fib_node_index_t index) -{ - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - return (&hm->node); -} - -/** - * Function definition to inform the FIB node that its last lock has gone. - */ -static void -vxlan_gpe_ioam_last_lock_gone (fib_node_t * node) -{ - ASSERT (0); -} - - -/* - * Virtual function table registered by MPLS GRE tunnels - * for participation in the FIB object graph. - */ -const static fib_node_vft_t vxlan_gpe_ioam_vft = { - .fnv_get = vxlan_gpe_ioam_fib_node_get, - .fnv_last_lock = vxlan_gpe_ioam_last_lock_gone, - .fnv_back_walk = vxlan_gpe_ioam_back_walk, -}; - -void -vxlan_gpe_ioam_interface_init (void) -{ - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - hm->fib_entry_type = fib_node_register_new_type (&vxlan_gpe_ioam_vft); - return; -} - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.h b/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.h deleted file mode 100644 index 3b7d72cf..00000000 --- a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.h +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __included_vxlan_gpe_ioam_h__ -#define __included_vxlan_gpe_ioam_h__ - -#include -#include -#include -#include - - -typedef struct vxlan_gpe_sw_interface_ -{ - u32 sw_if_index; -} vxlan_gpe_ioam_sw_interface_t; - -typedef struct vxlan_gpe_dest_tunnels_ -{ - ip46_address_t dst_addr; - u32 fp_proto; - u32 sibling_index; - fib_node_index_t fib_entry_index; - u32 outer_fib_index; -} vxlan_gpe_ioam_dest_tunnels_t; - -typedef struct vxlan_gpe_ioam_main_ -{ - /** - * Linkage into the FIB object graph - */ - fib_node_t node; - - /* time scale transform. Joy. */ - u32 unix_time_0; - f64 vlib_time_0; - - - /* Trace option */ - u8 has_trace_option; - - /* Pot option */ - u8 has_pot_option; - -#define PPC_NONE 0 -#define PPC_ENCAP 1 -#define PPC_DECAP 2 - u8 has_ppc_option; - -#define TSP_SECONDS 0 -#define TSP_MILLISECONDS 1 -#define TSP_MICROSECONDS 2 -#define TSP_NANOSECONDS 3 - - /* Array of function pointers to ADD and POP VxLAN-GPE iOAM option handling routines */ - u8 options_size[256]; - int (*add_options[256]) (u8 * rewrite_string, u8 * rewrite_size); - int (*pop_options[256]) (ip4_header_t * ip, vxlan_gpe_ioam_option_t * opt); - - /* Array of function pointers to iOAM option handling routines */ - int (*options[256]) (vlib_buffer_t * b, vxlan_gpe_ioam_option_t * opt, - u8 is_ipv4, u8 use_adj); - u8 *(*trace[256]) (u8 * s, vxlan_gpe_ioam_option_t * opt); - - /* API message ID base */ - u16 msg_id_base; - - /* Override to export for iOAM */ - uword decap_v4_next_override; - uword decap_v6_next_override; - - /* sequence of node graph for encap */ - uword encap_v4_next_node; - uword encap_v6_next_node; - - /* Software interfaces. */ - vxlan_gpe_ioam_sw_interface_t *sw_interfaces; - - /* hash ip4/ip6 -> list of destinations for doing transit iOAM operation */ - vxlan_gpe_ioam_dest_tunnels_t *dst_tunnels; - uword *dst_by_ip4; - uword *dst_by_ip6; - - /** per sw_if_index, to maintain bitmap */ - u8 *bool_ref_by_sw_if_index; - fib_node_type_t fib_entry_type; - - /** State convenience vlib_main_t */ - vlib_main_t *vlib_main; - /** State convenience vnet_main_t */ - vnet_main_t *vnet_main; - - -} vxlan_gpe_ioam_main_t; -extern vxlan_gpe_ioam_main_t vxlan_gpe_ioam_main; - -/* - * Primary h-b-h handler trace support - */ -typedef struct -{ - u32 next_index; - u32 trace_len; - u8 option_data[256]; -} ioam_trace_t; - - -vlib_node_registration_t vxlan_gpe_encap_ioam_v4_node; -vlib_node_registration_t vxlan_gpe_decap_ioam_v4_node; -vlib_node_registration_t vxlan_gpe_transit_ioam_v4_node; - -clib_error_t *vxlan_gpe_ioam_enable (int has_trace_option, int has_pot_option, - int has_ppc_option); - -clib_error_t *vxlan_gpe_ioam_disable (int has_trace_option, - int has_pot_option, int has_ppc_option); - -clib_error_t *vxlan_gpe_ioam_set (vxlan_gpe_tunnel_t * t, - int has_trace_option, - int has_pot_option, - int has_ppc_option, u8 ipv6_set); -clib_error_t *vxlan_gpe_ioam_clear (vxlan_gpe_tunnel_t * t, - int has_trace_option, int has_pot_option, - int has_ppc_option, u8 ipv6_set); - -int vxlan_gpe_ioam_add_register_option (u8 option, - u8 size, - int rewrite_options (u8 * - rewrite_string, - u8 * - rewrite_size)); - -int vxlan_gpe_add_unregister_option (u8 option); - -int vxlan_gpe_ioam_register_option (u8 option, - int options (vlib_buffer_t * b, - vxlan_gpe_ioam_option_t * - opt, u8 is_ipv4, u8 use_adj), - u8 * trace (u8 * s, - vxlan_gpe_ioam_option_t * - opt)); -int vxlan_gpe_ioam_unregister_option (u8 option); - -int vxlan_gpe_trace_profile_setup (void); - -int vxlan_gpe_trace_profile_cleanup (void); -extern void vxlan_gpe_ioam_interface_init (void); -int -vxlan_gpe_enable_disable_ioam_for_dest (vlib_main_t * vm, - ip46_address_t dst_addr, - u32 outer_fib_index, - u8 is_ipv4, u8 is_add); -int vxlan_gpe_ioam_disable_for_dest - (vlib_main_t * vm, ip46_address_t dst_addr, u32 outer_fib_index, - u8 ipv4_set); - -typedef enum -{ - VXLAN_GPE_DECAP_IOAM_V4_NEXT_POP, - VXLAN_GPE_DECAP_IOAM_V4_NEXT_DROP, - VXLAN_GPE_DECAP_IOAM_V4_N_NEXT -} vxlan_gpe_decap_ioam_v4_next_t; - -#endif - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_packet.h b/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_packet.h deleted file mode 100644 index a7ef859e..00000000 --- a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_packet.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __included_vxlan_gpe_ioam_packet_h__ -#define __included_vxlan_gpe_ioam_packet_h__ - -#include -#include -#include - - - -#define VXLAN_GPE_OPTION_TYPE_IOAM_TRACE 59 -#define VXLAN_GPE_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT 60 - -/** - * @brief VXLAN GPE Extension (iOAM) Header definition - */ -typedef struct -{ - u8 type; - u8 length; - /** Reserved */ - u8 reserved; - /** see vxlan_gpe_protocol_t */ - u8 protocol; -} vxlan_gpe_ioam_hdr_t; - -/* - * @brief VxLAN GPE iOAM Option definition - */ -typedef struct -{ - /* Option Type */ - u8 type; - /* Length in octets of the option data field */ - u8 length; -} vxlan_gpe_ioam_option_t; - - -#endif - - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_trace.c b/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_trace.c deleted file mode 100644 index e37b1642..00000000 --- a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_trace.c +++ /dev/null @@ -1,552 +0,0 @@ -/* - * 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. - */ -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include - -/* Timestamp precision multipliers for seconds, milliseconds, microseconds - * and nanoseconds respectively. - */ -static f64 trace_tsp_mul[4] = { 1, 1e3, 1e6, 1e9 }; - -typedef union -{ - u64 as_u64; - u32 as_u32[2]; -} time_u64_t; - - -/* *INDENT-OFF* */ -typedef CLIB_PACKED(struct { - vxlan_gpe_ioam_option_t hdr; - u8 ioam_trace_type; - u8 data_list_elts_left; - u32 elts[0]; /* Variable type. So keep it generic */ -}) vxlan_gpe_ioam_trace_option_t; -/* *INDENT-ON* */ - - -#define foreach_vxlan_gpe_ioam_trace_stats \ - _(SUCCESS, "Pkts updated with TRACE records") \ - _(FAILED, "Errors in TRACE due to lack of TRACE records") - -static char *vxlan_gpe_ioam_trace_stats_strings[] = { -#define _(sym,string) string, - foreach_vxlan_gpe_ioam_trace_stats -#undef _ -}; - -typedef enum -{ -#define _(sym,str) VXLAN_GPE_IOAM_TRACE_##sym, - foreach_vxlan_gpe_ioam_trace_stats -#undef _ - VXLAN_GPE_IOAM_TRACE_N_STATS, -} vxlan_gpe_ioam_trace_stats_t; - - -typedef struct -{ - /* stats */ - u64 counters[ARRAY_LEN (vxlan_gpe_ioam_trace_stats_strings)]; - - /* convenience */ - vlib_main_t *vlib_main; - vnet_main_t *vnet_main; -} vxlan_gpe_ioam_trace_main_t; - -vxlan_gpe_ioam_trace_main_t vxlan_gpe_ioam_trace_main; - -int -vxlan_gpe_ioam_add_register_option (u8 option, - u8 size, - int rewrite_options (u8 * rewrite_string, - u8 * rewrite_size)) -{ - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - - ASSERT (option < ARRAY_LEN (hm->add_options)); - - /* Already registered */ - if (hm->add_options[option]) - return (-1); - - hm->add_options[option] = rewrite_options; - hm->options_size[option] = size; - - return (0); -} - -int -vxlan_gpe_add_unregister_option (u8 option) -{ - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - - ASSERT (option < ARRAY_LEN (hm->add_options)); - - /* Not registered */ - if (!hm->add_options[option]) - return (-1); - - hm->add_options[option] = NULL; - hm->options_size[option] = 0; - return (0); -} - - -int -vxlan_gpe_ioam_register_option (u8 option, - int options (vlib_buffer_t * b, - vxlan_gpe_ioam_option_t * opt, - u8 is_ipv4, u8 use_adj), - u8 * trace (u8 * s, - vxlan_gpe_ioam_option_t * opt)) -{ - vxlan_gpe_ioam_main_t *im = &vxlan_gpe_ioam_main; - - ASSERT (option < ARRAY_LEN (im->options)); - - /* Already registered */ - if (im->options[option]) - return (-1); - - im->options[option] = options; - im->trace[option] = trace; - - return (0); -} - -int -vxlan_gpe_ioam_unregister_option (u8 option) -{ - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - - ASSERT (option < ARRAY_LEN (hm->options)); - - /* Not registered */ - if (!hm->options[option]) - return (-1); - - hm->options[option] = NULL; - hm->trace[option] = NULL; - - return (0); -} - - -always_inline void -vxlan_gpe_ioam_trace_stats_increment_counter (u32 counter_index, - u64 increment) -{ - vxlan_gpe_ioam_trace_main_t *hm = &vxlan_gpe_ioam_trace_main; - - hm->counters[counter_index] += increment; -} - - -static u8 * -format_ioam_data_list_element (u8 * s, va_list * args) -{ - u32 *elt = va_arg (*args, u32 *); - u8 *trace_type_p = va_arg (*args, u8 *); - u8 trace_type = *trace_type_p; - - - if (trace_type & BIT_TTL_NODEID) - { - u32 ttl_node_id_host_byte_order = clib_net_to_host_u32 (*elt); - s = format (s, "ttl 0x%x node id 0x%x ", - ttl_node_id_host_byte_order >> 24, - ttl_node_id_host_byte_order & 0x00FFFFFF); - - elt++; - } - - if (trace_type & BIT_ING_INTERFACE && trace_type & BIT_ING_INTERFACE) - { - u32 ingress_host_byte_order = clib_net_to_host_u32 (*elt); - s = format (s, "ingress 0x%x egress 0x%x ", - ingress_host_byte_order >> 16, - ingress_host_byte_order & 0xFFFF); - elt++; - } - - if (trace_type & BIT_TIMESTAMP) - { - u32 ts_in_host_byte_order = clib_net_to_host_u32 (*elt); - s = format (s, "ts 0x%x \n", ts_in_host_byte_order); - elt++; - } - - if (trace_type & BIT_APPDATA) - { - u32 appdata_in_host_byte_order = clib_net_to_host_u32 (*elt); - s = format (s, "app 0x%x ", appdata_in_host_byte_order); - elt++; - } - - return s; -} - - - -int -vxlan_gpe_ioam_trace_rewrite_handler (u8 * rewrite_string, u8 * rewrite_size) -{ - vxlan_gpe_ioam_trace_option_t *trace_option = NULL; - u8 trace_data_size = 0; - u8 trace_option_elts = 0; - trace_profile *profile = NULL; - - - profile = trace_profile_find (); - - if (PREDICT_FALSE (!profile)) - { - return (-1); - } - - if (PREDICT_FALSE (!rewrite_string)) - return -1; - - trace_option_elts = profile->num_elts; - trace_data_size = fetch_trace_data_size (profile->trace_type); - trace_option = (vxlan_gpe_ioam_trace_option_t *) rewrite_string; - trace_option->hdr.type = VXLAN_GPE_OPTION_TYPE_IOAM_TRACE; - trace_option->hdr.length = 2 /*ioam_trace_type,data_list_elts_left */ + - trace_option_elts * trace_data_size; - trace_option->ioam_trace_type = profile->trace_type & TRACE_TYPE_MASK; - trace_option->data_list_elts_left = trace_option_elts; - *rewrite_size = - sizeof (vxlan_gpe_ioam_trace_option_t) + - (trace_option_elts * trace_data_size); - - return 0; -} - - -int -vxlan_gpe_ioam_trace_data_list_handler (vlib_buffer_t * b, - vxlan_gpe_ioam_option_t * opt, - u8 is_ipv4, u8 use_adj) -{ - u8 elt_index = 0; - vxlan_gpe_ioam_trace_option_t *trace = - (vxlan_gpe_ioam_trace_option_t *) opt; - time_u64_t time_u64; - u32 *elt; - int rv = 0; - trace_profile *profile = NULL; - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - - - profile = trace_profile_find (); - - if (PREDICT_FALSE (!profile)) - { - return (-1); - } - - - time_u64.as_u64 = 0; - - if (PREDICT_TRUE (trace->data_list_elts_left)) - { - trace->data_list_elts_left--; - /* fetch_trace_data_size returns in bytes. Convert it to 4-bytes - * to skip to this node's location. - */ - elt_index = - trace->data_list_elts_left * - fetch_trace_data_size (trace->ioam_trace_type) / 4; - elt = &trace->elts[elt_index]; - if (is_ipv4) - { - if (trace->ioam_trace_type & BIT_TTL_NODEID) - { - ip4_header_t *ip0 = vlib_buffer_get_current (b); - /* The transit case is the only case where the TTL decrement happens - * before iOAM processing. For now, use the use_adj flag as an overload. - * We can probably use a separate flag instead of overloading the use_adj flag. - */ - *elt = clib_host_to_net_u32 (((ip0->ttl - 1 + use_adj) << 24) | - profile->node_id); - elt++; - } - - if (trace->ioam_trace_type & BIT_ING_INTERFACE) - { - u16 tx_if = 0; - u32 adj_index = vnet_buffer (b)->ip.adj_index[VLIB_TX]; - ip4_main_t *im4 = &ip4_main; - ip_lookup_main_t *lm = &im4->lookup_main; - if (use_adj) - { - ip_adjacency_t *adj = ip_get_adjacency (lm, adj_index); - tx_if = adj->rewrite_header.sw_if_index & 0xFFFF; - } - - *elt = - (vnet_buffer (b)->sw_if_index[VLIB_RX] & 0xFFFF) << 16 | - tx_if; - *elt = clib_host_to_net_u32 (*elt); - elt++; - } - } - else - { - if (trace->ioam_trace_type & BIT_TTL_NODEID) - { - ip6_header_t *ip0 = vlib_buffer_get_current (b); - *elt = clib_host_to_net_u32 ((ip0->hop_limit << 24) | - profile->node_id); - elt++; - } - if (trace->ioam_trace_type & BIT_ING_INTERFACE) - { - u16 tx_if = 0; - u32 adj_index = vnet_buffer (b)->ip.adj_index[VLIB_TX]; - ip6_main_t *im6 = &ip6_main; - ip_lookup_main_t *lm = &im6->lookup_main; - if (use_adj) - { - ip_adjacency_t *adj = ip_get_adjacency (lm, adj_index); - tx_if = adj->rewrite_header.sw_if_index & 0xFFFF; - } - - *elt = - (vnet_buffer (b)->sw_if_index[VLIB_RX] & 0xFFFF) << 16 | - tx_if; - *elt = clib_host_to_net_u32 (*elt); - elt++; - } - } - - if (trace->ioam_trace_type & BIT_TIMESTAMP) - { - /* Send least significant 32 bits */ - f64 time_f64 = - (f64) (((f64) hm->unix_time_0) + - (vlib_time_now (hm->vlib_main) - hm->vlib_time_0)); - - time_u64.as_u64 = time_f64 * trace_tsp_mul[profile->trace_tsp]; - *elt = clib_host_to_net_u32 (time_u64.as_u32[0]); - elt++; - } - - if (trace->ioam_trace_type & BIT_APPDATA) - { - /* $$$ set elt0->app_data */ - *elt = clib_host_to_net_u32 (profile->app_data); - elt++; - } - vxlan_gpe_ioam_trace_stats_increment_counter - (VXLAN_GPE_IOAM_TRACE_SUCCESS, 1); - } - else - { - vxlan_gpe_ioam_trace_stats_increment_counter - (VXLAN_GPE_IOAM_TRACE_FAILED, 1); - } - return (rv); -} - -u8 * -vxlan_gpe_ioam_trace_data_list_trace_handler (u8 * s, - vxlan_gpe_ioam_option_t * opt) -{ - vxlan_gpe_ioam_trace_option_t *trace; - u8 trace_data_size_in_words = 0; - u32 *elt; - int elt_index = 0; - - trace = (vxlan_gpe_ioam_trace_option_t *) opt; - s = - format (s, " Trace Type 0x%x , %d elts left\n", trace->ioam_trace_type, - trace->data_list_elts_left); - trace_data_size_in_words = - fetch_trace_data_size (trace->ioam_trace_type) / 4; - elt = &trace->elts[0]; - while ((u8 *) elt < ((u8 *) (&trace->elts[0]) + trace->hdr.length - 2 - /* -2 accounts for ioam_trace_type,elts_left */ )) - { - s = format (s, " [%d] %U\n", elt_index, - format_ioam_data_list_element, - elt, &trace->ioam_trace_type); - elt_index++; - elt += trace_data_size_in_words; - } - return (s); -} - - -static clib_error_t * -vxlan_gpe_show_ioam_trace_cmd_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - vxlan_gpe_ioam_trace_main_t *hm = &vxlan_gpe_ioam_trace_main; - u8 *s = 0; - int i = 0; - - for (i = 0; i < VXLAN_GPE_IOAM_TRACE_N_STATS; i++) - { - s = format (s, " %s - %lu\n", vxlan_gpe_ioam_trace_stats_strings[i], - hm->counters[i]); - } - - vlib_cli_output (vm, "%v", s); - vec_free (s); - return 0; -} - - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (vxlan_gpe_show_ioam_trace_cmd, static) = { - .path = "show ioam vxlan-gpe trace", - .short_help = "iOAM trace statistics", - .function = vxlan_gpe_show_ioam_trace_cmd_fn, -}; -/* *INDENT-ON* */ - - -static clib_error_t * -vxlan_gpe_ioam_trace_init (vlib_main_t * vm) -{ - vxlan_gpe_ioam_trace_main_t *hm = &vxlan_gpe_ioam_trace_main; - clib_error_t *error; - - if ((error = vlib_call_init_function (vm, ip_main_init))) - return (error); - - if ((error = vlib_call_init_function (vm, ip6_lookup_init))) - return error; - - if ((error = vlib_call_init_function (vm, vxlan_gpe_init))) - return (error); - - hm->vlib_main = vm; - hm->vnet_main = vnet_get_main (); - memset (hm->counters, 0, sizeof (hm->counters)); - - if (vxlan_gpe_ioam_register_option - (VXLAN_GPE_OPTION_TYPE_IOAM_TRACE, - vxlan_gpe_ioam_trace_data_list_handler, - vxlan_gpe_ioam_trace_data_list_trace_handler) < 0) - return (clib_error_create - ("registration of VXLAN_GPE_OPTION_TYPE_IOAM_TRACE failed")); - - - if (vxlan_gpe_ioam_add_register_option - (VXLAN_GPE_OPTION_TYPE_IOAM_TRACE, - sizeof (vxlan_gpe_ioam_trace_option_t), - vxlan_gpe_ioam_trace_rewrite_handler) < 0) - return (clib_error_create - ("registration of VXLAN_GPE_OPTION_TYPE_IOAM_TRACE for rewrite failed")); - - - return (0); -} - -VLIB_INIT_FUNCTION (vxlan_gpe_ioam_trace_init); - -int -vxlan_gpe_trace_profile_cleanup (void) -{ - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - - hm->options_size[VXLAN_GPE_OPTION_TYPE_IOAM_TRACE] = 0; - - return 0; - -} - -static int -vxlan_gpe_ioam_trace_get_sizeof_handler (u32 * result) -{ - u16 size = 0; - u8 trace_data_size = 0; - trace_profile *profile = NULL; - - *result = 0; - - profile = trace_profile_find (); - - if (PREDICT_FALSE (!profile)) - { - return (-1); - } - - trace_data_size = fetch_trace_data_size (profile->trace_type); - if (PREDICT_FALSE (trace_data_size == 0)) - return VNET_API_ERROR_INVALID_VALUE; - - if (PREDICT_FALSE (profile->num_elts * trace_data_size > 254)) - return VNET_API_ERROR_INVALID_VALUE; - - size += - sizeof (vxlan_gpe_ioam_trace_option_t) + - profile->num_elts * trace_data_size; - *result = size; - - return 0; -} - - -int -vxlan_gpe_trace_profile_setup (void) -{ - u32 trace_size = 0; - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - - trace_profile *profile = NULL; - - - profile = trace_profile_find (); - - if (PREDICT_FALSE (!profile)) - { - return (-1); - } - - - if (vxlan_gpe_ioam_trace_get_sizeof_handler (&trace_size) < 0) - return (-1); - - hm->options_size[VXLAN_GPE_OPTION_TYPE_IOAM_TRACE] = trace_size; - - return (0); -} - - - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_util.h b/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_util.h deleted file mode 100644 index c0ad8d9d..00000000 --- a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_util.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __included_vxlan_gpe_ioam_util_h__ -#define __included_vxlan_gpe_ioam_util_h__ - -#include -#include -#include - - -typedef struct -{ - u32 tunnel_index; - ioam_trace_t fmt_trace; -} vxlan_gpe_ioam_v4_trace_t; - - -static u8 * -format_vxlan_gpe_ioam_v4_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 *); - vxlan_gpe_ioam_v4_trace_t *t1 = va_arg (*args, vxlan_gpe_ioam_v4_trace_t *); - ioam_trace_t *t = &(t1->fmt_trace); - vxlan_gpe_ioam_option_t *fmt_trace0; - vxlan_gpe_ioam_option_t *opt0, *limit0; - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - - u8 type0; - - fmt_trace0 = (vxlan_gpe_ioam_option_t *) t->option_data; - - s = format (s, "VXLAN-GPE-IOAM: next_index %d len %d traced %d", - t->next_index, fmt_trace0->length, t->trace_len); - - opt0 = (vxlan_gpe_ioam_option_t *) (fmt_trace0 + 1); - limit0 = (vxlan_gpe_ioam_option_t *) ((u8 *) fmt_trace0) + t->trace_len; - - while (opt0 < limit0) - { - type0 = opt0->type; - switch (type0) - { - case 0: /* Pad, just stop */ - opt0 = (vxlan_gpe_ioam_option_t *) ((u8 *) opt0) + 1; - break; - - default: - if (hm->trace[type0]) - { - s = (*hm->trace[type0]) (s, opt0); - } - else - { - s = - format (s, "\n unrecognized option %d length %d", type0, - opt0->length); - } - opt0 = - (vxlan_gpe_ioam_option_t *) (((u8 *) opt0) + opt0->length + - sizeof (vxlan_gpe_ioam_option_t)); - break; - } - } - - s = format (s, "VXLAN-GPE-IOAM: tunnel %d", t1->tunnel_index); - return s; -} - - -always_inline void -vxlan_gpe_encap_decap_ioam_v4_one_inline (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_buffer_t * b0, - u32 * next0, u32 drop_node_val, - u8 use_adj) -{ - ip4_header_t *ip0; - udp_header_t *udp_hdr0; - vxlan_gpe_header_t *gpe_hdr0; - vxlan_gpe_ioam_hdr_t *gpe_ioam0; - vxlan_gpe_ioam_option_t *opt0; - vxlan_gpe_ioam_option_t *limit0; - vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; - - /* Populate the iOAM header */ - ip0 = vlib_buffer_get_current (b0); - udp_hdr0 = (udp_header_t *) (ip0 + 1); - gpe_hdr0 = (vxlan_gpe_header_t *) (udp_hdr0 + 1); - gpe_ioam0 = (vxlan_gpe_ioam_hdr_t *) (gpe_hdr0 + 1); - opt0 = (vxlan_gpe_ioam_option_t *) (gpe_ioam0 + 1); - limit0 = (vxlan_gpe_ioam_option_t *) ((u8 *) gpe_ioam0 + gpe_ioam0->length); - - /* - * Basic validity checks - */ - if (gpe_ioam0->length > clib_net_to_host_u16 (ip0->length)) - { - *next0 = drop_node_val; - return; - } - - /* Scan the set of h-b-h options, process ones that we understand */ - while (opt0 < limit0) - { - u8 type0; - type0 = opt0->type; - switch (type0) - { - case 0: /* Pad1 */ - opt0 = (vxlan_gpe_ioam_option_t *) ((u8 *) opt0) + 1; - continue; - case 1: /* PadN */ - break; - default: - if (hm->options[type0]) - { - if ((*hm->options[type0]) (b0, opt0, 1 /* is_ipv4 */ , - use_adj) < 0) - { - *next0 = drop_node_val; - return; - } - } - break; - } - opt0 = - (vxlan_gpe_ioam_option_t *) (((u8 *) opt0) + opt0->length + - sizeof (vxlan_gpe_ioam_hdr_t)); - } - - - if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) - { - vxlan_gpe_ioam_v4_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - u32 trace_len = gpe_ioam0->length; - t->fmt_trace.next_index = *next0; - /* Capture the ioam option verbatim */ - trace_len = - trace_len < - ARRAY_LEN (t->fmt_trace. - option_data) ? trace_len : ARRAY_LEN (t->fmt_trace. - option_data); - t->fmt_trace.trace_len = trace_len; - clib_memcpy (&(t->fmt_trace.option_data), gpe_ioam0, trace_len); - } - return; -} - - -#endif - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_msg_enum.h b/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_msg_enum.h deleted file mode 100644 index cc0a10a3..00000000 --- a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_msg_enum.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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. - */ -#ifndef included_vxlan_gpe_msg_enum_h -#define included_vxlan_gpe_msg_enum_h - -#include - -#define vl_msg_id(n,h) n, -typedef enum { -#include - /* 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_vxlan_gpe_msg_enum_h */ diff --git a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_test.c b/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_test.c deleted file mode 100644 index 47253eb6..00000000 --- a/plugins/ioam-plugin/ioam/lib-vxlan-gpe/vxlan_gpe_test.c +++ /dev/null @@ -1,600 +0,0 @@ -/* - * 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. - */ -/* - *------------------------------------------------------------------ - * vxlan_gpe_test.c - test harness for vxlan_gpe plugin - *------------------------------------------------------------------ - */ - -#include -#include -#include -#include -#include - -/* Declare message IDs */ -#include - -/* define message structures */ -#define vl_typedefs -#include -#undef vl_typedefs - -/* declare message handlers for each api */ - -#define vl_endianfun /* define message structures */ -#include -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) -#define vl_printfun -#include -#undef vl_printfun - -/* Get the API version number. */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#undef vl_api_version -#include -#include - -typedef struct -{ - /* API message ID base */ - u16 msg_id_base; - vat_main_t *vat_main; -} vxlan_gpe_test_main_t; - -vxlan_gpe_test_main_t vxlan_gpe_test_main; - -#define foreach_standard_reply_retval_handler \ -_(vxlan_gpe_ioam_enable_reply) \ -_(vxlan_gpe_ioam_disable_reply) \ -_(vxlan_gpe_ioam_vni_enable_reply) \ -_(vxlan_gpe_ioam_vni_disable_reply) \ -_(vxlan_gpe_ioam_transit_enable_reply) \ -_(vxlan_gpe_ioam_transit_disable_reply) - -#define _(n) \ - static void vl_api_##n##_t_handler \ - (vl_api_##n##_t * mp) \ - { \ - vat_main_t * vam = vxlan_gpe_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 \ -_(VXLAN_GPE_IOAM_ENABLE_REPLY, vxlan_gpe_ioam_enable_reply) \ -_(VXLAN_GPE_IOAM_DISABLE_REPLY, vxlan_gpe_ioam_disable_reply) \ -_(VXLAN_GPE_IOAM_VNI_ENABLE_REPLY, vxlan_gpe_ioam_vni_enable_reply) \ -_(VXLAN_GPE_IOAM_VNI_DISABLE_REPLY, vxlan_gpe_ioam_vni_disable_reply) \ -_(VXLAN_GPE_IOAM_TRANSIT_ENABLE_REPLY, vxlan_gpe_ioam_transit_enable_reply) \ -_(VXLAN_GPE_IOAM_TRANSIT_DISABLE_REPLY, vxlan_gpe_ioam_transit_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_vxlan_gpe_ioam_enable (vat_main_t * vam) -{ - vxlan_gpe_test_main_t *sm = &vxlan_gpe_test_main; - - unformat_input_t *input = vam->input; - vl_api_vxlan_gpe_ioam_enable_t *mp; - f64 timeout; - u32 id = 0; - int has_trace_option = 0; - int has_pow_option = 0; - int has_ppc_option = 0; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "trace")) - has_trace_option = 1; - else if (unformat (input, "pow")) - has_pow_option = 1; - else if (unformat (input, "ppc encap")) - has_ppc_option = PPC_ENCAP; - else if (unformat (input, "ppc decap")) - has_ppc_option = PPC_DECAP; - else if (unformat (input, "ppc none")) - has_ppc_option = PPC_NONE; - else - break; - } - M (VXLAN_GPE_IOAM_ENABLE, vxlan_gpe_ioam_enable); - mp->id = htons (id); - mp->trace_ppc = has_ppc_option; - mp->pow_enable = has_pow_option; - mp->trace_enable = has_trace_option; - - - S; - W; - - return (0); -} - - -static int -api_vxlan_gpe_ioam_disable (vat_main_t * vam) -{ - vxlan_gpe_test_main_t *sm = &vxlan_gpe_test_main; - vl_api_vxlan_gpe_ioam_disable_t *mp; - f64 timeout; - - M (VXLAN_GPE_IOAM_DISABLE, vxlan_gpe_ioam_disable); - S; - W; - return 0; -} - -static int -api_vxlan_gpe_ioam_vni_enable (vat_main_t * vam) -{ - vxlan_gpe_test_main_t *sm = &vxlan_gpe_test_main; - - unformat_input_t *line_input = vam->input; - vl_api_vxlan_gpe_ioam_vni_enable_t *mp; - ip4_address_t local4, remote4; - ip6_address_t local6, remote6; - u8 ipv4_set = 0, ipv6_set = 0; - u8 local_set = 0; - u8 remote_set = 0; - u32 vni; - u8 vni_set = 0; - f64 timeout; - - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "local %U", unformat_ip4_address, &local4)) - { - local_set = 1; - ipv4_set = 1; - } - else if (unformat (line_input, "remote %U", - unformat_ip4_address, &remote4)) - { - remote_set = 1; - ipv4_set = 1; - } - else if (unformat (line_input, "local %U", - unformat_ip6_address, &local6)) - { - local_set = 1; - ipv6_set = 1; - } - else if (unformat (line_input, "remote %U", - unformat_ip6_address, &remote6)) - { - remote_set = 1; - ipv6_set = 1; - } - - else if (unformat (line_input, "vni %d", &vni)) - vni_set = 1; - else - { - errmsg ("parse error '%U'\n", format_unformat_error, line_input); - return -99; - } - } - - if (local_set == 0) - { - errmsg ("tunnel local address not specified\n"); - return -99; - } - if (remote_set == 0) - { - errmsg ("tunnel remote address not specified\n"); - return -99; - } - if (ipv4_set && ipv6_set) - { - errmsg ("both IPv4 and IPv6 addresses specified"); - return -99; - } - - if (vni_set == 0) - { - errmsg ("vni not specified\n"); - return -99; - } - - M (VXLAN_GPE_IOAM_VNI_ENABLE, vxlan_gpe_ioam_vni_enable); - - - if (ipv6_set) - { - clib_memcpy (&mp->local, &local6, sizeof (local6)); - clib_memcpy (&mp->remote, &remote6, sizeof (remote6)); - } - else - { - clib_memcpy (&mp->local, &local4, sizeof (local4)); - clib_memcpy (&mp->remote, &remote4, sizeof (remote4)); - } - - mp->vni = ntohl (vni); - mp->is_ipv6 = ipv6_set; - - S; - W; - - return (0); -} - -static int -api_vxlan_gpe_ioam_vni_disable (vat_main_t * vam) -{ - vxlan_gpe_test_main_t *sm = &vxlan_gpe_test_main; - - unformat_input_t *line_input = vam->input; - vl_api_vxlan_gpe_ioam_vni_disable_t *mp; - ip4_address_t local4, remote4; - ip6_address_t local6, remote6; - u8 ipv4_set = 0, ipv6_set = 0; - u8 local_set = 0; - u8 remote_set = 0; - u32 vni; - u8 vni_set = 0; - f64 timeout; - - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "local %U", unformat_ip4_address, &local4)) - { - local_set = 1; - ipv4_set = 1; - } - else if (unformat (line_input, "remote %U", - unformat_ip4_address, &remote4)) - { - remote_set = 1; - ipv4_set = 1; - } - else if (unformat (line_input, "local %U", - unformat_ip6_address, &local6)) - { - local_set = 1; - ipv6_set = 1; - } - else if (unformat (line_input, "remote %U", - unformat_ip6_address, &remote6)) - { - remote_set = 1; - ipv6_set = 1; - } - - else if (unformat (line_input, "vni %d", &vni)) - vni_set = 1; - else - { - errmsg ("parse error '%U'\n", format_unformat_error, line_input); - return -99; - } - } - - if (local_set == 0) - { - errmsg ("tunnel local address not specified\n"); - return -99; - } - if (remote_set == 0) - { - errmsg ("tunnel remote address not specified\n"); - return -99; - } - if (ipv4_set && ipv6_set) - { - errmsg ("both IPv4 and IPv6 addresses specified"); - return -99; - } - - if (vni_set == 0) - { - errmsg ("vni not specified\n"); - return -99; - } - - M (VXLAN_GPE_IOAM_VNI_DISABLE, vxlan_gpe_ioam_vni_disable); - - - if (ipv6_set) - { - clib_memcpy (&mp->local, &local6, sizeof (local6)); - clib_memcpy (&mp->remote, &remote6, sizeof (remote6)); - } - else - { - clib_memcpy (&mp->local, &local4, sizeof (local4)); - clib_memcpy (&mp->remote, &remote4, sizeof (remote4)); - } - - mp->vni = ntohl (vni); - mp->is_ipv6 = ipv6_set; - - S; - W; - - return 0; -} - -static int -api_vxlan_gpe_ioam_transit_enable (vat_main_t * vam) -{ - vxlan_gpe_test_main_t *sm = &vxlan_gpe_test_main; - - unformat_input_t *line_input = vam->input; - vl_api_vxlan_gpe_ioam_transit_enable_t *mp; - ip4_address_t local4; - ip6_address_t local6; - u8 ipv4_set = 0, ipv6_set = 0; - u8 local_set = 0; - u32 outer_fib_index = 0; - f64 timeout; - - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "dst-ip %U", unformat_ip4_address, &local4)) - { - local_set = 1; - ipv4_set = 1; - } - else if (unformat (line_input, "dst-ip %U", - unformat_ip6_address, &local6)) - { - local_set = 1; - ipv6_set = 1; - } - - else if (unformat (line_input, "outer-fib-index %d", &outer_fib_index)) - ; - else - { - errmsg ("parse error '%U'\n", format_unformat_error, line_input); - return -99; - } - } - - if (local_set == 0) - { - errmsg ("destination address not specified\n"); - return -99; - } - if (ipv4_set && ipv6_set) - { - errmsg ("both IPv4 and IPv6 addresses specified"); - return -99; - } - - - M (VXLAN_GPE_IOAM_TRANSIT_ENABLE, vxlan_gpe_ioam_transit_enable); - - - if (ipv6_set) - { - errmsg ("IPv6 currently unsupported"); - return -1; - } - else - { - clib_memcpy (&mp->dst_addr, &local4, sizeof (local4)); - } - - mp->outer_fib_index = htonl (outer_fib_index); - mp->is_ipv6 = ipv6_set; - - S; - W; - - return (0); -} - -static int -api_vxlan_gpe_ioam_transit_disable (vat_main_t * vam) -{ - vxlan_gpe_test_main_t *sm = &vxlan_gpe_test_main; - - unformat_input_t *line_input = vam->input; - vl_api_vxlan_gpe_ioam_transit_disable_t *mp; - ip4_address_t local4; - ip6_address_t local6; - u8 ipv4_set = 0, ipv6_set = 0; - u8 local_set = 0; - u32 outer_fib_index; - f64 timeout; - - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "dst-ip %U", unformat_ip4_address, &local4)) - { - local_set = 1; - ipv4_set = 1; - } - else if (unformat (line_input, "dst-ip %U", - unformat_ip6_address, &local6)) - { - local_set = 1; - ipv6_set = 1; - } - - else if (unformat (line_input, "outer-fib-index %d", &outer_fib_index)) - ; - else - { - errmsg ("parse error '%U'\n", format_unformat_error, line_input); - return -99; - } - } - - if (local_set == 0) - { - errmsg ("destination address not specified\n"); - return -99; - } - if (ipv4_set && ipv6_set) - { - errmsg ("both IPv4 and IPv6 addresses specified"); - return -99; - } - - - M (VXLAN_GPE_IOAM_TRANSIT_DISABLE, vxlan_gpe_ioam_transit_disable); - - - if (ipv6_set) - { - return -1; - } - else - { - clib_memcpy (&mp->dst_addr, &local4, sizeof (local4)); - } - - mp->outer_fib_index = htonl (outer_fib_index); - mp->is_ipv6 = ipv6_set; - - S; - W; - - - return (0); -} - -/* - * List of messages that the api test plugin sends, - * and that the data plane plugin processes - */ -#define foreach_vpe_api_msg \ -_(vxlan_gpe_ioam_enable, ""\ - "[trace] [pow] [ppc ]") \ -_(vxlan_gpe_ioam_disable, "") \ -_(vxlan_gpe_ioam_vni_enable, ""\ - "local remote vni ") \ -_(vxlan_gpe_ioam_vni_disable, ""\ - "local remote vni ") \ -_(vxlan_gpe_ioam_transit_enable, ""\ - "dst-ip [outer-fib-index ]") \ -_(vxlan_gpe_ioam_transit_disable, ""\ - "dst-ip [outer-fib-index ]") \ - - -void -vat_api_hookup (vat_main_t * vam) -{ - vxlan_gpe_test_main_t *sm = &vxlan_gpe_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) -{ - vxlan_gpe_test_main_t *sm = &vxlan_gpe_test_main; - u8 *name; - - sm->vat_main = vam; - - name = format (0, "ioam_vxlan_gpe_%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; -} - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/lb-plugin/Makefile.am b/plugins/lb-plugin/Makefile.am deleted file mode 100644 index 8e360279..00000000 --- a/plugins/lb-plugin/Makefile.am +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright (c) 2016 Cisco Systems, Inc. -# 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 -AM_LDFLAGS = -module -shared -avoid-version - -vppapitestpluginsdir = ${libdir}/vpp_api_test_plugins -vpppluginsdir = ${libdir}/vpp_plugins - -vppapitestplugins_LTLIBRARIES = lb_test_plugin.la -vppplugins_LTLIBRARIES = lb_plugin.la - -lb_plugin_la_SOURCES = lb/lb.c lb/node.c lb/cli.c lb/util.c lb/refcount.c lb/api.c - -BUILT_SOURCES = \ - lb/lb.api.h \ - lb/lb.api.json - -SUFFIXES = .api.h .api .api.json - -%.api.h: %.api - mkdir -p `dirname $@` ; \ - $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ - | vppapigen --input - --output $@ --show-name $@ - -%.api.json: %.api - @echo " JSON APIGEN " $@ ; \ - mkdir -p `dirname $@` ; \ - $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ - | vppapigen --input - --json $@ - -apidir = $(prefix)/lb/ -api_DATA = lb/lb.api.json - -noinst_HEADERS = lb/lb.h lb/util.h lb/refcount.h lb/lbhash.h lb/lb.api.h - -lb_test_plugin_la_SOURCES = \ - lb/lb_test.c lb/lb_plugin.api.h - -# Remove *.la files -install-data-hook: - @(cd $(vpppluginsdir) && $(RM) $(vppplugins_LTLIBRARIES)) - @(cd $(vppapitestpluginsdir) && $(RM) $(vppapitestplugins_LTLIBRARIES)) diff --git a/plugins/lb-plugin/configure.ac b/plugins/lb-plugin/configure.ac deleted file mode 100644 index 1b02e54f..00000000 --- a/plugins/lb-plugin/configure.ac +++ /dev/null @@ -1,9 +0,0 @@ -AC_INIT(lb_plugin, 1.0) -AM_INIT_AUTOMAKE -AM_SILENT_RULES([yes]) -AC_PREFIX_DEFAULT([/usr]) - -AC_PROG_LIBTOOL -AC_PROG_CC - -AC_OUTPUT([Makefile]) diff --git a/plugins/lb-plugin/lb/api.c b/plugins/lb-plugin/lb/api.c deleted file mode 100644 index 06c53fa1..00000000 --- a/plugins/lb-plugin/lb/api.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * 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. - */ - -#include - -#include -#include -#include -#include -#include - -#define vl_msg_id(n,h) n, -typedef enum { -#include - /* We'll want to know how many messages IDs we need... */ - VL_MSG_FIRST_AVAILABLE, -} vl_msg_id_t; -#undef vl_msg_id - - -/* define message structures */ -#define vl_typedefs -#include -#undef vl_typedefs - -/* define generated endian-swappers */ -#define vl_endianfun -#include -#undef vl_endianfun - -#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) - -/* Get the API version number */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#undef vl_api_version - -#define vl_msg_name_crc_list -#include -#undef vl_msg_name_crc_list - -static void -setup_message_id_table (lb_main_t * lbm, api_main_t * am) -{ -#define _(id,n,crc) \ - vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + lbm->msg_id_base); - foreach_vl_msg_name_crc_lb; -#undef _ -} - -/* Macro to finish up custom dump fns */ -#define FINISH \ - vec_add1 (s, 0); \ - vl_print (handle, (char *)s); \ - vec_free (s); \ - return handle; - -/* - * 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)+lbm->msg_id_base); \ - rmp->context = mp->context; \ - rmp->retval = ntohl(rv); \ - \ - vl_msg_api_send_shmem (q, (u8 *)&rmp); \ -} while(0); - -static void -vl_api_lb_conf_t_handler -(vl_api_lb_conf_t * mp) -{ - lb_main_t *lbm = &lb_main; - vl_api_lb_conf_reply_t * rmp; - int rv = 0; - - rv = lb_conf((ip4_address_t *)&mp->ip4_src_address, - (ip6_address_t *)mp->ip6_src_address, - mp->sticky_buckets_per_core, - mp->flow_timeout); - - REPLY_MACRO (VL_API_LB_CONF_REPLY); -} - -static void *vl_api_lb_conf_t_print -(vl_api_lb_conf_t *mp, void * handle) -{ - u8 * s; - s = format (0, "SCRIPT: lb_conf "); - s = format (s, "%U ", format_ip4_address, (ip4_address_t *)&mp->ip4_src_address); - s = format (s, "%U ", format_ip6_address, (ip6_address_t *)mp->ip6_src_address); - s = format (s, "%u ", mp->sticky_buckets_per_core); - s = format (s, "%u ", mp->flow_timeout); - FINISH; -} - - -static void -vl_api_lb_add_del_vip_t_handler -(vl_api_lb_add_del_vip_t * mp) -{ - lb_main_t *lbm = &lb_main; - vl_api_lb_conf_reply_t * rmp; - int rv = 0; - ip46_address_t prefix; - memcpy(&prefix.ip6, mp->ip_prefix, sizeof(prefix.ip6)); - - if (mp->is_del) { - u32 vip_index; - if (!(rv = lb_vip_find_index(&prefix, mp->prefix_length, &vip_index))) - rv = lb_vip_del(vip_index); - } else { - u32 vip_index; - lb_vip_type_t type; - if (ip46_prefix_is_ip4(&prefix, mp->prefix_length)) { - type = mp->is_gre4?LB_VIP_TYPE_IP4_GRE4:LB_VIP_TYPE_IP4_GRE6; - } else { - type = mp->is_gre4?LB_VIP_TYPE_IP6_GRE4:LB_VIP_TYPE_IP6_GRE6; - } - - rv = lb_vip_add(&prefix, mp->prefix_length, type, - mp->new_flows_table_length, &vip_index); - } - REPLY_MACRO (VL_API_LB_CONF_REPLY); -} - -static void *vl_api_lb_add_del_vip_t_print -(vl_api_lb_add_del_vip_t *mp, void * handle) -{ - u8 * s; - s = format (0, "SCRIPT: lb_add_del_vip "); - s = format (s, "%U ", format_ip46_prefix, - (ip46_address_t *)mp->ip_prefix, mp->prefix_length, IP46_TYPE_ANY); - s = format (s, "%s ", mp->is_gre4?"gre4":"gre6"); - s = format (s, "%u ", mp->new_flows_table_length); - s = format (s, "%s ", mp->is_del?"del":"add"); - FINISH; -} - -static void -vl_api_lb_add_del_as_t_handler -(vl_api_lb_add_del_as_t * mp) -{ - lb_main_t *lbm = &lb_main; - vl_api_lb_conf_reply_t * rmp; - int rv = 0; - u32 vip_index; - if ((rv = lb_vip_find_index((ip46_address_t *)mp->vip_ip_prefix, - mp->vip_prefix_length, &vip_index))) - goto done; - - if (mp->is_del) - rv = lb_vip_del_ass(vip_index, (ip46_address_t *)mp->as_address, 1); - else - rv = lb_vip_add_ass(vip_index, (ip46_address_t *)mp->as_address, 1); - -done: - REPLY_MACRO (VL_API_LB_CONF_REPLY); -} - -static void *vl_api_lb_add_del_as_t_print -(vl_api_lb_add_del_as_t *mp, void * handle) -{ - u8 * s; - s = format (0, "SCRIPT: lb_add_del_as "); - s = format (s, "%U ", format_ip46_prefix, - (ip46_address_t *)mp->vip_ip_prefix, mp->vip_prefix_length, IP46_TYPE_ANY); - s = format (s, "%U ", format_ip46_address, - (ip46_address_t *)mp->as_address, IP46_TYPE_ANY); - s = format (s, "%s ", mp->is_del?"del":"add"); - FINISH; -} - -/* List of message types that this plugin understands */ -#define foreach_lb_plugin_api_msg \ -_(LB_CONF, lb_conf) \ -_(LB_ADD_DEL_VIP, lb_add_del_vip) \ -_(LB_ADD_DEL_AS, lb_add_del_as) - -static clib_error_t * lb_api_init (vlib_main_t * vm) -{ - lb_main_t *lbm = &lb_main; - u8 *name = format (0, "lb_%08x%c", api_version, 0); - lbm->msg_id_base = vl_msg_api_get_msg_ids - ((char *) name, VL_MSG_FIRST_AVAILABLE); - -#define _(N,n) \ - vl_msg_api_set_handlers((VL_API_##N + lbm->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_lb_plugin_api_msg; -#undef _ - - /* Add our API messages to the global name_crc hash table */ - setup_message_id_table (lbm, &api_main); - - return 0; -} - -VLIB_INIT_FUNCTION (lb_api_init); diff --git a/plugins/lb-plugin/lb/cli.c b/plugins/lb-plugin/lb/cli.c deleted file mode 100644 index b59c6426..00000000 --- a/plugins/lb-plugin/lb/cli.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * 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. - */ - -#include -#include - -static clib_error_t * -lb_vip_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - ip46_address_t prefix; - u8 plen; - u32 new_len = 1024; - u8 del = 0; - int ret; - u32 gre4 = 0; - lb_vip_type_t type; - - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - if (!unformat(line_input, "%U", unformat_ip46_prefix, &prefix, &plen, IP46_TYPE_ANY, &plen)) - return clib_error_return (0, "invalid vip prefix: '%U'", - format_unformat_error, line_input); - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat(line_input, "new_len %d", &new_len)) - ; - else if (unformat(line_input, "del")) - del = 1; - else if (unformat(line_input, "encap gre4")) - gre4 = 1; - else if (unformat(line_input, "encap gre6")) - gre4 = 0; - else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); - } - - unformat_free (line_input); - - - if (ip46_prefix_is_ip4(&prefix, plen)) { - type = (gre4)?LB_VIP_TYPE_IP4_GRE4:LB_VIP_TYPE_IP4_GRE6; - } else { - type = (gre4)?LB_VIP_TYPE_IP6_GRE4:LB_VIP_TYPE_IP6_GRE6; - } - - lb_garbage_collection(); - - u32 index; - if (!del) { - if ((ret = lb_vip_add(&prefix, plen, type, new_len, &index))) { - return clib_error_return (0, "lb_vip_add error %d", ret); - } else { - vlib_cli_output(vm, "lb_vip_add ok %d", index); - } - } else { - if ((ret = lb_vip_find_index(&prefix, plen, &index))) - return clib_error_return (0, "lb_vip_find_index error %d", ret); - else if ((ret = lb_vip_del(index))) - return clib_error_return (0, "lb_vip_del error %d", ret); - } - return NULL; -} - -VLIB_CLI_COMMAND (lb_vip_command, static) = -{ - .path = "lb vip", - .short_help = "lb vip [encap (gre6|gre4)] [new_len ] [del]", - .function = lb_vip_command_fn, -}; - -static clib_error_t * -lb_as_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - ip46_address_t vip_prefix, as_addr; - u8 vip_plen; - ip46_address_t *as_array = 0; - u32 vip_index; - u8 del = 0; - int ret; - - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - if (!unformat(line_input, "%U", unformat_ip46_prefix, &vip_prefix, &vip_plen, IP46_TYPE_ANY)) - return clib_error_return (0, "invalid as address: '%U'", - format_unformat_error, line_input); - - if ((ret = lb_vip_find_index(&vip_prefix, vip_plen, &vip_index))) - return clib_error_return (0, "lb_vip_find_index error %d", ret); - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat(line_input, "%U", unformat_ip46_address, &as_addr, IP46_TYPE_ANY)) { - vec_add1(as_array, as_addr); - } else if (unformat(line_input, "del")) { - del = 1; - } else { - vec_free(as_array); - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); - } - } - - if (!vec_len(as_array)) { - vec_free(as_array); - return clib_error_return (0, "No AS address provided"); - } - - lb_garbage_collection(); - clib_warning("vip index is %d", vip_index); - - if (del) { - if ((ret = lb_vip_del_ass(vip_index, as_array, vec_len(as_array)))) { - vec_free(as_array); - return clib_error_return (0, "lb_vip_del_ass error %d", ret); - } - } else { - if ((ret = lb_vip_add_ass(vip_index, as_array, vec_len(as_array)))) { - vec_free(as_array); - return clib_error_return (0, "lb_vip_add_ass error %d", ret); - } - } - - vec_free(as_array); - return 0; -} - -VLIB_CLI_COMMAND (lb_as_command, static) = -{ - .path = "lb as", - .short_help = "lb as [
[
[...]]] [del]", - .function = lb_as_command_fn, -}; - -static clib_error_t * -lb_conf_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - lb_main_t *lbm = &lb_main; - unformat_input_t _line_input, *line_input = &_line_input; - ip4_address_t ip4 = lbm->ip4_src_address; - ip6_address_t ip6 = lbm->ip6_src_address; - u32 per_cpu_sticky_buckets = lbm->per_cpu_sticky_buckets; - u32 per_cpu_sticky_buckets_log2 = 0; - u32 flow_timeout = lbm->flow_timeout; - int ret; - - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat(line_input, "ip4-src-address %U", unformat_ip4_address, &ip4)) - ; - else if (unformat(line_input, "ip6-src-address %U", unformat_ip6_address, &ip6)) - ; - else if (unformat(line_input, "buckets %d", &per_cpu_sticky_buckets)) - ; - else if (unformat(line_input, "buckets-log2 %d", &per_cpu_sticky_buckets_log2)) { - if (per_cpu_sticky_buckets_log2 >= 32) - return clib_error_return (0, "buckets-log2 value is too high"); - per_cpu_sticky_buckets = 1 << per_cpu_sticky_buckets_log2; - } else if (unformat(line_input, "timeout %d", &flow_timeout)) - ; - else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); - } - - unformat_free (line_input); - - lb_garbage_collection(); - - if ((ret = lb_conf(&ip4, &ip6, per_cpu_sticky_buckets, flow_timeout))) - return clib_error_return (0, "lb_conf error %d", ret); - - return NULL; -} - -VLIB_CLI_COMMAND (lb_conf_command, static) = -{ - .path = "lb conf", - .short_help = "lb conf [ip4-src-address ] [ip6-src-address ] [buckets ] [timeout ]", - .function = lb_conf_command_fn, -}; - -static clib_error_t * -lb_show_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - vlib_cli_output(vm, "%U", format_lb_main); - return NULL; -} - - -VLIB_CLI_COMMAND (lb_show_command, static) = -{ - .path = "show lb", - .short_help = "show lb", - .function = lb_show_command_fn, -}; - -static clib_error_t * -lb_show_vips_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - unformat_input_t line_input; - lb_main_t *lbm = &lb_main; - lb_vip_t *vip; - u8 verbose = 0; - - if (!unformat_user (input, unformat_line_input, &line_input)) - return 0; - - if (unformat(&line_input, "verbose")) - verbose = 1; - - pool_foreach(vip, lbm->vips, { - vlib_cli_output(vm, "%U\n", verbose?format_lb_vip_detailed:format_lb_vip, vip); - }); - - unformat_free (&line_input); - return NULL; -} - -VLIB_CLI_COMMAND (lb_show_vips_command, static) = -{ - .path = "show lb vips", - .short_help = "show lb vips [verbose]", - .function = lb_show_vips_command_fn, -}; diff --git a/plugins/lb-plugin/lb/lb.api b/plugins/lb-plugin/lb/lb.api deleted file mode 100644 index 39ee3c8f..00000000 --- a/plugins/lb-plugin/lb/lb.api +++ /dev/null @@ -1,71 +0,0 @@ -/** \brief Configure Load-Balancer global parameters - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param ip4_src_address - IPv4 address to be used as source for IPv4 GRE traffic. - @param ip6_src_address - IPv6 address to be used as source for IPv6 GRE traffic. - @param n_sticky_buckets - Number of buckets *per worker thread* in the - established flow table (must be power of 2). - @param flow_timeout - Time in seconds after which, if no packet is received - for a given flow, the flow is removed from the established flow table. -*/ -define lb_conf -{ - u32 client_index; - u32 context; - u32 ip4_src_address; - u8 ip6_src_address[16]; - u32 sticky_buckets_per_core; - u32 flow_timeout; -}; - -define lb_conf_reply { - u32 context; - i32 retval; -}; - -/** \brief Add a virtual address (or prefix) - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param ip_prefix - IP address (IPv4 in lower order 32 bits). - @param prefix_length - IP prefix length (96 + 'IPv4 prefix length' for IPv4). - @param is_gre4 - Encap is ip4 GRE (ip6 GRE otherwise). - @param new_flows_table_length - Size of the new connections flow table used - for this VIP (must be power of 2). - @param is_del - The VIP should be removed. -*/ -define lb_add_del_vip { - u32 client_index; - u32 context; - u8 ip_prefix[16]; - u8 prefix_length; - u8 is_gre4; - u32 new_flows_table_length; - u8 is_del; -}; - -define lb_add_del_vip_reply { - u32 context; - i32 retval; -}; - -/** \brief Add an application server for a given VIP - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param vip_ip_prefix - VIP IP address (IPv4 in lower order 32 bits). - @param vip_ip_prefix - VIP IP prefix length (96 + 'IPv4 prefix length' for IPv4). - @param as_address - The application server address (IPv4 in lower order 32 bits). - @param is_del - The AS should be removed. -*/ -define lb_add_del_as { - u32 client_index; - u32 context; - u8 vip_ip_prefix[16]; - u8 vip_prefix_length; - u8 as_address[16]; - u8 is_del; -}; - -define lb_add_del_as_reply { - u32 context; - i32 retval; -}; diff --git a/plugins/lb-plugin/lb/lb.c b/plugins/lb-plugin/lb/lb.c deleted file mode 100644 index 1d9b9870..00000000 --- a/plugins/lb-plugin/lb/lb.c +++ /dev/null @@ -1,844 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include - -//GC runs at most once every so many seconds -#define LB_GARBAGE_RUN 60 - -//After so many seconds. It is assumed that inter-core race condition will not occur. -#define LB_CONCURRENCY_TIMEOUT 10 - -lb_main_t lb_main; - -#define lb_get_writer_lock() do {} while(__sync_lock_test_and_set (lb_main.writer_lock, 1)) -#define lb_put_writer_lock() lb_main.writer_lock[0] = 0 - -static void lb_as_stack (lb_as_t *as); - - -const static char * const lb_dpo_gre4_ip4[] = { "lb4-gre4" , NULL }; -const static char * const lb_dpo_gre4_ip6[] = { "lb6-gre4" , NULL }; -const static char* const * const lb_dpo_gre4_nodes[DPO_PROTO_NUM] = - { - [DPO_PROTO_IP4] = lb_dpo_gre4_ip4, - [DPO_PROTO_IP6] = lb_dpo_gre4_ip6, - }; - -const static char * const lb_dpo_gre6_ip4[] = { "lb4-gre6" , NULL }; -const static char * const lb_dpo_gre6_ip6[] = { "lb6-gre6" , NULL }; -const static char* const * const lb_dpo_gre6_nodes[DPO_PROTO_NUM] = - { - [DPO_PROTO_IP4] = lb_dpo_gre6_ip4, - [DPO_PROTO_IP6] = lb_dpo_gre6_ip6, - }; - -u32 lb_hash_time_now(vlib_main_t * vm) -{ - return (u32) (vlib_time_now(vm) + 10000); -} - -u8 *format_lb_main (u8 * s, va_list * args) -{ - vlib_thread_main_t *tm = vlib_get_thread_main(); - lb_main_t *lbm = &lb_main; - s = format(s, "lb_main"); - s = format(s, " ip4-src-address: %U \n", format_ip4_address, &lbm->ip4_src_address); - s = format(s, " ip6-src-address: %U \n", format_ip6_address, &lbm->ip6_src_address); - s = format(s, " #vips: %u\n", pool_elts(lbm->vips)); - s = format(s, " #ass: %u\n", pool_elts(lbm->ass) - 1); - - u32 cpu_index; - for(cpu_index = 0; cpu_index < tm->n_vlib_mains; cpu_index++ ) { - lb_hash_t *h = lbm->per_cpu[cpu_index].sticky_ht; - if (h) { - s = format(s, "core %d\n", cpu_index); - s = format(s, " timeout: %ds\n", h->timeout); - s = format(s, " usage: %d / %d\n", lb_hash_elts(h, lb_hash_time_now(vlib_get_main())), lb_hash_size(h)); - } - } - - return s; -} - -static char *lb_vip_type_strings[] = { - [LB_VIP_TYPE_IP6_GRE6] = "ip6-gre6", - [LB_VIP_TYPE_IP6_GRE4] = "ip6-gre4", - [LB_VIP_TYPE_IP4_GRE6] = "ip4-gre6", - [LB_VIP_TYPE_IP4_GRE4] = "ip4-gre4", -}; - -u8 *format_lb_vip_type (u8 * s, va_list * args) -{ - lb_vip_type_t vipt = va_arg (*args, lb_vip_type_t); - u32 i; - for (i=0; itype, - format_ip46_prefix, &vip->prefix, vip->plen, IP46_TYPE_ANY, - vip->new_flow_table_mask + 1, - pool_elts(vip->as_indexes), - (vip->flags & LB_VIP_FLAGS_USED)?"":" removed"); -} - -u8 *format_lb_as (u8 * s, va_list * args) -{ - lb_as_t *as = va_arg (*args, lb_as_t *); - return format(s, "%U %s", format_ip46_address, - &as->address, IP46_TYPE_ANY, - (as->flags & LB_AS_FLAGS_USED)?"used":"removed"); -} - -u8 *format_lb_vip_detailed (u8 * s, va_list * args) -{ - lb_main_t *lbm = &lb_main; - lb_vip_t *vip = va_arg (*args, lb_vip_t *); - uword indent = format_get_indent (s); - - s = format(s, "%U %U [%u] %U%s\n" - "%U new_size:%u\n", - format_white_space, indent, - format_lb_vip_type, vip->type, - vip - lbm->vips, format_ip46_prefix, &vip->prefix, vip->plen, IP46_TYPE_ANY, - (vip->flags & LB_VIP_FLAGS_USED)?"":" removed", - format_white_space, indent, - vip->new_flow_table_mask + 1); - - //Print counters - s = format(s, "%U counters:\n", - format_white_space, indent); - u32 i; - for (i=0; ivip_counters[i].name, - vlib_get_simple_counter(&lbm->vip_counters[i], vip - lbm->vips)); - - - s = format(s, "%U #as:%u\n", - format_white_space, indent, - pool_elts(vip->as_indexes)); - - //Let's count the buckets for each AS - u32 *count = 0; - vec_validate(count, pool_len(lbm->ass)); //Possibly big alloc for not much... - lb_new_flow_entry_t *nfe; - vec_foreach(nfe, vip->new_flow_table) - count[nfe->as_index]++; - - lb_as_t *as; - u32 *as_index; - pool_foreach(as_index, vip->as_indexes, { - as = &lbm->ass[*as_index]; - s = format(s, "%U %U %d buckets %d flows dpo:%u %s\n", - format_white_space, indent, - format_ip46_address, &as->address, IP46_TYPE_ANY, - count[as - lbm->ass], - vlib_refcount_get(&lbm->as_refcount, as - lbm->ass), - as->dpo.dpoi_index, - (as->flags & LB_AS_FLAGS_USED)?"used":" removed"); - }); - - vec_free(count); - - /* - s = format(s, "%U new flows table:\n", format_white_space, indent); - lb_new_flow_entry_t *nfe; - vec_foreach(nfe, vip->new_flow_table) { - s = format(s, "%U %d: %d\n", format_white_space, indent, nfe - vip->new_flow_table, nfe->as_index); - } - */ - return s; -} - -typedef struct { - u32 as_index; - u32 last; - u32 skip; -} lb_pseudorand_t; - -static int lb_pseudorand_compare(void *a, void *b) -{ - lb_as_t *asa, *asb; - lb_main_t *lbm = &lb_main; - asa = &lbm->ass[((lb_pseudorand_t *)a)->as_index]; - asb = &lbm->ass[((lb_pseudorand_t *)b)->as_index]; - return memcmp(&asa->address, &asb->address, sizeof(asb->address)); -} - -static void lb_vip_garbage_collection(lb_vip_t *vip) -{ - lb_main_t *lbm = &lb_main; - ASSERT (lbm->writer_lock[0]); - - u32 now = (u32) vlib_time_now(vlib_get_main()); - if (!clib_u32_loop_gt(now, vip->last_garbage_collection + LB_GARBAGE_RUN)) - return; - - vip->last_garbage_collection = now; - lb_as_t *as; - u32 *as_index; - pool_foreach(as_index, vip->as_indexes, { - as = &lbm->ass[*as_index]; - if (!(as->flags & LB_AS_FLAGS_USED) && //Not used - clib_u32_loop_gt(now, as->last_used + LB_CONCURRENCY_TIMEOUT) && //Not recently used - (vlib_refcount_get(&lbm->as_refcount, as - lbm->ass) == 0)) - { //Not referenced - fib_entry_child_remove(as->next_hop_fib_entry_index, - as->next_hop_child_index); - fib_table_entry_delete_index(as->next_hop_fib_entry_index, - FIB_SOURCE_RR); - as->next_hop_fib_entry_index = FIB_NODE_INDEX_INVALID; - - pool_put(vip->as_indexes, as_index); - pool_put(lbm->ass, as); - } - }); -} - -void lb_garbage_collection() -{ - lb_main_t *lbm = &lb_main; - lb_get_writer_lock(); - lb_vip_t *vip; - u32 *to_be_removed_vips = 0, *i; - pool_foreach(vip, lbm->vips, { - lb_vip_garbage_collection(vip); - - if (!(vip->flags & LB_VIP_FLAGS_USED) && - (pool_elts(vip->as_indexes) == 0)) { - vec_add1(to_be_removed_vips, vip - lbm->vips); - } - }); - - vec_foreach(i, to_be_removed_vips) { - vip = &lbm->vips[*i]; - pool_put(lbm->vips, vip); - pool_free(vip->as_indexes); - } - - vec_free(to_be_removed_vips); - lb_put_writer_lock(); -} - -static void lb_vip_update_new_flow_table(lb_vip_t *vip) -{ - lb_main_t *lbm = &lb_main; - lb_new_flow_entry_t *old_table; - u32 i, *as_index; - lb_new_flow_entry_t *new_flow_table = 0; - lb_as_t *as; - lb_pseudorand_t *pr, *sort_arr = 0; - u32 count; - - ASSERT (lbm->writer_lock[0]); //We must have the lock - - //Check if some AS is configured or not - i = 0; - pool_foreach(as_index, vip->as_indexes, { - as = &lbm->ass[*as_index]; - if (as->flags & LB_AS_FLAGS_USED) { //Not used anymore - i = 1; - goto out; //Not sure 'break' works in this macro-loop - } - }); - -out: - if (i == 0) { - //Only the default. i.e. no AS - vec_validate(new_flow_table, vip->new_flow_table_mask); - for (i=0; ias_indexes)); - - i = 0; - pool_foreach(as_index, vip->as_indexes, { - as = &lbm->ass[*as_index]; - if (!(as->flags & LB_AS_FLAGS_USED)) //Not used anymore - continue; - - sort_arr[i].as_index = as - lbm->ass; - i++; - }); - _vec_len(sort_arr) = i; - - vec_sort_with_function(sort_arr, lb_pseudorand_compare); - - //Now let's pseudo-randomly generate permutations - vec_foreach(pr, sort_arr) { - lb_as_t *as = &lbm->ass[pr->as_index]; - - u64 seed = clib_xxhash(as->address.as_u64[0] ^ - as->address.as_u64[1]); - /* We have 2^n buckets. - * skip must be prime with 2^n. - * So skip must be odd. - * MagLev actually state that M should be prime, - * but this has a big computation cost (% operation). - * Using 2^n is more better (& operation). - */ - pr->skip = ((seed & 0xffffffff) | 1) & vip->new_flow_table_mask; - pr->last = (seed >> 32) & vip->new_flow_table_mask; - } - - //Let's create a new flow table - vec_validate(new_flow_table, vip->new_flow_table_mask); - for (i=0; ilast; - pr->last = (pr->last + pr->skip) & vip->new_flow_table_mask; - if (new_flow_table[last].as_index == ~0) { - new_flow_table[last].as_index = pr->as_index; - break; - } - } - done++; - if (done == vec_len(new_flow_table)) - goto finished; - } - } - - vec_free(sort_arr); - -finished: - -//Count number of changed entries - count = 0; - for (i=0; inew_flow_table == 0 || - new_flow_table[i].as_index != vip->new_flow_table[i].as_index) - count++; - - old_table = vip->new_flow_table; - vip->new_flow_table = new_flow_table; - vec_free(old_table); -} - -int lb_conf(ip4_address_t *ip4_address, ip6_address_t *ip6_address, - u32 per_cpu_sticky_buckets, u32 flow_timeout) -{ - lb_main_t *lbm = &lb_main; - - if (!is_pow2(per_cpu_sticky_buckets)) - return VNET_API_ERROR_INVALID_MEMORY_SIZE; - - lb_get_writer_lock(); //Not exactly necessary but just a reminder that it exists for my future self - lbm->ip4_src_address = *ip4_address; - lbm->ip6_src_address = *ip6_address; - lbm->per_cpu_sticky_buckets = per_cpu_sticky_buckets; - lbm->flow_timeout = flow_timeout; - lb_put_writer_lock(); - return 0; -} - -static -int lb_vip_find_index_with_lock(ip46_address_t *prefix, u8 plen, u32 *vip_index) -{ - lb_main_t *lbm = &lb_main; - lb_vip_t *vip; - ASSERT (lbm->writer_lock[0]); //This must be called with the lock owned - ip46_prefix_normalize(prefix, plen); - pool_foreach(vip, lbm->vips, { - if ((vip->flags & LB_AS_FLAGS_USED) && - vip->plen == plen && - vip->prefix.as_u64[0] == prefix->as_u64[0] && - vip->prefix.as_u64[1] == prefix->as_u64[1]) { - *vip_index = vip - lbm->vips; - return 0; - } - }); - return VNET_API_ERROR_NO_SUCH_ENTRY; -} - -int lb_vip_find_index(ip46_address_t *prefix, u8 plen, u32 *vip_index) -{ - int ret; - lb_get_writer_lock(); - ret = lb_vip_find_index_with_lock(prefix, plen, vip_index); - lb_put_writer_lock(); - return ret; -} - -static int lb_as_find_index_vip(lb_vip_t *vip, ip46_address_t *address, u32 *as_index) -{ - lb_main_t *lbm = &lb_main; - ASSERT (lbm->writer_lock[0]); //This must be called with the lock owned - lb_as_t *as; - u32 *asi; - pool_foreach(asi, vip->as_indexes, { - as = &lbm->ass[*asi]; - if (as->vip_index == (vip - lbm->vips) && - as->address.as_u64[0] == address->as_u64[0] && - as->address.as_u64[1] == address->as_u64[1]) { - *as_index = as - lbm->ass; - return 0; - } - }); - return -1; -} - -int lb_vip_add_ass(u32 vip_index, ip46_address_t *addresses, u32 n) -{ - lb_main_t *lbm = &lb_main; - lb_get_writer_lock(); - lb_vip_t *vip; - if (!(vip = lb_vip_get_by_index(vip_index))) { - lb_put_writer_lock(); - return VNET_API_ERROR_NO_SUCH_ENTRY; - } - - ip46_type_t type = lb_vip_is_gre4(vip)?IP46_TYPE_IP4:IP46_TYPE_IP6; - u32 *to_be_added = 0; - u32 *to_be_updated = 0; - u32 i; - u32 *ip; - - //Sanity check - while (n--) { - - if (!lb_as_find_index_vip(vip, &addresses[n], &i)) { - if (lbm->ass[i].flags & LB_AS_FLAGS_USED) { - vec_free(to_be_added); - vec_free(to_be_updated); - lb_put_writer_lock(); - return VNET_API_ERROR_VALUE_EXIST; - } - vec_add1(to_be_updated, i); - goto next; - } - - if (ip46_address_type(&addresses[n]) != type) { - vec_free(to_be_added); - vec_free(to_be_updated); - lb_put_writer_lock(); - return VNET_API_ERROR_INVALID_ADDRESS_FAMILY; - } - - if (n) { - u32 n2 = n; - while(n2--) //Check for duplicates - if (addresses[n2].as_u64[0] == addresses[n].as_u64[0] && - addresses[n2].as_u64[1] == addresses[n].as_u64[1]) - goto next; - } - - vec_add1(to_be_added, n); - -next: - continue; - } - - //Update reused ASs - vec_foreach(ip, to_be_updated) { - lbm->ass[*ip].flags = LB_AS_FLAGS_USED; - } - vec_free(to_be_updated); - - //Create those who have to be created - vec_foreach(ip, to_be_added) { - lb_as_t *as; - u32 *as_index; - pool_get(lbm->ass, as); - as->address = addresses[*ip]; - as->flags = LB_AS_FLAGS_USED; - as->vip_index = vip_index; - pool_get(vip->as_indexes, as_index); - *as_index = as - lbm->ass; - - /* - * become a child of the FIB entry - * so we are informed when its forwarding changes - */ - fib_prefix_t nh = {}; - if (lb_vip_is_gre4(vip)) { - nh.fp_addr.ip4 = as->address.ip4; - nh.fp_len = 32; - nh.fp_proto = FIB_PROTOCOL_IP4; - } else { - nh.fp_addr.ip6 = as->address.ip6; - nh.fp_len = 128; - nh.fp_proto = FIB_PROTOCOL_IP6; - } - - as->next_hop_fib_entry_index = - fib_table_entry_special_add(0, - &nh, - FIB_SOURCE_RR, - FIB_ENTRY_FLAG_NONE, - ADJ_INDEX_INVALID); - as->next_hop_child_index = - fib_entry_child_add(as->next_hop_fib_entry_index, - lbm->fib_node_type, - as - lbm->ass); - - lb_as_stack(as); - } - vec_free(to_be_added); - - //Recompute flows - lb_vip_update_new_flow_table(vip); - - //Garbage collection maybe - lb_vip_garbage_collection(vip); - - lb_put_writer_lock(); - return 0; -} - -int lb_vip_del_ass_withlock(u32 vip_index, ip46_address_t *addresses, u32 n) -{ - lb_main_t *lbm = &lb_main; - u32 now = (u32) vlib_time_now(vlib_get_main()); - u32 *ip = 0; - - lb_vip_t *vip; - if (!(vip = lb_vip_get_by_index(vip_index))) { - return VNET_API_ERROR_NO_SUCH_ENTRY; - } - - u32 *indexes = NULL; - while (n--) { - u32 i; - if (lb_as_find_index_vip(vip, &addresses[n], &i)) { - vec_free(indexes); - return VNET_API_ERROR_NO_SUCH_ENTRY; - } - - if (n) { //Check for duplicates - u32 n2 = n - 1; - while(n2--) { - if (addresses[n2].as_u64[0] == addresses[n].as_u64[0] && - addresses[n2].as_u64[1] == addresses[n].as_u64[1]) - goto next; - } - } - - vec_add1(indexes, i); -next: - continue; - } - - //Garbage collection maybe - lb_vip_garbage_collection(vip); - - if (indexes != NULL) { - vec_foreach(ip, indexes) { - lbm->ass[*ip].flags &= ~LB_AS_FLAGS_USED; - lbm->ass[*ip].last_used = now; - } - - //Recompute flows - lb_vip_update_new_flow_table(vip); - } - - vec_free(indexes); - return 0; -} - -int lb_vip_del_ass(u32 vip_index, ip46_address_t *addresses, u32 n) -{ - lb_get_writer_lock(); - int ret = lb_vip_del_ass_withlock(vip_index, addresses, n); - lb_put_writer_lock(); - return ret; -} - -/** - * Add the VIP adjacency to the ip4 or ip6 fib - */ -static void lb_vip_add_adjacency(lb_main_t *lbm, lb_vip_t *vip) -{ - dpo_proto_t proto = 0; - dpo_id_t dpo = DPO_INVALID; - fib_prefix_t pfx = {}; - if (lb_vip_is_ip4(vip)) { - pfx.fp_addr.ip4 = vip->prefix.ip4; - pfx.fp_len = vip->plen - 96; - pfx.fp_proto = FIB_PROTOCOL_IP4; - proto = DPO_PROTO_IP4; - } else { - pfx.fp_addr.ip6 = vip->prefix.ip6; - pfx.fp_len = vip->plen; - pfx.fp_proto = FIB_PROTOCOL_IP6; - proto = DPO_PROTO_IP6; - } - dpo_set(&dpo, lb_vip_is_gre4(vip)?lbm->dpo_gre4_type:lbm->dpo_gre6_type, - proto, vip - lbm->vips); - fib_table_entry_special_dpo_add(0, - &pfx, - FIB_SOURCE_PLUGIN_HI, - FIB_ENTRY_FLAG_EXCLUSIVE, - &dpo); - dpo_reset(&dpo); -} - -/** - * Deletes the adjacency associated with the VIP - */ -static void lb_vip_del_adjacency(lb_main_t *lbm, lb_vip_t *vip) -{ - fib_prefix_t pfx = {}; - if (lb_vip_is_ip4(vip)) { - pfx.fp_addr.ip4 = vip->prefix.ip4; - pfx.fp_len = vip->plen - 96; - pfx.fp_proto = FIB_PROTOCOL_IP4; - } else { - pfx.fp_addr.ip6 = vip->prefix.ip6; - pfx.fp_len = vip->plen; - pfx.fp_proto = FIB_PROTOCOL_IP6; - } - fib_table_entry_special_remove(0, &pfx, FIB_SOURCE_PLUGIN_HI); -} - -int lb_vip_add(ip46_address_t *prefix, u8 plen, lb_vip_type_t type, u32 new_length, u32 *vip_index) -{ - lb_main_t *lbm = &lb_main; - lb_vip_t *vip; - lb_get_writer_lock(); - ip46_prefix_normalize(prefix, plen); - - if (!lb_vip_find_index_with_lock(prefix, plen, vip_index)) { - lb_put_writer_lock(); - return VNET_API_ERROR_VALUE_EXIST; - } - - if (!is_pow2(new_length)) { - lb_put_writer_lock(); - return VNET_API_ERROR_INVALID_MEMORY_SIZE; - } - - if (ip46_prefix_is_ip4(prefix, plen) && - (type != LB_VIP_TYPE_IP4_GRE4) && - (type != LB_VIP_TYPE_IP4_GRE6)) - return VNET_API_ERROR_INVALID_ADDRESS_FAMILY; - - - //Allocate - pool_get(lbm->vips, vip); - - //Init - vip->prefix = *prefix; - vip->plen = plen; - vip->last_garbage_collection = (u32) vlib_time_now(vlib_get_main()); - vip->type = type; - vip->flags = LB_VIP_FLAGS_USED; - vip->as_indexes = 0; - - //Validate counters - u32 i; - for (i = 0; i < LB_N_VIP_COUNTERS; i++) { - vlib_validate_simple_counter(&lbm->vip_counters[i], vip - lbm->vips); - vlib_zero_simple_counter(&lbm->vip_counters[i], vip - lbm->vips); - } - - //Configure new flow table - vip->new_flow_table_mask = new_length - 1; - vip->new_flow_table = 0; - - //Create a new flow hash table full of the default entry - lb_vip_update_new_flow_table(vip); - - //Create adjacency to direct traffic - lb_vip_add_adjacency(lbm, vip); - - //Return result - *vip_index = vip - lbm->vips; - - lb_put_writer_lock(); - return 0; -} - -int lb_vip_del(u32 vip_index) -{ - lb_main_t *lbm = &lb_main; - lb_vip_t *vip; - lb_get_writer_lock(); - if (!(vip = lb_vip_get_by_index(vip_index))) { - lb_put_writer_lock(); - return VNET_API_ERROR_NO_SUCH_ENTRY; - } - - //FIXME: This operation is actually not working - //We will need to remove state before performing this. - - { - //Remove all ASs - ip46_address_t *ass = 0; - lb_as_t *as; - u32 *as_index; - pool_foreach(as_index, vip->as_indexes, { - as = &lbm->ass[*as_index]; - vec_add1(ass, as->address); - }); - if (vec_len(ass)) - lb_vip_del_ass_withlock(vip_index, ass, vec_len(ass)); - vec_free(ass); - } - - //Delete adjacency - lb_vip_del_adjacency(lbm, vip); - - //Set the VIP as unused - vip->flags &= ~LB_VIP_FLAGS_USED; - - lb_put_writer_lock(); - return 0; -} - -clib_error_t * -vlib_plugin_register (vlib_main_t * vm, - vnet_plugin_handoff_t * h, - int from_early_init) -{ - clib_error_t *error = 0; - return error; -} - - -u8 *format_lb_dpo (u8 * s, va_list * va) -{ - index_t index = va_arg (*va, index_t); - CLIB_UNUSED(u32 indent) = va_arg (*va, u32); - lb_main_t *lbm = &lb_main; - lb_vip_t *vip = pool_elt_at_index (lbm->vips, index); - return format (s, "%U", format_lb_vip, vip); -} - -static void lb_dpo_lock (dpo_id_t *dpo) {} -static void lb_dpo_unlock (dpo_id_t *dpo) {} - -static fib_node_t * -lb_fib_node_get_node (fib_node_index_t index) -{ - lb_main_t *lbm = &lb_main; - lb_as_t *as = pool_elt_at_index (lbm->ass, index); - return (&as->fib_node); -} - -static void -lb_fib_node_last_lock_gone (fib_node_t *node) -{ -} - -static lb_as_t * -lb_as_from_fib_node (fib_node_t *node) -{ - return ((lb_as_t*)(((char*)node) - - STRUCT_OFFSET_OF(lb_as_t, fib_node))); -} - -static void -lb_as_stack (lb_as_t *as) -{ - lb_main_t *lbm = &lb_main; - lb_vip_t *vip = &lbm->vips[as->vip_index]; - dpo_stack(lb_vip_is_gre4(vip)?lbm->dpo_gre4_type:lbm->dpo_gre6_type, - lb_vip_is_ip4(vip)?DPO_PROTO_IP4:DPO_PROTO_IP6, - &as->dpo, - fib_entry_contribute_ip_forwarding( - as->next_hop_fib_entry_index)); -} - -static fib_node_back_walk_rc_t -lb_fib_node_back_walk_notify (fib_node_t *node, - fib_node_back_walk_ctx_t *ctx) -{ - lb_as_stack(lb_as_from_fib_node(node)); - return (FIB_NODE_BACK_WALK_CONTINUE); -} - -clib_error_t * -lb_init (vlib_main_t * vm) -{ - vlib_thread_main_t *tm = vlib_get_thread_main (); - lb_main_t *lbm = &lb_main; - lb_as_t *default_as; - fib_node_vft_t lb_fib_node_vft = { - .fnv_get = lb_fib_node_get_node, - .fnv_last_lock = lb_fib_node_last_lock_gone, - .fnv_back_walk = lb_fib_node_back_walk_notify, - }; - dpo_vft_t lb_vft = { - .dv_lock = lb_dpo_lock, - .dv_unlock = lb_dpo_unlock, - .dv_format = format_lb_dpo, - }; - - lbm->vips = 0; - lbm->per_cpu = 0; - vec_validate(lbm->per_cpu, tm->n_vlib_mains - 1); - lbm->writer_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES); - lbm->writer_lock[0] = 0; - lbm->per_cpu_sticky_buckets = LB_DEFAULT_PER_CPU_STICKY_BUCKETS; - lbm->flow_timeout = LB_DEFAULT_FLOW_TIMEOUT; - lbm->ip4_src_address.as_u32 = 0xffffffff; - lbm->ip6_src_address.as_u64[0] = 0xffffffffffffffffL; - lbm->ip6_src_address.as_u64[1] = 0xffffffffffffffffL; - lbm->dpo_gre4_type = dpo_register_new_type(&lb_vft, lb_dpo_gre4_nodes); - lbm->dpo_gre6_type = dpo_register_new_type(&lb_vft, lb_dpo_gre6_nodes); - lbm->fib_node_type = fib_node_register_new_type(&lb_fib_node_vft); - - //Init AS reference counters - vlib_refcount_init(&lbm->as_refcount); - - //Allocate and init default AS. - lbm->ass = 0; - pool_get(lbm->ass, default_as); - default_as->flags = 0; - default_as->dpo.dpoi_next_node = LB_NEXT_DROP; - default_as->vip_index = ~0; - default_as->address.ip6.as_u64[0] = 0xffffffffffffffffL; - default_as->address.ip6.as_u64[1] = 0xffffffffffffffffL; - -#define _(a,b,c) lbm->vip_counters[c].name = b; - lb_foreach_vip_counter -#undef _ - return NULL; -} - -VLIB_INIT_FUNCTION (lb_init); diff --git a/plugins/lb-plugin/lb/lb.h b/plugins/lb-plugin/lb/lb.h deleted file mode 100644 index 882b9b30..00000000 --- a/plugins/lb-plugin/lb/lb.h +++ /dev/null @@ -1,333 +0,0 @@ -/* - * 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. - */ - -/** - * lb-plugin implements a MagLev-like load balancer. - * http://research.google.com/pubs/pub44824.html - * - * It hasn't been tested for interoperability with the original MagLev - * but intends to provide similar functionality. - * The load-balancer receives traffic destined to VIP (Virtual IP) - * addresses from one or multiple(ECMP) routers. - * The load-balancer tunnels the traffic toward many application servers - * ensuring session stickyness (i.e. that a single sessions is tunneled - * towards a single application server). - * - */ - -#ifndef LB_PLUGIN_LB_LB_H_ -#define LB_PLUGIN_LB_LB_H_ - -#include -#include - -#include -#include -#include -#include - -#include - -#define LB_DEFAULT_PER_CPU_STICKY_BUCKETS 1 << 10 -#define LB_DEFAULT_FLOW_TIMEOUT 40 - -typedef enum { - LB_NEXT_DROP, - LB_N_NEXT, -} lb_next_t; - -/** - * Each VIP is configured with a set of - * application server. - */ -typedef struct { - /** - * Registration to FIB event. - */ - fib_node_t fib_node; - - /** - * Destination address used to tunnel traffic towards - * that application server. - * The address is also used as ID and pseudo-random - * seed for the load-balancing process. - */ - ip46_address_t address; - - /** - * ASs are indexed by address and VIP Index. - * Which means there will be duplicated if the same server - * address is used for multiple VIPs. - */ - u32 vip_index; - - /** - * Some per-AS flags. - * For now only LB_AS_FLAGS_USED is defined. - */ - u8 flags; - -#define LB_AS_FLAGS_USED 0x1 - - /** - * Rotating timestamp of when LB_AS_FLAGS_USED flag was last set. - * - * AS removal is based on garbage collection and reference counting. - * When an AS is removed, there is a race between configuration core - * and worker cores which may still add a reference while it should not - * be used. This timestamp is used to not remove the AS while a race condition - * may happen. - */ - u32 last_used; - - /** - * The FIB entry index for the next-hop - */ - fib_node_index_t next_hop_fib_entry_index; - - /** - * The child index on the FIB entry - */ - u32 next_hop_child_index; - - /** - * The next DPO in the graph to follow. - */ - dpo_id_t dpo; - -} lb_as_t; - -format_function_t format_lb_as; - -typedef struct { - u32 as_index; -} lb_new_flow_entry_t; - -#define lb_foreach_vip_counter \ - _(NEXT_PACKET, "packet from existing sessions", 0) \ - _(FIRST_PACKET, "first session packet", 1) \ - _(UNTRACKED_PACKET, "untracked packet", 2) \ - _(NO_SERVER, "no server configured", 3) - -typedef enum { -#define _(a,b,c) LB_VIP_COUNTER_##a = c, - lb_foreach_vip_counter -#undef _ - LB_N_VIP_COUNTERS -} lb_vip_counter_t; - -/** - * The load balancer supports IPv4 and IPv6 traffic - * and GRE4 and GRE6 encap. - */ -typedef enum { - LB_VIP_TYPE_IP6_GRE6, - LB_VIP_TYPE_IP6_GRE4, - LB_VIP_TYPE_IP4_GRE6, - LB_VIP_TYPE_IP4_GRE4, - LB_VIP_N_TYPES, -} lb_vip_type_t; - -format_function_t format_lb_vip_type; -unformat_function_t unformat_lb_vip_type; - -/** - * Load balancing service is provided per VIP. - * In this data model, a VIP can be a whole prefix. - * But load balancing only - * occurs on a per-source-address/port basis. Meaning that if a given source - * reuses the same port for multiple destinations within the same VIP, - * they will be considered as a single flow. - */ -typedef struct { - - //Runtime - - /** - * Vector mapping (flow-hash & new_connect_table_mask) to AS index. - * This is used for new flows. - */ - lb_new_flow_entry_t *new_flow_table; - - /** - * New flows table length - 1 - * (length MUST be a power of 2) - */ - u32 new_flow_table_mask; - - /** - * Last time garbage collection was run to free the ASs. - */ - u32 last_garbage_collection; - - //Not runtime - - /** - * A Virtual IP represents a given service delivered - * by a set of application servers. It can be a single - * address or a prefix. - * IPv4 prefixes are encoded using IPv4-in-IPv6 embedded address - * (i.e. ::/96 prefix). - */ - ip46_address_t prefix; - - /** - * The VIP prefix length. - * In case of IPv4, plen = 96 + ip4_plen. - */ - u8 plen; - - /** - * The type of traffic for this. - * LB_TYPE_UNDEFINED if unknown. - */ - lb_vip_type_t type; - - /** - * Flags related to this VIP. - * LB_VIP_FLAGS_USED means the VIP is active. - * When it is not set, the VIP in the process of being removed. - * We cannot immediately remove a VIP because the VIP index still may be stored - * in the adjacency index. - */ - u8 flags; -#define LB_VIP_FLAGS_USED 0x1 - - /** - * Pool of AS indexes used for this VIP. - * This also includes ASs that have been removed (but are still referenced). - */ - u32 *as_indexes; -} lb_vip_t; - -#define lb_vip_is_ip4(vip) ((vip)->type == LB_VIP_TYPE_IP4_GRE6 || (vip)->type == LB_VIP_TYPE_IP4_GRE4) -#define lb_vip_is_gre4(vip) ((vip)->type == LB_VIP_TYPE_IP6_GRE4 || (vip)->type == LB_VIP_TYPE_IP4_GRE4) -format_function_t format_lb_vip; -format_function_t format_lb_vip_detailed; - -typedef struct { - /** - * Each CPU has its own sticky flow hash table. - * One single table is used for all VIPs. - */ - lb_hash_t *sticky_ht; -} lb_per_cpu_t; - -typedef struct { - /** - * Pool of all Virtual IPs - */ - lb_vip_t *vips; - - /** - * Pool of ASs. - * ASs are referenced by address and vip index. - * The first element (index 0) is special and used only to fill - * new_flow_tables when no AS has been configured. - */ - lb_as_t *ass; - - /** - * Each AS has an associated reference counter. - * As ass[0] has a special meaning, its associated counter - * starts at 0 and is decremented instead. i.e. do not use it. - */ - vlib_refcount_t as_refcount; - - /** - * Some global data is per-cpu - */ - lb_per_cpu_t *per_cpu; - - /** - * Node next index for IP adjacencies, for each of the traffic types. - */ - u32 ip_lookup_next_index[LB_VIP_N_TYPES]; - - /** - * Source address used in IPv6 encapsulated traffic - */ - ip6_address_t ip6_src_address; - - /** - * Source address used for IPv4 encapsulated traffic - */ - ip4_address_t ip4_src_address; - - /** - * Number of buckets in the per-cpu sticky hash table. - */ - u32 per_cpu_sticky_buckets; - - /** - * Flow timeout in seconds. - */ - u32 flow_timeout; - - /** - * Per VIP counter - */ - vlib_simple_counter_main_t vip_counters[LB_N_VIP_COUNTERS]; - - /** - * DPO used to send packet from IP4/6 lookup to LB node. - */ - dpo_type_t dpo_gre4_type; - dpo_type_t dpo_gre6_type; - - /** - * Node type for registering to fib changes. - */ - fib_node_type_t fib_node_type; - - /** - * API dynamically registered base ID. - */ - u16 msg_id_base; - - volatile u32 *writer_lock; -} lb_main_t; - -extern lb_main_t lb_main; -extern vlib_node_registration_t lb6_node; -extern vlib_node_registration_t lb4_node; - -/** - * Fix global load-balancer parameters. - * @param ip4_address IPv4 source address used for encapsulated traffic - * @param ip6_address IPv6 source address used for encapsulated traffic - * @return 0 on success. VNET_LB_ERR_XXX on error - */ -int lb_conf(ip4_address_t *ip4_address, ip6_address_t *ip6_address, - u32 sticky_buckets, u32 flow_timeout); - -int lb_vip_add(ip46_address_t *prefix, u8 plen, lb_vip_type_t type, - u32 new_length, u32 *vip_index); -int lb_vip_del(u32 vip_index); - -int lb_vip_find_index(ip46_address_t *prefix, u8 plen, u32 *vip_index); - -#define lb_vip_get_by_index(index) (pool_is_free_index(lb_main.vips, index)?NULL:pool_elt_at_index(lb_main.vips, index)) - -int lb_vip_add_ass(u32 vip_index, ip46_address_t *addresses, u32 n); -int lb_vip_del_ass(u32 vip_index, ip46_address_t *addresses, u32 n); - -u32 lb_hash_time_now(vlib_main_t * vm); - -void lb_garbage_collection(); - -format_function_t format_lb_main; - -#endif /* LB_PLUGIN_LB_LB_H_ */ diff --git a/plugins/lb-plugin/lb/lb_test.c b/plugins/lb-plugin/lb/lb_test.c deleted file mode 100644 index 8c2eaa91..00000000 --- a/plugins/lb-plugin/lb/lb_test.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include -#include -#include -#include - -//TODO: Move that to vat/plugin_api.c -////////////////////////// -uword unformat_ip46_address (unformat_input_t * input, va_list * args) -{ - ip46_address_t *ip46 = va_arg (*args, ip46_address_t *); - ip46_type_t type = va_arg (*args, ip46_type_t); - if ((type != IP46_TYPE_IP6) && - unformat(input, "%U", unformat_ip4_address, &ip46->ip4)) { - ip46_address_mask_ip4(ip46); - return 1; - } else if ((type != IP46_TYPE_IP4) && - unformat(input, "%U", unformat_ip6_address, &ip46->ip6)) { - return 1; - } - return 0; -} -uword unformat_ip46_prefix (unformat_input_t * input, va_list * args) -{ - ip46_address_t *ip46 = va_arg (*args, ip46_address_t *); - u8 *len = va_arg (*args, u8 *); - ip46_type_t type = va_arg (*args, ip46_type_t); - - u32 l; - if ((type != IP46_TYPE_IP6) && unformat(input, "%U/%u", unformat_ip4_address, &ip46->ip4, &l)) { - if (l > 32) - return 0; - *len = l + 96; - ip46->pad[0] = ip46->pad[1] = ip46->pad[2] = 0; - } else if ((type != IP46_TYPE_IP4) && unformat(input, "%U/%u", unformat_ip6_address, &ip46->ip6, &l)) { - if (l > 128) - return 0; - *len = l; - } else { - return 0; - } - return 1; -} -///////////////////////// - -#define vl_msg_id(n,h) n, -typedef enum { -#include - /* We'll want to know how many messages IDs we need... */ - VL_MSG_FIRST_AVAILABLE, -} vl_msg_id_t; -#undef vl_msg_id - -/* define message structures */ -#define vl_typedefs -#include -#undef vl_typedefs - -/* declare message handlers for each api */ - -#define vl_endianfun /* define message structures */ -#include -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) -#define vl_printfun -#include -#undef vl_printfun - -/* Get the API version number. */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#undef vl_api_version - -typedef struct { - /* API message ID base */ - u16 msg_id_base; - vat_main_t *vat_main; -} lb_test_main_t; - -lb_test_main_t lb_test_main; - -#define foreach_standard_reply_retval_handler \ -_(lb_conf_reply) \ -_(lb_add_del_vip_reply) \ -_(lb_add_del_as_reply) - -#define _(n) \ - static void vl_api_##n##_t_handler \ - (vl_api_##n##_t * mp) \ - { \ - vat_main_t * vam = lb_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 \ - _(LB_CONF_REPLY, lb_conf_reply) \ - _(LB_ADD_DEL_VIP_REPLY, lb_add_del_vip_reply) \ - _(LB_ADD_DEL_AS_REPLY, lb_add_del_as_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)); \ - memcpy (mp, &mps, sizeof (*mp)); \ - mp->_vl_msg_id = ntohs (VL_API_##T + lbtm->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_lb_conf (vat_main_t * vam) -{ - lb_test_main_t *lbtm = &lb_test_main; - unformat_input_t *i = vam->input; - f64 timeout; - vl_api_lb_conf_t mps, *mp; - - if (!unformat(i, "%U %U %u %u", - unformat_ip4_address, &mps.ip4_src_address, - unformat_ip6_address, mps.ip6_src_address, - &mps.sticky_buckets_per_core, - &mps.flow_timeout)) { - errmsg ("invalid arguments\n"); - return -99; - } - - M(LB_CONF, lb_conf); S; W; - - /* NOTREACHED */ - return 0; -} - -static int api_lb_add_del_vip (vat_main_t * vam) -{ - lb_test_main_t *lbtm = &lb_test_main; - unformat_input_t * i = vam->input; - f64 timeout; - vl_api_lb_add_del_vip_t mps, *mp; - mps.is_del = 0; - mps.is_gre4 = 0; - - if (!unformat(i, "%U", - unformat_ip46_prefix, mps.ip_prefix, &mps.prefix_length, IP46_TYPE_ANY)) { - errmsg ("invalid prefix\n"); - return -99; - } - - if (unformat(i, "gre4")) { - mps.is_gre4 = 1; - } else if (unformat(i, "gre6")) { - mps.is_gre4 = 0; - } else { - errmsg ("no encap\n"); - return -99; - } - - if (!unformat(i, "%d", &mps.new_flows_table_length)) { - errmsg ("no table lentgh\n"); - return -99; - } - - if (unformat(i, "del")) { - mps.is_del = 1; - } - - M(LB_ADD_DEL_VIP, lb_add_del_vip); S; W; - /* NOTREACHED */ - return 0; -} - -static int api_lb_add_del_as (vat_main_t * vam) -{ - lb_test_main_t *lbtm = &lb_test_main; - unformat_input_t * i = vam->input; - f64 timeout; - vl_api_lb_add_del_as_t mps, *mp; - mps.is_del = 0; - - if (!unformat(i, "%U %U", - unformat_ip46_prefix, mps.vip_ip_prefix, &mps.vip_prefix_length, IP46_TYPE_ANY, - unformat_ip46_address, mps.as_address)) { - errmsg ("invalid prefix or address\n"); - return -99; - } - - if (unformat(i, "del")) { - mps.is_del = 1; - } - - M(LB_ADD_DEL_AS, lb_add_del_as); S; W; - /* NOTREACHED */ - return 0; -} - -/* - * List of messages that the api test plugin sends, - * and that the data plane plugin processes - */ -#define foreach_vpe_api_msg \ -_(lb_conf, " ") \ -_(lb_add_del_vip, " [gre4|gre6] [del]") \ -_(lb_add_del_as, "
[del]") - -void vat_api_hookup (vat_main_t *vam) -{ - lb_test_main_t * lbtm = &lb_test_main; - /* Hook up handlers for replies from the data plane plug-in */ -#define _(N,n) \ - vl_msg_api_set_handlers((VL_API_##N + lbtm->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) -{ - lb_test_main_t * lbtm = &lb_test_main; - - u8 * name; - - lbtm->vat_main = vam; - - /* Ask the vpp engine for the first assigned message-id */ - name = format (0, "lb_%08x%c", api_version, 0); - lbtm->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name); - - if (lbtm->msg_id_base != (u16) ~0) - vat_api_hookup (vam); - - vec_free(name); - - return 0; -} diff --git a/plugins/lb-plugin/lb/lbhash.h b/plugins/lb-plugin/lb/lbhash.h deleted file mode 100644 index ca3cc143..00000000 --- a/plugins/lb-plugin/lb/lbhash.h +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (c) 2012 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. - */ - -/** - * vppinfra already includes tons of different hash tables. - * MagLev flow table is a bit different. It has to be very efficient - * for both writing and reading operations. But it does not need to - * be 100% reliable (write can fail). It also needs to recycle - * old entries in a lazy way. - * - * This hash table is the most dummy hash table you can do. - * Fixed total size, fixed bucket size. - * Advantage is that it could be very efficient (maybe). - * - */ - -#ifndef LB_PLUGIN_LB_LBHASH_H_ -#define LB_PLUGIN_LB_LBHASH_H_ - -#include - -#if defined (__SSE4_2__) -#include -#endif - -/* - * @brief Number of entries per bucket. - */ -#define LBHASH_ENTRY_PER_BUCKET 4 - -#define LB_HASH_DO_NOT_USE_SSE_BUCKETS 0 - -/* - * @brief One bucket contains 4 entries. - * Each bucket takes one 64B cache line in memory. - */ -typedef struct { - CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); - u32 hash[LBHASH_ENTRY_PER_BUCKET]; - u32 timeout[LBHASH_ENTRY_PER_BUCKET]; - u32 vip[LBHASH_ENTRY_PER_BUCKET]; - u32 value[LBHASH_ENTRY_PER_BUCKET]; -} lb_hash_bucket_t; - -typedef struct { - u32 buckets_mask; - u32 timeout; - lb_hash_bucket_t buckets[]; -} lb_hash_t; - -#define lb_hash_nbuckets(h) (((h)->buckets_mask) + 1) -#define lb_hash_size(h) ((h)->buckets_mask + LBHASH_ENTRY_PER_BUCKET) - -#define lb_hash_foreach_bucket(h, bucket) \ - for (bucket = (h)->buckets; \ - bucket < (h)->buckets + lb_hash_nbuckets(h); \ - bucket++) - -#define lb_hash_foreach_entry(h, bucket, i) \ - lb_hash_foreach_bucket(h, bucket) \ - for (i = 0; i < LBHASH_ENTRY_PER_BUCKET; i++) - -#define lb_hash_foreach_valid_entry(h, bucket, i, now) \ - lb_hash_foreach_entry(h, bucket, i) \ - if (!clib_u32_loop_gt((now), bucket->timeout[i])) - -static_always_inline -lb_hash_t *lb_hash_alloc(u32 buckets, u32 timeout) -{ - if (!is_pow2(buckets)) - return NULL; - - // Allocate 1 more bucket for prefetch - u32 size = ((u64)&((lb_hash_t *)(0))->buckets[0]) + - sizeof(lb_hash_bucket_t) * (buckets + 1); - u8 *mem = 0; - lb_hash_t *h; - vec_alloc_aligned(mem, size, CLIB_CACHE_LINE_BYTES); - h = (lb_hash_t *)mem; - h->buckets_mask = (buckets - 1); - h->timeout = timeout; - return h; -} - -static_always_inline -void lb_hash_free(lb_hash_t *h) -{ - u8 *mem = (u8 *)h; - vec_free(mem); -} - -#if __SSE4_2__ -static_always_inline -u32 lb_hash_hash(u64 k0, u64 k1, u64 k2, u64 k3, u64 k4) -{ - u64 val = 0; - val = _mm_crc32_u64(val, k0); - val = _mm_crc32_u64(val, k1); - val = _mm_crc32_u64(val, k2); - val = _mm_crc32_u64(val, k3); - val = _mm_crc32_u64(val, k4); - return (u32) val; -} -#else -static_always_inline -u32 lb_hash_hash(u64 k0, u64 k1, u64 k2, u64 k3, u64 k4) -{ - u64 tmp = k0 ^ k1 ^ k2 ^ k3 ^ k4; - return (u32)clib_xxhash (tmp); -} -#endif - -static_always_inline -void lb_hash_prefetch_bucket(lb_hash_t *ht, u32 hash) -{ - lb_hash_bucket_t *bucket = &ht->buckets[hash & ht->buckets_mask]; - CLIB_PREFETCH(bucket, sizeof(*bucket), READ); -} - -static_always_inline -void lb_hash_get(lb_hash_t *ht, u32 hash, u32 vip, u32 time_now, - u32 *available_index, u32 *found_value) -{ - lb_hash_bucket_t *bucket = &ht->buckets[hash & ht->buckets_mask]; - *found_value = ~0; - *available_index = ~0; -#if __SSE4_2__ && LB_HASH_DO_NOT_USE_SSE_BUCKETS == 0 - u32 bitmask, found_index; - __m128i mask; - - // mask[*] = timeout[*] > now - mask = _mm_cmpgt_epi32(_mm_loadu_si128 ((__m128i *) bucket->timeout), - _mm_set1_epi32 (time_now)); - // bitmask[*] = now <= timeout[*/4] - bitmask = (~_mm_movemask_epi8(mask)) & 0xffff; - // Get first index with now <= timeout[*], if any. - *available_index = (bitmask)?__builtin_ctz(bitmask)/4:*available_index; - - // mask[*] = (timeout[*] > now) && (hash[*] == hash) - mask = _mm_and_si128(mask, - _mm_cmpeq_epi32( - _mm_loadu_si128 ((__m128i *) bucket->hash), - _mm_set1_epi32 (hash))); - - // Load the array of vip values - // mask[*] = (timeout[*] > now) && (hash[*] == hash) && (vip[*] == vip) - mask = _mm_and_si128(mask, - _mm_cmpeq_epi32( - _mm_loadu_si128 ((__m128i *) bucket->vip), - _mm_set1_epi32 (vip))); - - // mask[*] = (timeout[*x4] > now) && (hash[*x4] == hash) && (vip[*x4] == vip) - bitmask = _mm_movemask_epi8(mask); - // Get first index, if any - found_index = (bitmask)?__builtin_ctzll(bitmask)/4:0; - ASSERT(found_index < 4); - *found_value = (bitmask)?bucket->value[found_index]:*found_value; - bucket->timeout[found_index] = - (bitmask)?time_now + ht->timeout:bucket->timeout[found_index]; -#else - u32 i; - for (i = 0; i < LBHASH_ENTRY_PER_BUCKET; i++) { - u8 cmp = (bucket->hash[i] == hash && bucket->vip[i] == vip); - u8 timeouted = clib_u32_loop_gt(time_now, bucket->timeout[i]); - *found_value = (cmp || timeouted)?*found_value:bucket->value[i]; - bucket->timeout[i] = (cmp || timeouted)?time_now + ht->timeout:bucket->timeout[i]; - *available_index = (timeouted && (*available_index == ~0))?i:*available_index; - - if (!cmp) - return; - } -#endif -} - -static_always_inline -u32 lb_hash_available_value(lb_hash_t *h, u32 hash, u32 available_index) -{ - return h->buckets[hash & h->buckets_mask].value[available_index]; -} - -static_always_inline -void lb_hash_put(lb_hash_t *h, u32 hash, u32 value, u32 vip, - u32 available_index, u32 time_now) -{ - lb_hash_bucket_t *bucket = &h->buckets[hash & h->buckets_mask]; - bucket->hash[available_index] = hash; - bucket->value[available_index] = value; - bucket->timeout[available_index] = time_now + h->timeout; - bucket->vip[available_index] = vip; -} - -static_always_inline -u32 lb_hash_elts(lb_hash_t *h, u32 time_now) -{ - u32 tot = 0; - lb_hash_bucket_t *bucket; - u32 i; - lb_hash_foreach_valid_entry(h, bucket, i, time_now) { - tot++; - } - return tot; -} - -#endif /* LB_PLUGIN_LB_LBHASH_H_ */ diff --git a/plugins/lb-plugin/lb/node.c b/plugins/lb-plugin/lb/node.c deleted file mode 100644 index 8b763c53..00000000 --- a/plugins/lb-plugin/lb/node.c +++ /dev/null @@ -1,419 +0,0 @@ -/* - * 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. - */ - -#include - -#include -#include - -#define foreach_lb_error \ - _(NONE, "no error") \ - _(PROTO_NOT_SUPPORTED, "protocol not supported") - -typedef enum { -#define _(sym,str) LB_ERROR_##sym, - foreach_lb_error -#undef _ - LB_N_ERROR, -} lb_error_t; - -static char *lb_error_strings[] = { -#define _(sym,string) string, - foreach_lb_error -#undef _ -}; - -typedef struct { - u32 vip_index; - u32 as_index; -} lb_trace_t; - -u8 * -format_lb_trace (u8 * s, va_list * args) -{ - lb_main_t *lbm = &lb_main; - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - lb_trace_t *t = va_arg (*args, lb_trace_t *); - if (pool_is_free_index(lbm->vips, t->vip_index)) { - s = format(s, "lb vip[%d]: This VIP was freed since capture\n"); - } else { - s = format(s, "lb vip[%d]: %U\n", t->vip_index, format_lb_vip, &lbm->vips[t->vip_index]); - } - if (pool_is_free_index(lbm->ass, t->as_index)) { - s = format(s, "lb as[%d]: This AS was freed since capture\n"); - } else { - s = format(s, "lb as[%d]: %U\n", t->as_index, format_lb_as, &lbm->ass[t->as_index]); - } - return s; -} - -lb_hash_t *lb_get_sticky_table(u32 cpu_index) -{ - lb_main_t *lbm = &lb_main; - lb_hash_t *sticky_ht = lbm->per_cpu[cpu_index].sticky_ht; - //Check if size changed - if (PREDICT_FALSE(sticky_ht && (lbm->per_cpu_sticky_buckets != lb_hash_nbuckets(sticky_ht)))) - { - //Dereference everything in there - lb_hash_bucket_t *b; - u32 i; - lb_hash_foreach_entry(sticky_ht, b, i) { - vlib_refcount_add(&lbm->as_refcount, cpu_index, b->value[i], -1); - vlib_refcount_add(&lbm->as_refcount, cpu_index, 0, 1); - } - - lb_hash_free(sticky_ht); - sticky_ht = NULL; - } - - //Create if necessary - if (PREDICT_FALSE(sticky_ht == NULL)) { - lbm->per_cpu[cpu_index].sticky_ht = lb_hash_alloc(lbm->per_cpu_sticky_buckets, lbm->flow_timeout); - sticky_ht = lbm->per_cpu[cpu_index].sticky_ht; - clib_warning("Regenerated sticky table %p", sticky_ht); - } - - ASSERT(sticky_ht); - - //Update timeout - sticky_ht->timeout = lbm->flow_timeout; - return sticky_ht; -} - -u64 -lb_node_get_other_ports4(ip4_header_t *ip40) -{ - return 0; -} - -u64 -lb_node_get_other_ports6(ip6_header_t *ip60) -{ - return 0; -} - -static_always_inline u32 -lb_node_get_hash(vlib_buffer_t *p, u8 is_input_v4) -{ - u32 hash; - if (is_input_v4) - { - ip4_header_t *ip40; - u64 ports; - ip40 = vlib_buffer_get_current (p); - if (PREDICT_TRUE (ip40->protocol == IP_PROTOCOL_TCP || - ip40->protocol == IP_PROTOCOL_UDP)) - ports = ((u64)((udp_header_t *)(ip40 + 1))->src_port << 16) | - ((u64)((udp_header_t *)(ip40 + 1))->dst_port); - else - ports = lb_node_get_other_ports4(ip40); - - hash = lb_hash_hash(*((u64 *)&ip40->address_pair), ports, - 0, 0, 0); - } - else - { - ip6_header_t *ip60; - ip60 = vlib_buffer_get_current (p); - u64 ports; - if (PREDICT_TRUE (ip60->protocol == IP_PROTOCOL_TCP || - ip60->protocol == IP_PROTOCOL_UDP)) - ports = ((u64)((udp_header_t *)(ip60 + 1))->src_port << 16) | - ((u64)((udp_header_t *)(ip60 + 1))->dst_port); - else - ports = lb_node_get_other_ports6(ip60); - - hash = lb_hash_hash(ip60->src_address.as_u64[0], - ip60->src_address.as_u64[1], - ip60->dst_address.as_u64[0], - ip60->dst_address.as_u64[1], - ports); - } - return hash; -} - -static_always_inline uword -lb_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame, - u8 is_input_v4, //Compile-time parameter stating that is input is v4 (or v6) - u8 is_encap_v4) //Compile-time parameter stating that is GRE encap is v4 (or v6) -{ - lb_main_t *lbm = &lb_main; - u32 n_left_from, *from, next_index, *to_next, n_left_to_next; - u32 cpu_index = os_get_cpu_number(); - u32 lb_time = lb_hash_time_now(vm); - - lb_hash_t *sticky_ht = lb_get_sticky_table(cpu_index); - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - u32 nexthash0 = 0; - if (PREDICT_TRUE(n_left_from > 0)) - nexthash0 = lb_node_get_hash(vlib_get_buffer (vm, from[0]), is_input_v4); - - while (n_left_from > 0) - { - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 pi0; - vlib_buffer_t *p0; - lb_vip_t *vip0; - u32 asindex0; - u16 len0; - u32 available_index0; - u8 counter = 0; - u32 hash0 = nexthash0; - - if (PREDICT_TRUE(n_left_from > 1)) - { - vlib_buffer_t *p1 = vlib_get_buffer (vm, from[1]); - //Compute next hash and prefetch bucket - nexthash0 = lb_node_get_hash(p1, is_input_v4); - lb_hash_prefetch_bucket(sticky_ht, nexthash0); - //Prefetch for encap, next - CLIB_PREFETCH (vlib_buffer_get_current(p1) - 64, 64, STORE); - } - - if (PREDICT_TRUE(n_left_from > 2)) - { - vlib_buffer_t *p2; - p2 = vlib_get_buffer(vm, from[2]); - /* prefetch packet header and data */ - vlib_prefetch_buffer_header(p2, STORE); - CLIB_PREFETCH (vlib_buffer_get_current(p2), 64, STORE); - } - - pi0 = to_next[0] = from[0]; - from += 1; - n_left_from -= 1; - to_next += 1; - n_left_to_next -= 1; - - p0 = vlib_get_buffer (vm, pi0); - vip0 = pool_elt_at_index (lbm->vips, - vnet_buffer (p0)->ip.adj_index[VLIB_TX]); - - if (is_input_v4) - { - ip4_header_t *ip40; - ip40 = vlib_buffer_get_current (p0); - len0 = clib_net_to_host_u16(ip40->length); - } - else - { - ip6_header_t *ip60; - ip60 = vlib_buffer_get_current (p0); - len0 = clib_net_to_host_u16(ip60->payload_length) + sizeof(ip6_header_t); - } - - lb_hash_get(sticky_ht, hash0, vnet_buffer (p0)->ip.adj_index[VLIB_TX], - lb_time, &available_index0, &asindex0); - - if (PREDICT_TRUE(asindex0 != ~0)) - { - //Found an existing entry - counter = LB_VIP_COUNTER_NEXT_PACKET; - } - else if (PREDICT_TRUE(available_index0 != ~0)) - { - //There is an available slot for a new flow - asindex0 = vip0->new_flow_table[hash0 & vip0->new_flow_table_mask].as_index; - counter = LB_VIP_COUNTER_FIRST_PACKET; - counter = (asindex0 == 0)?LB_VIP_COUNTER_NO_SERVER:counter; - - //TODO: There are race conditions with as0 and vip0 manipulation. - //Configuration may be changed, vectors resized, etc... - - //Dereference previously used - vlib_refcount_add(&lbm->as_refcount, cpu_index, - lb_hash_available_value(sticky_ht, hash0, available_index0), -1); - vlib_refcount_add(&lbm->as_refcount, cpu_index, - asindex0, 1); - - //Add sticky entry - //Note that when there is no AS configured, an entry is configured anyway. - //But no configured AS is not something that should happen - lb_hash_put(sticky_ht, hash0, asindex0, - vnet_buffer (p0)->ip.adj_index[VLIB_TX], - available_index0, lb_time); - } - else - { - //Could not store new entry in the table - asindex0 = vip0->new_flow_table[hash0 & vip0->new_flow_table_mask].as_index; - counter = LB_VIP_COUNTER_UNTRACKED_PACKET; - } - - vlib_increment_simple_counter(&lbm->vip_counters[counter], - cpu_index, - vnet_buffer (p0)->ip.adj_index[VLIB_TX], - 1); - - //Now let's encap - { - gre_header_t *gre0; - if (is_encap_v4) - { - ip4_header_t *ip40; - vlib_buffer_advance(p0, - sizeof(ip4_header_t) - sizeof(gre_header_t)); - ip40 = vlib_buffer_get_current(p0); - gre0 = (gre_header_t *)(ip40 + 1); - ip40->src_address = lbm->ip4_src_address; - ip40->dst_address = lbm->ass[asindex0].address.ip4; - ip40->ip_version_and_header_length = 0x45; - ip40->ttl = 128; - ip40->length = clib_host_to_net_u16(len0 + sizeof(gre_header_t) + sizeof(ip4_header_t)); - ip40->protocol = IP_PROTOCOL_GRE; - ip40->checksum = ip4_header_checksum (ip40); - } - else - { - ip6_header_t *ip60; - vlib_buffer_advance(p0, - sizeof(ip6_header_t) - sizeof(gre_header_t)); - ip60 = vlib_buffer_get_current(p0); - gre0 = (gre_header_t *)(ip60 + 1); - ip60->dst_address = lbm->ass[asindex0].address.ip6; - ip60->src_address = lbm->ip6_src_address; - ip60->hop_limit = 128; - ip60->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (0x6<<28); - ip60->payload_length = clib_host_to_net_u16(len0 + sizeof(gre_header_t)); - ip60->protocol = IP_PROTOCOL_GRE; - } - - gre0->flags_and_version = 0; - gre0->protocol = (is_input_v4)? - clib_host_to_net_u16(0x0800): - clib_host_to_net_u16(0x86DD); - } - - if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) - { - lb_trace_t *tr = vlib_add_trace (vm, node, p0, sizeof (*tr)); - tr->as_index = asindex0; - tr->vip_index = vnet_buffer (p0)->ip.adj_index[VLIB_TX]; - } - - //Enqueue to next - //Note that this is going to error if asindex0 == 0 - vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbm->ass[asindex0].dpo.dpoi_index; - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, pi0, - lbm->ass[asindex0].dpo.dpoi_next_node); - } - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - return frame->n_vectors; -} - -static uword -lb6_gre6_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) -{ - return lb_node_fn(vm, node, frame, 0, 0); -} - -static uword -lb6_gre4_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) -{ - return lb_node_fn(vm, node, frame, 0, 1); -} - -static uword -lb4_gre6_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) -{ - return lb_node_fn(vm, node, frame, 1, 0); -} - -static uword -lb4_gre4_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) -{ - return lb_node_fn(vm, node, frame, 1, 1); -} - -VLIB_REGISTER_NODE (lb6_gre6_node) = -{ - .function = lb6_gre6_node_fn, - .name = "lb6-gre6", - .vector_size = sizeof (u32), - .format_trace = format_lb_trace, - - .n_errors = LB_N_ERROR, - .error_strings = lb_error_strings, - - .n_next_nodes = LB_N_NEXT, - .next_nodes = - { - [LB_NEXT_DROP] = "error-drop" - }, -}; - -VLIB_REGISTER_NODE (lb6_gre4_node) = -{ - .function = lb6_gre4_node_fn, - .name = "lb6-gre4", - .vector_size = sizeof (u32), - .format_trace = format_lb_trace, - - .n_errors = LB_N_ERROR, - .error_strings = lb_error_strings, - - .n_next_nodes = LB_N_NEXT, - .next_nodes = - { - [LB_NEXT_DROP] = "error-drop" - }, -}; - -VLIB_REGISTER_NODE (lb4_gre6_node) = -{ - .function = lb4_gre6_node_fn, - .name = "lb4-gre6", - .vector_size = sizeof (u32), - .format_trace = format_lb_trace, - - .n_errors = LB_N_ERROR, - .error_strings = lb_error_strings, - - .n_next_nodes = LB_N_NEXT, - .next_nodes = - { - [LB_NEXT_DROP] = "error-drop" - }, -}; - -VLIB_REGISTER_NODE (lb4_gre4_node) = -{ - .function = lb4_gre4_node_fn, - .name = "lb4-gre4", - .vector_size = sizeof (u32), - .format_trace = format_lb_trace, - - .n_errors = LB_N_ERROR, - .error_strings = lb_error_strings, - - .n_next_nodes = LB_N_NEXT, - .next_nodes = - { - [LB_NEXT_DROP] = "error-drop" - }, -}; - diff --git a/plugins/lb-plugin/lb/refcount.c b/plugins/lb-plugin/lb/refcount.c deleted file mode 100644 index 22415c88..00000000 --- a/plugins/lb-plugin/lb/refcount.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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. - */ - -#include - -void __vlib_refcount_resize(vlib_refcount_per_cpu_t *per_cpu, u32 size) -{ - u32 *new_counter = 0, *old_counter; - vec_validate(new_counter, size); - memcpy(new_counter, per_cpu->counters, per_cpu->length); - old_counter = per_cpu->counters; - per_cpu->counters = new_counter; - CLIB_MEMORY_BARRIER(); - per_cpu->length = vec_len(new_counter); - vec_free(old_counter); -} - -u64 vlib_refcount_get(vlib_refcount_t *r, u32 index) -{ - u64 count = 0; - vlib_thread_main_t *tm = vlib_get_thread_main (); - u32 cpu_index; - for (cpu_index = 0; cpu_index < tm->n_vlib_mains; cpu_index++) { - if (r->per_cpu[cpu_index].length > index) - count += r->per_cpu[cpu_index].counters[index]; - } - return count; -} - diff --git a/plugins/lb-plugin/lb/refcount.h b/plugins/lb-plugin/lb/refcount.h deleted file mode 100644 index 8c26e7be..00000000 --- a/plugins/lb-plugin/lb/refcount.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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. - */ - -/* - * vlib provides lock-free counters but those - * - Have 16bits per-CPU counter, which may overflow. - * - Would only increment. - * - * This is very similar to vlib counters, but may be used to count reference. - * Such a counter includes an arbitrary number of counters. Each counter - * is identified by its index. This is used to aggregate per-cpu memory. - * - * Warning: - * This reference counter is lock-free but is not race-condition free. - * The counting result is approximate and another mechanism needs to be used - * in order to ensure that an object may be freed. - * - */ - -#include - -typedef struct { - u32 *counters; - u32 length; - u32 *reader_lengths; - CLIB_CACHE_LINE_ALIGN_MARK(o); -} vlib_refcount_per_cpu_t; - -typedef struct { - vlib_refcount_per_cpu_t *per_cpu; -} vlib_refcount_t; - -void __vlib_refcount_resize(vlib_refcount_per_cpu_t *per_cpu, u32 size); - -static_always_inline -void vlib_refcount_add(vlib_refcount_t *r, u32 cpu_index, u32 counter_index, i32 v) -{ - vlib_refcount_per_cpu_t *per_cpu = &r->per_cpu[cpu_index]; - if (PREDICT_FALSE(counter_index >= per_cpu->length)) - __vlib_refcount_resize(per_cpu, clib_max(counter_index + 16, per_cpu->length * 2)); - - per_cpu->counters[counter_index] += v; -} - -u64 vlib_refcount_get(vlib_refcount_t *r, u32 index); - -static_always_inline -void vlib_refcount_init(vlib_refcount_t *r) -{ - vlib_thread_main_t *tm = vlib_get_thread_main (); - r->per_cpu = 0; - vec_validate (r->per_cpu, tm->n_vlib_mains - 1); -} - - diff --git a/plugins/lb-plugin/lb/util.c b/plugins/lb-plugin/lb/util.c deleted file mode 100644 index d969d168..00000000 --- a/plugins/lb-plugin/lb/util.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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. - */ - -#include - -void ip46_prefix_normalize(ip46_address_t *prefix, u8 plen) -{ - if (plen == 0) { - prefix->as_u64[0] = 0; - prefix->as_u64[1] = 0; - } else if (plen <= 64) { - prefix->as_u64[0] &= clib_host_to_net_u64(0xffffffffffffffffL << (64 - plen)); - prefix->as_u64[1] = 0; - } else { - prefix->as_u64[1] &= clib_host_to_net_u64(0xffffffffffffffffL << (128 - plen)); - } - -} - -uword unformat_ip46_prefix (unformat_input_t * input, va_list * args) -{ - ip46_address_t *ip46 = va_arg (*args, ip46_address_t *); - u8 *len = va_arg (*args, u8 *); - ip46_type_t type = va_arg (*args, ip46_type_t); - - u32 l; - if ((type != IP46_TYPE_IP6) && unformat(input, "%U/%u", unformat_ip4_address, &ip46->ip4, &l)) { - if (l > 32) - return 0; - *len = l + 96; - ip46->pad[0] = ip46->pad[1] = ip46->pad[2] = 0; - } else if ((type != IP46_TYPE_IP4) && unformat(input, "%U/%u", unformat_ip6_address, &ip46->ip6, &l)) { - if (l > 128) - return 0; - *len = l; - } else { - return 0; - } - return 1; -} - -u8 *format_ip46_prefix (u8 * s, va_list * args) -{ - ip46_address_t *ip46 = va_arg (*args, ip46_address_t *); - u32 len = va_arg (*args, u32); //va_arg cannot use u8 or u16 - ip46_type_t type = va_arg (*args, ip46_type_t); - - int is_ip4 = 0; - if (type == IP46_TYPE_IP4) - is_ip4 = 1; - else if (type == IP46_TYPE_IP6) - is_ip4 = 0; - else - is_ip4 = (len >= 96) && ip46_address_is_ip4(ip46); - - return is_ip4 ? - format(s, "%U/%d", format_ip4_address, &ip46->ip4, len - 96): - format(s, "%U/%d", format_ip6_address, &ip46->ip6, len); -} - diff --git a/plugins/lb-plugin/lb/util.h b/plugins/lb-plugin/lb/util.h deleted file mode 100644 index 3f082310..00000000 --- a/plugins/lb-plugin/lb/util.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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. - */ - -/* - * Non-LB specific stuff comes here - */ - -#ifndef LB_PLUGIN_LB_UTIL_H_ -#define LB_PLUGIN_LB_UTIL_H_ - -#include -#include - -#define ip46_address_type(ip46) (ip46_address_is_ip4(ip46)?IP46_TYPE_IP4:IP46_TYPE_IP6) -#define ip46_prefix_is_ip4(ip46, len) ((len) >= 96 && ip46_address_is_ip4(ip46)) -#define ip46_prefix_type(ip46, len) (ip46_prefix_is_ip4(ip46, len)?IP46_TYPE_IP4:IP46_TYPE_IP6) - -void ip46_prefix_normalize(ip46_address_t *prefix, u8 plen); -uword unformat_ip46_prefix (unformat_input_t * input, va_list * args); -u8 *format_ip46_prefix (u8 * s, va_list * args); - -/** - * 32 bits integer comparison for running values. - * 1 > 0 is true. But 1 > 0xffffffff also is. - */ -#define clib_u32_loop_gt(a, b) (((u32)(a)) - ((u32)(b)) < 0x7fffffff) - -#endif /* LB_PLUGIN_LB_UTIL_H_ */ diff --git a/plugins/lb-plugin/lb_plugin_doc.md b/plugins/lb-plugin/lb_plugin_doc.md deleted file mode 100644 index c7885ffb..00000000 --- a/plugins/lb-plugin/lb_plugin_doc.md +++ /dev/null @@ -1,141 +0,0 @@ -# Load Balancer plugin for VPP {#lb_plugin_doc} - -## Version - -The load balancer plugin is currently in *beta* version. -Both CLIs and APIs are subject to *heavy* changes. -Wich also means feedback is really welcome regarding features, apis, etc... - -## Overview - -This plugin provides load balancing for VPP in a way that is largely inspired -from Google's MagLev: http://research.google.com/pubs/pub44824.html - -The load balancer is configured with a set of Virtual IPs (VIP, which can be -prefixes), and for each VIP, with a set of Application Server addresses (ASs). - -Traffic received for a given VIP (or VIP prefix) is tunneled using GRE towards -the different ASs in a way that (tries to) ensure that a given session will -always be tunneled to the same AS. - -Both VIPs or ASs can be IPv4 or IPv6, but for a given VIP, all ASs must be using -the same encap. type (i.e. IPv4+GRE or IPv6+GRE). Meaning that for a given VIP, -all AS addresses must be of the same family. - -## Performances - -The load balancer has been tested up to 1 millions flows and still forwards more -than 3Mpps per core in such circumstances. -Although 3Mpps seems already good, it is likely that performances will be improved -in next versions. - -## Configuration - -### Global LB parameters - -The load balancer needs to be configured with some parameters: - - lb conf [ip4-src-address ] [ip6-src-address ] - [buckets ] [timeout ] - -ip4-src-address: the source address used to send encap. packets using IPv4. - -ip6-src-address: the source address used to send encap. packets using IPv6. - -buckets: the *per-thread* established-connexions-table number of buckets. - -timeout: the number of seconds a connection will remain in the - established-connexions-table while no packet for this flow - is received. - - -### Configure the VIPs - - lb vip [encap (gre6|gre4)] [new_len ] [del] - -new_len is the size of the new-connection-table. It should be 1 or 2 orders of -magnitude bigger than the number of ASs for the VIP in order to ensure a good -load balancing. - -Examples: - - lb vip 2002::/16 encap gre6 new_len 1024 - lb vip 2003::/16 encap gre4 new_len 2048 - lb vip 80.0.0.0/8 encap gre6 new_len 16 - lb vip 90.0.0.0/8 encap gre4 new_len 1024 - -### Configure the ASs (for each VIP) - - lb as [
[
[...]]] [del] - -You can add (or delete) as many ASs at a time (for a single VIP). -Note that the AS address family must correspond to the VIP encap. IP family. - -Examples: - - lb as 2002::/16 2001::2 2001::3 2001::4 - lb as 2003::/16 10.0.0.1 10.0.0.2 - lb as 80.0.0.0/8 2001::2 - lb as 90.0.0.0/8 10.0.0.1 - - - -## Monitoring - -The plugin provides quite a bunch of counters and information. -These are still subject to quite significant changes. - - show lb - show lb vip - show lb vip verbose - - show node counters - - -## Design notes - -### Multi-Threading - -MagLev is a distributed system which pseudo-randomly generates a -new-connections-table based on AS names such that each server configured with -the same set of ASs ends up with the same table. Connection stickyness is then -ensured with an established-connections-table. Using ECMP, it is assumed (but -not relied on) that servers will mostly receive traffic for different flows. - -This implementation pushes the parallelism a little bit further by using -one established-connections table per thread. This is equivalent to assuming -that RSS will make a job similar to ECMP, and is pretty useful as threads don't -need to get a lock in order to write in the table. - -### Hash Table - -A load balancer requires an efficient read and write hash table. The hash table -used by ip6-forward is very read-efficient, but not so much for writing. In -addition, it is not a big deal if writing into the hash table fails (again, -MagLev uses a flow table but does not heaviliy relies on it). - -The plugin therefore uses a very specific (and stupid) hash table. - - Fixed (and power of 2) number of buckets (configured at runtime) - - Fixed (and power of 2) elements per buckets (configured at compilation time) - -### Reference counting - -When an AS is removed, there is two possible ways to react. - - Keep using the AS for established connections - - Change AS for established connections (likely to cause error for TCP) - -In the first case, although an AS is removed from the configuration, its -associated state needs to stay around as long as it is used by at least one -thread. - -In order to avoid locks, a specific reference counter is used. The design is quite -similar to clib counters but: - - It is possible to decrease the value - - Summing will not zero the per-thread counters - - Only the thread can reallocate its own counters vector (to avoid concurrency issues) - -This reference counter is lock free, but reading a count of 0 does not mean -the value can be freed unless it is ensured by *other* means that no other thread -is concurrently referencing the object. In the case of this plugin, it is assumed -that no concurrent event will take place after a few seconds. - diff --git a/plugins/sample-plugin/Makefile.am b/plugins/sample-plugin/Makefile.am deleted file mode 100644 index e221f8c1..00000000 --- a/plugins/sample-plugin/Makefile.am +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright (c) 2015 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -AUTOMAKE_OPTIONS = foreign subdir-objects - -AM_CFLAGS = -Wall -AM_LDFLAGS = -module -shared -avoid-version - -vppapitestpluginsdir = ${libdir}/vpp_api_test_plugins -vpppluginsdir = ${libdir}/vpp_plugins - -vppapitestplugins_LTLIBRARIES = sample_test_plugin.la -vppplugins_LTLIBRARIES = sample_plugin.la - -sample_plugin_la_SOURCES = sample/sample.c sample/node.c \ - sample/sample_plugin.api.h - -BUILT_SOURCES = sample/sample.api.h sample/sample.api.json - -SUFFIXES = .api.h .api - -%.api.h: %.api - mkdir -p `dirname $@` ; \ - $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ - | vppapigen --input - --output $@ --show-name $@ - -%.api.json: %.api - @echo " JSON APIGEN " $@ ; \ - mkdir -p `dirname $@` ; \ - $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ - | vppapigen --input - --json $@ - -apidir = $(prefix)/sample/ -api_DATA = sample.api.json - -noinst_HEADERS = \ - sample/sample_all_api_h.h \ - sample/sample_msg_enum.h \ - sample/sample.api.h - -sample_test_plugin_la_SOURCES = sample/sample_test.c sample/sample_plugin.api.h - -# Remove *.la files -install-data-hook: - @(cd $(vpppluginsdir) && $(RM) $(vppplugins_LTLIBRARIES)) - @(cd $(vppapitestpluginsdir) && $(RM) $(vppapitestplugins_LTLIBRARIES)) diff --git a/plugins/sample-plugin/configure.ac b/plugins/sample-plugin/configure.ac deleted file mode 100644 index 43642732..00000000 --- a/plugins/sample-plugin/configure.ac +++ /dev/null @@ -1,9 +0,0 @@ -AC_INIT(sample_plugin, 1.0) -LT_INIT -AM_INIT_AUTOMAKE -AM_SILENT_RULES([yes]) -AC_PREFIX_DEFAULT([/usr]) - -AC_PROG_CC - -AC_OUTPUT([Makefile]) diff --git a/plugins/sample-plugin/sample/node.c b/plugins/sample-plugin/sample/node.c deleted file mode 100644 index 94c1706b..00000000 --- a/plugins/sample-plugin/sample/node.c +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include - -typedef struct { - u32 next_index; - u32 sw_if_index; - u8 new_src_mac[6]; - u8 new_dst_mac[6]; -} sample_trace_t; - -static u8 * -format_mac_address (u8 * s, va_list * args) -{ - u8 *a = va_arg (*args, u8 *); - return format (s, "%02x:%02x:%02x:%02x:%02x:%02x", - a[0], a[1], a[2], a[3], a[4], a[5]); -} - -/* packet trace format function */ -static u8 * format_sample_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - sample_trace_t * t = va_arg (*args, sample_trace_t *); - - s = format (s, "SAMPLE: sw_if_index %d, next index %d\n", - t->sw_if_index, t->next_index); - s = format (s, " new src %U -> new dst %U", - format_mac_address, t->new_src_mac, - format_mac_address, t->new_dst_mac); - - return s; -} - -vlib_node_registration_t sample_node; - -#define foreach_sample_error \ -_(SWAPPED, "Mac swap packets processed") - -typedef enum { -#define _(sym,str) SAMPLE_ERROR_##sym, - foreach_sample_error -#undef _ - SAMPLE_N_ERROR, -} sample_error_t; - -static char * sample_error_strings[] = { -#define _(sym,string) string, - foreach_sample_error -#undef _ -}; - -typedef enum { - SAMPLE_NEXT_INTERFACE_OUTPUT, - SAMPLE_N_NEXT, -} sample_next_t; - -#define foreach_mac_address_offset \ -_(0) \ -_(1) \ -_(2) \ -_(3) \ -_(4) \ -_(5) - -static uword -sample_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - u32 n_left_from, * from, * to_next; - sample_next_t next_index; - u32 pkts_swapped = 0; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, - to_next, n_left_to_next); - - while (n_left_from >= 4 && n_left_to_next >= 2) - { - u32 next0 = SAMPLE_NEXT_INTERFACE_OUTPUT; - u32 next1 = SAMPLE_NEXT_INTERFACE_OUTPUT; - u32 sw_if_index0, sw_if_index1; - u8 tmp0[6], tmp1[6]; - ethernet_header_t *en0, *en1; - u32 bi0, bi1; - vlib_buffer_t * b0, * b1; - - /* Prefetch next iteration. */ - { - vlib_buffer_t * p2, * p3; - - p2 = vlib_get_buffer (vm, from[2]); - p3 = vlib_get_buffer (vm, from[3]); - - vlib_prefetch_buffer_header (p2, LOAD); - vlib_prefetch_buffer_header (p3, LOAD); - - CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE); - CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE); - } - - /* speculatively enqueue b0 and b1 to the current next frame */ - to_next[0] = bi0 = from[0]; - to_next[1] = bi1 = from[1]; - from += 2; - to_next += 2; - n_left_from -= 2; - n_left_to_next -= 2; - - b0 = vlib_get_buffer (vm, bi0); - b1 = vlib_get_buffer (vm, bi1); - - ASSERT (b0->current_data == 0); - ASSERT (b1->current_data == 0); - - en0 = vlib_buffer_get_current (b0); - en1 = vlib_buffer_get_current (b1); - - /* This is not the fastest way to swap src + dst mac addresses */ -#define _(a) tmp0[a] = en0->src_address[a]; - foreach_mac_address_offset; -#undef _ -#define _(a) en0->src_address[a] = en0->dst_address[a]; - foreach_mac_address_offset; -#undef _ -#define _(a) en0->dst_address[a] = tmp0[a]; - foreach_mac_address_offset; -#undef _ - -#define _(a) tmp1[a] = en1->src_address[a]; - foreach_mac_address_offset; -#undef _ -#define _(a) en1->src_address[a] = en1->dst_address[a]; - foreach_mac_address_offset; -#undef _ -#define _(a) en1->dst_address[a] = tmp1[a]; - foreach_mac_address_offset; -#undef _ - - - - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX]; - - /* Send pkt back out the RX interface */ - vnet_buffer(b0)->sw_if_index[VLIB_TX] = sw_if_index0; - vnet_buffer(b1)->sw_if_index[VLIB_TX] = sw_if_index1; - - pkts_swapped += 2; - - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE))) - { - if (b0->flags & VLIB_BUFFER_IS_TRACED) - { - sample_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - t->next_index = next0; - clib_memcpy (t->new_src_mac, en0->src_address, - sizeof (t->new_src_mac)); - clib_memcpy (t->new_dst_mac, en0->dst_address, - sizeof (t->new_dst_mac)); - - } - if (b1->flags & VLIB_BUFFER_IS_TRACED) - { - sample_trace_t *t = - vlib_add_trace (vm, node, b1, sizeof (*t)); - t->sw_if_index = sw_if_index1; - t->next_index = next1; - clib_memcpy (t->new_src_mac, en1->src_address, - sizeof (t->new_src_mac)); - clib_memcpy (t->new_dst_mac, en1->dst_address, - sizeof (t->new_dst_mac)); - } - } - - /* verify speculative enqueues, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x2 (vm, node, next_index, - to_next, n_left_to_next, - bi0, bi1, next0, next1); - } - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t * b0; - u32 next0 = SAMPLE_NEXT_INTERFACE_OUTPUT; - u32 sw_if_index0; - u8 tmp0[6]; - ethernet_header_t *en0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - /* - * Direct from the driver, we should be at offset 0 - * aka at &b0->data[0] - */ - ASSERT (b0->current_data == 0); - - en0 = vlib_buffer_get_current (b0); - - /* This is not the fastest way to swap src + dst mac addresses */ -#define _(a) tmp0[a] = en0->src_address[a]; - foreach_mac_address_offset; -#undef _ -#define _(a) en0->src_address[a] = en0->dst_address[a]; - foreach_mac_address_offset; -#undef _ -#define _(a) en0->dst_address[a] = tmp0[a]; - foreach_mac_address_offset; -#undef _ - - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - - /* Send pkt back out the RX interface */ - vnet_buffer(b0)->sw_if_index[VLIB_TX] = sw_if_index0; - - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) { - sample_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - t->next_index = next0; - clib_memcpy (t->new_src_mac, en0->src_address, - sizeof (t->new_src_mac)); - clib_memcpy (t->new_dst_mac, en0->dst_address, - sizeof (t->new_dst_mac)); - } - - pkts_swapped += 1; - - /* verify speculative enqueue, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, n_left_to_next, - bi0, next0); - } - - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - vlib_node_increment_counter (vm, sample_node.index, - SAMPLE_ERROR_SWAPPED, pkts_swapped); - return frame->n_vectors; -} - -VLIB_REGISTER_NODE (sample_node) = { - .function = sample_node_fn, - .name = "sample", - .vector_size = sizeof (u32), - .format_trace = format_sample_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(sample_error_strings), - .error_strings = sample_error_strings, - - .n_next_nodes = SAMPLE_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [SAMPLE_NEXT_INTERFACE_OUTPUT] = "interface-output", - }, -}; diff --git a/plugins/sample-plugin/sample/sample.api b/plugins/sample-plugin/sample/sample.api deleted file mode 100644 index f99cdb38..00000000 --- a/plugins/sample-plugin/sample/sample.api +++ /dev/null @@ -1,39 +0,0 @@ -/* Hey Emacs use -*- mode: C -*- */ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* Define a simple binary API to control the feature */ - -define sample_macswap_enable_disable { - /* Client identifier, set from api_main.my_client_index */ - u32 client_index; - - /* Arbitrary context, so client can match reply to request */ - u32 context; - - /* Enable / disable the feature */ - u8 enable_disable; - - /* Interface handle */ - u32 sw_if_index; -}; - -define sample_macswap_enable_disable_reply { - /* From the request */ - u32 context; - - /* Return value, zero means all OK */ - i32 retval; -}; diff --git a/plugins/sample-plugin/sample/sample.c b/plugins/sample-plugin/sample/sample.c deleted file mode 100644 index 603cb2d0..00000000 --- a/plugins/sample-plugin/sample/sample.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - *------------------------------------------------------------------ - * sample.c - simple MAC-swap API / debug CLI handling - *------------------------------------------------------------------ - */ - -#include -#include -#include - -#include -#include -#include - -/* define message IDs */ -#include - -/* define message structures */ -#define vl_typedefs -#include -#undef vl_typedefs - -/* define generated endian-swappers */ -#define vl_endianfun -#include -#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 -#undef vl_printfun - -/* Get the API version number */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#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_sample_plugin_api_msg \ -_(SAMPLE_MACSWAP_ENABLE_DISABLE, sample_macswap_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) -{ - sample_main_t * sm = &sample_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 sample_macswap_enable_disable (sample_main_t * sm, u32 sw_if_index, - int enable_disable) -{ - vnet_sw_interface_t * sw; - int rv = 0; - - /* Utterly wrong? */ - if (pool_is_free_index (sm->vnet_main->interface_main.sw_interfaces, - sw_if_index)) - return VNET_API_ERROR_INVALID_SW_IF_INDEX; - - /* Not a physical port? */ - sw = vnet_get_sw_interface (sm->vnet_main, sw_if_index); - if (sw->type != VNET_SW_INTERFACE_TYPE_HARDWARE) - return VNET_API_ERROR_INVALID_SW_IF_INDEX; - - vnet_feature_enable_disable ("device-input", "sample", - sw_if_index, enable_disable, 0, 0); - - return rv; -} - -static clib_error_t * -macswap_enable_disable_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - sample_main_t * sm = &sample_main; - u32 sw_if_index = ~0; - int enable_disable = 1; - - int rv; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { - if (unformat (input, "disable")) - enable_disable = 0; - else if (unformat (input, "%U", unformat_vnet_sw_interface, - sm->vnet_main, &sw_if_index)) - ; - else - break; - } - - if (sw_if_index == ~0) - return clib_error_return (0, "Please specify an interface..."); - - rv = sample_macswap_enable_disable (sm, sw_if_index, enable_disable); - - switch(rv) { - case 0: - break; - - case VNET_API_ERROR_INVALID_SW_IF_INDEX: - return clib_error_return - (0, "Invalid interface, only works on physical ports"); - break; - - case VNET_API_ERROR_UNIMPLEMENTED: - return clib_error_return (0, "Device driver doesn't support redirection"); - break; - - default: - return clib_error_return (0, "sample_macswap_enable_disable returned %d", - rv); - } - return 0; -} - -VLIB_CLI_COMMAND (sr_content_command, static) = { - .path = "sample macswap", - .short_help = - "sample macswap [disable]", - .function = macswap_enable_disable_command_fn, -}; - -/* API message handler */ -static void vl_api_sample_macswap_enable_disable_t_handler -(vl_api_sample_macswap_enable_disable_t * mp) -{ - vl_api_sample_macswap_enable_disable_reply_t * rmp; - sample_main_t * sm = &sample_main; - int rv; - - rv = sample_macswap_enable_disable (sm, ntohl(mp->sw_if_index), - (int) (mp->enable_disable)); - - REPLY_MACRO(VL_API_SAMPLE_MACSWAP_ENABLE_DISABLE_REPLY); -} - -/* Set up the API message handling tables */ -static clib_error_t * -sample_plugin_api_hookup (vlib_main_t *vm) -{ - sample_main_t * sm = &sample_main; -#define _(N,n) \ - vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base), \ - #n, \ - vl_api_##n##_t_handler, \ - vl_noop_handler, \ - vl_api_##n##_t_endian, \ - vl_api_##n##_t_print, \ - sizeof(vl_api_##n##_t), 1); - foreach_sample_plugin_api_msg; -#undef _ - - return 0; -} - -#define vl_msg_name_crc_list -#include -#undef vl_msg_name_crc_list - -static void -setup_message_id_table (sample_main_t * sm, api_main_t *am) -{ -#define _(id,n,crc) \ - vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base); - foreach_vl_msg_name_crc_sample; -#undef _ -} - -static clib_error_t * sample_init (vlib_main_t * vm) -{ - sample_main_t * sm = &sample_main; - clib_error_t * error = 0; - u8 * name; - - name = format (0, "sample_%08x%c", api_version, 0); - - /* Ask for a correctly-sized block of API message decode slots */ - sm->msg_id_base = vl_msg_api_get_msg_ids - ((char *) name, VL_MSG_FIRST_AVAILABLE); - - error = sample_plugin_api_hookup (vm); - - /* Add our API messages to the global name_crc hash table */ - setup_message_id_table (sm, &api_main); - - vec_free(name); - - return error; -} - -VLIB_INIT_FUNCTION (sample_init); - -VNET_FEATURE_INIT (sample, static) = -{ - .arc_name = "device-input", - .node_name = "sample", - .runs_before = VNET_FEATURES ("ethernet-input"), -}; diff --git a/plugins/sample-plugin/sample/sample.h b/plugins/sample-plugin/sample/sample.h deleted file mode 100644 index d268d482..00000000 --- a/plugins/sample-plugin/sample/sample.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __included_sample_h__ -#define __included_sample_h__ - -#include -#include -#include - -#include -#include -#include - -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; -} sample_main_t; - -sample_main_t sample_main; - -vlib_node_registration_t sample_node; - -#endif /* __included_sample_h__ */ diff --git a/plugins/sample-plugin/sample/sample_all_api_h.h b/plugins/sample-plugin/sample/sample_all_api_h.h deleted file mode 100644 index 774d782f..00000000 --- a/plugins/sample-plugin/sample/sample_all_api_h.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* Include the generated file, see BUILT_SOURCES in Makefile.am */ -#include diff --git a/plugins/sample-plugin/sample/sample_msg_enum.h b/plugins/sample-plugin/sample/sample_msg_enum.h deleted file mode 100644 index af4172f7..00000000 --- a/plugins/sample-plugin/sample/sample_msg_enum.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef included_sample_msg_enum_h -#define included_sample_msg_enum_h - -#include - -#define vl_msg_id(n,h) n, -typedef enum { -#include - /* We'll want to know how many messages IDs we need... */ - VL_MSG_FIRST_AVAILABLE, -} vl_msg_id_t; -#undef vl_msg_id - -#endif /* included_sample_msg_enum_h */ diff --git a/plugins/sample-plugin/sample/sample_test.c b/plugins/sample-plugin/sample/sample_test.c deleted file mode 100644 index dd1b0215..00000000 --- a/plugins/sample-plugin/sample/sample_test.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - *------------------------------------------------------------------ - * sample_test.c - test harness plugin - *------------------------------------------------------------------ - */ - -#include -#include -#include -#include -#include - -uword unformat_sw_if_index (unformat_input_t * input, va_list * args); - -/* Declare message IDs */ -#include - -/* define message structures */ -#define vl_typedefs -#include -#undef vl_typedefs - -/* declare message handlers for each api */ - -#define vl_endianfun /* define message structures */ -#include -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) -#define vl_printfun -#include -#undef vl_printfun - -/* Get the API version number. */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#undef vl_api_version - - -typedef struct { - /* API message ID base */ - u16 msg_id_base; - vat_main_t *vat_main; -} sample_test_main_t; - -sample_test_main_t sample_test_main; - -#define foreach_standard_reply_retval_handler \ -_(sample_macswap_enable_disable_reply) - -#define _(n) \ - static void vl_api_##n##_t_handler \ - (vl_api_##n##_t * mp) \ - { \ - vat_main_t * vam = sample_test_main.vat_main; \ - i32 retval = ntohl(mp->retval); \ - if (vam->async_mode) { \ - vam->async_errors += (retval < 0); \ - } else { \ - vam->retval = retval; \ - vam->result_ready = 1; \ - } \ - } -foreach_standard_reply_retval_handler; -#undef _ - -/* - * Table of message reply handlers, must include boilerplate handlers - * we just generated - */ -#define foreach_vpe_api_reply_msg \ -_(SAMPLE_MACSWAP_ENABLE_DISABLE_REPLY, sample_macswap_enable_disable_reply) - - -/* 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_sample_macswap_enable_disable (vat_main_t * vam) -{ - sample_test_main_t * sm = &sample_test_main; - unformat_input_t * i = vam->input; - f64 timeout; - int enable_disable = 1; - u32 sw_if_index = ~0; - vl_api_sample_macswap_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(SAMPLE_MACSWAP_ENABLE_DISABLE, sample_macswap_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 \ -_(sample_macswap_enable_disable, " [disable]") - -void vat_api_hookup (vat_main_t *vam) -{ - sample_test_main_t * sm = &sample_test_main; - /* Hook up handlers for replies from the data plane plug-in */ -#define _(N,n) \ - vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base), \ - #n, \ - vl_api_##n##_t_handler, \ - vl_noop_handler, \ - vl_api_##n##_t_endian, \ - vl_api_##n##_t_print, \ - sizeof(vl_api_##n##_t), 1); - foreach_vpe_api_reply_msg; -#undef _ - - /* API messages we can send */ -#define _(n,h) hash_set_mem (vam->function_by_name, #n, api_##n); - foreach_vpe_api_msg; -#undef _ - - /* Help strings */ -#define _(n,h) hash_set_mem (vam->help_by_name, #n, h); - foreach_vpe_api_msg; -#undef _ -} - -clib_error_t * vat_plugin_register (vat_main_t *vam) -{ - sample_test_main_t * sm = &sample_test_main; - u8 * name; - - sm->vat_main = vam; - - name = format (0, "sample_%08x%c", api_version, 0); - sm->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name); - - if (sm->msg_id_base != (u16) ~0) - vat_api_hookup (vam); - - vec_free(name); - - return 0; -} diff --git a/plugins/snat-plugin/Makefile.am b/plugins/snat-plugin/Makefile.am deleted file mode 100644 index e1922eb0..00000000 --- a/plugins/snat-plugin/Makefile.am +++ /dev/null @@ -1,113 +0,0 @@ - -# Copyright (c) -# 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 @DPDK@ -AM_LDFLAGS = -module -shared -avoid-version - -vppapitestpluginsdir = ${libdir}/vpp_api_test_plugins -vpppluginsdir = ${libdir}/vpp_plugins - -vppapitestplugins_LTLIBRARIES = snat_test_plugin.la -vppplugins_LTLIBRARIES = snat_plugin.la - -snat_plugin_la_SOURCES = snat/snat.c \ - snat/in2out.c \ - snat/out2in.c \ - snat/snat_plugin.api.h - -BUILT_SOURCES = snat/snat.api.h snat/snat.api.json - -SUFFIXES = .api.h .api - -%.api.h: %.api - mkdir -p `dirname $@` ; \ - $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ - | vppapigen --input - --output $@ --show-name $@ - -%.api.json: %.api - @echo " JSON APIGEN " $@ ; \ - mkdir -p `dirname $@` ; \ - $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ - | vppapigen --input - --json $@ - -apidir = $(prefix)/snat/ -api_DATA = snat.api.json - -noinst_HEADERS = \ - snat/snat_all_api_h.h \ - snat/snat_msg_enum.h \ - snat/snat.api.h - -snat_test_plugin_la_SOURCES = \ - snat/snat_test.c snat/snat_plugin.api.h - -# Remove *.la files -install-data-hook: - @(cd $(vpppluginsdir) && $(RM) $(vppplugins_LTLIBRARIES)) - @(cd $(vppapitestpluginsdir) && $(RM) $(vppapitestplugins_LTLIBRARIES)) - -# -# Java code generation -# -jvpp_registry_root = ../../vpp-api/java -jvpp_registry_version = 17.04 -jsnat_jarfile = jvpp-snat-$(PACKAGE_VERSION).jar -jvpp_package_dir = io/fd/vpp/jvpp/snat -jvpp_root = snat/jvpp -jvpp_target_dir = target -jvpp_target = $(jvpp_root)/$(jvpp_target_dir) -api_file=$(srcdir)/snat/snat.api - -lib_LTLIBRARIES = libjvpp_snat.la -libjvpp_snat_la_SOURCES = snat/snat.api.h snat/jvpp_snat.c snat/jvpp/io_fd_vpp_jvpp_snat_JVppSnatImpl.h -libjvpp_snat_la_LIBADD = -lvlibmemoryclient -lvlibapi -lvppinfra \ - -lpthread -lm -lrt -L$(jvpp_registry_root)/.libs -ljvpp_common -libjvpp_snat_la_LDFLAGS = -module -libjvpp_snat_la_CPPFLAGS = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -I../ -I$(srcdir)/../ - -BUILT_SOURCES += $(jvpp_root)/io_fd_vpp_jvpp_snat_JVppSnatImpl.h - -$(jvpp_root)/io_fd_vpp_jvpp_snat_JVppSnatImpl.h: snat.api.json - dir=`pwd`; \ - mkdir -p $(jvpp_target); \ - mkdir -p $(jvpp_root)/$(jvpp_package_dir); \ - cd $(jvpp_root)/$(jvpp_package_dir); \ - mkdir -p dto future callfacade callback notification test; \ - @srcdir@/$(jvpp_registry_root)/jvpp/gen/jvpp_gen.py -i $${dir}/snat.api.json --plugin_name snat; \ - cd -; \ - mv -f $(jvpp_root)/$(jvpp_package_dir)/jvpp_snat_gen.h $(jvpp_root)/jvpp_snat_gen.h; \ - cp $(srcdir)/$(jvpp_root)/$(jvpp_package_dir)/test/*.java $(jvpp_root)/$(jvpp_package_dir)/test/; \ - cd $(jvpp_root); \ - $(JAVAC) -classpath .:$(jvpp_target_dir):../../$(jvpp_registry_root)/jvpp-registry-$(jvpp_registry_version).jar -d $(jvpp_target_dir) $(jvpp_package_dir)/*.java \ - $(jvpp_package_dir)/dto/*.java \ - $(jvpp_package_dir)/callback/*.java \ - $(jvpp_package_dir)/notification/*.java \ - $(jvpp_package_dir)/future/*.java \ - $(jvpp_package_dir)/callfacade/*.java \ - $(jvpp_package_dir)/test/*.java \ - || (echo "snat jvpp compilation failed: $$?"; exit 1); \ - $(JAVAH) -classpath .:$(jvpp_target_dir):../../$(jvpp_registry_root)/jvpp-registry-$(jvpp_registry_version).jar -d . io.fd.vpp.jvpp.snat.JVppSnatImpl ; - -$(jsnat_jarfile): libjvpp_snat.la - cp .libs/libjvpp_snat.so.0.0.0 $(jvpp_target); \ - cd $(jvpp_target); \ - $(JAR) cfv $(JARFLAGS) ../../../$@ libjvpp_snat.so.0.0.0 $(jvpp_package_dir)/* ; cd ..; - -snat.api.json: - @echo " jSnat_sfc API"; \ - vppapigen --input $(api_file) --json snat.api.json; - -all-local: $(jsnat_jarfile) diff --git a/plugins/snat-plugin/configure.ac b/plugins/snat-plugin/configure.ac deleted file mode 100644 index 011246cd..00000000 --- a/plugins/snat-plugin/configure.ac +++ /dev/null @@ -1,32 +0,0 @@ -AC_INIT(snat_plugin, 1.0) -AC_CONFIG_MACRO_DIR([../../vpp-api/java/m4]) -AM_INIT_AUTOMAKE -AM_SILENT_RULES([yes]) -AC_PREFIX_DEFAULT([/usr]) - -AC_PROG_LIBTOOL -AC_PROG_CC - -if test -f /usr/bin/lsb_release && test `lsb_release -si` == "Ubuntu" && test `lsb_release -sr` == "14.04" && test -d /usr/lib/jvm/java-8-openjdk-amd64/ ; then - JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/ - JAVAC=${JAVA_HOME}/bin/javac - PATH=${JAVA_HOME}/bin/:${PATH} - break -fi - -AX_CHECK_JAVA_HOME -AX_PROG_JAVAC -AX_PROG_JAVAH -AX_PROG_JAR -AX_PROG_JAVADOC -AX_PROG_JAVA - -AC_ARG_WITH(dpdk, - AC_HELP_STRING([--with-dpdk],[Use DPDK]), - [with_dpdk=1], - [with_dpdk=0]) - -AM_CONDITIONAL(WITH_DPDK, test "$with_dpdk" = "1") -AC_SUBST(DPDK,["-DDPDK=${with_dpdk}"]) - -AC_OUTPUT([Makefile]) diff --git a/plugins/snat-plugin/snat/in2out.c b/plugins/snat-plugin/snat/in2out.c deleted file mode 100644 index c78fdd76..00000000 --- a/plugins/snat-plugin/snat/in2out.c +++ /dev/null @@ -1,1597 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -typedef struct { - u32 sw_if_index; - u32 next_index; - u32 session_index; - u32 is_slow_path; -} snat_in2out_trace_t; - -typedef struct { - u32 next_worker_index; - u8 do_handoff; -} snat_in2out_worker_handoff_trace_t; - -/* packet trace format function */ -static u8 * format_snat_in2out_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 *); - snat_in2out_trace_t * t = va_arg (*args, snat_in2out_trace_t *); - char * tag; - - tag = t->is_slow_path ? "SNAT_IN2OUT_SLOW_PATH" : "SNAT_IN2OUT_FAST_PATH"; - - s = format (s, "%s: sw_if_index %d, next index %d, session %d", tag, - t->sw_if_index, t->next_index, t->session_index); - - return s; -} - -static u8 * format_snat_in2out_fast_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 *); - snat_in2out_trace_t * t = va_arg (*args, snat_in2out_trace_t *); - - s = format (s, "SANT_IN2OUT_FAST: sw_if_index %d, next index %d", - t->sw_if_index, t->next_index); - - return s; -} - -static u8 * format_snat_in2out_worker_handoff_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 *); - snat_in2out_worker_handoff_trace_t * t = - va_arg (*args, snat_in2out_worker_handoff_trace_t *); - char * m; - - m = t->do_handoff ? "next worker" : "same worker"; - s = format (s, "SNAT_IN2OUT_WORKER_HANDOFF: %s %d", m, t->next_worker_index); - - return s; -} - -vlib_node_registration_t snat_in2out_node; -vlib_node_registration_t snat_in2out_slowpath_node; -vlib_node_registration_t snat_in2out_fast_node; -vlib_node_registration_t snat_in2out_worker_handoff_node; - -#define foreach_snat_in2out_error \ -_(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \ -_(IN2OUT_PACKETS, "Good in2out packets processed") \ -_(OUT_OF_PORTS, "Out of ports") \ -_(BAD_OUTSIDE_FIB, "Outside VRF ID not found") \ -_(BAD_ICMP_TYPE, "icmp type not echo-request") \ -_(NO_TRANSLATION, "No translation") - -typedef enum { -#define _(sym,str) SNAT_IN2OUT_ERROR_##sym, - foreach_snat_in2out_error -#undef _ - SNAT_IN2OUT_N_ERROR, -} snat_in2out_error_t; - -static char * snat_in2out_error_strings[] = { -#define _(sym,string) string, - foreach_snat_in2out_error -#undef _ -}; - -typedef enum { - SNAT_IN2OUT_NEXT_LOOKUP, - SNAT_IN2OUT_NEXT_DROP, - SNAT_IN2OUT_NEXT_SLOW_PATH, - SNAT_IN2OUT_N_NEXT, -} snat_in2out_next_t; - -static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, - ip4_header_t * ip0, - u32 rx_fib_index0, - snat_session_key_t * key0, - snat_session_t ** sessionp, - vlib_node_runtime_t * node, - u32 next0, - u32 cpu_index) -{ - snat_user_t *u; - snat_user_key_t user_key; - snat_session_t *s; - clib_bihash_kv_8_8_t kv0, value0; - u32 oldest_per_user_translation_list_index; - dlist_elt_t * oldest_per_user_translation_list_elt; - dlist_elt_t * per_user_translation_list_elt; - dlist_elt_t * per_user_list_head_elt; - u32 session_index; - snat_session_key_t key1; - u32 address_index = ~0; - u32 outside_fib_index; - uword * p; - snat_static_mapping_key_t worker_by_out_key; - - p = hash_get (sm->ip4_main->fib_index_by_table_id, sm->outside_vrf_id); - if (! p) - { - b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_OUTSIDE_FIB]; - return SNAT_IN2OUT_NEXT_DROP; - } - outside_fib_index = p[0]; - - user_key.addr = ip0->src_address; - user_key.fib_index = rx_fib_index0; - kv0.key = user_key.as_u64; - - /* Ever heard of the "user" = src ip4 address before? */ - if (clib_bihash_search_8_8 (&sm->user_hash, &kv0, &value0)) - { - /* no, make a new one */ - pool_get (sm->per_thread_data[cpu_index].users, u); - memset (u, 0, sizeof (*u)); - u->addr = ip0->src_address; - - pool_get (sm->per_thread_data[cpu_index].list_pool, per_user_list_head_elt); - - u->sessions_per_user_list_head_index = per_user_list_head_elt - - sm->per_thread_data[cpu_index].list_pool; - - clib_dlist_init (sm->per_thread_data[cpu_index].list_pool, - u->sessions_per_user_list_head_index); - - kv0.value = u - sm->per_thread_data[cpu_index].users; - - /* add user */ - clib_bihash_add_del_8_8 (&sm->user_hash, &kv0, 1 /* is_add */); - } - else - { - u = pool_elt_at_index (sm->per_thread_data[cpu_index].users, - value0.value); - } - - /* Over quota? Recycle the least recently used dynamic translation */ - if (u->nsessions >= sm->max_translations_per_user) - { - /* Remove the oldest dynamic translation */ - do { - oldest_per_user_translation_list_index = - clib_dlist_remove_head (sm->per_thread_data[cpu_index].list_pool, - u->sessions_per_user_list_head_index); - - ASSERT (oldest_per_user_translation_list_index != ~0); - - /* add it back to the end of the LRU list */ - clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, - u->sessions_per_user_list_head_index, - oldest_per_user_translation_list_index); - /* Get the list element */ - oldest_per_user_translation_list_elt = - pool_elt_at_index (sm->per_thread_data[cpu_index].list_pool, - oldest_per_user_translation_list_index); - - /* Get the session index from the list element */ - session_index = oldest_per_user_translation_list_elt->value; - - /* Get the session */ - s = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, - session_index); - } while (snat_is_session_static (s)); - - /* Remove in2out, out2in keys */ - kv0.key = s->in2out.as_u64; - if (clib_bihash_add_del_8_8 (&sm->in2out, &kv0, 0 /* is_add */)) - clib_warning ("in2out key delete failed"); - kv0.key = s->out2in.as_u64; - if (clib_bihash_add_del_8_8 (&sm->out2in, &kv0, 0 /* is_add */)) - clib_warning ("out2in key delete failed"); - - snat_free_outside_address_and_port - (sm, &s->out2in, s->outside_address_index); - s->outside_address_index = ~0; - - if (snat_alloc_outside_address_and_port (sm, &key1, &address_index)) - { - ASSERT(0); - - b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS]; - return SNAT_IN2OUT_NEXT_DROP; - } - s->outside_address_index = address_index; - } - else - { - u8 static_mapping = 1; - - /* First try to match static mapping by local address and port */ - if (snat_static_mapping_match (sm, *key0, &key1, 0)) - { - static_mapping = 0; - /* Try to create dynamic translation */ - if (snat_alloc_outside_address_and_port (sm, &key1, &address_index)) - { - b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS]; - return SNAT_IN2OUT_NEXT_DROP; - } - } - - /* Create a new session */ - pool_get (sm->per_thread_data[cpu_index].sessions, s); - memset (s, 0, sizeof (*s)); - - s->outside_address_index = address_index; - - if (static_mapping) - { - u->nstaticsessions++; - s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; - } - else - { - u->nsessions++; - } - - /* Create list elts */ - pool_get (sm->per_thread_data[cpu_index].list_pool, - per_user_translation_list_elt); - clib_dlist_init (sm->per_thread_data[cpu_index].list_pool, - per_user_translation_list_elt - - sm->per_thread_data[cpu_index].list_pool); - - per_user_translation_list_elt->value = - s - sm->per_thread_data[cpu_index].sessions; - s->per_user_index = per_user_translation_list_elt - - sm->per_thread_data[cpu_index].list_pool; - s->per_user_list_head_index = u->sessions_per_user_list_head_index; - - clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, - s->per_user_list_head_index, - per_user_translation_list_elt - - sm->per_thread_data[cpu_index].list_pool); - } - - s->in2out = *key0; - s->out2in = key1; - s->out2in.protocol = key0->protocol; - s->out2in.fib_index = outside_fib_index; - *sessionp = s; - - /* Add to translation hashes */ - kv0.key = s->in2out.as_u64; - kv0.value = s - sm->per_thread_data[cpu_index].sessions; - if (clib_bihash_add_del_8_8 (&sm->in2out, &kv0, 1 /* is_add */)) - clib_warning ("in2out key add failed"); - - kv0.key = s->out2in.as_u64; - kv0.value = s - sm->per_thread_data[cpu_index].sessions; - - if (clib_bihash_add_del_8_8 (&sm->out2in, &kv0, 1 /* is_add */)) - clib_warning ("out2in key add failed"); - - /* Add to translated packets worker lookup */ - worker_by_out_key.addr = s->out2in.addr; - worker_by_out_key.port = s->out2in.port; - worker_by_out_key.fib_index = s->out2in.fib_index; - kv0.key = worker_by_out_key.as_u64; - kv0.value = cpu_index; - clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv0, 1); - return next0; -} - -static inline u32 icmp_in2out_slow_path (snat_main_t *sm, - vlib_buffer_t * b0, - ip4_header_t * ip0, - icmp46_header_t * icmp0, - u32 sw_if_index0, - u32 rx_fib_index0, - vlib_node_runtime_t * node, - u32 next0, - f64 now, - u32 cpu_index) -{ - snat_session_key_t key0; - icmp_echo_header_t *echo0; - clib_bihash_kv_8_8_t kv0, value0; - snat_session_t * s0; - u32 new_addr0, old_addr0; - u16 old_id0, new_id0; - ip_csum_t sum0; - snat_runtime_t * rt = (snat_runtime_t *)node->runtime_data; - - if (PREDICT_FALSE(icmp0->type != ICMP4_echo_request)) - { - b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE]; - return SNAT_IN2OUT_NEXT_DROP; - } - - echo0 = (icmp_echo_header_t *)(icmp0+1); - - key0.addr = ip0->src_address; - key0.port = echo0->identifier; - key0.protocol = SNAT_PROTOCOL_ICMP; - key0.fib_index = rx_fib_index0; - - kv0.key = key0.as_u64; - - if (clib_bihash_search_8_8 (&sm->in2out, &kv0, &value0)) - { - ip4_address_t * first_int_addr; - - if (PREDICT_FALSE(rt->cached_sw_if_index != sw_if_index0)) - { - first_int_addr = - ip4_interface_first_address (sm->ip4_main, sw_if_index0, - 0 /* just want the address */); - rt->cached_sw_if_index = sw_if_index0; - rt->cached_ip4_address = first_int_addr->as_u32; - } - - /* Don't NAT packet aimed at the intfc address */ - if (PREDICT_FALSE(ip0->dst_address.as_u32 == - rt->cached_ip4_address)) - return next0; - - next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0, - &s0, node, next0, cpu_index); - - if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP)) - return next0; - } - else - s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, - value0.value); - - old_addr0 = ip0->src_address.as_u32; - ip0->src_address = s0->out2in.addr; - new_addr0 = ip0->src_address.as_u32; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - src_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - old_id0 = echo0->identifier; - new_id0 = s0->out2in.port; - echo0->identifier = new_id0; - - sum0 = icmp0->checksum; - sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t, - identifier); - icmp0->checksum = ip_csum_fold (sum0); - - /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (sm->vlib_main, b0); - /* Per-user LRU list maintenance for dynamic translations */ - if (!snat_is_session_static (s0)) - { - clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, - s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, - s0->per_user_list_head_index, - s0->per_user_index); - } - - return next0; -} - -/** - * @brief Hairpinning - * - * Hairpinning allows two endpoints on the internal side of the NAT to - * communicate even if they only use each other's external IP addresses - * and ports. - * - * @param sm SNAT main. - * @param b0 Vlib buffer. - * @param ip0 IP header. - * @param udp0 UDP header. - * @param tcp0 TCP header. - * @param proto0 SNAT protocol. - */ -static inline void -snat_hairpinning (snat_main_t *sm, - vlib_buffer_t * b0, - ip4_header_t * ip0, - udp_header_t * udp0, - tcp_header_t * tcp0, - u32 proto0) -{ - snat_session_key_t key0, sm0; - snat_static_mapping_key_t k0; - snat_session_t * s0; - clib_bihash_kv_8_8_t kv0, value0; - ip_csum_t sum0; - u32 new_dst_addr0 = 0, old_dst_addr0, ti = 0, si; - u16 new_dst_port0, old_dst_port0; - - key0.addr = ip0->dst_address; - key0.port = udp0->dst_port; - key0.protocol = proto0; - key0.fib_index = sm->outside_fib_index; - kv0.key = key0.as_u64; - - /* Check if destination is in active sessions */ - if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0)) - { - /* or static mappings */ - if (!snat_static_mapping_match(sm, key0, &sm0, 1)) - { - new_dst_addr0 = sm0.addr.as_u32; - new_dst_port0 = sm0.port; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index; - } - } - else - { - si = value0.value; - if (sm->num_workers > 1) - { - k0.addr = ip0->dst_address; - k0.port = udp0->dst_port; - k0.fib_index = sm->outside_fib_index; - kv0.key = k0.as_u64; - if (clib_bihash_search_8_8 (&sm->worker_by_out, &kv0, &value0)) - ASSERT(0); - else - ti = value0.value; - } - else - ti = sm->num_workers; - - s0 = pool_elt_at_index (sm->per_thread_data[ti].sessions, si); - new_dst_addr0 = s0->in2out.addr.as_u32; - new_dst_port0 = s0->in2out.port; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index; - } - - /* Destination is behind the same NAT, use internal address and port */ - if (new_dst_addr0) - { - old_dst_addr0 = ip0->dst_address.as_u32; - ip0->dst_address.as_u32 = new_dst_addr0; - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0, - ip4_header_t, dst_address); - ip0->checksum = ip_csum_fold (sum0); - - old_dst_port0 = tcp0->ports.dst; - if (PREDICT_TRUE(new_dst_port0 != old_dst_port0)) - { - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - tcp0->ports.dst = new_dst_port0; - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0, - ip4_header_t, dst_address); - sum0 = ip_csum_update (sum0, old_dst_port0, new_dst_port0, - ip4_header_t /* cheat */, length); - tcp0->checksum = ip_csum_fold(sum0); - } - else - { - udp0->dst_port = new_dst_port0; - udp0->checksum = 0; - } - } - } -} - -static inline uword -snat_in2out_node_fn_inline (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame, int is_slow_path) -{ - u32 n_left_from, * from, * to_next; - snat_in2out_next_t next_index; - u32 pkts_processed = 0; - snat_main_t * sm = &snat_main; - snat_runtime_t * rt = (snat_runtime_t *)node->runtime_data; - f64 now = vlib_time_now (vm); - u32 stats_node_index; - u32 cpu_index = os_get_cpu_number (); - - stats_node_index = is_slow_path ? snat_in2out_slowpath_node.index : - snat_in2out_node.index; - - 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 bi0, bi1; - vlib_buffer_t * b0, * b1; - u32 next0, next1; - u32 sw_if_index0, sw_if_index1; - ip4_header_t * ip0, * ip1; - ip_csum_t sum0, sum1; - u32 new_addr0, old_addr0, new_addr1, old_addr1; - u16 old_port0, new_port0, old_port1, new_port1; - udp_header_t * udp0, * udp1; - tcp_header_t * tcp0, * tcp1; - icmp46_header_t * icmp0, * icmp1; - snat_session_key_t key0, key1; - u32 rx_fib_index0, rx_fib_index1; - u32 proto0, proto1; - snat_session_t * s0 = 0, * s1 = 0; - clib_bihash_kv_8_8_t kv0, value0, kv1, value1; - - /* 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); - - ip0 = vlib_buffer_get_current (b0); - udp0 = ip4_next_header (ip0); - tcp0 = (tcp_header_t *) udp0; - icmp0 = (icmp46_header_t *) udp0; - - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, - sw_if_index0); - - next0 = next1 = SNAT_IN2OUT_NEXT_LOOKUP; - - proto0 = ~0; - proto0 = (ip0->protocol == IP_PROTOCOL_UDP) - ? SNAT_PROTOCOL_UDP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_TCP) - ? SNAT_PROTOCOL_TCP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_ICMP) - ? SNAT_PROTOCOL_ICMP : proto0; - - /* Next configured feature, probably ip4-lookup */ - if (is_slow_path) - { - if (PREDICT_FALSE (proto0 == ~0)) - goto trace00; - - if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) - { - next0 = icmp_in2out_slow_path - (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, - node, next0, now, cpu_index); - goto trace00; - } - } - else - { - if (PREDICT_FALSE (proto0 == ~0 || proto0 == SNAT_PROTOCOL_ICMP)) - { - next0 = SNAT_IN2OUT_NEXT_SLOW_PATH; - goto trace00; - } - } - - key0.addr = ip0->src_address; - key0.port = udp0->src_port; - key0.protocol = proto0; - key0.fib_index = rx_fib_index0; - - kv0.key = key0.as_u64; - - if (PREDICT_FALSE (clib_bihash_search_8_8 (&sm->in2out, &kv0, &value0) != 0)) - { - if (is_slow_path) - { - ip4_address_t * first_int_addr; - - if (PREDICT_FALSE(rt->cached_sw_if_index != sw_if_index0)) - { - first_int_addr = - ip4_interface_first_address (sm->ip4_main, sw_if_index0, - 0 /* just want the address */); - rt->cached_sw_if_index = sw_if_index0; - rt->cached_ip4_address = first_int_addr->as_u32; - } - - /* Don't NAT packet aimed at the intfc address */ - if (PREDICT_FALSE(ip0->dst_address.as_u32 == - rt->cached_ip4_address)) - goto trace00; - - next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0, - &s0, node, next0, cpu_index); - if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP)) - goto trace00; - } - else - { - next0 = SNAT_IN2OUT_NEXT_SLOW_PATH; - goto trace00; - } - } - else - s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, - value0.value); - - old_addr0 = ip0->src_address.as_u32; - ip0->src_address = s0->out2in.addr; - new_addr0 = ip0->src_address.as_u32; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - src_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - old_port0 = tcp0->ports.src; - tcp0->ports.src = s0->out2in.port; - new_port0 = tcp0->ports.src; - - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - sum0 = ip_csum_update (sum0, old_port0, new_port0, - ip4_header_t /* cheat */, - length /* changed member */); - tcp0->checksum = ip_csum_fold(sum0); - } - else - { - old_port0 = udp0->src_port; - udp0->src_port = s0->out2in.port; - udp0->checksum = 0; - } - - /* Hairpinning */ - snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0); - - /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); - /* Per-user LRU list maintenance for dynamic translation */ - if (!snat_is_session_static (s0)) - { - clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, - s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, - s0->per_user_list_head_index, - s0->per_user_index); - } - trace00: - - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_in2out_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->is_slow_path = is_slow_path; - t->sw_if_index = sw_if_index0; - t->next_index = next0; - t->session_index = ~0; - if (s0) - t->session_index = s0 - sm->per_thread_data[cpu_index].sessions; - } - - pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP; - - ip1 = vlib_buffer_get_current (b1); - udp1 = ip4_next_header (ip1); - tcp1 = (tcp_header_t *) udp1; - icmp1 = (icmp46_header_t *) udp1; - - sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX]; - rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, - sw_if_index1); - - proto1 = ~0; - proto1 = (ip1->protocol == IP_PROTOCOL_UDP) - ? SNAT_PROTOCOL_UDP : proto1; - proto1 = (ip1->protocol == IP_PROTOCOL_TCP) - ? SNAT_PROTOCOL_TCP : proto1; - proto1 = (ip1->protocol == IP_PROTOCOL_ICMP) - ? SNAT_PROTOCOL_ICMP : proto1; - - /* Next configured feature, probably ip4-lookup */ - if (is_slow_path) - { - if (PREDICT_FALSE (proto1 == ~0)) - goto trace01; - - if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP)) - { - next1 = icmp_in2out_slow_path - (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node, - next1, now, cpu_index); - goto trace01; - } - } - else - { - if (PREDICT_FALSE (proto1 == ~0 || proto1 == SNAT_PROTOCOL_ICMP)) - { - next1 = SNAT_IN2OUT_NEXT_SLOW_PATH; - goto trace01; - } - } - - key1.addr = ip1->src_address; - key1.port = udp1->src_port; - key1.protocol = proto1; - key1.fib_index = rx_fib_index1; - - kv1.key = key1.as_u64; - - if (PREDICT_FALSE(clib_bihash_search_8_8 (&sm->in2out, &kv1, &value1) != 0)) - { - if (is_slow_path) - { - ip4_address_t * first_int_addr; - - if (PREDICT_FALSE(rt->cached_sw_if_index != sw_if_index1)) - { - first_int_addr = - ip4_interface_first_address (sm->ip4_main, sw_if_index1, - 0 /* just want the address */); - rt->cached_sw_if_index = sw_if_index1; - rt->cached_ip4_address = first_int_addr->as_u32; - } - - /* Don't NAT packet aimed at the intfc address */ - if (PREDICT_FALSE(ip1->dst_address.as_u32 == - rt->cached_ip4_address)) - goto trace01; - - next1 = slow_path (sm, b1, ip1, rx_fib_index1, &key1, - &s1, node, next1, cpu_index); - if (PREDICT_FALSE (next1 == SNAT_IN2OUT_NEXT_DROP)) - goto trace01; - } - else - { - next1 = SNAT_IN2OUT_NEXT_SLOW_PATH; - goto trace01; - } - } - else - s1 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, - value1.value); - - old_addr1 = ip1->src_address.as_u32; - ip1->src_address = s1->out2in.addr; - new_addr1 = ip1->src_address.as_u32; - vnet_buffer(b1)->sw_if_index[VLIB_TX] = s1->out2in.fib_index; - - sum1 = ip1->checksum; - sum1 = ip_csum_update (sum1, old_addr1, new_addr1, - ip4_header_t, - src_address /* changed member */); - ip1->checksum = ip_csum_fold (sum1); - - if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP)) - { - old_port1 = tcp1->ports.src; - tcp1->ports.src = s1->out2in.port; - new_port1 = tcp1->ports.src; - - sum1 = tcp1->checksum; - sum1 = ip_csum_update (sum1, old_addr1, new_addr1, - ip4_header_t, - dst_address /* changed member */); - sum1 = ip_csum_update (sum1, old_port1, new_port1, - ip4_header_t /* cheat */, - length /* changed member */); - tcp1->checksum = ip_csum_fold(sum1); - } - else - { - old_port1 = udp1->src_port; - udp1->src_port = s1->out2in.port; - udp1->checksum = 0; - } - - /* Hairpinning */ - snat_hairpinning (sm, b1, ip1, udp1, tcp1, proto1); - - /* Accounting */ - s1->last_heard = now; - s1->total_pkts++; - s1->total_bytes += vlib_buffer_length_in_chain (vm, b1); - /* Per-user LRU list maintenance for dynamic translation */ - if (!snat_is_session_static (s1)) - { - clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, - s1->per_user_index); - clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, - s1->per_user_list_head_index, - s1->per_user_index); - } - trace01: - - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b1->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_in2out_trace_t *t = - vlib_add_trace (vm, node, b1, sizeof (*t)); - t->sw_if_index = sw_if_index1; - t->next_index = next1; - t->session_index = ~0; - if (s1) - t->session_index = s1 - sm->per_thread_data[cpu_index].sessions; - } - - pkts_processed += next1 != SNAT_IN2OUT_NEXT_DROP; - - /* 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; - u32 sw_if_index0; - ip4_header_t * ip0; - ip_csum_t sum0; - u32 new_addr0, old_addr0; - u16 old_port0, new_port0; - udp_header_t * udp0; - tcp_header_t * tcp0; - icmp46_header_t * icmp0; - snat_session_key_t key0; - u32 rx_fib_index0; - u32 proto0; - snat_session_t * s0 = 0; - clib_bihash_kv_8_8_t kv0, value0; - - /* 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); - next0 = SNAT_IN2OUT_NEXT_LOOKUP; - - ip0 = vlib_buffer_get_current (b0); - udp0 = ip4_next_header (ip0); - tcp0 = (tcp_header_t *) udp0; - icmp0 = (icmp46_header_t *) udp0; - - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, - sw_if_index0); - - proto0 = ~0; - proto0 = (ip0->protocol == IP_PROTOCOL_UDP) - ? SNAT_PROTOCOL_UDP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_TCP) - ? SNAT_PROTOCOL_TCP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_ICMP) - ? SNAT_PROTOCOL_ICMP : proto0; - - /* Next configured feature, probably ip4-lookup */ - if (is_slow_path) - { - if (PREDICT_FALSE (proto0 == ~0)) - goto trace0; - - if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) - { - next0 = icmp_in2out_slow_path - (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, - next0, now, cpu_index); - goto trace0; - } - } - else - { - if (PREDICT_FALSE (proto0 == ~0 || proto0 == SNAT_PROTOCOL_ICMP)) - { - next0 = SNAT_IN2OUT_NEXT_SLOW_PATH; - goto trace0; - } - } - - key0.addr = ip0->src_address; - key0.port = udp0->src_port; - key0.protocol = proto0; - key0.fib_index = rx_fib_index0; - - kv0.key = key0.as_u64; - - if (clib_bihash_search_8_8 (&sm->in2out, &kv0, &value0)) - { - if (is_slow_path) - { - ip4_address_t * first_int_addr; - - if (PREDICT_FALSE(rt->cached_sw_if_index != sw_if_index0)) - { - first_int_addr = - ip4_interface_first_address (sm->ip4_main, sw_if_index0, - 0 /* just want the address */); - rt->cached_sw_if_index = sw_if_index0; - rt->cached_ip4_address = first_int_addr->as_u32; - } - - /* Don't NAT packet aimed at the intfc address */ - if (PREDICT_FALSE(ip0->dst_address.as_u32 == - rt->cached_ip4_address)) - goto trace0; - - next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0, - &s0, node, next0, cpu_index); - if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP)) - goto trace0; - } - else - { - next0 = SNAT_IN2OUT_NEXT_SLOW_PATH; - goto trace0; - } - } - else - s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, - value0.value); - - old_addr0 = ip0->src_address.as_u32; - ip0->src_address = s0->out2in.addr; - new_addr0 = ip0->src_address.as_u32; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - src_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - old_port0 = tcp0->ports.src; - tcp0->ports.src = s0->out2in.port; - new_port0 = tcp0->ports.src; - - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - sum0 = ip_csum_update (sum0, old_port0, new_port0, - ip4_header_t /* cheat */, - length /* changed member */); - tcp0->checksum = ip_csum_fold(sum0); - } - else - { - old_port0 = udp0->src_port; - udp0->src_port = s0->out2in.port; - udp0->checksum = 0; - } - - /* Hairpinning */ - snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0); - - /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); - /* Per-user LRU list maintenance for dynamic translation */ - if (!snat_is_session_static (s0)) - { - clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, - s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, - s0->per_user_list_head_index, - s0->per_user_index); - } - - trace0: - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_in2out_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->is_slow_path = is_slow_path; - t->sw_if_index = sw_if_index0; - t->next_index = next0; - t->session_index = ~0; - if (s0) - t->session_index = s0 - sm->per_thread_data[cpu_index].sessions; - } - - pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP; - - /* 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, stats_node_index, - SNAT_IN2OUT_ERROR_IN2OUT_PACKETS, - pkts_processed); - return frame->n_vectors; -} - -static uword -snat_in2out_fast_path_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return snat_in2out_node_fn_inline (vm, node, frame, 0 /* is_slow_path */); -} - -VLIB_REGISTER_NODE (snat_in2out_node) = { - .function = snat_in2out_fast_path_fn, - .name = "snat-in2out", - .vector_size = sizeof (u32), - .format_trace = format_snat_in2out_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(snat_in2out_error_strings), - .error_strings = snat_in2out_error_strings, - - .runtime_data_bytes = sizeof (snat_runtime_t), - - .n_next_nodes = SNAT_IN2OUT_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [SNAT_IN2OUT_NEXT_DROP] = "error-drop", - [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup", - [SNAT_IN2OUT_NEXT_SLOW_PATH] = "snat-in2out-slowpath", - }, -}; - -VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_node, snat_in2out_fast_path_fn); - -static uword -snat_in2out_slow_path_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return snat_in2out_node_fn_inline (vm, node, frame, 1 /* is_slow_path */); -} - -VLIB_REGISTER_NODE (snat_in2out_slowpath_node) = { - .function = snat_in2out_slow_path_fn, - .name = "snat-in2out-slowpath", - .vector_size = sizeof (u32), - .format_trace = format_snat_in2out_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(snat_in2out_error_strings), - .error_strings = snat_in2out_error_strings, - - .runtime_data_bytes = sizeof (snat_runtime_t), - - .n_next_nodes = SNAT_IN2OUT_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [SNAT_IN2OUT_NEXT_DROP] = "error-drop", - [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup", - [SNAT_IN2OUT_NEXT_SLOW_PATH] = "snat-in2out-slowpath", - }, -}; - -VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_slowpath_node, snat_in2out_slow_path_fn); - -static uword -snat_in2out_worker_handoff_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - snat_main_t *sm = &snat_main; - vlib_thread_main_t *tm = vlib_get_thread_main (); - u32 n_left_from, *from, *to_next = 0; - static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index; - static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index - = 0; - vlib_frame_queue_elt_t *hf = 0; - vlib_frame_t *f = 0; - int i; - u32 n_left_to_next_worker = 0, *to_next_worker = 0; - u32 next_worker_index = 0; - u32 current_worker_index = ~0; - u32 cpu_index = os_get_cpu_number (); - - ASSERT (vec_len (sm->workers)); - - if (PREDICT_FALSE (handoff_queue_elt_by_worker_index == 0)) - { - vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1); - - vec_validate_init_empty (congested_handoff_queue_by_worker_index, - sm->first_worker_index + sm->num_workers - 1, - (vlib_frame_queue_t *) (~0)); - } - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - - while (n_left_from > 0) - { - u32 bi0; - vlib_buffer_t *b0; - u32 sw_if_index0; - u32 rx_fib_index0; - ip4_header_t * ip0; - snat_user_key_t key0; - clib_bihash_kv_8_8_t kv0, value0; - u8 do_handoff; - - bi0 = from[0]; - from += 1; - n_left_from -= 1; - - b0 = vlib_get_buffer (vm, bi0); - - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0); - - ip0 = vlib_buffer_get_current (b0); - - key0.addr = ip0->src_address; - key0.fib_index = rx_fib_index0; - - kv0.key = key0.as_u64; - - /* Ever heard of of the "user" before? */ - if (clib_bihash_search_8_8 (&sm->worker_by_in, &kv0, &value0)) - { - /* No, assign next available worker (RR) */ - next_worker_index = sm->first_worker_index + - sm->workers[sm->next_worker++ % vec_len (sm->workers)]; - - /* add non-traslated packets worker lookup */ - kv0.value = next_worker_index; - clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv0, 1); - } - else - next_worker_index = value0.value; - - if (PREDICT_FALSE (next_worker_index != cpu_index)) - { - do_handoff = 1; - - if (next_worker_index != current_worker_index) - { - if (hf) - hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker; - - hf = vlib_get_worker_handoff_queue_elt (sm->fq_in2out_index, - next_worker_index, - handoff_queue_elt_by_worker_index); - - n_left_to_next_worker = VLIB_FRAME_SIZE - hf->n_vectors; - to_next_worker = &hf->buffer_index[hf->n_vectors]; - current_worker_index = next_worker_index; - } - - /* enqueue to correct worker thread */ - to_next_worker[0] = bi0; - to_next_worker++; - n_left_to_next_worker--; - - if (n_left_to_next_worker == 0) - { - hf->n_vectors = VLIB_FRAME_SIZE; - vlib_put_frame_queue_elt (hf); - current_worker_index = ~0; - handoff_queue_elt_by_worker_index[next_worker_index] = 0; - hf = 0; - } - } - else - { - do_handoff = 0; - /* if this is 1st frame */ - if (!f) - { - f = vlib_get_frame_to_node (vm, snat_in2out_node.index); - to_next = vlib_frame_vector_args (f); - } - - to_next[0] = bi0; - to_next += 1; - f->n_vectors++; - } - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_in2out_worker_handoff_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->next_worker_index = next_worker_index; - t->do_handoff = do_handoff; - } - } - - if (f) - vlib_put_frame_to_node (vm, snat_in2out_node.index, f); - - if (hf) - hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker; - - /* Ship frames to the worker nodes */ - for (i = 0; i < vec_len (handoff_queue_elt_by_worker_index); i++) - { - if (handoff_queue_elt_by_worker_index[i]) - { - hf = handoff_queue_elt_by_worker_index[i]; - /* - * It works better to let the handoff node - * rate-adapt, always ship the handoff queue element. - */ - if (1 || hf->n_vectors == hf->last_n_vectors) - { - vlib_put_frame_queue_elt (hf); - handoff_queue_elt_by_worker_index[i] = 0; - } - else - hf->last_n_vectors = hf->n_vectors; - } - congested_handoff_queue_by_worker_index[i] = - (vlib_frame_queue_t *) (~0); - } - hf = 0; - current_worker_index = ~0; - return frame->n_vectors; -} - -VLIB_REGISTER_NODE (snat_in2out_worker_handoff_node) = { - .function = snat_in2out_worker_handoff_fn, - .name = "snat-in2out-worker-handoff", - .vector_size = sizeof (u32), - .format_trace = format_snat_in2out_worker_handoff_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_next_nodes = 1, - - .next_nodes = { - [0] = "error-drop", - }, -}; - -VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_worker_handoff_node, snat_in2out_worker_handoff_fn); - -static inline u32 icmp_in2out_static_map (snat_main_t *sm, - vlib_buffer_t * b0, - ip4_header_t * ip0, - icmp46_header_t * icmp0, - u32 sw_if_index0, - vlib_node_runtime_t * node, - u32 next0, - u32 rx_fib_index0) -{ - snat_session_key_t key0, sm0; - icmp_echo_header_t *echo0; - u32 new_addr0, old_addr0; - u16 old_id0, new_id0; - ip_csum_t sum0; - snat_runtime_t * rt = (snat_runtime_t *)node->runtime_data; - - echo0 = (icmp_echo_header_t *)(icmp0+1); - - key0.addr = ip0->src_address; - key0.port = echo0->identifier; - key0.fib_index = rx_fib_index0; - - if (snat_static_mapping_match(sm, key0, &sm0, 0)) - { - ip4_address_t * first_int_addr; - - if (PREDICT_FALSE(rt->cached_sw_if_index != sw_if_index0)) - { - first_int_addr = - ip4_interface_first_address (sm->ip4_main, sw_if_index0, - 0 /* just want the address */); - rt->cached_sw_if_index = sw_if_index0; - rt->cached_ip4_address = first_int_addr->as_u32; - } - - /* Don't NAT packet aimed at the intfc address */ - if (PREDICT_FALSE(ip0->dst_address.as_u32 == - rt->cached_ip4_address)) - return next0; - - b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION]; - return SNAT_IN2OUT_NEXT_DROP; - } - - new_addr0 = sm0.addr.as_u32; - new_id0 = sm0.port; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index; - old_addr0 = ip0->src_address.as_u32; - ip0->src_address.as_u32 = new_addr0; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - src_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - if (PREDICT_FALSE(new_id0 != echo0->identifier)) - { - old_id0 = echo0->identifier; - echo0->identifier = new_id0; - - sum0 = icmp0->checksum; - sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t, - identifier); - icmp0->checksum = ip_csum_fold (sum0); - } - - return next0; -} - -static uword -snat_in2out_fast_static_map_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - u32 n_left_from, * from, * to_next; - snat_in2out_next_t next_index; - u32 pkts_processed = 0; - snat_main_t * sm = &snat_main; - snat_runtime_t * rt = (snat_runtime_t *)node->runtime_data; - u32 stats_node_index; - - stats_node_index = snat_in2out_fast_node.index; - - 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 > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t * b0; - u32 next0; - u32 sw_if_index0; - ip4_header_t * ip0; - ip_csum_t sum0; - u32 new_addr0, old_addr0; - u16 old_port0, new_port0; - udp_header_t * udp0; - tcp_header_t * tcp0; - icmp46_header_t * icmp0; - snat_session_key_t key0, sm0; - u32 proto0; - u32 rx_fib_index0; - - /* 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); - next0 = SNAT_IN2OUT_NEXT_LOOKUP; - - ip0 = vlib_buffer_get_current (b0); - udp0 = ip4_next_header (ip0); - tcp0 = (tcp_header_t *) udp0; - icmp0 = (icmp46_header_t *) udp0; - - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0); - - proto0 = ~0; - proto0 = (ip0->protocol == IP_PROTOCOL_UDP) - ? SNAT_PROTOCOL_UDP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_TCP) - ? SNAT_PROTOCOL_TCP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_ICMP) - ? SNAT_PROTOCOL_ICMP : proto0; - - if (PREDICT_FALSE (proto0 == ~0)) - goto trace0; - - if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) - { - ip4_address_t * first_int_addr; - - if (PREDICT_FALSE(rt->cached_sw_if_index != sw_if_index0)) - { - first_int_addr = - ip4_interface_first_address (sm->ip4_main, sw_if_index0, - 0 /* just want the address */); - rt->cached_sw_if_index = sw_if_index0; - rt->cached_ip4_address = first_int_addr->as_u32; - } - - /* Don't NAT packet aimed at the intfc address */ - if (PREDICT_FALSE(ip0->dst_address.as_u32 == - rt->cached_ip4_address)) - goto trace0; - - next0 = icmp_in2out_static_map - (sm, b0, ip0, icmp0, sw_if_index0, node, next0, rx_fib_index0); - goto trace0; - } - - key0.addr = ip0->src_address; - key0.port = udp0->src_port; - key0.fib_index = rx_fib_index0; - - if (snat_static_mapping_match(sm, key0, &sm0, 0)) - { - b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION]; - next0= SNAT_IN2OUT_NEXT_DROP; - goto trace0; - } - - new_addr0 = sm0.addr.as_u32; - new_port0 = sm0.port; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index; - old_addr0 = ip0->src_address.as_u32; - ip0->src_address.as_u32 = new_addr0; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - src_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - if (PREDICT_FALSE(new_port0 != udp0->dst_port)) - { - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - old_port0 = tcp0->ports.src; - tcp0->ports.src = new_port0; - - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - sum0 = ip_csum_update (sum0, old_port0, new_port0, - ip4_header_t /* cheat */, - length /* changed member */); - tcp0->checksum = ip_csum_fold(sum0); - } - else - { - old_port0 = udp0->src_port; - udp0->src_port = new_port0; - udp0->checksum = 0; - } - } - else - { - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - tcp0->checksum = ip_csum_fold(sum0); - } - } - - /* Hairpinning */ - snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0); - - trace0: - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_in2out_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - t->next_index = next0; - } - - pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP; - - /* 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, stats_node_index, - SNAT_IN2OUT_ERROR_IN2OUT_PACKETS, - pkts_processed); - return frame->n_vectors; -} - - -VLIB_REGISTER_NODE (snat_in2out_fast_node) = { - .function = snat_in2out_fast_static_map_fn, - .name = "snat-in2out-fast", - .vector_size = sizeof (u32), - .format_trace = format_snat_in2out_fast_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(snat_in2out_error_strings), - .error_strings = snat_in2out_error_strings, - - .runtime_data_bytes = sizeof (snat_runtime_t), - - .n_next_nodes = SNAT_IN2OUT_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [SNAT_IN2OUT_NEXT_DROP] = "error-drop", - [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup", - [SNAT_IN2OUT_NEXT_SLOW_PATH] = "snat-in2out-slowpath", - }, -}; - -VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_fast_node, snat_in2out_fast_static_map_fn); diff --git a/plugins/snat-plugin/snat/jvpp/io/fd/vpp/jvpp/snat/test/CallbackApiTest.java b/plugins/snat-plugin/snat/jvpp/io/fd/vpp/jvpp/snat/test/CallbackApiTest.java deleted file mode 100644 index 32165d96..00000000 --- a/plugins/snat-plugin/snat/jvpp/io/fd/vpp/jvpp/snat/test/CallbackApiTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.snat.test; - -import io.fd.vpp.jvpp.JVpp; -import io.fd.vpp.jvpp.JVppRegistry; -import io.fd.vpp.jvpp.JVppRegistryImpl; -import io.fd.vpp.jvpp.VppCallbackException; -import io.fd.vpp.jvpp.snat.JVppSnatImpl; -import io.fd.vpp.jvpp.snat.callback.SnatInterfaceAddDelFeatureCallback; -import io.fd.vpp.jvpp.snat.dto.SnatInterfaceAddDelFeature; -import io.fd.vpp.jvpp.snat.dto.SnatInterfaceAddDelFeatureReply; - -public class CallbackApiTest { - - static class TestCallback implements SnatInterfaceAddDelFeatureCallback { - - @Override - public void onSnatInterfaceAddDelFeatureReply(final SnatInterfaceAddDelFeatureReply msg) { - System.out.printf("Received SnatInterfaceAddDelFeatureReply: context=%d%n", - msg.context); - } - - @Override - public void onError(VppCallbackException ex) { - System.out.printf("Received onError exception: call=%s, context=%d, retval=%d%n", ex.getMethodName(), - ex.getCtxId(), ex.getErrorCode()); - } - } - - public static void main(String[] args) throws Exception { - testCallbackApi(); - } - - private static void testCallbackApi() throws Exception { - System.out.println("Testing Java callback API for snat plugin"); - try (final JVppRegistry registry = new JVppRegistryImpl("SnatCallbackApiTest"); - final JVpp jvpp = new JVppSnatImpl()) { - registry.register(jvpp, new TestCallback()); - - System.out.println("Sending SnatInterfaceAddDelFeature request..."); - SnatInterfaceAddDelFeature request = new SnatInterfaceAddDelFeature(); - request.isAdd = 1; - request.isInside = 1; - request.swIfIndex = 1; - final int result = jvpp.send(request); - System.out.printf("SnatInterfaceAddDelFeature send result = %d%n", result); - - Thread.sleep(1000); - - System.out.println("Disconnecting..."); - } - } -} diff --git a/plugins/snat-plugin/snat/jvpp/io/fd/vpp/jvpp/snat/test/Readme.txt b/plugins/snat-plugin/snat/jvpp/io/fd/vpp/jvpp/snat/test/Readme.txt deleted file mode 100644 index a2b0c41f..00000000 --- a/plugins/snat-plugin/snat/jvpp/io/fd/vpp/jvpp/snat/test/Readme.txt +++ /dev/null @@ -1 +0,0 @@ -sudo java -cp build-vpp-native/vpp-api/java/jvpp-registry-17.01.jar:build-vpp-native/plugins/snat-plugin/jvpp-snat-1.0.jar io.fd.vpp.jvpp.snat.test.CallbackApiTest diff --git a/plugins/snat-plugin/snat/jvpp_snat.c b/plugins/snat-plugin/snat/jvpp_snat.c deleted file mode 100644 index fd72ddb1..00000000 --- a/plugins/snat-plugin/snat/jvpp_snat.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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. - */ - -#include - -#include -#define vl_typedefs /* define message structures */ -#include -#undef vl_typedefs - -#define vl_endianfun -#include -#undef vl_endianfun - -#define vl_print(handle, ...) -#define vl_printfun -#include -#undef vl_printfun - -/* Get the API version number */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#undef vl_api_version - -#include -#include -#include - -#if VPPJNI_DEBUG == 1 - #define DEBUG_LOG(...) clib_warning(__VA_ARGS__) -#else - #define DEBUG_LOG(...) -#endif - -#include - -#include "snat/jvpp/io_fd_vpp_jvpp_snat_JVppSnatImpl.h" -#include "jvpp_snat.h" -#include "snat/jvpp/jvpp_snat_gen.h" - -/* - * Class: io_fd_vpp_jvpp_snat_JVppsnatImpl - * Method: init0 - * Signature: (JI)V - */ -JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_snat_JVppSnatImpl_init0 - (JNIEnv *env, jclass clazz, jobject callback, jlong queue_address, jint my_client_index) { - snat_main_t * plugin_main = &snat_main; - u8 * name; - clib_warning ("Java_io_fd_vpp_jvpp_snat_JVppSnatImpl_init0"); - - plugin_main->my_client_index = my_client_index; - plugin_main->vl_input_queue = (unix_shared_memory_queue_t *)queue_address; - - name = format (0, "snat_%08x%c", api_version, 0); - plugin_main->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name); - - if (plugin_main->msg_id_base == (u16) ~0) { - jclass exClass = (*env)->FindClass(env, "java/lang/IllegalStateException"); - (*env)->ThrowNew(env, exClass, "snat plugin is not loaded in VPP"); - } else { - plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback); - plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback)); - - #define _(N,n) \ - vl_msg_api_set_handlers(VL_API_##N + plugin_main->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_api_reply_handler; - #undef _ - } -} - -JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_snat_JVppSnatImpl_close0 -(JNIEnv *env, jclass clazz) { - snat_main_t * plugin_main = &snat_main; - - // cleanup: - (*env)->DeleteGlobalRef(env, plugin_main->callbackClass); - (*env)->DeleteGlobalRef(env, plugin_main->callbackObject); - - plugin_main->callbackClass = NULL; - plugin_main->callbackObject = NULL; -} - -/* Attach thread to JVM and cache class references when initiating JVPP SNAT */ -jint JNI_OnLoad(JavaVM *vm, void *reserved) { - JNIEnv* env; - - if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { - return JNI_EVERSION; - } - - if (cache_class_references(env) != 0) { - clib_warning ("Failed to cache class references\n"); - return JNI_ERR; - } - - return JNI_VERSION_1_8; -} - -/* Clean up cached references when disposing JVPP SNAT */ -void JNI_OnUnload(JavaVM *vm, void *reserved) { - JNIEnv* env; - if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { - return; - } - delete_class_references(env); -} diff --git a/plugins/snat-plugin/snat/jvpp_snat.h b/plugins/snat-plugin/snat/jvpp_snat.h deleted file mode 100644 index 6426bda8..00000000 --- a/plugins/snat-plugin/snat/jvpp_snat.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - */ -#ifndef __included_jvpp_snat_h__ -#define __included_jvpp_snat_h__ - -#include -#include -#include -#include -#include -#include - -/* Global state for JVPP-SNAT */ -typedef struct { - /* Base message index for the nsh plugin */ - u16 msg_id_base; - - /* Pointer to shared memory queue */ - unix_shared_memory_queue_t * vl_input_queue; - - /* VPP api client index */ - u32 my_client_index; - - /* Callback object and class references enabling asynchronous Java calls */ - jobject callbackObject; - jclass callbackClass; - -} snat_main_t; - -snat_main_t snat_main __attribute__((aligned (64))); - - -#endif /* __included_jvpp_snat_h__ */ diff --git a/plugins/snat-plugin/snat/out2in.c b/plugins/snat-plugin/snat/out2in.c deleted file mode 100644 index f1f4159c..00000000 --- a/plugins/snat-plugin/snat/out2in.c +++ /dev/null @@ -1,1261 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -typedef struct { - u32 sw_if_index; - u32 next_index; - u32 session_index; -} snat_out2in_trace_t; - -typedef struct { - u32 next_worker_index; - u8 do_handoff; -} snat_out2in_worker_handoff_trace_t; - -/* packet trace format function */ -static u8 * format_snat_out2in_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 *); - snat_out2in_trace_t * t = va_arg (*args, snat_out2in_trace_t *); - - s = format (s, "SNAT_OUT2IN: sw_if_index %d, next index %d, session index %d", - t->sw_if_index, t->next_index, t->session_index); - return s; -} - -static u8 * format_snat_out2in_fast_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 *); - snat_out2in_trace_t * t = va_arg (*args, snat_out2in_trace_t *); - - s = format (s, "SNAT_OUT2IN_FAST: sw_if_index %d, next index %d", - t->sw_if_index, t->next_index); - return s; -} - -static u8 * format_snat_out2in_worker_handoff_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 *); - snat_out2in_worker_handoff_trace_t * t = - va_arg (*args, snat_out2in_worker_handoff_trace_t *); - char * m; - - m = t->do_handoff ? "next worker" : "same worker"; - s = format (s, "SNAT_OUT2IN_WORKER_HANDOFF: %s %d", m, t->next_worker_index); - - return s; -} - -vlib_node_registration_t snat_out2in_node; -vlib_node_registration_t snat_out2in_fast_node; -vlib_node_registration_t snat_out2in_worker_handoff_node; - -#define foreach_snat_out2in_error \ -_(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \ -_(OUT2IN_PACKETS, "Good out2in packets processed") \ -_(BAD_ICMP_TYPE, "icmp type not echo-reply") \ -_(NO_TRANSLATION, "No translation") - -typedef enum { -#define _(sym,str) SNAT_OUT2IN_ERROR_##sym, - foreach_snat_out2in_error -#undef _ - SNAT_OUT2IN_N_ERROR, -} snat_out2in_error_t; - -static char * snat_out2in_error_strings[] = { -#define _(sym,string) string, - foreach_snat_out2in_error -#undef _ -}; - -typedef enum { - SNAT_OUT2IN_NEXT_DROP, - SNAT_OUT2IN_NEXT_LOOKUP, - SNAT_OUT2IN_N_NEXT, -} snat_out2in_next_t; - -/** - * @brief Create session for static mapping. - * - * Create NAT session initiated by host from external network with static - * mapping. - * - * @param sm SNAT main. - * @param b0 Vlib buffer. - * @param in2out In2out SNAT session key. - * @param out2in Out2in SNAT session key. - * @param node Vlib node. - * - * @returns SNAT session if successfully created otherwise 0. - */ -static inline snat_session_t * -create_session_for_static_mapping (snat_main_t *sm, - vlib_buffer_t *b0, - snat_session_key_t in2out, - snat_session_key_t out2in, - vlib_node_runtime_t * node, - u32 cpu_index) -{ - snat_user_t *u; - snat_user_key_t user_key; - snat_session_t *s; - clib_bihash_kv_8_8_t kv0, value0; - dlist_elt_t * per_user_translation_list_elt; - dlist_elt_t * per_user_list_head_elt; - - user_key.addr = in2out.addr; - user_key.fib_index = in2out.fib_index; - kv0.key = user_key.as_u64; - - /* Ever heard of the "user" = inside ip4 address before? */ - if (clib_bihash_search_8_8 (&sm->user_hash, &kv0, &value0)) - { - /* no, make a new one */ - pool_get (sm->per_thread_data[cpu_index].users, u); - memset (u, 0, sizeof (*u)); - u->addr = in2out.addr; - - pool_get (sm->per_thread_data[cpu_index].list_pool, - per_user_list_head_elt); - - u->sessions_per_user_list_head_index = per_user_list_head_elt - - sm->per_thread_data[cpu_index].list_pool; - - clib_dlist_init (sm->per_thread_data[cpu_index].list_pool, - u->sessions_per_user_list_head_index); - - kv0.value = u - sm->per_thread_data[cpu_index].users; - - /* add user */ - clib_bihash_add_del_8_8 (&sm->user_hash, &kv0, 1 /* is_add */); - - /* add non-traslated packets worker lookup */ - kv0.value = cpu_index; - clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv0, 1); - } - else - { - u = pool_elt_at_index (sm->per_thread_data[cpu_index].users, - value0.value); - } - - pool_get (sm->per_thread_data[cpu_index].sessions, s); - memset (s, 0, sizeof (*s)); - - s->outside_address_index = ~0; - s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; - u->nstaticsessions++; - - /* Create list elts */ - pool_get (sm->per_thread_data[cpu_index].list_pool, - per_user_translation_list_elt); - clib_dlist_init (sm->per_thread_data[cpu_index].list_pool, - per_user_translation_list_elt - - sm->per_thread_data[cpu_index].list_pool); - - per_user_translation_list_elt->value = - s - sm->per_thread_data[cpu_index].sessions; - s->per_user_index = - per_user_translation_list_elt - sm->per_thread_data[cpu_index].list_pool; - s->per_user_list_head_index = u->sessions_per_user_list_head_index; - - clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, - s->per_user_list_head_index, - per_user_translation_list_elt - - sm->per_thread_data[cpu_index].list_pool); - - s->in2out = in2out; - s->out2in = out2in; - s->in2out.protocol = out2in.protocol; - - /* Add to translation hashes */ - kv0.key = s->in2out.as_u64; - kv0.value = s - sm->per_thread_data[cpu_index].sessions; - if (clib_bihash_add_del_8_8 (&sm->in2out, &kv0, 1 /* is_add */)) - clib_warning ("in2out key add failed"); - - kv0.key = s->out2in.as_u64; - kv0.value = s - sm->per_thread_data[cpu_index].sessions; - - if (clib_bihash_add_del_8_8 (&sm->out2in, &kv0, 1 /* is_add */)) - clib_warning ("out2in key add failed"); - - return s; -} - -static inline u32 icmp_out2in_slow_path (snat_main_t *sm, - vlib_buffer_t * b0, - ip4_header_t * ip0, - icmp46_header_t * icmp0, - u32 sw_if_index0, - u32 rx_fib_index0, - vlib_node_runtime_t * node, - u32 next0, f64 now, - u32 cpu_index) -{ - snat_session_key_t key0, sm0; - icmp_echo_header_t *echo0; - clib_bihash_kv_8_8_t kv0, value0; - snat_session_t * s0; - u32 new_addr0, old_addr0; - u16 old_id0, new_id0; - ip_csum_t sum0; - snat_runtime_t * rt = (snat_runtime_t *)node->runtime_data; - - echo0 = (icmp_echo_header_t *)(icmp0+1); - - key0.addr = ip0->dst_address; - key0.port = echo0->identifier; - key0.protocol = SNAT_PROTOCOL_ICMP; - key0.fib_index = rx_fib_index0; - - kv0.key = key0.as_u64; - - if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0)) - { - /* Try to match static mapping by external address and port, - destination address and port in packet */ - if (snat_static_mapping_match(sm, key0, &sm0, 1)) - { - ip4_address_t * first_int_addr; - - if (PREDICT_FALSE(rt->cached_sw_if_index != sw_if_index0)) - { - first_int_addr = - ip4_interface_first_address (sm->ip4_main, sw_if_index0, - 0 /* just want the address */); - rt->cached_sw_if_index = sw_if_index0; - rt->cached_ip4_address = first_int_addr->as_u32; - } - - /* Don't NAT packet aimed at the intfc address */ - if (PREDICT_FALSE(ip0->dst_address.as_u32 == - rt->cached_ip4_address)) - return next0; - - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - return SNAT_OUT2IN_NEXT_DROP; - } - - /* Create session initiated by host from external network */ - s0 = create_session_for_static_mapping(sm, b0, sm0, key0, - node, cpu_index); - if (!s0) - return SNAT_OUT2IN_NEXT_DROP; - } - else - s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, - value0.value); - - old_addr0 = ip0->dst_address.as_u32; - ip0->dst_address = s0->in2out.addr; - new_addr0 = ip0->dst_address.as_u32; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - old_id0 = echo0->identifier; - new_id0 = s0->in2out.port; - echo0->identifier = new_id0; - - sum0 = icmp0->checksum; - sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t, - identifier); - icmp0->checksum = ip_csum_fold (sum0); - - /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (sm->vlib_main, b0); - /* Per-user LRU list maintenance for dynamic translation */ - if (!snat_is_session_static (s0)) - { - clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, - s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, - s0->per_user_list_head_index, - s0->per_user_index); - } - - return next0; -} - -static uword -snat_out2in_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - u32 n_left_from, * from, * to_next; - snat_out2in_next_t next_index; - u32 pkts_processed = 0; - snat_main_t * sm = &snat_main; - f64 now = vlib_time_now (vm); - u32 cpu_index = os_get_cpu_number (); - - 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 bi0, bi1; - vlib_buffer_t * b0, * b1; - u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP; - u32 next1 = SNAT_OUT2IN_NEXT_LOOKUP; - u32 sw_if_index0, sw_if_index1; - ip4_header_t * ip0, *ip1; - ip_csum_t sum0, sum1; - u32 new_addr0, old_addr0; - u16 new_port0, old_port0; - u32 new_addr1, old_addr1; - u16 new_port1, old_port1; - udp_header_t * udp0, * udp1; - tcp_header_t * tcp0, * tcp1; - icmp46_header_t * icmp0, * icmp1; - snat_session_key_t key0, key1, sm0, sm1; - u32 rx_fib_index0, rx_fib_index1; - u32 proto0, proto1; - snat_session_t * s0 = 0, * s1 = 0; - clib_bihash_kv_8_8_t kv0, kv1, value0, value1; - - /* 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); - - ip0 = vlib_buffer_get_current (b0); - udp0 = ip4_next_header (ip0); - tcp0 = (tcp_header_t *) udp0; - icmp0 = (icmp46_header_t *) udp0; - - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, - sw_if_index0); - - proto0 = ~0; - proto0 = (ip0->protocol == IP_PROTOCOL_UDP) - ? SNAT_PROTOCOL_UDP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_TCP) - ? SNAT_PROTOCOL_TCP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_ICMP) - ? SNAT_PROTOCOL_ICMP : proto0; - - if (PREDICT_FALSE (proto0 == ~0)) - goto trace0; - - if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) - { - next0 = icmp_out2in_slow_path - (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, - next0, now, cpu_index); - goto trace0; - } - - key0.addr = ip0->dst_address; - key0.port = udp0->dst_port; - key0.protocol = proto0; - key0.fib_index = rx_fib_index0; - - kv0.key = key0.as_u64; - - if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0)) - { - /* Try to match static mapping by external address and port, - destination address and port in packet */ - if (snat_static_mapping_match(sm, key0, &sm0, 1)) - { - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - goto trace0; - } - - /* Create session initiated by host from external network */ - s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node, - cpu_index); - if (!s0) - goto trace0; - } - else - s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, - value0.value); - - old_addr0 = ip0->dst_address.as_u32; - ip0->dst_address = s0->in2out.addr; - new_addr0 = ip0->dst_address.as_u32; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - old_port0 = tcp0->ports.dst; - tcp0->ports.dst = s0->in2out.port; - new_port0 = tcp0->ports.dst; - - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - - sum0 = ip_csum_update (sum0, old_port0, new_port0, - ip4_header_t /* cheat */, - length /* changed member */); - tcp0->checksum = ip_csum_fold(sum0); - } - else - { - old_port0 = udp0->dst_port; - udp0->dst_port = s0->in2out.port; - udp0->checksum = 0; - } - - /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); - /* Per-user LRU list maintenance for dynamic translation */ - if (!snat_is_session_static (s0)) - { - clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, - s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, - s0->per_user_list_head_index, - s0->per_user_index); - } - trace0: - - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_out2in_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - t->next_index = next0; - t->session_index = ~0; - if (s0) - t->session_index = s0 - sm->per_thread_data[cpu_index].sessions; - } - - pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP; - - - ip1 = vlib_buffer_get_current (b1); - udp1 = ip4_next_header (ip1); - tcp1 = (tcp_header_t *) udp1; - icmp1 = (icmp46_header_t *) udp1; - - sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX]; - rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, - sw_if_index1); - - proto1 = ~0; - proto1 = (ip1->protocol == IP_PROTOCOL_UDP) - ? SNAT_PROTOCOL_UDP : proto1; - proto1 = (ip1->protocol == IP_PROTOCOL_TCP) - ? SNAT_PROTOCOL_TCP : proto1; - proto1 = (ip1->protocol == IP_PROTOCOL_ICMP) - ? SNAT_PROTOCOL_ICMP : proto1; - - if (PREDICT_FALSE (proto1 == ~0)) - goto trace1; - - if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP)) - { - next1 = icmp_out2in_slow_path - (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node, - next1, now, cpu_index); - goto trace1; - } - - key1.addr = ip1->dst_address; - key1.port = udp1->dst_port; - key1.protocol = proto1; - key1.fib_index = rx_fib_index1; - - kv1.key = key1.as_u64; - - if (clib_bihash_search_8_8 (&sm->out2in, &kv1, &value1)) - { - /* Try to match static mapping by external address and port, - destination address and port in packet */ - if (snat_static_mapping_match(sm, key1, &sm1, 1)) - { - b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - goto trace1; - } - - /* Create session initiated by host from external network */ - s1 = create_session_for_static_mapping(sm, b1, sm1, key1, node, - cpu_index); - if (!s1) - goto trace1; - } - else - s1 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, - value1.value); - - old_addr1 = ip1->dst_address.as_u32; - ip1->dst_address = s1->in2out.addr; - new_addr1 = ip1->dst_address.as_u32; - vnet_buffer(b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index; - - sum1 = ip1->checksum; - sum1 = ip_csum_update (sum1, old_addr1, new_addr1, - ip4_header_t, - dst_address /* changed member */); - ip1->checksum = ip_csum_fold (sum1); - - if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP)) - { - old_port1 = tcp1->ports.dst; - tcp1->ports.dst = s1->in2out.port; - new_port1 = tcp1->ports.dst; - - sum1 = tcp1->checksum; - sum1 = ip_csum_update (sum1, old_addr1, new_addr1, - ip4_header_t, - dst_address /* changed member */); - - sum1 = ip_csum_update (sum1, old_port1, new_port1, - ip4_header_t /* cheat */, - length /* changed member */); - tcp1->checksum = ip_csum_fold(sum1); - } - else - { - old_port1 = udp1->dst_port; - udp1->dst_port = s1->in2out.port; - udp1->checksum = 0; - } - - /* Accounting */ - s1->last_heard = now; - s1->total_pkts++; - s1->total_bytes += vlib_buffer_length_in_chain (vm, b1); - /* Per-user LRU list maintenance for dynamic translation */ - if (!snat_is_session_static (s1)) - { - clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, - s1->per_user_index); - clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, - s1->per_user_list_head_index, - s1->per_user_index); - } - trace1: - - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b1->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_out2in_trace_t *t = - vlib_add_trace (vm, node, b1, sizeof (*t)); - t->sw_if_index = sw_if_index1; - t->next_index = next1; - t->session_index = ~0; - if (s1) - t->session_index = s1 - sm->per_thread_data[cpu_index].sessions; - } - - pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP; - - /* 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 = SNAT_OUT2IN_NEXT_LOOKUP; - u32 sw_if_index0; - ip4_header_t * ip0; - ip_csum_t sum0; - u32 new_addr0, old_addr0; - u16 new_port0, old_port0; - udp_header_t * udp0; - tcp_header_t * tcp0; - icmp46_header_t * icmp0; - snat_session_key_t key0, sm0; - u32 rx_fib_index0; - u32 proto0; - snat_session_t * s0 = 0; - clib_bihash_kv_8_8_t kv0, value0; - - /* 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); - - ip0 = vlib_buffer_get_current (b0); - udp0 = ip4_next_header (ip0); - tcp0 = (tcp_header_t *) udp0; - icmp0 = (icmp46_header_t *) udp0; - - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, - sw_if_index0); - - proto0 = ~0; - proto0 = (ip0->protocol == IP_PROTOCOL_UDP) - ? SNAT_PROTOCOL_UDP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_TCP) - ? SNAT_PROTOCOL_TCP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_ICMP) - ? SNAT_PROTOCOL_ICMP : proto0; - - if (PREDICT_FALSE (proto0 == ~0)) - goto trace00; - - if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) - { - next0 = icmp_out2in_slow_path - (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, - next0, now, cpu_index); - goto trace00; - } - - key0.addr = ip0->dst_address; - key0.port = udp0->dst_port; - key0.protocol = proto0; - key0.fib_index = rx_fib_index0; - - kv0.key = key0.as_u64; - - if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0)) - { - /* Try to match static mapping by external address and port, - destination address and port in packet */ - if (snat_static_mapping_match(sm, key0, &sm0, 1)) - { - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - goto trace00; - } - - /* Create session initiated by host from external network */ - s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node, - cpu_index); - if (!s0) - goto trace00; - } - else - s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, - value0.value); - - old_addr0 = ip0->dst_address.as_u32; - ip0->dst_address = s0->in2out.addr; - new_addr0 = ip0->dst_address.as_u32; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - old_port0 = tcp0->ports.dst; - tcp0->ports.dst = s0->in2out.port; - new_port0 = tcp0->ports.dst; - - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - - sum0 = ip_csum_update (sum0, old_port0, new_port0, - ip4_header_t /* cheat */, - length /* changed member */); - tcp0->checksum = ip_csum_fold(sum0); - } - else - { - old_port0 = udp0->dst_port; - udp0->dst_port = s0->in2out.port; - udp0->checksum = 0; - } - - /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); - /* Per-user LRU list maintenance for dynamic translation */ - if (!snat_is_session_static (s0)) - { - clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, - s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, - s0->per_user_list_head_index, - s0->per_user_index); - } - trace00: - - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_out2in_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - t->next_index = next0; - t->session_index = ~0; - if (s0) - t->session_index = s0 - sm->per_thread_data[cpu_index].sessions; - } - - pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP; - - /* 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, snat_out2in_node.index, - SNAT_OUT2IN_ERROR_OUT2IN_PACKETS, - pkts_processed); - return frame->n_vectors; -} - -VLIB_REGISTER_NODE (snat_out2in_node) = { - .function = snat_out2in_node_fn, - .name = "snat-out2in", - .vector_size = sizeof (u32), - .format_trace = format_snat_out2in_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(snat_out2in_error_strings), - .error_strings = snat_out2in_error_strings, - - .runtime_data_bytes = sizeof (snat_runtime_t), - - .n_next_nodes = SNAT_OUT2IN_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [SNAT_OUT2IN_NEXT_DROP] = "error-drop", - [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup", - }, -}; -VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_node, snat_out2in_node_fn); - -static uword -snat_out2in_worker_handoff_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - snat_main_t *sm = &snat_main; - vlib_thread_main_t *tm = vlib_get_thread_main (); - u32 n_left_from, *from, *to_next = 0; - static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index; - static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index - = 0; - vlib_frame_queue_elt_t *hf = 0; - vlib_frame_t *f = 0; - int i; - u32 n_left_to_next_worker = 0, *to_next_worker = 0; - u32 next_worker_index = 0; - u32 current_worker_index = ~0; - u32 cpu_index = os_get_cpu_number (); - - ASSERT (vec_len (sm->workers)); - - if (PREDICT_FALSE (handoff_queue_elt_by_worker_index == 0)) - { - vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1); - - vec_validate_init_empty (congested_handoff_queue_by_worker_index, - sm->first_worker_index + sm->num_workers - 1, - (vlib_frame_queue_t *) (~0)); - } - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - - while (n_left_from > 0) - { - u32 bi0; - vlib_buffer_t *b0; - u32 sw_if_index0; - u32 rx_fib_index0; - ip4_header_t * ip0; - udp_header_t * udp0; - snat_static_mapping_key_t key0; - clib_bihash_kv_8_8_t kv0, value0; - u8 do_handoff; - - bi0 = from[0]; - from += 1; - n_left_from -= 1; - - b0 = vlib_get_buffer (vm, bi0); - - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0); - - ip0 = vlib_buffer_get_current (b0); - udp0 = ip4_next_header (ip0); - - key0.addr = ip0->dst_address; - key0.port = udp0->dst_port; - key0.fib_index = rx_fib_index0; - - kv0.key = key0.as_u64; - - /* Ever heard of of the "user" before? */ - if (clib_bihash_search_8_8 (&sm->worker_by_out, &kv0, &value0)) - { - key0.port = 0; - kv0.key = key0.as_u64; - - if (clib_bihash_search_8_8 (&sm->worker_by_out, &kv0, &value0)) - { - /* No, assign next available worker (RR) */ - next_worker_index = sm->first_worker_index + - sm->workers[sm->next_worker++ % vec_len (sm->workers)]; - } - else - { - /* Static mapping without port */ - next_worker_index = value0.value; - } - - /* Add to translated packets worker lookup */ - kv0.value = next_worker_index; - clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv0, 1); - } - else - next_worker_index = value0.value; - - if (PREDICT_FALSE (next_worker_index != cpu_index)) - { - do_handoff = 1; - - if (next_worker_index != current_worker_index) - { - if (hf) - hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker; - - hf = vlib_get_worker_handoff_queue_elt (sm->fq_out2in_index, - next_worker_index, - handoff_queue_elt_by_worker_index); - - n_left_to_next_worker = VLIB_FRAME_SIZE - hf->n_vectors; - to_next_worker = &hf->buffer_index[hf->n_vectors]; - current_worker_index = next_worker_index; - } - - /* enqueue to correct worker thread */ - to_next_worker[0] = bi0; - to_next_worker++; - n_left_to_next_worker--; - - if (n_left_to_next_worker == 0) - { - hf->n_vectors = VLIB_FRAME_SIZE; - vlib_put_frame_queue_elt (hf); - current_worker_index = ~0; - handoff_queue_elt_by_worker_index[next_worker_index] = 0; - hf = 0; - } - } - else - { - do_handoff = 0; - /* if this is 1st frame */ - if (!f) - { - f = vlib_get_frame_to_node (vm, snat_out2in_node.index); - to_next = vlib_frame_vector_args (f); - } - - to_next[0] = bi0; - to_next += 1; - f->n_vectors++; - } - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_out2in_worker_handoff_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->next_worker_index = next_worker_index; - t->do_handoff = do_handoff; - } - } - - if (f) - vlib_put_frame_to_node (vm, snat_out2in_node.index, f); - - if (hf) - hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker; - - /* Ship frames to the worker nodes */ - for (i = 0; i < vec_len (handoff_queue_elt_by_worker_index); i++) - { - if (handoff_queue_elt_by_worker_index[i]) - { - hf = handoff_queue_elt_by_worker_index[i]; - /* - * It works better to let the handoff node - * rate-adapt, always ship the handoff queue element. - */ - if (1 || hf->n_vectors == hf->last_n_vectors) - { - vlib_put_frame_queue_elt (hf); - handoff_queue_elt_by_worker_index[i] = 0; - } - else - hf->last_n_vectors = hf->n_vectors; - } - congested_handoff_queue_by_worker_index[i] = - (vlib_frame_queue_t *) (~0); - } - hf = 0; - current_worker_index = ~0; - return frame->n_vectors; -} - -VLIB_REGISTER_NODE (snat_out2in_worker_handoff_node) = { - .function = snat_out2in_worker_handoff_fn, - .name = "snat-out2in-worker-handoff", - .vector_size = sizeof (u32), - .format_trace = format_snat_out2in_worker_handoff_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_next_nodes = 1, - - .next_nodes = { - [0] = "error-drop", - }, -}; - -VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_worker_handoff_node, snat_out2in_worker_handoff_fn); - -static inline u32 icmp_out2in_fast (snat_main_t *sm, - vlib_buffer_t * b0, - ip4_header_t * ip0, - icmp46_header_t * icmp0, - u32 sw_if_index0, - vlib_node_runtime_t * node, - u32 next0, - u32 rx_fib_index0) -{ - snat_session_key_t key0, sm0; - icmp_echo_header_t *echo0; - u32 new_addr0, old_addr0; - u16 old_id0, new_id0; - ip_csum_t sum0; - snat_runtime_t * rt = (snat_runtime_t *)node->runtime_data; - - echo0 = (icmp_echo_header_t *)(icmp0+1); - - key0.addr = ip0->dst_address; - key0.port = echo0->identifier; - key0.fib_index = rx_fib_index0; - - if (snat_static_mapping_match(sm, key0, &sm0, 1)) - { - ip4_address_t * first_int_addr; - - if (PREDICT_FALSE(rt->cached_sw_if_index != sw_if_index0)) - { - first_int_addr = - ip4_interface_first_address (sm->ip4_main, sw_if_index0, - 0 /* just want the address */); - rt->cached_sw_if_index = sw_if_index0; - rt->cached_ip4_address = first_int_addr->as_u32; - } - - /* Don't NAT packet aimed at the intfc address */ - if (PREDICT_FALSE(ip0->dst_address.as_u32 == - rt->cached_ip4_address)) - return next0; - - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - return SNAT_OUT2IN_NEXT_DROP; - } - - new_addr0 = sm0.addr.as_u32; - new_id0 = sm0.port; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index; - - old_addr0 = ip0->dst_address.as_u32; - ip0->dst_address.as_u32 = new_addr0; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - if (PREDICT_FALSE(new_id0 != echo0->identifier)) - { - old_id0 = echo0->identifier; - echo0->identifier = new_id0; - - sum0 = icmp0->checksum; - sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t, - identifier); - icmp0->checksum = ip_csum_fold (sum0); - } - - return next0; -} - -static uword -snat_out2in_fast_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - u32 n_left_from, * from, * to_next; - snat_out2in_next_t next_index; - u32 pkts_processed = 0; - snat_main_t * sm = &snat_main; - - 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 > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t * b0; - u32 next0 = SNAT_OUT2IN_NEXT_DROP; - u32 sw_if_index0; - ip4_header_t * ip0; - ip_csum_t sum0; - u32 new_addr0, old_addr0; - u16 new_port0, old_port0; - udp_header_t * udp0; - tcp_header_t * tcp0; - icmp46_header_t * icmp0; - snat_session_key_t key0, sm0; - u32 proto0; - u32 rx_fib_index0; - - /* 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); - - ip0 = vlib_buffer_get_current (b0); - udp0 = ip4_next_header (ip0); - tcp0 = (tcp_header_t *) udp0; - icmp0 = (icmp46_header_t *) udp0; - - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0); - - vnet_feature_next (sw_if_index0, &next0, b0); - - proto0 = ~0; - proto0 = (ip0->protocol == IP_PROTOCOL_UDP) - ? SNAT_PROTOCOL_UDP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_TCP) - ? SNAT_PROTOCOL_TCP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_ICMP) - ? SNAT_PROTOCOL_ICMP : proto0; - - if (PREDICT_FALSE (proto0 == ~0)) - goto trace00; - - if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) - { - next0 = icmp_out2in_fast - (sm, b0, ip0, icmp0, sw_if_index0, node, next0, rx_fib_index0); - goto trace00; - } - - key0.addr = ip0->dst_address; - key0.port = udp0->dst_port; - key0.fib_index = rx_fib_index0; - - if (snat_static_mapping_match(sm, key0, &sm0, 1)) - { - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - goto trace00; - } - - new_addr0 = sm0.addr.as_u32; - new_port0 = sm0.port; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index; - old_addr0 = ip0->dst_address.as_u32; - ip0->dst_address.as_u32 = new_addr0; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - if (PREDICT_FALSE(new_port0 != udp0->dst_port)) - { - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - old_port0 = tcp0->ports.dst; - tcp0->ports.dst = new_port0; - - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - - sum0 = ip_csum_update (sum0, old_port0, new_port0, - ip4_header_t /* cheat */, - length /* changed member */); - tcp0->checksum = ip_csum_fold(sum0); - } - else - { - old_port0 = udp0->dst_port; - udp0->dst_port = new_port0; - udp0->checksum = 0; - } - } - else - { - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - - tcp0->checksum = ip_csum_fold(sum0); - } - } - - trace00: - - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_out2in_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - t->next_index = next0; - } - - pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP; - - /* 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, snat_out2in_fast_node.index, - SNAT_OUT2IN_ERROR_OUT2IN_PACKETS, - pkts_processed); - return frame->n_vectors; -} - -VLIB_REGISTER_NODE (snat_out2in_fast_node) = { - .function = snat_out2in_fast_node_fn, - .name = "snat-out2in-fast", - .vector_size = sizeof (u32), - .format_trace = format_snat_out2in_fast_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(snat_out2in_error_strings), - .error_strings = snat_out2in_error_strings, - - .runtime_data_bytes = sizeof (snat_runtime_t), - - .n_next_nodes = SNAT_OUT2IN_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup", - [SNAT_OUT2IN_NEXT_DROP] = "error-drop", - }, -}; -VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_fast_node, snat_out2in_fast_node_fn); diff --git a/plugins/snat-plugin/snat/snat.api b/plugins/snat-plugin/snat/snat.api deleted file mode 100644 index a191eed5..00000000 --- a/plugins/snat-plugin/snat/snat.api +++ /dev/null @@ -1,283 +0,0 @@ -/* - * 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. - */ -/** - * @file snat.api - * @brief VPP control-plane API messages. - * - * This file defines VPP control-plane API messages which are generally - * called through a shared memory interface. - */ - -/** \brief Add/del S-NAT address range - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param is_ip4 - 1 if address type is IPv4 - @first_ip_address - first IP address - @last_ip_address - last IP address - @is_add - 1 if add, 0 if delete -*/ -define snat_add_address_range { - u32 client_index; - u32 context; - u8 is_ip4; - u8 first_ip_address[16]; - u8 last_ip_address[16]; - u8 is_add; -}; - -/** \brief Add S-NAT address range reply - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param retval - return code -*/ -define snat_add_address_range_reply { - u32 context; - i32 retval; -}; - -/** \brief Dump S-NAT addresses - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define snat_address_dump { - u32 client_index; - u32 context; -}; - -/** \brief S-NAT address details response - @param context - sender context, to match reply w/ request - @param is_ip4 - 1 if address type is IPv4 - @param ip_address - IP address -*/ -define snat_address_details { - u32 context; - u8 is_ip4; - u8 ip_address[16]; -}; - -/** \brief Enable/disable S-NAT feature on the interface - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param is_add - 1 if add, 0 if delete - @param is_inside - 1 if inside, 0 if outside - @param sw_if_index - software index of the interface -*/ -define snat_interface_add_del_feature { - u32 client_index; - u32 context; - u8 is_add; - u8 is_inside; - u32 sw_if_index; -}; - -/** \brief Enable/disable S-NAT feature on the interface reply - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param retval - return code -*/ -define snat_interface_add_del_feature_reply { - u32 context; - i32 retval; -}; - -/** \brief Dump interfaces with S-NAT feature - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define snat_interface_dump { - u32 client_index; - u32 context; -}; - -/** \brief S-NAT interface details response - @param context - sender context, to match reply w/ request - @param is_inside - 1 if inside, 0 if outside - @param sw_if_index - software index of the interface -*/ -define snat_interface_details { - u32 context; - u8 is_inside; - u32 sw_if_index; -}; - -/** \brief Add/delete S-NAT static mapping - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param is_add - 1 if add, 0 if delete - @param is_ip4 - 1 if address type is IPv4 - @param addr_only - 1 if address only mapping - @param local_ip_address - local IP address - @param external_ip_address - external IP address - @param local_port - local port number - @param external_port - external port number - @param vfr_id - VRF ID -*/ -define snat_add_static_mapping { - u32 client_index; - u32 context; - u8 is_add; - u8 is_ip4; - u8 addr_only; - u8 local_ip_address[16]; - u8 external_ip_address[16]; - u16 local_port; - u16 external_port; - u32 vrf_id; -}; - -/** \brief Add/delete S-NAT static mapping reply - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param retval - return code -*/ -define snat_add_static_mapping_reply { - u32 context; - i32 retval; -}; - -/** \brief Dump S-NAT static mappings - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define snat_static_mapping_dump { - u32 client_index; - u32 context; -}; - -/** \brief S-NAT static mapping details response - @param context - sender context, to match reply w/ request - @param is_ip4 - 1 if address type is IPv4 - @param addr_only - 1 if address only mapping - @param local_ip_address - local IP address - @param external_ip_address - external IP address - @param local_port - local port number - @param external_port - external port number - @param vfr_id - VRF ID -*/ -define snat_static_mapping_details { - u32 context; - u8 is_ip4; - u8 addr_only; - u8 local_ip_address[16]; - u8 external_ip_address[16]; - u16 local_port; - u16 external_port; - u32 vrf_id; -}; - -/** \brief Control ping from client to api server request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define snat_control_ping -{ - u32 client_index; - u32 context; -}; - -/** \brief Control ping from the client to the server response - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param retval - return code for the request - @param vpe_pid - the pid of the vpe, returned by the server -*/ -define snat_control_ping_reply -{ - u32 context; - i32 retval; - u32 client_index; - u32 vpe_pid; -}; - -/** \brief Show S-NAT plugin startup config - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define snat_show_config -{ - u32 client_index; - u32 context; -}; - -/** \brief Show S-NAT plugin startup config reply - @param context - sender context, to match reply w/ request - @param retval - return code for the request - @param static_mapping_only - if 1 dynamic translations disabled - @param static_mapping_connection_tracking - if 1 create session data - @param translation_buckets - number of translation hash buckets - @param translation_memory_size - translation hash memory size - @param user_buckets - number of user hash buckets - @param user_memory_size - user hash memory size - @param max_translations_per_user - maximum number of translations per user - @param outside_vrf_id - outside VRF id - @param inside_vrf_id - default inside VRF id -*/ -define snat_show_config_reply -{ - u32 context; - i32 retval; - u8 static_mapping_only; - u8 static_mapping_connection_tracking; - u32 translation_buckets; - u32 translation_memory_size; - u32 user_buckets; - u32 user_memory_size; - u32 max_translations_per_user; - u32 outside_vrf_id; - u32 inside_vrf_id; -}; - -/** \brief Set S-NAT workers - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param worker_mask - S-NAT workers mask -*/ -define snat_set_workers { - u32 client_index; - u32 context; - u64 worker_mask; -}; - -/** \brief Set S-NAT workers reply - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param retval - return code -*/ -define snat_set_workers_reply { - u32 context; - i32 retval; -}; - -/** \brief Dump S-NAT workers - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define snat_worker_dump { - u32 client_index; - u32 context; -}; - -/** \brief S-NAT workers details response - @param context - sender context, to match reply w/ request - @param worker_index - worker index - @param lcore_id - lcore ID - @param name - worker name -*/ -define snat_worker_details { - u32 context; - u32 worker_index; - u32 lcore_id; - u8 name[64]; -}; diff --git a/plugins/snat-plugin/snat/snat.c b/plugins/snat-plugin/snat/snat.c deleted file mode 100644 index bc995684..00000000 --- a/plugins/snat-plugin/snat/snat.c +++ /dev/null @@ -1,1957 +0,0 @@ -/* - * snat.c - simple nat plugin - * - * 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. - */ - -#include -#include -#include -#include - -#include -#include -#include - -snat_main_t snat_main; - -/* define message IDs */ -#include - -/* define message structures */ -#define vl_typedefs -#include -#undef vl_typedefs - -/* define generated endian-swappers */ -#define vl_endianfun -#include -#undef vl_endianfun - -#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) - -/* Get the API version number */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#undef vl_api_version - -/* Macro to finish up custom dump fns */ -#define FINISH \ - vec_add1 (s, 0); \ - vl_print (handle, (char *)s); \ - vec_free (s); \ - return handle; - -/* - * 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); - -#define REPLY_MACRO2(t, body) \ -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); \ - do {body;} while (0); \ - vl_msg_api_send_shmem (q, (u8 *)&rmp); \ -} while(0); - - -/* Hook up input features */ -VNET_FEATURE_INIT (ip4_snat_in2out, static) = { - .arc_name = "ip4-unicast", - .node_name = "snat-in2out", - .runs_before = VNET_FEATURES ("snat-out2in"), -}; -VNET_FEATURE_INIT (ip4_snat_out2in, static) = { - .arc_name = "ip4-unicast", - .node_name = "snat-out2in", - .runs_before = VNET_FEATURES ("ip4-lookup"), -}; -VNET_FEATURE_INIT (ip4_snat_in2out_worker_handoff, static) = { - .arc_name = "ip4-unicast", - .node_name = "snat-in2out-worker-handoff", - .runs_before = VNET_FEATURES ("snat-out2in-worker-handoff"), -}; -VNET_FEATURE_INIT (ip4_snat_out2in_worker_handoff, static) = { - .arc_name = "ip4-unicast", - .node_name = "snat-out2in-worker-handoff", - .runs_before = VNET_FEATURES ("ip4-lookup"), -}; -VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = { - .arc_name = "ip4-unicast", - .node_name = "snat-in2out-fast", - .runs_before = VNET_FEATURES ("snat-out2in-fast"), -}; -VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = { - .arc_name = "ip4-unicast", - .node_name = "snat-out2in-fast", - .runs_before = VNET_FEATURES ("ip4-lookup"), -}; - - -/* - * 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) -{ - snat_main_t * sm = &snat_main; - clib_error_t * error = 0; - - sm->vlib_main = vm; - sm->vnet_main = h->vnet_main; - sm->ethernet_main = h->ethernet_main; - - return error; -} - -/*$$$$$ move to an installed header file */ -#if (1 || CLIB_DEBUG > 0) /* "trust, but verify" */ - -#define VALIDATE_SW_IF_INDEX(mp) \ - do { u32 __sw_if_index = ntohl(mp->sw_if_index); \ - vnet_main_t *__vnm = vnet_get_main(); \ - if (pool_is_free_index(__vnm->interface_main.sw_interfaces, \ - __sw_if_index)) { \ - rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; \ - goto bad_sw_if_index; \ - } \ -} while(0); - -#define BAD_SW_IF_INDEX_LABEL \ -do { \ -bad_sw_if_index: \ - ; \ -} while (0); - -#define VALIDATE_RX_SW_IF_INDEX(mp) \ - do { u32 __rx_sw_if_index = ntohl(mp->rx_sw_if_index); \ - vnet_main_t *__vnm = vnet_get_main(); \ - if (pool_is_free_index(__vnm->interface_main.sw_interfaces, \ - __rx_sw_if_index)) { \ - rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; \ - goto bad_rx_sw_if_index; \ - } \ -} while(0); - -#define BAD_RX_SW_IF_INDEX_LABEL \ -do { \ -bad_rx_sw_if_index: \ - ; \ -} while (0); - -#define VALIDATE_TX_SW_IF_INDEX(mp) \ - do { u32 __tx_sw_if_index = ntohl(mp->tx_sw_if_index); \ - vnet_main_t *__vnm = vnet_get_main(); \ - if (pool_is_free_index(__vnm->interface_main.sw_interfaces, \ - __tx_sw_if_index)) { \ - rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; \ - goto bad_tx_sw_if_index; \ - } \ -} while(0); - -#define BAD_TX_SW_IF_INDEX_LABEL \ -do { \ -bad_tx_sw_if_index: \ - ; \ -} while (0); - -#else - -#define VALIDATE_SW_IF_INDEX(mp) -#define BAD_SW_IF_INDEX_LABEL -#define VALIDATE_RX_SW_IF_INDEX(mp) -#define BAD_RX_SW_IF_INDEX_LABEL -#define VALIDATE_TX_SW_IF_INDEX(mp) -#define BAD_TX_SW_IF_INDEX_LABEL - -#endif /* CLIB_DEBUG > 0 */ - -void snat_add_address (snat_main_t *sm, ip4_address_t *addr) -{ - snat_address_t * ap; - - /* Check if address already exists */ - vec_foreach (ap, sm->addresses) - { - if (ap->addr.as_u32 == addr->as_u32) - return; - } - - vec_add2 (sm->addresses, ap, 1); - ap->addr = *addr; - clib_bitmap_alloc (ap->busy_port_bitmap, 65535); -} - -static int is_snat_address_used_in_static_mapping (snat_main_t *sm, - ip4_address_t addr) -{ - snat_static_mapping_t *m; - pool_foreach (m, sm->static_mappings, - ({ - if (m->external_addr.as_u32 == addr.as_u32) - return 1; - })); - - return 0; -} - -int snat_del_address (snat_main_t *sm, ip4_address_t addr) -{ - snat_address_t *a = 0; - snat_session_t *ses; - u32 *ses_to_be_removed = 0, *ses_index; - clib_bihash_kv_8_8_t kv, value; - snat_user_key_t user_key; - snat_user_t *u; - snat_main_per_thread_data_t *tsm; - - int i; - - /* Find SNAT address */ - for (i=0; i < vec_len (sm->addresses); i++) - { - if (sm->addresses[i].addr.as_u32 == addr.as_u32) - { - a = sm->addresses + i; - break; - } - } - if (!a) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - /* Check if address is used in some static mapping */ - if (is_snat_address_used_in_static_mapping(sm, addr)) - { - clib_warning ("address used in static mapping"); - return VNET_API_ERROR_UNSPECIFIED; - } - - /* Delete sessions using address */ - if (a->busy_ports) - { - vec_foreach (tsm, sm->per_thread_data) - { - pool_foreach (ses, tsm->sessions, ({ - if (ses->out2in.addr.as_u32 == addr.as_u32) - { - vec_add1 (ses_to_be_removed, ses - tsm->sessions); - kv.key = ses->in2out.as_u64; - clib_bihash_add_del_8_8 (&sm->in2out, &kv, 0); - kv.key = ses->out2in.as_u64; - clib_bihash_add_del_8_8 (&sm->out2in, &kv, 0); - clib_dlist_remove (tsm->list_pool, ses->per_user_index); - user_key.addr = ses->in2out.addr; - user_key.fib_index = ses->in2out.fib_index; - kv.key = user_key.as_u64; - if (!clib_bihash_search_8_8 (&sm->user_hash, &kv, &value)) - { - u = pool_elt_at_index (tsm->users, value.value); - u->nsessions--; - } - } - })); - - vec_foreach (ses_index, ses_to_be_removed) - pool_put_index (tsm->sessions, ses_index[0]); - - vec_free (ses_to_be_removed); - } - } - - vec_del1 (sm->addresses, i); - - return 0; -} - -static void increment_v4_address (ip4_address_t * a) -{ - u32 v; - - v = clib_net_to_host_u32(a->as_u32) + 1; - a->as_u32 = clib_host_to_net_u32(v); -} - -/** - * @brief Add static mapping. - * - * Create static mapping between local addr+port and external addr+port. - * - * @param l_addr Local IPv4 address. - * @param e_addr External IPv4 address. - * @param l_port Local port number. - * @param e_port External port number. - * @param vrf_id VRF ID. - * @param addr_only If 0 address port and pair mapping, otherwise address only. - * @param is_add If 0 delete static mapping, otherwise add. - * - * @returns - */ -int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, - u16 l_port, u16 e_port, u32 vrf_id, int addr_only, - int is_add) -{ - snat_main_t * sm = &snat_main; - snat_static_mapping_t *m; - snat_static_mapping_key_t m_key; - clib_bihash_kv_8_8_t kv, value; - snat_address_t *a = 0; - u32 fib_index = ~0; - uword * p; - int i; - - /* If outside FIB index is not resolved yet */ - if (sm->outside_fib_index == ~0) - { - p = hash_get (sm->ip4_main->fib_index_by_table_id, sm->outside_vrf_id); - if (!p) - return VNET_API_ERROR_NO_SUCH_FIB; - sm->outside_fib_index = p[0]; - } - - m_key.addr = e_addr; - m_key.port = addr_only ? 0 : e_port; - m_key.fib_index = sm->outside_fib_index; - kv.key = m_key.as_u64; - if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value)) - m = 0; - else - m = pool_elt_at_index (sm->static_mappings, value.value); - - if (is_add) - { - if (m) - return VNET_API_ERROR_VALUE_EXIST; - - /* Convert VRF id to FIB index */ - if (vrf_id != ~0) - { - p = hash_get (sm->ip4_main->fib_index_by_table_id, vrf_id); - if (!p) - return VNET_API_ERROR_NO_SUCH_FIB; - fib_index = p[0]; - } - /* If not specified use inside VRF id from SNAT plugin startup config */ - else - { - if (sm->inside_fib_index == ~0) - { - p = hash_get (sm->ip4_main->fib_index_by_table_id, sm->inside_vrf_id); - if (!p) - return VNET_API_ERROR_NO_SUCH_FIB; - fib_index = p[0]; - sm->inside_fib_index = fib_index; - } - else - fib_index = sm->inside_fib_index; - - vrf_id = sm->inside_vrf_id; - } - - /* Find external address in allocated addresses and reserve port for - address and port pair mapping when dynamic translations enabled */ - if (!addr_only && !(sm->static_mapping_only)) - { - for (i = 0; i < vec_len (sm->addresses); i++) - { - if (sm->addresses[i].addr.as_u32 == e_addr.as_u32) - { - a = sm->addresses + i; - /* External port must be unused */ - if (clib_bitmap_get_no_check (a->busy_port_bitmap, e_port)) - return VNET_API_ERROR_INVALID_VALUE; - clib_bitmap_set_no_check (a->busy_port_bitmap, e_port, 1); - if (e_port > 1024) - a->busy_ports++; - - break; - } - } - /* External address must be allocated */ - if (!a) - return VNET_API_ERROR_NO_SUCH_ENTRY; - } - - pool_get (sm->static_mappings, m); - memset (m, 0, sizeof (*m)); - m->local_addr = l_addr; - m->external_addr = e_addr; - m->addr_only = addr_only; - m->vrf_id = vrf_id; - m->fib_index = fib_index; - if (!addr_only) - { - m->local_port = l_port; - m->external_port = e_port; - } - - m_key.addr = m->local_addr; - m_key.port = m->local_port; - m_key.fib_index = m->fib_index; - kv.key = m_key.as_u64; - kv.value = m - sm->static_mappings; - clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1); - - m_key.addr = m->external_addr; - m_key.port = m->external_port; - m_key.fib_index = sm->outside_fib_index; - kv.key = m_key.as_u64; - kv.value = m - sm->static_mappings; - clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1); - - /* Assign worker */ - if (sm->workers) - { - snat_user_key_t w_key0; - snat_static_mapping_key_t w_key1; - - w_key0.addr = m->local_addr; - w_key0.fib_index = m->fib_index; - kv.key = w_key0.as_u64; - - if (clib_bihash_search_8_8 (&sm->worker_by_in, &kv, &value)) - { - kv.value = sm->first_worker_index + - sm->workers[sm->next_worker++ % vec_len (sm->workers)]; - - clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv, 1); - } - else - { - kv.value = value.value; - } - - w_key1.addr = m->external_addr; - w_key1.port = clib_host_to_net_u16 (m->external_port); - w_key1.fib_index = sm->outside_fib_index; - kv.key = w_key1.as_u64; - clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv, 1); - } - } - else - { - if (!m) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - /* Free external address port */ - if (!addr_only && !(sm->static_mapping_only)) - { - for (i = 0; i < vec_len (sm->addresses); i++) - { - if (sm->addresses[i].addr.as_u32 == e_addr.as_u32) - { - a = sm->addresses + i; - clib_bitmap_set_no_check (a->busy_port_bitmap, e_port, 0); - a->busy_ports--; - - break; - } - } - } - - m_key.addr = m->local_addr; - m_key.port = m->local_port; - m_key.fib_index = m->fib_index; - kv.key = m_key.as_u64; - clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0); - - m_key.addr = m->external_addr; - m_key.port = m->external_port; - m_key.fib_index = sm->outside_fib_index; - kv.key = m_key.as_u64; - clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0); - - /* Delete session(s) for static mapping if exist */ - if (!(sm->static_mapping_only) || - (sm->static_mapping_only && sm->static_mapping_connection_tracking)) - { - snat_user_key_t u_key; - snat_user_t *u; - dlist_elt_t * head, * elt; - u32 elt_index, head_index, del_elt_index; - u32 ses_index; - u64 user_index; - snat_session_t * s; - snat_main_per_thread_data_t *tsm; - - u_key.addr = m->local_addr; - u_key.fib_index = m->fib_index; - kv.key = u_key.as_u64; - if (!clib_bihash_search_8_8 (&sm->user_hash, &kv, &value)) - { - user_index = value.value; - if (!clib_bihash_search_8_8 (&sm->worker_by_in, &kv, &value)) - tsm = vec_elt_at_index (sm->per_thread_data, value.value); - else - tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); - u = pool_elt_at_index (tsm->users, user_index); - if (u->nstaticsessions) - { - head_index = u->sessions_per_user_list_head_index; - head = pool_elt_at_index (tsm->list_pool, head_index); - elt_index = head->next; - elt = pool_elt_at_index (tsm->list_pool, elt_index); - ses_index = elt->value; - while (ses_index != ~0) - { - s = pool_elt_at_index (tsm->sessions, ses_index); - del_elt_index = elt_index; - elt_index = elt->next; - elt = pool_elt_at_index (tsm->list_pool, elt_index); - ses_index = elt->value; - - if (!addr_only) - { - if ((s->out2in.addr.as_u32 != e_addr.as_u32) && - (clib_net_to_host_u16 (s->out2in.port) != e_port)) - continue; - } - - value.key = s->in2out.as_u64; - clib_bihash_add_del_8_8 (&sm->in2out, &value, 0); - value.key = s->out2in.as_u64; - clib_bihash_add_del_8_8 (&sm->out2in, &value, 0); - pool_put (tsm->sessions, s); - - clib_dlist_remove (tsm->list_pool, del_elt_index); - pool_put_index (tsm->list_pool, del_elt_index); - u->nstaticsessions--; - - if (!addr_only) - break; - } - if (addr_only) - { - pool_put (tsm->users, u); - clib_bihash_add_del_8_8 (&sm->user_hash, &kv, 0); - } - } - } - } - - /* Delete static mapping from pool */ - pool_put (sm->static_mappings, m); - } - - return 0; -} - -static int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del) -{ - snat_main_t *sm = &snat_main; - snat_interface_t *i; - const char * feature_name; - - if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)) - feature_name = is_inside ? "snat-in2out-fast" : "snat-out2in-fast"; - else - { - if (sm->num_workers > 1) - feature_name = is_inside ? "snat-in2out-worker-handoff" : "snat-out2in-worker-handoff"; - else - feature_name = is_inside ? "snat-in2out" : "snat-out2in"; - } - - vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, - !is_del, 0, 0); - - if (sm->fq_in2out_index == ~0) - sm->fq_in2out_index = vlib_frame_queue_main_init (snat_in2out_node.index, 0); - - if (sm->fq_out2in_index == ~0) - sm->fq_out2in_index = vlib_frame_queue_main_init (snat_out2in_node.index, 0); - - pool_foreach (i, sm->interfaces, - ({ - if (i->sw_if_index == sw_if_index) - { - if (is_del) - pool_put (sm->interfaces, i); - else - return VNET_API_ERROR_VALUE_EXIST; - - return 0; - } - })); - - if (is_del) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - pool_get (sm->interfaces, i); - i->sw_if_index = sw_if_index; - i->is_inside = is_inside; - - return 0; -} - -static int snat_set_workers (uword * bitmap) -{ - snat_main_t *sm = &snat_main; - int i; - - if (sm->num_workers < 2) - return VNET_API_ERROR_FEATURE_DISABLED; - - if (clib_bitmap_last_set (bitmap) >= sm->num_workers) - return VNET_API_ERROR_INVALID_WORKER; - - vec_free (sm->workers); - clib_bitmap_foreach (i, bitmap, - ({ - vec_add1(sm->workers, i); - })); - - return 0; -} - -static void -vl_api_snat_add_address_range_t_handler -(vl_api_snat_add_address_range_t * mp) -{ - snat_main_t * sm = &snat_main; - vl_api_snat_add_address_range_reply_t * rmp; - ip4_address_t this_addr; - u32 start_host_order, end_host_order; - int i, count; - int rv = 0; - u32 * tmp; - - if (mp->is_ip4 != 1) - { - rv = VNET_API_ERROR_UNIMPLEMENTED; - goto send_reply; - } - - if (sm->static_mapping_only) - { - rv = VNET_API_ERROR_FEATURE_DISABLED; - goto send_reply; - } - - tmp = (u32 *) mp->first_ip_address; - start_host_order = clib_host_to_net_u32 (tmp[0]); - tmp = (u32 *) mp->last_ip_address; - end_host_order = clib_host_to_net_u32 (tmp[0]); - - count = (end_host_order - start_host_order) + 1; - - if (count > 1024) - clib_warning ("%U - %U, %d addresses...", - format_ip4_address, mp->first_ip_address, - format_ip4_address, mp->last_ip_address, - count); - - memcpy (&this_addr.as_u8, mp->first_ip_address, 4); - - for (i = 0; i < count; i++) - { - if (mp->is_add) - snat_add_address (sm, &this_addr); - else - rv = snat_del_address (sm, this_addr); - - if (rv) - goto send_reply; - - increment_v4_address (&this_addr); - } - - send_reply: - REPLY_MACRO (VL_API_SNAT_ADD_ADDRESS_RANGE_REPLY); -} - -static void *vl_api_snat_add_address_range_t_print -(vl_api_snat_add_address_range_t *mp, void * handle) -{ - u8 * s; - - s = format (0, "SCRIPT: snat_add_address_range "); - s = format (s, "%U ", format_ip4_address, mp->first_ip_address); - if (memcmp (mp->first_ip_address, mp->last_ip_address, 4)) - { - s = format (s, " - %U ", format_ip4_address, mp->last_ip_address); - } - FINISH; -} - -static void -send_snat_address_details -(snat_address_t * a, unix_shared_memory_queue_t * q, u32 context) -{ - vl_api_snat_address_details_t *rmp; - snat_main_t * sm = &snat_main; - - rmp = vl_msg_api_alloc (sizeof (*rmp)); - memset (rmp, 0, sizeof (*rmp)); - rmp->_vl_msg_id = ntohs (VL_API_SNAT_ADDRESS_DETAILS+sm->msg_id_base); - rmp->is_ip4 = 1; - clib_memcpy (rmp->ip_address, &(a->addr), 4); - rmp->context = context; - - vl_msg_api_send_shmem (q, (u8 *) & rmp); -} - -static void -vl_api_snat_address_dump_t_handler -(vl_api_snat_address_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - snat_main_t * sm = &snat_main; - snat_address_t * a; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - return; - - vec_foreach (a, sm->addresses) - send_snat_address_details (a, q, mp->context); -} - -static void *vl_api_snat_address_dump_t_print -(vl_api_snat_address_dump_t *mp, void * handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_address_dump "); - - FINISH; -} - -static void -vl_api_snat_interface_add_del_feature_t_handler -(vl_api_snat_interface_add_del_feature_t * mp) -{ - snat_main_t * sm = &snat_main; - vl_api_snat_interface_add_del_feature_reply_t * rmp; - u8 is_del = mp->is_add == 0; - u32 sw_if_index = ntohl(mp->sw_if_index); - int rv = 0; - - VALIDATE_SW_IF_INDEX(mp); - - rv = snat_interface_add_del (sw_if_index, mp->is_inside, is_del); - - BAD_SW_IF_INDEX_LABEL; - - REPLY_MACRO(VL_API_SNAT_INTERFACE_ADD_DEL_FEATURE_REPLY); -} - -static void *vl_api_snat_interface_add_del_feature_t_print -(vl_api_snat_interface_add_del_feature_t * mp, void *handle) -{ - u8 * s; - - s = format (0, "SCRIPT: snat_interface_add_del_feature "); - s = format (s, "sw_if_index %d %s %s", - clib_host_to_net_u32(mp->sw_if_index), - mp->is_inside ? "in":"out", - mp->is_add ? "" : "del"); - - FINISH; -} - -static void -send_snat_interface_details -(snat_interface_t * i, unix_shared_memory_queue_t * q, u32 context) -{ - vl_api_snat_interface_details_t *rmp; - snat_main_t * sm = &snat_main; - - rmp = vl_msg_api_alloc (sizeof (*rmp)); - memset (rmp, 0, sizeof (*rmp)); - rmp->_vl_msg_id = ntohs (VL_API_SNAT_INTERFACE_DETAILS+sm->msg_id_base); - rmp->sw_if_index = ntohl (i->sw_if_index); - rmp->is_inside = i->is_inside; - rmp->context = context; - - vl_msg_api_send_shmem (q, (u8 *) & rmp); -} - -static void -vl_api_snat_interface_dump_t_handler -(vl_api_snat_interface_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - snat_main_t * sm = &snat_main; - snat_interface_t * i; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - return; - - pool_foreach (i, sm->interfaces, - ({ - send_snat_interface_details(i, q, mp->context); - })); -} - -static void *vl_api_snat_interface_dump_t_print -(vl_api_snat_interface_dump_t *mp, void * handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_interface_dump "); - - FINISH; -}static void - -vl_api_snat_add_static_mapping_t_handler -(vl_api_snat_add_static_mapping_t * mp) -{ - snat_main_t * sm = &snat_main; - vl_api_snat_add_static_mapping_reply_t * rmp; - ip4_address_t local_addr, external_addr; - u16 local_port = 0, external_port = 0; - u32 vrf_id; - int rv = 0; - - if (mp->is_ip4 != 1) - { - rv = VNET_API_ERROR_UNIMPLEMENTED; - goto send_reply; - } - - memcpy (&local_addr.as_u8, mp->local_ip_address, 4); - memcpy (&external_addr.as_u8, mp->external_ip_address, 4); - if (mp->addr_only == 0) - { - local_port = clib_net_to_host_u16 (mp->local_port); - external_port = clib_net_to_host_u16 (mp->external_port); - } - vrf_id = clib_net_to_host_u32 (mp->vrf_id); - - rv = snat_add_static_mapping(local_addr, external_addr, local_port, - external_port, vrf_id, mp->addr_only, - mp->is_add); - - send_reply: - REPLY_MACRO (VL_API_SNAT_ADD_ADDRESS_RANGE_REPLY); -} - -static void *vl_api_snat_add_static_mapping_t_print -(vl_api_snat_add_static_mapping_t *mp, void * handle) -{ - u8 * s; - - s = format (0, "SCRIPT: snat_add_static_mapping "); - s = format (s, "local_addr %U external_addr %U ", - format_ip4_address, mp->local_ip_address, - format_ip4_address, mp->external_ip_address); - - if (mp->addr_only == 0) - s = format (s, "local_port %d external_port %d ", - clib_net_to_host_u16 (mp->local_port), - clib_net_to_host_u16 (mp->external_port)); - - if (mp->vrf_id != ~0) - s = format (s, "vrf %d", clib_net_to_host_u32 (mp->vrf_id)); - - FINISH; -} - -static void -send_snat_static_mapping_details -(snat_static_mapping_t * m, unix_shared_memory_queue_t * q, u32 context) -{ - vl_api_snat_static_mapping_details_t *rmp; - snat_main_t * sm = &snat_main; - - rmp = vl_msg_api_alloc (sizeof (*rmp)); - memset (rmp, 0, sizeof (*rmp)); - rmp->_vl_msg_id = ntohs (VL_API_SNAT_STATIC_MAPPING_DETAILS+sm->msg_id_base); - rmp->is_ip4 = 1; - rmp->addr_only = m->addr_only; - clib_memcpy (rmp->local_ip_address, &(m->local_addr), 4); - clib_memcpy (rmp->external_ip_address, &(m->external_addr), 4); - rmp->local_port = htons (m->local_port); - rmp->external_port = htons (m->external_port); - rmp->vrf_id = htonl (m->vrf_id); - rmp->context = context; - - vl_msg_api_send_shmem (q, (u8 *) & rmp); -} - -static void -vl_api_snat_static_mapping_dump_t_handler -(vl_api_snat_static_mapping_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - snat_main_t * sm = &snat_main; - snat_static_mapping_t * m; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - return; - - pool_foreach (m, sm->static_mappings, - ({ - send_snat_static_mapping_details (m, q, mp->context); - })); -} - -static void *vl_api_snat_static_mapping_dump_t_print -(vl_api_snat_static_mapping_dump_t *mp, void * handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_static_mapping_dump "); - - FINISH; -} - -static void -vl_api_snat_control_ping_t_handler -(vl_api_snat_control_ping_t * mp) -{ - vl_api_snat_control_ping_reply_t *rmp; - snat_main_t * sm = &snat_main; - int rv = 0; - - REPLY_MACRO2(VL_API_SNAT_CONTROL_PING_REPLY, - ({ - rmp->vpe_pid = ntohl (getpid()); - })); -} - -static void *vl_api_snat_control_ping_t_print -(vl_api_snat_control_ping_t *mp, void * handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_control_ping "); - - FINISH; -} - -static void -vl_api_snat_show_config_t_handler -(vl_api_snat_show_config_t * mp) -{ - vl_api_snat_show_config_reply_t *rmp; - snat_main_t * sm = &snat_main; - int rv = 0; - - REPLY_MACRO2(VL_API_SNAT_SHOW_CONFIG_REPLY, - ({ - rmp->translation_buckets = htonl (sm->translation_buckets); - rmp->translation_memory_size = htonl (sm->translation_memory_size); - rmp->user_buckets = htonl (sm->user_buckets); - rmp->user_memory_size = htonl (sm->user_memory_size); - rmp->max_translations_per_user = htonl (sm->max_translations_per_user); - rmp->outside_vrf_id = htonl (sm->outside_vrf_id); - rmp->inside_vrf_id = htonl (sm->inside_vrf_id); - rmp->static_mapping_only = sm->static_mapping_only; - rmp->static_mapping_connection_tracking = - sm->static_mapping_connection_tracking; - })); -} - -static void *vl_api_snat_show_config_t_print -(vl_api_snat_show_config_t *mp, void * handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_show_config "); - - FINISH; -} - -static void -vl_api_snat_set_workers_t_handler -(vl_api_snat_set_workers_t * mp) -{ - snat_main_t * sm = &snat_main; - vl_api_snat_set_workers_reply_t * rmp; - int rv = 0; - uword *bitmap = 0; - u64 mask = clib_net_to_host_u64 (mp->worker_mask); - - if (sm->num_workers < 2) - { - rv = VNET_API_ERROR_FEATURE_DISABLED; - goto send_reply; - } - - bitmap = clib_bitmap_set_multiple (bitmap, 0, mask, BITS (mask)); - rv = snat_set_workers(bitmap); - clib_bitmap_free (bitmap); - - send_reply: - REPLY_MACRO (VL_API_SNAT_SET_WORKERS_REPLY); -} - -static void *vl_api_snat_set_workers_t_print -(vl_api_snat_set_workers_t *mp, void * handle) -{ - u8 * s; - uword *bitmap = 0; - u8 first = 1; - int i; - u64 mask = clib_net_to_host_u64 (mp->worker_mask); - - s = format (0, "SCRIPT: snat_set_workers "); - bitmap = clib_bitmap_set_multiple (bitmap, 0, mask, BITS (mask)); - clib_bitmap_foreach (i, bitmap, - ({ - if (first) - s = format (s, "%d", i); - else - s = format (s, ",%d", i); - first = 0; - })); - clib_bitmap_free (bitmap); - FINISH; -} - -static void -send_snat_worker_details -(u32 worker_index, unix_shared_memory_queue_t * q, u32 context) -{ - vl_api_snat_worker_details_t *rmp; - snat_main_t * sm = &snat_main; - vlib_worker_thread_t *w = - vlib_worker_threads + worker_index + sm->first_worker_index; - - rmp = vl_msg_api_alloc (sizeof (*rmp)); - memset (rmp, 0, sizeof (*rmp)); - rmp->_vl_msg_id = ntohs (VL_API_SNAT_WORKER_DETAILS+sm->msg_id_base); - rmp->context = context; - rmp->worker_index = htonl (worker_index); - rmp->lcore_id = htonl (w->lcore_id); - strncpy ((char *) rmp->name, (char *) w->name, ARRAY_LEN (rmp->name) - 1); - - vl_msg_api_send_shmem (q, (u8 *) & rmp); -} - -static void -vl_api_snat_worker_dump_t_handler -(vl_api_snat_worker_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - snat_main_t * sm = &snat_main; - u32 * worker_index; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - return; - - vec_foreach (worker_index, sm->workers) - { - send_snat_worker_details(*worker_index, q, mp->context); - } -} - -static void *vl_api_snat_worker_dump_t_print -(vl_api_snat_worker_dump_t *mp, void * handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_worker_dump "); - - FINISH; -} - -/* List of message types that this plugin understands */ -#define foreach_snat_plugin_api_msg \ -_(SNAT_ADD_ADDRESS_RANGE, snat_add_address_range) \ -_(SNAT_INTERFACE_ADD_DEL_FEATURE, snat_interface_add_del_feature) \ -_(SNAT_ADD_STATIC_MAPPING, snat_add_static_mapping) \ -_(SNAT_CONTROL_PING, snat_control_ping) \ -_(SNAT_STATIC_MAPPING_DUMP, snat_static_mapping_dump) \ -_(SNAT_SHOW_CONFIG, snat_show_config) \ -_(SNAT_ADDRESS_DUMP, snat_address_dump) \ -_(SNAT_INTERFACE_DUMP, snat_interface_dump) \ -_(SNAT_SET_WORKERS, snat_set_workers) \ -_(SNAT_WORKER_DUMP, snat_worker_dump) - -/* Set up the API message handling tables */ -static clib_error_t * -snat_plugin_api_hookup (vlib_main_t *vm) -{ - snat_main_t * sm __attribute__ ((unused)) = &snat_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_snat_plugin_api_msg; -#undef _ - - return 0; -} - -#define vl_msg_name_crc_list -#include -#undef vl_msg_name_crc_list - -static void -setup_message_id_table (snat_main_t * sm, api_main_t * am) -{ -#define _(id,n,crc) \ - vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base); - foreach_vl_msg_name_crc_snat; -#undef _ -} - -static void plugin_custom_dump_configure (snat_main_t * sm) -{ -#define _(n,f) sm->api_main->msg_print_handlers \ - [VL_API_##n + sm->msg_id_base] \ - = (void *) vl_api_##f##_t_print; - foreach_snat_plugin_api_msg; -#undef _ -} - -static clib_error_t * snat_init (vlib_main_t * vm) -{ - snat_main_t * sm = &snat_main; - clib_error_t * error = 0; - ip4_main_t * im = &ip4_main; - ip_lookup_main_t * lm = &im->lookup_main; - u8 * name; - uword *p; - vlib_thread_registration_t *tr; - vlib_thread_main_t *tm = vlib_get_thread_main (); - uword *bitmap = 0; - u32 i; - - name = format (0, "snat_%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); - - sm->vlib_main = vm; - sm->vnet_main = vnet_get_main(); - sm->ip4_main = im; - sm->ip4_lookup_main = lm; - sm->api_main = &api_main; - sm->first_worker_index = 0; - sm->next_worker = 0; - sm->num_workers = 0; - sm->workers = 0; - sm->fq_in2out_index = ~0; - sm->fq_out2in_index = ~0; - - p = hash_get_mem (tm->thread_registrations_by_name, "workers"); - if (p) - { - tr = (vlib_thread_registration_t *) p[0]; - if (tr) - { - sm->num_workers = tr->count; - sm->first_worker_index = tr->first_index; - } - } - - /* Use all available workers by default */ - if (sm->num_workers > 1) - { - for (i=0; i < sm->num_workers; i++) - bitmap = clib_bitmap_set (bitmap, i, 1); - snat_set_workers(bitmap); - clib_bitmap_free (bitmap); - } - - error = snat_plugin_api_hookup (vm); - - /* Add our API messages to the global name_crc hash table */ - setup_message_id_table (sm, &api_main); - - plugin_custom_dump_configure (sm); - vec_free(name); - - return error; -} - -VLIB_INIT_FUNCTION (snat_init); - -void snat_free_outside_address_and_port (snat_main_t * sm, - snat_session_key_t * k, - u32 address_index) -{ - snat_address_t *a; - u16 port_host_byte_order = clib_net_to_host_u16 (k->port); - - ASSERT (address_index < vec_len (sm->addresses)); - - a = sm->addresses + address_index; - - ASSERT (clib_bitmap_get_no_check (a->busy_port_bitmap, - port_host_byte_order) == 1); - - clib_bitmap_set_no_check (a->busy_port_bitmap, port_host_byte_order, 0); - a->busy_ports--; -} - -/** - * @brief Match SNAT static mapping. - * - * @param sm SNAT main. - * @param match Address and port to match. - * @param mapping External or local address and port of the matched mapping. - * @param by_external If 0 match by local address otherwise match by external - * address. - * - * @returns 0 if match found otherwise 1. - */ -int snat_static_mapping_match (snat_main_t * sm, - snat_session_key_t match, - snat_session_key_t * mapping, - u8 by_external) -{ - clib_bihash_kv_8_8_t kv, value; - snat_static_mapping_t *m; - snat_static_mapping_key_t m_key; - clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local; - - if (by_external) - mapping_hash = &sm->static_mapping_by_external; - - m_key.addr = match.addr; - m_key.port = clib_net_to_host_u16 (match.port); - m_key.fib_index = match.fib_index; - - kv.key = m_key.as_u64; - - if (clib_bihash_search_8_8 (mapping_hash, &kv, &value)) - { - /* Try address only mapping */ - m_key.port = 0; - kv.key = m_key.as_u64; - if (clib_bihash_search_8_8 (mapping_hash, &kv, &value)) - return 1; - } - - m = pool_elt_at_index (sm->static_mappings, value.value); - - if (by_external) - { - mapping->addr = m->local_addr; - /* Address only mapping doesn't change port */ - mapping->port = m->addr_only ? match.port - : clib_host_to_net_u16 (m->local_port); - mapping->fib_index = m->fib_index; - } - else - { - mapping->addr = m->external_addr; - /* Address only mapping doesn't change port */ - mapping->port = m->addr_only ? match.port - : clib_host_to_net_u16 (m->external_port); - mapping->fib_index = sm->outside_fib_index; - } - - return 0; -} - -int snat_alloc_outside_address_and_port (snat_main_t * sm, - snat_session_key_t * k, - u32 * address_indexp) -{ - int i; - snat_address_t *a; - u32 portnum; - - for (i = 0; i < vec_len (sm->addresses); i++) - { - if (sm->addresses[i].busy_ports < (65535-1024)) - { - a = sm->addresses + i; - - while (1) - { - portnum = random_u32 (&sm->random_seed); - portnum &= 0xFFFF; - if (portnum < 1024) - continue; - if (clib_bitmap_get_no_check (a->busy_port_bitmap, portnum)) - continue; - clib_bitmap_set_no_check (a->busy_port_bitmap, portnum, 1); - a->busy_ports++; - /* Caller sets protocol and fib index */ - k->addr = a->addr; - k->port = clib_host_to_net_u16(portnum); - *address_indexp = i; - return 0; - } - } - } - /* Totally out of translations to use... */ - return 1; -} - - -static clib_error_t * -add_address_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - snat_main_t * sm = &snat_main; - ip4_address_t start_addr, end_addr, this_addr; - u32 start_host_order, end_host_order; - int i, count; - int is_add = 1; - int rv = 0; - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "%U - %U", - unformat_ip4_address, &start_addr, - unformat_ip4_address, &end_addr)) - ; - else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr)) - end_addr = start_addr; - else if (unformat (line_input, "del")) - is_add = 0; - else - return clib_error_return (0, "unknown input '%U'", - format_unformat_error, input); - } - unformat_free (line_input); - - if (sm->static_mapping_only) - return clib_error_return (0, "static mapping only mode"); - - start_host_order = clib_host_to_net_u32 (start_addr.as_u32); - end_host_order = clib_host_to_net_u32 (end_addr.as_u32); - - if (end_host_order < start_host_order) - return clib_error_return (0, "end address less than start address"); - - count = (end_host_order - start_host_order) + 1; - - if (count > 1024) - clib_warning ("%U - %U, %d addresses...", - format_ip4_address, &start_addr, - format_ip4_address, &end_addr, - count); - - this_addr = start_addr; - - for (i = 0; i < count; i++) - { - if (is_add) - snat_add_address (sm, &this_addr); - else - rv = snat_del_address (sm, this_addr); - - switch (rv) - { - case VNET_API_ERROR_NO_SUCH_ENTRY: - return clib_error_return (0, "S-NAT address not exist."); - break; - case VNET_API_ERROR_UNSPECIFIED: - return clib_error_return (0, "S-NAT address used in static mapping."); - break; - default: - break; - } - - increment_v4_address (&this_addr); - } - - return 0; -} - -VLIB_CLI_COMMAND (add_address_command, static) = { - .path = "snat add address", - .short_help = "snat add addresses [- ] [del]", - .function = add_address_command_fn, -}; - -static clib_error_t * -snat_feature_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - vnet_main_t * vnm = vnet_get_main(); - clib_error_t * error = 0; - u32 sw_if_index; - u32 * inside_sw_if_indices = 0; - u32 * outside_sw_if_indices = 0; - int is_del = 0; - int i; - - sw_if_index = ~0; - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "in %U", unformat_vnet_sw_interface, - vnm, &sw_if_index)) - vec_add1 (inside_sw_if_indices, sw_if_index); - else if (unformat (line_input, "out %U", unformat_vnet_sw_interface, - vnm, &sw_if_index)) - vec_add1 (outside_sw_if_indices, sw_if_index); - else if (unformat (line_input, "del")) - is_del = 1; - else - return clib_error_return (0, "unknown input '%U'", - format_unformat_error, input); - } - unformat_free (line_input); - - if (vec_len (inside_sw_if_indices)) - { - for (i = 0; i < vec_len(inside_sw_if_indices); i++) - { - sw_if_index = inside_sw_if_indices[i]; - snat_interface_add_del (sw_if_index, 1, is_del); - } - } - - if (vec_len (outside_sw_if_indices)) - { - for (i = 0; i < vec_len(outside_sw_if_indices); i++) - { - sw_if_index = outside_sw_if_indices[i]; - snat_interface_add_del (sw_if_index, 0, is_del); - } - } - - vec_free (inside_sw_if_indices); - vec_free (outside_sw_if_indices); - - return error; -} - -VLIB_CLI_COMMAND (set_interface_snat_command, static) = { - .path = "set interface snat", - .function = snat_feature_command_fn, - .short_help = "set interface snat in out [del]", -}; - -static clib_error_t * -add_static_mapping_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - clib_error_t * error = 0; - ip4_address_t l_addr, e_addr; - u32 l_port = 0, e_port = 0, vrf_id = ~0; - int is_add = 1; - int addr_only = 1; - int rv; - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr, - &l_port)) - addr_only = 0; - else if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr)) - ; - else if (unformat (line_input, "external %U %u", unformat_ip4_address, - &e_addr, &e_port)) - addr_only = 0; - else if (unformat (line_input, "external %U", unformat_ip4_address, - &e_addr)) - ; - else if (unformat (line_input, "vrf %u", &vrf_id)) - ; - else if (unformat (line_input, "del")) - is_add = 0; - else - return clib_error_return (0, "unknown input: '%U'", - format_unformat_error, line_input); - } - unformat_free (line_input); - - rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port, - vrf_id, addr_only, is_add); - - switch (rv) - { - case VNET_API_ERROR_INVALID_VALUE: - return clib_error_return (0, "External port already in use."); - break; - case VNET_API_ERROR_NO_SUCH_ENTRY: - if (is_add) - return clib_error_return (0, "External addres must be allocated."); - else - return clib_error_return (0, "Mapping not exist."); - break; - case VNET_API_ERROR_NO_SUCH_FIB: - return clib_error_return (0, "No such VRF id."); - case VNET_API_ERROR_VALUE_EXIST: - return clib_error_return (0, "Mapping already exist."); - default: - break; - } - - return error; -} - -/*? - * @cliexpar - * @cliexstart{snat add static mapping} - * Static mapping allows hosts on the external network to initiate connection - * to to the local network host. - * To create static mapping between local host address 10.0.0.3 port 6303 and - * external address 4.4.4.4 port 3606 use: - * vpp# snat add static mapping local 10.0.0.3 6303 external 4.4.4.4 3606 - * If not runnig "static mapping only" S-NAT plugin mode use before: - * vpp# snat add address 4.4.4.4 - * To create static mapping between local and external address use: - * vpp# snat add static mapping local 10.0.0.3 external 4.4.4.4 - * @cliexend -?*/ -VLIB_CLI_COMMAND (add_static_mapping_command, static) = { - .path = "snat add static mapping", - .function = add_static_mapping_command_fn, - .short_help = - "snat add static mapping local [] external [] [vrf ] [del]", -}; - -static clib_error_t * -set_workers_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - uword *bitmap = 0; - int rv = 0; - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap)) - ; - else - return clib_error_return (0, "unknown input '%U'", - format_unformat_error, input); - } - unformat_free (line_input); - - if (bitmap == 0) - return clib_error_return (0, "List of workers must be specified."); - - rv = snat_set_workers(bitmap); - - clib_bitmap_free (bitmap); - - switch (rv) - { - case VNET_API_ERROR_INVALID_WORKER: - return clib_error_return (0, "Invalid worker(s)."); - break; - case VNET_API_ERROR_FEATURE_DISABLED: - return clib_error_return (0, - "Supported only if 2 or more workes available."); - break; - default: - break; - } - - return 0; -} - -/*? - * @cliexpar - * @cliexstart{set snat workers} - * Set SNAT workers if 2 or more workers available, use: - * vpp# set snat workers 0-2,5 - * @cliexend -?*/ -VLIB_CLI_COMMAND (set_workers_command, static) = { - .path = "set snat workers", - .function = set_workers_command_fn, - .short_help = - "set snat workers ", -}; - -static clib_error_t * -snat_config (vlib_main_t * vm, unformat_input_t * input) -{ - snat_main_t * sm = &snat_main; - u32 translation_buckets = 1024; - u32 translation_memory_size = 128<<20; - u32 user_buckets = 128; - u32 user_memory_size = 64<<20; - u32 max_translations_per_user = 100; - u32 outside_vrf_id = 0; - u32 inside_vrf_id = 0; - u32 static_mapping_buckets = 1024; - u32 static_mapping_memory_size = 64<<20; - u8 static_mapping_only = 0; - u8 static_mapping_connection_tracking = 0; - vlib_thread_main_t *tm = vlib_get_thread_main (); - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "translation hash buckets %d", &translation_buckets)) - ; - else if (unformat (input, "translation hash memory %d", - &translation_memory_size)); - else if (unformat (input, "user hash buckets %d", &user_buckets)) - ; - else if (unformat (input, "user hash memory %d", - &user_memory_size)) - ; - else if (unformat (input, "max translations per user %d", - &max_translations_per_user)) - ; - else if (unformat (input, "outside VRF id %d", - &outside_vrf_id)) - ; - else if (unformat (input, "inside VRF id %d", - &inside_vrf_id)) - ; - else if (unformat (input, "static mapping only")) - { - static_mapping_only = 1; - if (unformat (input, "connection tracking")) - static_mapping_connection_tracking = 1; - } - else - return clib_error_return (0, "unknown input '%U'", - format_unformat_error, input); - } - - /* for show commands, etc. */ - sm->translation_buckets = translation_buckets; - sm->translation_memory_size = translation_memory_size; - sm->user_buckets = user_buckets; - sm->user_memory_size = user_memory_size; - sm->max_translations_per_user = max_translations_per_user; - sm->outside_vrf_id = outside_vrf_id; - sm->outside_fib_index = ~0; - sm->inside_vrf_id = inside_vrf_id; - sm->inside_fib_index = ~0; - sm->static_mapping_only = static_mapping_only; - sm->static_mapping_connection_tracking = static_mapping_connection_tracking; - - if (!static_mapping_only || - (static_mapping_only && static_mapping_connection_tracking)) - { - clib_bihash_init_8_8 (&sm->worker_by_in, "worker-by-in", user_buckets, - user_memory_size); - - clib_bihash_init_8_8 (&sm->worker_by_out, "worker-by-out", user_buckets, - user_memory_size); - - vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1); - - clib_bihash_init_8_8 (&sm->in2out, "in2out", translation_buckets, - translation_memory_size); - - clib_bihash_init_8_8 (&sm->out2in, "out2in", translation_buckets, - translation_memory_size); - - clib_bihash_init_8_8 (&sm->user_hash, "users", user_buckets, - user_memory_size); - } - clib_bihash_init_8_8 (&sm->static_mapping_by_local, - "static_mapping_by_local", static_mapping_buckets, - static_mapping_memory_size); - - clib_bihash_init_8_8 (&sm->static_mapping_by_external, - "static_mapping_by_external", static_mapping_buckets, - static_mapping_memory_size); - return 0; -} - -VLIB_CONFIG_FUNCTION (snat_config, "snat"); - -u8 * format_snat_key (u8 * s, va_list * args) -{ - snat_session_key_t * key = va_arg (*args, snat_session_key_t *); - char * protocol_string = "unknown"; - static char *protocol_strings[] = { - "UDP", - "TCP", - "ICMP", - }; - - if (key->protocol < ARRAY_LEN(protocol_strings)) - protocol_string = protocol_strings[key->protocol]; - - s = format (s, "%U proto %s port %d fib %d", - format_ip4_address, &key->addr, protocol_string, - clib_net_to_host_u16 (key->port), key->fib_index); - return s; -} - -u8 * format_snat_session (u8 * s, va_list * args) -{ - snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *); - snat_session_t * sess = va_arg (*args, snat_session_t *); - - s = format (s, " i2o %U\n", format_snat_key, &sess->in2out); - s = format (s, " o2i %U\n", format_snat_key, &sess->out2in); - s = format (s, " last heard %.2f\n", sess->last_heard); - s = format (s, " total pkts %d, total bytes %lld\n", - sess->total_pkts, sess->total_bytes); - if (snat_is_session_static (sess)) - s = format (s, " static translation\n"); - else - s = format (s, " dynamic translation\n"); - - return s; -} - -u8 * format_snat_user (u8 * s, va_list * args) -{ - snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *); - snat_user_t * u = va_arg (*args, snat_user_t *); - int verbose = va_arg (*args, int); - dlist_elt_t * head, * elt; - u32 elt_index, head_index; - u32 session_index; - snat_session_t * sess; - - s = format (s, "%U: %d dynamic translations, %d static translations\n", - format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions); - - if (verbose == 0) - return s; - - if (u->nsessions || u->nstaticsessions) - { - head_index = u->sessions_per_user_list_head_index; - head = pool_elt_at_index (sm->list_pool, head_index); - - elt_index = head->next; - elt = pool_elt_at_index (sm->list_pool, elt_index); - session_index = elt->value; - - while (session_index != ~0) - { - sess = pool_elt_at_index (sm->sessions, session_index); - - s = format (s, " %U\n", format_snat_session, sm, sess); - - elt_index = elt->next; - elt = pool_elt_at_index (sm->list_pool, elt_index); - session_index = elt->value; - } - } - - return s; -} - -u8 * format_snat_static_mapping (u8 * s, va_list * args) -{ - snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *); - - if (m->addr_only) - s = format (s, "local %U external %U vrf %d", - format_ip4_address, &m->local_addr, - format_ip4_address, &m->external_addr, - m->vrf_id); - else - s = format (s, "local %U:%d external %U:%d vrf %d", - format_ip4_address, &m->local_addr, m->local_port, - format_ip4_address, &m->external_addr, m->external_port, - m->vrf_id); - - return s; -} - -static clib_error_t * -show_snat_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - int verbose = 0; - snat_main_t * sm = &snat_main; - snat_user_t * u; - snat_static_mapping_t *m; - snat_interface_t *i; - snat_address_t * ap; - vnet_main_t *vnm = vnet_get_main(); - snat_main_per_thread_data_t *tsm; - u32 users_num = 0, sessions_num = 0, *worker; - uword j = 0; - - if (unformat (input, "detail")) - verbose = 1; - else if (unformat (input, "verbose")) - verbose = 2; - - if (sm->static_mapping_only) - { - if (sm->static_mapping_connection_tracking) - vlib_cli_output (vm, "SNAT mode: static mapping only connection " - "tracking"); - else - vlib_cli_output (vm, "SNAT mode: static mapping only"); - } - else - { - vlib_cli_output (vm, "SNAT mode: dynamic translations enabled"); - } - - if (verbose > 0) - { - pool_foreach (i, sm->interfaces, - ({ - vlib_cli_output (vm, "%U %s", format_vnet_sw_interface_name, vnm, - vnet_get_sw_interface (vnm, i->sw_if_index), - i->is_inside ? "in" : "out"); - })); - - vec_foreach (ap, sm->addresses) - { - u8 * s = format (0, ""); - vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr); - clib_bitmap_foreach (j, ap->busy_port_bitmap, - ({ - s = format (s, " %d", j); - })); - vlib_cli_output (vm, " %d busy ports:%v", ap->busy_ports, s); - } - } - - if (sm->num_workers > 1) - { - vlib_cli_output (vm, "%d workers", vec_len (sm->workers)); - if (verbose > 0) - { - vec_foreach (worker, sm->workers) - { - vlib_worker_thread_t *w = - vlib_worker_threads + *worker + sm->first_worker_index; - vlib_cli_output (vm, " %v", w->name); - } - } - } - - if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)) - { - vlib_cli_output (vm, "%d static mappings", - pool_elts (sm->static_mappings)); - - if (verbose > 0) - { - pool_foreach (m, sm->static_mappings, - ({ - vlib_cli_output (vm, "%U", format_snat_static_mapping, m); - })); - } - } - else - { - vec_foreach (tsm, sm->per_thread_data) - { - users_num += pool_elts (tsm->users); - sessions_num += pool_elts (tsm->sessions); - } - - vlib_cli_output (vm, "%d users, %d outside addresses, %d active sessions," - " %d static mappings", - users_num, - vec_len (sm->addresses), - sessions_num, - pool_elts (sm->static_mappings)); - - if (verbose > 0) - { - vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->in2out, - verbose - 1); - vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->out2in, - verbose - 1); - vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_in, - verbose - 1); - vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_out, - verbose - 1); - vec_foreach_index (j, sm->per_thread_data) - { - tsm = vec_elt_at_index (sm->per_thread_data, j); - - if (pool_elts (tsm->users) == 0) - continue; - - vlib_worker_thread_t *w = vlib_worker_threads + j; - vlib_cli_output (vm, "Thread %d (%v at lcore %u):", j, w->name, - w->lcore_id); - vlib_cli_output (vm, " %d list pool elements", - pool_elts (tsm->list_pool)); - - pool_foreach (u, tsm->users, - ({ - vlib_cli_output (vm, " %U", format_snat_user, tsm, u, - verbose - 1); - })); - } - - if (pool_elts (sm->static_mappings)) - { - vlib_cli_output (vm, "static mappings:"); - pool_foreach (m, sm->static_mappings, - ({ - vlib_cli_output (vm, "%U", format_snat_static_mapping, m); - })); - } - } - } - - return 0; -} - -VLIB_CLI_COMMAND (show_snat_command, static) = { - .path = "show snat", - .short_help = "show snat", - .function = show_snat_command_fn, -}; diff --git a/plugins/snat-plugin/snat/snat.h b/plugins/snat-plugin/snat/snat.h deleted file mode 100644 index cb31dc51..00000000 --- a/plugins/snat-plugin/snat/snat.h +++ /dev/null @@ -1,259 +0,0 @@ - -/* - * snat.h - simple nat definitions - * - * 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. - */ -#ifndef __included_snat_h__ -#define __included_snat_h__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Key */ -typedef struct { - union - { - struct - { - ip4_address_t addr; - u16 port; - u16 protocol:3, - fib_index:13; - }; - u64 as_u64; - }; -} snat_session_key_t; - -typedef struct { - union - { - struct - { - ip4_address_t addr; - u32 fib_index; - }; - u64 as_u64; - }; -} snat_user_key_t; - -typedef struct { - union - { - struct - { - ip4_address_t addr; - u16 port; - u16 fib_index; - }; - u64 as_u64; - }; -} snat_static_mapping_key_t; - - -typedef enum { - SNAT_PROTOCOL_UDP = 0, - SNAT_PROTOCOL_TCP, - SNAT_PROTOCOL_ICMP, -} snat_protocol_t; - - -#define SNAT_SESSION_FLAG_STATIC_MAPPING 1 - -typedef CLIB_PACKED(struct { - snat_session_key_t out2in; /* 0-15 */ - - snat_session_key_t in2out; /* 16-31 */ - - u32 flags; /* 32-35 */ - - /* per-user translations */ - u32 per_user_index; /* 36-39 */ - - u32 per_user_list_head_index; /* 40-43 */ - - /* Last heard timer */ - f64 last_heard; /* 44-51 */ - - u64 total_bytes; /* 52-59 */ - - u32 total_pkts; /* 60-63 */ - - /* Outside address */ - u32 outside_address_index; /* 64-67 */ - -}) snat_session_t; - - -typedef struct { - ip4_address_t addr; - u32 sessions_per_user_list_head_index; - u32 nsessions; - u32 nstaticsessions; -} snat_user_t; - -typedef struct { - ip4_address_t addr; - u32 busy_ports; - uword * busy_port_bitmap; -} snat_address_t; - -typedef struct { - ip4_address_t local_addr; - ip4_address_t external_addr; - u16 local_port; - u16 external_port; - u8 addr_only; - u32 vrf_id; - u32 fib_index; -} snat_static_mapping_t; - -typedef struct { - u32 sw_if_index; - u8 is_inside; -} snat_interface_t; - -typedef struct { - /* User pool */ - snat_user_t * users; - - /* Session pool */ - snat_session_t * sessions; - - /* Pool of doubly-linked list elements */ - dlist_elt_t * list_pool; -} snat_main_per_thread_data_t; - -typedef struct { - /* Main lookup tables */ - clib_bihash_8_8_t out2in; - clib_bihash_8_8_t in2out; - - /* Find-a-user => src address lookup */ - clib_bihash_8_8_t user_hash; - - /* Non-translated packets worker lookup => src address + VRF */ - clib_bihash_8_8_t worker_by_in; - - /* Translated packets worker lookup => IP address + port number */ - clib_bihash_8_8_t worker_by_out; - - u32 num_workers; - u32 first_worker_index; - u32 next_worker; - u32 * workers; - - /* Per thread data */ - snat_main_per_thread_data_t * per_thread_data; - - /* Find a static mapping by local */ - clib_bihash_8_8_t static_mapping_by_local; - - /* Find a static mapping by external */ - clib_bihash_8_8_t static_mapping_by_external; - - /* Static mapping pool */ - snat_static_mapping_t * static_mappings; - - /* Interface pool */ - snat_interface_t * interfaces; - - /* Vector of outside addresses */ - snat_address_t * addresses; - - /* Randomize port allocation order */ - u32 random_seed; - - /* Worker handoff index */ - u32 fq_in2out_index; - u32 fq_out2in_index; - - /* Config parameters */ - u8 static_mapping_only; - u8 static_mapping_connection_tracking; - u32 translation_buckets; - u32 translation_memory_size; - u32 user_buckets; - u32 user_memory_size; - u32 max_translations_per_user; - u32 outside_vrf_id; - u32 outside_fib_index; - u32 inside_vrf_id; - u32 inside_fib_index; - - /* API message ID base */ - u16 msg_id_base; - - /* convenience */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; - ip4_main_t * ip4_main; - ip_lookup_main_t * ip4_lookup_main; - ethernet_main_t * ethernet_main; - api_main_t * api_main; -} snat_main_t; - -extern snat_main_t snat_main; -extern vlib_node_registration_t snat_in2out_node; -extern vlib_node_registration_t snat_out2in_node; -extern vlib_node_registration_t snat_in2out_fast_node; -extern vlib_node_registration_t snat_out2in_fast_node; -extern vlib_node_registration_t snat_in2out_worker_handoff_node; -extern vlib_node_registration_t snat_out2in_worker_handoff_node; - -void snat_free_outside_address_and_port (snat_main_t * sm, - snat_session_key_t * k, - u32 address_index); - -int snat_alloc_outside_address_and_port (snat_main_t * sm, - snat_session_key_t * k, - u32 * address_indexp); - -int snat_static_mapping_match (snat_main_t * sm, - snat_session_key_t match, - snat_session_key_t * mapping, - u8 by_external); - -format_function_t format_snat_user; - -typedef struct { - u32 cached_sw_if_index; - u32 cached_ip4_address; -} snat_runtime_t; - -/** \brief Check if SNAT session is created from static mapping. - @param s SNAT session - @return 1 if SNAT session is created from static mapping otherwise 0 -*/ -#define snat_is_session_static(s) s->flags & SNAT_SESSION_FLAG_STATIC_MAPPING - -/* - * Why is this here? Because we don't need to touch this layer to - * simply reply to an icmp. We need to change id to a unique - * value to NAT an echo request/reply. - */ - -typedef struct { - u16 identifier; - u16 sequence; -} icmp_echo_header_t; - -#endif /* __included_snat_h__ */ diff --git a/plugins/snat-plugin/snat/snat_all_api_h.h b/plugins/snat-plugin/snat/snat_all_api_h.h deleted file mode 100644 index 49017700..00000000 --- a/plugins/snat-plugin/snat/snat_all_api_h.h +++ /dev/null @@ -1,19 +0,0 @@ - -/* - * snat_all_api_h.h - skeleton vpp engine plug-in api #include file - * - * Copyright (c) - * 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 diff --git a/plugins/snat-plugin/snat/snat_msg_enum.h b/plugins/snat-plugin/snat/snat_msg_enum.h deleted file mode 100644 index 2c76fd51..00000000 --- a/plugins/snat-plugin/snat/snat_msg_enum.h +++ /dev/null @@ -1,31 +0,0 @@ - -/* - * snat_msg_enum.h - skeleton vpp engine plug-in message enumeration - * - * Copyright (c) - * 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_snat_msg_enum_h -#define included_snat_msg_enum_h - -#include - -#define vl_msg_id(n,h) n, -typedef enum { -#include - /* 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_snat_msg_enum_h */ diff --git a/plugins/snat-plugin/snat/snat_test.c b/plugins/snat-plugin/snat/snat_test.c deleted file mode 100644 index 2a003ba6..00000000 --- a/plugins/snat-plugin/snat/snat_test.c +++ /dev/null @@ -1,602 +0,0 @@ - -/* - * snat.c - skeleton vpp-api-test plug-in - * - * Copyright (c) - * 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 -#include -#include -#include -#include -#include - -uword unformat_sw_if_index (unformat_input_t * input, va_list * args); - -/* Declare message IDs */ -#include - -/* define message structures */ -#define vl_typedefs -#include -#undef vl_typedefs - -/* declare message handlers for each api */ - -#define vl_endianfun /* define message structures */ -#include -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) -#define vl_printfun -#include -#undef vl_printfun - -/* Get the API version number. */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#undef vl_api_version - -typedef struct { - /* API message ID base */ - u16 msg_id_base; - vat_main_t *vat_main; -} snat_test_main_t; - -snat_test_main_t snat_test_main; - -#define foreach_standard_reply_retval_handler \ -_(snat_add_address_range_reply) \ -_(snat_interface_add_del_feature_reply) \ -_(snat_add_static_mapping_reply) \ -_(snat_set_workers_reply) - -#define _(n) \ - static void vl_api_##n##_t_handler \ - (vl_api_##n##_t * mp) \ - { \ - vat_main_t * vam = snat_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 \ -_(SNAT_ADD_ADDRESS_RANGE_REPLY, snat_add_address_range_reply) \ -_(SNAT_INTERFACE_ADD_DEL_FEATURE_REPLY, \ - snat_interface_add_del_feature_reply) \ -_(SNAT_ADD_STATIC_MAPPING_REPLY, snat_add_static_mapping_reply) \ -_(SNAT_CONTROL_PING_REPLY, snat_control_ping_reply) \ -_(SNAT_STATIC_MAPPING_DETAILS, snat_static_mapping_details) \ -_(SNAT_SHOW_CONFIG_REPLY, snat_show_config_reply) \ -_(SNAT_ADDRESS_DETAILS, snat_address_details) \ -_(SNAT_INTERFACE_DETAILS, snat_interface_details) \ -_(SNAT_SET_WORKERS_REPLY, snat_set_workers_reply) \ -_(SNAT_WORKER_DETAILS, snat_worker_details) - -/* 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_snat_add_address_range (vat_main_t * vam) -{ - snat_test_main_t * sm = &snat_test_main; - unformat_input_t * i = vam->input; - f64 timeout; - ip4_address_t start_addr, end_addr; - u32 start_host_order, end_host_order; - vl_api_snat_add_address_range_t * mp; - u8 is_add = 1; - int count; - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "%U - %U", - unformat_ip4_address, &start_addr, - unformat_ip4_address, &end_addr)) - ; - else if (unformat (i, "%U", unformat_ip4_address, &start_addr)) - end_addr = start_addr; - else if (unformat (i, "del")) - is_add = 0; - else - { - clib_warning("unknown input '%U'", format_unformat_error, i); - return -99; - } - } - - start_host_order = clib_host_to_net_u32 (start_addr.as_u32); - end_host_order = clib_host_to_net_u32 (end_addr.as_u32); - - if (end_host_order < start_host_order) - { - errmsg ("end address less than start address\n"); - return -99; - } - - count = (end_host_order - start_host_order) + 1; - - if (count > 1024) - { - errmsg ("%U - %U, %d addresses...\n", - format_ip4_address, &start_addr, - format_ip4_address, &end_addr, - count); - } - - M(SNAT_ADD_ADDRESS_RANGE, snat_add_address_range); - - memcpy (mp->first_ip_address, &start_addr, 4); - memcpy (mp->last_ip_address, &end_addr, 4); - mp->is_ip4 = 1; - mp->is_add = is_add; - - S; W; - - /* NOTREACHED */ - return 0; -} - -static int api_snat_interface_add_del_feature (vat_main_t * vam) -{ - snat_test_main_t * sm = &snat_test_main; - unformat_input_t * i = vam->input; - f64 timeout; - vl_api_snat_interface_add_del_feature_t * mp; - u32 sw_if_index; - u8 sw_if_index_set = 0; - u8 is_inside = 1; - u8 is_add = 1; - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index)) - sw_if_index_set = 1; - else if (unformat (i, "sw_if_index %d", &sw_if_index)) - sw_if_index_set = 1; - else if (unformat (i, "out")) - is_inside = 0; - else if (unformat (i, "in")) - is_inside = 1; - else if (unformat (i, "del")) - is_add = 0; - else - { - clib_warning("unknown input '%U'", format_unformat_error, i); - return -99; - } - } - - if (sw_if_index_set == 0) - { - errmsg ("interface / sw_if_index required\n"); - return -99; - } - - M(SNAT_INTERFACE_ADD_DEL_FEATURE, snat_interface_add_del_feature); - mp->sw_if_index = ntohl(sw_if_index); - mp->is_add = is_add; - mp->is_inside = is_inside; - - S; W; - /* NOTREACHED */ - return 0; -} - -static int api_snat_add_static_mapping(vat_main_t * vam) -{ - snat_test_main_t * sm = &snat_test_main; - unformat_input_t * i = vam->input; - f64 timeout; - vl_api_snat_add_static_mapping_t * mp; - u8 addr_set_n = 0; - u8 is_add = 1; - u8 addr_only = 1; - ip4_address_t local_addr, external_addr; - u32 local_port = 0, external_port = 0, vrf_id = ~0; - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "local_addr %U", unformat_ip4_address, &local_addr)) - addr_set_n++; - else if (unformat (i, "external_addr %U", unformat_ip4_address, - &external_addr)) - addr_set_n++; - else if (unformat (i, "local_port %u", &local_port)) - addr_only = 0; - else if (unformat (i, "external_port %u", &external_port)) - addr_only = 0; - else if (unformat (i, "vrf %u", &vrf_id)) - ; - else if (unformat (i, "del")) - is_add = 0; - else - { - clib_warning("unknown input '%U'", format_unformat_error, i); - return -99; - } - } - - if (addr_set_n != 2) - { - errmsg ("local_addr and remote_addr required\n"); - return -99; - } - - M(SNAT_ADD_STATIC_MAPPING, snat_add_static_mapping); - mp->is_add = is_add; - mp->is_ip4 = 1; - mp->addr_only = addr_only; - mp->local_port = ntohs ((u16) local_port); - mp->external_port = ntohs ((u16) external_port); - mp->vrf_id = ntohl (vrf_id); - memcpy (mp->local_ip_address, &local_addr, 4); - memcpy (mp->external_ip_address, &external_addr, 4); - - S; W; - /* NOTREACHED */ - return 0; -} - -static void vl_api_snat_control_ping_reply_t_handler - (vl_api_snat_control_ping_reply_t * mp) -{ - vat_main_t *vam = &vat_main; - i32 retval = ntohl (mp->retval); - if (vam->async_mode) - { - vam->async_errors += (retval < 0); - } - else - { - vam->retval = retval; - vam->result_ready = 1; - } -} - -static void vl_api_snat_static_mapping_details_t_handler - (vl_api_snat_static_mapping_details_t *mp) -{ - snat_test_main_t * sm = &snat_test_main; - vat_main_t *vam = sm->vat_main; - - if (mp->addr_only) - fformat (vam->ofp, "%15U%6s%15U%6s%11d\n", - format_ip4_address, &mp->local_ip_address, "", - format_ip4_address, &mp->external_ip_address, "", - ntohl (mp->vrf_id)); - else - fformat (vam->ofp, "%15U%6d%15U%6d%11d\n", - format_ip4_address, &mp->local_ip_address, - ntohs (mp->local_port), - format_ip4_address, &mp->external_ip_address, - ntohs (mp->external_port), - ntohl (mp->vrf_id)); - -} - -static int api_snat_static_mapping_dump(vat_main_t * vam) -{ - snat_test_main_t * sm = &snat_test_main; - f64 timeout; - vl_api_snat_static_mapping_dump_t * mp; - - if (vam->json_output) - { - clib_warning ("JSON output not supported for snat_static_mapping_dump"); - return -99; - } - - fformat (vam->ofp, "%21s%21s\n", "local", "external"); - fformat (vam->ofp, "%15s%6s%15s%6s%11s\n", "address", "port", "address", - "port", "vrf"); - - M(SNAT_STATIC_MAPPING_DUMP, snat_static_mapping_dump); - S; - /* Use a control ping for synchronization */ - { - vl_api_snat_control_ping_t *mp; - M (SNAT_CONTROL_PING, snat_control_ping); - S; - } - W; - /* NOTREACHED */ - return 0; -} - -static void vl_api_snat_show_config_reply_t_handler - (vl_api_snat_show_config_reply_t *mp) -{ - snat_test_main_t * sm = &snat_test_main; - vat_main_t *vam = sm->vat_main; - i32 retval = ntohl (mp->retval); - - if (retval >= 0) - { - fformat (vam->ofp, "translation hash buckets %d\n", - ntohl (mp->translation_buckets)); - fformat (vam->ofp, "translation hash memory %d\n", - ntohl (mp->translation_memory_size)); - fformat (vam->ofp, "user hash buckets %d\n", ntohl (mp->user_buckets)); - fformat (vam->ofp, "user hash memory %d\n", ntohl (mp->user_memory_size)); - fformat (vam->ofp, "max translations per user %d\n", - ntohl (mp->max_translations_per_user)); - fformat (vam->ofp, "outside VRF id %d\n", ntohl (mp->outside_vrf_id)); - fformat (vam->ofp, "inside VRF id %d\n", ntohl (mp->inside_vrf_id)); - if (mp->static_mapping_only) - { - fformat (vam->ofp, "static mapping only"); - if (mp->static_mapping_connection_tracking) - fformat (vam->ofp, " connection tracking"); - fformat (vam->ofp, "\n"); - } - } - vam->retval = retval; - vam->result_ready = 1; -} - -static int api_snat_show_config(vat_main_t * vam) -{ - snat_test_main_t * sm = &snat_test_main; - f64 timeout; - vl_api_snat_show_config_t * mp; - - if (vam->json_output) - { - clib_warning ("JSON output not supported for snat_show_config"); - return -99; - } - - M(SNAT_SHOW_CONFIG, snat_show_config); - S; W; - /* NOTREACHED */ - return 0; -} - -static void vl_api_snat_address_details_t_handler - (vl_api_snat_address_details_t *mp) -{ - snat_test_main_t * sm = &snat_test_main; - vat_main_t *vam = sm->vat_main; - - fformat (vam->ofp, "%U\n", format_ip4_address, &mp->ip_address); -} - -static int api_snat_address_dump(vat_main_t * vam) -{ - snat_test_main_t * sm = &snat_test_main; - f64 timeout; - vl_api_snat_address_dump_t * mp; - - if (vam->json_output) - { - clib_warning ("JSON output not supported for snat_address_dump"); - return -99; - } - - M(SNAT_ADDRESS_DUMP, snat_address_dump); - S; - /* Use a control ping for synchronization */ - { - vl_api_snat_control_ping_t *mp; - M (SNAT_CONTROL_PING, snat_control_ping); - S; - } - W; - /* NOTREACHED */ - return 0; -} - -static void vl_api_snat_interface_details_t_handler - (vl_api_snat_interface_details_t *mp) -{ - snat_test_main_t * sm = &snat_test_main; - vat_main_t *vam = sm->vat_main; - - fformat (vam->ofp, "sw_if_index %d %s\n", ntohl (mp->sw_if_index), - mp->is_inside ? "in" : "out"); -} - -static int api_snat_interface_dump(vat_main_t * vam) -{ - snat_test_main_t * sm = &snat_test_main; - f64 timeout; - vl_api_snat_interface_dump_t * mp; - - if (vam->json_output) - { - clib_warning ("JSON output not supported for snat_address_dump"); - return -99; - } - - M(SNAT_INTERFACE_DUMP, snat_interface_dump); - S; - /* Use a control ping for synchronization */ - { - vl_api_snat_control_ping_t *mp; - M (SNAT_CONTROL_PING, snat_control_ping); - S; - } - W; - /* NOTREACHED */ - return 0; -} - -static int api_snat_set_workers (vat_main_t * vam) -{ - snat_test_main_t * sm = &snat_test_main; - unformat_input_t * i = vam->input; - f64 timeout; - vl_api_snat_set_workers_t * mp; - uword *bitmap; - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "%U", unformat_bitmap_list, &bitmap)) - ; - else - { - clib_warning("unknown input '%U'", format_unformat_error, i); - return -99; - } - } - - M(SNAT_SET_WORKERS, snat_set_workers); - mp->worker_mask = clib_host_to_net_u64 (bitmap[0]); - - S; W; - - /* NOTREACHED */ - return 0; -} - -static void vl_api_snat_worker_details_t_handler - (vl_api_snat_worker_details_t *mp) -{ - snat_test_main_t * sm = &snat_test_main; - vat_main_t *vam = sm->vat_main; - - fformat (vam->ofp, "worker_index %d (%s at lcore %u)\n", - ntohl (mp->worker_index), mp->name, ntohl (mp->lcore_id)); -} - -static int api_snat_worker_dump(vat_main_t * vam) -{ - snat_test_main_t * sm = &snat_test_main; - f64 timeout; - vl_api_snat_worker_dump_t * mp; - - if (vam->json_output) - { - clib_warning ("JSON output not supported for snat_address_dump"); - return -99; - } - - M(SNAT_WORKER_DUMP, snat_worker_dump); - S; - /* Use a control ping for synchronization */ - { - vl_api_snat_control_ping_t *mp; - M (SNAT_CONTROL_PING, snat_control_ping); - S; - } - W; - /* NOTREACHED */ - return 0; -} - -/* - * List of messages that the api test plugin sends, - * and that the data plane plugin processes - */ -#define foreach_vpe_api_msg \ -_(snat_add_address_range, " [- | sw_if_index [in] [out] [del]") \ -_(snat_add_static_mapping, "local_addr external_addr " \ - "[local_port ] [external_port ] [vrf ] [del]") \ -_(snat_set_workers, "") \ -_(snat_static_mapping_dump, "") \ -_(snat_show_config, "") \ -_(snat_address_dump, "") \ -_(snat_interface_dump, "") \ -_(snat_worker_dump, "") - -void vat_api_hookup (vat_main_t *vam) -{ - snat_test_main_t * sm __attribute__((unused)) = &snat_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) -{ - snat_test_main_t * sm = &snat_test_main; - u8 * name; - - sm->vat_main = vam; - - /* Ask the vpp engine for the first assigned message-id */ - name = format (0, "snat_%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/src/Makefile.am b/src/Makefile.am index e691a539..0fc437a4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -79,7 +79,15 @@ include vnet.am include vpp.am include vpp-api-test.am -SUBDIRS += vpp-api/python plugins +SUBDIRS += plugins + +if ENABLE_PAPI +SUBDIRS += vpp-api/python +endif + +if ENABLE_JAPI +SUBDIRS += vpp-api/java +endif ############################################################################### # API diff --git a/src/configure.ac b/src/configure.ac index f8e4d94f..4ed55705 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -3,7 +3,8 @@ LT_INIT AC_CONFIG_AUX_DIR([.]) AM_INIT_AUTOMAKE([subdir-objects]) AM_SILENT_RULES([yes]) -AC_CONFIG_FILES([Makefile plugins/Makefile vpp-api/python/Makefile]) +AC_CONFIG_FILES([Makefile plugins/Makefile vpp-api/python/Makefile vpp-api/java/Makefile]) +AC_CONFIG_MACRO_DIR([m4]) AC_PROG_CC AM_PROG_AS @@ -89,6 +90,8 @@ ENABLE_ARG(g2, [Enable g2]) # --disable-X DISABLE_ARG(vlib, [Disable vlib and dependant libs and binaries]) DISABLE_ARG(svm, [Disable svm and dependant libs and binaries]) +DISABLE_ARG(papi, [Disable Python API bindings]) +DISABLE_ARG(japi, [Disable Java API bindings]) # --with-X WITH_ARG(dpdk, [Use use DPDK]) @@ -131,6 +134,25 @@ AC_DEFINE_UNQUOTED(DPDK_CRYPTO, [${n_with_dpdk_crypto}]) AC_DEFINE_UNQUOTED(IPSEC, [${n_with_ipsec}]) AC_DEFINE_UNQUOTED(IPV6SR, [${n_with_ipv6sr}]) + +# Silence following noise: +# ar: `u' modifier ignored since `D' is the default (see `U') +AR_FLAGS=cr +AC_SUBST(AR_FLAGS) + +############################################################################### +# Plugins +############################################################################### + +# Please keep alphabetical order +PLUGIN_ENABLED(acl) +PLUGIN_ENABLED(flowperpkt) +PLUGIN_ENABLED(ila) +PLUGIN_ENABLED(ioam) +PLUGIN_ENABLED(lb) +PLUGIN_ENABLED(sixrd) +PLUGIN_ENABLED(snat) + ############################################################################### # Dependency checks ############################################################################### @@ -151,12 +173,17 @@ AM_COND_IF([ENABLE_G2], ]) ############################################################################### -# Plugins +# JAVA ############################################################################### -PLUGIN_ENABLED(sixrd) -PLUGIN_ENABLED(ila) -PLUGIN_ENABLED(flowperpkt) +AM_COND_IF([ENABLE_JAPI], +[ + AX_VPP_FIND_JDK8 + AC_SUBST(JAVA_HOME) + AC_SUBST(JAVAC) + AC_SUBST(JAVAH) + AC_SUBST(JAR) +]) ############################################################################### # Output @@ -172,6 +199,11 @@ PRINT_VAL([includedir], ${includedir}) PRINT_VAL([CFLAGS], ${CFLAGS}) PRINT_VAL([CPPFLAGS], ${CPPFLAGS}) PRINT_VAL([LDFLAGS], ${LDFLAGS}) +AM_COND_IF([ENABLE_JAPI], +[ + PRINT_VAL([JAVA_VERSION], ${JAVA_VERSION}) + PRINT_VAL([JAVA_HOME], ${JAVA_HOME}) +]) AC_MSG_RESULT([]) AC_MSG_RESULT([with:]) diff --git a/src/examples/sample-plugin/Makefile.am b/src/examples/sample-plugin/Makefile.am new file mode 100644 index 00000000..e221f8c1 --- /dev/null +++ b/src/examples/sample-plugin/Makefile.am @@ -0,0 +1,56 @@ +# Copyright (c) 2015 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +AUTOMAKE_OPTIONS = foreign subdir-objects + +AM_CFLAGS = -Wall +AM_LDFLAGS = -module -shared -avoid-version + +vppapitestpluginsdir = ${libdir}/vpp_api_test_plugins +vpppluginsdir = ${libdir}/vpp_plugins + +vppapitestplugins_LTLIBRARIES = sample_test_plugin.la +vppplugins_LTLIBRARIES = sample_plugin.la + +sample_plugin_la_SOURCES = sample/sample.c sample/node.c \ + sample/sample_plugin.api.h + +BUILT_SOURCES = sample/sample.api.h sample/sample.api.json + +SUFFIXES = .api.h .api + +%.api.h: %.api + mkdir -p `dirname $@` ; \ + $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ + | vppapigen --input - --output $@ --show-name $@ + +%.api.json: %.api + @echo " JSON APIGEN " $@ ; \ + mkdir -p `dirname $@` ; \ + $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ + | vppapigen --input - --json $@ + +apidir = $(prefix)/sample/ +api_DATA = sample.api.json + +noinst_HEADERS = \ + sample/sample_all_api_h.h \ + sample/sample_msg_enum.h \ + sample/sample.api.h + +sample_test_plugin_la_SOURCES = sample/sample_test.c sample/sample_plugin.api.h + +# Remove *.la files +install-data-hook: + @(cd $(vpppluginsdir) && $(RM) $(vppplugins_LTLIBRARIES)) + @(cd $(vppapitestpluginsdir) && $(RM) $(vppapitestplugins_LTLIBRARIES)) diff --git a/src/examples/sample-plugin/configure.ac b/src/examples/sample-plugin/configure.ac new file mode 100644 index 00000000..43642732 --- /dev/null +++ b/src/examples/sample-plugin/configure.ac @@ -0,0 +1,9 @@ +AC_INIT(sample_plugin, 1.0) +LT_INIT +AM_INIT_AUTOMAKE +AM_SILENT_RULES([yes]) +AC_PREFIX_DEFAULT([/usr]) + +AC_PROG_CC + +AC_OUTPUT([Makefile]) diff --git a/src/examples/sample-plugin/sample/node.c b/src/examples/sample-plugin/sample/node.c new file mode 100644 index 00000000..94c1706b --- /dev/null +++ b/src/examples/sample-plugin/sample/node.c @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include + +typedef struct { + u32 next_index; + u32 sw_if_index; + u8 new_src_mac[6]; + u8 new_dst_mac[6]; +} sample_trace_t; + +static u8 * +format_mac_address (u8 * s, va_list * args) +{ + u8 *a = va_arg (*args, u8 *); + return format (s, "%02x:%02x:%02x:%02x:%02x:%02x", + a[0], a[1], a[2], a[3], a[4], a[5]); +} + +/* packet trace format function */ +static u8 * format_sample_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + sample_trace_t * t = va_arg (*args, sample_trace_t *); + + s = format (s, "SAMPLE: sw_if_index %d, next index %d\n", + t->sw_if_index, t->next_index); + s = format (s, " new src %U -> new dst %U", + format_mac_address, t->new_src_mac, + format_mac_address, t->new_dst_mac); + + return s; +} + +vlib_node_registration_t sample_node; + +#define foreach_sample_error \ +_(SWAPPED, "Mac swap packets processed") + +typedef enum { +#define _(sym,str) SAMPLE_ERROR_##sym, + foreach_sample_error +#undef _ + SAMPLE_N_ERROR, +} sample_error_t; + +static char * sample_error_strings[] = { +#define _(sym,string) string, + foreach_sample_error +#undef _ +}; + +typedef enum { + SAMPLE_NEXT_INTERFACE_OUTPUT, + SAMPLE_N_NEXT, +} sample_next_t; + +#define foreach_mac_address_offset \ +_(0) \ +_(1) \ +_(2) \ +_(3) \ +_(4) \ +_(5) + +static uword +sample_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + u32 n_left_from, * from, * to_next; + sample_next_t next_index; + u32 pkts_swapped = 0; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame (vm, node, next_index, + to_next, n_left_to_next); + + while (n_left_from >= 4 && n_left_to_next >= 2) + { + u32 next0 = SAMPLE_NEXT_INTERFACE_OUTPUT; + u32 next1 = SAMPLE_NEXT_INTERFACE_OUTPUT; + u32 sw_if_index0, sw_if_index1; + u8 tmp0[6], tmp1[6]; + ethernet_header_t *en0, *en1; + u32 bi0, bi1; + vlib_buffer_t * b0, * b1; + + /* Prefetch next iteration. */ + { + vlib_buffer_t * p2, * p3; + + p2 = vlib_get_buffer (vm, from[2]); + p3 = vlib_get_buffer (vm, from[3]); + + vlib_prefetch_buffer_header (p2, LOAD); + vlib_prefetch_buffer_header (p3, LOAD); + + CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE); + CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE); + } + + /* speculatively enqueue b0 and b1 to the current next frame */ + to_next[0] = bi0 = from[0]; + to_next[1] = bi1 = from[1]; + from += 2; + to_next += 2; + n_left_from -= 2; + n_left_to_next -= 2; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + + ASSERT (b0->current_data == 0); + ASSERT (b1->current_data == 0); + + en0 = vlib_buffer_get_current (b0); + en1 = vlib_buffer_get_current (b1); + + /* This is not the fastest way to swap src + dst mac addresses */ +#define _(a) tmp0[a] = en0->src_address[a]; + foreach_mac_address_offset; +#undef _ +#define _(a) en0->src_address[a] = en0->dst_address[a]; + foreach_mac_address_offset; +#undef _ +#define _(a) en0->dst_address[a] = tmp0[a]; + foreach_mac_address_offset; +#undef _ + +#define _(a) tmp1[a] = en1->src_address[a]; + foreach_mac_address_offset; +#undef _ +#define _(a) en1->src_address[a] = en1->dst_address[a]; + foreach_mac_address_offset; +#undef _ +#define _(a) en1->dst_address[a] = tmp1[a]; + foreach_mac_address_offset; +#undef _ + + + + sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; + sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX]; + + /* Send pkt back out the RX interface */ + vnet_buffer(b0)->sw_if_index[VLIB_TX] = sw_if_index0; + vnet_buffer(b1)->sw_if_index[VLIB_TX] = sw_if_index1; + + pkts_swapped += 2; + + if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE))) + { + if (b0->flags & VLIB_BUFFER_IS_TRACED) + { + sample_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + t->next_index = next0; + clib_memcpy (t->new_src_mac, en0->src_address, + sizeof (t->new_src_mac)); + clib_memcpy (t->new_dst_mac, en0->dst_address, + sizeof (t->new_dst_mac)); + + } + if (b1->flags & VLIB_BUFFER_IS_TRACED) + { + sample_trace_t *t = + vlib_add_trace (vm, node, b1, sizeof (*t)); + t->sw_if_index = sw_if_index1; + t->next_index = next1; + clib_memcpy (t->new_src_mac, en1->src_address, + sizeof (t->new_src_mac)); + clib_memcpy (t->new_dst_mac, en1->dst_address, + sizeof (t->new_dst_mac)); + } + } + + /* verify speculative enqueues, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, + to_next, n_left_to_next, + bi0, bi1, next0, next1); + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t * b0; + u32 next0 = SAMPLE_NEXT_INTERFACE_OUTPUT; + u32 sw_if_index0; + u8 tmp0[6]; + ethernet_header_t *en0; + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + /* + * Direct from the driver, we should be at offset 0 + * aka at &b0->data[0] + */ + ASSERT (b0->current_data == 0); + + en0 = vlib_buffer_get_current (b0); + + /* This is not the fastest way to swap src + dst mac addresses */ +#define _(a) tmp0[a] = en0->src_address[a]; + foreach_mac_address_offset; +#undef _ +#define _(a) en0->src_address[a] = en0->dst_address[a]; + foreach_mac_address_offset; +#undef _ +#define _(a) en0->dst_address[a] = tmp0[a]; + foreach_mac_address_offset; +#undef _ + + sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; + + /* Send pkt back out the RX interface */ + vnet_buffer(b0)->sw_if_index[VLIB_TX] = sw_if_index0; + + if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) { + sample_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + t->next_index = next0; + clib_memcpy (t->new_src_mac, en0->src_address, + sizeof (t->new_src_mac)); + clib_memcpy (t->new_dst_mac, en0->dst_address, + sizeof (t->new_dst_mac)); + } + + pkts_swapped += 1; + + /* verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + vlib_node_increment_counter (vm, sample_node.index, + SAMPLE_ERROR_SWAPPED, pkts_swapped); + return frame->n_vectors; +} + +VLIB_REGISTER_NODE (sample_node) = { + .function = sample_node_fn, + .name = "sample", + .vector_size = sizeof (u32), + .format_trace = format_sample_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(sample_error_strings), + .error_strings = sample_error_strings, + + .n_next_nodes = SAMPLE_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [SAMPLE_NEXT_INTERFACE_OUTPUT] = "interface-output", + }, +}; diff --git a/src/examples/sample-plugin/sample/sample.api b/src/examples/sample-plugin/sample/sample.api new file mode 100644 index 00000000..f99cdb38 --- /dev/null +++ b/src/examples/sample-plugin/sample/sample.api @@ -0,0 +1,39 @@ +/* Hey Emacs use -*- mode: C -*- */ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Define a simple binary API to control the feature */ + +define sample_macswap_enable_disable { + /* Client identifier, set from api_main.my_client_index */ + u32 client_index; + + /* Arbitrary context, so client can match reply to request */ + u32 context; + + /* Enable / disable the feature */ + u8 enable_disable; + + /* Interface handle */ + u32 sw_if_index; +}; + +define sample_macswap_enable_disable_reply { + /* From the request */ + u32 context; + + /* Return value, zero means all OK */ + i32 retval; +}; diff --git a/src/examples/sample-plugin/sample/sample.c b/src/examples/sample-plugin/sample/sample.c new file mode 100644 index 00000000..603cb2d0 --- /dev/null +++ b/src/examples/sample-plugin/sample/sample.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + *------------------------------------------------------------------ + * sample.c - simple MAC-swap API / debug CLI handling + *------------------------------------------------------------------ + */ + +#include +#include +#include + +#include +#include +#include + +/* define message IDs */ +#include + +/* define message structures */ +#define vl_typedefs +#include +#undef vl_typedefs + +/* define generated endian-swappers */ +#define vl_endianfun +#include +#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 +#undef vl_printfun + +/* Get the API version number */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#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_sample_plugin_api_msg \ +_(SAMPLE_MACSWAP_ENABLE_DISABLE, sample_macswap_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) +{ + sample_main_t * sm = &sample_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 sample_macswap_enable_disable (sample_main_t * sm, u32 sw_if_index, + int enable_disable) +{ + vnet_sw_interface_t * sw; + int rv = 0; + + /* Utterly wrong? */ + if (pool_is_free_index (sm->vnet_main->interface_main.sw_interfaces, + sw_if_index)) + return VNET_API_ERROR_INVALID_SW_IF_INDEX; + + /* Not a physical port? */ + sw = vnet_get_sw_interface (sm->vnet_main, sw_if_index); + if (sw->type != VNET_SW_INTERFACE_TYPE_HARDWARE) + return VNET_API_ERROR_INVALID_SW_IF_INDEX; + + vnet_feature_enable_disable ("device-input", "sample", + sw_if_index, enable_disable, 0, 0); + + return rv; +} + +static clib_error_t * +macswap_enable_disable_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + sample_main_t * sm = &sample_main; + u32 sw_if_index = ~0; + int enable_disable = 1; + + int rv; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { + if (unformat (input, "disable")) + enable_disable = 0; + else if (unformat (input, "%U", unformat_vnet_sw_interface, + sm->vnet_main, &sw_if_index)) + ; + else + break; + } + + if (sw_if_index == ~0) + return clib_error_return (0, "Please specify an interface..."); + + rv = sample_macswap_enable_disable (sm, sw_if_index, enable_disable); + + switch(rv) { + case 0: + break; + + case VNET_API_ERROR_INVALID_SW_IF_INDEX: + return clib_error_return + (0, "Invalid interface, only works on physical ports"); + break; + + case VNET_API_ERROR_UNIMPLEMENTED: + return clib_error_return (0, "Device driver doesn't support redirection"); + break; + + default: + return clib_error_return (0, "sample_macswap_enable_disable returned %d", + rv); + } + return 0; +} + +VLIB_CLI_COMMAND (sr_content_command, static) = { + .path = "sample macswap", + .short_help = + "sample macswap [disable]", + .function = macswap_enable_disable_command_fn, +}; + +/* API message handler */ +static void vl_api_sample_macswap_enable_disable_t_handler +(vl_api_sample_macswap_enable_disable_t * mp) +{ + vl_api_sample_macswap_enable_disable_reply_t * rmp; + sample_main_t * sm = &sample_main; + int rv; + + rv = sample_macswap_enable_disable (sm, ntohl(mp->sw_if_index), + (int) (mp->enable_disable)); + + REPLY_MACRO(VL_API_SAMPLE_MACSWAP_ENABLE_DISABLE_REPLY); +} + +/* Set up the API message handling tables */ +static clib_error_t * +sample_plugin_api_hookup (vlib_main_t *vm) +{ + sample_main_t * sm = &sample_main; +#define _(N,n) \ + vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base), \ + #n, \ + vl_api_##n##_t_handler, \ + vl_noop_handler, \ + vl_api_##n##_t_endian, \ + vl_api_##n##_t_print, \ + sizeof(vl_api_##n##_t), 1); + foreach_sample_plugin_api_msg; +#undef _ + + return 0; +} + +#define vl_msg_name_crc_list +#include +#undef vl_msg_name_crc_list + +static void +setup_message_id_table (sample_main_t * sm, api_main_t *am) +{ +#define _(id,n,crc) \ + vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base); + foreach_vl_msg_name_crc_sample; +#undef _ +} + +static clib_error_t * sample_init (vlib_main_t * vm) +{ + sample_main_t * sm = &sample_main; + clib_error_t * error = 0; + u8 * name; + + name = format (0, "sample_%08x%c", api_version, 0); + + /* Ask for a correctly-sized block of API message decode slots */ + sm->msg_id_base = vl_msg_api_get_msg_ids + ((char *) name, VL_MSG_FIRST_AVAILABLE); + + error = sample_plugin_api_hookup (vm); + + /* Add our API messages to the global name_crc hash table */ + setup_message_id_table (sm, &api_main); + + vec_free(name); + + return error; +} + +VLIB_INIT_FUNCTION (sample_init); + +VNET_FEATURE_INIT (sample, static) = +{ + .arc_name = "device-input", + .node_name = "sample", + .runs_before = VNET_FEATURES ("ethernet-input"), +}; diff --git a/src/examples/sample-plugin/sample/sample.h b/src/examples/sample-plugin/sample/sample.h new file mode 100644 index 00000000..d268d482 --- /dev/null +++ b/src/examples/sample-plugin/sample/sample.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __included_sample_h__ +#define __included_sample_h__ + +#include +#include +#include + +#include +#include +#include + +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; +} sample_main_t; + +sample_main_t sample_main; + +vlib_node_registration_t sample_node; + +#endif /* __included_sample_h__ */ diff --git a/src/examples/sample-plugin/sample/sample_all_api_h.h b/src/examples/sample-plugin/sample/sample_all_api_h.h new file mode 100644 index 00000000..774d782f --- /dev/null +++ b/src/examples/sample-plugin/sample/sample_all_api_h.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Include the generated file, see BUILT_SOURCES in Makefile.am */ +#include diff --git a/src/examples/sample-plugin/sample/sample_msg_enum.h b/src/examples/sample-plugin/sample/sample_msg_enum.h new file mode 100644 index 00000000..af4172f7 --- /dev/null +++ b/src/examples/sample-plugin/sample/sample_msg_enum.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef included_sample_msg_enum_h +#define included_sample_msg_enum_h + +#include + +#define vl_msg_id(n,h) n, +typedef enum { +#include + /* We'll want to know how many messages IDs we need... */ + VL_MSG_FIRST_AVAILABLE, +} vl_msg_id_t; +#undef vl_msg_id + +#endif /* included_sample_msg_enum_h */ diff --git a/src/examples/sample-plugin/sample/sample_test.c b/src/examples/sample-plugin/sample/sample_test.c new file mode 100644 index 00000000..dd1b0215 --- /dev/null +++ b/src/examples/sample-plugin/sample/sample_test.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + *------------------------------------------------------------------ + * sample_test.c - test harness plugin + *------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include + +uword unformat_sw_if_index (unformat_input_t * input, va_list * args); + +/* Declare message IDs */ +#include + +/* define message structures */ +#define vl_typedefs +#include +#undef vl_typedefs + +/* declare message handlers for each api */ + +#define vl_endianfun /* define message structures */ +#include +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) +#define vl_printfun +#include +#undef vl_printfun + +/* Get the API version number. */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#undef vl_api_version + + +typedef struct { + /* API message ID base */ + u16 msg_id_base; + vat_main_t *vat_main; +} sample_test_main_t; + +sample_test_main_t sample_test_main; + +#define foreach_standard_reply_retval_handler \ +_(sample_macswap_enable_disable_reply) + +#define _(n) \ + static void vl_api_##n##_t_handler \ + (vl_api_##n##_t * mp) \ + { \ + vat_main_t * vam = sample_test_main.vat_main; \ + i32 retval = ntohl(mp->retval); \ + if (vam->async_mode) { \ + vam->async_errors += (retval < 0); \ + } else { \ + vam->retval = retval; \ + vam->result_ready = 1; \ + } \ + } +foreach_standard_reply_retval_handler; +#undef _ + +/* + * Table of message reply handlers, must include boilerplate handlers + * we just generated + */ +#define foreach_vpe_api_reply_msg \ +_(SAMPLE_MACSWAP_ENABLE_DISABLE_REPLY, sample_macswap_enable_disable_reply) + + +/* 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_sample_macswap_enable_disable (vat_main_t * vam) +{ + sample_test_main_t * sm = &sample_test_main; + unformat_input_t * i = vam->input; + f64 timeout; + int enable_disable = 1; + u32 sw_if_index = ~0; + vl_api_sample_macswap_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(SAMPLE_MACSWAP_ENABLE_DISABLE, sample_macswap_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 \ +_(sample_macswap_enable_disable, " [disable]") + +void vat_api_hookup (vat_main_t *vam) +{ + sample_test_main_t * sm = &sample_test_main; + /* Hook up handlers for replies from the data plane plug-in */ +#define _(N,n) \ + vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base), \ + #n, \ + vl_api_##n##_t_handler, \ + vl_noop_handler, \ + vl_api_##n##_t_endian, \ + vl_api_##n##_t_print, \ + sizeof(vl_api_##n##_t), 1); + foreach_vpe_api_reply_msg; +#undef _ + + /* API messages we can send */ +#define _(n,h) hash_set_mem (vam->function_by_name, #n, api_##n); + foreach_vpe_api_msg; +#undef _ + + /* Help strings */ +#define _(n,h) hash_set_mem (vam->help_by_name, #n, h); + foreach_vpe_api_msg; +#undef _ +} + +clib_error_t * vat_plugin_register (vat_main_t *vam) +{ + sample_test_main_t * sm = &sample_test_main; + u8 * name; + + sm->vat_main = vam; + + name = format (0, "sample_%08x%c", api_version, 0); + sm->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name); + + if (sm->msg_id_base != (u16) ~0) + vat_api_hookup (vam); + + vec_free(name); + + return 0; +} diff --git a/src/m4/ax_vpp_find_jdk8.m4 b/src/m4/ax_vpp_find_jdk8.m4 new file mode 100644 index 00000000..29459822 --- /dev/null +++ b/src/m4/ax_vpp_find_jdk8.m4 @@ -0,0 +1,29 @@ + + +AC_DEFUN([AX_VPP_FIND_JDK8], +[ +while true +do + test "${JAVA_HOME+set}" = set && break + + for dir in $(find /usr/lib/jvm/* -maxdepth 0 -type d); do + AC_MSG_CHECKING([${dir} for Java 8 compiler]) + JAVA_VERSION=$(${dir}/bin/javac -source 8 -version 2>&1) + if test 0 -eq "$?"; then + JAVA_VERSION=$(echo "${JAVA_VERSION}" | cut -d\ -f2) + JAVA_HOME=${dir} + JAVAC=${dir}/bin/javac + JAVAH=${dir}/bin/javah + JAR=${dir}/bin/jar + AC_MSG_RESULT([found version $JAVA_VERSION]) + break + else + JAVA_VERSION="" + AC_MSG_RESULT([no]) + fi + done + + test "${JAVA_HOME}set" = set && AC_MSG_ERROR([Could not find Java 8 compiler]) + break +done +]) diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index ffc4b3ab..987310b7 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -22,10 +22,15 @@ BUILT_SOURCES = vppplugins_LTLIBRARIES = vppapitestplugins_LTLIBRARIES = noinst_HEADERS = +nobase_apiinclude_HEADERS = vppapitestpluginsdir = ${libdir}/vpp_api_test_plugins vpppluginsdir = ${libdir}/vpp_plugins +if ENABLE_ACL_PLUGIN +include acl.am +endif + if ENABLE_FLOWPERPKT_PLUGIN include flowperpkt.am endif @@ -34,10 +39,22 @@ if ENABLE_ILA_PLUGIN include ila.am endif +if ENABLE_IOAM_PLUGIN +include ioam.am +endif + +if ENABLE_LB_PLUGIN +include lb.am +endif + if ENABLE_SIXRD_PLUGIN include sixrd.am endif +if ENABLE_SNAT_PLUGIN +include snat.am +endif + include ../suffix-rules.mk # Remove *.la files @@ -50,6 +67,7 @@ install-data-hook: ############################################################################### apidir = $(prefix)/share/vpp/api/plugins +apiincludedir = ${includedir}/vpp_plugins api_DATA = \ $(patsubst %.api,%.api.json,$(API_FILES)) diff --git a/src/plugins/acl.am b/src/plugins/acl.am new file mode 100644 index 00000000..efed31c2 --- /dev/null +++ b/src/plugins/acl.am @@ -0,0 +1,35 @@ +# Copyright (c) 2016 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +vppapitestplugins_LTLIBRARIES += acl_test_plugin.la +vppplugins_LTLIBRARIES += acl_plugin.la + +acl_plugin_la_SOURCES = \ + acl/acl.c \ + acl/node_in.c \ + acl/node_out.c \ + acl/l2sess.c \ + acl/l2sess_node.c \ + acl/l2sess.h \ + acl/acl_plugin.api.h + +API_FILES += acl/acl.api + +nobase_apiinclude_HEADERS += \ + acl/acl_all_api_h.h \ + acl/acl_msg_enum.h \ + acl/acl.api.h + +acl_test_plugin_la_SOURCES = acl/acl_test.c acl/acl_plugin.api.h + +# vi:syntax=automake diff --git a/src/plugins/acl/acl.api b/src/plugins/acl/acl.api new file mode 100644 index 00000000..58a5a171 --- /dev/null +++ b/src/plugins/acl/acl.api @@ -0,0 +1,444 @@ +/* Hey Emacs use -*- mode: C -*- */ +/* + * 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. + */ + +/** \file + This file defines the vpp control-plane API messages + used to control the ACL plugin +*/ + + +/** \brief Get the plugin version + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ + +define acl_plugin_get_version +{ + u32 client_index; + u32 context; +}; + +/** \brief Reply to get the plugin version + @param context - returned sender context, to match reply w/ request + @param major - Incremented every time a known breaking behavior change is introduced + @param minor - Incremented with small changes, may be used to avoid buggy versions +*/ + +define acl_plugin_get_version_reply +{ + u32 context; + u32 major; + u32 minor; +}; + +/** \brief Access List Rule entry + @param is_permit - deny (0), permit (1), or permit+reflect(2) action on this rule. + @param is_ipv6 - IP addresses in this rule are IPv6 (1) or IPv4 (0) + @param src_ip_addr - Source prefix value + @param src_ip_prefix_len - Source prefix length + @param dst_ip_addr - Destination prefix value + @param dst_ip_prefix_len - Destination prefix length + @param proto - L4 protocol (http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml) + @param srcport_or_icmptype_first - beginning of source port or ICMP4/6 type range + @param srcport_or_icmptype_last - end of source port or ICMP4/6 type range + @param dstport_or_icmpcode_first - beginning of destination port or ICMP4/6 code range + @param dstport_or_icmpcode_last - end of destination port or ICMP4/6 code range + @param tcp_flags_mask - if proto==6, match masked TCP flags with this value + @param tcp_flags_value - if proto==6, mask to AND the TCP flags in the packet with +*/ + +typeonly manual_print manual_endian define acl_rule +{ + u8 is_permit; + u8 is_ipv6; + u8 src_ip_addr[16]; + u8 src_ip_prefix_len; + u8 dst_ip_addr[16]; + u8 dst_ip_prefix_len; +/* + * L4 protocol. IANA number. 1 = ICMP, 58 = ICMPv6, 6 = TCP, 17 = UDP. + * 0 => ignore L4 and ignore the ports/tcpflags when matching. + */ + u8 proto; +/* + * If the L4 protocol is TCP or UDP, the below + * hold ranges of ports, else if the L4 is ICMP/ICMPv6 + * they hold ranges of ICMP(v6) types/codes. + * + * Ranges are inclusive, i.e. to match "any" TCP/UDP port, + * use first=0,last=65535. For ICMP(v6), + * use first=0,last=255. + */ + u16 srcport_or_icmptype_first; + u16 srcport_or_icmptype_last; + u16 dstport_or_icmpcode_first; + u16 dstport_or_icmpcode_last; +/* + * for proto = 6, this matches if the + * TCP flags in the packet, ANDed with tcp_flags_mask, + * is equal to tcp_flags_value. + */ + u8 tcp_flags_mask; + u8 tcp_flags_value; +}; + +/** \brief MACIP Access List Rule entry + @param is_permit - deny (0), permit (1) action on this rule. + @param is_ipv6 - IP addresses in this rule are IPv6 (1) or IPv4 (0) + @param src_mac - match masked source MAC address against this value + @param src_mac_mask - AND source MAC address with this value before matching + @param src_ip_addr - Source prefix value + @param src_ip_prefix_len - Source prefix length +*/ + +typeonly manual_print manual_endian define macip_acl_rule +{ + u8 is_permit; + u8 is_ipv6; +/* + * The source mac of the packet ANDed with src_mac_mask. + * The source ip[46] address in the packet is matched + * against src_ip_addr, with src_ip_prefix_len set to 0. + * + * For better performance, minimize the number of + * (src_mac_mask, src_ip_prefix_len) combinations + * in a MACIP ACL. + */ + u8 src_mac[6]; + u8 src_mac_mask[6]; + u8 src_ip_addr[16]; + u8 src_ip_prefix_len; +}; + +/** \brief Replace an existing ACL in-place or create a new ACL + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param acl_index - an existing ACL entry (0..0xfffffffe) to replace, or 0xffffffff to make new ACL + @param tag - a string value stored along with the ACL, for descriptive purposes + @param count - number of ACL rules + @r - Rules for this access-list +*/ + +manual_print manual_endian define acl_add_replace +{ + u32 client_index; + u32 context; + u32 acl_index; /* ~0 to add, existing ACL# to replace */ + u8 tag[64]; /* What gets in here gets out in the corresponding tag field when dumping the ACLs. */ + u32 count; + vl_api_acl_rule_t r[count]; +}; + +/** \brief Reply to add/replace ACL + @param context - returned sender context, to match reply w/ request + @param acl_index - index of the updated or newly created ACL + @param retval 0 - no error +*/ + +define acl_add_replace_reply +{ + u32 context; + u32 acl_index; + i32 retval; +}; + +/** \brief Delete an ACL + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param acl_index - ACL index to delete +*/ + +define acl_del +{ + u32 client_index; + u32 context; + u32 acl_index; +}; + +/** \brief Reply to delete the ACL + @param context - returned sender context, to match reply w/ request + @param retval 0 - no error +*/ + +define acl_del_reply +{ + u32 context; + i32 retval; +}; + +/* acl_interface_add_del(_reply) to be deprecated in lieu of acl_interface_set_acl_list */ +/** \brief Use acl_interface_set_acl_list instead + Append/remove an ACL index to/from the list of ACLs checked for an interface + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param is_add - add or delete the ACL index from the list + @param is_input - check the ACL on input (1) or output (0) + @param sw_if_index - the interface to alter the list of ACLs on + @param acl_index - index of ACL for the operation +*/ + +define acl_interface_add_del +{ + u32 client_index; + u32 context; + u8 is_add; +/* + * is_input = 0 => ACL applied on interface egress + * is_input = 1 => ACL applied on interface ingress + */ + u8 is_input; + u32 sw_if_index; + u32 acl_index; +}; + +/** \brief Reply to alter the ACL list + @param context - returned sender context, to match reply w/ request + @param retval 0 - no error +*/ + +define acl_interface_add_del_reply +{ + u32 context; + i32 retval; +}; + +/** \brief Set the vector of input/output ACLs checked for an interface + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sw_if_index - the interface to alter the list of ACLs on + @param count - total number of ACL indices in the vector + @param n_input - this many first elements correspond to input ACLs, the rest - output + @param acls - vector of ACL indices +*/ + +manual_endian define acl_interface_set_acl_list +{ + u32 client_index; + u32 context; + u32 sw_if_index; + u8 count; + u8 n_input; /* First n_input ACLs are set as a list of input ACLs, the rest are applied as output */ + u32 acls[count]; +}; + +/** \brief Reply to set the ACL list on an interface + @param context - returned sender context, to match reply w/ request + @param retval 0 - no error +*/ + +define acl_interface_set_acl_list_reply +{ + u32 context; + i32 retval; +}; + +/** \brief Dump the specific ACL contents or all of the ACLs' contents + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param acl_index - ACL index to dump, ~0 to dump all ACLs +*/ + +define acl_dump +{ + u32 client_index; + u32 context; + u32 acl_index; /* ~0 for all ACLs */ +}; + +/** \brief Details about a single ACL contents + @param context - returned sender context, to match reply w/ request + @param acl_index - ACL index whose contents are being sent in this message + @param tag - Descriptive tag value which was supplied at ACL creation + @param count - Number of rules in this ACL + @param r - Array of rules within this ACL +*/ + +manual_print manual_endian define acl_details +{ + u32 context; + u32 acl_index; + u8 tag[64]; /* Same blob that was supplied to us when creating the ACL, one hopes. */ + u32 count; + vl_api_acl_rule_t r[count]; +}; + +/** \brief Dump the list(s) of ACL applied to specific or all interfaces + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sw_if_index - interface to dump the ACL list for +*/ + +define acl_interface_list_dump +{ + u32 client_index; + u32 context; + u32 sw_if_index; /* ~0 for all interfaces */ +}; + +/** \brief Details about a single ACL contents + @param context - returned sender context, to match reply w/ request + @param sw_if_index - interface for which the list of ACLs is applied + @param count - total length of acl indices vector + @param n_input - this many of indices in the beginning are input ACLs, the rest - output + @param acls - the vector of ACL indices +*/ + +manual_endian define acl_interface_list_details +{ + u32 context; + u32 sw_if_index; + u8 count; + u8 n_input; + u32 acls[count]; +}; + +/** \brief Add a MACIP ACL + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param tag - descriptive value for this MACIP ACL + @param count - number of rules in this ACL + @param r - vector of MACIP ACL rules +*/ + +manual_print manual_endian define macip_acl_add +{ + u32 client_index; + u32 context; + u8 tag[64]; + u32 count; + vl_api_macip_acl_rule_t r[count]; +}; + +/** \brief Reply to add MACIP ACL + @param context - returned sender context, to match reply w/ request + @param acl_index - index of the newly created ACL + @param retval 0 - no error +*/ + +define macip_acl_add_reply +{ + u32 context; + u32 acl_index; + i32 retval; +}; + +/** \brief Delete a MACIP ACL + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param acl_index - MACIP ACL index to delete +*/ + +define macip_acl_del +{ + u32 client_index; + u32 context; + u32 acl_index; +}; + +/** \brief Reply to delete the MACIP ACL + @param context - returned sender context, to match reply w/ request + @param retval 0 - no error +*/ + +define macip_acl_del_reply +{ + u32 context; + i32 retval; +}; + +/** \brief Add or delete a MACIP ACL to/from interface + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param is_add - add (1) or delete (0) ACL from being used on an interface + @param sw_if_index - interface to apply the action to + @param acl_index - MACIP ACL index +*/ + +define macip_acl_interface_add_del +{ + u32 client_index; + u32 context; + u8 is_add; + /* macip ACLs are always input */ + u32 sw_if_index; + u32 acl_index; +}; + +/** \brief Reply to apply/unapply the MACIP ACL + @param context - returned sender context, to match reply w/ request + @param retval 0 - no error +*/ + +define macip_acl_interface_add_del_reply +{ + u32 context; + i32 retval; +}; + +/** \brief Dump one or all defined MACIP ACLs + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param acl_index - MACIP ACL index or ~0 to dump all ACLs +*/ + +define macip_acl_dump +{ + u32 client_index; + u32 context; + u32 acl_index; /* ~0 for all ACLs */ +}; + +/** \brief Details about one MACIP ACL + @param context - returned sender context, to match reply w/ request + @param acl_index - index of this MACIP ACL + @param tag - descriptive tag which was supplied during the creation + @param count - length of the vector of MACIP ACL rules + @param r - rules comprising this ACL +*/ + +manual_print manual_endian define macip_acl_details +{ + u32 context; + u32 acl_index; + u8 tag[64]; + u32 count; + vl_api_macip_acl_rule_t r[count]; +}; + +/** \brief Get the vector of MACIP ACL IDs applied to the interfaces + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ + +define macip_acl_interface_get +{ + u32 client_index; + u32 context; +}; + +/** \brief Reply with the vector of MACIP ACLs by sw_if_index + @param context - returned sender context, to match reply w/ request + @param count - total number of elements in the vector + @param acls - the vector of active MACACL indices per sw_if_index +*/ + +define macip_acl_interface_get_reply +{ + u32 context; + u32 count; + u32 acls[count]; +}; + diff --git a/src/plugins/acl/acl.c b/src/plugins/acl/acl.c new file mode 100644 index 00000000..8ff5a6b7 --- /dev/null +++ b/src/plugins/acl/acl.c @@ -0,0 +1,1901 @@ +/* + * 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. + */ + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +/* define message IDs */ +#include + +/* define message structures */ +#define vl_typedefs +#include +#undef vl_typedefs + +/* define generated endian-swappers */ +#define vl_endianfun +#include +#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 +#undef vl_printfun + +/* Get the API version number */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#undef vl_api_version + +#include "node_in.h" +#include "node_out.h" + +acl_main_t acl_main; + +/* + * 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); + +#define REPLY_MACRO2(t, body) \ +do { \ + unix_shared_memory_queue_t * q; \ + rv = vl_msg_api_pd_handler (mp, rv); \ + 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)+am->msg_id_base); \ + rmp->context = mp->context; \ + rmp->retval = ntohl(rv); \ + do {body;} while (0); \ + vl_msg_api_send_shmem (q, (u8 *)&rmp); \ +} while(0); + +#define REPLY_MACRO3(t, n, body) \ +do { \ + unix_shared_memory_queue_t * q; \ + rv = vl_msg_api_pd_handler (mp, rv); \ + q = vl_api_client_index_to_input_queue (mp->client_index); \ + if (!q) \ + return; \ + \ + rmp = vl_msg_api_alloc (sizeof (*rmp) + n); \ + rmp->_vl_msg_id = ntohs((t)+am->msg_id_base); \ + rmp->context = mp->context; \ + rmp->retval = ntohl(rv); \ + do {body;} while (0); \ + vl_msg_api_send_shmem (q, (u8 *)&rmp); \ +} while(0); + + +/* List of message types that this plugin understands */ + +#define foreach_acl_plugin_api_msg \ +_(ACL_PLUGIN_GET_VERSION, acl_plugin_get_version) \ +_(ACL_ADD_REPLACE, acl_add_replace) \ +_(ACL_DEL, acl_del) \ +_(ACL_INTERFACE_ADD_DEL, acl_interface_add_del) \ +_(ACL_INTERFACE_SET_ACL_LIST, acl_interface_set_acl_list) \ +_(ACL_DUMP, acl_dump) \ +_(ACL_INTERFACE_LIST_DUMP, acl_interface_list_dump) \ +_(MACIP_ACL_ADD, macip_acl_add) \ +_(MACIP_ACL_DEL, macip_acl_del) \ +_(MACIP_ACL_INTERFACE_ADD_DEL, macip_acl_interface_add_del) \ +_(MACIP_ACL_DUMP, macip_acl_dump) \ +_(MACIP_ACL_INTERFACE_GET, macip_acl_interface_get) + +/* + * 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) +{ + acl_main_t *am = &acl_main; + clib_error_t *error = 0; + + am->vlib_main = vm; + am->vnet_main = h->vnet_main; + am->ethernet_main = h->ethernet_main; + + l2sess_vlib_plugin_register(vm, h, from_early_init); + + return error; +} + + +static void +vl_api_acl_plugin_get_version_t_handler (vl_api_acl_plugin_get_version_t * mp) +{ + acl_main_t *am = &acl_main; + vl_api_acl_plugin_get_version_reply_t *rmp; + int msg_size = sizeof (*rmp); + unix_shared_memory_queue_t *q; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + { + return; + } + + rmp = vl_msg_api_alloc (msg_size); + memset (rmp, 0, msg_size); + rmp->_vl_msg_id = + ntohs (VL_API_ACL_PLUGIN_GET_VERSION_REPLY + am->msg_id_base); + rmp->context = mp->context; + rmp->major = htonl (ACL_PLUGIN_VERSION_MAJOR); + rmp->minor = htonl (ACL_PLUGIN_VERSION_MINOR); + + vl_msg_api_send_shmem (q, (u8 *) & rmp); +} + + +static int +acl_add_list (u32 count, vl_api_acl_rule_t rules[], + u32 * acl_list_index, u8 * tag) +{ + acl_main_t *am = &acl_main; + acl_list_t *a; + acl_rule_t *r; + acl_rule_t *acl_new_rules; + int i; + + if (*acl_list_index != ~0) + { + /* They supplied some number, let's see if this ACL exists */ + if (pool_is_free_index (am->acls, *acl_list_index)) + { + /* tried to replace a non-existent ACL, no point doing anything */ + return -1; + } + } + + /* Create and populate the rules */ + acl_new_rules = clib_mem_alloc_aligned (sizeof (acl_rule_t) * count, + CLIB_CACHE_LINE_BYTES); + if (!acl_new_rules) + { + /* Could not allocate rules. New or existing ACL - bail out regardless */ + return -1; + } + + for (i = 0; i < count; i++) + { + r = &acl_new_rules[i]; + r->is_permit = rules[i].is_permit; + r->is_ipv6 = rules[i].is_ipv6; + if (r->is_ipv6) + { + memcpy (&r->src, rules[i].src_ip_addr, sizeof (r->src)); + memcpy (&r->dst, rules[i].dst_ip_addr, sizeof (r->dst)); + } + else + { + memcpy (&r->src.ip4, rules[i].src_ip_addr, sizeof (r->src.ip4)); + memcpy (&r->dst.ip4, rules[i].dst_ip_addr, sizeof (r->dst.ip4)); + } + r->src_prefixlen = rules[i].src_ip_prefix_len; + r->dst_prefixlen = rules[i].dst_ip_prefix_len; + r->proto = rules[i].proto; + r->src_port_or_type_first = rules[i].srcport_or_icmptype_first; + r->src_port_or_type_last = rules[i].srcport_or_icmptype_last; + r->dst_port_or_code_first = rules[i].dstport_or_icmpcode_first; + r->dst_port_or_code_last = rules[i].dstport_or_icmpcode_last; + r->tcp_flags_value = rules[i].tcp_flags_value; + r->tcp_flags_mask = rules[i].tcp_flags_mask; + } + + if (~0 == *acl_list_index) + { + /* Get ACL index */ + pool_get_aligned (am->acls, a, CLIB_CACHE_LINE_BYTES); + memset (a, 0, sizeof (*a)); + /* Will return the newly allocated ACL index */ + *acl_list_index = a - am->acls; + } + else + { + a = am->acls + *acl_list_index; + /* Get rid of the old rules */ + clib_mem_free (a->rules); + } + a->rules = acl_new_rules; + a->count = count; + memcpy (a->tag, tag, sizeof (a->tag)); + + return 0; +} + +static int +acl_del_list (u32 acl_list_index) +{ + acl_main_t *am = &acl_main; + acl_list_t *a; + int i, ii; + if (pool_is_free_index (am->acls, acl_list_index)) + { + return -1; + } + + /* delete any references to the ACL */ + for (i = 0; i < vec_len (am->output_acl_vec_by_sw_if_index); i++) + { + for (ii = 0; ii < vec_len (am->output_acl_vec_by_sw_if_index[i]); + /* see body */ ) + { + if (acl_list_index == am->output_acl_vec_by_sw_if_index[i][ii]) + { + vec_del1 (am->output_acl_vec_by_sw_if_index[i], ii); + } + else + { + ii++; + } + } + } + for (i = 0; i < vec_len (am->input_acl_vec_by_sw_if_index); i++) + { + for (ii = 0; ii < vec_len (am->input_acl_vec_by_sw_if_index[i]); + /* see body */ ) + { + if (acl_list_index == am->input_acl_vec_by_sw_if_index[i][ii]) + { + vec_del1 (am->input_acl_vec_by_sw_if_index[i], ii); + } + else + { + ii++; + } + } + } + + /* now we can delete the ACL itself */ + a = &am->acls[acl_list_index]; + if (a->rules) + { + clib_mem_free (a->rules); + } + pool_put (am->acls, a); + return 0; +} + +/* Some aids in ASCII graphing the content */ +#define XX "\377" +#define __ "\000" +#define _(x) +#define v + +u8 ip4_5tuple_mask[] = +_(" dmac smac etype ") +_(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v __ __ v + _(" v ihl totlen ") + _(0x0000) + __ __ __ __ + _(" ident fl+fo ") + _(0x0004) + __ __ __ __ + _(" ttl pr checksum ") + _(0x0008) + __ XX __ __ + _(" src address ") + _(0x000C) + XX XX XX XX + _(" dst address ") + _(0x0010) + XX XX XX XX + _("L4 T/U sport dport ") + _(tcpudp) + XX XX XX XX + _(padpad) + __ __ __ __ + _(padpad) + __ __ __ __ + _(padeth) + __ __; + + u8 ip6_5tuple_mask[] = + _(" dmac smac etype ") + _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v __ __ v + _(" v tc + flow ") + _(0x0000) __ __ __ __ + _(" plen nh hl ") + _(0x0004) __ __ XX __ + _(" src address ") + _(0x0008) XX XX XX XX + _(0x000C) XX XX XX XX + _(0x0010) XX XX XX XX + _(0x0014) XX XX XX XX + _(" dst address ") + _(0x0018) XX XX XX XX + _(0x001C) XX XX XX XX + _(0x0020) XX XX XX XX + _(0x0024) XX XX XX XX + _("L4T/U sport dport ") + _(tcpudp) XX XX XX XX _(padpad) __ __ __ __ _(padeth) __ __; + +#undef XX +#undef __ +#undef _ +#undef v + + static int count_skip (u8 * p, u32 size) +{ + u64 *p64 = (u64 *) p; + /* Be tolerant to null pointer */ + if (0 == p) + return 0; + + while ((0ULL == *p64) && ((u8 *) p64 - p) < size) + { + p64++; + } + return (p64 - (u64 *) p) / 2; +} + +static int +acl_classify_add_del_table_big (vnet_classify_main_t * cm, u8 * mask, + u32 mask_len, u32 next_table_index, + u32 miss_next_index, u32 * table_index, + int is_add) +{ + u32 nbuckets = 65536; + u32 memory_size = 2 << 30; + u32 skip = count_skip (mask, mask_len); + u32 match = (mask_len / 16) - skip; + u8 *skip_mask_ptr = mask + 16 * skip; + u32 current_data_flag = 0; + int current_data_offset = 0; + + if (0 == match) + match = 1; + + return vnet_classify_add_del_table (cm, skip_mask_ptr, nbuckets, + memory_size, skip, match, + next_table_index, miss_next_index, + table_index, current_data_flag, + current_data_offset, is_add, + 1 /* delete_chain */); +} + +static int +acl_classify_add_del_table_small (vnet_classify_main_t * cm, u8 * mask, + u32 mask_len, u32 next_table_index, + u32 miss_next_index, u32 * table_index, + int is_add) +{ + u32 nbuckets = 32; + u32 memory_size = 2 << 20; + u32 skip = count_skip (mask, mask_len); + u32 match = (mask_len / 16) - skip; + u8 *skip_mask_ptr = mask + 16 * skip; + u32 current_data_flag = 0; + int current_data_offset = 0; + + if (0 == match) + match = 1; + + return vnet_classify_add_del_table (cm, skip_mask_ptr, nbuckets, + memory_size, skip, match, + next_table_index, miss_next_index, + table_index, current_data_flag, + current_data_offset, is_add, + 1 /* delete_chain */); +} + + +static int +acl_unhook_l2_input_classify (acl_main_t * am, u32 sw_if_index) +{ + vnet_classify_main_t *cm = &vnet_classify_main; + u32 ip4_table_index = ~0; + u32 ip6_table_index = ~0; + + vec_validate_init_empty (am->acl_ip4_input_classify_table_by_sw_if_index, + sw_if_index, ~0); + vec_validate_init_empty (am->acl_ip6_input_classify_table_by_sw_if_index, + sw_if_index, ~0); + + vnet_l2_input_classify_enable_disable (sw_if_index, 0); + + if (am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] != ~0) + { + ip4_table_index = + am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index]; + am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] = ~0; + acl_classify_add_del_table_big (cm, ip4_5tuple_mask, + sizeof (ip4_5tuple_mask) - 1, ~0, + am->l2_input_classify_next_acl, + &ip4_table_index, 0); + } + if (am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] != ~0) + { + ip6_table_index = + am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index]; + am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] = ~0; + acl_classify_add_del_table_big (cm, ip6_5tuple_mask, + sizeof (ip6_5tuple_mask) - 1, ~0, + am->l2_input_classify_next_acl, + &ip6_table_index, 0); + } + + return 0; +} + +static int +acl_unhook_l2_output_classify (acl_main_t * am, u32 sw_if_index) +{ + vnet_classify_main_t *cm = &vnet_classify_main; + u32 ip4_table_index = ~0; + u32 ip6_table_index = ~0; + + vec_validate_init_empty (am->acl_ip4_output_classify_table_by_sw_if_index, + sw_if_index, ~0); + vec_validate_init_empty (am->acl_ip6_output_classify_table_by_sw_if_index, + sw_if_index, ~0); + + vnet_l2_output_classify_enable_disable (sw_if_index, 0); + + if (am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] != ~0) + { + ip4_table_index = + am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index]; + am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] = ~0; + acl_classify_add_del_table_big (cm, ip4_5tuple_mask, + sizeof (ip4_5tuple_mask) - 1, ~0, + am->l2_output_classify_next_acl, + &ip4_table_index, 0); + } + if (am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] != ~0) + { + ip6_table_index = + am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index]; + am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] = ~0; + acl_classify_add_del_table_big (cm, ip6_5tuple_mask, + sizeof (ip6_5tuple_mask) - 1, ~0, + am->l2_output_classify_next_acl, + &ip6_table_index, 0); + } + + return 0; +} + +static int +acl_hook_l2_input_classify (acl_main_t * am, u32 sw_if_index) +{ + vnet_classify_main_t *cm = &vnet_classify_main; + u32 ip4_table_index = ~0; + u32 ip6_table_index = ~0; + int rv; + + /* in case there were previous tables attached */ + acl_unhook_l2_input_classify (am, sw_if_index); + rv = + acl_classify_add_del_table_big (cm, ip4_5tuple_mask, + sizeof (ip4_5tuple_mask) - 1, ~0, + am->l2_input_classify_next_acl, + &ip4_table_index, 1); + if (rv) + return rv; + rv = + acl_classify_add_del_table_big (cm, ip6_5tuple_mask, + sizeof (ip6_5tuple_mask) - 1, ~0, + am->l2_input_classify_next_acl, + &ip6_table_index, 1); + if (rv) + { + acl_classify_add_del_table_big (cm, ip4_5tuple_mask, + sizeof (ip4_5tuple_mask) - 1, ~0, + am->l2_input_classify_next_acl, + &ip4_table_index, 0); + return rv; + } + rv = + vnet_l2_input_classify_set_tables (sw_if_index, ip4_table_index, + ip6_table_index, ~0); + clib_warning + ("ACL enabling on interface sw_if_index %d, setting tables to the following: ip4: %d ip6: %d\n", + sw_if_index, ip4_table_index, ip6_table_index); + if (rv) + { + acl_classify_add_del_table_big (cm, ip6_5tuple_mask, + sizeof (ip6_5tuple_mask) - 1, ~0, + am->l2_input_classify_next_acl, + &ip6_table_index, 0); + acl_classify_add_del_table_big (cm, ip4_5tuple_mask, + sizeof (ip4_5tuple_mask) - 1, ~0, + am->l2_input_classify_next_acl, + &ip4_table_index, 0); + return rv; + } + + am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] = + ip4_table_index; + am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] = + ip6_table_index; + + vnet_l2_input_classify_enable_disable (sw_if_index, 1); + return rv; +} + +static int +acl_hook_l2_output_classify (acl_main_t * am, u32 sw_if_index) +{ + vnet_classify_main_t *cm = &vnet_classify_main; + u32 ip4_table_index = ~0; + u32 ip6_table_index = ~0; + int rv; + + /* in case there were previous tables attached */ + acl_unhook_l2_output_classify (am, sw_if_index); + rv = + acl_classify_add_del_table_big (cm, ip4_5tuple_mask, + sizeof (ip4_5tuple_mask) - 1, ~0, + am->l2_output_classify_next_acl, + &ip4_table_index, 1); + if (rv) + return rv; + rv = + acl_classify_add_del_table_big (cm, ip6_5tuple_mask, + sizeof (ip6_5tuple_mask) - 1, ~0, + am->l2_output_classify_next_acl, + &ip6_table_index, 1); + if (rv) + { + acl_classify_add_del_table_big (cm, ip4_5tuple_mask, + sizeof (ip4_5tuple_mask) - 1, ~0, + am->l2_output_classify_next_acl, + &ip4_table_index, 0); + return rv; + } + rv = + vnet_l2_output_classify_set_tables (sw_if_index, ip4_table_index, + ip6_table_index, ~0); + clib_warning + ("ACL enabling on interface sw_if_index %d, setting tables to the following: ip4: %d ip6: %d\n", + sw_if_index, ip4_table_index, ip6_table_index); + if (rv) + { + acl_classify_add_del_table_big (cm, ip6_5tuple_mask, + sizeof (ip6_5tuple_mask) - 1, ~0, + am->l2_output_classify_next_acl, + &ip6_table_index, 0); + acl_classify_add_del_table_big (cm, ip4_5tuple_mask, + sizeof (ip4_5tuple_mask) - 1, ~0, + am->l2_output_classify_next_acl, + &ip4_table_index, 0); + return rv; + } + + am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] = + ip4_table_index; + am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] = + ip6_table_index; + + vnet_l2_output_classify_enable_disable (sw_if_index, 1); + return rv; +} + + +int +acl_interface_in_enable_disable (acl_main_t * am, u32 sw_if_index, + int enable_disable) +{ + int rv; + + /* Utterly wrong? */ + if (pool_is_free_index (am->vnet_main->interface_main.sw_interfaces, + sw_if_index)) + return VNET_API_ERROR_INVALID_SW_IF_INDEX; + + if (enable_disable) + { + rv = acl_hook_l2_input_classify (am, sw_if_index); + } + else + { + rv = acl_unhook_l2_input_classify (am, sw_if_index); + } + + return rv; +} + +int +acl_interface_out_enable_disable (acl_main_t * am, u32 sw_if_index, + int enable_disable) +{ + int rv; + + /* Utterly wrong? */ + if (pool_is_free_index (am->vnet_main->interface_main.sw_interfaces, + sw_if_index)) + return VNET_API_ERROR_INVALID_SW_IF_INDEX; + + if (enable_disable) + { + rv = acl_hook_l2_output_classify (am, sw_if_index); + } + else + { + rv = acl_unhook_l2_output_classify (am, sw_if_index); + } + + return rv; +} + + +static int +acl_interface_add_inout_acl (u32 sw_if_index, u8 is_input, u32 acl_list_index) +{ + acl_main_t *am = &acl_main; + if (is_input) + { + vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index); + vec_add (am->input_acl_vec_by_sw_if_index[sw_if_index], &acl_list_index, + 1); + acl_interface_in_enable_disable (am, sw_if_index, 1); + } + else + { + vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index); + vec_add (am->output_acl_vec_by_sw_if_index[sw_if_index], + &acl_list_index, 1); + acl_interface_out_enable_disable (am, sw_if_index, 1); + } + return 0; +} + +static int +acl_interface_del_inout_acl (u32 sw_if_index, u8 is_input, u32 acl_list_index) +{ + acl_main_t *am = &acl_main; + int i; + int rv = -1; + if (is_input) + { + vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index); + for (i = 0; i < vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]); + i++) + { + if (acl_list_index == + am->input_acl_vec_by_sw_if_index[sw_if_index][i]) + { + vec_del1 (am->input_acl_vec_by_sw_if_index[sw_if_index], i); + rv = 0; + break; + } + } + if (0 == vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index])) + { + acl_interface_in_enable_disable (am, sw_if_index, 0); + } + } + else + { + vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index); + for (i = 0; + i < vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]); i++) + { + if (acl_list_index == + am->output_acl_vec_by_sw_if_index[sw_if_index][i]) + { + vec_del1 (am->output_acl_vec_by_sw_if_index[sw_if_index], i); + rv = 0; + break; + } + } + if (0 == vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index])) + { + acl_interface_out_enable_disable (am, sw_if_index, 0); + } + } + return rv; +} + +static void +acl_interface_reset_inout_acls (u32 sw_if_index, u8 is_input) +{ + acl_main_t *am = &acl_main; + if (is_input) + { + acl_interface_in_enable_disable (am, sw_if_index, 0); + vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index); + vec_reset_length (am->input_acl_vec_by_sw_if_index[sw_if_index]); + } + else + { + acl_interface_out_enable_disable (am, sw_if_index, 0); + vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index); + vec_reset_length (am->output_acl_vec_by_sw_if_index[sw_if_index]); + } +} + +static int +acl_interface_add_del_inout_acl (u32 sw_if_index, u8 is_add, u8 is_input, + u32 acl_list_index) +{ + int rv = -1; + if (is_add) + { + rv = + acl_interface_add_inout_acl (sw_if_index, is_input, acl_list_index); + } + else + { + rv = + acl_interface_del_inout_acl (sw_if_index, is_input, acl_list_index); + } + return rv; +} + + +static void * +get_ptr_to_offset (vlib_buffer_t * b0, int offset) +{ + u8 *p = vlib_buffer_get_current (b0) + offset; + return p; +} + +static u8 +acl_get_l4_proto (vlib_buffer_t * b0, int node_is_ip6) +{ + u8 proto; + int proto_offset; + if (node_is_ip6) + { + proto_offset = 20; + } + else + { + proto_offset = 23; + } + proto = *((u8 *) vlib_buffer_get_current (b0) + proto_offset); + return proto; +} + +static int +acl_match_addr (ip46_address_t * addr1, ip46_address_t * addr2, int prefixlen, + int is_ip6) +{ + if (prefixlen == 0) + { + /* match any always succeeds */ + return 1; + } + if (is_ip6) + { + if (memcmp (addr1, addr2, prefixlen / 8)) + { + /* If the starting full bytes do not match, no point in bittwidling the thumbs further */ + return 0; + } + if (prefixlen % 8) + { + u8 b1 = *((u8 *) addr1 + 1 + prefixlen / 8); + u8 b2 = *((u8 *) addr2 + 1 + prefixlen / 8); + u8 mask0 = (0xff - ((1 << (8 - (prefixlen % 8))) - 1)); + return (b1 & mask0) == b2; + } + else + { + /* The prefix fits into integer number of bytes, so nothing left to do */ + return 1; + } + } + else + { + uint32_t a1 = ntohl (addr1->ip4.as_u32); + uint32_t a2 = ntohl (addr2->ip4.as_u32); + uint32_t mask0 = 0xffffffff - ((1 << (32 - prefixlen)) - 1); + return (a1 & mask0) == a2; + } +} + +static int +acl_match_port (u16 port, u16 port_first, u16 port_last, int is_ip6) +{ + return ((port >= port_first) && (port <= port_last)); +} + +static int +acl_packet_match (acl_main_t * am, u32 acl_index, vlib_buffer_t * b0, + u8 * r_action, int *r_is_ip6, u32 * r_acl_match_p, + u32 * r_rule_match_p, u32 * trace_bitmap) +{ + ethernet_header_t *h0; + u16 type0; + + ip46_address_t src, dst; + int is_ip6; + int is_ip4; + u8 proto; + u16 src_port; + u16 dst_port; + u8 tcp_flags = 0; + int i; + acl_list_t *a; + acl_rule_t *r; + + h0 = vlib_buffer_get_current (b0); + type0 = clib_net_to_host_u16 (h0->type); + is_ip4 = (type0 == ETHERNET_TYPE_IP4); + is_ip6 = (type0 == ETHERNET_TYPE_IP6); + + if (!(is_ip4 || is_ip6)) + { + return 0; + } + /* The bunch of hardcoded offsets here is intentional to get rid of them + ASAP, when getting to a faster matching code */ + if (is_ip4) + { + clib_memcpy (&src.ip4, get_ptr_to_offset (b0, 26), 4); + clib_memcpy (&dst.ip4, get_ptr_to_offset (b0, 30), 4); + proto = acl_get_l4_proto (b0, 0); + if (1 == proto) + { + *trace_bitmap |= 0x00000001; + /* type */ + src_port = *(u8 *) get_ptr_to_offset (b0, 34); + /* code */ + dst_port = *(u8 *) get_ptr_to_offset (b0, 35); + } + else + { + /* assume TCP/UDP */ + src_port = (*(u16 *) get_ptr_to_offset (b0, 34)); + dst_port = (*(u16 *) get_ptr_to_offset (b0, 36)); + /* UDP gets ability to check on an oddball data byte as a bonus */ + tcp_flags = *(u8 *) get_ptr_to_offset (b0, 14 + 20 + 13); + } + } + else /* is_ipv6 implicitly */ + { + clib_memcpy (&src, get_ptr_to_offset (b0, 22), 16); + clib_memcpy (&dst, get_ptr_to_offset (b0, 38), 16); + proto = acl_get_l4_proto (b0, 1); + if (58 == proto) + { + *trace_bitmap |= 0x00000002; + /* type */ + src_port = *(u8 *) get_ptr_to_offset (b0, 54); + /* code */ + dst_port = *(u8 *) get_ptr_to_offset (b0, 55); + } + else + { + /* assume TCP/UDP */ + src_port = (*(u16 *) get_ptr_to_offset (b0, 54)); + dst_port = (*(u16 *) get_ptr_to_offset (b0, 56)); + tcp_flags = *(u8 *) get_ptr_to_offset (b0, 14 + 40 + 13); + } + } + if (pool_is_free_index (am->acls, acl_index)) + { + if (r_acl_match_p) + *r_acl_match_p = acl_index; + if (r_rule_match_p) + *r_rule_match_p = -1; + /* the ACL does not exist but is used for policy. Block traffic. */ + return 0; + } + a = am->acls + acl_index; + for (i = 0; i < a->count; i++) + { + r = a->rules + i; + if (is_ip6 != r->is_ipv6) + { + continue; + } + if (!acl_match_addr (&dst, &r->dst, r->dst_prefixlen, is_ip6)) + continue; + if (!acl_match_addr (&src, &r->src, r->src_prefixlen, is_ip6)) + continue; + if (r->proto) + { + if (proto != r->proto) + continue; + if (!acl_match_port + (src_port, r->src_port_or_type_first, r->src_port_or_type_last, + is_ip6)) + continue; + if (!acl_match_port + (dst_port, r->dst_port_or_code_first, r->dst_port_or_code_last, + is_ip6)) + continue; + /* No need for check of proto == TCP, since in other rules both fields should be zero, so this match will succeed */ + if ((tcp_flags & r->tcp_flags_mask) != r->tcp_flags_value) + continue; + } + /* everything matches! */ + *r_action = r->is_permit; + *r_is_ip6 = is_ip6; + if (r_acl_match_p) + *r_acl_match_p = acl_index; + if (r_rule_match_p) + *r_rule_match_p = i; + return 1; + } + return 0; +} + +void +input_acl_packet_match (u32 sw_if_index, vlib_buffer_t * b0, u32 * nextp, + u32 * acl_match_p, u32 * rule_match_p, + u32 * trace_bitmap) +{ + acl_main_t *am = &acl_main; + uint8_t action = 0; + int is_ip6 = 0; + int i; + vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index); + for (i = 0; i < vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]); + i++) + { + if (acl_packet_match + (am, am->input_acl_vec_by_sw_if_index[sw_if_index][i], b0, &action, + &is_ip6, acl_match_p, rule_match_p, trace_bitmap)) + { + if (is_ip6) + { + *nextp = am->acl_in_ip6_match_next[action]; + } + else + { + *nextp = am->acl_in_ip4_match_next[action]; + } + return; + } + } + if (vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]) > 0) + { + /* If there are ACLs and none matched, deny by default */ + *nextp = 0; + } + +} + +void +output_acl_packet_match (u32 sw_if_index, vlib_buffer_t * b0, u32 * nextp, + u32 * acl_match_p, u32 * rule_match_p, + u32 * trace_bitmap) +{ + acl_main_t *am = &acl_main; + uint8_t action = 0; + int is_ip6 = 0; + int i; + vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index); + for (i = 0; i < vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]); + i++) + { + if (acl_packet_match + (am, am->output_acl_vec_by_sw_if_index[sw_if_index][i], b0, &action, + &is_ip6, acl_match_p, rule_match_p, trace_bitmap)) + { + if (is_ip6) + { + *nextp = am->acl_out_ip6_match_next[action]; + } + else + { + *nextp = am->acl_out_ip4_match_next[action]; + } + return; + } + } + if (vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]) > 0) + { + /* If there are ACLs and none matched, deny by default */ + *nextp = 0; + } +} + +typedef struct +{ + u8 is_ipv6; + u8 mac_mask[6]; + u8 prefix_len; + u32 count; + u32 table_index; +} macip_match_type_t; + +static u32 +macip_find_match_type (macip_match_type_t * mv, u8 * mac_mask, u8 prefix_len, + u8 is_ipv6) +{ + u32 i; + if (mv) + { + for (i = 0; i < vec_len (mv); i++) + { + if ((mv[i].prefix_len == prefix_len) && (mv[i].is_ipv6 == is_ipv6) + && (0 == memcmp (mv[i].mac_mask, mac_mask, 6))) + { + return i; + } + } + } + return ~0; +} + + +/* Get metric used to sort match types. + The more specific and the more often seen - the bigger the metric */ +static int +match_type_metric (macip_match_type_t * m) +{ + /* FIXME: count the ones in the MAC mask as well, check how well this heuristic works in real life */ + return m->prefix_len + m->is_ipv6 + 10 * m->count; +} + +static int +match_type_compare (macip_match_type_t * m1, macip_match_type_t * m2) +{ + /* Ascending sort based on the metric values */ + return match_type_metric (m1) - match_type_metric (m2); +} + +/* Get the offset of L3 source within ethernet packet */ +static int +get_l3_src_offset(int is6) +{ + if(is6) + return (sizeof(ethernet_header_t) + offsetof(ip6_header_t, src_address)); + else + return (sizeof(ethernet_header_t) + offsetof(ip4_header_t, src_address)); +} + +static int +macip_create_classify_tables (acl_main_t * am, u32 macip_acl_index) +{ + macip_match_type_t *mvec = NULL; + macip_match_type_t *mt; + macip_acl_list_t *a = &am->macip_acls[macip_acl_index]; + int i; + u32 match_type_index; + u32 last_table; + u8 mask[5 * 16]; + vnet_classify_main_t *cm = &vnet_classify_main; + + /* Count the number of different types of rules */ + for (i = 0; i < a->count; i++) + { + if (~0 == + (match_type_index = + macip_find_match_type (mvec, a->rules[i].src_mac_mask, + a->rules[i].src_prefixlen, + a->rules[i].is_ipv6))) + { + match_type_index = vec_len (mvec); + vec_validate (mvec, match_type_index); + memcpy (mvec[match_type_index].mac_mask, + a->rules[match_type_index].src_mac_mask, 6); + mvec[match_type_index].prefix_len = a->rules[i].src_prefixlen; + mvec[match_type_index].is_ipv6 = a->rules[i].is_ipv6; + mvec[match_type_index].table_index = ~0; + } + mvec[match_type_index].count++; + } + /* Put the most frequently used tables last in the list so we can create classifier tables in reverse order */ + vec_sort_with_function (mvec, match_type_compare); + /* Create the classifier tables */ + last_table = ~0; + vec_foreach (mt, mvec) + { + int mask_len; + int is6 = mt->is_ipv6; + int l3_src_offs = get_l3_src_offset(is6); + memset (mask, 0, sizeof (mask)); + memcpy (&mask[6], mt->mac_mask, 6); + for (i = 0; i < (mt->prefix_len / 8); i++) + { + mask[l3_src_offs + i] = 0xff; + } + if (mt->prefix_len % 8) + { + mask[l3_src_offs + (mt->prefix_len / 8)] = + 0xff - ((1 << (8 - mt->prefix_len % 8)) - 1); + } + /* + * Round-up the number of bytes needed to store the prefix, + * and round up the number of vectors too + */ + mask_len = ((l3_src_offs + ((mt->prefix_len+7) / 8) + + (sizeof (u32x4)-1))/sizeof(u32x4)) * sizeof (u32x4); + acl_classify_add_del_table_small (cm, mask, mask_len, last_table, + (~0 == last_table) ? 0 : ~0, &mt->table_index, + 1); + last_table = mt->table_index; + } + a->ip4_table_index = ~0; + a->ip6_table_index = ~0; + a->l2_table_index = last_table; + + /* Populate the classifier tables with rules from the MACIP ACL */ + for (i = 0; i < a->count; i++) + { + u32 action = 0; + u32 metadata = 0; + int is6 = a->rules[i].is_ipv6; + int l3_src_offs = get_l3_src_offset(is6); + memset (mask, 0, sizeof (mask)); + memcpy (&mask[6], a->rules[i].src_mac, 6); + if (is6) + { + memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip6, 16); + } + else + { + memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip4, 4); + } + match_type_index = + macip_find_match_type (mvec, a->rules[i].src_mac_mask, + a->rules[i].src_prefixlen, + a->rules[i].is_ipv6); + /* add session to table mvec[match_type_index].table_index; */ + vnet_classify_add_del_session (cm, mvec[match_type_index].table_index, + mask, a->rules[i].is_permit ? ~0 : 0, i, + 0, action, metadata, 1); + } + return 0; +} + +static void +macip_destroy_classify_tables (acl_main_t * am, u32 macip_acl_index) +{ + vnet_classify_main_t *cm = &vnet_classify_main; + macip_acl_list_t *a = &am->macip_acls[macip_acl_index]; + + if (a->ip4_table_index != ~0) + { + acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->ip4_table_index, 0); + a->ip4_table_index = ~0; + } + if (a->ip6_table_index != ~0) + { + acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->ip6_table_index, 0); + a->ip6_table_index = ~0; + } + if (a->l2_table_index != ~0) + { + acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->l2_table_index, 0); + a->l2_table_index = ~0; + } +} + +static int +macip_acl_add_list (u32 count, vl_api_macip_acl_rule_t rules[], + u32 * acl_list_index, u8 * tag) +{ + acl_main_t *am = &acl_main; + macip_acl_list_t *a; + macip_acl_rule_t *r; + macip_acl_rule_t *acl_new_rules; + int i; + + /* Create and populate the rules */ + acl_new_rules = clib_mem_alloc_aligned (sizeof (macip_acl_rule_t) * count, + CLIB_CACHE_LINE_BYTES); + if (!acl_new_rules) + { + /* Could not allocate rules. New or existing ACL - bail out regardless */ + return -1; + } + + for (i = 0; i < count; i++) + { + r = &acl_new_rules[i]; + r->is_permit = rules[i].is_permit; + r->is_ipv6 = rules[i].is_ipv6; + memcpy (&r->src_mac, rules[i].src_mac, 6); + memcpy (&r->src_mac_mask, rules[i].src_mac_mask, 6); + if(rules[i].is_ipv6) + memcpy (&r->src_ip_addr.ip6, rules[i].src_ip_addr, 16); + else + memcpy (&r->src_ip_addr.ip4, rules[i].src_ip_addr, 4); + r->src_prefixlen = rules[i].src_ip_prefix_len; + } + + /* Get ACL index */ + pool_get_aligned (am->macip_acls, a, CLIB_CACHE_LINE_BYTES); + memset (a, 0, sizeof (*a)); + /* Will return the newly allocated ACL index */ + *acl_list_index = a - am->macip_acls; + + a->rules = acl_new_rules; + a->count = count; + memcpy (a->tag, tag, sizeof (a->tag)); + + /* Create and populate the classifer tables */ + macip_create_classify_tables (am, *acl_list_index); + + return 0; +} + + +/* No check for validity of sw_if_index - the callers were supposed to validate */ + +static int +macip_acl_interface_del_acl (acl_main_t * am, u32 sw_if_index) +{ + int rv; + u32 macip_acl_index; + macip_acl_list_t *a; + vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0); + macip_acl_index = am->macip_acl_by_sw_if_index[sw_if_index]; + /* No point in deleting MACIP ACL which is not applied */ + if (~0 == macip_acl_index) + return -1; + a = &am->macip_acls[macip_acl_index]; + /* remove the classifier tables off the interface L2 ACL */ + rv = + vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index, + a->ip6_table_index, a->l2_table_index, 0); + /* Unset the MACIP ACL index */ + am->macip_acl_by_sw_if_index[sw_if_index] = ~0; + return rv; +} + +/* No check for validity of sw_if_index - the callers were supposed to validate */ + +static int +macip_acl_interface_add_acl (acl_main_t * am, u32 sw_if_index, + u32 macip_acl_index) +{ + macip_acl_list_t *a; + int rv; + if (pool_is_free_index (am->macip_acls, macip_acl_index)) + { + return -1; + } + a = &am->macip_acls[macip_acl_index]; + vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0); + /* If there already a MACIP ACL applied, unapply it */ + if (~0 != am->macip_acl_by_sw_if_index[sw_if_index]) + macip_acl_interface_del_acl(am, sw_if_index); + am->macip_acl_by_sw_if_index[sw_if_index] = macip_acl_index; + /* Apply the classifier tables for L2 ACLs */ + rv = + vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index, + a->ip6_table_index, a->l2_table_index, 1); + return rv; +} + +static int +macip_acl_del_list (u32 acl_list_index) +{ + acl_main_t *am = &acl_main; + macip_acl_list_t *a; + int i; + if (pool_is_free_index (am->macip_acls, acl_list_index)) + { + return -1; + } + + /* delete any references to the ACL */ + for (i = 0; i < vec_len (am->macip_acl_by_sw_if_index); i++) + { + if (am->macip_acl_by_sw_if_index[i] == acl_list_index) + { + macip_acl_interface_del_acl (am, i); + } + } + + /* Now that classifier tables are detached, clean them up */ + macip_destroy_classify_tables (am, acl_list_index); + + /* now we can delete the ACL itself */ + a = &am->macip_acls[acl_list_index]; + if (a->rules) + { + clib_mem_free (a->rules); + } + pool_put (am->macip_acls, a); + return 0; +} + + +static int +macip_acl_interface_add_del_acl (u32 sw_if_index, u8 is_add, + u32 acl_list_index) +{ + acl_main_t *am = &acl_main; + int rv = -1; + if (is_add) + { + rv = macip_acl_interface_add_acl (am, sw_if_index, acl_list_index); + } + else + { + rv = macip_acl_interface_del_acl (am, sw_if_index); + } + return rv; +} + +/* API message handler */ +static void +vl_api_acl_add_replace_t_handler (vl_api_acl_add_replace_t * mp) +{ + vl_api_acl_add_replace_reply_t *rmp; + acl_main_t *am = &acl_main; + int rv; + u32 acl_list_index = ntohl (mp->acl_index); + + rv = acl_add_list (ntohl (mp->count), mp->r, &acl_list_index, mp->tag); + + /* *INDENT-OFF* */ + REPLY_MACRO2(VL_API_ACL_ADD_REPLACE_REPLY, + ({ + rmp->acl_index = htonl(acl_list_index); + })); + /* *INDENT-ON* */ +} + +static void +vl_api_acl_del_t_handler (vl_api_acl_del_t * mp) +{ + acl_main_t *sm = &acl_main; + vl_api_acl_del_reply_t *rmp; + int rv; + + rv = acl_del_list (ntohl (mp->acl_index)); + + REPLY_MACRO (VL_API_ACL_DEL_REPLY); +} + +static void +vl_api_acl_interface_add_del_t_handler (vl_api_acl_interface_add_del_t * mp) +{ + acl_main_t *sm = &acl_main; + vnet_interface_main_t *im = &sm->vnet_main->interface_main; + u32 sw_if_index = ntohl (mp->sw_if_index); + vl_api_acl_interface_add_del_reply_t *rmp; + int rv = -1; + + if (pool_is_free_index(im->sw_interfaces, sw_if_index)) + rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; + else + rv = + acl_interface_add_del_inout_acl (sw_if_index, mp->is_add, + mp->is_input, ntohl (mp->acl_index)); + + REPLY_MACRO (VL_API_ACL_INTERFACE_ADD_DEL_REPLY); +} + +static void +vl_api_acl_interface_set_acl_list_t_handler + (vl_api_acl_interface_set_acl_list_t * mp) +{ + acl_main_t *sm = &acl_main; + vl_api_acl_interface_set_acl_list_reply_t *rmp; + int rv = 0; + int i; + vnet_interface_main_t *im = &sm->vnet_main->interface_main; + u32 sw_if_index = ntohl (mp->sw_if_index); + + if (pool_is_free_index(im->sw_interfaces, sw_if_index)) + rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; + else + { + acl_interface_reset_inout_acls (sw_if_index, 0); + acl_interface_reset_inout_acls (sw_if_index, 1); + + for (i = 0; i < mp->count; i++) + { + acl_interface_add_del_inout_acl (sw_if_index, 1, (i < mp->n_input), + ntohl (mp->acls[i])); + } + } + + REPLY_MACRO (VL_API_ACL_INTERFACE_SET_ACL_LIST_REPLY); +} + +static void +copy_acl_rule_to_api_rule (vl_api_acl_rule_t * api_rule, acl_rule_t * r) +{ + api_rule->is_permit = r->is_permit; + api_rule->is_ipv6 = r->is_ipv6; + if(r->is_ipv6) + { + memcpy (api_rule->src_ip_addr, &r->src, sizeof (r->src)); + memcpy (api_rule->dst_ip_addr, &r->dst, sizeof (r->dst)); + } + else + { + memcpy (api_rule->src_ip_addr, &r->src.ip4, sizeof (r->src.ip4)); + memcpy (api_rule->dst_ip_addr, &r->dst.ip4, sizeof (r->dst.ip4)); + } + api_rule->src_ip_prefix_len = r->src_prefixlen; + api_rule->dst_ip_prefix_len = r->dst_prefixlen; + api_rule->proto = r->proto; + api_rule->srcport_or_icmptype_first = r->src_port_or_type_first; + api_rule->srcport_or_icmptype_last = r->src_port_or_type_last; + api_rule->dstport_or_icmpcode_first = r->dst_port_or_code_first; + api_rule->dstport_or_icmpcode_last = r->dst_port_or_code_last; + api_rule->tcp_flags_mask = r->tcp_flags_mask; + api_rule->tcp_flags_value = r->tcp_flags_value; +} + +static void +send_acl_details (acl_main_t * am, unix_shared_memory_queue_t * q, + acl_list_t * acl, u32 context) +{ + vl_api_acl_details_t *mp; + vl_api_acl_rule_t *rules; + int i; + int msg_size = sizeof (*mp) + sizeof (mp->r[0]) * acl->count; + + mp = vl_msg_api_alloc (msg_size); + memset (mp, 0, msg_size); + mp->_vl_msg_id = ntohs (VL_API_ACL_DETAILS + am->msg_id_base); + + /* fill in the message */ + mp->context = context; + mp->count = htonl (acl->count); + mp->acl_index = htonl (acl - am->acls); + memcpy (mp->tag, acl->tag, sizeof (mp->tag)); + // clib_memcpy (mp->r, acl->rules, acl->count * sizeof(acl->rules[0])); + rules = mp->r; + for (i = 0; i < acl->count; i++) + { + copy_acl_rule_to_api_rule (&rules[i], &acl->rules[i]); + } + + clib_warning("Sending acl details for ACL index %d", ntohl(mp->acl_index)); + vl_msg_api_send_shmem (q, (u8 *) & mp); +} + + +static void +vl_api_acl_dump_t_handler (vl_api_acl_dump_t * mp) +{ + acl_main_t *am = &acl_main; + u32 acl_index; + acl_list_t *acl; + + int rv = -1; + unix_shared_memory_queue_t *q; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + { + return; + } + + if (mp->acl_index == ~0) + { + /* *INDENT-OFF* */ + /* Just dump all ACLs */ + pool_foreach (acl, am->acls, + ({ + send_acl_details(am, q, acl, mp->context); + })); + /* *INDENT-ON* */ + } + else + { + acl_index = ntohl (mp->acl_index); + if (!pool_is_free_index (am->acls, acl_index)) + { + acl = &am->acls[acl_index]; + send_acl_details (am, q, acl, mp->context); + } + } + + if (rv == -1) + { + /* FIXME API: should we signal an error here at all ? */ + return; + } +} + +static void +send_acl_interface_list_details (acl_main_t * am, + unix_shared_memory_queue_t * q, + u32 sw_if_index, u32 context) +{ + vl_api_acl_interface_list_details_t *mp; + int msg_size; + int n_input; + int n_output; + int count; + int i = 0; + + vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index); + vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index); + + n_input = vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]); + n_output = vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]); + count = n_input + n_output; + + msg_size = sizeof (*mp); + msg_size += sizeof (mp->acls[0]) * count; + + mp = vl_msg_api_alloc (msg_size); + memset (mp, 0, msg_size); + mp->_vl_msg_id = + ntohs (VL_API_ACL_INTERFACE_LIST_DETAILS + am->msg_id_base); + + /* fill in the message */ + mp->context = context; + mp->sw_if_index = htonl (sw_if_index); + mp->count = count; + mp->n_input = n_input; + for (i = 0; i < n_input; i++) + { + mp->acls[i] = htonl (am->input_acl_vec_by_sw_if_index[sw_if_index][i]); + } + for (i = 0; i < n_output; i++) + { + mp->acls[n_input + i] = + htonl (am->output_acl_vec_by_sw_if_index[sw_if_index][i]); + } + + vl_msg_api_send_shmem (q, (u8 *) & mp); +} + +static void +vl_api_acl_interface_list_dump_t_handler (vl_api_acl_interface_list_dump_t * + mp) +{ + acl_main_t *am = &acl_main; + vnet_sw_interface_t *swif; + vnet_interface_main_t *im = &am->vnet_main->interface_main; + + u32 sw_if_index; + unix_shared_memory_queue_t *q; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + { + return; + } + + if (mp->sw_if_index == ~0) + { + /* *INDENT-OFF* */ + pool_foreach (swif, im->sw_interfaces, + ({ + send_acl_interface_list_details(am, q, swif->sw_if_index, mp->context); + })); + /* *INDENT-ON* */ + } + else + { + sw_if_index = ntohl (mp->sw_if_index); + if (!pool_is_free_index(im->sw_interfaces, sw_if_index)) + send_acl_interface_list_details (am, q, sw_if_index, mp->context); + } +} + +/* MACIP ACL API handlers */ + +static void +vl_api_macip_acl_add_t_handler (vl_api_macip_acl_add_t * mp) +{ + vl_api_macip_acl_add_reply_t *rmp; + acl_main_t *am = &acl_main; + int rv; + u32 acl_list_index = ~0; + + rv = + macip_acl_add_list (ntohl (mp->count), mp->r, &acl_list_index, mp->tag); + + /* *INDENT-OFF* */ + REPLY_MACRO2(VL_API_MACIP_ACL_ADD_REPLY, + ({ + rmp->acl_index = htonl(acl_list_index); + })); + /* *INDENT-ON* */ +} + +static void +vl_api_macip_acl_del_t_handler (vl_api_macip_acl_del_t * mp) +{ + acl_main_t *sm = &acl_main; + vl_api_macip_acl_del_reply_t *rmp; + int rv; + + rv = macip_acl_del_list (ntohl (mp->acl_index)); + + REPLY_MACRO (VL_API_MACIP_ACL_DEL_REPLY); +} + +static void +vl_api_macip_acl_interface_add_del_t_handler + (vl_api_macip_acl_interface_add_del_t * mp) +{ + acl_main_t *sm = &acl_main; + vl_api_macip_acl_interface_add_del_reply_t *rmp; + int rv = -1; + vnet_interface_main_t *im = &sm->vnet_main->interface_main; + u32 sw_if_index = ntohl (mp->sw_if_index); + + if (pool_is_free_index(im->sw_interfaces, sw_if_index)) + rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; + else + rv = + macip_acl_interface_add_del_acl (ntohl (mp->sw_if_index), mp->is_add, + ntohl (mp->acl_index)); + + REPLY_MACRO (VL_API_MACIP_ACL_INTERFACE_ADD_DEL_REPLY); +} + +static void +send_macip_acl_details (acl_main_t * am, unix_shared_memory_queue_t * q, + macip_acl_list_t * acl, u32 context) +{ + vl_api_macip_acl_details_t *mp; + vl_api_macip_acl_rule_t *rules; + macip_acl_rule_t *r; + int i; + int msg_size = sizeof (*mp) + (acl ? sizeof (mp->r[0]) * acl->count : 0); + + mp = vl_msg_api_alloc (msg_size); + memset (mp, 0, msg_size); + mp->_vl_msg_id = ntohs (VL_API_MACIP_ACL_DETAILS + am->msg_id_base); + + /* fill in the message */ + mp->context = context; + if (acl) + { + memcpy (mp->tag, acl->tag, sizeof (mp->tag)); + mp->count = htonl (acl->count); + mp->acl_index = htonl (acl - am->macip_acls); + rules = mp->r; + for (i = 0; i < acl->count; i++) + { + r = &acl->rules[i]; + rules[i].is_permit = r->is_permit; + rules[i].is_ipv6 = r->is_ipv6; + memcpy (rules[i].src_mac, &r->src_mac, sizeof (r->src_mac)); + memcpy (rules[i].src_mac_mask, &r->src_mac_mask, + sizeof (r->src_mac_mask)); + if (r->is_ipv6) + memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip6, + sizeof (r->src_ip_addr.ip6)); + else + memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip4, + sizeof (r->src_ip_addr.ip4)); + rules[i].src_ip_prefix_len = r->src_prefixlen; + } + } + else + { + /* No martini, no party - no ACL applied to this interface. */ + mp->acl_index = ~0; + mp->count = 0; + } + + vl_msg_api_send_shmem (q, (u8 *) & mp); +} + + +static void +vl_api_macip_acl_dump_t_handler (vl_api_macip_acl_dump_t * mp) +{ + acl_main_t *am = &acl_main; + macip_acl_list_t *acl; + + unix_shared_memory_queue_t *q; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + { + return; + } + + if (mp->acl_index == ~0) + { + /* Just dump all ACLs for now, with sw_if_index = ~0 */ + pool_foreach (acl, am->macip_acls, ( + { + send_macip_acl_details (am, q, acl, + mp-> + context);} + )); + /* *INDENT-ON* */ + } + else + { + u32 acl_index = ntohl (mp->acl_index); + if (!pool_is_free_index (am->macip_acls, acl_index)) + { + acl = &am->macip_acls[acl_index]; + send_macip_acl_details (am, q, acl, mp->context); + } + } +} + +static void +vl_api_macip_acl_interface_get_t_handler (vl_api_macip_acl_interface_get_t * + mp) +{ + acl_main_t *am = &acl_main; + vl_api_macip_acl_interface_get_reply_t *rmp; + u32 count = vec_len (am->macip_acl_by_sw_if_index); + int msg_size = sizeof (*rmp) + sizeof (rmp->acls[0]) * count; + unix_shared_memory_queue_t *q; + int i; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + { + return; + } + + rmp = vl_msg_api_alloc (msg_size); + memset (rmp, 0, msg_size); + rmp->_vl_msg_id = + ntohs (VL_API_MACIP_ACL_INTERFACE_GET_REPLY + am->msg_id_base); + rmp->context = mp->context; + rmp->count = htonl (count); + for (i = 0; i < count; i++) + { + rmp->acls[i] = htonl (am->macip_acl_by_sw_if_index[i]); + } + + vl_msg_api_send_shmem (q, (u8 *) & rmp); +} + + + +/* Set up the API message handling tables */ +static clib_error_t * +acl_plugin_api_hookup (vlib_main_t * vm) +{ + acl_main_t *sm = &acl_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_acl_plugin_api_msg; +#undef _ + + return 0; +} + +#define vl_msg_name_crc_list +#include +#undef vl_msg_name_crc_list + +static void +setup_message_id_table (acl_main_t * sm, api_main_t * am) +{ +#define _(id,n,crc) \ + vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base); + foreach_vl_msg_name_crc_acl; +#undef _ +} + +u32 +register_match_action_nexts (u32 next_in_ip4, u32 next_in_ip6, + u32 next_out_ip4, u32 next_out_ip6) +{ + acl_main_t *am = &acl_main; + u32 act = am->n_match_actions; + if (am->n_match_actions == 255) + { + return ~0; + } + am->n_match_actions++; + am->acl_in_ip4_match_next[act] = next_in_ip4; + am->acl_in_ip6_match_next[act] = next_in_ip6; + am->acl_out_ip4_match_next[act] = next_out_ip4; + am->acl_out_ip6_match_next[act] = next_out_ip6; + return act; +} + +void +acl_setup_nodes (void) +{ + vlib_main_t *vm = vlib_get_main (); + acl_main_t *am = &acl_main; + vlib_node_t *n; + + n = vlib_get_node_by_name (vm, (u8 *) "l2-input-classify"); + am->l2_input_classify_next_acl = + vlib_node_add_next_with_slot (vm, n->index, acl_in_node.index, ~0); + n = vlib_get_node_by_name (vm, (u8 *) "l2-output-classify"); + am->l2_output_classify_next_acl = + vlib_node_add_next_with_slot (vm, n->index, acl_out_node.index, ~0); + + feat_bitmap_init_next_nodes (vm, acl_in_node.index, L2INPUT_N_FEAT, + l2input_get_feat_names (), + am->acl_in_node_input_next_node_index); + + memset (&am->acl_in_ip4_match_next[0], 0, + sizeof (am->acl_in_ip4_match_next)); + memset (&am->acl_in_ip6_match_next[0], 0, + sizeof (am->acl_in_ip6_match_next)); + memset (&am->acl_out_ip4_match_next[0], 0, + sizeof (am->acl_out_ip4_match_next)); + memset (&am->acl_out_ip6_match_next[0], 0, + sizeof (am->acl_out_ip6_match_next)); + am->n_match_actions = 0; + + register_match_action_nexts (0, 0, 0, 0); /* drop */ + register_match_action_nexts (~0, ~0, ~0, ~0); /* permit */ + register_match_action_nexts (ACL_IN_L2S_INPUT_IP4_ADD, ACL_IN_L2S_INPUT_IP6_ADD, ACL_OUT_L2S_OUTPUT_IP4_ADD, ACL_OUT_L2S_OUTPUT_IP6_ADD); /* permit + create session */ +} + + + +static clib_error_t * +acl_init (vlib_main_t * vm) +{ + acl_main_t *am = &acl_main; + clib_error_t *error = 0; + memset (am, 0, sizeof (*am)); + am->vlib_main = vm; + am->vnet_main = vnet_get_main (); + + u8 *name = format (0, "acl_%08x%c", api_version, 0); + + /* Ask for a correctly-sized block of API message decode slots */ + am->msg_id_base = vl_msg_api_get_msg_ids ((char *) name, + VL_MSG_FIRST_AVAILABLE); + + error = acl_plugin_api_hookup (vm); + acl_setup_nodes (); + + /* Add our API messages to the global name_crc hash table */ + setup_message_id_table (am, &api_main); + + vec_free (name); + + return error; +} + +VLIB_INIT_FUNCTION (acl_init); diff --git a/src/plugins/acl/acl.h b/src/plugins/acl/acl.h new file mode 100644 index 00000000..afc9b289 --- /dev/null +++ b/src/plugins/acl/acl.h @@ -0,0 +1,148 @@ +/* + * 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. + */ +#ifndef included_acl_h +#define included_acl_h + +#include +#include +#include +#include + + +#include +#include +#include + +#define ACL_PLUGIN_VERSION_MAJOR 1 +#define ACL_PLUGIN_VERSION_MINOR 1 + +extern vlib_node_registration_t acl_in_node; +extern vlib_node_registration_t acl_out_node; + +void input_acl_packet_match(u32 sw_if_index, vlib_buffer_t * b0, u32 *nextp, u32 *acl_match_p, u32 *rule_match_p, u32 *trace_bitmap); +void output_acl_packet_match(u32 sw_if_index, vlib_buffer_t * b0, u32 *nextp, u32 *acl_match_p, u32 *rule_match_p, u32 *trace_bitmap); + +enum address_e { IP4, IP6 }; +typedef struct +{ + enum address_e type; + union { + ip6_address_t ip6; + ip4_address_t ip4; + } addr; +} address_t; + +/* + * ACL rules + */ +typedef struct +{ + u8 is_permit; + u8 is_ipv6; + ip46_address_t src; + u8 src_prefixlen; + ip46_address_t dst; + u8 dst_prefixlen; + u8 proto; + u16 src_port_or_type_first; + u16 src_port_or_type_last; + u16 dst_port_or_code_first; + u16 dst_port_or_code_last; + u8 tcp_flags_value; + u8 tcp_flags_mask; +} acl_rule_t; + +typedef struct +{ + u8 is_permit; + u8 is_ipv6; + u8 src_mac[6]; + u8 src_mac_mask[6]; + ip46_address_t src_ip_addr; + u8 src_prefixlen; +} macip_acl_rule_t; + +/* + * ACL + */ +typedef struct +{ + u8 tag[64]; + u32 count; + acl_rule_t *rules; +} acl_list_t; + +typedef struct +{ + u8 tag[64]; + u32 count; + macip_acl_rule_t *rules; + /* References to the classifier tables that will enforce the rules */ + u32 ip4_table_index; + u32 ip6_table_index; + u32 l2_table_index; +} macip_acl_list_t; + +typedef struct { + /* API message ID base */ + u16 msg_id_base; + + acl_list_t *acls; /* Pool of ACLs */ + macip_acl_list_t *macip_acls; /* Pool of MAC-IP ACLs */ + + /* ACLs associated with interfaces */ + u32 **input_acl_vec_by_sw_if_index; + u32 **output_acl_vec_by_sw_if_index; + + /* + * Classify tables used to grab the packets for the ACL check, + * and serving as the 5-tuple session tables at the same time + */ + u32 *acl_ip4_input_classify_table_by_sw_if_index; + u32 *acl_ip6_input_classify_table_by_sw_if_index; + u32 *acl_ip4_output_classify_table_by_sw_if_index; + u32 *acl_ip6_output_classify_table_by_sw_if_index; + + /* MACIP (input) ACLs associated with the interfaces */ + u32 *macip_acl_by_sw_if_index; + + /* next indices for our nodes in the l2-classify tables */ + u32 l2_input_classify_next_acl; + u32 l2_output_classify_next_acl; + + /* next node indices for feature bitmap */ + u32 acl_in_node_input_next_node_index[32]; + /* the respective thing for the output feature */ + l2_output_next_nodes_st acl_out_output_next_nodes; + + /* ACL match actions (must be coherent across in/out ACLs to next indices (can differ) */ + + u32 acl_in_ip4_match_next[256]; + u32 acl_in_ip6_match_next[256]; + u32 acl_out_ip4_match_next[256]; + u32 acl_out_ip6_match_next[256]; + u32 n_match_actions; + + + /* convenience */ + vlib_main_t * vlib_main; + vnet_main_t * vnet_main; + ethernet_main_t * ethernet_main; +} acl_main_t; + +extern acl_main_t acl_main; + + +#endif diff --git a/src/plugins/acl/acl_all_api_h.h b/src/plugins/acl/acl_all_api_h.h new file mode 100644 index 00000000..96eca56d --- /dev/null +++ b/src/plugins/acl/acl_all_api_h.h @@ -0,0 +1,321 @@ +/* + * 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. + */ +/* Include the generated file, see BUILT_SOURCES in Makefile.am */ +#include + +#ifdef vl_printfun + +#ifdef LP64 +#define _uword_fmt "%lld" +#define _uword_cast (long long) +#else +#define _uword_fmt "%ld" +#define _uword_cast long +#endif + +static inline void * +vl_api_acl_rule_t_print (vl_api_acl_rule_t * a, void *handle) +{ + vl_print (handle, "vl_api_acl_rule_t:\n"); + vl_print (handle, "is_permit: %u\n", (unsigned) a->is_permit); + vl_print (handle, "is_ipv6: %u\n", (unsigned) a->is_ipv6); + { + int _i; + for (_i = 0; _i < 16; _i++) + { + vl_print (handle, "src_ip_addr[%d]: %u\n", _i, a->src_ip_addr[_i]); + } + } + vl_print (handle, "src_ip_prefix_len: %u\n", + (unsigned) a->src_ip_prefix_len); + { + int _i; + for (_i = 0; _i < 16; _i++) + { + vl_print (handle, "dst_ip_addr[%d]: %u\n", _i, a->dst_ip_addr[_i]); + } + } + vl_print (handle, "dst_ip_prefix_len: %u\n", + (unsigned) a->dst_ip_prefix_len); + vl_print (handle, "proto: %u\n", (unsigned) a->proto); + vl_print (handle, "srcport_or_icmptype_first: %u\n", + (unsigned) a->srcport_or_icmptype_first); + vl_print (handle, "srcport_or_icmptype_last: %u\n", + (unsigned) a->srcport_or_icmptype_last); + vl_print (handle, "dstport_or_icmpcode_first: %u\n", + (unsigned) a->dstport_or_icmpcode_first); + vl_print (handle, "dstport_or_icmpcode_last: %u\n", + (unsigned) a->dstport_or_icmpcode_last); + vl_print (handle, "tcp_flags_mask: %u\n", (unsigned) a->tcp_flags_mask); + vl_print (handle, "tcp_flags_value: %u\n", (unsigned) a->tcp_flags_value); + return handle; +} + +static inline void * +vl_api_acl_add_replace_t_print (vl_api_acl_add_replace_t * a, void *handle) +{ + int i; + vl_print (handle, "vl_api_acl_add_replace_t:\n"); + vl_print (handle, "_vl_msg_id: %u\n", (unsigned) a->_vl_msg_id); + vl_print (handle, "client_index: %u\n", (unsigned) a->client_index); + vl_print (handle, "context: %u\n", (unsigned) a->context); + vl_print (handle, "acl_index: %u\n", (unsigned) a->acl_index); + vl_print (handle, "count: %u\n", (unsigned) a->count); + vl_print (handle, "r ----- \n"); + for (i = 0; i < a->count; i++) + { + vl_print (handle, " r[%d]:\n", i); + vl_api_acl_rule_t_print (&a->r[i], handle); + } + vl_print (handle, "r ----- END \n"); + return handle; +} + + +static inline void *vl_api_acl_details_t_print (vl_api_acl_details_t *a,void *handle) +{ + vl_print(handle, "vl_api_acl_details_t:\n"); + vl_print(handle, "_vl_msg_id: %u\n", (unsigned) a->_vl_msg_id); + vl_print(handle, "context: %u\n", (unsigned) a->context); + vl_print(handle, "acl_index: %u\n", (unsigned) a->acl_index); + { + int _i; + for (_i = 0; _i < 64; _i++) { + vl_print(handle, "tag[%d]: %u\n", _i, a->tag[_i]); + } + } + vl_print(handle, "count: %u\n", (unsigned) a->count); + vl_print(handle, "r ----- \n"); + // FIXME vl_api_acl_rule_t_print(&a->r, handle); + vl_print(handle, "r ----- END \n"); + return handle; +} + +static inline void * +vl_api_macip_acl_rule_t_print (vl_api_macip_acl_rule_t * a, void *handle) +{ + vl_print (handle, "vl_api_macip_acl_rule_t:\n"); + vl_print (handle, "is_permit: %u\n", (unsigned) a->is_permit); + vl_print (handle, "is_ipv6: %u\n", (unsigned) a->is_ipv6); + { + int _i; + for (_i = 0; _i < 6; _i++) + { + vl_print (handle, "src_mac[%d]: %u\n", _i, a->src_mac[_i]); + } + } + { + int _i; + for (_i = 0; _i < 6; _i++) + { + vl_print (handle, "src_mac_mask[%d]: %u\n", _i, a->src_mac_mask[_i]); + } + } + { + int _i; + for (_i = 0; _i < 16; _i++) + { + vl_print (handle, "src_ip_addr[%d]: %u\n", _i, a->src_ip_addr[_i]); + } + } + vl_print (handle, "src_ip_prefix_len: %u\n", + (unsigned) a->src_ip_prefix_len); + return handle; +} + +static inline void * +vl_api_macip_acl_add_t_print (vl_api_macip_acl_add_t * a, void *handle) +{ + int i; + vl_print (handle, "vl_api_macip_acl_add_t:\n"); + vl_print (handle, "_vl_msg_id: %u\n", (unsigned) a->_vl_msg_id); + vl_print (handle, "client_index: %u\n", (unsigned) a->client_index); + vl_print (handle, "context: %u\n", (unsigned) a->context); + vl_print (handle, "count: %u\n", (unsigned) a->count); + vl_print (handle, "r ----- \n"); + for (i = 0; i < a->count; i++) + { + vl_print (handle, " r[%d]:\n", i); + vl_api_macip_acl_rule_t_print (&a->r[i], handle); + } + vl_print (handle, "r ----- END \n"); + return handle; +} + +static inline void *vl_api_macip_acl_details_t_print (vl_api_macip_acl_details_t *a,void *handle) +{ + int i; + vl_print(handle, "vl_api_macip_acl_details_t:\n"); + vl_print(handle, "_vl_msg_id: %u\n", (unsigned) a->_vl_msg_id); + vl_print(handle, "context: %u\n", (unsigned) a->context); + vl_print(handle, "acl_index: %u\n", (unsigned) a->acl_index); + { + int _i; + for (_i = 0; _i < 64; _i++) { + vl_print(handle, "tag[%d]: %u\n", _i, a->tag[_i]); + } + } + vl_print(handle, "count: %u\n", (unsigned) a->count); + vl_print(handle, "r ----- \n"); + for (i = 0; i < a->count; i++) + { + vl_print (handle, " r[%d]:\n", i); + vl_api_macip_acl_rule_t_print (&a->r[i], handle); + } + vl_print(handle, "r ----- END \n"); + return handle; +} + +#endif /* vl_printfun */ + + +#ifdef vl_endianfun + +#undef clib_net_to_host_uword +#ifdef LP64 +#define clib_net_to_host_uword clib_net_to_host_u64 +#else +#define clib_net_to_host_uword clib_net_to_host_u32 +#endif + +/* + * Manual endian/print functions created by copypasting the automatically + * generated ones with small required adjustments. Appears the codegen + * can't make code to print the contents of custom-type array. + */ + +static inline void +vl_api_acl_rule_t_endian (vl_api_acl_rule_t * a) +{ + /* a->is_permit = a->is_permit (no-op) */ + /* a->is_ipv6 = a->is_ipv6 (no-op) */ + /* a->src_ip_addr[0..15] = a->src_ip_addr[0..15] (no-op) */ + /* a->src_ip_prefix_len = a->src_ip_prefix_len (no-op) */ + /* a->dst_ip_addr[0..15] = a->dst_ip_addr[0..15] (no-op) */ + /* a->dst_ip_prefix_len = a->dst_ip_prefix_len (no-op) */ + /* a->proto = a->proto (no-op) */ + a->srcport_or_icmptype_first = + clib_net_to_host_u16 (a->srcport_or_icmptype_first); + a->srcport_or_icmptype_last = + clib_net_to_host_u16 (a->srcport_or_icmptype_last); + a->dstport_or_icmpcode_first = + clib_net_to_host_u16 (a->dstport_or_icmpcode_first); + a->dstport_or_icmpcode_last = + clib_net_to_host_u16 (a->dstport_or_icmpcode_last); + /* a->tcp_flags_mask = a->tcp_flags_mask (no-op) */ + /* a->tcp_flags_value = a->tcp_flags_value (no-op) */ +} + +static inline void +vl_api_acl_add_replace_t_endian (vl_api_acl_add_replace_t * a) +{ + int i; + a->_vl_msg_id = clib_net_to_host_u16 (a->_vl_msg_id); + a->client_index = clib_net_to_host_u32 (a->client_index); + a->context = clib_net_to_host_u32 (a->context); + a->acl_index = clib_net_to_host_u32 (a->acl_index); + a->count = clib_net_to_host_u32 (a->count); + for (i = 0; i < a->count; i++) + { + vl_api_acl_rule_t_endian (&a->r[i]); + } +} + +static inline void vl_api_acl_details_t_endian (vl_api_acl_details_t *a) +{ + int i; + a->_vl_msg_id = clib_net_to_host_u16(a->_vl_msg_id); + a->context = clib_net_to_host_u32(a->context); + a->acl_index = clib_net_to_host_u32(a->acl_index); + /* a->tag[0..63] = a->tag[0..63] (no-op) */ + a->count = clib_net_to_host_u32(a->count); + for (i = 0; i < a->count; i++) + { + vl_api_acl_rule_t_endian (&a->r[i]); + } +} + +static inline void vl_api_acl_interface_list_details_t_endian (vl_api_acl_interface_list_details_t *a) +{ + int i; + a->_vl_msg_id = clib_net_to_host_u16(a->_vl_msg_id); + a->context = clib_net_to_host_u32(a->context); + a->sw_if_index = clib_net_to_host_u32(a->sw_if_index); + /* a->count = a->count (no-op) */ + /* a->n_input = a->n_input (no-op) */ + for(i=0; icount; i++) { + a->acls[i] = clib_net_to_host_u32(a->acls[i]); + } +} + +static inline void vl_api_acl_interface_set_acl_list_t_endian (vl_api_acl_interface_set_acl_list_t *a) +{ + int i; + a->_vl_msg_id = clib_net_to_host_u16(a->_vl_msg_id); + a->client_index = clib_net_to_host_u32(a->client_index); + a->context = clib_net_to_host_u32(a->context); + a->sw_if_index = clib_net_to_host_u32(a->sw_if_index); + /* a->count = a->count (no-op) */ + /* a->n_input = a->n_input (no-op) */ + for(i=0; icount; i++) { + a->acls[i] = clib_net_to_host_u32(a->acls[i]); + } +} + +static inline void +vl_api_macip_acl_rule_t_endian (vl_api_macip_acl_rule_t * a) +{ + /* a->is_permit = a->is_permit (no-op) */ + /* a->is_ipv6 = a->is_ipv6 (no-op) */ + /* a->src_mac[0..5] = a->src_mac[0..5] (no-op) */ + /* a->src_mac_mask[0..5] = a->src_mac_mask[0..5] (no-op) */ + /* a->src_ip_addr[0..15] = a->src_ip_addr[0..15] (no-op) */ + /* a->src_ip_prefix_len = a->src_ip_prefix_len (no-op) */ +} + +static inline void +vl_api_macip_acl_add_t_endian (vl_api_macip_acl_add_t * a) +{ + int i; + a->_vl_msg_id = clib_net_to_host_u16 (a->_vl_msg_id); + a->client_index = clib_net_to_host_u32 (a->client_index); + a->context = clib_net_to_host_u32 (a->context); + a->count = clib_net_to_host_u32 (a->count); + for (i = 0; i < a->count; i++) + { + vl_api_macip_acl_rule_t_endian (&a->r[i]); + } +} + +static inline void vl_api_macip_acl_details_t_endian (vl_api_macip_acl_details_t *a) +{ + int i; + a->_vl_msg_id = clib_net_to_host_u16(a->_vl_msg_id); + a->context = clib_net_to_host_u32(a->context); + a->acl_index = clib_net_to_host_u32(a->acl_index); + /* a->tag[0..63] = a->tag[0..63] (no-op) */ + a->count = clib_net_to_host_u32(a->count); + for (i = 0; i < a->count; i++) + { + vl_api_macip_acl_rule_t_endian (&a->r[i]); + } +} + + + + +#endif /* vl_printfun */ + + diff --git a/src/plugins/acl/acl_msg_enum.h b/src/plugins/acl/acl_msg_enum.h new file mode 100644 index 00000000..14d8b48c --- /dev/null +++ b/src/plugins/acl/acl_msg_enum.h @@ -0,0 +1,28 @@ +/* + * 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. + */ +#ifndef included_acl_msg_enum_h +#define included_acl_msg_enum_h + +#include + +#define vl_msg_id(n,h) n, +typedef enum { +#include + /* We'll want to know how many messages IDs we need... */ + VL_MSG_FIRST_AVAILABLE, +} vl_msg_id_t; +#undef vl_msg_id + +#endif diff --git a/src/plugins/acl/acl_test.c b/src/plugins/acl/acl_test.c new file mode 100644 index 00000000..a0e413e1 --- /dev/null +++ b/src/plugins/acl/acl_test.c @@ -0,0 +1,1024 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + *------------------------------------------------------------------ + * acl_test.c - test harness plugin + *------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include +#include +#include + +uword unformat_sw_if_index (unformat_input_t * input, va_list * args); + +/* Declare message IDs */ +#include + +/* define message structures */ +#define vl_typedefs +#include +#undef vl_typedefs + +/* define message structures */ +#define vl_endianfun +#include +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) +#define vl_printfun +#include +#undef vl_printfun + +/* Get the API version number. */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#undef vl_api_version + +typedef struct { + /* API message ID base */ + u16 msg_id_base; + vat_main_t *vat_main; +} acl_test_main_t; + +acl_test_main_t acl_test_main; + +#define foreach_standard_reply_retval_handler \ +_(acl_del_reply) \ +_(acl_interface_add_del_reply) \ +_(macip_acl_interface_add_del_reply) \ +_(acl_interface_set_acl_list_reply) \ +_(macip_acl_del_reply) + +#define foreach_reply_retval_aclindex_handler \ +_(acl_add_replace_reply) \ +_(macip_acl_add_reply) + +#define _(n) \ + static void vl_api_##n##_t_handler \ + (vl_api_##n##_t * mp) \ + { \ + vat_main_t * vam = acl_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 _ + +#define _(n) \ + static void vl_api_##n##_t_handler \ + (vl_api_##n##_t * mp) \ + { \ + vat_main_t * vam = acl_test_main.vat_main; \ + i32 retval = ntohl(mp->retval); \ + if (vam->async_mode) { \ + vam->async_errors += (retval < 0); \ + } else { \ + clib_warning("ACL index: %d", ntohl(mp->acl_index)); \ + vam->retval = retval; \ + vam->result_ready = 1; \ + } \ + } +foreach_reply_retval_aclindex_handler; +#undef _ + +/* These two ought to be in a library somewhere but they aren't */ +static uword +my_unformat_mac_address (unformat_input_t * input, va_list * args) +{ + u8 *a = va_arg (*args, u8 *); + return unformat (input, "%x:%x:%x:%x:%x:%x", &a[0], &a[1], &a[2], &a[3], + &a[4], &a[5]); +} + +static u8 * +my_format_mac_address (u8 * s, va_list * args) +{ + u8 *a = va_arg (*args, u8 *); + return format (s, "%02x:%02x:%02x:%02x:%02x:%02x", + a[0], a[1], a[2], a[3], a[4], a[5]); +} + + + +static void vl_api_acl_plugin_get_version_reply_t_handler + (vl_api_acl_plugin_get_version_reply_t * mp) + { + vat_main_t * vam = acl_test_main.vat_main; + clib_warning("ACL plugin version: %d.%d", ntohl(mp->major), ntohl(mp->minor)); + vam->result_ready = 1; + } + +static void vl_api_acl_interface_list_details_t_handler + (vl_api_acl_interface_list_details_t * mp) + { + int i; + vat_main_t * vam = acl_test_main.vat_main; + u8 *out = 0; + vl_api_acl_interface_list_details_t_endian(mp); + out = format(out, "sw_if_index: %d, count: %d, n_input: %d\n", mp->sw_if_index, mp->count, mp->n_input); + out = format(out, " input "); + for(i=0; icount; i++) { + out = format(out, "%d ", mp->acls[i]); + if (i == mp->n_input-1) + out = format(out, "\n output "); + } + out = format(out, "\n"); + clib_warning("%s", out); + vec_free(out); + vam->result_ready = 1; + } + + +static inline u8 * +vl_api_acl_rule_t_pretty_format (u8 *out, vl_api_acl_rule_t * a) +{ + int af = a->is_ipv6 ? AF_INET6 : AF_INET; + u8 src[INET6_ADDRSTRLEN]; + u8 dst[INET6_ADDRSTRLEN]; + inet_ntop(af, a->src_ip_addr, (void *)src, sizeof(src)); + inet_ntop(af, a->dst_ip_addr, (void *)dst, sizeof(dst)); + + out = format(out, "%s action %d src %s/%d dst %s/%d proto %d sport %d-%d dport %d-%d tcpflags %d %d", + a->is_ipv6 ? "ipv6" : "ipv4", a->is_permit, + src, a->src_ip_prefix_len, + dst, a->dst_ip_prefix_len, + a->proto, + a->srcport_or_icmptype_first, a->srcport_or_icmptype_last, + a->dstport_or_icmpcode_first, a->dstport_or_icmpcode_last, + a->tcp_flags_mask, a->tcp_flags_value); + return(out); +} + + + +static void vl_api_acl_details_t_handler + (vl_api_acl_details_t * mp) + { + int i; + vat_main_t * vam = acl_test_main.vat_main; + vl_api_acl_details_t_endian(mp); + u8 *out = 0; + out = format(0, "acl_index: %d, count: %d\n tag {%s}\n", mp->acl_index, mp->count, mp->tag); + for(i=0; icount; i++) { + out = format(out, " "); + out = vl_api_acl_rule_t_pretty_format(out, &mp->r[i]); + out = format(out, "%s\n", icount-1 ? "," : ""); + } + clib_warning("%s", out); + vec_free(out); + vam->result_ready = 1; + } + +static inline u8 * +vl_api_macip_acl_rule_t_pretty_format (u8 *out, vl_api_macip_acl_rule_t * a) +{ + int af = a->is_ipv6 ? AF_INET6 : AF_INET; + u8 src[INET6_ADDRSTRLEN]; + inet_ntop(af, a->src_ip_addr, (void *)src, sizeof(src)); + + out = format(out, "%s action %d ip %s/%d mac %U mask %U", + a->is_ipv6 ? "ipv6" : "ipv4", a->is_permit, + src, a->src_ip_prefix_len, + my_format_mac_address, a->src_mac, + my_format_mac_address, a->src_mac_mask); + return(out); +} + + +static void vl_api_macip_acl_details_t_handler + (vl_api_macip_acl_details_t * mp) + { + int i; + vat_main_t * vam = acl_test_main.vat_main; + vl_api_macip_acl_details_t_endian(mp); + u8 *out = format(0,"MACIP acl_index: %d, count: %d\n tag {%s}\n", mp->acl_index, mp->count, mp->tag); + for(i=0; icount; i++) { + out = format(out, " "); + out = vl_api_macip_acl_rule_t_pretty_format(out, &mp->r[i]); + out = format(out, "%s\n", icount-1 ? "," : ""); + } + clib_warning("%s", out); + vec_free(out); + vam->result_ready = 1; + } + +static void vl_api_macip_acl_interface_get_reply_t_handler + (vl_api_macip_acl_interface_get_reply_t * mp) + { + int i; + vat_main_t * vam = acl_test_main.vat_main; + u8 *out = format(0, "sw_if_index with MACIP ACL count: %d\n", ntohl(mp->count)); + for(i=0; icount); i++) { + out = format(out, " macip_acl_interface_add_del sw_if_index %d add acl %d\n", i, ntohl(mp->acls[i])); + } + out = format(out, "\n"); + clib_warning("%s", out); + vec_free(out); + vam->result_ready = 1; + } + + +/* + * Table of message reply handlers, must include boilerplate handlers + * we just generated + */ +#define foreach_vpe_api_reply_msg \ +_(ACL_ADD_REPLACE_REPLY, acl_add_replace_reply) \ +_(ACL_DEL_REPLY, acl_del_reply) \ +_(ACL_INTERFACE_ADD_DEL_REPLY, acl_interface_add_del_reply) \ +_(ACL_INTERFACE_SET_ACL_LIST_REPLY, acl_interface_set_acl_list_reply) \ +_(ACL_INTERFACE_LIST_DETAILS, acl_interface_list_details) \ +_(ACL_DETAILS, acl_details) \ +_(MACIP_ACL_ADD_REPLY, macip_acl_add_reply) \ +_(MACIP_ACL_DEL_REPLY, macip_acl_del_reply) \ +_(MACIP_ACL_DETAILS, macip_acl_details) \ +_(MACIP_ACL_INTERFACE_ADD_DEL_REPLY, macip_acl_interface_add_del_reply) \ +_(MACIP_ACL_INTERFACE_GET_REPLY, macip_acl_interface_get_reply) \ +_(ACL_PLUGIN_GET_VERSION_REPLY, acl_plugin_get_version_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_acl_plugin_get_version (vat_main_t * vam) +{ + acl_test_main_t * sm = &acl_test_main; + vl_api_acl_plugin_get_version_t * mp; + u32 msg_size = sizeof(*mp); + f64 timeout; + + vam->result_ready = 0; + mp = vl_msg_api_alloc_as_if_client(msg_size); + memset (mp, 0, msg_size); + mp->_vl_msg_id = ntohs (VL_API_ACL_PLUGIN_GET_VERSION + sm->msg_id_base); + mp->client_index = vam->my_client_index; + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + return 0; +} + +static int api_macip_acl_interface_get (vat_main_t * vam) +{ + acl_test_main_t * sm = &acl_test_main; + vl_api_acl_plugin_get_version_t * mp; + u32 msg_size = sizeof(*mp); + f64 timeout; + + vam->result_ready = 0; + mp = vl_msg_api_alloc_as_if_client(msg_size); + memset (mp, 0, msg_size); + mp->_vl_msg_id = ntohs (VL_API_MACIP_ACL_INTERFACE_GET + sm->msg_id_base); + mp->client_index = vam->my_client_index; + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + return 0; +} + +#define vec_validate_acl_rules(v, idx) \ + do { \ + if (vec_len(v) < idx+1) { \ + vec_validate(v, idx); \ + v[idx].is_permit = 0x1; \ + v[idx].srcport_or_icmptype_last = 0xffff; \ + v[idx].dstport_or_icmpcode_last = 0xffff; \ + } \ + } while (0) + + +static int api_acl_add_replace (vat_main_t * vam) +{ + acl_test_main_t * sm = &acl_test_main; + unformat_input_t * i = vam->input; + f64 timeout; + vl_api_acl_add_replace_t * mp; + u32 acl_index = ~0; + u32 msg_size = sizeof (*mp); /* without the rules */ + + vl_api_acl_rule_t *rules = 0; + int rule_idx = 0; + int n_rules = 0; + u32 proto = 0; + u32 port1 = 0; + u32 port2 = 0; + u32 action = 0; + u32 tcpflags, tcpmask; + u32 src_prefix_length = 0, dst_prefix_length = 0; + ip4_address_t src_v4address, dst_v4address; + ip6_address_t src_v6address, dst_v6address; + u8 *tag = 0; + + if (!unformat (i, "%d", &acl_index)) { + /* Just assume -1 */ + } + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "ipv6")) + { + vec_validate_acl_rules(rules, rule_idx); + rules[rule_idx].is_ipv6 = 1; + } + else if (unformat (i, "ipv4")) + { + vec_validate_acl_rules(rules, rule_idx); + rules[rule_idx].is_ipv6 = 0; + } + else if (unformat (i, "permit+reflect")) + { + vec_validate_acl_rules(rules, rule_idx); + rules[rule_idx].is_permit = 2; + } + else if (unformat (i, "permit")) + { + vec_validate_acl_rules(rules, rule_idx); + rules[rule_idx].is_permit = 1; + } + else if (unformat (i, "action %d", &action)) + { + vec_validate_acl_rules(rules, rule_idx); + rules[rule_idx].is_permit = action; + } + else if (unformat (i, "src %U/%d", + unformat_ip4_address, &src_v4address, &src_prefix_length)) + { + vec_validate_acl_rules(rules, rule_idx); + memcpy (rules[rule_idx].src_ip_addr, &src_v4address, 4); + rules[rule_idx].src_ip_prefix_len = src_prefix_length; + rules[rule_idx].is_ipv6 = 0; + } + else if (unformat (i, "src %U/%d", + unformat_ip6_address, &src_v6address, &src_prefix_length)) + { + vec_validate_acl_rules(rules, rule_idx); + memcpy (rules[rule_idx].src_ip_addr, &src_v6address, 16); + rules[rule_idx].src_ip_prefix_len = src_prefix_length; + rules[rule_idx].is_ipv6 = 1; + } + else if (unformat (i, "dst %U/%d", + unformat_ip4_address, &dst_v4address, &dst_prefix_length)) + { + vec_validate_acl_rules(rules, rule_idx); + memcpy (rules[rule_idx].dst_ip_addr, &dst_v4address, 4); + rules[rule_idx].dst_ip_prefix_len = dst_prefix_length; + rules[rule_idx].is_ipv6 = 0; + } + else if (unformat (i, "dst %U/%d", + unformat_ip6_address, &dst_v6address, &dst_prefix_length)) + { + vec_validate_acl_rules(rules, rule_idx); + memcpy (rules[rule_idx].dst_ip_addr, &dst_v6address, 16); + rules[rule_idx].dst_ip_prefix_len = dst_prefix_length; + rules[rule_idx].is_ipv6 = 1; + } + else if (unformat (i, "sport %d-%d", &port1, &port2)) + { + vec_validate_acl_rules(rules, rule_idx); + rules[rule_idx].srcport_or_icmptype_first = htons(port1); + rules[rule_idx].srcport_or_icmptype_last = htons(port2); + } + else if (unformat (i, "sport %d", &port1)) + { + vec_validate_acl_rules(rules, rule_idx); + rules[rule_idx].srcport_or_icmptype_first = htons(port1); + rules[rule_idx].srcport_or_icmptype_last = htons(port1); + } + else if (unformat (i, "dport %d-%d", &port1, &port2)) + { + vec_validate_acl_rules(rules, rule_idx); + rules[rule_idx].dstport_or_icmpcode_first = htons(port1); + rules[rule_idx].dstport_or_icmpcode_last = htons(port2); + } + else if (unformat (i, "dport %d", &port1)) + { + vec_validate_acl_rules(rules, rule_idx); + rules[rule_idx].dstport_or_icmpcode_first = htons(port1); + rules[rule_idx].dstport_or_icmpcode_last = htons(port1); + } + else if (unformat (i, "tcpflags %d %d", &tcpflags, &tcpmask)) + { + vec_validate_acl_rules(rules, rule_idx); + rules[rule_idx].tcp_flags_value = tcpflags; + rules[rule_idx].tcp_flags_mask = tcpmask; + } + else if (unformat (i, "proto %d", &proto)) + { + vec_validate_acl_rules(rules, rule_idx); + rules[rule_idx].proto = proto; + } + else if (unformat (i, "tag %s", &tag)) + { + } + else if (unformat (i, ",")) + { + rule_idx++; + vec_validate_acl_rules(rules, rule_idx); + } + else + break; + } + + /* Construct the API message */ + vam->result_ready = 0; + + if(rules) + n_rules = vec_len(rules); + else + n_rules = 0; + + msg_size += n_rules*sizeof(rules[0]); + + mp = vl_msg_api_alloc_as_if_client(msg_size); + memset (mp, 0, msg_size); + mp->_vl_msg_id = ntohs (VL_API_ACL_ADD_REPLACE + sm->msg_id_base); + mp->client_index = vam->my_client_index; + if (n_rules > 0) + clib_memcpy(mp->r, rules, n_rules*sizeof (vl_api_acl_rule_t)); + if (tag) + { + if (vec_len(tag) >= sizeof(mp->tag)) + { + tag[sizeof(mp->tag)-1] = 0; + _vec_len(tag) = sizeof(mp->tag); + } + clib_memcpy(mp->tag, tag, vec_len(tag)); + vec_free(tag); + } + mp->acl_index = ntohl(acl_index); + mp->count = htonl(n_rules); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int api_acl_del (vat_main_t * vam) +{ + acl_test_main_t * sm = &acl_test_main; + unformat_input_t * i = vam->input; + f64 timeout; + vl_api_acl_del_t * mp; + u32 acl_index = ~0; + + if (!unformat (i, "%d", &acl_index)) { + errmsg ("missing acl index\n"); + return -99; + } + + /* Construct the API message */ + M(ACL_DEL, acl_del); + mp->acl_index = ntohl(acl_index); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int api_macip_acl_del (vat_main_t * vam) +{ + acl_test_main_t * sm = &acl_test_main; + unformat_input_t * i = vam->input; + f64 timeout; + vl_api_acl_del_t * mp; + u32 acl_index = ~0; + + if (!unformat (i, "%d", &acl_index)) { + errmsg ("missing acl index\n"); + return -99; + } + + /* Construct the API message */ + M(MACIP_ACL_DEL, acl_del); + mp->acl_index = ntohl(acl_index); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int api_acl_interface_add_del (vat_main_t * vam) +{ + acl_test_main_t * sm = &acl_test_main; + unformat_input_t * i = vam->input; + f64 timeout; + vl_api_acl_interface_add_del_t * mp; + u32 sw_if_index = ~0; + u32 acl_index = ~0; + u8 is_input = 0; + u8 is_add = 0; + +// acl_interface_add_del | sw_if_index acl_index [out] [del] + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%d", &acl_index)) + ; + else + break; + } + + + /* 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, "add")) + is_add = 1; + else if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "acl %d", &acl_index)) + ; + else if (unformat (i, "input")) + is_input = 1; + else if (unformat (i, "output")) + is_input = 0; + else + break; + } + + if (sw_if_index == ~0) { + errmsg ("missing interface name / explicit sw_if_index number \n"); + return -99; + } + + if (acl_index == ~0) { + errmsg ("missing ACL index\n"); + return -99; + } + + + + /* Construct the API message */ + M(ACL_INTERFACE_ADD_DEL, acl_interface_add_del); + mp->acl_index = ntohl(acl_index); + mp->sw_if_index = ntohl(sw_if_index); + mp->is_add = is_add; + mp->is_input = is_input; + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int api_macip_acl_interface_add_del (vat_main_t * vam) +{ + acl_test_main_t * sm = &acl_test_main; + unformat_input_t * i = vam->input; + f64 timeout; + vl_api_macip_acl_interface_add_del_t * mp; + u32 sw_if_index = ~0; + u32 acl_index = ~0; + u8 is_add = 0; + + /* 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, "add")) + is_add = 1; + else if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "acl %d", &acl_index)) + ; + else + break; + } + + if (sw_if_index == ~0) { + errmsg ("missing interface name / explicit sw_if_index number \n"); + return -99; + } + + if (acl_index == ~0) { + errmsg ("missing ACL index\n"); + return -99; + } + + + + /* Construct the API message */ + M(MACIP_ACL_INTERFACE_ADD_DEL, macip_acl_interface_add_del); + mp->acl_index = ntohl(acl_index); + mp->sw_if_index = ntohl(sw_if_index); + mp->is_add = is_add; + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int api_acl_interface_set_acl_list (vat_main_t * vam) +{ + acl_test_main_t * sm = &acl_test_main; + unformat_input_t * i = vam->input; + f64 timeout; + vl_api_acl_interface_set_acl_list_t * mp; + u32 sw_if_index = ~0; + u32 acl_index = ~0; + u32 *inacls = 0; + u32 *outacls = 0; + u8 is_input = 0; + +// acl_interface_set_acl_list | sw_if_index input [acl-idx list] output [acl-idx list] + + /* 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, "%d", &acl_index)) + { + if(is_input) + vec_add1(inacls, htonl(acl_index)); + else + vec_add1(outacls, htonl(acl_index)); + } + else if (unformat (i, "acl %d", &acl_index)) + ; + else if (unformat (i, "input")) + is_input = 1; + else if (unformat (i, "output")) + is_input = 0; + else + break; + } + + if (sw_if_index == ~0) { + errmsg ("missing interface name / explicit sw_if_index number \n"); + return -99; + } + + /* Construct the API message */ + M2(ACL_INTERFACE_SET_ACL_LIST, acl_interface_set_acl_list, sizeof(u32) * (vec_len(inacls) + vec_len(outacls))); + mp->sw_if_index = ntohl(sw_if_index); + mp->n_input = vec_len(inacls); + mp->count = vec_len(inacls) + vec_len(outacls); + vec_append(inacls, outacls); + if (vec_len(inacls) > 0) + clib_memcpy(mp->acls, inacls, vec_len(inacls)*sizeof(u32)); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + + +static int api_acl_interface_list_dump (vat_main_t * vam) +{ + acl_test_main_t * sm = &acl_test_main; + unformat_input_t * i = vam->input; + f64 timeout; + u32 sw_if_index = ~0; + vl_api_acl_interface_list_dump_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 + break; + } + + /* Construct the API message */ + M(ACL_INTERFACE_LIST_DUMP, acl_interface_list_dump); + mp->sw_if_index = ntohl (sw_if_index); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int api_acl_dump (vat_main_t * vam) +{ + acl_test_main_t * sm = &acl_test_main; + unformat_input_t * i = vam->input; + f64 timeout; + u32 acl_index = ~0; + vl_api_acl_dump_t * mp; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) { + if (unformat (i, "%d", &acl_index)) + ; + else + break; + } + + /* Construct the API message */ + M(ACL_DUMP, acl_dump); + mp->acl_index = ntohl (acl_index); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int api_macip_acl_dump (vat_main_t * vam) +{ + acl_test_main_t * sm = &acl_test_main; + unformat_input_t * i = vam->input; + f64 timeout; + u32 acl_index = ~0; + vl_api_acl_dump_t * mp; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) { + if (unformat (i, "%d", &acl_index)) + ; + else + break; + } + + /* Construct the API message */ + M(MACIP_ACL_DUMP, macip_acl_dump); + mp->acl_index = ntohl (acl_index); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +#define vec_validate_macip_acl_rules(v, idx) \ + do { \ + if (vec_len(v) < idx+1) { \ + vec_validate(v, idx); \ + v[idx].is_permit = 0x1; \ + } \ + } while (0) + + +static int api_macip_acl_add (vat_main_t * vam) +{ + acl_test_main_t * sm = &acl_test_main; + unformat_input_t * i = vam->input; + f64 timeout; + vl_api_macip_acl_add_t * mp; + u32 msg_size = sizeof (*mp); /* without the rules */ + + vl_api_macip_acl_rule_t *rules = 0; + int rule_idx = 0; + int n_rules = 0; + u32 src_prefix_length = 0; + u32 action = 0; + ip4_address_t src_v4address; + ip6_address_t src_v6address; + u8 src_mac[6]; + u8 *tag = 0; + u8 mac_mask_all_1[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "ipv6")) + { + vec_validate_macip_acl_rules(rules, rule_idx); + rules[rule_idx].is_ipv6 = 1; + } + else if (unformat (i, "ipv4")) + { + vec_validate_macip_acl_rules(rules, rule_idx); + rules[rule_idx].is_ipv6 = 1; + } + else if (unformat (i, "permit")) + { + vec_validate_macip_acl_rules(rules, rule_idx); + rules[rule_idx].is_permit = 1; + } + else if (unformat (i, "deny")) + { + vec_validate_macip_acl_rules(rules, rule_idx); + rules[rule_idx].is_permit = 0; + } + else if (unformat (i, "action %d", &action)) + { + vec_validate_macip_acl_rules(rules, rule_idx); + rules[rule_idx].is_permit = action; + } + else if (unformat (i, "ip %U/%d", + unformat_ip4_address, &src_v4address, &src_prefix_length)) + { + vec_validate_macip_acl_rules(rules, rule_idx); + memcpy (rules[rule_idx].src_ip_addr, &src_v4address, 4); + rules[rule_idx].src_ip_prefix_len = src_prefix_length; + rules[rule_idx].is_ipv6 = 0; + } + else if (unformat (i, "ip %U/%d", + unformat_ip6_address, &src_v6address, &src_prefix_length)) + { + vec_validate_macip_acl_rules(rules, rule_idx); + memcpy (rules[rule_idx].src_ip_addr, &src_v6address, 16); + rules[rule_idx].src_ip_prefix_len = src_prefix_length; + rules[rule_idx].is_ipv6 = 1; + } + else if (unformat (i, "mac %U", + my_unformat_mac_address, &src_mac)) + { + vec_validate_macip_acl_rules(rules, rule_idx); + memcpy (rules[rule_idx].src_mac, &src_mac, 6); + memcpy (rules[rule_idx].src_mac_mask, &mac_mask_all_1, 6); + } + else if (unformat (i, "mask %U", + my_unformat_mac_address, &src_mac)) + { + vec_validate_macip_acl_rules(rules, rule_idx); + memcpy (rules[rule_idx].src_mac_mask, &src_mac, 6); + } + else if (unformat (i, "tag %s", &tag)) + { + } + else if (unformat (i, ",")) + { + rule_idx++; + vec_validate_macip_acl_rules(rules, rule_idx); + } + else + break; + } + + /* Construct the API message */ + vam->result_ready = 0; + + if(rules) + n_rules = vec_len(rules); + else + n_rules = 0; + + msg_size += n_rules*sizeof(rules[0]); + + mp = vl_msg_api_alloc_as_if_client(msg_size); + memset (mp, 0, msg_size); + mp->_vl_msg_id = ntohs (VL_API_MACIP_ACL_ADD + sm->msg_id_base); + mp->client_index = vam->my_client_index; + if (n_rules > 0) + clib_memcpy(mp->r, rules, n_rules*sizeof (mp->r[0])); + if (tag) + { + if (vec_len(tag) >= sizeof(mp->tag)) + { + tag[sizeof(mp->tag)-1] = 0; + _vec_len(tag) = sizeof(mp->tag); + } + clib_memcpy(mp->tag, tag, vec_len(tag)); + vec_free(tag); + } + + mp->count = htonl(n_rules); + + /* 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 \ +_(acl_plugin_get_version, "") \ +_(acl_add_replace, " [ [src IP/plen] [dst IP/plen] [sport X-Y] [dport X-Y] [proto P] [tcpflags FL MASK], ... , ...") \ +_(acl_del, "") \ +_(acl_dump, "[]") \ +_(acl_interface_add_del, " | sw_if_index [add|del] [input|output] acl ") \ +_(acl_interface_set_acl_list, " | sw_if_index input [acl-idx list] output [acl-idx list]") \ +_(acl_interface_list_dump, "[ | sw_if_index ]") \ +_(macip_acl_add, "...") \ +_(macip_acl_del, "")\ +_(macip_acl_dump, "[]") \ +_(macip_acl_interface_add_del, " | sw_if_index [add|del] acl ") \ +_(macip_acl_interface_get, "") + + + +void vat_api_hookup (vat_main_t *vam) +{ + acl_test_main_t * sm = &acl_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) +{ + acl_test_main_t * sm = &acl_test_main; + u8 * name; + + sm->vat_main = vam; + + name = format (0, "acl_%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/src/plugins/acl/l2sess.c b/src/plugins/acl/l2sess.c new file mode 100644 index 00000000..cc9bde44 --- /dev/null +++ b/src/plugins/acl/l2sess.c @@ -0,0 +1,243 @@ +/* + * 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. + */ +/* + *------------------------------------------------------------------ + * l2sess.c - simple MAC-swap API / debug CLI handling + *------------------------------------------------------------------ + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +void +l2sess_vlib_plugin_register (vlib_main_t * vm, void* hh, + int from_early_init) +{ + l2sess_main_t *sm = &l2sess_main; + vnet_plugin_handoff_t * h = hh; + memset (sm, 0, sizeof (*sm)); + + sm->vlib_main = vm; + sm->vnet_main = h->vnet_main; + sm->ethernet_main = h->ethernet_main; +} + +void +l2sess_init_next_features_input (vlib_main_t * vm, l2sess_main_t * sm) +{ +#define _(node_name, node_var, is_out, is_ip6, is_track) \ + if (!is_out) feat_bitmap_init_next_nodes(vm, node_var.index, L2INPUT_N_FEAT, l2input_get_feat_names (), sm->node_var ## _input_next_node_index); + foreach_l2sess_node +#undef _ +} + +void +l2sess_add_our_next_nodes (vlib_main_t * vm, l2sess_main_t * sm, + u8 * prev_node_name, int add_output_nodes) +{ + vlib_node_t *n; + n = vlib_get_node_by_name (vm, prev_node_name); +#define _(node_name, node_var, is_out, is_ip6, is_track) \ + if (is_out == add_output_nodes) { \ + u32 idx = vlib_node_add_next_with_slot(vm, n->index, node_var.index, ~0); \ + if (is_track) { \ + sm->next_slot_track_node_by_is_ip6_is_out[is_ip6][is_out] = idx; \ + } \ + } + foreach_l2sess_node +#undef _ +} + +void +l2sess_setup_nodes (void) +{ + vlib_main_t *vm = vlib_get_main (); + l2sess_main_t *sm = &l2sess_main; + + l2sess_init_next_features_input (vm, sm); + + l2sess_add_our_next_nodes (vm, sm, (u8 *) "l2-input-classify", 0); + l2sess_add_our_next_nodes (vm, sm, (u8 *) "l2-output-classify", 1); + +} + +static char * +get_l4_proto_str (int is_ip6, uint8_t l4_proto) +{ + switch (l4_proto) + { + case 6: + return "tcp"; + case 17: + return "udp"; + case 1: + return "icmp"; + case 58: + return "icmp6"; + default: + return ""; + } +} + +static clib_error_t * +l2sess_show_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + l2sess_main_t *sm = &l2sess_main; + clib_time_t *ct = &vm->clib_time; + l2s_session_t *s; + u64 now = clib_cpu_time_now (); + + vlib_cli_output (vm, "Timing wheel info: \n%U", format_timing_wheel, + &sm->timing_wheel, 255); + + pool_foreach (s, sm->sessions, ( + { + f64 ctime = + (now - + s->create_time) * ct->seconds_per_clock; + f64 atime0 = + (now - + s->side[0].active_time) * + ct->seconds_per_clock; + f64 atime1 = + (now - + s->side[1].active_time) * + ct->seconds_per_clock; +/* + f64 ctime = (s->create_time - vm->cpu_time_main_loop_start) * ct->seconds_per_clock; + f64 atime0 = (s->side[0].active_time - vm->cpu_time_main_loop_start) * ct->seconds_per_clock; + f64 atime1 = (s->side[1].active_time - vm->cpu_time_main_loop_start) * ct->seconds_per_clock; +*/ + u8 * out0 = + format (0, + "%5d: create time: %U pkts/bytes/active time: [ %ld %ld %U : %ld %ld %U ]\n", + (s - sm->sessions), + format_time_interval, "h:m:s:u", + ctime, s->side[0].n_packets, + s->side[0].n_bytes, + format_time_interval, "h:m:s:u", + atime0, s->side[1].n_packets, + s->side[1].n_bytes, + format_time_interval, "h:m:s:u", + atime1); u8 * out1 = 0; + if (s->is_ip6) + { + out1 = + format (0, "%s %U :%u <-> %U :%u", + get_l4_proto_str (s->is_ip6, + s->l4_proto), + format_ip6_address, + &s->side[0].addr.ip6, + s->side[0].port, + format_ip6_address, + &s->side[1].addr.ip6, + s->side[1].port);} + else + { + out1 = + format (0, "%s %U :%u <-> %U :%u", + get_l4_proto_str (s->is_ip6, + s->l4_proto), + format_ip4_address, + &s->side[0].addr.ip4, + s->side[0].port, + format_ip4_address, + &s->side[1].addr.ip4, + s->side[1].port);} + vlib_cli_output (vm, "%s %s", out0, + out1); vec_free (out0); + vec_free (out1);} + )); + return 0; +} + +static clib_error_t * +l2sess_show_count_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + l2sess_main_t *sm = &l2sess_main; + + vlib_cli_output (vm, "Timing wheel info: \n%U", format_timing_wheel, + &sm->timing_wheel, 255); + vlib_cli_output (vm, "session pool len: %d, pool elts: %d", + pool_len (sm->sessions), pool_elts (sm->sessions)); + vlib_cli_output (vm, + "attempted to delete sessions which were already free: %d", + sm->counter_attempted_delete_free_session); + return 0; +} + + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (l2sess_show_command, static) = { + .path = "show l2sess", + .short_help = "show l2sess", + .function = l2sess_show_command_fn, +}; + +VLIB_CLI_COMMAND (l2sess_show_count_command, static) = { + .path = "show l2sess count", + .short_help = "show l2sess count", + .function = l2sess_show_count_command_fn, +}; +/* *INDENT-OFF* */ + +static inline u64 +time_sec_to_clock( clib_time_t *ct, f64 sec) +{ + return (u64)(((f64)sec)/ct->seconds_per_clock); +} + +static clib_error_t * l2sess_init (vlib_main_t * vm) +{ + l2sess_main_t * sm = &l2sess_main; + clib_error_t * error = 0; + u64 cpu_time_now = clib_cpu_time_now(); + + + clib_time_t *ct = &vm->clib_time; + sm->udp_session_idle_timeout = time_sec_to_clock(ct, UDP_SESSION_IDLE_TIMEOUT_SEC); + sm->tcp_session_idle_timeout = time_sec_to_clock(ct, TCP_SESSION_IDLE_TIMEOUT_SEC); + sm->tcp_session_transient_timeout = time_sec_to_clock(ct, TCP_SESSION_TRANSIENT_TIMEOUT_SEC); + + /* The min sched time of 10e-1 causes erroneous behavior... */ + sm->timing_wheel.min_sched_time = 10e-2; + sm->timing_wheel.max_sched_time = 3600.0*48.0; + timing_wheel_init (&sm->timing_wheel, cpu_time_now, vm->clib_time.clocks_per_second); + sm->timer_wheel_next_expiring_time = 0; + sm->timer_wheel_tick = time_sec_to_clock(ct, sm->timing_wheel.min_sched_time); + /* Pre-allocate expired nodes. */ + vec_alloc (sm->data_from_advancing_timing_wheel, 32); + + l2sess_setup_nodes(); + l2output_init_output_node_vec (&sm->output_next_nodes.output_node_index_vec); + + return error; +} + +VLIB_INIT_FUNCTION (l2sess_init); + + diff --git a/src/plugins/acl/l2sess.h b/src/plugins/acl/l2sess.h new file mode 100644 index 00000000..db899917 --- /dev/null +++ b/src/plugins/acl/l2sess.h @@ -0,0 +1,150 @@ +/* + * 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. + */ +#ifndef __included_l2sess_h__ +#define __included_l2sess_h__ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#define _(node_name, node_var, is_out, is_ip6, is_track) +#undef _ +#define foreach_l2sess_node \ + _("aclp-l2s-input-ip4-add", l2sess_in_ip4_add, 0, 0, 0) \ + _("aclp-l2s-input-ip6-add", l2sess_in_ip6_add, 0, 1, 0) \ + _("aclp-l2s-output-ip4-add", l2sess_out_ip4_add, 1, 0, 0) \ + _("aclp-l2s-output-ip6-add", l2sess_out_ip6_add, 1, 1, 0) \ + _("aclp-l2s-input-ip4-track", l2sess_in_ip4_track, 0, 0, 1) \ + _("aclp-l2s-input-ip6-track", l2sess_in_ip6_track, 0, 1, 1) \ + _("aclp-l2s-output-ip4-track",l2sess_out_ip4_track, 1, 0, 1) \ + _("aclp-l2s-output-ip6-track", l2sess_out_ip6_track, 1, 1, 1) + +#define _(node_name, node_var, is_out, is_ip6, is_track) \ + extern vlib_node_registration_t node_var; +foreach_l2sess_node +#undef _ + +#define TCP_FLAG_FIN 0x01 +#define TCP_FLAG_SYN 0x02 +#define TCP_FLAG_RST 0x04 +#define TCP_FLAG_PUSH 0x08 +#define TCP_FLAG_ACK 0x10 +#define TCP_FLAG_URG 0x20 +#define TCP_FLAG_ECE 0x40 +#define TCP_FLAG_CWR 0x80 +#define TCP_FLAGS_RSTFINACKSYN (TCP_FLAG_RST + TCP_FLAG_FIN + TCP_FLAG_SYN + TCP_FLAG_ACK) +#define TCP_FLAGS_ACKSYN (TCP_FLAG_SYN + TCP_FLAG_ACK) + +typedef struct { + ip46_address_t addr; + u64 active_time; + u64 n_packets; + u64 n_bytes; + u16 port; +} l2s_session_side_t; + +enum { + L2S_SESSION_SIDE_IN = 0, + L2S_SESSION_SIDE_OUT, + L2S_N_SESSION_SIDES +}; + +typedef struct { + u64 create_time; + l2s_session_side_t side[L2S_N_SESSION_SIDES]; + u8 l4_proto; + u8 is_ip6; + u16 tcp_flags_seen; /* u16 because of two sides */ +} l2s_session_t; + +#define PROD +#ifdef PROD +#define UDP_SESSION_IDLE_TIMEOUT_SEC 600 +#define TCP_SESSION_IDLE_TIMEOUT_SEC (3600*24) +#define TCP_SESSION_TRANSIENT_TIMEOUT_SEC 120 +#else +#define UDP_SESSION_IDLE_TIMEOUT_SEC 15 +#define TCP_SESSION_IDLE_TIMEOUT_SEC 15 +#define TCP_SESSION_TRANSIENT_TIMEOUT_SEC 5 +#endif + +typedef struct { + /* + * the next two fields are present for all nodes, but + * only one of them is used per node - depending + * on whether the node is an input or output one. + */ +#define _(node_name, node_var, is_out, is_ip6, is_track) \ + u32 node_var ## _input_next_node_index[32]; \ + l2_output_next_nodes_st node_var ## _next_nodes; +foreach_l2sess_node +#undef _ + l2_output_next_nodes_st output_next_nodes; + + /* Next indices of the tracker nodes */ + u32 next_slot_track_node_by_is_ip6_is_out[2][2]; + + /* + * Pairing of "forward" and "reverse" tables by table index. + * Each relationship has two entries - for one and the other table, + * so it is bidirectional. + */ + + u32 *fwd_to_rev_by_table_index; + + /* + * The vector of per-interface session pools + */ + + l2s_session_t *sessions; + + /* The session timeouts */ + u64 tcp_session_transient_timeout; + u64 tcp_session_idle_timeout; + u64 udp_session_idle_timeout; + + /* Timing wheel to time out the idle sessions */ + timing_wheel_t timing_wheel; + u32 *data_from_advancing_timing_wheel; + u64 timer_wheel_next_expiring_time; + u64 timer_wheel_tick; + + /* convenience */ + vlib_main_t * vlib_main; + vnet_main_t * vnet_main; + ethernet_main_t * ethernet_main; + + /* Counter(s) */ + u64 counter_attempted_delete_free_session; +} l2sess_main_t; + +l2sess_main_t l2sess_main; + +/* Just exposed for acl.c */ + +void +l2sess_vlib_plugin_register (vlib_main_t * vm, void * hh, + int from_early_init); + + +#endif /* __included_l2sess_h__ */ diff --git a/src/plugins/acl/l2sess_node.c b/src/plugins/acl/l2sess_node.c new file mode 100644 index 00000000..520e5929 --- /dev/null +++ b/src/plugins/acl/l2sess_node.c @@ -0,0 +1,816 @@ +/* + * 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. + */ +#include +#include +#include +#include +#include +#include +#include + + +typedef struct +{ + u32 next_index; + u32 sw_if_index; + u32 trace_flags; + u32 session_tables[2]; + u32 session_nexts[2]; + u8 l4_proto; +} l2sess_trace_t; + +/* packet trace format function */ + +#define _(node_name, node_var, is_out, is_ip6, is_track) \ +static u8 * format_## node_var ##_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 *); \ + l2sess_trace_t * t = va_arg (*args, l2sess_trace_t *); \ + \ + s = format (s, node_name ": sw_if_index %d, next index %d trace_flags %08x L4 proto %d\n" \ + " tables [ %d, %d ] nexts [ %d, %d ]", \ + t->sw_if_index, t->next_index, t->trace_flags, t->l4_proto, \ + t->session_tables[0], t->session_tables[1], \ + t->session_nexts[0], t->session_nexts[1]); \ + return s; \ +} +foreach_l2sess_node +#undef _ +#define foreach_l2sess_error \ +_(SWAPPED, "Mac swap packets processed") + typedef enum +{ +#define _(sym,str) L2SESS_ERROR_##sym, + foreach_l2sess_error +#undef _ + L2SESS_N_ERROR, +} l2sess_error_t; + +static char *l2sess_error_strings[] = { +#define _(sym,string) string, + foreach_l2sess_error +#undef _ +}; + +typedef enum +{ + L2SESS_NEXT_DROP, + L2SESS_N_NEXT, +} l2sess_next_t; + +u8 +l2sess_get_l4_proto (vlib_buffer_t * b0, int node_is_ip6) +{ + u8 proto; + int proto_offset; + if (node_is_ip6) + { + proto_offset = 20; + } + else + { + proto_offset = 23; + } + proto = *((u8 *) vlib_buffer_get_current (b0) + proto_offset); + return proto; +} + + +u8 +l2sess_get_tcp_flags (vlib_buffer_t * b0, int node_is_ip6) +{ + u8 flags; + int flags_offset; + if (node_is_ip6) + { + flags_offset = 14 + 40 + 13; /* FIXME: no extension headers assumed */ + } + else + { + flags_offset = 14 + 20 + 13; + } + flags = *((u8 *) vlib_buffer_get_current (b0) + flags_offset); + return flags; +} + +static inline int +l4_tcp_or_udp (u8 proto) +{ + return ((proto == 6) || (proto == 17)); +} + +void +l2sess_get_session_tables (l2sess_main_t * sm, u32 sw_if_index, + int node_is_out, int node_is_ip6, u8 l4_proto, + u32 * session_tables) +{ +/* + * Based on the direction, l3 and l4 protocol, fill a u32[2] array: + * [0] is index for the "direct match" path, [1] is for "mirrored match". + * Store the indices of the tables to add the session to in session_tables[] + */ + l2_output_classify_main_t *l2om = &l2_output_classify_main; + l2_input_classify_main_t *l2im = &l2_input_classify_main; + + u32 output_table_index; + u32 input_table_index; + + if (!l4_tcp_or_udp (l4_proto)) + { + return; + } + + if (node_is_ip6) + { + vec_validate_init_empty (l2im-> + classify_table_index_by_sw_if_index + [L2_INPUT_CLASSIFY_TABLE_IP6], sw_if_index, + ~0); + input_table_index = + l2im-> + classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP6] + [sw_if_index]; + vec_validate_init_empty (l2om-> + classify_table_index_by_sw_if_index + [L2_OUTPUT_CLASSIFY_TABLE_IP6], sw_if_index, + ~0); + output_table_index = + l2om-> + classify_table_index_by_sw_if_index[L2_OUTPUT_CLASSIFY_TABLE_IP6] + [sw_if_index]; + } + else + { + vec_validate_init_empty (l2im-> + classify_table_index_by_sw_if_index + [L2_INPUT_CLASSIFY_TABLE_IP4], sw_if_index, + ~0); + input_table_index = + l2im-> + classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP4] + [sw_if_index]; + vec_validate_init_empty (l2om-> + classify_table_index_by_sw_if_index + [L2_OUTPUT_CLASSIFY_TABLE_IP4], sw_if_index, + ~0); + output_table_index = + l2om-> + classify_table_index_by_sw_if_index[L2_OUTPUT_CLASSIFY_TABLE_IP4] + [sw_if_index]; + } + + if (node_is_out) + { + session_tables[0] = output_table_index; + session_tables[1] = input_table_index; + } + else + { + session_tables[0] = input_table_index; + session_tables[1] = output_table_index; + } +} + +void +l2sess_get_session_nexts (l2sess_main_t * sm, u32 sw_if_index, + int node_is_out, int node_is_ip6, u8 l4_proto, + u32 * session_nexts) +{ +/* + * Based on the direction, l3 and l4 protocol, fill a u32[2] array: + * [0] is the index for the "direct match" path, [1] is for "mirrored match". + * Store the match_next_index in session_nexts[] for a new session entry which is being added to session tables. + */ + u32 input_node_index; + u32 output_node_index; + + if (!l4_tcp_or_udp (l4_proto)) + { + return; + } + + input_node_index = + sm->next_slot_track_node_by_is_ip6_is_out[node_is_ip6][0]; + output_node_index = + sm->next_slot_track_node_by_is_ip6_is_out[node_is_ip6][1]; + + if (node_is_out) + { + session_nexts[0] = output_node_index; + session_nexts[1] = input_node_index; + } + else + { + session_nexts[0] = input_node_index; + session_nexts[1] = output_node_index; + } +} + + +static inline void +swap_bytes (vlib_buffer_t * b0, int off_a, int off_b, int nbytes) +{ + u8 tmp; + u8 *pa = vlib_buffer_get_current (b0) + off_a; + u8 *pb = vlib_buffer_get_current (b0) + off_b; + while (nbytes--) + { + tmp = *pa; + *pa++ = *pb; + *pb++ = tmp; + } +} + +/* + * This quite pro[bv]ably is a terrible idea performance wise. Moreso doing it twice. + * Would having a long (ish) chunk of memory work better for this ? + * We will see when we get to the performance of this. + */ +void +l2sess_flip_l3l4_fields (vlib_buffer_t * b0, int node_is_ip6, u8 l4_proto) +{ + if (!l4_tcp_or_udp (l4_proto)) + { + return; + } + if (node_is_ip6) + { + swap_bytes (b0, 22, 38, 16); /* L3 */ + swap_bytes (b0, 54, 56, 2); /* L4 (when no EH!) */ + } + else + { + swap_bytes (b0, 26, 30, 4); /* L3 */ + swap_bytes (b0, 34, 36, 2); /* L4 */ + } +} + +void +l2sess_add_session (vlib_buffer_t * b0, int node_is_out, int node_is_ip6, + u32 session_table, u32 session_match_next, + u32 opaque_index) +{ + vnet_classify_main_t *cm = &vnet_classify_main; + u32 action = 0; + u32 metadata = 0; + +#ifdef DEBUG_SESSIONS + printf ("Adding session to table %d with next %d\n", session_table, + session_match_next); +#endif + vnet_classify_add_del_session (cm, session_table, + vlib_buffer_get_current (b0), + session_match_next, opaque_index, 0, action, + metadata, 1); +} + + + +static void * +get_ptr_to_offset (vlib_buffer_t * b0, int offset) +{ + u8 *p = vlib_buffer_get_current (b0) + offset; + return p; +} + + +/* + * FIXME: Hardcoded offsets are ugly, although if casting to structs one + * would need to take care about alignment.. So let's for now be naive and simple. + */ + +void +session_store_ip4_l3l4_info (vlib_buffer_t * b0, l2s_session_t * sess, + int node_is_out) +{ + clib_memcpy (&sess->side[1 - node_is_out].addr.ip4, + get_ptr_to_offset (b0, 26), 4); + clib_memcpy (&sess->side[node_is_out].addr.ip4, get_ptr_to_offset (b0, 30), + 4); + sess->side[1 - node_is_out].port = + ntohs (*(u16 *) get_ptr_to_offset (b0, 34)); + sess->side[node_is_out].port = ntohs (*(u16 *) get_ptr_to_offset (b0, 36)); +} + +void +session_store_ip6_l3l4_info (vlib_buffer_t * b0, l2s_session_t * sess, + int node_is_out) +{ + clib_memcpy (&sess->side[1 - node_is_out].addr.ip6, + get_ptr_to_offset (b0, 22), 16); + clib_memcpy (&sess->side[node_is_out].addr.ip4, get_ptr_to_offset (b0, 38), + 16); + sess->side[1 - node_is_out].port = + ntohs (*(u16 *) get_ptr_to_offset (b0, 54)); + sess->side[node_is_out].port = ntohs (*(u16 *) get_ptr_to_offset (b0, 56)); +} + +static void +build_match_from_session (l2sess_main_t * sm, u8 * match, + l2s_session_t * sess, int is_out) +{ + if (sess->is_ip6) + { + match[20] = sess->l4_proto; + clib_memcpy (&match[22], &sess->side[1 - is_out].addr.ip6, 16); + clib_memcpy (&match[38], &sess->side[is_out].addr.ip4, 16); + *(u16 *) & match[54] = htons (sess->side[1 - is_out].port); + *(u16 *) & match[56] = htons (sess->side[is_out].port); + } + else + { + match[23] = sess->l4_proto; + clib_memcpy (&match[26], &sess->side[1 - is_out].addr.ip6, 4); + clib_memcpy (&match[30], &sess->side[is_out].addr.ip4, 4); + *(u16 *) & match[34] = htons (sess->side[1 - is_out].port); + *(u16 *) & match[36] = htons (sess->side[is_out].port); + } +} + +static void +delete_session (l2sess_main_t * sm, u32 sw_if_index, u32 session_index) +{ + vnet_classify_main_t *cm = &vnet_classify_main; + u8 match[5 * 16]; /* For building the mock of the packet to delete the classifier session */ + u32 session_tables[2] = { ~0, ~0 }; + l2s_session_t *sess = sm->sessions + session_index; + if (pool_is_free (sm->sessions, sess)) + { + sm->counter_attempted_delete_free_session++; + return; + } + l2sess_get_session_tables (sm, sw_if_index, 0, sess->is_ip6, sess->l4_proto, + session_tables); + if (session_tables[1] != ~0) + { + build_match_from_session (sm, match, sess, 1); + vnet_classify_add_del_session (cm, session_tables[1], match, 0, 0, 0, 0, + 0, 0); + } + if (session_tables[1] != ~0) + { + build_match_from_session (sm, match, sess, 1); + vnet_classify_add_del_session (cm, session_tables[1], match, 0, 0, 0, 0, + 0, 0); + } + pool_put (sm->sessions, sess); +} + +static void +udp_session_account_buffer (vlib_buffer_t * b0, l2s_session_t * s, + int which_side, u64 now) +{ + l2s_session_side_t *ss = &s->side[which_side]; + ss->active_time = now; + ss->n_packets++; + ss->n_bytes += b0->current_data + b0->current_length; +} + +static inline u64 +udp_session_get_timeout (l2sess_main_t * sm, l2s_session_t * sess, u64 now) +{ + return (sm->udp_session_idle_timeout); +} + +static void +tcp_session_account_buffer (vlib_buffer_t * b0, l2s_session_t * s, + int which_side, u64 now) +{ + l2s_session_side_t *ss = &s->side[which_side]; + ss->active_time = now; + ss->n_packets++; + ss->n_bytes += b0->current_data + b0->current_length; + /* Very very lightweight TCP state tracking: just record which flags were seen */ + s->tcp_flags_seen |= + l2sess_get_tcp_flags (b0, s->is_ip6) << (8 * which_side); +} + +/* + * Since we are tracking for the purposes of timing the sessions out, + * we mostly care about two states: established (maximize the idle timeouts) + * and transient (halfopen/halfclosed/reset) - we need to have a reasonably short timeout to + * quickly get rid of sessions but not short enough to violate the TCP specs. + */ + +static inline u64 +tcp_session_get_timeout (l2sess_main_t * sm, l2s_session_t * sess, u64 now) +{ + /* seen both SYNs and ACKs but not FINs means we are in establshed state */ + u16 masked_flags = + sess->tcp_flags_seen & ((TCP_FLAGS_RSTFINACKSYN << 8) + + TCP_FLAGS_RSTFINACKSYN); + if (((TCP_FLAGS_ACKSYN << 8) + TCP_FLAGS_ACKSYN) == masked_flags) + { + return (sm->tcp_session_idle_timeout); + } + else + { + return (sm->tcp_session_transient_timeout); + } +} + +static inline u64 +session_get_timeout (l2sess_main_t * sm, l2s_session_t * sess, u64 now) +{ + u64 timeout; + + switch (sess->l4_proto) + { + case 6: + timeout = tcp_session_get_timeout (sm, sess, now); + break; + case 17: + timeout = udp_session_get_timeout (sm, sess, now); + break; + default: + timeout = 0; + } + + return timeout; +} + +static inline u64 +get_session_last_active_time(l2s_session_t * sess) +{ + u64 last_active = + sess->side[0].active_time > + sess->side[1].active_time ? sess->side[0].active_time : sess->side[1]. + active_time; + return last_active; +} + +static int +session_is_alive (l2sess_main_t * sm, l2s_session_t * sess, u64 now, u64 *last_active_cache) +{ + u64 last_active = get_session_last_active_time(sess); + u64 timeout = session_get_timeout (sm, sess, now); + int is_alive = ((now - last_active) < timeout); + if (last_active_cache) + *last_active_cache = last_active; + return is_alive; +} + +static void +check_idle_sessions (l2sess_main_t * sm, u32 sw_if_index, u64 now) +{ + sm->timer_wheel_next_expiring_time = 0; + sm->data_from_advancing_timing_wheel + = + timing_wheel_advance (&sm->timing_wheel, now, + sm->data_from_advancing_timing_wheel, + &sm->timer_wheel_next_expiring_time); +#ifdef DEBUG_SESSIONS_VERBOSE + { + clib_time_t *ct = &sm->vlib_main->clib_time; + f64 ctime; + ctime = now * ct->seconds_per_clock; + clib_warning ("Now : %U", format_time_interval, "h:m:s:u", ctime); + ctime = sm->timer_wheel_next_expiring_time * ct->seconds_per_clock; + clib_warning ("Next expire: %U", format_time_interval, "h:m:s:u", ctime); + clib_warning ("Expired items: %d", + (int) vec_len (sm->data_from_advancing_timing_wheel)); + } +#endif + + sm->timer_wheel_next_expiring_time = now + sm->timer_wheel_tick; + if (PREDICT_FALSE ( 0 == sm->data_from_advancing_timing_wheel )) { + return; + } + + if (PREDICT_FALSE (_vec_len (sm->data_from_advancing_timing_wheel) > 0)) + { + uword i; + for (i = 0; i < _vec_len (sm->data_from_advancing_timing_wheel); i++) + { + u32 session_index = sm->data_from_advancing_timing_wheel[i]; + if (!pool_is_free_index (sm->sessions, session_index)) + { + l2s_session_t *sess = sm->sessions + session_index; + u64 last_active; + if (session_is_alive (sm, sess, now, &last_active)) + { +#ifdef DEBUG_SESSIONS + clib_warning ("Restarting timer for session %d", (int) session_index); +#endif + /* Pretend we did this in the past, at last_active moment */ + timing_wheel_insert (&sm->timing_wheel, + last_active + session_get_timeout (sm, sess, + last_active), + session_index); + } + else + { +#ifdef DEBUG_SESSIONS + clib_warning ("Deleting session %d", (int) session_index); +#endif + delete_session (sm, sw_if_index, session_index); + } + } + } + _vec_len (sm->data_from_advancing_timing_wheel) = 0; + } +} + +static uword +l2sess_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + l2sess_next_t next_index; + u32 pkts_swapped = 0; + u32 cached_sw_if_index = (u32) ~ 0; + u32 cached_next_index = (u32) ~ 0; + u32 feature_bitmap0; + u32 trace_flags0; + + l2sess_main_t *sm = &l2sess_main; + + 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); + + /* Only a single loop for now for simplicity */ + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0 = L2SESS_NEXT_DROP; + u32 sw_if_index0; + //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); + //en0 = vlib_buffer_get_current (b0); + +/* + * The non-boilerplate is in the block below. + * Note first a magic macro block that sets up the behavior qualifiers: + * node_is_out : 1 = is output, 0 = is input + * node_is_ip6 : 1 = is ip6, 0 = is ip4 + * node_is_track : 1 = is a state tracking node, 0 - is a session addition node + * + * Subsequently the code adjusts its behavior depending on these variables. + * It's most probably not great performance wise but much easier to work with. + * + */ + { + int node_is_out = -1; + CLIB_UNUSED (int node_is_ip6) = -1; + CLIB_UNUSED (int node_is_track) = -1; + u32 node_index = 0; + u32 session_tables[2] = { ~0, ~0 }; + u32 session_nexts[2] = { ~0, ~0 }; + l2_output_next_nodes_st *next_nodes = 0; + u32 *input_feat_next_node_index; + u8 l4_proto; + u64 now = clib_cpu_time_now (); + +/* + * Set the variables according to which of the 8 nodes we are. + * Hopefully the compiler is smart enough to eliminate the extraneous. + */ +#define _(node_name, node_var, is_out, is_ip6, is_track) \ +if(node_var.index == node->node_index) \ + { \ + node_is_out = is_out; \ + node_is_ip6 = is_ip6; \ + node_is_track = is_track; \ + node_index = node_var.index; \ + next_nodes = &sm->node_var ## _next_nodes; \ + input_feat_next_node_index = sm->node_var ## _input_next_node_index; \ + } + foreach_l2sess_node +#undef _ + trace_flags0 = 0; + if (node_is_out) + { + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + } + else + { + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + } + /* potentially also remove the nodes here */ + feature_bitmap0 = vnet_buffer (b0)->l2.feature_bitmap; + + if (node_is_track) + { + u32 sess_index = vnet_buffer (b0)->l2_classify.opaque_index; + l2s_session_t *sess = sm->sessions + sess_index; + l4_proto = sess->l4_proto; + + if (session_is_alive (sm, sess, now, 0)) + { + if (6 == l4_proto) + { + tcp_session_account_buffer (b0, sess, node_is_out, + now); + } + else + { + udp_session_account_buffer (b0, sess, node_is_out, + now); + } + } + else + { + timing_wheel_delete (&sm->timing_wheel, sess_index); + delete_session (sm, sw_if_index0, sess_index); + /* FIXME: drop the packet that hit the obsolete node, for now. We really ought to recycle it. */ + next0 = 0; + } + } + else + { + /* + * "-add" node: take l2opaque which arrived to us, and deduce + * the tables out of that. ~0 means the topmost classifier table + * applied for this AF on the RX(for input)/TX(for output)) sw_if_index. + * Also add the mirrored session to the paired table. + */ + l2s_session_t *sess; + u32 sess_index; + + l4_proto = l2sess_get_l4_proto (b0, node_is_ip6); + + pool_get (sm->sessions, sess); + sess_index = sess - sm->sessions; + sess->create_time = now; + sess->side[node_is_out].active_time = now; + sess->side[1 - node_is_out].active_time = now; + sess->l4_proto = l4_proto; + sess->is_ip6 = node_is_ip6; + if (node_is_ip6) + { + session_store_ip6_l3l4_info (b0, sess, node_is_out); + } + else + { + session_store_ip4_l3l4_info (b0, sess, node_is_out); + } + + l2sess_get_session_tables (sm, sw_if_index0, node_is_out, + node_is_ip6, l4_proto, + session_tables); + l2sess_get_session_nexts (sm, sw_if_index0, node_is_out, + node_is_ip6, l4_proto, + session_nexts); + l2sess_flip_l3l4_fields (b0, node_is_ip6, l4_proto); + if (session_tables[1] != ~0) + { + l2sess_add_session (b0, node_is_out, node_is_ip6, + session_tables[1], session_nexts[1], + sess_index); + } + l2sess_flip_l3l4_fields (b0, node_is_ip6, l4_proto); + if (session_tables[0] != ~0) + { + l2sess_add_session (b0, node_is_out, node_is_ip6, + session_tables[0], session_nexts[0], + sess_index); + } + if (6 == sess->l4_proto) + { + tcp_session_account_buffer (b0, sess, node_is_out, now); + } + else + { + udp_session_account_buffer (b0, sess, node_is_out, now); + } + timing_wheel_insert (&sm->timing_wheel, + now + session_get_timeout (sm, sess, + now), + sess_index); + } + + if (now >= sm->timer_wheel_next_expiring_time) + { + check_idle_sessions (sm, sw_if_index0, now); + } + + if (node_is_out) + { + if (feature_bitmap0) + { + trace_flags0 |= 0x10; + } + if (sw_if_index0 == cached_sw_if_index) + { + trace_flags0 |= 0x20; + } + l2_output_dispatch (sm->vlib_main, + sm->vnet_main, + node, + node_index, + &cached_sw_if_index, + &cached_next_index, + next_nodes, + b0, sw_if_index0, feature_bitmap0, + &next0); + trace_flags0 |= 2; + + } + else + { + next0 = + feat_bitmap_get_next_node_index (input_feat_next_node_index, + feature_bitmap0); + trace_flags0 |= 4; + + } + + + + if (next0 >= node->n_next_nodes) + { + trace_flags0 |= 1; + } + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + l2sess_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + t->next_index = next0; + t->trace_flags = trace_flags0; + t->l4_proto = l4_proto; + t->session_tables[0] = session_tables[0]; + t->session_tables[1] = session_tables[1]; + t->session_nexts[0] = session_nexts[0]; + t->session_nexts[1] = session_nexts[1]; + } + + } + pkts_swapped += 1; + if (next0 >= node->n_next_nodes) + { + next0 = 0; + } + + /* 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, node->node_index, + L2SESS_ERROR_SWAPPED, pkts_swapped); + return frame->n_vectors; +} + + +#define _(node_name, node_var, is_out, is_ip6, is_track) \ +static uword \ +node_var ## node_fn (vlib_main_t * vm, \ + vlib_node_runtime_t * node, \ + vlib_frame_t * frame) \ +{ \ + return l2sess_node_fn(vm, node, frame); \ +} \ +VLIB_REGISTER_NODE (node_var) = { \ + .function = node_var ## node_fn, \ + .name = node_name, \ + .vector_size = sizeof (u32), \ + .format_trace = format_ ## node_var ## _trace, \ + .type = VLIB_NODE_TYPE_INTERNAL, \ + \ + .n_errors = ARRAY_LEN(l2sess_error_strings), \ + .error_strings = l2sess_error_strings, \ + \ + .n_next_nodes = L2SESS_N_NEXT, \ + .next_nodes = { \ + [L2SESS_NEXT_DROP] = "error-drop", \ + }, \ +}; +foreach_l2sess_node +#undef _ diff --git a/src/plugins/acl/node_in.c b/src/plugins/acl/node_in.c new file mode 100644 index 00000000..2a5199a9 --- /dev/null +++ b/src/plugins/acl/node_in.c @@ -0,0 +1,168 @@ +/* + * 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. + */ +#include +#include +#include +#include +#include +#include "node_in.h" + +typedef struct +{ + u32 next_index; + u32 sw_if_index; + u32 match_acl_index; + u32 match_rule_index; + u32 trace_bitmap; +} acl_in_trace_t; + +/* packet trace format function */ +static u8 * +format_acl_in_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 *); + acl_in_trace_t *t = va_arg (*args, acl_in_trace_t *); + + s = + format (s, + "ACL_IN: sw_if_index %d, next index %d, match: inacl %d rule %d trace_bits %08x", + t->sw_if_index, t->next_index, t->match_acl_index, + t->match_rule_index, t->trace_bitmap); + return s; +} + +vlib_node_registration_t acl_in_node; + +#define foreach_acl_in_error \ +_(ACL_CHECK, "InACL check packets processed") + +typedef enum +{ +#define _(sym,str) ACL_IN_ERROR_##sym, + foreach_acl_in_error +#undef _ + ACL_IN_N_ERROR, +} acl_in_error_t; + +static char *acl_in_error_strings[] = { +#define _(sym,string) string, + foreach_acl_in_error +#undef _ +}; + +static uword +acl_in_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + acl_in_next_t next_index; + u32 pkts_acl_checked = 0; + u32 feature_bitmap0; + u32 trace_bitmap = 0; + u32 *input_feat_next_node_index = + acl_main.acl_in_node_input_next_node_index; + + 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 > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0 = ~0; + u32 sw_if_index0; + u32 next = ~0; + u32 match_acl_index = ~0; + u32 match_rule_index = ~0; + + /* 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); + + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + feature_bitmap0 = vnet_buffer (b0)->l2.feature_bitmap; + + input_acl_packet_match (sw_if_index0, b0, &next, &match_acl_index, + &match_rule_index, &trace_bitmap); + if (next != ~0) + { + next0 = next; + } + if (next0 == ~0) + { + next0 = + feat_bitmap_get_next_node_index (input_feat_next_node_index, + feature_bitmap0); + } + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + acl_in_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + t->next_index = next0; + t->match_acl_index = match_acl_index; + t->match_rule_index = match_rule_index; + t->trace_bitmap = trace_bitmap; + } + + next0 = next0 < node->n_next_nodes ? next0 : 0; + + pkts_acl_checked += 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, acl_in_node.index, + ACL_IN_ERROR_ACL_CHECK, pkts_acl_checked); + return frame->n_vectors; +} + +VLIB_REGISTER_NODE (acl_in_node) = +{ + .function = acl_in_node_fn,.name = "acl-plugin-in",.vector_size = + sizeof (u32),.format_trace = format_acl_in_trace,.type = + VLIB_NODE_TYPE_INTERNAL,.n_errors = + ARRAY_LEN (acl_in_error_strings),.error_strings = + acl_in_error_strings,.n_next_nodes = ACL_IN_N_NEXT, + /* edit / add dispositions here */ + .next_nodes = + { + [ACL_IN_ERROR_DROP] = "error-drop", + [ACL_IN_ETHERNET_INPUT] = "ethernet-input", + [ACL_IN_L2S_INPUT_IP4_ADD] = "aclp-l2s-input-ip4-add", + [ACL_IN_L2S_INPUT_IP6_ADD] = "aclp-l2s-input-ip6-add",} +,}; diff --git a/src/plugins/acl/node_in.h b/src/plugins/acl/node_in.h new file mode 100644 index 00000000..502bbf8d --- /dev/null +++ b/src/plugins/acl/node_in.h @@ -0,0 +1,12 @@ +#ifndef _NODE_IN_H_ +#define _NODE_IN_H_ + +typedef enum { + ACL_IN_ERROR_DROP, + ACL_IN_ETHERNET_INPUT, + ACL_IN_L2S_INPUT_IP4_ADD, + ACL_IN_L2S_INPUT_IP6_ADD, + ACL_IN_N_NEXT, +} acl_in_next_t; + +#endif diff --git a/src/plugins/acl/node_out.c b/src/plugins/acl/node_out.c new file mode 100644 index 00000000..50af3679 --- /dev/null +++ b/src/plugins/acl/node_out.c @@ -0,0 +1,175 @@ +/* + * 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. + */ +#include +#include +#include +#include +#include + +#include "node_out.h" + +typedef struct +{ + u32 next_index; + u32 sw_if_index; + u32 match_acl_index; + u32 match_rule_index; + u32 trace_bitmap; +} acl_out_trace_t; + +/* packet trace format function */ +static u8 * +format_acl_out_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 *); + acl_out_trace_t *t = va_arg (*args, acl_out_trace_t *); + s = + format (s, + "ACL_OUT: sw_if_index %d, next index %d, match: outacl %d rule %d trace_bits %08x", + t->sw_if_index, t->next_index, t->match_acl_index, + t->match_rule_index, t->trace_bitmap); + return s; +} + +vlib_node_registration_t acl_out_node; + +#define foreach_acl_out_error \ +_(ACL_CHECK, "OutACL check packets processed") + +typedef enum +{ +#define _(sym,str) ACL_OUT_ERROR_##sym, + foreach_acl_out_error +#undef _ + ACL_OUT_N_ERROR, +} acl_out_error_t; + +static char *acl_out_error_strings[] = { +#define _(sym,string) string, + foreach_acl_out_error +#undef _ +}; + +static uword +acl_out_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + acl_main_t *am = &acl_main; + l2_output_next_nodes_st *next_nodes = &am->acl_out_output_next_nodes; + u32 n_left_from, *from, *to_next; + acl_out_next_t next_index; + u32 pkts_acl_checked = 0; + u32 feature_bitmap0; + u32 cached_sw_if_index = (u32) ~ 0; + u32 cached_next_index = (u32) ~ 0; + u32 match_acl_index = ~0; + u32 match_rule_index = ~0; + u32 trace_bitmap = 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 > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0 = ~0; + u32 next = 0; + u32 sw_if_index0; + + /* 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); + + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + feature_bitmap0 = vnet_buffer (b0)->l2.feature_bitmap; + + output_acl_packet_match (sw_if_index0, b0, &next, &match_acl_index, + &match_rule_index, &trace_bitmap); + if (next != ~0) + { + next0 = next; + } + if (next0 == ~0) + { + l2_output_dispatch (vm, + am->vnet_main, + node, + acl_out_node.index, + &cached_sw_if_index, + &cached_next_index, + next_nodes, + b0, sw_if_index0, feature_bitmap0, &next0); + } + + + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + acl_out_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + t->next_index = next0; + t->match_acl_index = match_acl_index; + t->match_rule_index = match_rule_index; + t->trace_bitmap = trace_bitmap; + } + + pkts_acl_checked += 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, acl_out_node.index, + ACL_OUT_ERROR_ACL_CHECK, pkts_acl_checked); + return frame->n_vectors; +} + +VLIB_REGISTER_NODE (acl_out_node) = +{ + .function = acl_out_node_fn,.name = "acl-plugin-out",.vector_size = + sizeof (u32),.format_trace = format_acl_out_trace,.type = + VLIB_NODE_TYPE_INTERNAL,.n_errors = + ARRAY_LEN (acl_out_error_strings),.error_strings = + acl_out_error_strings,.n_next_nodes = ACL_OUT_N_NEXT, + /* edit / add dispositions here */ + .next_nodes = + { + [ACL_OUT_ERROR_DROP] = "error-drop", + [ACL_OUT_INTERFACE_OUTPUT] = "interface-output", + [ACL_OUT_L2S_OUTPUT_IP4_ADD] = "aclp-l2s-output-ip4-add", + [ACL_OUT_L2S_OUTPUT_IP6_ADD] = "aclp-l2s-output-ip6-add",} +,}; diff --git a/src/plugins/acl/node_out.h b/src/plugins/acl/node_out.h new file mode 100644 index 00000000..c919f3b7 --- /dev/null +++ b/src/plugins/acl/node_out.h @@ -0,0 +1,12 @@ +#ifndef _NODE_OUT_H_ +#define _NODE_OUT_H_ + +typedef enum { + ACL_OUT_ERROR_DROP, + ACL_OUT_INTERFACE_OUTPUT, + ACL_OUT_L2S_OUTPUT_IP4_ADD, + ACL_OUT_L2S_OUTPUT_IP6_ADD, + ACL_OUT_N_NEXT, +} acl_out_next_t; + +#endif diff --git a/src/plugins/acl/test/run-python b/src/plugins/acl/test/run-python new file mode 100755 index 00000000..215eb17a --- /dev/null +++ b/src/plugins/acl/test/run-python @@ -0,0 +1,28 @@ +#!/bin/sh +# +# Do all the legwork to run a scapy shell with APIs available for load +# +CURR_DIR=`pwd` +ROOT_DIR=`git rev-parse --show-toplevel` +cd $ROOT_DIR +sudo apt-get install -y python-virtualenv +# uncomment the line below to enable build of plugins and api each time +# make plugins && make build-vpp-api || exit +virtualenv virtualenv +virtualenv/bin/pip install ipaddress +virtualenv/bin/pip install scapy +# install the python API into the virtualenv +cd $ROOT_DIR/vpp-api/python/ +$ROOT_DIR/virtualenv/bin/python setup.py install +# install the python ACL plugin API into the virtualenv +ACL_PLUGIN_SETUP_DIR=`find $ROOT_DIR/build-root -name acl-plugin` +cd $ACL_PLUGIN_SETUP_DIR; +$ROOT_DIR/virtualenv/bin/python setup.py install +cd $ROOT_DIR +# figure out the shared library path and start scapy +export LD_LIBRARY_PATH=`pwd`/`find . -name "libpneum.so" -exec dirname {} \; | grep lib64 | head -n 1` +cd $CURR_DIR +sudo LD_LIBRARY_PATH=$LD_LIBRARY_PATH $ROOT_DIR/virtualenv/bin/python $1 $2 $3 $4 $5 $6 $7 $8 $9 + + + diff --git a/src/plugins/acl/test/run-scapy b/src/plugins/acl/test/run-scapy new file mode 100755 index 00000000..266f07d1 --- /dev/null +++ b/src/plugins/acl/test/run-scapy @@ -0,0 +1,26 @@ +#!/bin/sh +# +# Do all the legwork to run a scapy shell with APIs available for load +# +ROOT_DIR=`git rev-parse --show-toplevel` +cd $ROOT_DIR +sudo apt-get install -y python-virtualenv +# uncomment the line below to enable the build of plugins and API each time.. +# make plugins && make build-vpp-api || exit +virtualenv virtualenv +virtualenv/bin/pip install ipaddress +virtualenv/bin/pip install scapy +# install the python API into the virtualenv +cd $ROOT_DIR/vpp-api/python/ +$ROOT_DIR/virtualenv/bin/python setup.py install +# install the python ACL plugin API into the virtualenv +ACL_PLUGIN_SETUP_DIR=`find $ROOT_DIR/build-root -name acl-plugin` +cd $ACL_PLUGIN_SETUP_DIR; +$ROOT_DIR/virtualenv/bin/python setup.py install +cd $ROOT_DIR +# figure out the shared library path and start scapy +export LD_LIBRARY_PATH=`pwd`/`find . -name "libpneum.so" -exec dirname {} \; | grep lib64 | head -n 1` +sudo LD_LIBRARY_PATH=$LD_LIBRARY_PATH virtualenv/bin/scapy + + + diff --git a/src/plugins/acl/test/test_acl_plugin.py b/src/plugins/acl/test/test_acl_plugin.py new file mode 100644 index 00000000..7fc72d67 --- /dev/null +++ b/src/plugins/acl/test/test_acl_plugin.py @@ -0,0 +1,118 @@ +from __future__ import print_function +import unittest, sys, time, threading, struct, logging, os +import vpp_papi +# import vpp_papi_plugins.acl +from ipaddress import * +papi_event = threading.Event() +print(vpp_papi.vpe.VL_API_SW_INTERFACE_SET_FLAGS) +def papi_event_handler(result): + if result.vl_msg_id == vpp_papi.vpe.VL_API_SW_INTERFACE_SET_FLAGS: + return + if result.vl_msg_id == vpp_papi.vpe.VL_API_VNET_INTERFACE_COUNTERS: + print('Interface counters', result) + return + if result.vl_msg_id == vpp_papi.vpe.VL_API_VNET_IP6_FIB_COUNTERS: + print('IPv6 FIB counters', result) + papi_event.set() + return + + print('Unknown message id:', result.vl_msg_id) + +import glob, subprocess +class TestAclPlugin(unittest.TestCase): + @classmethod + def setUpClass(cls): + print("Setup") + @classmethod + def tearDownClass(cls): + print("Teardown") + + def setUp(self): + print("Connecting API") + r = vpp_papi.connect("test_papi") + self.assertEqual(r, 0) + + def tearDown(self): + r = vpp_papi.disconnect() + self.assertEqual(r, 0) + + # + # The tests themselves + # + + # + # Basic request / reply + # + def test_show_version(self): + t = vpp_papi.show_version() + print('T', t); + program = t.program.decode().rstrip('\x00') + self.assertEqual('vpe', program) + + def x_test_acl_add(self): + print("Test ACL add") + self.assertEqual(1, 1) + + # + # Details / Dump + # + def x_test_details_dump(self): + t = vpp_papi.sw_interface_dump(0, b'') + print('Dump/details T', t) + + # + # Arrays + # + def x_test_arrays(self): + t = vpp_papi.vnet_get_summary_stats() + print('Summary stats', t) + print('Packets:', t.total_pkts[0]) + print('Packets:', t.total_pkts[1]) + # + # Variable sized arrays and counters + # + #@unittest.skip("stats") + def x_test_want_stats(self): + pid = 123 + vpp_papi.register_event_callback(papi_event_handler) + papi_event.clear() + + # Need to configure IPv6 to get som IPv6 FIB stats + t = vpp_papi.create_loopback('') + print(t) + self.assertEqual(t.retval, 0) + + ifindex = t.sw_if_index + addr = str(IPv6Address(u'1::1').packed) + t = vpp_papi.sw_interface_add_del_address(ifindex, 1, 1, 0, 16, addr) + print(t) + self.assertEqual(t.retval, 0) + + # Check if interface is up + # XXX: Add new API to query interface state based on ifindex, instead of dump all. + t = vpp_papi.sw_interface_set_flags(ifindex, 1, 1, 0) + self.assertEqual(t.retval, 0) + + t = vpp_papi.want_stats(True, pid) + + print (t) + + # + # Wait for some stats + # + self.assertEqual(papi_event.wait(15), True) + t = vpp_papi.want_stats(False, pid) + print (t) + + + # + # Plugins? + # + +if __name__ == '__main__' or __name__ == '__builtin__': + print("This is main") + suite = unittest.TestLoader().loadTestsFromTestCase(TestAclPlugin) + unittest.TextTestRunner(verbosity=2).run(suite) + #logging.basicConfig(level=logging.DEBUG) + # unittest.main() + diff --git a/src/plugins/ioam.am b/src/plugins/ioam.am new file mode 100644 index 00000000..a4984b18 --- /dev/null +++ b/src/plugins/ioam.am @@ -0,0 +1,150 @@ +# Copyright (c) 2015 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +######################################## +# iOAM Proof of Transit +######################################## + +ioam_pot_plugin_la_SOURCES = \ + ioam/lib-pot/pot_util.c \ + ioam/encap/ip6_ioam_pot.c \ + ioam/lib-pot/pot_util.h \ + ioam/lib-pot/math64.h \ + ioam/lib-pot/pot_api.c + +noinst_HEADERS += \ + ioam/lib-pot/pot_all_api_h.h \ + ioam/lib-pot/pot_msg_enum.h \ + ioam/lib-pot/pot.api.h \ + ioam/lib-pot/pot_util.h \ + ioam/lib-pot/math64.h + +API_FILES += ioam/lib-pot/pot.api + +ioam_pot_test_plugin_la_SOURCES = \ + ioam/lib-pot/pot_test.c \ + ioam/lib-pot/pot_plugin.api.h + +vppapitestplugins_LTLIBRARIES += ioam_pot_test_plugin.la +vppplugins_LTLIBRARIES += ioam_pot_plugin.la + +######################################## +# iOAM trace export for IPv6 +######################################## + +ioam_export_plugin_la_SOURCES = \ +ioam/export/ioam_export.c \ +ioam/export/node.c \ +ioam/export/ioam_export.api.h \ +ioam/export/ioam_export_thread.c + +noinst_HEADERS += \ + ioam/export/ioam_export_all_api_h.h \ + ioam/export/ioam_export_msg_enum.h \ + ioam/export/ioam_export.api.h + +API_FILES += ioam/export/ioam_export.api + +ioam_export_test_plugin_la_SOURCES = \ + ioam/export/ioam_export_test.c \ + ioam/export/ioam_export_plugin.api.h + +vppapitestplugins_LTLIBRARIES += ioam_export_test_plugin.la +vppplugins_LTLIBRARIES += ioam_export_plugin.la + +######################################## +# iOAM Trace +######################################## +libioam_trace_plugin_la_SOURCES = \ + ioam/lib-trace/trace_util.c \ + ioam/encap/ip6_ioam_trace.c \ + ioam/lib-trace/trace_util.h \ + ioam/lib-trace/trace_api.c + +noinst_HEADERS += \ + ioam/export/ioam_export_all_api_h.h \ + ioam/lib-trace/trace_all_api_h.h \ + ioam/lib-trace/trace_msg_enum.h \ + ioam/lib-trace/trace.api.h \ + ioam/lib-trace/trace_util.h + +API_FILES += ioam/lib-trace/trace.api + +ioam_trace_test_plugin_la_SOURCES = \ + ioam/lib-trace/trace_test.c \ + ioam/lib-trace/trace_plugin.api.h + +vppapitestplugins_LTLIBRARIES += ioam_trace_test_plugin.la +vppplugins_LTLIBRARIES += libioam_trace_plugin.la + +######################################## +# VxLAN-GPE +######################################## +libioam_vxlan_gpe_plugin_la_SOURCES = \ + ioam/lib-vxlan-gpe/ioam_encap.c \ + ioam/lib-vxlan-gpe/ioam_decap.c \ + ioam/lib-vxlan-gpe/ioam_transit.c \ + ioam/lib-vxlan-gpe/ioam_pop.c \ + ioam/lib-vxlan-gpe/vxlan_gpe_api.c \ + ioam/lib-vxlan-gpe/vxlan_gpe_ioam_trace.c \ + ioam/lib-vxlan-gpe/vxlan_gpe_ioam.c \ + ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.c \ + ioam/export-vxlan-gpe/vxlan_gpe_node.c \ + ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.api.h\ + ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_thread.c + +noinst_HEADERS += \ + ioam/export/ioam_export_all_api_h.h \ + ioam/lib-vxlan-gpe/vxlan_gpe_all_api_h.h \ + ioam/lib-vxlan-gpe/vxlan_gpe_msg_enum.h \ + ioam/lib-vxlan-gpe/ioam_vxlan_gpe.api.h \ + ioam/lib-vxlan-gpe/vxlan_gpe_ioam_util.h \ + ioam/lib-vxlan-gpe/vxlan_gpe_ioam_packet.h \ + ioam/lib-vxlan-gpe/vxlan_gpe_ioam.h \ + ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_all_api_h.h \ + ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_msg_enum.h \ + ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.api.h + +API_FILES += ioam/lib-vxlan-gpe/ioam_vxlan_gpe.api +API_FILES += ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.api + +ioam_vxlan_gpe_test_plugin_la_SOURCES = \ + ioam/lib-vxlan-gpe/vxlan_gpe_test.c \ + ioam/lib-vxlan-gpe/vxlan_gpe_plugin.api.h + +vppapitestplugins_LTLIBRARIES += ioam_vxlan_gpe_test_plugin.la +vppplugins_LTLIBRARIES += libioam_vxlan_gpe_plugin.la + +vxlan_gpe_ioam_export_test_plugin_la_SOURCES = \ + ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_test.c \ + ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_plugin.api.h + +vppapitestplugins_LTLIBRARIES += vxlan_gpe_ioam_export_test_plugin.la + +######################################## +# iOAM E2E plugin +######################################## + +ioam_e2e_plugin_la_SOURCES = \ + ioam/encap/ip6_ioam_e2e.c \ + ioam/encap/ip6_ioam_seqno.c \ + ioam/encap/ip6_ioam_seqno_analyse.c + +noinst_HEADERS += \ + ioam/encap/ip6_ioam_e2e.h \ + ioam/encap/ip6_ioam_seqno.h + +vppplugins_LTLIBRARIES += ioam_e2e_plugin.la + +# vi:syntax=automake diff --git a/src/plugins/ioam/dir.dox b/src/plugins/ioam/dir.dox new file mode 100644 index 00000000..f3389b52 --- /dev/null +++ b/src/plugins/ioam/dir.dox @@ -0,0 +1,18 @@ +/* + * 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. + */ +/** + @dir + @brief Inband OAM (iOAM) implementation +*/ diff --git a/src/plugins/ioam/encap/ip6_ioam_e2e.c b/src/plugins/ioam/encap/ip6_ioam_e2e.c new file mode 100644 index 00000000..0839cdce --- /dev/null +++ b/src/plugins/ioam/encap/ip6_ioam_e2e.c @@ -0,0 +1,232 @@ +/* + * 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. + */ + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include "ip6_ioam_e2e.h" + +ioam_e2e_main_t ioam_e2e_main; + +static u8 * ioam_e2e_trace_handler (u8 * s, + ip6_hop_by_hop_option_t *opt) +{ + ioam_e2e_option_t * e2e = (ioam_e2e_option_t *)opt; + u32 seqno = 0; + + if (e2e) + { + seqno = clib_net_to_host_u32 (e2e->e2e_data); + } + + s = format (s, "SeqNo = 0x%Lx", seqno); + return s; +} + +int +ioam_e2e_config_handler (void *data, u8 disable) +{ + int *analyse = data; + + /* Register hanlders if enabled */ + if (!disable) + { + /* If encap node register for encap handler */ + if (0 == *analyse) + { + if (ip6_hbh_register_option(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE, + ioam_seqno_encap_handler, + ioam_e2e_trace_handler) < 0) + { + return (-1); + } + } + /* If analyze node then register for decap handler */ + else + { + if (ip6_hbh_pop_register_option(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE, + ioam_seqno_decap_handler) < 0) + { + return (-1); + } + } + return 0; + } + + /* UnRegister handlers */ + (void) ip6_hbh_unregister_option(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE); + (void) ip6_hbh_pop_unregister_option(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE); + return 0; +} + +int +ioam_e2e_rewrite_handler (u8 *rewrite_string, + u8 *rewrite_size) +{ + ioam_e2e_option_t *e2e_option; + + if (rewrite_string && *rewrite_size == sizeof(ioam_e2e_option_t)) + { + e2e_option = (ioam_e2e_option_t *)rewrite_string; + e2e_option->hdr.type = HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE + | HBH_OPTION_TYPE_SKIP_UNKNOWN; + e2e_option->hdr.length = sizeof (ioam_e2e_option_t) - + sizeof (ip6_hop_by_hop_option_t); + return(0); + } + return(-1); +} + +u32 +ioam_e2e_flow_handler (u32 ctx, u8 add) +{ + ioam_e2e_data_t *data; + u16 i; + + if (add) + { + pool_get(ioam_e2e_main.e2e_data, data); + data->flow_ctx = ctx; + ioam_seqno_init_bitmap(&data->seqno_data); + return ((u32) (data - ioam_e2e_main.e2e_data)); + } + + /* Delete case */ + for (i = 0; i < vec_len(ioam_e2e_main.e2e_data); i++) + { + if (pool_is_free_index(ioam_e2e_main.e2e_data, i)) + continue; + + data = pool_elt_at_index(ioam_e2e_main.e2e_data, i); + if (data && (data->flow_ctx == ctx)) + { + pool_put_index(ioam_e2e_main.e2e_data, i); + return (0); + } + } + return 0; +} + +static clib_error_t * +ioam_show_e2e_cmd_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + ioam_e2e_data_t *e2e_data; + u8 *s = 0; + int i; + + vec_reset_length(s); + + s = format(0, "IOAM E2E information: \n"); + for (i = 0; i < vec_len(ioam_e2e_main.e2e_data); i++) + { + if (pool_is_free_index(ioam_e2e_main.e2e_data, i)) + continue; + + e2e_data = pool_elt_at_index(ioam_e2e_main.e2e_data, i); + s = format(s, "Flow name: %s\n", get_flow_name_from_flow_ctx(e2e_data->flow_ctx)); + + s = show_ioam_seqno_cmd_fn(s, + &e2e_data->seqno_data, + !IOAM_DEAP_ENABLED(e2e_data->flow_ctx)); + } + + vlib_cli_output(vm, "%v", s); + return 0; +} + + +VLIB_CLI_COMMAND (ioam_show_e2e_cmd, static) = { + .path = "show ioam e2e ", + .short_help = "show ioam e2e information", + .function = ioam_show_e2e_cmd_fn, +}; + +/* + * 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) +{ + clib_error_t * error = 0; + + ioam_e2e_main.vlib_main = vm; + ioam_e2e_main.vnet_main = h->vnet_main; + return error; +} + +/* + * Init handler E2E headet handling. + * Init hanlder registers encap, decap, trace and Rewrite handlers. + */ +static clib_error_t * +ioam_e2e_init (vlib_main_t * vm) +{ + clib_error_t * error; + + if ((error = vlib_call_init_function (vm, ip6_hop_by_hop_ioam_init))) + { + return(error); + } + + /* + * As of now we have only PPC under E2E header. + */ + if (ip6_hbh_config_handler_register(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE, + ioam_e2e_config_handler) < 0) + { + return (clib_error_create("Registration of " + "HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE for rewrite failed")); + } + + if (ip6_hbh_add_register_option(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE, + sizeof(ioam_e2e_option_t), + ioam_e2e_rewrite_handler) < 0) + { + return (clib_error_create("Registration of " + "HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE for rewrite failed")); + } + + if (ip6_hbh_flow_handler_register(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE, + ioam_e2e_flow_handler) < 0) + { + return (clib_error_create("Registration of " + "HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE Flow handler failed")); + } + + return (0); +} + +/* + * Init function for the E2E lib. + * ip6_hop_by_hop_ioam_e2e_init gets called during init. + */ +VLIB_INIT_FUNCTION (ioam_e2e_init); diff --git a/src/plugins/ioam/encap/ip6_ioam_e2e.h b/src/plugins/ioam/encap/ip6_ioam_e2e.h new file mode 100644 index 00000000..18f35f80 --- /dev/null +++ b/src/plugins/ioam/encap/ip6_ioam_e2e.h @@ -0,0 +1,47 @@ +/* + * 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. + */ + +#ifndef __included_ip6_ioam_e2e_h__ +#define __included_ip6_ioam_e2e_h__ + +#include "ip6_ioam_seqno.h" + +typedef struct ioam_e2e_data_t_ { + u32 flow_ctx; + u32 pad; + ioam_seqno_data seqno_data; +} ioam_e2e_data_t; + +typedef struct { + ioam_e2e_data_t *e2e_data; + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} ioam_e2e_main_t; + +extern ioam_e2e_main_t ioam_e2e_main; + +static inline ioam_seqno_data * +ioam_e2ec_get_seqno_data_from_flow_ctx (u32 flow_ctx) +{ + ioam_e2e_data_t *data = NULL; + u32 index; + + index = get_flow_data_from_flow_ctx(flow_ctx, + HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE); + data = &ioam_e2e_main.e2e_data[index]; + return &(data->seqno_data); +} + +#endif /* __included_ioam_e2e_h__ */ diff --git a/src/plugins/ioam/encap/ip6_ioam_pot.c b/src/plugins/ioam/encap/ip6_ioam_pot.c new file mode 100644 index 00000000..05f42c91 --- /dev/null +++ b/src/plugins/ioam/encap/ip6_ioam_pot.c @@ -0,0 +1,276 @@ +/* + * 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. + */ +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +typedef CLIB_PACKED(struct { + ip6_hop_by_hop_option_t hdr; + u8 pot_type; +#define PROFILE_ID_MASK 0xF + u8 reserved_profile_id; /* 4 bits reserved, 4 bits to carry profile id */ + u64 random; + u64 cumulative; +}) ioam_pot_option_t; + +#define foreach_ip6_hop_by_hop_ioam_pot_stats \ + _(PROCESSED, "Pkts with ip6 hop-by-hop pot options") \ + _(PROFILE_MISS, "Pkts with ip6 hop-by-hop pot options but no profile set") \ + _(PASSED, "Pkts with POT in Policy") \ + _(FAILED, "Pkts with POT out of Policy") + +static char * ip6_hop_by_hop_ioam_pot_stats_strings[] = { +#define _(sym,string) string, + foreach_ip6_hop_by_hop_ioam_pot_stats +#undef _ +}; + +typedef enum { +#define _(sym,str) IP6_IOAM_POT_##sym, + foreach_ip6_hop_by_hop_ioam_pot_stats +#undef _ + IP6_IOAM_POT_N_STATS, +} ip6_ioam_pot_stats_t; + +typedef struct { + /* stats */ + u64 counters[ARRAY_LEN(ip6_hop_by_hop_ioam_pot_stats_strings)]; + + /* convenience */ + vlib_main_t * vlib_main; + vnet_main_t * vnet_main; +} ip6_hop_by_hop_ioam_pot_main_t; + +ip6_hop_by_hop_ioam_pot_main_t ip6_hop_by_hop_ioam_pot_main; + +always_inline void +ip6_ioam_stats_increment_counter (u32 counter_index, u64 increment) +{ + ip6_hop_by_hop_ioam_pot_main_t *hm = &ip6_hop_by_hop_ioam_pot_main; + + hm->counters[counter_index] += increment; +} + + +static u8 * format_ioam_pot (u8 * s, va_list * args) +{ + ioam_pot_option_t * pot0 = va_arg (*args, ioam_pot_option_t *); + u64 random, cumulative; + random = cumulative = 0; + if (pot0) + { + random = clib_net_to_host_u64 (pot0->random); + cumulative = clib_net_to_host_u64 (pot0->cumulative); + } + + s = format (s, "random = 0x%Lx, Cumulative = 0x%Lx, Index = 0x%x", + random, cumulative, pot0 ? pot0->reserved_profile_id : ~0); + return s; +} + +u8 * +ip6_hbh_ioam_proof_of_transit_trace_handler (u8 *s, ip6_hop_by_hop_option_t *opt) +{ + ioam_pot_option_t *pot; + + s = format (s, " POT opt present\n"); + pot = (ioam_pot_option_t *) opt; + s = format (s, " %U\n", format_ioam_pot, pot); + return (s); +} + +int +ip6_hbh_ioam_proof_of_transit_handler (vlib_buffer_t *b, + ip6_header_t *ip, + ip6_hop_by_hop_option_t *opt0) +{ + ioam_pot_option_t * pot0; + u64 random = 0, cumulative = 0; + int rv = 0; + u8 pot_profile_index; + pot_profile *pot_profile = 0, *new_profile = 0; + u8 pot_encap = 0; + + pot0 = (ioam_pot_option_t *) opt0; + pot_encap = (pot0->random == 0); + pot_profile_index = pot_profile_get_active_id(); + pot_profile = pot_profile_get_active(); + if (pot_encap && PREDICT_FALSE(!pot_profile)) + { + ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PROFILE_MISS, 1); + return(-1); + } + if (pot_encap) + { + pot0->reserved_profile_id = + pot_profile_index & PROFILE_ID_MASK; + pot_profile_incr_usage_stats(pot_profile); + } + else + { /* Non encap node */ + if (PREDICT_FALSE(pot0->reserved_profile_id != + pot_profile_index || pot_profile == 0)) + { + /* New profile announced by encap node. */ + new_profile = + pot_profile_find(pot0->reserved_profile_id); + if (PREDICT_FALSE(new_profile == 0 || + new_profile->valid == 0)) + { + ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PROFILE_MISS, 1); + return(-1); + } + else + { + pot_profile_index = pot0->reserved_profile_id; + pot_profile = new_profile; + pot_profile_set_active(pot_profile_index); + pot_profile_reset_usage_stats(pot_profile); + } + } + pot_profile_incr_usage_stats(pot_profile); + } + + if (pot0->random == 0) + { + pot0->random = clib_host_to_net_u64(pot_generate_random(pot_profile)); + pot0->cumulative = 0; + } + random = clib_net_to_host_u64(pot0->random); + cumulative = clib_net_to_host_u64(pot0->cumulative); + pot0->cumulative = clib_host_to_net_u64( + pot_update_cumulative(pot_profile, + cumulative, + random)); + ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PROCESSED, 1); + + return (rv); +} + +int +ip6_hbh_ioam_proof_of_transit_pop_handler (vlib_buffer_t *b, ip6_header_t *ip, + ip6_hop_by_hop_option_t *opt0) +{ + ioam_pot_option_t * pot0; + u64 random = 0; + u64 cumulative = 0; + int rv = 0; + pot_profile *pot_profile = 0; + u8 result = 0; + + pot0 = (ioam_pot_option_t *) opt0; + random = clib_net_to_host_u64(pot0->random); + cumulative = clib_net_to_host_u64(pot0->cumulative); + pot_profile = pot_profile_get_active(); + result = pot_validate (pot_profile, + cumulative, random); + + if (result == 1) + { + ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PASSED, 1); + } + else + { + ip6_ioam_stats_increment_counter (IP6_IOAM_POT_FAILED, 1); + } + return (rv); +} + +int ip6_hop_by_hop_ioam_pot_rewrite_handler (u8 *rewrite_string, u8 *rewrite_size) +{ + ioam_pot_option_t * pot_option; + if (rewrite_string && *rewrite_size == sizeof(ioam_pot_option_t)) + { + pot_option = (ioam_pot_option_t *)rewrite_string; + pot_option->hdr.type = HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT + | HBH_OPTION_TYPE_DATA_CHANGE_ENROUTE; + pot_option->hdr.length = sizeof (ioam_pot_option_t) - + sizeof (ip6_hop_by_hop_option_t); + return(0); + } + return(-1); +} + +static clib_error_t * +ip6_show_ioam_pot_cmd_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + ip6_hop_by_hop_ioam_pot_main_t *hm = &ip6_hop_by_hop_ioam_pot_main; + u8 *s = 0; + int i = 0; + + for ( i = 0; i < IP6_IOAM_POT_N_STATS; i++) + { + s = format(s, " %s - %lu\n", ip6_hop_by_hop_ioam_pot_stats_strings[i], + hm->counters[i]); + } + + vlib_cli_output(vm, "%v", s); + vec_free(s); + return 0; +} + + +VLIB_CLI_COMMAND (ip6_show_ioam_pot_cmd, static) = { + .path = "show ioam pot", + .short_help = "iOAM pot statistics", + .function = ip6_show_ioam_pot_cmd_fn, +}; + + +static clib_error_t * +ip6_hop_by_hop_ioam_pot_init (vlib_main_t * vm) +{ + ip6_hop_by_hop_ioam_pot_main_t * hm = &ip6_hop_by_hop_ioam_pot_main; + clib_error_t * error; + + if ((error = vlib_call_init_function (vm, ip6_hop_by_hop_ioam_init))) + return(error); + + hm->vlib_main = vm; + hm->vnet_main = vnet_get_main(); + memset(hm->counters, 0, sizeof(hm->counters)); + + if (ip6_hbh_register_option(HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT, ip6_hbh_ioam_proof_of_transit_handler, + ip6_hbh_ioam_proof_of_transit_trace_handler) < 0) + return (clib_error_create("registration of HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT failed")); + + if (ip6_hbh_add_register_option(HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT, + sizeof(ioam_pot_option_t), + ip6_hop_by_hop_ioam_pot_rewrite_handler) < 0) + return (clib_error_create("registration of HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT for rewrite failed")); + + if (ip6_hbh_pop_register_option(HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT, + ip6_hbh_ioam_proof_of_transit_pop_handler) < 0) + return (clib_error_create("registration of HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT POP failed")); + + return (0); +} + +VLIB_INIT_FUNCTION (ip6_hop_by_hop_ioam_pot_init); + + diff --git a/src/plugins/ioam/encap/ip6_ioam_seqno.c b/src/plugins/ioam/encap/ip6_ioam_seqno.c new file mode 100644 index 00000000..0b4d4192 --- /dev/null +++ b/src/plugins/ioam/encap/ip6_ioam_seqno.c @@ -0,0 +1,109 @@ +/* + * 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. + */ + + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "ip6_ioam_seqno.h" +#include "ip6_ioam_e2e.h" + +ioam_seqno_data_main_t ioam_seqno_main; + +void ioam_seqno_init_bitmap (ioam_seqno_data *data) +{ + seqno_bitmap *bitmap = &data->seqno_rx.bitmap; + bitmap->window_size = SEQNO_WINDOW_SIZE; + bitmap->array_size = SEQNO_WINDOW_ARRAY_SIZE; + bitmap->mask = 32 * SEQNO_WINDOW_ARRAY_SIZE - 1; + bitmap->array[0] = 0x00000000;/* pretend we haven seen sequence numbers 0*/ + bitmap->highest = 0; + + data->seq_num = 0; + return ; +} + +/* + * This Routine gets called from IPv6 hop-by-hop option handling. + * Only if we are encap node, then add PPC data. + * On a Transit(MID) node we dont do anything with E2E headers. + * On decap node decap is handled by seperate function. + */ +int +ioam_seqno_encap_handler (vlib_buffer_t *b, ip6_header_t *ip, + ip6_hop_by_hop_option_t *opt) +{ + u32 opaque_index = vnet_buffer(b)->l2_classify.opaque_index; + ioam_e2e_option_t * e2e; + int rv = 0; + ioam_seqno_data *data; + + data = ioam_e2ec_get_seqno_data_from_flow_ctx(opaque_index); + e2e = (ioam_e2e_option_t *) opt; + e2e->e2e_data = clib_host_to_net_u32(++data->seq_num); + + return (rv); +} + +/* + * This Routine gets called on POP/Decap node. + */ +int +ioam_seqno_decap_handler (vlib_buffer_t *b, ip6_header_t *ip, + ip6_hop_by_hop_option_t *opt) +{ + u32 opaque_index = vnet_buffer(b)->l2_classify.opaque_index; + ioam_e2e_option_t * e2e; + int rv = 0; + ioam_seqno_data *data; + + data = ioam_e2ec_get_seqno_data_from_flow_ctx(opaque_index); + e2e = (ioam_e2e_option_t *) opt; + ioam_analyze_seqno(&data->seqno_rx, (u64) clib_net_to_host_u32(e2e->e2e_data)); + + return (rv); +} + +u8 * +show_ioam_seqno_cmd_fn (u8 *s, ioam_seqno_data *seqno_data, u8 enc) +{ + seqno_rx_info *rx; + + s = format(s, "SeqNo Data:\n"); + if (enc) + { + s = format(s, " Current Seq. Number : %llu\n", seqno_data->seq_num); + } + else + { + rx = &seqno_data->seqno_rx; + s = format(s, " Highest Seq. Number : %llu\n", rx->bitmap.highest); + s = format(s, " Packets received : %llu\n", rx->rx_packets); + s = format(s, " Lost packets : %llu\n", rx->lost_packets); + s = format(s, " Reordered packets : %llu\n", rx->reordered_packets); + s = format(s, " Duplicate packets : %llu\n", rx->dup_packets); + } + + format(s, "\n"); + return s; +} diff --git a/src/plugins/ioam/encap/ip6_ioam_seqno.h b/src/plugins/ioam/encap/ip6_ioam_seqno.h new file mode 100644 index 00000000..13a84db0 --- /dev/null +++ b/src/plugins/ioam/encap/ip6_ioam_seqno.h @@ -0,0 +1,70 @@ +/* + * 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. + */ + +#ifndef __included_ip6_ioam_seqno_h__ +#define __included_ip6_ioam_seqno_h__ + +#include +#include + +#define SEQ_CHECK_VALUE 0x80000000 /* for seq number wraparound detection */ + +#define SEQNO_WINDOW_SIZE 2048 +#define SEQNO_WINDOW_ARRAY_SIZE 64 + +typedef struct seqno_bitmap_ { + u32 window_size; + u32 array_size; + u32 mask; + u32 pad; + u64 highest; + u64 array[SEQNO_WINDOW_ARRAY_SIZE]; /* Will be alloc to array_size */ +} seqno_bitmap; + +typedef struct seqno_rx_info_ { + u64 rx_packets; + u64 lost_packets; + u64 reordered_packets; + u64 dup_packets; + seqno_bitmap bitmap; +} seqno_rx_info; + +/* This structure is 64-byte aligned */ +typedef struct ioam_seqno_data_ { + union { + u32 seq_num; /* Useful only for encap node */ + seqno_rx_info seqno_rx; + }; +} ioam_seqno_data; + +typedef struct ioam_seqno_data_main_t_ { + ioam_seqno_data *seqno_data; +} ioam_seqno_data_main_t; + +void ioam_seqno_init_bitmap(ioam_seqno_data *data); + +int ioam_seqno_encap_handler(vlib_buffer_t *b, ip6_header_t *ip, + ip6_hop_by_hop_option_t *opt); + +int +ioam_seqno_decap_handler(vlib_buffer_t *b, ip6_header_t *ip, + ip6_hop_by_hop_option_t *opt); + +void ioam_analyze_seqno(seqno_rx_info *ppc_rx, u64 seqno); + +u8 * +show_ioam_seqno_cmd_fn(u8 *s, ioam_seqno_data *seqno_data, u8 enc); + +#endif diff --git a/src/plugins/ioam/encap/ip6_ioam_seqno_analyse.c b/src/plugins/ioam/encap/ip6_ioam_seqno_analyse.c new file mode 100644 index 00000000..4638871c --- /dev/null +++ b/src/plugins/ioam/encap/ip6_ioam_seqno_analyse.c @@ -0,0 +1,141 @@ +/* + * 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. + */ + +#include +#include "ip6_ioam_seqno.h" + +static inline void BIT_SET (u64 *p, u32 n) +{ + p[ n>>5 ] |= (1 << (n&31)); +} + +static inline int BIT_TEST (u64 *p, u32 n) +{ + return p[ n>>5 ] & (1 << (n&31)); +} + +static void BIT_CLEAR (u64 *p, u64 start, int num_bits, u32 mask) +{ + int n, t; + int start_index = (start >> 5); + int mask_index = (mask >> 5); + + start_index &= mask_index; + if (start & 0x1f) + { + int start_bit = (start & 0x1f); + + n = (1 << start_bit)-1; + t = start_bit + num_bits; + if (t < 32) + { + n |= ~((1 << t)-1); + p[ start_index ] &= n; + return; + } + p[ start_index ] &= n; + start_index = (start_index + 1) & mask_index; + num_bits -= (32 - start_bit); + } + while (num_bits >= 32) + { + p[ start_index ] = 0; + start_index = (start_index + 1) & mask_index; + num_bits -= 32; + } + n = ~((1 << num_bits) - 1); + p[ start_index ] &= n; +} + +static inline u8 seqno_check_wraparound(u32 a, u32 b) +{ + if ((a != b) && (a > b) && ((a - b) > SEQ_CHECK_VALUE)) + { + return 1; + } + return 0; +} + +/* + * Function to analyze the PPC value recevied. + * - Updates the bitmap with received sequence number + * - counts the received/lost/duplicate/reordered packets + */ +void ioam_analyze_seqno (seqno_rx_info *seqno_rx, u64 seqno) +{ + int diff; + static int peer_dead_count; + seqno_bitmap *bitmap = &seqno_rx->bitmap; + + seqno_rx->rx_packets++; + + if (seqno > bitmap->highest) + { /* new larger sequence number */ + peer_dead_count = 0; + diff = seqno - bitmap->highest; + if (diff < bitmap->window_size) + { + if (diff > 1) + { /* diff==1 is *such* a common case it's a win to optimize it */ + BIT_CLEAR(bitmap->array, bitmap->highest+1, diff-1, bitmap->mask); + seqno_rx->lost_packets += diff -1; + } + } + else + { + seqno_rx->lost_packets += diff -1; + memset( bitmap->array, 0, bitmap->array_size * sizeof(u64) ); + } + BIT_SET(bitmap->array, seqno & bitmap->mask); + bitmap->highest = seqno; + return; + } + + /* we've seen a bigger seq number before */ + diff = bitmap->highest - seqno; + if (diff >= bitmap->window_size) + { + if (seqno_check_wraparound(bitmap->highest, seqno)) + { + memset( bitmap->array, 0, bitmap->array_size * sizeof(u64)); + BIT_SET(bitmap->array, seqno & bitmap->mask); + bitmap->highest = seqno; + return; + } + else + { + peer_dead_count++; + if (peer_dead_count > 25) + { + peer_dead_count = 0; + memset( bitmap->array, 0, bitmap->array_size * sizeof(u64) ); + BIT_SET(bitmap->array, seqno & bitmap->mask); + bitmap->highest = seqno; + } + //ppc_rx->reordered_packets++; + } + return; + } + + if (BIT_TEST(bitmap->array, seqno & bitmap->mask)) + { + seqno_rx->dup_packets++; + return; /* Already seen */ + } + seqno_rx->reordered_packets++; + seqno_rx->lost_packets--; + BIT_SET(bitmap->array, seqno & bitmap->mask); + return; +} diff --git a/src/plugins/ioam/encap/ip6_ioam_trace.c b/src/plugins/ioam/encap/ip6_ioam_trace.c new file mode 100644 index 00000000..e63db6e4 --- /dev/null +++ b/src/plugins/ioam/encap/ip6_ioam_trace.c @@ -0,0 +1,438 @@ +/* + * 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. + */ +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +/* Timestamp precision multipliers for seconds, milliseconds, microseconds + * and nanoseconds respectively. + */ +static f64 trace_tsp_mul[4] = { 1, 1e3, 1e6, 1e9 }; + +typedef union +{ + u64 as_u64; + u32 as_u32[2]; +} time_u64_t; + +/* *INDENT-OFF* */ +typedef CLIB_PACKED(struct { + ip6_hop_by_hop_option_t hdr; + u8 ioam_trace_type; + u8 data_list_elts_left; + u32 elts[0]; /* Variable type. So keep it generic */ +}) ioam_trace_option_t; +/* *INDENT-ON* */ + + +extern ip6_hop_by_hop_ioam_main_t ip6_hop_by_hop_ioam_main; +extern ip6_main_t ip6_main; + +#define foreach_ip6_hop_by_hop_ioam_trace_stats \ + _(PROCESSED, "Pkts with ip6 hop-by-hop trace options") \ + _(PROFILE_MISS, "Pkts with ip6 hop-by-hop trace options but no profile set") \ + _(UPDATED, "Pkts with trace updated") \ + _(FULL, "Pkts with trace options but no space") + +static char *ip6_hop_by_hop_ioam_trace_stats_strings[] = { +#define _(sym,string) string, + foreach_ip6_hop_by_hop_ioam_trace_stats +#undef _ +}; + +typedef enum +{ +#define _(sym,str) IP6_IOAM_TRACE_##sym, + foreach_ip6_hop_by_hop_ioam_trace_stats +#undef _ + IP6_IOAM_TRACE_N_STATS, +} ip6_ioam_trace_stats_t; + + +typedef struct +{ + /* stats */ + u64 counters[ARRAY_LEN (ip6_hop_by_hop_ioam_trace_stats_strings)]; + + /* convenience */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} ip6_hop_by_hop_ioam_trace_main_t; + +ip6_hop_by_hop_ioam_trace_main_t ip6_hop_by_hop_ioam_trace_main; + +always_inline void +ip6_ioam_trace_stats_increment_counter (u32 counter_index, u64 increment) +{ + ip6_hop_by_hop_ioam_trace_main_t *hm = &ip6_hop_by_hop_ioam_trace_main; + + hm->counters[counter_index] += increment; +} + + +static u8 * +format_ioam_data_list_element (u8 * s, va_list * args) +{ + u32 *elt = va_arg (*args, u32 *); + u8 *trace_type_p = va_arg (*args, u8 *); + u8 trace_type = *trace_type_p; + + + if (trace_type & BIT_TTL_NODEID) + { + u32 ttl_node_id_host_byte_order = clib_net_to_host_u32 (*elt); + s = format (s, "ttl 0x%x node id 0x%x ", + ttl_node_id_host_byte_order >> 24, + ttl_node_id_host_byte_order & 0x00FFFFFF); + + elt++; + } + + if (trace_type & BIT_ING_INTERFACE && trace_type & BIT_ING_INTERFACE) + { + u32 ingress_host_byte_order = clib_net_to_host_u32 (*elt); + s = format (s, "ingress 0x%x egress 0x%x ", + ingress_host_byte_order >> 16, + ingress_host_byte_order & 0xFFFF); + elt++; + } + + if (trace_type & BIT_TIMESTAMP) + { + u32 ts_in_host_byte_order = clib_net_to_host_u32 (*elt); + s = format (s, "ts 0x%x \n", ts_in_host_byte_order); + elt++; + } + + if (trace_type & BIT_APPDATA) + { + u32 appdata_in_host_byte_order = clib_net_to_host_u32 (*elt); + s = format (s, "app 0x%x ", appdata_in_host_byte_order); + elt++; + } + + return s; +} + + +int +ip6_ioam_trace_get_sizeof_handler (u32 * result) +{ + u16 size = 0; + u8 trace_data_size = 0; + trace_profile *profile = NULL; + + *result = 0; + + profile = trace_profile_find (); + + if (PREDICT_FALSE (!profile)) + { + ip6_ioam_trace_stats_increment_counter (IP6_IOAM_TRACE_PROFILE_MISS, 1); + return (-1); + } + + trace_data_size = fetch_trace_data_size (profile->trace_type); + if (PREDICT_FALSE (trace_data_size == 0)) + return VNET_API_ERROR_INVALID_VALUE; + + if (PREDICT_FALSE (profile->num_elts * trace_data_size > 254)) + return VNET_API_ERROR_INVALID_VALUE; + + size += + sizeof (ioam_trace_option_t) + (profile->num_elts * trace_data_size); + *result = size; + + return 0; +} + + + +int +ip6_hop_by_hop_ioam_trace_rewrite_handler (u8 * rewrite_string, + u8 * rewrite_size) +{ + ioam_trace_option_t *trace_option = NULL; + u8 trace_data_size = 0; + u8 trace_option_elts = 0; + trace_profile *profile = NULL; + + + profile = trace_profile_find (); + + if (PREDICT_FALSE (!profile)) + { + ip6_ioam_trace_stats_increment_counter (IP6_IOAM_TRACE_PROFILE_MISS, 1); + return (-1); + } + + if (PREDICT_FALSE (!rewrite_string)) + return -1; + + trace_option_elts = profile->num_elts; + trace_data_size = fetch_trace_data_size (profile->trace_type); + trace_option = (ioam_trace_option_t *) rewrite_string; + trace_option->hdr.type = HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST | + HBH_OPTION_TYPE_DATA_CHANGE_ENROUTE; + trace_option->hdr.length = 2 /*ioam_trace_type,data_list_elts_left */ + + trace_option_elts * trace_data_size; + trace_option->ioam_trace_type = profile->trace_type & TRACE_TYPE_MASK; + trace_option->data_list_elts_left = trace_option_elts; + *rewrite_size = + sizeof (ioam_trace_option_t) + (trace_option_elts * trace_data_size); + + return 0; +} + + +int +ip6_hbh_ioam_trace_data_list_handler (vlib_buffer_t * b, ip6_header_t * ip, + ip6_hop_by_hop_option_t * opt) +{ + ip6_main_t *im = &ip6_main; + ip_lookup_main_t *lm = &im->lookup_main; + ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; + u8 elt_index = 0; + ioam_trace_option_t *trace = (ioam_trace_option_t *) opt; + u32 adj_index = vnet_buffer (b)->ip.adj_index[VLIB_TX]; + ip_adjacency_t *adj = ip_get_adjacency (lm, adj_index); + time_u64_t time_u64; + u32 *elt; + int rv = 0; + trace_profile *profile = NULL; + + + profile = trace_profile_find (); + + if (PREDICT_FALSE (!profile)) + { + ip6_ioam_trace_stats_increment_counter (IP6_IOAM_TRACE_PROFILE_MISS, 1); + return (-1); + } + + + time_u64.as_u64 = 0; + + if (PREDICT_TRUE (trace->data_list_elts_left)) + { + trace->data_list_elts_left--; + /* fetch_trace_data_size returns in bytes. Convert it to 4-bytes + * to skip to this node's location. + */ + elt_index = + trace->data_list_elts_left * + fetch_trace_data_size (trace->ioam_trace_type) / 4; + elt = &trace->elts[elt_index]; + if (trace->ioam_trace_type & BIT_TTL_NODEID) + { + *elt = + clib_host_to_net_u32 ((ip->hop_limit << 24) | profile->node_id); + elt++; + } + + if (trace->ioam_trace_type & BIT_ING_INTERFACE) + { + *elt = + (vnet_buffer (b)->sw_if_index[VLIB_RX] & 0xFFFF) << 16 | + (adj->rewrite_header.sw_if_index & 0xFFFF); + *elt = clib_host_to_net_u32 (*elt); + elt++; + } + + if (trace->ioam_trace_type & BIT_TIMESTAMP) + { + /* Send least significant 32 bits */ + f64 time_f64 = + (f64) (((f64) hm->unix_time_0) + + (vlib_time_now (hm->vlib_main) - hm->vlib_time_0)); + + time_u64.as_u64 = time_f64 * trace_tsp_mul[profile->trace_tsp]; + *elt = clib_host_to_net_u32 (time_u64.as_u32[0]); + elt++; + } + + if (trace->ioam_trace_type & BIT_APPDATA) + { + /* $$$ set elt0->app_data */ + *elt = clib_host_to_net_u32 (profile->app_data); + elt++; + } + ip6_ioam_trace_stats_increment_counter (IP6_IOAM_TRACE_UPDATED, 1); + } + else + { + ip6_ioam_trace_stats_increment_counter (IP6_IOAM_TRACE_FULL, 1); + } + return (rv); +} + +u8 * +ip6_hbh_ioam_trace_data_list_trace_handler (u8 * s, + ip6_hop_by_hop_option_t * opt) +{ + ioam_trace_option_t *trace; + u8 trace_data_size_in_words = 0; + u32 *elt; + int elt_index = 0; + + trace = (ioam_trace_option_t *) opt; + s = + format (s, " Trace Type 0x%x , %d elts left\n", trace->ioam_trace_type, + trace->data_list_elts_left); + trace_data_size_in_words = + fetch_trace_data_size (trace->ioam_trace_type) / 4; + elt = &trace->elts[0]; + while ((u8 *) elt < ((u8 *) (&trace->elts[0]) + trace->hdr.length - 2 + /* -2 accounts for ioam_trace_type,elts_left */ )) + { + s = format (s, " [%d] %U\n", elt_index, + format_ioam_data_list_element, + elt, &trace->ioam_trace_type); + elt_index++; + elt += trace_data_size_in_words; + } + return (s); +} + + +static clib_error_t * +ip6_show_ioam_trace_cmd_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + ip6_hop_by_hop_ioam_trace_main_t *hm = &ip6_hop_by_hop_ioam_trace_main; + u8 *s = 0; + int i = 0; + + for (i = 0; i < IP6_IOAM_TRACE_N_STATS; i++) + { + s = + format (s, " %s - %lu\n", ip6_hop_by_hop_ioam_trace_stats_strings[i], + hm->counters[i]); + } + + vlib_cli_output (vm, "%v", s); + vec_free (s); + return 0; +} + + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (ip6_show_ioam_trace_cmd, static) = { + .path = "show ioam trace", + .short_help = "iOAM trace statistics", + .function = ip6_show_ioam_trace_cmd_fn, +}; +/* *INDENT-ON* */ + + +static clib_error_t * +ip6_hop_by_hop_ioam_trace_init (vlib_main_t * vm) +{ + ip6_hop_by_hop_ioam_trace_main_t *hm = &ip6_hop_by_hop_ioam_trace_main; + clib_error_t *error; + + if ((error = vlib_call_init_function (vm, ip_main_init))) + return (error); + + if ((error = vlib_call_init_function (vm, ip6_lookup_init))) + return error; + + if ((error = vlib_call_init_function (vm, ip6_hop_by_hop_ioam_init))) + return (error); + + hm->vlib_main = vm; + hm->vnet_main = vnet_get_main (); + memset (hm->counters, 0, sizeof (hm->counters)); + + + if (ip6_hbh_register_option + (HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST, + ip6_hbh_ioam_trace_data_list_handler, + ip6_hbh_ioam_trace_data_list_trace_handler) < 0) + return (clib_error_create + ("registration of HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST failed")); + + + if (ip6_hbh_add_register_option (HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST, + sizeof (ioam_trace_option_t), + ip6_hop_by_hop_ioam_trace_rewrite_handler) + < 0) + return (clib_error_create + ("registration of HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST for rewrite failed")); + + + return (0); +} + +int +ip6_trace_profile_cleanup (void) +{ + ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; + + hm->options_size[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST] = 0; + + return 0; + +} + + +int +ip6_trace_profile_setup (void) +{ + u32 trace_size = 0; + ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; + + trace_profile *profile = NULL; + + + profile = trace_profile_find (); + + if (PREDICT_FALSE (!profile)) + { + ip6_ioam_trace_stats_increment_counter (IP6_IOAM_TRACE_PROFILE_MISS, 1); + return (-1); + } + + + if (ip6_ioam_trace_get_sizeof_handler (&trace_size) < 0) + return (-1); + + hm->options_size[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST] = trace_size; + + return (0); +} + + +VLIB_INIT_FUNCTION (ip6_hop_by_hop_ioam_trace_init); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/export-common/ioam_export.h b/src/plugins/ioam/export-common/ioam_export.h new file mode 100644 index 00000000..fbd86180 --- /dev/null +++ b/src/plugins/ioam/export-common/ioam_export.h @@ -0,0 +1,616 @@ +/* + * 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. + */ +#ifndef __included_ioam_export_h__ +#define __included_ioam_export_h__ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +typedef struct ioam_export_buffer +{ + /* Allocated buffer */ + u32 buffer_index; + u64 touched_at; + u8 records_in_this_buffer; +} ioam_export_buffer_t; + + +typedef struct +{ + /* API message ID base */ + u16 msg_id_base; + + /* TODO: to support multiple collectors all this has to be grouped and create a vector here */ + u8 *record_header; + u32 sequence_number; + u32 domain_id; + + /* ipfix collector, our ip address */ + ip4_address_t ipfix_collector; + ip4_address_t src_address; + + /* Pool of ioam_export_buffer_t */ + ioam_export_buffer_t *buffer_pool; + /* Vector of per thread ioam_export_buffer_t to buffer pool index */ + u32 *buffer_per_thread; + /* Lock per thread to swap buffers between worker and timer process */ + volatile u32 **lockp; + + /* time scale transform */ + u32 unix_time_0; + f64 vlib_time_0; + + /* convenience */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; + u32 ip4_lookup_node_index; + + uword my_hbh_slot; + u32 export_process_node_index; +} ioam_export_main_t; + +ioam_export_main_t ioam_export_main; +ioam_export_main_t vxlan_gpe_ioam_export_main; + +extern vlib_node_registration_t export_node; + +#define DEFAULT_EXPORT_SIZE (3 * CLIB_CACHE_LINE_BYTES) +/* + * Number of records in a buffer + * ~(MTU (1500) - [ip hdr(40) + UDP(8) + ipfix (24)]) / DEFAULT_EXPORT_SIZE + */ +#define DEFAULT_EXPORT_RECORDS 7 + +always_inline ioam_export_buffer_t * +ioam_export_get_my_buffer (ioam_export_main_t * em, u32 thread_id) +{ + + if (vec_len (em->buffer_per_thread) > thread_id) + return (pool_elt_at_index + (em->buffer_pool, em->buffer_per_thread[thread_id])); + return (0); +} + +inline static int +ioam_export_buffer_add_header (ioam_export_main_t * em, vlib_buffer_t * b0) +{ + clib_memcpy (b0->data, em->record_header, vec_len (em->record_header)); + b0->current_data = 0; + b0->current_length = vec_len (em->record_header); + b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID; + return (1); +} + +inline static int +ioam_export_init_buffer (ioam_export_main_t * em, vlib_main_t * vm, + ioam_export_buffer_t * eb) +{ + vlib_buffer_t *b = 0; + + if (!eb) + return (-1); + /* TODO: Perhaps buffer init from template here */ + if (vlib_buffer_alloc (vm, &(eb->buffer_index), 1) != 1) + return (-2); + eb->records_in_this_buffer = 0; + eb->touched_at = vlib_time_now (vm); + b = vlib_get_buffer (vm, eb->buffer_index); + (void) ioam_export_buffer_add_header (em, b); + vnet_buffer (b)->sw_if_index[VLIB_RX] = 0; + vnet_buffer (b)->sw_if_index[VLIB_TX] = ~0; + return (1); +} + +inline static void +ioam_export_thread_buffer_free (ioam_export_main_t * em) +{ + vlib_main_t *vm = em->vlib_main; + ioam_export_buffer_t *eb = 0; + int i; + for (i = 0; i < vec_len (em->buffer_per_thread); i++) + { + eb = pool_elt_at_index (em->buffer_pool, em->buffer_per_thread[i]); + if (eb) + vlib_buffer_free (vm, &(eb->buffer_index), 1); + } + for (i = 0; i < vec_len (em->lockp); i++) + clib_mem_free ((void *) em->lockp[i]); + vec_free (em->buffer_per_thread); + pool_free (em->buffer_pool); + vec_free (em->lockp); + em->buffer_per_thread = 0; + em->buffer_pool = 0; + em->lockp = 0; +} + +inline static int +ioam_export_thread_buffer_init (ioam_export_main_t * em, vlib_main_t * vm) +{ + int no_of_threads = vec_len (vlib_worker_threads); + int i; + ioam_export_buffer_t *eb = 0; + vlib_node_t *ip4_lookup_node; + + pool_alloc_aligned (em->buffer_pool, + no_of_threads - 1, CLIB_CACHE_LINE_BYTES); + vec_validate_aligned (em->buffer_per_thread, + no_of_threads - 1, CLIB_CACHE_LINE_BYTES); + vec_validate_aligned (em->lockp, no_of_threads - 1, CLIB_CACHE_LINE_BYTES); + ip4_lookup_node = vlib_get_node_by_name (vm, (u8 *) "ip4-lookup"); + em->ip4_lookup_node_index = ip4_lookup_node->index; + if (!em->buffer_per_thread || !em->buffer_pool || !em->lockp) + { + return (-1); + } + for (i = 0; i < no_of_threads; i++) + { + eb = 0; + pool_get_aligned (em->buffer_pool, eb, CLIB_CACHE_LINE_BYTES); + memset (eb, 0, sizeof (*eb)); + em->buffer_per_thread[i] = eb - em->buffer_pool; + if (ioam_export_init_buffer (em, vm, eb) != 1) + { + ioam_export_thread_buffer_free (em); + return (-2); + } + em->lockp[i] = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, + CLIB_CACHE_LINE_BYTES); + memset ((void *) em->lockp[i], 0, CLIB_CACHE_LINE_BYTES); + } + return (1); +} + +#define IPFIX_IOAM_EXPORT_ID 272 + +/* Used to build the rewrite */ +/* data set packet */ +typedef struct +{ + ipfix_message_header_t h; + ipfix_set_header_t s; +} ipfix_data_packet_t; + +typedef struct +{ + ip4_header_t ip4; + udp_header_t udp; + ipfix_data_packet_t ipfix; +} ip4_ipfix_data_packet_t; + + +inline static void +ioam_export_header_cleanup (ioam_export_main_t * em, + ip4_address_t * collector_address, + ip4_address_t * src_address) +{ + vec_free (em->record_header); + em->record_header = 0; +} + +inline static int +ioam_export_header_create (ioam_export_main_t * em, + ip4_address_t * collector_address, + ip4_address_t * src_address) +{ + ip4_header_t *ip; + udp_header_t *udp; + ipfix_message_header_t *h; + ipfix_set_header_t *s; + u8 *rewrite = 0; + ip4_ipfix_data_packet_t *tp; + + + /* allocate rewrite space */ + vec_validate_aligned (rewrite, + sizeof (ip4_ipfix_data_packet_t) - 1, + CLIB_CACHE_LINE_BYTES); + + tp = (ip4_ipfix_data_packet_t *) rewrite; + ip = (ip4_header_t *) & tp->ip4; + udp = (udp_header_t *) (ip + 1); + h = (ipfix_message_header_t *) (udp + 1); + s = (ipfix_set_header_t *) (h + 1); + + ip->ip_version_and_header_length = 0x45; + ip->ttl = 254; + ip->protocol = IP_PROTOCOL_UDP; + ip->src_address.as_u32 = src_address->as_u32; + ip->dst_address.as_u32 = collector_address->as_u32; + udp->src_port = clib_host_to_net_u16 (4939 /* $$FIXME */ ); + udp->dst_port = clib_host_to_net_u16 (4939); + /* FIXUP: UDP length */ + udp->length = clib_host_to_net_u16 (vec_len (rewrite) + + (DEFAULT_EXPORT_RECORDS * + DEFAULT_EXPORT_SIZE) - sizeof (*ip)); + + /* FIXUP: message header export_time */ + /* FIXUP: message header sequence_number */ + h->domain_id = clib_host_to_net_u32 (em->domain_id); + + /*FIXUP: Setid length in octets if records exported are not default */ + s->set_id_length = ipfix_set_id_length (IPFIX_IOAM_EXPORT_ID, + (sizeof (*s) + + (DEFAULT_EXPORT_RECORDS * + DEFAULT_EXPORT_SIZE))); + + /* FIXUP: h version and length length in octets if records exported are not default */ + h->version_length = version_length (sizeof (*h) + + (sizeof (*s) + + (DEFAULT_EXPORT_RECORDS * + DEFAULT_EXPORT_SIZE))); + + /* FIXUP: ip length if records exported are not default */ + /* FIXUP: ip checksum if records exported are not default */ + ip->length = clib_host_to_net_u16 (vec_len (rewrite) + + (DEFAULT_EXPORT_RECORDS * + DEFAULT_EXPORT_SIZE)); + ip->checksum = ip4_header_checksum (ip); + _vec_len (rewrite) = sizeof (ip4_ipfix_data_packet_t); + em->record_header = rewrite; + return (1); +} + +inline static int +ioam_export_send_buffer (ioam_export_main_t * em, vlib_main_t * vm, + ioam_export_buffer_t * eb) +{ + ip4_header_t *ip; + udp_header_t *udp; + ipfix_message_header_t *h; + ipfix_set_header_t *s; + ip4_ipfix_data_packet_t *tp; + vlib_buffer_t *b0; + u16 new_l0, old_l0; + ip_csum_t sum0; + vlib_frame_t *nf = 0; + u32 *to_next; + + b0 = vlib_get_buffer (vm, eb->buffer_index); + tp = vlib_buffer_get_current (b0); + ip = (ip4_header_t *) & tp->ip4; + udp = (udp_header_t *) (ip + 1); + h = (ipfix_message_header_t *) (udp + 1); + s = (ipfix_set_header_t *) (h + 1); + + /* FIXUP: message header export_time */ + h->export_time = clib_host_to_net_u32 ((u32) + (((f64) em->unix_time_0) + + (vlib_time_now (em->vlib_main) - + em->vlib_time_0))); + + /* FIXUP: message header sequence_number */ + h->sequence_number = clib_host_to_net_u32 (em->sequence_number++); + + /* FIXUP: lengths if different from default */ + if (PREDICT_FALSE (eb->records_in_this_buffer != DEFAULT_EXPORT_RECORDS)) + { + s->set_id_length = + ipfix_set_id_length (IPFIX_IOAM_EXPORT_ID /* set_id */ , + b0->current_length - (sizeof (*ip) + + sizeof (*udp) + + sizeof (*h))); + h->version_length = + version_length (b0->current_length - (sizeof (*ip) + sizeof (*udp))); + sum0 = ip->checksum; + old_l0 = ip->length; + new_l0 = clib_host_to_net_u16 ((u16) b0->current_length); + sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t, + length /* changed member */ ); + ip->checksum = ip_csum_fold (sum0); + ip->length = new_l0; + udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip)); + } + + /* Enqueue pkts to ip4-lookup */ + + nf = vlib_get_frame_to_node (vm, em->ip4_lookup_node_index); + nf->n_vectors = 0; + to_next = vlib_frame_vector_args (nf); + nf->n_vectors = 1; + to_next[0] = eb->buffer_index; + vlib_put_frame_to_node (vm, em->ip4_lookup_node_index, nf); + return (1); + +} + +#define EXPORT_TIMEOUT (20.0) +#define THREAD_PERIOD (30.0) +inline static uword +ioam_export_process_common (ioam_export_main_t * em, vlib_main_t * vm, + vlib_node_runtime_t * rt, vlib_frame_t * f, + u32 index) +{ + f64 now; + f64 timeout = 30.0; + uword event_type; + uword *event_data = 0; + int i; + ioam_export_buffer_t *eb = 0, *new_eb = 0; + u32 *vec_buffer_indices = 0; + u32 *vec_buffer_to_be_sent = 0; + u32 *thread_index = 0; + u32 new_pool_index = 0; + + em->export_process_node_index = index; + /* Wait for Godot... */ + vlib_process_wait_for_event_or_clock (vm, 1e9); + event_type = vlib_process_get_events (vm, &event_data); + if (event_type != 1) + clib_warning ("bogus kickoff event received, %d", event_type); + vec_reset_length (event_data); + + while (1) + { + vlib_process_wait_for_event_or_clock (vm, timeout); + event_type = vlib_process_get_events (vm, &event_data); + switch (event_type) + { + case 2: /* Stop and Wait for kickoff again */ + timeout = 1e9; + break; + case 1: /* kickoff : Check for unsent buffers */ + timeout = THREAD_PERIOD; + break; + case ~0: /* timeout */ + break; + } + vec_reset_length (event_data); + now = vlib_time_now (vm); + /* + * Create buffers for threads that are not active enough + * to send out the export records + */ + for (i = 0; i < vec_len (em->buffer_per_thread); i++) + { + /* If the worker thread is processing export records ignore further checks */ + if (*em->lockp[i] == 1) + continue; + eb = pool_elt_at_index (em->buffer_pool, em->buffer_per_thread[i]); + if (eb->records_in_this_buffer > 0 + && now > (eb->touched_at + EXPORT_TIMEOUT)) + { + pool_get_aligned (em->buffer_pool, new_eb, + CLIB_CACHE_LINE_BYTES); + memset (new_eb, 0, sizeof (*new_eb)); + if (ioam_export_init_buffer (em, vm, new_eb) == 1) + { + new_pool_index = new_eb - em->buffer_pool; + vec_add (vec_buffer_indices, &new_pool_index, 1); + vec_add (vec_buffer_to_be_sent, &em->buffer_per_thread[i], + 1); + vec_add (thread_index, &i, 1); + } + else + { + pool_put (em->buffer_pool, new_eb); + /*Give up */ + goto CLEANUP; + } + } + } + if (vec_len (thread_index) != 0) + { + /* + * Now swap the buffers out + */ + for (i = 0; i < vec_len (thread_index); i++) + { + while (__sync_lock_test_and_set (em->lockp[thread_index[i]], 1)) + ; + em->buffer_per_thread[thread_index[i]] = + vec_pop (vec_buffer_indices); + *em->lockp[thread_index[i]] = 0; + } + + /* Send the buffers */ + for (i = 0; i < vec_len (vec_buffer_to_be_sent); i++) + { + eb = + pool_elt_at_index (em->buffer_pool, vec_buffer_to_be_sent[i]); + ioam_export_send_buffer (em, vm, eb); + pool_put (em->buffer_pool, eb); + } + } + + CLEANUP: + /* Free any leftover/unused buffers and everything that was allocated */ + for (i = 0; i < vec_len (vec_buffer_indices); i++) + { + new_eb = pool_elt_at_index (em->buffer_pool, vec_buffer_indices[i]); + vlib_buffer_free (vm, &new_eb->buffer_index, 1); + pool_put (em->buffer_pool, new_eb); + } + vec_free (vec_buffer_indices); + vec_free (vec_buffer_to_be_sent); + vec_free (thread_index); + } + return 0; /* not so much */ +} + +#define ioam_export_node_common(EM, VM, N, F, HTYPE, L, V, NEXT) \ +do { \ + u32 n_left_from, *from, *to_next; \ + export_next_t next_index; \ + u32 pkts_recorded = 0; \ + ioam_export_buffer_t *my_buf = 0; \ + vlib_buffer_t *eb0 = 0; \ + u32 ebi0 = 0; \ + from = vlib_frame_vector_args (F); \ + n_left_from = (F)->n_vectors; \ + next_index = (N)->cached_next_index; \ + while (__sync_lock_test_and_set ((EM)->lockp[(VM)->cpu_index], 1)); \ + my_buf = ioam_export_get_my_buffer (EM, (VM)->cpu_index); \ + my_buf->touched_at = vlib_time_now (VM); \ + while (n_left_from > 0) \ + { \ + u32 n_left_to_next; \ + vlib_get_next_frame (VM, N, next_index, to_next, n_left_to_next); \ + while (n_left_from >= 4 && n_left_to_next >= 2) \ + { \ + u32 next0 = NEXT; \ + u32 next1 = NEXT; \ + u32 bi0, bi1; \ + HTYPE *ip0, *ip1; \ + vlib_buffer_t *p0, *p1; \ + u32 ip_len0, ip_len1; \ + { \ + 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, 3 * CLIB_CACHE_LINE_BYTES, LOAD); \ + CLIB_PREFETCH (p3->data, 3 * CLIB_CACHE_LINE_BYTES, LOAD); \ + } \ + 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; \ + p0 = vlib_get_buffer (VM, bi0); \ + p1 = vlib_get_buffer (VM, bi1); \ + ip0 = vlib_buffer_get_current (p0); \ + ip1 = vlib_buffer_get_current (p1); \ + ip_len0 = \ + clib_net_to_host_u16 (ip0->L) + sizeof (HTYPE); \ + ip_len1 = \ + clib_net_to_host_u16 (ip1->L) + sizeof (HTYPE); \ + ebi0 = my_buf->buffer_index; \ + eb0 = vlib_get_buffer (VM, ebi0); \ + if (PREDICT_FALSE (eb0 == 0)) \ + goto NO_BUFFER1; \ + ip_len0 = \ + ip_len0 > DEFAULT_EXPORT_SIZE ? DEFAULT_EXPORT_SIZE : ip_len0; \ + ip_len1 = \ + ip_len1 > DEFAULT_EXPORT_SIZE ? DEFAULT_EXPORT_SIZE : ip_len1; \ + copy3cachelines (eb0->data + eb0->current_length, ip0, ip_len0); \ + eb0->current_length += DEFAULT_EXPORT_SIZE; \ + my_buf->records_in_this_buffer++; \ + if (my_buf->records_in_this_buffer >= DEFAULT_EXPORT_RECORDS) \ + { \ + ioam_export_send_buffer (EM, VM, my_buf); \ + ioam_export_init_buffer (EM, VM, my_buf); \ + } \ + ebi0 = my_buf->buffer_index; \ + eb0 = vlib_get_buffer (VM, ebi0); \ + if (PREDICT_FALSE (eb0 == 0)) \ + goto NO_BUFFER1; \ + copy3cachelines (eb0->data + eb0->current_length, ip1, ip_len1); \ + eb0->current_length += DEFAULT_EXPORT_SIZE; \ + my_buf->records_in_this_buffer++; \ + if (my_buf->records_in_this_buffer >= DEFAULT_EXPORT_RECORDS) \ + { \ + ioam_export_send_buffer (EM, VM, my_buf); \ + ioam_export_init_buffer (EM, VM, my_buf); \ + } \ + pkts_recorded += 2; \ + if (PREDICT_FALSE (((node)->flags & VLIB_NODE_FLAG_TRACE))) \ + { \ + if (p0->flags & VLIB_BUFFER_IS_TRACED) \ + { \ + export_trace_t *t = \ + vlib_add_trace (VM, node, p0, sizeof (*t)); \ + t->flow_label = \ + clib_net_to_host_u32 (ip0->V); \ + t->next_index = next0; \ + } \ + if (p1->flags & VLIB_BUFFER_IS_TRACED) \ + { \ + export_trace_t *t = \ + vlib_add_trace (VM, N, p1, sizeof (*t)); \ + t->flow_label = \ + clib_net_to_host_u32 (ip1->V); \ + t->next_index = next1; \ + } \ + } \ + NO_BUFFER1: \ + vlib_validate_buffer_enqueue_x2 (VM, N, 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 *p0; \ + u32 next0 = NEXT; \ + HTYPE *ip0; \ + u32 ip_len0; \ + bi0 = from[0]; \ + to_next[0] = bi0; \ + from += 1; \ + to_next += 1; \ + n_left_from -= 1; \ + n_left_to_next -= 1; \ + p0 = vlib_get_buffer (VM, bi0); \ + ip0 = vlib_buffer_get_current (p0); \ + ip_len0 = \ + clib_net_to_host_u16 (ip0->L) + sizeof (HTYPE); \ + ebi0 = my_buf->buffer_index; \ + eb0 = vlib_get_buffer (VM, ebi0); \ + if (PREDICT_FALSE (eb0 == 0)) \ + goto NO_BUFFER; \ + ip_len0 = \ + ip_len0 > DEFAULT_EXPORT_SIZE ? DEFAULT_EXPORT_SIZE : ip_len0; \ + copy3cachelines (eb0->data + eb0->current_length, ip0, ip_len0); \ + eb0->current_length += DEFAULT_EXPORT_SIZE; \ + my_buf->records_in_this_buffer++; \ + if (my_buf->records_in_this_buffer >= DEFAULT_EXPORT_RECORDS) \ + { \ + ioam_export_send_buffer (EM, VM, my_buf); \ + ioam_export_init_buffer (EM, VM, my_buf); \ + } \ + if (PREDICT_FALSE (((N)->flags & VLIB_NODE_FLAG_TRACE) \ + && (p0->flags & VLIB_BUFFER_IS_TRACED))) \ + { \ + export_trace_t *t = vlib_add_trace (VM, (N), p0, sizeof (*t)); \ + t->flow_label = \ + clib_net_to_host_u32 (ip0->V); \ + t->next_index = next0; \ + } \ + pkts_recorded += 1; \ + NO_BUFFER: \ + vlib_validate_buffer_enqueue_x1 (VM, N, next_index, \ + to_next, n_left_to_next, \ + bi0, next0); \ + } \ + vlib_put_next_frame (VM, N, next_index, n_left_to_next); \ + } \ + vlib_node_increment_counter (VM, export_node.index, \ + EXPORT_ERROR_RECORDED, pkts_recorded); \ + *(EM)->lockp[(VM)->cpu_index] = 0; \ +} while(0) + +#endif /* __included_ioam_export_h__ */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.api b/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.api new file mode 100644 index 00000000..7b17c3f7 --- /dev/null +++ b/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.api @@ -0,0 +1,42 @@ +/* Hey Emacs use -*- mode: C -*- */ +/* + * 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. + */ + +/* Define a simple binary API to control the feature */ + +define vxlan_gpe_ioam_export_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 is_disable; + + /* Collector ip address */ + u8 collector_address[4]; + u8 src_address[4]; + + /* Src ip address */ +}; + +define vxlan_gpe_ioam_export_enable_disable_reply { + /* From the request */ + u32 context; + + /* Return value, zero means all OK */ + i32 retval; +}; \ No newline at end of file diff --git a/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.c b/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.c new file mode 100644 index 00000000..bab8d977 --- /dev/null +++ b/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.c @@ -0,0 +1,271 @@ +/* + * 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. + */ +/* + *------------------------------------------------------------------ + * vxlan_gpe_ioam_export.c - ioam export API / debug CLI handling + *------------------------------------------------------------------ + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +/* define message IDs */ +#include + +/* define message structures */ +#define vl_typedefs +#include +#undef vl_typedefs + +/* define generated endian-swappers */ +#define vl_endianfun +#include +#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 +#undef vl_printfun + +/* Get the API version number */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#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_vxlan_gpe_ioam_export_plugin_api_msg \ +_(VXLAN_GPE_IOAM_EXPORT_ENABLE_DISABLE, vxlan_gpe_ioam_export_enable_disable) + +extern void vxlan_gpe_set_next_override (uword next); +/* Action function shared between message handler and debug CLI */ +int +vxlan_gpe_ioam_export_enable_disable (ioam_export_main_t * em, + u8 is_disable, + ip4_address_t * collector_address, + ip4_address_t * src_address) +{ + vlib_main_t *vm = em->vlib_main; + u32 node_index = export_node.index; + vlib_node_t *vxlan_gpe_decap_ioam_node = NULL; + + if (is_disable == 0) + { + if (em->my_hbh_slot == ~0) + { + /* Hook this export node to vxlan-gpe-decap-ioam-v4 */ + vxlan_gpe_decap_ioam_node = + vlib_get_node_by_name (vm, (u8 *) "vxlan-gpe-decap-ioam-v4"); + if (!vxlan_gpe_decap_ioam_node) + { + /* node does not exist give up */ + return (-1); + } + em->my_hbh_slot = + vlib_node_add_next (vm, vxlan_gpe_decap_ioam_node->index, + node_index); + } + if (1 == ioam_export_header_create (em, collector_address, src_address)) + { + ioam_export_thread_buffer_init (em, vm); + vxlan_gpe_set_next_override (em->my_hbh_slot); + /* Turn on the export buffer check process */ + vlib_process_signal_event (vm, em->export_process_node_index, 1, 0); + + } + else + { + return (-2); + } + } + else + { + vxlan_gpe_set_next_override (VXLAN_GPE_DECAP_IOAM_V4_NEXT_POP); + ioam_export_header_cleanup (em, collector_address, src_address); + ioam_export_thread_buffer_free (em); + /* Turn off the export buffer check process */ + vlib_process_signal_event (vm, em->export_process_node_index, 2, 0); + + } + + return 0; +} + +/* API message handler */ +static void vl_api_vxlan_gpe_ioam_export_enable_disable_t_handler + (vl_api_vxlan_gpe_ioam_export_enable_disable_t * mp) +{ + vl_api_vxlan_gpe_ioam_export_enable_disable_reply_t *rmp; + ioam_export_main_t *sm = &vxlan_gpe_ioam_export_main; + int rv; + + rv = vxlan_gpe_ioam_export_enable_disable (sm, (int) (mp->is_disable), + (ip4_address_t *) + mp->collector_address, + (ip4_address_t *) + mp->src_address); + + REPLY_MACRO (VL_API_VXLAN_GPE_IOAM_EXPORT_ENABLE_DISABLE_REPLY); +} /* API message handler */ + + + +/* Set up the API message handling tables */ +static clib_error_t * +vxlan_gpe_ioam_export_plugin_api_hookup (vlib_main_t * vm) +{ + ioam_export_main_t *sm = &vxlan_gpe_ioam_export_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_vxlan_gpe_ioam_export_plugin_api_msg; +#undef _ + + return 0; +} + + +static clib_error_t * +set_vxlan_gpe_ioam_export_ipfix_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + ioam_export_main_t *em = &vxlan_gpe_ioam_export_main; + ip4_address_t collector, src; + u8 is_disable = 0; + + collector.as_u32 = 0; + src.as_u32 = 0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "collector %U", unformat_ip4_address, &collector)) + ; + else if (unformat (input, "src %U", unformat_ip4_address, &src)) + ; + else if (unformat (input, "disable")) + is_disable = 1; + else + break; + } + + if (collector.as_u32 == 0) + return clib_error_return (0, "collector address required"); + + if (src.as_u32 == 0) + return clib_error_return (0, "src address required"); + + em->ipfix_collector.as_u32 = collector.as_u32; + em->src_address.as_u32 = src.as_u32; + + vlib_cli_output (vm, "Collector %U, src address %U", + format_ip4_address, &em->ipfix_collector, + format_ip4_address, &em->src_address); + + /* Turn on the export timer process */ + // vlib_process_signal_event (vm, flow_report_process_node.index, + //1, 0); + if (0 != + vxlan_gpe_ioam_export_enable_disable (em, is_disable, &collector, &src)) + { + return clib_error_return (0, "Unable to set ioam vxlan-gpe export"); + } + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (set_vxlan_gpe_ioam_ipfix_command, static) = +{ +.path = "set vxlan-gpe-ioam export ipfix", +.short_help = "set vxlan-gpe-ioam export ipfix collector src ", +.function = set_vxlan_gpe_ioam_export_ipfix_command_fn, +}; +/* *INDENT-ON* */ + + +static clib_error_t * +vxlan_gpe_ioam_export_init (vlib_main_t * vm) +{ + ioam_export_main_t *em = &vxlan_gpe_ioam_export_main; + clib_error_t *error = 0; + u8 *name; + + name = format (0, "vxlan_gpe_ioam_export_%08x%c", api_version, 0); + + /* Ask for a correctly-sized block of API message decode slots */ + em->msg_id_base = vl_msg_api_get_msg_ids + ((char *) name, VL_MSG_FIRST_AVAILABLE); + em->unix_time_0 = (u32) time (0); /* Store starting time */ + em->vlib_time_0 = vlib_time_now (vm); + + error = vxlan_gpe_ioam_export_plugin_api_hookup (vm); + em->my_hbh_slot = ~0; + em->vlib_main = vm; + em->vnet_main = vnet_get_main (); + vec_free (name); + + return error; +} + +VLIB_INIT_FUNCTION (vxlan_gpe_ioam_export_init); + + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_all_api_h.h b/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_all_api_h.h new file mode 100644 index 00000000..6d93f093 --- /dev/null +++ b/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_all_api_h.h @@ -0,0 +1,16 @@ +/* + * 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. + */ +/* Include the generated file, see BUILT_SOURCES in Makefile.am */ +#include diff --git a/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_msg_enum.h b/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_msg_enum.h new file mode 100644 index 00000000..cc5698de --- /dev/null +++ b/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_msg_enum.h @@ -0,0 +1,28 @@ +/* + * 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. + */ +#ifndef included_vxlan_gpe_ioam_export_msg_enum_h +#define included_vxlan_gpe_ioam_export_msg_enum_h + +#include + +#define vl_msg_id(n,h) n, +typedef enum { +#include + /* 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_vxlan_gpe_ioam_export_msg_enum_h */ diff --git a/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_test.c b/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_test.c new file mode 100644 index 00000000..494263d9 --- /dev/null +++ b/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_test.c @@ -0,0 +1,215 @@ +/* + * 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. + */ +/* + *------------------------------------------------------------------ + * vxlan_gpe_ioam_export_test.c - test harness plugin + *------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include + + +/* Declare message IDs */ +#include + +/* define message structures */ +#define vl_typedefs +#include +#undef vl_typedefs + +/* declare message handlers for each api */ + +#define vl_endianfun /* define message structures */ +#include +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) +#define vl_printfun +#include +#undef vl_printfun + +/* Get the API version number. */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#undef vl_api_version + + +typedef struct +{ + /* API message ID base */ + u16 msg_id_base; + vat_main_t *vat_main; +} export_test_main_t; + +export_test_main_t export_test_main; + +#define foreach_standard_reply_retval_handler \ +_(vxlan_gpe_ioam_export_enable_disable_reply) + +#define _(n) \ + static void vl_api_##n##_t_handler \ + (vl_api_##n##_t * mp) \ + { \ + vat_main_t * vam = export_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 \ +_(VXLAN_GPE_IOAM_EXPORT_ENABLE_DISABLE_REPLY, vxlan_gpe_ioam_export_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_vxlan_gpe_ioam_export_enable_disable (vat_main_t * vam) +{ + export_test_main_t *sm = &export_test_main; + unformat_input_t *i = vam->input; + f64 timeout; + int is_disable = 0; + vl_api_vxlan_gpe_ioam_export_enable_disable_t *mp; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "disable")) + is_disable = 1; + else + break; + } + + /* Construct the API message */ + M (VXLAN_GPE_IOAM_EXPORT_ENABLE_DISABLE, + vxlan_gpe_ioam_export_enable_disable); + mp->is_disable = is_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 \ +_(vxlan_gpe_ioam_export_enable_disable, " [disable]") + +void +vat_api_hookup (vat_main_t * vam) +{ + export_test_main_t *sm = &export_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) +{ + export_test_main_t *sm = &export_test_main; + u8 *name; + + sm->vat_main = vam; + + name = format (0, "vxlan_gpe_ioam_export_%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; +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_thread.c b/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_thread.c new file mode 100644 index 00000000..58508ebf --- /dev/null +++ b/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export_thread.c @@ -0,0 +1,49 @@ +/* + * 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. + */ +/* + * ioam_export_thread.c + */ +#include +#include +#include + +static vlib_node_registration_t vxlan_gpe_ioam_export_process_node; + +static uword +vxlan_gpe_ioam_export_process (vlib_main_t * vm, + vlib_node_runtime_t * rt, vlib_frame_t * f) +{ + return (ioam_export_process_common (&vxlan_gpe_ioam_export_main, + vm, rt, f, + vxlan_gpe_ioam_export_process_node.index)); +} + + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (vxlan_gpe_ioam_export_process_node, static) = +{ + .function = vxlan_gpe_ioam_export_process, + .type = VLIB_NODE_TYPE_PROCESS, + .name = "vxlan-gpe-ioam-export-process", +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_node.c b/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_node.c new file mode 100644 index 00000000..722c2b06 --- /dev/null +++ b/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_node.c @@ -0,0 +1,162 @@ +/* + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct +{ + u32 next_index; + u32 flow_label; +} export_trace_t; + +/* packet trace format function */ +static u8 * +format_export_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 *); + export_trace_t *t = va_arg (*args, export_trace_t *); + + s = format (s, "EXPORT: flow_label %d, next index %d", + t->flow_label, t->next_index); + return s; +} + +vlib_node_registration_t export_node; + +#define foreach_export_error \ +_(RECORDED, "Packets recorded for export") + +typedef enum +{ +#define _(sym,str) EXPORT_ERROR_##sym, + foreach_export_error +#undef _ + EXPORT_N_ERROR, +} export_error_t; + +static char *export_error_strings[] = { +#define _(sym,string) string, + foreach_export_error +#undef _ +}; + +typedef enum +{ + EXPORT_NEXT_VXLAN_GPE_INPUT, + EXPORT_N_NEXT, +} export_next_t; + +always_inline void +copy3cachelines (void *dst, const void *src, size_t n) +{ +#if 0 + if (PREDICT_FALSE (n < DEFAULT_EXPORT_SIZE)) + { + /* Copy only the first 1/2 cache lines whatever is available */ + if (n >= 64) + clib_mov64 ((u8 *) dst, (const u8 *) src); + if (n >= 128) + clib_mov64 ((u8 *) dst + 64, (const u8 *) src + 64); + return; + } + clib_mov64 ((u8 *) dst, (const u8 *) src); + clib_mov64 ((u8 *) dst + 64, (const u8 *) src + 64); + clib_mov64 ((u8 *) dst + 128, (const u8 *) src + 128); +#endif +#if 1 + + u64 *copy_dst, *copy_src; + int i; + copy_dst = (u64 *) dst; + copy_src = (u64 *) src; + if (PREDICT_FALSE (n < DEFAULT_EXPORT_SIZE)) + { + for (i = 0; i < n / 64; i++) + { + copy_dst[0] = copy_src[0]; + copy_dst[1] = copy_src[1]; + copy_dst[2] = copy_src[2]; + copy_dst[3] = copy_src[3]; + copy_dst[4] = copy_src[4]; + copy_dst[5] = copy_src[5]; + copy_dst[6] = copy_src[6]; + copy_dst[7] = copy_src[7]; + copy_dst += 8; + copy_src += 8; + } + return; + } + for (i = 0; i < 3; i++) + { + copy_dst[0] = copy_src[0]; + copy_dst[1] = copy_src[1]; + copy_dst[2] = copy_src[2]; + copy_dst[3] = copy_src[3]; + copy_dst[4] = copy_src[4]; + copy_dst[5] = copy_src[5]; + copy_dst[6] = copy_src[6]; + copy_dst[7] = copy_src[7]; + copy_dst += 8; + copy_src += 8; + } +#endif +} + + +static uword +vxlan_gpe_export_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + ioam_export_main_t *em = &vxlan_gpe_ioam_export_main; + ioam_export_node_common (em, vm, node, frame, ip4_header_t, length, + ip_version_and_header_length, + EXPORT_NEXT_VXLAN_GPE_INPUT); + return frame->n_vectors; +} + +/* + * Node for VXLAN-GPE export + */ +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (export_node) = +{ + .function = vxlan_gpe_export_node_fn, + .name = "vxlan-gpe-ioam-export", + .vector_size = sizeof (u32), + .format_trace = format_export_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (export_error_strings), + .error_strings = export_error_strings, + .n_next_nodes = EXPORT_N_NEXT, + /* edit / add dispositions here */ + .next_nodes = + {[EXPORT_NEXT_VXLAN_GPE_INPUT] = "vxlan-gpe-pop-ioam-v4"}, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/export/ioam_export.api b/src/plugins/ioam/export/ioam_export.api new file mode 100644 index 00000000..f22d9fc8 --- /dev/null +++ b/src/plugins/ioam/export/ioam_export.api @@ -0,0 +1,42 @@ +/* Hey Emacs use -*- mode: C -*- */ +/* + * 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. + */ + +/* Define a simple binary API to control the feature */ + +define ioam_export_ip6_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 is_disable; + + /* Collector ip address */ + u8 collector_address[4]; + u8 src_address[4]; + + /* Src ip address */ +}; + +define ioam_export_ip6_enable_disable_reply { + /* From the request */ + u32 context; + + /* Return value, zero means all OK */ + i32 retval; +}; diff --git a/src/plugins/ioam/export/ioam_export.c b/src/plugins/ioam/export/ioam_export.c new file mode 100644 index 00000000..b122e445 --- /dev/null +++ b/src/plugins/ioam/export/ioam_export.c @@ -0,0 +1,282 @@ +/* + * 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. + */ +/* + *------------------------------------------------------------------ + * ioam_export.c - ioam export API / debug CLI handling + *------------------------------------------------------------------ + */ + +#include +#include +#include + +#include +#include +#include +#include + + +/* define message IDs */ +#include + +/* define message structures */ +#define vl_typedefs +#include +#undef vl_typedefs + +/* define generated endian-swappers */ +#define vl_endianfun +#include +#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 +#undef vl_printfun + +/* Get the API version number */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#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_ioam_export_plugin_api_msg \ +_(IOAM_EXPORT_IP6_ENABLE_DISABLE, ioam_export_ip6_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) +{ + ioam_export_main_t *em = &ioam_export_main; + clib_error_t *error = 0; + + em->vlib_main = vm; + em->vnet_main = h->vnet_main; + + return error; +} + +/* Action function shared between message handler and debug CLI */ + +int +ioam_export_ip6_enable_disable (ioam_export_main_t * em, + u8 is_disable, + ip4_address_t * collector_address, + ip4_address_t * src_address) +{ + vlib_main_t *vm = em->vlib_main; + + if (is_disable == 0) + { + if (1 == ioam_export_header_create (em, collector_address, src_address)) + { + ioam_export_thread_buffer_init (em, vm); + ip6_hbh_set_next_override (em->my_hbh_slot); + /* Turn on the export buffer check process */ + vlib_process_signal_event (vm, em->export_process_node_index, 1, 0); + + } + else + { + return (-2); + } + } + else + { + ip6_hbh_set_next_override (IP6_LOOKUP_NEXT_POP_HOP_BY_HOP); + ioam_export_header_cleanup (em, collector_address, src_address); + ioam_export_thread_buffer_free (em); + /* Turn off the export buffer check process */ + vlib_process_signal_event (vm, em->export_process_node_index, 2, 0); + + } + + return 0; +} + +/* API message handler */ +static void vl_api_ioam_export_ip6_enable_disable_t_handler + (vl_api_ioam_export_ip6_enable_disable_t * mp) +{ + vl_api_ioam_export_ip6_enable_disable_reply_t *rmp; + ioam_export_main_t *sm = &ioam_export_main; + int rv; + + rv = ioam_export_ip6_enable_disable (sm, (int) (mp->is_disable), + (ip4_address_t *) + mp->collector_address, + (ip4_address_t *) mp->src_address); + + REPLY_MACRO (VL_API_IOAM_EXPORT_IP6_ENABLE_DISABLE_REPLY); +} + +/* Set up the API message handling tables */ +static clib_error_t * +ioam_export_plugin_api_hookup (vlib_main_t * vm) +{ + ioam_export_main_t *sm = &ioam_export_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_ioam_export_plugin_api_msg; +#undef _ + + return 0; +} + +#define vl_msg_name_crc_list +#include +#undef vl_msg_name_crc_list + +static void +setup_message_id_table (ioam_export_main_t * sm, api_main_t * am) +{ +#define _(id,n,crc) \ + vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base); + foreach_vl_msg_name_crc_ioam_export; +#undef _ +} + +static clib_error_t * +set_ioam_export_ipfix_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + ioam_export_main_t *em = &ioam_export_main; + ip4_address_t collector, src; + u8 is_disable = 0; + + collector.as_u32 = 0; + src.as_u32 = 0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "collector %U", unformat_ip4_address, &collector)) + ; + else if (unformat (input, "src %U", unformat_ip4_address, &src)) + ; + else if (unformat (input, "disable")) + is_disable = 1; + else + break; + } + + if (collector.as_u32 == 0) + return clib_error_return (0, "collector address required"); + + if (src.as_u32 == 0) + return clib_error_return (0, "src address required"); + + em->ipfix_collector.as_u32 = collector.as_u32; + em->src_address.as_u32 = src.as_u32; + + vlib_cli_output (vm, "Collector %U, src address %U", + format_ip4_address, &em->ipfix_collector, + format_ip4_address, &em->src_address); + + /* Turn on the export timer process */ + // vlib_process_signal_event (vm, flow_report_process_node.index, + //1, 0); + ioam_export_ip6_enable_disable (em, is_disable, &collector, &src); + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (set_ipfix_command, static) = +{ +.path = "set ioam export ipfix",.short_help = + "set ioam export ipfix collector src ",. + function = set_ioam_export_ipfix_command_fn,}; +/* *INDENT-ON* */ + + +static clib_error_t * +ioam_export_init (vlib_main_t * vm) +{ + ioam_export_main_t *em = &ioam_export_main; + clib_error_t *error = 0; + u8 *name; + u32 node_index = export_node.index; + vlib_node_t *ip6_hbyh_node = NULL; + + name = format (0, "ioam_export_%08x%c", api_version, 0); + + /* Ask for a correctly-sized block of API message decode slots */ + em->msg_id_base = vl_msg_api_get_msg_ids + ((char *) name, VL_MSG_FIRST_AVAILABLE); + em->unix_time_0 = (u32) time (0); /* Store starting time */ + em->vlib_time_0 = vlib_time_now (vm); + + error = ioam_export_plugin_api_hookup (vm); + + /* Add our API messages to the global name_crc hash table */ + setup_message_id_table (em, &api_main); + + /* Hook this export node to ip6-hop-by-hop */ + ip6_hbyh_node = vlib_get_node_by_name (vm, (u8 *) "ip6-hop-by-hop"); + em->my_hbh_slot = vlib_node_add_next (vm, ip6_hbyh_node->index, node_index); + vec_free (name); + + return error; +} + +VLIB_INIT_FUNCTION (ioam_export_init); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/export/ioam_export_all_api_h.h b/src/plugins/ioam/export/ioam_export_all_api_h.h new file mode 100644 index 00000000..bc4368f2 --- /dev/null +++ b/src/plugins/ioam/export/ioam_export_all_api_h.h @@ -0,0 +1,16 @@ +/* + * 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. + */ +/* Include the generated file, see BUILT_SOURCES in Makefile.am */ +#include diff --git a/src/plugins/ioam/export/ioam_export_msg_enum.h b/src/plugins/ioam/export/ioam_export_msg_enum.h new file mode 100644 index 00000000..c2de7988 --- /dev/null +++ b/src/plugins/ioam/export/ioam_export_msg_enum.h @@ -0,0 +1,28 @@ +/* + * 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. + */ +#ifndef included_ioam_export_msg_enum_h +#define included_ioam_export_msg_enum_h + +#include + +#define vl_msg_id(n,h) n, +typedef enum { +#include + /* 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_ioam_export_msg_enum_h */ diff --git a/src/plugins/ioam/export/ioam_export_test.c b/src/plugins/ioam/export/ioam_export_test.c new file mode 100644 index 00000000..f991fc0c --- /dev/null +++ b/src/plugins/ioam/export/ioam_export_test.c @@ -0,0 +1,206 @@ +/* + * 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. + */ +/* + *------------------------------------------------------------------ + * ioam_export_test.c - test harness plugin + *------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include + + +/* Declare message IDs */ +#include + +/* define message structures */ +#define vl_typedefs +#include +#undef vl_typedefs + +/* declare message handlers for each api */ + +#define vl_endianfun /* define message structures */ +#include +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) +#define vl_printfun +#include +#undef vl_printfun + +/* Get the API version number. */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#undef vl_api_version + + +typedef struct +{ + /* API message ID base */ + u16 msg_id_base; + vat_main_t *vat_main; +} export_test_main_t; + +export_test_main_t export_test_main; + +#define foreach_standard_reply_retval_handler \ +_(ioam_export_ip6_enable_disable_reply) + +#define _(n) \ + static void vl_api_##n##_t_handler \ + (vl_api_##n##_t * mp) \ + { \ + vat_main_t * vam = export_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 \ +_(IOAM_EXPORT_IP6_ENABLE_DISABLE_REPLY, ioam_export_ip6_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_ioam_export_ip6_enable_disable (vat_main_t * vam) +{ + export_test_main_t *sm = &export_test_main; + unformat_input_t *i = vam->input; + f64 timeout; + int is_disable = 0; + vl_api_ioam_export_ip6_enable_disable_t *mp; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "disable")) + is_disable = 1; + else + break; + } + + /* Construct the API message */ + M (IOAM_EXPORT_IP6_ENABLE_DISABLE, ioam_export_ip6_enable_disable); + mp->is_disable = is_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 \ +_(ioam_export_ip6_enable_disable, " [disable]") + +void +vat_api_hookup (vat_main_t * vam) +{ + export_test_main_t *sm = &export_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) +{ + export_test_main_t *sm = &export_test_main; + u8 *name; + + sm->vat_main = vam; + + name = format (0, "ioam_export_%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/src/plugins/ioam/export/ioam_export_thread.c b/src/plugins/ioam/export/ioam_export_thread.c new file mode 100644 index 00000000..d2eb2009 --- /dev/null +++ b/src/plugins/ioam/export/ioam_export_thread.c @@ -0,0 +1,38 @@ +/* + * 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. + */ +/* + * ioam_export_thread.c + */ +#include +#include +#include + +static vlib_node_registration_t ioam_export_process_node; + +static uword +ioam_export_process (vlib_main_t * vm, + vlib_node_runtime_t * rt, vlib_frame_t * f) +{ + return (ioam_export_process_common(&ioam_export_main, + vm, rt, f, + ioam_export_process_node.index)); +} + +VLIB_REGISTER_NODE (ioam_export_process_node, static) = +{ + .function = ioam_export_process, + .type = VLIB_NODE_TYPE_PROCESS, + .name = "ioam-export-process", +}; diff --git a/src/plugins/ioam/export/node.c b/src/plugins/ioam/export/node.c new file mode 100644 index 00000000..19f143df --- /dev/null +++ b/src/plugins/ioam/export/node.c @@ -0,0 +1,151 @@ +/* + * 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. + */ +#include +#include +#include +#include +#include +#include + +typedef struct +{ + u32 next_index; + u32 flow_label; +} export_trace_t; + +/* packet trace format function */ +static u8 * +format_export_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 *); + export_trace_t *t = va_arg (*args, export_trace_t *); + + s = format (s, "EXPORT: flow_label %d, next index %d", + t->flow_label, t->next_index); + return s; +} + +vlib_node_registration_t export_node; + +#define foreach_export_error \ +_(RECORDED, "Packets recorded for export") + +typedef enum +{ +#define _(sym,str) EXPORT_ERROR_##sym, + foreach_export_error +#undef _ + EXPORT_N_ERROR, +} export_error_t; + +static char *export_error_strings[] = { +#define _(sym,string) string, + foreach_export_error +#undef _ +}; + +typedef enum +{ + EXPORT_NEXT_POP_HBYH, + EXPORT_N_NEXT, +} export_next_t; + +always_inline void +copy3cachelines (void *dst, const void *src, size_t n) +{ +#if 0 + if (PREDICT_FALSE (n < DEFAULT_EXPORT_SIZE)) + { + /* Copy only the first 1/2 cache lines whatever is available */ + if (n >= 64) + clib_mov64 ((u8 *) dst, (const u8 *) src); + if (n >= 128) + clib_mov64 ((u8 *) dst + 64, (const u8 *) src + 64); + return; + } + clib_mov64 ((u8 *) dst, (const u8 *) src); + clib_mov64 ((u8 *) dst + 64, (const u8 *) src + 64); + clib_mov64 ((u8 *) dst + 128, (const u8 *) src + 128); +#endif +#if 1 + + u64 *copy_dst, *copy_src; + int i; + copy_dst = (u64 *) dst; + copy_src = (u64 *) src; + if (PREDICT_FALSE (n < DEFAULT_EXPORT_SIZE)) + { + for (i = 0; i < n / 64; i++) + { + copy_dst[0] = copy_src[0]; + copy_dst[1] = copy_src[1]; + copy_dst[2] = copy_src[2]; + copy_dst[3] = copy_src[3]; + copy_dst[4] = copy_src[4]; + copy_dst[5] = copy_src[5]; + copy_dst[6] = copy_src[6]; + copy_dst[7] = copy_src[7]; + copy_dst += 8; + copy_src += 8; + } + return; + } + for (i = 0; i < 3; i++) + { + copy_dst[0] = copy_src[0]; + copy_dst[1] = copy_src[1]; + copy_dst[2] = copy_src[2]; + copy_dst[3] = copy_src[3]; + copy_dst[4] = copy_src[4]; + copy_dst[5] = copy_src[5]; + copy_dst[6] = copy_src[6]; + copy_dst[7] = copy_src[7]; + copy_dst += 8; + copy_src += 8; + } +#endif +} + +static uword +ip6_export_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + ioam_export_main_t *em = &ioam_export_main; + ioam_export_node_common(em, vm, node, frame, ip6_header_t, payload_length, + ip_version_traffic_class_and_flow_label, + EXPORT_NEXT_POP_HBYH); + return frame->n_vectors; +} + +/* + * Node for IP6 export + */ +VLIB_REGISTER_NODE (export_node) = +{ + .function = ip6_export_node_fn, + .name = "ip6-export", + .vector_size = sizeof (u32), + .format_trace = format_export_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (export_error_strings), + .error_strings = export_error_strings, + .n_next_nodes = EXPORT_N_NEXT, + /* edit / add dispositions here */ + .next_nodes = + { + [EXPORT_NEXT_POP_HBYH] = "ip6-pop-hop-by-hop" + }, +}; diff --git a/src/plugins/ioam/ioam_plugin_doc.md b/src/plugins/ioam/ioam_plugin_doc.md new file mode 100644 index 00000000..343abcf7 --- /dev/null +++ b/src/plugins/ioam/ioam_plugin_doc.md @@ -0,0 +1,464 @@ +## VPP Inband OAM (iOAM) {#ioam_plugin_doc} + +In-band OAM (iOAM) is an implementation study to record operational +information in the packet while the packet traverses a path between +two points in the network. + +Overview of iOAM can be found in [iOAM-Devnet] page. +The following IETF drafts detail the motivation and mechanism for +recording operational information: + - [iOAM-ietf-requirements] - Describes motivation and usecases for iOAM + - [iOAM-ietf-data] - Describes data records that can be collected using iOAM + - [iOAM-ietf-transport] - Lists out the transport protocols + and mechanism to carry iOAM data records + - [iOAM-ietf-proof-of-transit] - Describes the idea of Proof of Transit (POT) + and mechanisms to operationalize the idea + +## Terminology +In-band OAM is expected to be deployed in a specific domain rather +than on the overall Internet. The part of the network which employs in-band OAM +is referred to as **"in-band OAM-domain"**. + +In-band OAM data is added to a packet on entering the in-band OAM-domain +and is removed from the packet when exiting the domain. +Within the in-band OAM-domain, network nodes that the packet traverses +may update the in-band OAM data records. + +- The node which adds in-band OAM data to the packet is called the +**"in-band OAM encapsulating node"**. + +- The node which removes the in-band OAM data is referred to as the +**"in-band OAM decapsulating node"**. + +- Nodes within the domain which are aware of in-band OAM data and read +and/or write or process the in-band OAM data are called +**"in-band OAM transit nodes"**. + +## Features supported in the current release +VPP can function as in-band OAM encapsulating, transit and decapsulating node. +In this version of VPP in-band OAM data is transported as options in an +IPv6 hop-by-hop extension header. Hence in-band OAM can be enabled +for IPv6 traffic. + +The following iOAM features are supported: + +- **In-band OAM Tracing** : In-band OAM supports multiple data records to be +recorded in the packet as the packet traverses the network. +These data records offer insights into the operational behavior of the network. +The following information can be collected in the tracing +data from the nodes a packet traverses: + - Node ID + - Ingress interface ID + - Egress interface ID + - Timestamp + - Pre-configured application data + +- **In-band OAM Proof of Transit (POT)**: Proof of transit iOAM data is +added to every packet for verifying that a packet traverses a specific +set of nodes. +In-band OAM data is updated at every node that is enabled with iOAM +proof of transit and is used to verify whether a packet traversed +all the specified nodes. When the verifier receives each packet, +it can validate whether the packet traversed the specified nodes. + + +## Configuration +Configuring iOAM involves: +- Selecting the packets for which iOAM data must be inserted, updated or removed + - Selection of packets for iOAM data insertion on iOAM encapsulating node. + Selection of packets is done by 5-tuple based classification + - Selection of packets for updating iOAM data is implicitly done on the + presence of iOAM options in the packet + - Selection of packets for removing the iOAM data is done on 5-tuple + based classification +- The kind of data to be collected + - Tracing data + - Proof of transit +- Additional details for processing iOAM data to be collected + - For trace data - trace type, number of nodes to be recorded in the trace, + time stamp precision, etc. + - For POT data - configuration of POT profile required to process the POT data + +The CLI for configuring iOAM is explained here followed by detailed steps +and examples to deploy iOAM on VPP as an encapsulating, transit or +decapsulating iOAM node in the subsequent sub-sections. + +VPP iOAM configuration for enabling trace and POT is as follows: + + set ioam rewrite trace-type <0x1f|0x7|0x9|0x11|0x19> + trace-elts trace-tsp <0|1|2|3> + node-id app-data [pot] + +A description of each of the options of the CLI follows: +- trace-type : An entry in the "Node data List" array of the trace option +can have different formats, following the needs of the a deployment. +For example: Some deployments might only be interested +in recording the node identifiers, whereas others might be interested +in recording node identifier and timestamp. +The following types are currently supported: + - 0x1f : Node data to include hop limit (8 bits), node ID (24 bits), + ingress and egress interface IDs (16 bits each), timestamp (32 bits), + application data (32 bits) + - 0x7 : Node data to include hop limit (8 bits), node ID (24 bits), + ingress and egress interface IDs (16 bits each) + - 0x9 : Node data to include hop limit (8 bits), node ID (24 bits), + timestamp (32 bits) + - 0x11: Node data to include hop limit (8 bits), node ID (24 bits), + application data (32 bits) + - 0x19: Node data to include hop limit (8 bits), node ID (24 bits), + timestamp (32 bits), application data (32 bits) +- trace-elts : Defines the length of the node data array in the trace option. +- trace-tsp : Defines the timestamp precision to use with the enumerated value + for precision as follows: + - 0 : 32bits timestamp in seconds + - 1 : 32bits timestamp in milliseconds + - 2 : 32bits timestamp in microseconds + - 3 : 32bits timestamp in nanoseconds +- node-id : Unique identifier for the node, included in the node ID + field of the node data in trace option. +- app-data : The value configured here is included as is in +application data field of node data in trace option. +- pot : Enables POT option to be included in the iOAM options. + +### Trace configuration + +#### On in-band OAM encapsulating node + - **Configure classifier and apply ACL** to select packets for + iOAM data insertion + - Example to enable iOAM data insertion for all the packets + towards IPv6 address db06::06: + + vpp# classify table miss-next node ip6-lookup mask l3 ip6 dst + + vpp# classify session acl-hit-next node ip6-add-hop-by-hop + table-index 0 match l3 ip6 dst db06::06 + + vpp# set int input acl intfc GigabitEthernet0/0/0 ip6-table 0 + + - **Enable tracing** : Specify node ID, maximum number of nodes for which + trace data should be recorded, type of data to be included for recording, + optionally application data to be included + - Example to enable tracing with a maximum of 4 nodes recorded + and the data to be recorded to include - hop limit, node id, + ingress and egress interface IDs, timestamp (millisecond precision), + application data (0x1234): + + + vpp# set ioam rewrite trace-type 0x1f trace-elts 4 trace-tsp 1 + node-id 0x1 app-data 0x1234 + + + +#### On in-band OAM transit node +- The transit node requires trace type, timestamp precision, node ID and +optionally application data to be configured, +to update its node data in the trace option. + +Example: + + vpp# set ioam rewrite trace-type 0x1f trace-elts 4 trace-tsp 1 + node-id 0x2 app-data 0x1234 + +#### On the In-band OAM decapsulating node +- The decapsulating node similar to encapsulating node requires +**classification** of the packets to remove iOAM data from. + - Example to decapsulate iOAM data for packets towards + db06::06, configure classifier and enable it as an ACL as follows: + + + vpp# classify table miss-next node ip6-lookup mask l3 ip6 dst + + vpp# classify session acl-hit-next node ip6-lookup table-index 0 + match l3 ip6 dst db06::06 opaque-index 100 + + vpp# set int input acl intfc GigabitEthernet0/0/0 ip6-table 0 + + +- Decapsulating node requires trace type, timestamp precision, +node ID and optionally application data to be configured, +to update its node data in the trace option before it is decapsulated. + +Example: + + vpp# set ioam rewrite trace-type 0x1f trace-elts 4 + trace-tsp 1 node-id 0x3 app-data 0x1234 + + +### Proof of Transit configuration + +For details on proof-of-transit, +see the IETF draft [iOAM-ietf-proof-of-transit]. +To enable Proof of Transit all the nodes that participate +and hence are verified for transit need a proof of transit profile. +A script to generate a proof of transit profile as per the mechanism +described in [iOAM-ietf-proof-of-transit] will be available at [iOAM-Devnet]. + +The Proof of transit mechanism implemented here is based on +Shamir's Secret Sharing algorithm. +The overall algorithm uses two polynomials +POLY-1 and POLY-2. The degree of polynomials depends on number of nodes +to be verified for transit. +POLY-1 is secret and constant. Each node gets a point on POLY-1 +at setup-time and keeps it secret. +POLY-2 is public, random and per packet. +Each node is assigned a point on POLY-1 and POLY-2 with the same x index. +Each node derives its point on POLY-2 each time a packet arrives at it. +A node then contributes its points on POLY-1 and POLY-2 to construct +POLY-3 (POLY-3 = POLY-1 + POLY-2) using lagrange extrapolation and +forwards it towards the verifier by updating POT data in the packet. +The verifier constructs POLY-3 from the accumulated value from all the nodes +and its own points on POLY-1 and POLY-2 and verifies whether +POLY-3 = POLY-1 + POLY-2. Only the verifier knows POLY-1. +The solution leverages finite field arithmetic in a field of size "prime number" +for reasons explained in description of Shamir's secret sharing algorithm. + +Here is an explanation of POT profile list and profile configuration CLI to +realize the above mechanism. +It is best to use the script provided at [iOAM-Devnet] to generate +this configuration. +- **Create POT profile** : set pot profile name id [0-1] +[validator-key 0xu64] prime-number 0xu64 secret_share 0xu64 +lpc 0xu64 polynomial2 0xu64 bits-in-random [0-64] + - name : Profile list name. + - id : Profile id, it can be 0 or 1. + A maximum of two profiles can be configured per profile list. + - validator-key : Secret key configured only on the + verifier/decapsulating node used to compare and verify proof of transit. + - prime-number : Prime number for finite field arithmetic as required by the + proof of transit mechanism. + - secret_share : Unique point for each node on the secret polynomial POLY-1. + - lpc : Lagrange Polynomial Constant(LPC) calculated per node based on + its point (x value used for evaluating the points on the polynomial) + on the polynomial used in lagrange extrapolation + for reconstructing polynomial (POLY-3). + - polynomial2 : Is the pre-evaluated value of the point on + 2nd polynomial(POLY-2). This is unique for each node. + It is pre-evaluated for all the coefficients of POLY-2 except + for the constant part of the polynomial that changes per packet + and is received as part of the POT data in the packet. + - bits-in-random : To control the size of the random number to be + generated. This number has to match the other numbers generated and used + in the profile as per the algorithm. + +- **Set a configured profile as active/in-use** : +set pot profile-active name ID [0-1] + - name : Name of the profile list to be used for computing + POT data per packet. + - ID : Identifier of the profile within the list to be used. + +#### On In-band OAM encapsulating node + - Configure the classifier and apply ACL to select packets for iOAM data insertion. + - Example to enable iOAM data insertion for all the packet towards + IPv6 address db06::06 - + + + vpp# classify table miss-next node ip6-lookup mask l3 ip6 dst + + vpp# classify session acl-hit-next node + ip6-add-hop-by-hop table-index 0 match l3 ip6 dst db06::06 + + vpp# set int input acl intfc GigabitEthernet0/0/0 ip6-table 0 + + + - Configure the proof of transit profile list with profiles. +Each profile list referred to by a name can contain 2 profiles, +only one is in use for updating proof of transit data at any time. + - Example profile list example with a profile generated from the + script to verify transit through 3 nodes is: + + + vpp# set pot profile name example id 0 prime-number 0x7fff0000fa884685 + secret_share 0x6c22eff0f45ec56d lpc 0x7fff0000fa884682 + polynomial2 0xffb543d4a9c bits-in-random 63 + + - Enable one of the profiles from the configured profile list as active + so that is will be used for calculating proof of transit + +Example enable profile ID 0 from profile list example configured above: + + + vpp# set pot profile-active name example ID 0 + + + - Enable POT option to be inserted + + + vpp# set ioam rewrite pot + + +#### On in-band OAM transit node + - Configure the proof of transit profile list with profiles for transit node. +Example: + + + vpp# set pot profile name example id 0 prime-number 0x7fff0000fa884685 + secret_share 0x564cdbdec4eb625d lpc 0x1 + polynomial2 0x23f3a227186a bits-in-random 63 + +#### On in-band OAM decapsulating node / verifier +- The decapsulating node, similar to the encapsulating node requires +classification of the packets to remove iOAM data from. + - Example to decapsulate iOAM data for packets towards db06::06 + configure classifier and enable it as an ACL as follows: + + + vpp# classify table miss-next node ip6-lookup mask l3 ip6 dst + + vpp# classify session acl-hit-next node ip6-lookup table-index 0 + match l3 ip6 dst db06::06 opaque-index 100 + + vpp# set int input acl intfc GigabitEthernet0/0/0 ip6-table 0 + +- To update and verify the proof of transit, POT profile list should be configured. + - Example POT profile list configured as follows: + + vpp# set pot profile name example id 0 validate-key 0x7fff0000fa88465d + prime-number 0x7fff0000fa884685 secret_share 0x7a08fbfc5b93116d lpc 0x3 + polynomial2 0x3ff738597ce bits-in-random 63 + +## Operational data + +Following CLIs are available to check iOAM operation: +- To check iOAM configuration that are effective use "show ioam summary" + +Example: + + vpp# show ioam summary + REWRITE FLOW CONFIGS - Not configured + HOP BY HOP OPTIONS - TRACE CONFIG - + Trace Type : 0x1f (31) + Trace timestamp precision : 1 (Milliseconds) + Num of trace nodes : 4 + Node-id : 0x2 (2) + App Data : 0x1234 (4660) + POT OPTION - 1 (Enabled) + Try 'show ioam pot and show pot profile' for more information + +- To find statistics about packets for which iOAM options were +added (encapsulating node) and removed (decapsulating node) execute +*show errors* + +Example on encapsulating node: + + + vpp# show error + Count Node Reason + 1208804706 ip6-inacl input ACL hits + 1208804706 ip6-add-hop-by-hop Pkts w/ added ip6 hop-by-hop options + +Example on decapsulating node: + + vpp# show error + Count Node Reason + 69508569 ip6-inacl input ACL hits + 69508569 ip6-pop-hop-by-hop Pkts w/ removed ip6 hop-by-hop options + +- To check the POT profiles use "show pot profile" + +Example: + + vpp# show pot profile + Profile list in use : example + POT Profile at index: 0 + ID : 0 + Validator : False (0) + Secret share : 0x564cdbdec4eb625d (6218586935324795485) + Prime number : 0x7fff0000fa884685 (9223090566081300101) + 2nd polynomial(eval) : 0x23f3a227186a (39529304496234) + LPC : 0x1 (1) + Bit mask : 0x7fffffffffffffff (9223372036854775807) + Profile index in use: 0 + Pkts passed : 0x36 (54) + +- To get statistics of POT for packets use "show ioam pot" + +Example at encapsulating or transit node: + + vpp# show ioam pot + Pkts with ip6 hop-by-hop POT options - 54 + Pkts with ip6 hop-by-hop POT options but no profile set - 0 + Pkts with POT in Policy - 0 + Pkts with POT out of Policy - 0 + + +Example at decapsulating/verification node: + + + vpp# show ioam pot + Pkts with ip6 hop-by-hop POT options - 54 + Pkts with ip6 hop-by-hop POT options but no profile set - 0 + Pkts with POT in Policy - 54 + Pkts with POT out of Policy - 0 + +- Tracing - enable trace of IPv6 packets to view the data inserted and +collected. + +Example when the nodes are receiving data over a DPDK interface: +Enable tracing using "trace add dpdk-input 20" and +execute "show trace" to view the iOAM data collected: + + + vpp# trace add dpdk-input 20 + + vpp# show trace + + ------------------- Start of thread 0 vpp_main ------------------- + + Packet 1 + + 00:00:19:294697: dpdk-input + GigabitEthernetb/0/0 rx queue 0 + buffer 0x10e6b: current data 0, length 214, free-list 0, totlen-nifb 0, trace 0x0 + PKT MBUF: port 0, nb_segs 1, pkt_len 214 + buf_len 2176, data_len 214, ol_flags 0x0, data_off 128, phys_addr 0xe9a35a00 + packet_type 0x0 + IP6: 00:50:56:9c:df:72 -> 00:50:56:9c:be:55 + IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 + tos 0x00, flow label 0x0, hop limit 63, payload length 160 + 00:00:19:294737: ethernet-input + IP6: 00:50:56:9c:df:72 -> 00:50:56:9c:be:55 + 00:00:19:294753: ip6-input + IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 + tos 0x00, flow label 0x0, hop limit 63, payload length 160 + 00:00:19:294757: ip6-lookup + fib 0 adj-idx 15 : indirect via db05::2 flow hash: 0x00000000 + IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 + tos 0x00, flow label 0x0, hop limit 63, payload length 160 + 00:00:19:294802: ip6-hop-by-hop + IP6_HOP_BY_HOP: next index 5 len 96 traced 96 Trace Type 0x1f , 1 elts left + [0] ttl 0x0 node ID 0x0 ingress 0x0 egress 0x0 ts 0x0 + app 0x0 + [1] ttl 0x3e node ID 0x3 ingress 0x1 egress 0x2 ts 0xb68c2213 + app 0x1234 + [2] ttl 0x3f node ID 0x2 ingress 0x1 egress 0x2 ts 0xb68c2204 + app 0x1234 + [3] ttl 0x40 node ID 0x1 ingress 0x5 egress 0x6 ts 0xb68c2200 + app 0x1234 + POT opt present + random = 0x577a916946071950, Cumulative = 0x10b46e78a35a392d, Index = 0x0 + 00:00:19:294810: ip6-rewrite + tx_sw_if_index 1 adj-idx 14 : GigabitEthernetb/0/0 + IP6: 00:50:56:9c:be:55 -> 00:50:56:9c:df:72 flow hash: 0x00000000 + IP6: 00:50:56:9c:be:55 -> 00:50:56:9c:df:72 + IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 + tos 0x00, flow label 0x0, hop limit 62, payload length 160 + 00:00:19:294814: GigabitEthernetb/0/0-output + GigabitEthernetb/0/0 + IP6: 00:50:56:9c:be:55 -> 00:50:56:9c:df:72 + IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 + tos 0x00, flow label 0x0, hop limit 62, payload length 160 + 00:00:19:294820: GigabitEthernetb/0/0-tx + GigabitEthernetb/0/0 tx queue 0 + buffer 0x10e6b: current data 0, length 214, free-list 0, totlen-nifb 0, trace 0x0 + IP6: 00:50:56:9c:be:55 -> 00:50:56:9c:df:72 + + IP6_HOP_BY_HOP_OPTIONS: db05::2 -> db06::6 + + tos 0x00, flow label 0x0, hop limit 62, payload length 160 + + +[iOAM-Devnet]: +[iOAM-ietf-requirements]: +[iOAM-ietf-transport]: +[iOAM-ietf-data]: +[iOAM-ietf-proof-of-transit]: diff --git a/src/plugins/ioam/lib-pot/math64.h b/src/plugins/ioam/lib-pot/math64.h new file mode 100644 index 00000000..4c608a37 --- /dev/null +++ b/src/plugins/ioam/lib-pot/math64.h @@ -0,0 +1,159 @@ +/* + * math64.h provides the 64 bit unsigned integer add, multiply followed by modulo operation + * The linux/math64.h provides divide and multiply 64 bit integers but: + * 1. multiply: mul_u64_u64_shr - only returns 64 bits of the result and has to be called + * twice to get the complete 128 bits of the result. + * 2. Modulo operation of the result of addition and multiplication of u64 that may result + * in integers > 64 bits is not supported + * Hence this header to combine add/multiply followed by modulo of u64 integrers + * always resulting in u64. + * + * 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. + */ +#ifndef include_vnet_math64_h +#define include_vnet_math64_h +#include + +/* + * multiplies and returns result in hi and lo + */ +static inline void mul64by64(u64 a, u64 b, u64 * hi, u64 * lo) +{ + u64 a_lo = (u64) (uint32_t) a; + u64 a_hi = a >> 32; + u64 b_lo = (u64) (u32) b; + u64 b_hi = b >> 32; + + u64 p0 = a_lo * b_lo; + u64 p1 = a_lo * b_hi; + u64 p2 = a_hi * b_lo; + u64 p3 = a_hi * b_hi; + + u32 cy = (u32) (((p0 >> 32) + (u32) p1 + (u32) p2) >> 32); + + *lo = p0 + (p1 << 32) + (p2 << 32); + *hi = p3 + (p1 >> 32) + (p2 >> 32) + cy; + return; +} + +#define TWO64 18446744073709551616.0 + +static inline u64 mod128by64(u64 x, u64 y, u64 m, double di) +{ + u64 q1, q2, q; + u64 p1, p0; + double dq; + + /* calculate quotient first pass 53 bits */ + dq = (TWO64 * (double)x + (double)y) * di; + + if (dq >= TWO64) + q1 = 0xfffffffffffff800L; + else + q1 = dq; + + /* q1 * m to compare the product to the dividend. */ + mul64by64(q1, m, &p1, &p0); + + /* Adjust quotient. is it > actual result: */ + if (x < p1 || (x == p1 && y < p0)) + { + /* q1 > quotient. calculate abs remainder */ + x = p1 - (x + (p0 < y)); + y = p0 - y; + + /* use the remainder as new dividend to adjust quotient */ + q2 = (u64) ((TWO64 * (double)x + (double)y) * di); + mul64by64(q2, m, &p1, &p0); + + q = q1 - q2; + if (x < p1 || (x == p1 && y <= p0)) + { + y = p0 - y; + } + else + { + y = p0 - y; + y += m; + q--; + } + } + else + { + x = x - (p1 + (y < p0)); + y = y - p0; + + q2 = (u64) ((TWO64 * (double)x + (double)y) * di); + mul64by64(q2, m, &p1, &p0); + + q = q1 + q2; + if (x < p1 || (x == p1 && y < p0)) + { + y = y - p0; + y += m; + q--; + } + else + { + y = y - p0; + if (y >= m) + { + y -= m; + q++; + } + } + } + + return y; +} + +/* + * returns a % p + */ +static inline u64 mod64by64(u64 a, u64 p, u64 primeinv) +{ + return (mod128by64(0, a, p, primeinv)); +} + +static inline void add64(u64 a, u64 b, u64 * whi, u64 * wlo) +{ + *wlo = a + b; + if (*wlo < a) + *whi = 1; + +} + +/* + * returns (a + b)%p + */ +static inline u64 add64_mod(u64 a, u64 b, u64 p, double pi) +{ + u64 shi = 0, slo = 0; + + add64(a, b, &shi, &slo); + return (mod128by64(shi, slo, p, pi)); +} + +/* + * returns (ab) % p + */ +static inline u64 mul64_mod(u64 a, u64 b, u64 p, double pi) +{ + u64 phi = 0, plo = 0; + + mul64by64(a, b, &phi, &plo); + return (mod128by64(phi, plo, p, pi)); +} + +#endif diff --git a/src/plugins/ioam/lib-pot/pot.api b/src/plugins/ioam/lib-pot/pot.api new file mode 100644 index 00000000..fa2fc126 --- /dev/null +++ b/src/plugins/ioam/lib-pot/pot.api @@ -0,0 +1,133 @@ +/* Hey Emacs use -*- mode: C -*- */ +/* + * 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. + */ + + +/** \brief Proof of Transit(POT): Set POT profile + @param id - id of the profile + @param validator - True/False to indicate if this is verifier + @param secret_key - Verification key + @param secret_share - Share of the 1st polynomial + @param prime - Prime number used for modulo operation + @param max_bits - Max bits to be used for Random number generation + @param lpc - Lagrange basis polynomial + @param polynomial_public - pre-evaluated public polynomial + @param list_name_len - length of the name of this profile list + @param list_name - name of this profile list +*/ +define pot_profile_add { + u32 client_index; + u32 context; + u8 id; + u8 validator; + u64 secret_key; + u64 secret_share; + u64 prime; + u8 max_bits; + u64 lpc; + u64 polynomial_public; + u8 list_name_len; + u8 list_name[0]; +}; + +/** \brief Proof of Transit profile add / del response + @param context - sender context, to match reply w/ request + @param retval - return value for request +*/ +define pot_profile_add_reply { + u32 context; + i32 retval; +}; + + +/** \brief Proof of Transit(POT): Activate POT profile in the list + @param id - id of the profile + @param list_name_len - length of the name of this profile list + @param list_name - name of this profile list +*/ +define pot_profile_activate { + u32 client_index; + u32 context; + u8 id; + u8 list_name_len; + u8 list_name[0]; +}; + +/** \brief Proof of Transit profile activate response + @param context - sender context, to match reply w/ request + @param retval - return value for request +*/ +define pot_profile_activate_reply { + u32 context; + i32 retval; +}; + +/** \brief Delete POT Profile + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param list_name_len - length of the name of the profile list + @param list_name - name of profile list to delete +*/ +define pot_profile_del { + u32 client_index; + u32 context; + u8 list_name_len; + u8 list_name[0]; +}; + +/** \brief Proof of Transit profile add / del response + @param context - sender context, to match reply w/ request + @param retval - return value for request +*/ +define pot_profile_del_reply { + u32 context; + i32 retval; +}; + +/** \brief Show POT Profiles + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param id - id of the profile +*/ +define pot_profile_show_config_dump { + u32 client_index; + u32 context; + u8 id; +}; + +/** \brief Show POT profile reply + @param id - id of the profile + @param validator - True/False to indicate if this is verifier + @param secret_key - Verification key + @param secret_share - Share of the 1st polynomial + @param prime - Prime number used for modulo operation + @param max_bits - Max bits to be used for Random number generation + @param lpc - Lagrange basis polynomial + @param polynomial_public - pre-evaluated public polynomial + @param list_name_len - length of the name of this profile list + @param list_name - name of this profile list +*/ +define pot_profile_show_config_details { + u32 context; + i32 retval; + u8 id; + u8 validator; + u64 secret_key; + u64 secret_share; + u64 prime; + u64 bit_mask; + u64 lpc; + u64 polynomial_public; +}; diff --git a/src/plugins/ioam/lib-pot/pot_all_api_h.h b/src/plugins/ioam/lib-pot/pot_all_api_h.h new file mode 100644 index 00000000..63967c45 --- /dev/null +++ b/src/plugins/ioam/lib-pot/pot_all_api_h.h @@ -0,0 +1,16 @@ +/* + * 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. + */ +/* Include the generated file, see BUILT_SOURCES in Makefile.am */ +#include diff --git a/src/plugins/ioam/lib-pot/pot_api.c b/src/plugins/ioam/lib-pot/pot_api.c new file mode 100644 index 00000000..d3af7b40 --- /dev/null +++ b/src/plugins/ioam/lib-pot/pot_api.c @@ -0,0 +1,292 @@ +/* + * 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. + */ +/* + *------------------------------------------------------------------ + * pot_api.c - Proof of Transit related APIs to create + * and maintain profiles + *------------------------------------------------------------------ + */ + +#include +#include +#include + +#include +#include +#include + +/* define message IDs */ +#include + +/* define message structures */ +#define vl_typedefs +#include +#undef vl_typedefs + +/* define generated endian-swappers */ +#define vl_endianfun +#include +#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 +#undef vl_printfun + +/* Get the API version number */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#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); + +#define REPLY_MACRO2(t, body) \ +do { \ + unix_shared_memory_queue_t * q; \ + rv = vl_msg_api_pd_handler (mp, rv); \ + 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); \ + do {body;} while (0); \ + vl_msg_api_send_shmem (q, (u8 *)&rmp); \ +} while(0); + +/* List of message types that this plugin understands */ + +#define foreach_pot_plugin_api_msg \ +_(POT_PROFILE_ADD, pot_profile_add) \ +_(POT_PROFILE_ACTIVATE, pot_profile_activate) \ +_(POT_PROFILE_DEL, pot_profile_del) \ +_(POT_PROFILE_SHOW_CONFIG_DUMP, pot_profile_show_config_dump) \ + +static void vl_api_pot_profile_add_t_handler +(vl_api_pot_profile_add_t *mp) +{ + pot_main_t * sm = &pot_main; + int rv = 0; + vl_api_pot_profile_add_reply_t * rmp; + u8 id; + pot_profile *profile = NULL; + u8 *name = 0; + + if (mp->list_name_len) + name = format(0, "%s", mp->list_name); + + pot_profile_list_init(name); + id = mp->id; + profile = pot_profile_find(id); + if (profile) { + rv = pot_profile_create(profile, + clib_net_to_host_u64(mp->prime), + clib_net_to_host_u64(mp->polynomial_public), + clib_net_to_host_u64(mp->lpc), + clib_net_to_host_u64(mp->secret_share)); + if (rv != 0) + goto ERROROUT; + if (1 == mp->validator) + (void)pot_set_validator(profile, clib_net_to_host_u64(mp->secret_key)); + (void)pot_profile_set_bit_mask(profile, mp->max_bits); + } else { + rv = -3; + } + ERROROUT: + vec_free(name); + REPLY_MACRO(VL_API_POT_PROFILE_ADD_REPLY); +} + +static void send_pot_profile_details(vl_api_pot_profile_show_config_dump_t *mp, u8 id) +{ + vl_api_pot_profile_show_config_details_t * rmp; + pot_main_t * sm = &pot_main; + pot_profile *profile = pot_profile_find(id); + int rv = 0; + if(profile){ + REPLY_MACRO2(VL_API_POT_PROFILE_SHOW_CONFIG_DETAILS, + rmp->id=id; + rmp->validator=profile->validator; + rmp->secret_key=clib_host_to_net_u64(profile->secret_key); + rmp->secret_share=clib_host_to_net_u64(profile->secret_share); + rmp->prime=clib_host_to_net_u64(profile->prime); + rmp->bit_mask=clib_host_to_net_u64(profile->bit_mask); + rmp->lpc=clib_host_to_net_u64(profile->lpc); + rmp->polynomial_public=clib_host_to_net_u64(profile->poly_pre_eval); + ); + } + else{ + REPLY_MACRO2(VL_API_POT_PROFILE_SHOW_CONFIG_DETAILS, + rmp->id=id; + rmp->validator=0; + rmp->secret_key=0; + rmp->secret_share=0; + rmp->prime=0; + rmp->bit_mask=0; + rmp->lpc=0; + rmp->polynomial_public=0; + ); + } +} + +static void vl_api_pot_profile_show_config_dump_t_handler +(vl_api_pot_profile_show_config_dump_t *mp) +{ + u8 id = mp->id; + u8 dump_call_id = ~0; + if(dump_call_id==id){ + for(id=0;idlist_name_len) + name = format(0, "%s", mp->list_name); + if (!pot_profile_list_is_enabled(name)) { + rv = -1; + } else { + id = mp->id; + rv = pot_profile_set_active(id); + } + + vec_free(name); + REPLY_MACRO(VL_API_POT_PROFILE_ACTIVATE_REPLY); +} + + +static void vl_api_pot_profile_del_t_handler +(vl_api_pot_profile_del_t *mp) +{ + pot_main_t * sm = &pot_main; + int rv = 0; + vl_api_pot_profile_del_reply_t * rmp; + + clear_pot_profiles(); + + REPLY_MACRO(VL_API_POT_PROFILE_DEL_REPLY); +} + + +/* + * 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) +{ + pot_main_t * sm = &pot_main; + clib_error_t * error = 0; + + sm->vlib_main = vm; + sm->vnet_main = h->vnet_main; + return error; +} + +/* Set up the API message handling tables */ +static clib_error_t * +pot_plugin_api_hookup (vlib_main_t *vm) +{ + pot_main_t * sm = &pot_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_pot_plugin_api_msg; +#undef _ + + return 0; +} + +#define vl_msg_name_crc_list +#include +#undef vl_msg_name_crc_list + +static void +setup_message_id_table (pot_main_t * sm, api_main_t * am) +{ +#define _(id,n,crc) \ + vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base); + foreach_vl_msg_name_crc_pot; +#undef _ +} + +static clib_error_t * pot_init (vlib_main_t * vm) +{ + pot_main_t * sm = &pot_main; + clib_error_t * error = 0; + u8 * name; + + bzero(sm, sizeof(pot_main)); + (void)pot_util_init(); + name = format (0, "ioam_pot_%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 = pot_plugin_api_hookup (vm); + + /* Add our API messages to the global name_crc hash table */ + setup_message_id_table (sm, &api_main); + + vec_free(name); + + return error; +} + +VLIB_INIT_FUNCTION (pot_init); diff --git a/src/plugins/ioam/lib-pot/pot_msg_enum.h b/src/plugins/ioam/lib-pot/pot_msg_enum.h new file mode 100644 index 00000000..a4a88bed --- /dev/null +++ b/src/plugins/ioam/lib-pot/pot_msg_enum.h @@ -0,0 +1,28 @@ +/* + * 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. + */ +#ifndef included_pot_msg_enum_h +#define included_pot_msg_enum_h + +#include + +#define vl_msg_id(n,h) n, +typedef enum { +#include + /* 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_pot_msg_enum_h */ diff --git a/src/plugins/ioam/lib-pot/pot_test.c b/src/plugins/ioam/lib-pot/pot_test.c new file mode 100644 index 00000000..2e870238 --- /dev/null +++ b/src/plugins/ioam/lib-pot/pot_test.c @@ -0,0 +1,365 @@ +/* + * 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. + */ +/* + *------------------------------------------------------------------ + * pot_test.c - test harness for pot plugin + *------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include + +/* Declare message IDs */ +#include + +/* define message structures */ +#define vl_typedefs +#include +#undef vl_typedefs + +/* declare message handlers for each api */ + +#define vl_endianfun /* define message structures */ +#include +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) +#define vl_printfun +#include +#undef vl_printfun + +/* Get the API version number. */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#undef vl_api_version + + +typedef struct { + /* API message ID base */ + u16 msg_id_base; + vat_main_t *vat_main; +} pot_test_main_t; + +pot_test_main_t pot_test_main; + +#define foreach_standard_reply_retval_handler \ +_(pot_profile_add_reply) \ +_(pot_profile_activate_reply) \ +_(pot_profile_del_reply) + +#define foreach_custom_reply_retval_handler \ +_(pot_profile_show_config_details, \ + errmsg(" ID:%d\n",mp->id); \ + errmsg(" Validator:%d\n",mp->validator); \ + errmsg(" secret_key:%Lx\n",clib_net_to_host_u64(mp->secret_key)); \ + errmsg(" secret_share:%Lx\n",clib_net_to_host_u64(mp->secret_share)); \ + errmsg(" prime:%Lx\n",clib_net_to_host_u64(mp->prime)); \ + errmsg(" bitmask:%Lx\n",clib_net_to_host_u64(mp->bit_mask)); \ + errmsg(" lpc:%Lx\n",clib_net_to_host_u64(mp->lpc)); \ + errmsg(" public poly:%Lx\n",clib_net_to_host_u64(mp->polynomial_public)); \ + ) + +#define _(n) \ + static void vl_api_##n##_t_handler \ + (vl_api_##n##_t * mp) \ + { \ + vat_main_t * vam = pot_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 _ + +#define _(n,body) \ + static void vl_api_##n##_t_handler \ + (vl_api_##n##_t * mp) \ + { \ + vat_main_t * vam = pot_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; \ + } \ + do{body;}while(0); \ + } +foreach_custom_reply_retval_handler; +#undef _ + +/* + * Table of message reply handlers, must include boilerplate handlers + * we just generated + */ +#define foreach_vpe_api_reply_msg \ +_(POT_PROFILE_ADD_REPLY, pot_profile_add_reply) \ +_(POT_PROFILE_ACTIVATE_REPLY, pot_profile_activate_reply) \ +_(POT_PROFILE_DEL_REPLY, pot_profile_del_reply) \ +_(POT_PROFILE_SHOW_CONFIG_DETAILS, pot_profile_show_config_details) + + +/* 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_pot_profile_add (vat_main_t *vam) +{ +#define MAX_BITS 64 + pot_test_main_t * sm = &pot_test_main; + unformat_input_t *input = vam->input; + vl_api_pot_profile_add_t *mp; + u8 *name = NULL; + u64 prime = 0; + u64 secret_share = 0; + u64 secret_key = 0; + u32 bits = MAX_BITS; + u64 lpc = 0, poly2 = 0; + f64 timeout; + u8 id = 0; + int rv = 0; + + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) + { + if (unformat(input, "name %s", &name)) + ; + else if(unformat(input, "id %d", &id)) + ; + else if (unformat(input, "validator-key 0x%Lx", &secret_key)) + ; + else if (unformat(input, "prime-number 0x%Lx", &prime)) + ; + else if (unformat(input, "secret-share 0x%Lx", &secret_share)) + ; + else if (unformat(input, "polynomial-public 0x%Lx", &poly2)) + ; + else if (unformat(input, "lpc 0x%Lx", &lpc)) + ; + else if (unformat(input, "bits-in-random %u", &bits)) + { + if (bits > MAX_BITS) + bits = MAX_BITS; + } + else + break; + } + + if (!name) + { + errmsg ("name required\n"); + rv = -99; + goto OUT; + } + + M2(POT_PROFILE_ADD, pot_profile_add, vec_len(name)); + + mp->list_name_len = vec_len(name); + clib_memcpy(mp->list_name, name, mp->list_name_len); + mp->secret_share = clib_host_to_net_u64(secret_share); + mp->polynomial_public = clib_host_to_net_u64(poly2); + mp->lpc = clib_host_to_net_u64(lpc); + mp->prime = clib_host_to_net_u64(prime); + if (secret_key != 0) + { + mp->secret_key = clib_host_to_net_u64(secret_key); + mp->validator = 1; + } + else + { + mp->validator = 0; + } + mp->id = id; + mp->max_bits = bits; + + S; W; + +OUT: + vec_free(name); + return(rv); +} + +static int api_pot_profile_activate (vat_main_t *vam) +{ +#define MAX_BITS 64 + pot_test_main_t * sm = &pot_test_main; + unformat_input_t *input = vam->input; + vl_api_pot_profile_activate_t *mp; + u8 *name = NULL; + u8 id = 0; + int rv = 0; + f64 timeout; + + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) + { + if (unformat(input, "name %s", &name)) + ; + else if(unformat(input, "id %d", &id)) + ; + else + break; + } + + if (!name) + { + errmsg ("name required\n"); + rv = -99; + goto OUT; + } + + M2(POT_PROFILE_ACTIVATE, pot_profile_activate, vec_len(name)); + + mp->list_name_len = vec_len(name); + clib_memcpy(mp->list_name, name, mp->list_name_len); + mp->id = id; + + S; W; + +OUT: + vec_free(name); + return(rv); +} + + +static int api_pot_profile_del (vat_main_t *vam) +{ + pot_test_main_t * sm = &pot_test_main; + vl_api_pot_profile_del_t *mp; + f64 timeout; + + M(POT_PROFILE_DEL, pot_profile_del); + mp->list_name_len = 0; + S; W; + return 0; +} + +static int api_pot_profile_show_config_dump (vat_main_t *vam) +{ + pot_test_main_t * sm = &pot_test_main; + unformat_input_t *input = vam->input; + vl_api_pot_profile_show_config_dump_t *mp; + f64 timeout; + u8 id = 0; + + while(unformat_check_input(input) != UNFORMAT_END_OF_INPUT) + { + if(unformat(input,"id %d",&id)); + else + break; + } + M(POT_PROFILE_SHOW_CONFIG_DUMP, pot_profile_show_config_dump); + + mp->id = id; + + S; W; + return 0; +} + +/* + * List of messages that the api test plugin sends, + * and that the data plane plugin processes + */ +#define foreach_vpe_api_msg \ +_(pot_profile_add, "name id [0-1] " \ + "prime-number <0xu64> bits-in-random [0-64] " \ + "secret-share <0xu64> lpc <0xu64> polynomial-public <0xu64> " \ + "[validator-key <0xu64>] [validity <0xu64>]") \ +_(pot_profile_activate, "name id [0-1] ") \ +_(pot_profile_del, "[id ]") \ +_(pot_profile_show_config_dump, "id [0-1]") + +void vat_api_hookup (vat_main_t *vam) +{ + pot_test_main_t * sm = &pot_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) +{ + pot_test_main_t * sm = &pot_test_main; + u8 * name; + + sm->vat_main = vam; + + name = format (0, "ioam_pot_%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/src/plugins/ioam/lib-pot/pot_util.c b/src/plugins/ioam/lib-pot/pot_util.c new file mode 100644 index 00000000..a253ad41 --- /dev/null +++ b/src/plugins/ioam/lib-pot/pot_util.c @@ -0,0 +1,445 @@ +/* + * 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. + */ +#include +#include +#include +#include +#include +#include "math64.h" +#include "pot_util.h" + +pot_main_t pot_main; + +static void pot_profile_cleanup(pot_profile *profile); + +static void pot_main_profiles_reset (void) +{ + pot_main_t *sm = &pot_main; + int i = 0; + + for (i = 0; i < MAX_POT_PROFILES; i++) + { + pot_profile_cleanup(&(sm->profile_list[i])); + } + sm->active_profile_id = 0; + if (sm->profile_list_name) + vec_free(sm->profile_list_name); + sm->profile_list_name = NULL; +} + +int pot_util_init (void) +{ + pot_main_profiles_reset(); + + return(0); +} + +static void pot_profile_init(pot_profile * new, u8 id) +{ + if (new) + { + memset(new, 0, sizeof(pot_profile)); + new->id = id; + } +} + +pot_profile *pot_profile_find(u8 id) +{ + pot_main_t *sm = &pot_main; + + if (id < MAX_POT_PROFILES) + { + return (&(sm->profile_list[id])); + } + return (NULL); +} +static int pot_profile_name_equal (u8 *name0, u8 *name1) +{ + int len0, len1; + + len0 = vec_len (name0); + len1 = vec_len (name1); + if (len0 != len1) + return(0); + return (0==strncmp ((char *) name0, (char *)name1, len0)); +} + +int pot_profile_list_is_enabled (u8 *name) +{ + pot_main_t *sm = &pot_main; + return (pot_profile_name_equal(sm->profile_list_name, name)); +} + +void pot_profile_list_init(u8 * profile_list_name) +{ + pot_main_t *sm = &pot_main; + int i = 0; + + /* If it is the same profile list skip reset */ + if (pot_profile_name_equal(sm->profile_list_name, profile_list_name)) + { + return; + } + + pot_main_profiles_reset(); + if (vec_len(profile_list_name)) + sm->profile_list_name = (u8 *)vec_dup(profile_list_name); + else + sm->profile_list_name = 0; + sm->active_profile_id = 0; + + for (i = 0; i < MAX_POT_PROFILES; i++) + { + pot_profile_init(&(sm->profile_list[i]), i); + } +} + +static void pot_profile_cleanup(pot_profile * profile) +{ + u16 id = profile->id; + + memset(profile, 0, sizeof(pot_profile)); + profile->id = id; /* Restore id alone */ +} + +int pot_profile_create(pot_profile * profile, u64 prime, + u64 poly2, u64 lpc, u64 secret_share) +{ + if (profile && !profile->in_use) + { + pot_profile_cleanup(profile); + profile->prime = prime; + profile->primeinv = 1.0 / prime; + profile->lpc = lpc; + profile->poly_pre_eval = poly2; + profile->secret_share = secret_share; + profile->total_pkts_using_this_profile = 0; + profile->valid = 1; + return(0); + } + + return(-1); +} + +int pot_set_validator(pot_profile * profile, u64 key) +{ + if (profile && !profile->in_use) + { + profile->validator = 1; + profile->secret_key = key; + return(0); + } + return(-1); +} + +always_inline u64 pot_update_cumulative_inline(u64 cumulative, u64 random, + u64 secret_share, u64 prime, u64 lpc, u64 pre_split, double prime_inv) +{ + u64 share_random = 0; + u64 cumulative_new = 0; + + /* + * calculate split share for random + */ + share_random = add64_mod(pre_split, random, prime, prime_inv); + + /* + * lpc * (share_secret + share_random) + */ + share_random = add64_mod(share_random, secret_share, prime, prime_inv); + share_random = mul64_mod(share_random, lpc, prime, prime_inv); + + cumulative_new = add64_mod(cumulative, share_random, prime, prime_inv); + + return (cumulative_new); +} + +u64 pot_update_cumulative(pot_profile * profile, u64 cumulative, u64 random) +{ + if (profile && profile->valid != 0) + { + return (pot_update_cumulative_inline(cumulative, random, profile->secret_share, + profile->prime, profile->lpc, profile->poly_pre_eval, + profile->primeinv)); + } + return (0); +} + +always_inline u8 pot_validate_inline(u64 secret, u64 prime, double prime_inv, + u64 cumulative, u64 random) +{ + if (cumulative == (random + secret)) + { + return (1); + } + else if (cumulative == add64_mod(random, secret, prime, prime_inv)) + { + return (1); + } + return (0); +} + +/* + * return True if the cumulative matches secret from a profile + */ +u8 pot_validate(pot_profile * profile, u64 cumulative, u64 random) +{ + if (profile && profile->validator) + { + return (pot_validate_inline(profile->secret_key, profile->prime, + profile->primeinv, cumulative, random)); + } + return (0); +} + +/* + * Utility function to get random number per pack + */ +u64 pot_generate_random(pot_profile * profile) +{ + u64 random = 0; + int32_t second_half; + static u32 seed = 0; + + if (PREDICT_FALSE(!seed)) + seed = random_default_seed(); + + /* + * Upper 4 bytes seconds + */ + random = (u64) time(NULL); + + random &= 0xffffffff; + random = random << 32; + /* + * Lower 4 bytes random number + */ + second_half = random_u32(&seed); + + random |= second_half; + + if (PREDICT_TRUE(profile != NULL)) + { + random &= profile->bit_mask; + } + return (random); +} + +int pot_profile_set_bit_mask(pot_profile * profile, u16 bits) +{ + int sizeInBits; + + if (profile && !profile->in_use) + { + sizeInBits = sizeof(profile->bit_mask) * 8; + profile->bit_mask = + (bits >= + sizeInBits ? (u64) - 1 : (u64) ((u64) 1 << (u64) bits) - 1); + return(0); + } + return(-1); +} + +clib_error_t *clear_pot_profile_command_fn(vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + + pot_main_profiles_reset(); + + return 0; +} + +void clear_pot_profiles() +{ + clear_pot_profile_command_fn(0, 0, 0); +} + +VLIB_CLI_COMMAND(clear_pot_profile_command) = +{ +.path = "clear pot profile", +.short_help = "clear pot profile [|all]", +.function = clear_pot_profile_command_fn, +}; + +static clib_error_t *set_pot_profile_command_fn(vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + u64 prime; + u64 secret_share; + u64 secret_key; + u8 validator = 0; + u32 profile_id = ~0; + u32 bits; + u64 lpc = 0, poly2 = 0; + pot_profile *profile = NULL; + u8 *profile_list_name = NULL; + + bits = MAX_BITS; + + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) + { + if (unformat(input, "name %s", + &profile_list_name)); + else if (unformat(input, "id %d", &profile_id)) + ; + else if (unformat(input, "validate-key 0x%Lx", &secret_key)) + validator = 1; + else if (unformat(input, "prime-number 0x%Lx", &prime)) + ; + else if (unformat(input, "secret_share 0x%Lx", &secret_share)) + ; + else if (unformat(input, "polynomial2 0x%Lx", &poly2)) + ; + else if (unformat(input, "lpc 0x%Lx", &lpc)) + ; + else if (unformat(input, "bits-in-random %d", &bits)) + { + if (bits > MAX_BITS) + bits = MAX_BITS; + } + else + break; + } + if (profile_list_name == 0) + { + return clib_error_return(0, "Name cannot be null"); + } + pot_profile_list_init(profile_list_name); + profile = pot_profile_find(profile_id); + + if (profile) + { + pot_profile_create(profile, prime, poly2, lpc, secret_share); + if (validator) + pot_set_validator(profile, secret_key); + pot_profile_set_bit_mask(profile, bits); + } + vec_free(profile_list_name); + return 0; +} + +VLIB_CLI_COMMAND(set_pot_profile_command) = +{ +.path = "set pot profile", +.short_help = "set pot profile name id [0-1] [validator-key 0xu64] \ + prime-number 0xu64 secret_share 0xu64 lpc 0xu64 \ + polynomial2 0xu64 bits-in-random [0-64] ", +.function = set_pot_profile_command_fn, +}; + +static clib_error_t *set_pot_profile_activate_command_fn(vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + pot_main_t *sm = &pot_main; + u8 *profile_list_name = NULL; + u32 id = 0; + clib_error_t *result = NULL; + + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) + { + if (unformat(input, "name %s", + &profile_list_name)); + else if (unformat(input, "id %d", &id)) + ; + else + return clib_error_return(0, "unknown input `%U'", + format_unformat_error, input); + } + if (profile_list_name == 0) + { + return clib_error_return(0, "Name cannot be null"); + } + + if (!pot_profile_list_is_enabled(profile_list_name)) { + result = clib_error_return(0, "%s list is not enabled, profile in use %s", + profile_list_name, sm->profile_list_name); + } else if (0 != pot_profile_set_active((u8)id)) { + result = clib_error_return(0, "Profile %d not defined in %s", + id, sm->profile_list_name); + } + vec_free(profile_list_name); + return result; +} + +VLIB_CLI_COMMAND(set_pot_profile_activate_command) = +{ +.path = "set pot profile-active", +.short_help = "set pot profile-active name id [0-1]", +.function = set_pot_profile_activate_command_fn, +}; + +static clib_error_t *show_pot_profile_command_fn(vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + pot_main_t *sm = &pot_main; + pot_profile *p = NULL; + u16 i; + u8 *s = 0; + + if (vec_len(sm->profile_list_name) == 0) + { + s = format(s, "POT Profiles not configured\n"); + vlib_cli_output(vm, "%v", s); + return 0; + } + s = format(s, "Profile list in use : %s\n",sm->profile_list_name); + for (i = 0; i < MAX_POT_PROFILES; i++) + { + p = pot_profile_find(i); + if (p->valid == 0) + continue; + s = format(s, "POT Profile at index: %d\n", i); + s = format(s, " Id : %d\n", p->id); + s = format(s, " Validator : %s (%d)\n", + (p->validator) ? "True" : "False", p->validator); + if (p->validator == 1) + s = format(s, " Secret key : 0x%Lx (%Ld)\n", + p->secret_key, p->secret_key); + s = format(s, " Secret share : 0x%Lx (%Ld)\n", + p->secret_share, p->secret_share); + s = format(s, " Prime number : 0x%Lx (%Ld)\n", + p->prime, p->prime); + s = format(s, "2nd polynomial(eval) : 0x%Lx (%Ld)\n", + p->poly_pre_eval, p->poly_pre_eval); + s = format(s, " LPC : 0x%Lx (%Ld)\n", p->lpc, p->lpc); + + s = format(s, " Bit mask : 0x%Lx (%Ld)\n", + p->bit_mask, p->bit_mask); + } + + p = pot_profile_find(sm->active_profile_id); + + if (p && p->valid && p->in_use) { + s = format(s, "\nProfile index in use: %d\n", sm->active_profile_id); + s = format(s, "Pkts passed : 0x%Lx (%Ld)\n", + p->total_pkts_using_this_profile, + p->total_pkts_using_this_profile); + if (pot_is_decap(p)) + s = format(s, " This is Decap node. \n"); + } else { + s = format(s, "\nProfile index in use: None\n"); + } + vlib_cli_output(vm, "%v", s); + vec_free(s); + + return 0; +} + +VLIB_CLI_COMMAND(show_pot_profile_command) = +{ +.path = "show pot profile", +.short_help = "show pot profile", +.function = show_pot_profile_command_fn, +}; diff --git a/src/plugins/ioam/lib-pot/pot_util.h b/src/plugins/ioam/lib-pot/pot_util.h new file mode 100644 index 00000000..9df31fae --- /dev/null +++ b/src/plugins/ioam/lib-pot/pot_util.h @@ -0,0 +1,195 @@ +/* + * pot_util.h -- Proof Of Transit Utility Header + * + * 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. + */ + +#ifndef include_vnet_pot_util_h +#define include_vnet_pot_util_h + +#include +#define debug_ioam debug_ioam_fn +/* Dont change this size 256. This is there across multiple components */ +#define PATH_NAME_SIZE 256 + +/* Ring size. this should be same as the one in ODL. Do not change this + without change in ODL. */ +#define MAX_POT_PROFILES 2 + +/** + * Usage: + * + * On any node that participates in Proof of Transit: + * + * Step 1: Initialize this library by calling pot_init() + * Step 2: Setup a proof of transit profile that contains all the parameters needed to compute cumulative: + * Call these functions: + * pot_profile_find + * pot_profile_create + * pot_profile_set_bit_mask - To setup how large we want the numbers used in the computation and random number <= 64 bits + * Step 2a: For validator do this: + * pot_set_validator + * Step 2b: On initial node enable the profile to be used: + * pot_profile_set_active / pot_profile_get_active will return the profile + * Step 3a: At the initial node to generate Random number that will be read by all other nodes: + * pot_generate_random + * Step 3b: At all nodes including initial and verifier call this to compute cumulative: + * pot_update_cumulative + * Step 4: At the verifier: + * pot_validate + * + */ + +typedef struct pot_profile_ +{ + u8 id : 1; + u8 valid : 1; + u8 in_use : 1; + u64 random; + u8 validator; + u64 secret_key; + u64 secret_share; + u64 prime; + u64 lpc; + u64 poly_pre_eval; + u64 bit_mask; + u64 limit; + double primeinv; + u64 total_pkts_using_this_profile; +} pot_profile; + +typedef struct { + /* Name of the default profile list in use*/ + u8 *profile_list_name; + pot_profile profile_list[MAX_POT_PROFILES]; + /* number of profiles in the list */ + u8 active_profile_id : 1; + + /* API message ID base */ + u16 msg_id_base; + + /* convenience */ + vlib_main_t * vlib_main; + vnet_main_t * vnet_main; +} pot_main_t; + +extern pot_main_t pot_main; + +/* + * Initialize proof of transit + */ +int pot_util_init(void); +void pot_profile_list_init(u8 * name); + + +/* + * Find a pot profile by ID + */ +pot_profile *pot_profile_find(u8 id); + +static inline u16 pot_profile_get_id(pot_profile * profile) +{ + if (profile) + { + return (profile->id); + } + return (0); +} + +/* setup and clean up profile */ +int pot_profile_create(pot_profile * profile, u64 prime, + u64 poly2, u64 lpc, u64 secret_share); +/* + * Setup profile as a validator + */ +int pot_set_validator(pot_profile * profile, u64 key); + +/* + * Setup max bits to be used for random number generation + */ +#define MAX_BITS 64 +int pot_profile_set_bit_mask(pot_profile * profile, u16 bits); + +/* + * Given a random and cumulative compute the new cumulative for a given profile + */ +u64 pot_update_cumulative(pot_profile * profile, u64 cumulative, u64 random); + +/* + * return True if the cumulative matches secret from a profile + */ +u8 pot_validate(pot_profile * profile, u64 cumulative, u64 random); + +/* + * Utility function to get random number per pack + */ +u64 pot_generate_random(pot_profile * profile); + + +extern void clear_pot_profiles(); +extern int pot_profile_list_is_enabled(u8 *name); + +static inline u8 pot_is_decap(pot_profile * p) +{ + return (p->validator == 1); +} + +static inline int pot_profile_set_active (u8 id) +{ + pot_main_t *sm = &pot_main; + pot_profile *profile = NULL; + pot_profile *current_active_prof = NULL; + + current_active_prof = pot_profile_find(sm->active_profile_id); + profile = pot_profile_find(id); + if (profile && profile->valid) { + sm->active_profile_id = id; + current_active_prof->in_use = 0; + profile->in_use = 1; + return(0); + } + return(-1); +} +static inline u8 pot_profile_get_active_id (void) +{ + pot_main_t *sm = &pot_main; + return (sm->active_profile_id); +} + +static inline pot_profile * pot_profile_get_active (void) +{ + pot_main_t *sm = &pot_main; + pot_profile *profile = NULL; + profile = pot_profile_find(sm->active_profile_id); + if (profile && profile->in_use) + return(profile); + return (NULL); +} + +static inline void pot_profile_reset_usage_stats (pot_profile *pow) +{ + if (pow) { + pow->total_pkts_using_this_profile = 0; + } +} + +static inline void pot_profile_incr_usage_stats (pot_profile *pow) +{ + if (pow) { + pow->total_pkts_using_this_profile++; + } +} + + +#endif diff --git a/src/plugins/ioam/lib-trace/trace.api b/src/plugins/ioam/lib-trace/trace.api new file mode 100644 index 00000000..cb958325 --- /dev/null +++ b/src/plugins/ioam/lib-trace/trace.api @@ -0,0 +1,92 @@ +/* Hey Emacs use -*- mode: C -*- */ +/* + * 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. + */ + + +/** \brief iOAM6 Trace - Set the iOAM6 trace profile + @param trace_type - Type of trace requested + @param num_elts - Number of trace elements to be inserted + @param node_id - Trace Node ID + @param trace_tsp- Timestamp resolution + @param app_data - Application specific opaque +*/ +define trace_profile_add { + u32 client_index; + u32 context; + u8 trace_type; + u8 num_elts; + u8 trace_tsp; + u32 node_id; + u32 app_data; +}; + +/** \brief Trace profile add / del response + @param context - sender context, to match reply w/ request + @param retval - return value for request +*/ +define trace_profile_add_reply { + u32 context; + i32 retval; +}; + + + +/** \brief Delete trace Profile + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define trace_profile_del { + u32 client_index; + u32 context; +}; + +/** \brief Trace profile add / del response + @param context - sender context, to match reply w/ request + @param retval - return value for request +*/ +define trace_profile_del_reply { + u32 context; + i32 retval; +}; + + + +/** \brief Show trace Profile + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define trace_profile_show_config { + u32 client_index; + u32 context; +}; + +/** \brief Show trace config response + @param context - sender context, to match reply w/ request + @param retval - return value for request + @param trace_type - Type of trace requested + @param num_elts - Number of trace elements to be inserted + @param node_id - Trace Node ID + @param trace_tsp- Timestamp resolution + @param app_data - Application specific opaque +*/ +define trace_profile_show_config_reply { + u32 context; + i32 retval; + u8 trace_type; + u8 num_elts; + u8 trace_tsp; + u32 node_id; + u32 app_data; +}; diff --git a/src/plugins/ioam/lib-trace/trace_all_api_h.h b/src/plugins/ioam/lib-trace/trace_all_api_h.h new file mode 100644 index 00000000..223f9545 --- /dev/null +++ b/src/plugins/ioam/lib-trace/trace_all_api_h.h @@ -0,0 +1,16 @@ +/* + * 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. + */ +/* Include the generated file, see BUILT_SOURCES in Makefile.am */ +#include diff --git a/src/plugins/ioam/lib-trace/trace_api.c b/src/plugins/ioam/lib-trace/trace_api.c new file mode 100644 index 00000000..7e0d708e --- /dev/null +++ b/src/plugins/ioam/lib-trace/trace_api.c @@ -0,0 +1,252 @@ +/* + * 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. + */ +/* + *------------------------------------------------------------------ + * trace_api.c - iOAM Trace related APIs to create + * and maintain profiles + *------------------------------------------------------------------ + */ + +#include +#include +#include + +#include +#include +#include + +/* define message IDs */ +#include + +/* define message structures */ +#define vl_typedefs +#include +#undef vl_typedefs + +/* define generated endian-swappers */ +#define vl_endianfun +#include +#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 +#undef vl_printfun + +/* Get the API version number */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#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 TRACE_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); + +/* *INDENT-OFF* */ +#define TRACE_REPLY_MACRO2(t, body) \ +do { \ + unix_shared_memory_queue_t * q; \ + rv = vl_msg_api_pd_handler (mp, rv); \ + 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); \ + do {body;} while (0); \ + vl_msg_api_send_shmem (q, (u8 *)&rmp); \ +} while(0); +/* *INDENT-ON* */ + +/* List of message types that this plugin understands */ + +#define foreach_trace_plugin_api_msg \ +_(TRACE_PROFILE_ADD, trace_profile_add) \ +_(TRACE_PROFILE_DEL, trace_profile_del) \ +_(TRACE_PROFILE_SHOW_CONFIG, trace_profile_show_config) + +static void vl_api_trace_profile_add_t_handler + (vl_api_trace_profile_add_t * mp) +{ + trace_main_t *sm = &trace_main; + int rv = 0; + vl_api_trace_profile_add_reply_t *rmp; + trace_profile *profile = NULL; + + profile = trace_profile_find (); + if (profile) + { + rv = + trace_profile_create (profile, mp->trace_type, mp->num_elts, + mp->trace_tsp, ntohl (mp->node_id), + ntohl (mp->app_data)); + if (rv != 0) + goto ERROROUT; + } + else + { + rv = -3; + } +ERROROUT: + TRACE_REPLY_MACRO (VL_API_TRACE_PROFILE_ADD_REPLY); +} + + +static void vl_api_trace_profile_del_t_handler + (vl_api_trace_profile_del_t * mp) +{ + trace_main_t *sm = &trace_main; + int rv = 0; + vl_api_trace_profile_del_reply_t *rmp; + + clear_trace_profiles (); + + TRACE_REPLY_MACRO (VL_API_TRACE_PROFILE_DEL_REPLY); +} + +static void vl_api_trace_profile_show_config_t_handler + (vl_api_trace_profile_show_config_t * mp) +{ + trace_main_t *sm = &trace_main; + vl_api_trace_profile_show_config_reply_t *rmp; + int rv = 0; + trace_profile *profile = trace_profile_find (); + if (profile->valid) + { + TRACE_REPLY_MACRO2 (VL_API_TRACE_PROFILE_SHOW_CONFIG_REPLY, + rmp->trace_type = profile->trace_type; + rmp->num_elts = profile->num_elts; + rmp->trace_tsp = profile->trace_tsp; + rmp->node_id = htonl (profile->node_id); + rmp->app_data = htonl (profile->app_data); + ); + } + else + { + TRACE_REPLY_MACRO2 (VL_API_TRACE_PROFILE_SHOW_CONFIG_REPLY, + rmp->trace_type = 0; + rmp->num_elts = 0; rmp->trace_tsp = 0; + rmp->node_id = 0; rmp->app_data = 0; + ); + } +} + +/* + * 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) +{ + trace_main_t *sm = &trace_main; + clib_error_t *error = 0; + + sm->vlib_main = vm; + sm->vnet_main = h->vnet_main; + return error; +} + +/* Set up the API message handling tables */ +static clib_error_t * +trace_plugin_api_hookup (vlib_main_t * vm) +{ + trace_main_t *sm = &trace_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_trace_plugin_api_msg; +#undef _ + + return 0; +} + +#define vl_msg_name_crc_list +#include +#undef vl_msg_name_crc_list + +static void +setup_message_id_table (trace_main_t * sm, api_main_t * am) +{ +#define _(id,n,crc) \ + vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base); + foreach_vl_msg_name_crc_trace; +#undef _ +} + +static clib_error_t * +trace_init (vlib_main_t * vm) +{ + trace_main_t *sm = &trace_main; + clib_error_t *error = 0; + u8 *name; + + bzero (sm, sizeof (trace_main)); + (void) trace_util_init (); + name = format (0, "ioam_trace_%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 = trace_plugin_api_hookup (vm); + + /* Add our API messages to the global name_crc hash table */ + setup_message_id_table (sm, &api_main); + + vec_free (name); + + return error; +} + +VLIB_INIT_FUNCTION (trace_init); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/lib-trace/trace_msg_enum.h b/src/plugins/ioam/lib-trace/trace_msg_enum.h new file mode 100644 index 00000000..78c35665 --- /dev/null +++ b/src/plugins/ioam/lib-trace/trace_msg_enum.h @@ -0,0 +1,28 @@ +/* + * 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. + */ +#ifndef included_trace_msg_enum_h +#define included_trace_msg_enum_h + +#include + +#define vl_msg_id(n,h) n, +typedef enum { +#include + /* 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_trace_msg_enum_h */ diff --git a/src/plugins/ioam/lib-trace/trace_test.c b/src/plugins/ioam/lib-trace/trace_test.c new file mode 100644 index 00000000..111dd461 --- /dev/null +++ b/src/plugins/ioam/lib-trace/trace_test.c @@ -0,0 +1,292 @@ +/* + * 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. + */ +/* + *------------------------------------------------------------------ + * trace_test.c - test harness for trace plugin + *------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include + +/* Declare message IDs */ +#include + +/* define message structures */ +#define vl_typedefs +#include +#undef vl_typedefs + +/* declare message handlers for each api */ + +#define vl_endianfun /* define message structures */ +#include +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) +#define vl_printfun +#include +#undef vl_printfun + +/* Get the API version number. */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#undef vl_api_version + + +typedef struct +{ + /* API message ID base */ + u16 msg_id_base; + vat_main_t *vat_main; +} trace_test_main_t; + +trace_test_main_t trace_test_main; + +#define foreach_standard_reply_retval_handler \ +_(trace_profile_add_reply) \ +_(trace_profile_del_reply) + +#define foreach_custom_reply_handler \ +_(trace_profile_show_config_reply, \ + if(mp->trace_type) \ + { \ + errmsg(" Trace Type : 0x%x (%d)\n",mp->trace_type, mp->trace_type); \ + errmsg(" Trace timestamp precision : %d \n",mp->trace_tsp); \ + errmsg(" Node Id : 0x%x (%d)\n",htonl(mp->node_id), htonl(mp->node_id)); \ + errmsg(" App Data : 0x%x (%d)\n",htonl(mp->app_data), htonl(mp->app_data)); \ + } \ + else errmsg("No valid trace profile configuration found\n");) +#define _(n) \ + static void vl_api_##n##_t_handler \ + (vl_api_##n##_t * mp) \ + { \ + vat_main_t * vam = trace_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 _ + +#define _(n,body) \ + static void vl_api_##n##_t_handler \ + (vl_api_##n##_t * mp) \ + { \ + vat_main_t * vam = trace_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; \ + } \ + if(retval>=0)do{body;} while(0); \ + else errmsg("Error, retval: %d",retval); \ + } +foreach_custom_reply_handler; +#undef _ +/* + * Table of message reply handlers, must include boilerplate handlers + * we just generated + */ +#define foreach_vpe_api_reply_msg \ +_(TRACE_PROFILE_ADD_REPLY, trace_profile_add_reply) \ +_(TRACE_PROFILE_DEL_REPLY, trace_profile_del_reply) \ +_(TRACE_PROFILE_SHOW_CONFIG_REPLY, trace_profile_show_config_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_trace_profile_add (vat_main_t * vam) +{ + trace_test_main_t *sm = &trace_test_main; + unformat_input_t *input = vam->input; + vl_api_trace_profile_add_t *mp; + u8 trace_type = 0; + u8 num_elts = 0; + int rv = 0; + u32 node_id = 0; + u32 app_data = 0; + u8 trace_tsp = 0; + f64 timeout; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "trace-type 0x%x", &trace_type)) + ; + else if (unformat (input, "trace-elts %d", &num_elts)) + ; + else if (unformat (input, "trace-tsp %d", &trace_tsp)) + ; + else if (unformat (input, "node-id 0x%x", &node_id)) + ; + else if (unformat (input, "app-data 0x%x", &app_data)) + ; + + else + break; + } + + + M (TRACE_PROFILE_ADD, trace_profile_add); + + mp->trace_type = trace_type; + mp->trace_tsp = trace_tsp; + mp->node_id = htonl (node_id); + mp->app_data = htonl (app_data); + mp->num_elts = num_elts; + + S; + W; + + return (rv); +} + + + +static int +api_trace_profile_del (vat_main_t * vam) +{ + trace_test_main_t *sm = &trace_test_main; + vl_api_trace_profile_del_t *mp; + f64 timeout; + + M (TRACE_PROFILE_DEL, trace_profile_del); + S; + W; + return 0; +} + +static int +api_trace_profile_show_config (vat_main_t * vam) +{ + trace_test_main_t *sm = &trace_test_main; + vl_api_trace_profile_show_config_t *mp; + f64 timeout; + M (TRACE_PROFILE_SHOW_CONFIG, trace_profile_show_config); + S; + W; + return 0; +} + +/* + * List of messages that the api test plugin sends, + * and that the data plane plugin processes + */ +#define foreach_vpe_api_msg \ +_(trace_profile_add, ""\ + "trace-type <0x1f|0x3|0x9|0x11|0x19> trace-elts trace-tsp <0|1|2|3> node-id app-data ") \ +_(trace_profile_del, "[id ]") \ +_(trace_profile_show_config, "[id ]") + + +void +vat_api_hookup (vat_main_t * vam) +{ + trace_test_main_t *sm = &trace_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) +{ + trace_test_main_t *sm = &trace_test_main; + u8 *name; + + sm->vat_main = vam; + + name = format (0, "ioam_trace_%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; +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/lib-trace/trace_util.c b/src/plugins/ioam/lib-trace/trace_util.c new file mode 100644 index 00000000..5c7f1eef --- /dev/null +++ b/src/plugins/ioam/lib-trace/trace_util.c @@ -0,0 +1,206 @@ +/* + * 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. + */ +#include +#include +#include +#include +#include +#include "trace_util.h" + +trace_main_t trace_main; + +static int +trace_profile_cleanup (trace_profile * profile) +{ + + memset (profile, 0, sizeof (trace_profile)); + profile->trace_tsp = TSP_MICROSECONDS; /* Micro seconds */ + ip6_trace_profile_cleanup (); /* lib-trace_TODO: Remove this once IOAM-IPv6 transport is a plugin */ + return 0; + +} + +static int +trace_main_profiles_reset (void) +{ + int rv; + + trace_main_t *sm = &trace_main; + rv = trace_profile_cleanup (&(sm->profile)); + return (rv); +} + +int +trace_util_init (void) +{ + int rv; + + rv = trace_main_profiles_reset (); + return (rv); +} + + +int +trace_profile_create (trace_profile * profile, u8 trace_type, u8 num_elts, + u32 trace_tsp, u32 node_id, u32 app_data) +{ + + if (!trace_type || !num_elts || !(node_id)) + { + return (-1); + } + if (profile && !profile->valid) + { + //rv = trace_profile_cleanup (profile); + profile->trace_type = trace_type; + profile->num_elts = num_elts; + profile->trace_tsp = trace_tsp; + profile->node_id = node_id; + profile->app_data = app_data; + profile->valid = 1; + + /* lib-trace_TODO: Remove this once IOAM-IPv6 transport is a plugin */ + ip6_trace_profile_setup (); + return (0); + } + + return (-1); +} + + + +clib_error_t * +clear_trace_profile_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + + trace_main_profiles_reset (); + return 0; +} + +void +clear_trace_profiles (void) +{ + clear_trace_profile_command_fn (0, 0, 0); +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND(clear_trace_profile_command) = +{ +.path = "clear ioam-trace profile", +.short_help = "clear ioam-trace profile [|all]", +.function = clear_trace_profile_command_fn, +}; +/* *INDENT-ON* */ + +static clib_error_t * +set_trace_profile_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + u8 trace_type = 0; + u8 num_elts = 0; + u32 node_id = 0; + u32 app_data = 0; + u32 trace_tsp = 0; + trace_profile *profile = NULL; + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "trace-type 0x%x", &trace_type)); + else if (unformat (input, "trace-elts %d", &num_elts)); + else if (unformat (input, "trace-tsp %d", &trace_tsp)); + else if (unformat (input, "node-id 0x%x", &node_id)); + else if (unformat (input, "app-data 0x%x", &app_data)); + else + break; + } + profile = trace_profile_find (); + if (profile) + { + trace_profile_create (profile, trace_type, num_elts, trace_tsp, + node_id, app_data); + } + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (set_trace_profile_command, static) = +{ +.path = "set ioam-trace profile", +.short_help = "set ioam-trace \ + trace-type <0x1f|0x3|0x9|0x11|0x19> trace-elts trace-tsp <0|1|2|3> \ + node-id app-data ", +.function = set_trace_profile_command_fn, +}; +/* *INDENT-ON* */ + +static clib_error_t * +show_trace_profile_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + trace_profile *p = NULL; + u8 *s = 0; + p = trace_profile_find (); + if (!(p && p->valid)) + { + s = format (s, "\nTrace configuration not valid\n"); + vlib_cli_output (vm, "%v", s); + vec_free (s); + return 0; + } + s = format (s, " HOP BY HOP OPTIONS - TRACE CONFIG - \n"); + s = format (s, " Trace Type : 0x%x (%d)\n", + p->trace_type, p->trace_type); + s = + format (s, " Trace timestamp precision : %d (%s)\n", + p->trace_tsp, + (p->trace_tsp == + TSP_SECONDS) ? "Seconds" : ((p->trace_tsp == + TSP_MILLISECONDS) ? + "Milliseconds" + : (((p->trace_tsp == + TSP_MICROSECONDS) ? + "Microseconds" : + "Nanoseconds")))); + s = format (s, " Num of trace nodes : %d\n", p->num_elts); + s = + format (s, " Node-id : 0x%x (%d)\n", + p->node_id, p->node_id); + s = + format (s, " App Data : 0x%x (%d)\n", + p->app_data, p->app_data); + vlib_cli_output (vm, "%v", s); + vec_free (s); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_trace_profile_command, static) = +{ +.path = "show ioam-trace profile", +.short_help = "show ioam-trace profile", +.function = show_trace_profile_command_fn, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/lib-trace/trace_util.h b/src/plugins/ioam/lib-trace/trace_util.h new file mode 100644 index 00000000..556f07ee --- /dev/null +++ b/src/plugins/ioam/lib-trace/trace_util.h @@ -0,0 +1,247 @@ +/* + * trace_util.h -- Trace Profile Utility header + * + * 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. + */ + +#ifndef include_vnet_trace_util_h +#define include_vnet_trace_util_h + +#define debug_ioam debug_ioam_fn + + +/** + * Usage: + * + * On any node that participates in iOAM Trace. + * + * Step 1: Initialize this library by calling trace_init() + * Step 2: Setup a trace profile that contains all the parameters needed to compute cumulative: + * Call these functions: + * trace_profile_find + * trace_profile_create + * Step 2a: On initial node enable the profile to be used: + * trace_profile_set_active / trace_profile_get_active will return the profile + * Step 4: TBD + * trace_validate + * + */ + +typedef struct trace_profile_ +{ + u8 valid:1; + u8 trace_type; + u8 num_elts; + /* Configured node-id */ + u32 node_id; + u32 app_data; + u32 trace_tsp; +} trace_profile; + +typedef struct +{ + /* Name of the default profile list in use */ + trace_profile profile; + + /* API message ID base */ + u16 msg_id_base; + + /* convenience */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} trace_main_t; + +extern trace_main_t trace_main; + +/* + * Initialize Trace profile + */ +int trace_util_init (void); + + +/* + * Find a trace profile + */ + +always_inline trace_profile * +trace_profile_find (void) +{ + trace_main_t *sm = &trace_main; + + return (&(sm->profile)); +} + + +/* setup and clean up profile */ +int trace_profile_create (trace_profile * profile, u8 trace_type, u8 num_elts, + u32 trace_tsp, u32 node_id, u32 app_data); + +void clear_trace_profiles (void); + + + +#define BIT_TTL_NODEID (1<<0) +#define BIT_ING_INTERFACE (1<<1) +#define BIT_EGR_INTERFACE (1<<2) +#define BIT_TIMESTAMP (1<<3) +#define BIT_APPDATA (1<<4) +#define TRACE_TYPE_MASK 0x1F /* Mask of all above bits */ + +/* + 0x00011111 iOAM-trace-type is 0x00011111 then the format of node + data is: + + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Hop_Lim | node_id | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ingress_if_id | egress_if_id | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + timestamp + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | app_data | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +*/ +#define TRACE_TYPE_IF_TS_APP 0x1f +typedef struct +{ + u32 ttl_node_id; + u16 ingress_if; + u16 egress_if; + u32 timestamp; + u32 app_data; +} ioam_trace_if_ts_app_t; + +/* + 0x00000111 iOAM-trace-type is 0x00000111 then the format is: + + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Hop_Lim | node_id | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ingress_if_id | egress_if_id | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +*/ + +#define TRACE_TYPE_IF 0x03 +typedef struct +{ + u32 ttl_node_id; + u16 ingress_if; + u16 egress_if; +} ioam_trace_if_t; + +/* + 0x00001001 iOAM-trace-type is 0x00001001 then the format is: + + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Hop_Lim | node_id | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + timestamp + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +*/ + +#define TRACE_TYPE_TS 0x09 +typedef struct +{ + u32 ttl_node_id; + u32 timestamp; +} ioam_trace_ts_t; + +/* + 0x00010001 iOAM-trace-type is 0x00010001 then the format is: + + + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Hop_Lim | node_id | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | app_data | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +*/ + + +#define TRACE_TYPE_APP 0x11 +typedef struct +{ + u32 ttl_node_id; + u32 app_data; +} ioam_trace_app_t; + +/* + + 0x00011001 iOAM-trace-type is 0x00011001 then the format is: + + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Hop_Lim | node_id | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + timestamp + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | app_data | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +#define TRACE_TYPE_TS_APP 0x19 +typedef struct +{ + u32 ttl_node_id; + u32 timestamp; + u32 app_data; +} ioam_trace_ts_app_t; + + + +static inline u8 +fetch_trace_data_size (u8 trace_type) +{ + u8 trace_data_size = 0; + + if (trace_type == TRACE_TYPE_IF_TS_APP) + trace_data_size = sizeof (ioam_trace_if_ts_app_t); + else if (trace_type == TRACE_TYPE_IF) + trace_data_size = sizeof (ioam_trace_if_t); + else if (trace_type == TRACE_TYPE_TS) + trace_data_size = sizeof (ioam_trace_ts_t); + else if (trace_type == TRACE_TYPE_APP) + trace_data_size = sizeof (ioam_trace_app_t); + else if (trace_type == TRACE_TYPE_TS_APP) + trace_data_size = sizeof (ioam_trace_ts_app_t); + + return trace_data_size; +} + +int ioam_trace_get_sizeof_handler (u32 * result); +int ip6_trace_profile_setup (void); +int ip6_trace_profile_cleanup (void); + +#define TSP_SECONDS 0 +#define TSP_MILLISECONDS 1 +#define TSP_MICROSECONDS 2 +#define TSP_NANOSECONDS 3 + +#endif + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/lib-vxlan-gpe/ioam_decap.c b/src/plugins/ioam/lib-vxlan-gpe/ioam_decap.c new file mode 100644 index 00000000..fd308657 --- /dev/null +++ b/src/plugins/ioam/lib-vxlan-gpe/ioam_decap.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Statistics (not really errors) */ +#define foreach_vxlan_gpe_decap_ioam_v4_error \ +_(DECAPSULATED, "good packets decapsulated") + +static char *vxlan_gpe_decap_ioam_v4_error_strings[] = { +#define _(sym,string) string, + foreach_vxlan_gpe_decap_ioam_v4_error +#undef _ +}; + +typedef enum +{ +#define _(sym,str) VXLAN_GPE_DECAP_IOAM_V4_ERROR_##sym, + foreach_vxlan_gpe_decap_ioam_v4_error +#undef _ + VXLAN_GPE_DECAP_IOAM_V4_N_ERROR, +} vxlan_gpe_decap_ioam_v4_error_t; + + +always_inline void +vxlan_gpe_decap_ioam_v4_two_inline (vlib_main_t * vm, + vlib_node_runtime_t * node, + vxlan_gpe_main_t * ngm, + vlib_buffer_t * b0, vlib_buffer_t * b1, + u32 * next0, u32 * next1) +{ + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + + next0[0] = next1[0] = hm->decap_v4_next_override; + vxlan_gpe_encap_decap_ioam_v4_one_inline (vm, node, b0, &next0[0], + VXLAN_GPE_DECAP_IOAM_V4_NEXT_DROP, + 0 /* use_adj */ ); + vxlan_gpe_encap_decap_ioam_v4_one_inline (vm, node, b1, &next0[1], + VXLAN_GPE_DECAP_IOAM_V4_NEXT_DROP, + 0 /* use_adj */ ); +} + + + +static uword +vxlan_gpe_decap_ioam (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * from_frame, u8 is_ipv6) +{ + u32 n_left_from, next_index, *from, *to_next; + vxlan_gpe_main_t *ngm = &vxlan_gpe_main; + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + + from = vlib_frame_vector_args (from_frame); + n_left_from = 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 bi0, bi1; + vlib_buffer_t *b0, *b1; + u32 next0, next1; + + next0 = next1 = hm->decap_v4_next_override; + + /* 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, 2 * CLIB_CACHE_LINE_BYTES, LOAD); + CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD); + } + + bi0 = from[0]; + bi1 = from[1]; + to_next[0] = bi0; + to_next[1] = bi1; + from += 2; + to_next += 2; + n_left_to_next -= 2; + n_left_from -= 2; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + + + vlib_buffer_advance (b0, + -(word) (sizeof (udp_header_t) + + sizeof (ip4_header_t) + + sizeof (vxlan_gpe_header_t))); + vlib_buffer_advance (b1, + -(word) (sizeof (udp_header_t) + + sizeof (ip4_header_t) + + sizeof (vxlan_gpe_header_t))); + + vxlan_gpe_decap_ioam_v4_two_inline (vm, node, ngm, b0, b1, + &next0, &next1); + + + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, + n_left_to_next, bi0, bi1, next0, + next1); + + if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) + { + vxlan_gpe_ioam_v4_trace_t *tr = vlib_add_trace (vm, node, b0, + sizeof (*tr)); + } + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0 = hm->decap_v4_next_override; + + 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); + + + vlib_buffer_advance (b0, + -(word) (sizeof (udp_header_t) + + sizeof (ip4_header_t) + + sizeof (vxlan_gpe_header_t))); + + next0 = hm->decap_v4_next_override; + vxlan_gpe_encap_decap_ioam_v4_one_inline (vm, node, b0, + &next0, + VXLAN_GPE_DECAP_IOAM_V4_NEXT_DROP, + 0 /* use_adj */ ); + + if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) + { + vxlan_gpe_ioam_v4_trace_t *tr = vlib_add_trace (vm, node, b0, + sizeof (*tr)); + } + 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); + } + + return from_frame->n_vectors; +} + + +static uword +vxlan_gpe_decap_ioam_v4 (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + return vxlan_gpe_decap_ioam (vm, node, from_frame, 0); +} + + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (vxlan_gpe_decap_ioam_v4_node) = { + .function = vxlan_gpe_decap_ioam_v4, + .name = "vxlan-gpe-decap-ioam-v4", + .vector_size = sizeof (u32), + .format_trace = format_vxlan_gpe_ioam_v4_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(vxlan_gpe_decap_ioam_v4_error_strings), + .error_strings = vxlan_gpe_decap_ioam_v4_error_strings, + + .n_next_nodes = VXLAN_GPE_DECAP_IOAM_V4_N_NEXT, + + .next_nodes = { + [VXLAN_GPE_DECAP_IOAM_V4_NEXT_POP] = "vxlan-gpe-pop-ioam-v4", + [VXLAN_GPE_DECAP_IOAM_V4_NEXT_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/lib-vxlan-gpe/ioam_encap.c b/src/plugins/ioam/lib-vxlan-gpe/ioam_encap.c new file mode 100644 index 00000000..4b18bfea --- /dev/null +++ b/src/plugins/ioam/lib-vxlan-gpe/ioam_encap.c @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Statistics (not really errors) */ +#define foreach_vxlan_gpe_encap_ioam_v4_error \ +_(ENCAPSULATED, "good packets encapsulated") + +static char *vxlan_gpe_encap_ioam_v4_error_strings[] = { +#define _(sym,string) string, + foreach_vxlan_gpe_encap_ioam_v4_error +#undef _ +}; + +typedef enum +{ +#define _(sym,str) VXLAN_GPE_ENCAP_IOAM_V4_ERROR_##sym, + foreach_vxlan_gpe_encap_ioam_v4_error +#undef _ + VXLAN_GPE_ENCAP_IOAM_V4_N_ERROR, +} vxlan_gpe_encap_ioam_v4_error_t; + +typedef enum +{ + VXLAN_GPE_ENCAP_IOAM_V4_NEXT_IP4_LOOKUP, + VXLAN_GPE_ENCAP_IOAM_V4_NEXT_DROP, + VXLAN_GPE_ENCAP_IOAM_V4_N_NEXT +} vxlan_gpe_encap_ioam_v4_next_t; + + +always_inline void +vxlan_gpe_encap_ioam_v4_two_inline (vlib_main_t * vm, + vlib_node_runtime_t * node, + vxlan_gpe_main_t * ngm, + vlib_buffer_t * b0, vlib_buffer_t * b1, + u32 * next0, u32 * next1) +{ + next0[0] = next1[0] = VXLAN_GPE_ENCAP_IOAM_V4_NEXT_IP4_LOOKUP; + vxlan_gpe_encap_decap_ioam_v4_one_inline (vm, node, b0, next0, + VXLAN_GPE_ENCAP_IOAM_V4_NEXT_DROP, + 0 /* use_adj */ ); + vxlan_gpe_encap_decap_ioam_v4_one_inline (vm, node, b1, next1, + VXLAN_GPE_ENCAP_IOAM_V4_NEXT_DROP, + 0 /* use_adj */ ); +} + + +static uword +vxlan_gpe_encap_ioam_v4 (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + u32 n_left_from, next_index, *from, *to_next; + vxlan_gpe_main_t *ngm = &vxlan_gpe_main; + + from = vlib_frame_vector_args (from_frame); + n_left_from = 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 bi0, bi1; + vlib_buffer_t *b0, *b1; + u32 next0, next1; + + next0 = next1 = VXLAN_GPE_ENCAP_IOAM_V4_NEXT_IP4_LOOKUP; + + /* 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, 2 * CLIB_CACHE_LINE_BYTES, LOAD); + CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD); + } + + bi0 = from[0]; + bi1 = from[1]; + to_next[0] = bi0; + to_next[1] = bi1; + from += 2; + to_next += 2; + n_left_to_next -= 2; + n_left_from -= 2; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + + vxlan_gpe_encap_ioam_v4_two_inline (vm, node, ngm, b0, b1, + &next0, &next1); + + + 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 = VXLAN_GPE_ENCAP_IOAM_V4_NEXT_IP4_LOOKUP; + + 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); + + vxlan_gpe_encap_decap_ioam_v4_one_inline (vm, node, b0, + &next0, + VXLAN_GPE_ENCAP_IOAM_V4_NEXT_DROP, + 0 /* use_adj */ ); + + if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) + { + vxlan_gpe_ioam_v4_trace_t *tr = vlib_add_trace (vm, node, b0, + sizeof (*tr)); + } + 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); + } + + return from_frame->n_vectors; +} + + + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (vxlan_gpe_encap_ioam_v4_node) = { + .function = vxlan_gpe_encap_ioam_v4, + .name = "vxlan-gpe-encap-ioam-v4", + .vector_size = sizeof (u32), + .format_trace = format_vxlan_gpe_ioam_v4_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(vxlan_gpe_encap_ioam_v4_error_strings), + .error_strings = vxlan_gpe_encap_ioam_v4_error_strings, + + .n_next_nodes = VXLAN_GPE_ENCAP_IOAM_V4_N_NEXT, + + .next_nodes = { + [VXLAN_GPE_ENCAP_IOAM_V4_NEXT_IP4_LOOKUP] = "ip4-lookup", + [VXLAN_GPE_ENCAP_IOAM_V4_NEXT_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/lib-vxlan-gpe/ioam_pop.c b/src/plugins/ioam/lib-vxlan-gpe/ioam_pop.c new file mode 100644 index 00000000..55c33b14 --- /dev/null +++ b/src/plugins/ioam/lib-vxlan-gpe/ioam_pop.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include + +/* Statistics (not really errors) */ +#define foreach_vxlan_gpe_pop_ioam_v4_error \ +_(POPPED, "good packets popped") + +static char *vxlan_gpe_pop_ioam_v4_error_strings[] = { +#define _(sym,string) string, + foreach_vxlan_gpe_pop_ioam_v4_error +#undef _ +}; + +typedef enum +{ +#define _(sym,str) VXLAN_GPE_POP_IOAM_V4_ERROR_##sym, + foreach_vxlan_gpe_pop_ioam_v4_error +#undef _ + VXLAN_GPE_POP_IOAM_V4_N_ERROR, +} vxlan_gpe_pop_ioam_v4_error_t; + +typedef struct +{ + ioam_trace_t fmt_trace; +} vxlan_gpe_pop_ioam_v4_trace_t; + + +u8 * +format_vxlan_gpe_pop_ioam_v4_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 *); + vxlan_gpe_pop_ioam_v4_trace_t *t1 + = va_arg (*args, vxlan_gpe_pop_ioam_v4_trace_t *); + ioam_trace_t *t = &(t1->fmt_trace); + vxlan_gpe_ioam_option_t *fmt_trace0; + vxlan_gpe_ioam_option_t *opt0, *limit0; + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + + u8 type0; + + fmt_trace0 = (vxlan_gpe_ioam_option_t *) t->option_data; + + s = format (s, "VXLAN_GPE_IOAM_POP: next_index %d len %d traced %d", + t->next_index, fmt_trace0->length, t->trace_len); + + opt0 = (vxlan_gpe_ioam_option_t *) (fmt_trace0 + 1); + limit0 = (vxlan_gpe_ioam_option_t *) ((u8 *) fmt_trace0) + t->trace_len; + + while (opt0 < limit0) + { + type0 = opt0->type; + switch (type0) + { + case 0: /* Pad, just stop */ + opt0 = (vxlan_gpe_ioam_option_t *) ((u8 *) opt0) + 1; + break; + + default: + if (hm->trace[type0]) + { + s = (*hm->trace[type0]) (s, opt0); + } + else + { + s = + format (s, "\n unrecognized option %d length %d", type0, + opt0->length); + } + opt0 = + (vxlan_gpe_ioam_option_t *) (((u8 *) opt0) + opt0->length + + sizeof (vxlan_gpe_ioam_option_t)); + break; + } + } + + return s; +} + +always_inline void +vxlan_gpe_ioam_pop_v4 (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_buffer_t * b0) +{ + ip4_header_t *ip0; + udp_header_t *udp_hdr0; + vxlan_gpe_header_t *gpe_hdr0; + vxlan_gpe_ioam_hdr_t *gpe_ioam0; + + ip0 = vlib_buffer_get_current (b0); + + udp_hdr0 = (udp_header_t *) (ip0 + 1); + gpe_hdr0 = (vxlan_gpe_header_t *) (udp_hdr0 + 1); + gpe_ioam0 = (vxlan_gpe_ioam_hdr_t *) (gpe_hdr0 + 1); + + /* Pop the iOAM data */ + vlib_buffer_advance (b0, + (word) (sizeof (udp_header_t) + + sizeof (ip4_header_t) + + sizeof (vxlan_gpe_header_t) + + gpe_ioam0->length)); + + return; +} + + + +always_inline void +vxlan_gpe_pop_ioam_v4_one_inline (vlib_main_t * vm, + vlib_node_runtime_t * node, + vxlan_gpe_main_t * ngm, + vlib_buffer_t * b0, u32 * next0) +{ + CLIB_UNUSED (ip4_header_t * ip0); + CLIB_UNUSED (udp_header_t * udp_hdr0); + CLIB_UNUSED (vxlan_gpe_header_t * gpe_hdr0); + CLIB_UNUSED (vxlan_gpe_ioam_hdr_t * gpe_ioam0); + CLIB_UNUSED (vxlan_gpe_ioam_option_t * opt0); + CLIB_UNUSED (vxlan_gpe_ioam_option_t * limit0); + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + + + /* Pop the iOAM header */ + ip0 = vlib_buffer_get_current (b0); + udp_hdr0 = (udp_header_t *) (ip0 + 1); + gpe_hdr0 = (vxlan_gpe_header_t *) (udp_hdr0 + 1); + gpe_ioam0 = (vxlan_gpe_ioam_hdr_t *) (gpe_hdr0 + 1); + opt0 = (vxlan_gpe_ioam_option_t *) (gpe_ioam0 + 1); + limit0 = (vxlan_gpe_ioam_option_t *) ((u8 *) gpe_ioam0 + gpe_ioam0->length); + + /* + * Basic validity checks + */ + if (gpe_ioam0->length > clib_net_to_host_u16 (ip0->length)) + { + next0[0] = VXLAN_GPE_INPUT_NEXT_DROP; + goto trace00; + } + + /* Scan the set of h-b-h options, process ones that we understand */ + while (opt0 < limit0) + { + u8 type0; + type0 = opt0->type; + switch (type0) + { + case 0: /* Pad1 */ + opt0 = (vxlan_gpe_ioam_option_t *) ((u8 *) opt0) + 1; + continue; + case 1: /* PadN */ + break; + default: + if (hm->pop_options[type0]) + { + if ((*hm->pop_options[type0]) (ip0, opt0) < 0) + { + next0[0] = VXLAN_GPE_INPUT_NEXT_DROP; + goto trace00; + } + } + break; + } + opt0 = + (vxlan_gpe_ioam_option_t *) (((u8 *) opt0) + opt0->length + + sizeof (vxlan_gpe_ioam_hdr_t)); + } + + + next0[0] = + (gpe_ioam0->protocol < VXLAN_GPE_PROTOCOL_MAX) ? + ngm-> + decap_next_node_list[gpe_ioam0->protocol] : VXLAN_GPE_INPUT_NEXT_DROP; + +trace00: + if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) + { + vxlan_gpe_pop_ioam_v4_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + u32 trace_len = gpe_ioam0->length; + t->fmt_trace.next_index = next0[0]; + /* Capture the h-b-h option verbatim */ + trace_len = + trace_len < + ARRAY_LEN (t->fmt_trace. + option_data) ? trace_len : ARRAY_LEN (t->fmt_trace. + option_data); + t->fmt_trace.trace_len = trace_len; + clib_memcpy (&(t->fmt_trace.option_data), gpe_ioam0, trace_len); + } + + /* Remove the iOAM header inside the VxLAN-GPE header */ + vxlan_gpe_ioam_pop_v4 (vm, node, b0); + return; +} + +always_inline void +vxlan_gpe_pop_ioam_v4_two_inline (vlib_main_t * vm, + vlib_node_runtime_t * node, + vxlan_gpe_main_t * ngm, + vlib_buffer_t * b0, vlib_buffer_t * b1, + u32 * next0, u32 * next1) +{ + + vxlan_gpe_pop_ioam_v4_one_inline (vm, node, ngm, b0, next0); + vxlan_gpe_pop_ioam_v4_one_inline (vm, node, ngm, b1, next1); +} + + + +static uword +vxlan_gpe_pop_ioam (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * from_frame, u8 is_ipv6) +{ + u32 n_left_from, next_index, *from, *to_next; + vxlan_gpe_main_t *ngm = &vxlan_gpe_main; + + from = vlib_frame_vector_args (from_frame); + n_left_from = 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 bi0, bi1; + vlib_buffer_t *b0, *b1; + u32 next0, next1; + + /* 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, 2 * CLIB_CACHE_LINE_BYTES, LOAD); + CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD); + } + + bi0 = from[0]; + bi1 = from[1]; + to_next[0] = bi0; + to_next[1] = bi1; + from += 2; + to_next += 2; + n_left_to_next -= 2; + n_left_from -= 2; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + + vxlan_gpe_pop_ioam_v4_two_inline (vm, node, ngm, b0, b1, &next0, + &next1); + + + 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; + + 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); + + vxlan_gpe_pop_ioam_v4_one_inline (vm, node, ngm, b0, &next0); + + + 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); + } + + return from_frame->n_vectors; +} + + +static uword +vxlan_gpe_pop_ioam_v4 (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * from_frame) +{ + return vxlan_gpe_pop_ioam (vm, node, from_frame, 0); +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (vxlan_gpe_pop_ioam_v4_node) = { + .function = vxlan_gpe_pop_ioam_v4, + .name = "vxlan-gpe-pop-ioam-v4", + .vector_size = sizeof (u32), + .format_trace = format_vxlan_gpe_pop_ioam_v4_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(vxlan_gpe_pop_ioam_v4_error_strings), + .error_strings = vxlan_gpe_pop_ioam_v4_error_strings, + + .n_next_nodes = VXLAN_GPE_INPUT_N_NEXT, + + .next_nodes = { +#define _(s,n) [VXLAN_GPE_INPUT_NEXT_##s] = n, + foreach_vxlan_gpe_input_next +#undef _ + }, +}; +/* *INDENT-ON* */ + + + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/lib-vxlan-gpe/ioam_transit.c b/src/plugins/ioam/lib-vxlan-gpe/ioam_transit.c new file mode 100644 index 00000000..b42c357c --- /dev/null +++ b/src/plugins/ioam/lib-vxlan-gpe/ioam_transit.c @@ -0,0 +1,188 @@ + /* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Statistics (not really errors) */ +#define foreach_vxlan_gpe_transit_ioam_error \ +_(ENCAPSULATED, "good packets encapsulated") + +static char *vxlan_gpe_transit_ioam_error_strings[] = { +#define _(sym,string) string, + foreach_vxlan_gpe_transit_ioam_error +#undef _ +}; + +typedef enum +{ +#define _(sym,str) VXLAN_GPE_TRANSIT_IOAM_ERROR_##sym, + foreach_vxlan_gpe_transit_ioam_error +#undef _ + VXLAN_GPE_TRANSIT_IOAM_N_ERROR, +} vxlan_gpe_transit_ioam_error_t; + +typedef enum +{ + VXLAN_GPE_TRANSIT_IOAM_NEXT_OUTPUT, + VXLAN_GPE_TRANSIT_IOAM_NEXT_DROP, + VXLAN_GPE_TRANSIT_IOAM_N_NEXT +} vxlan_gpe_transit_ioam_next_t; + + +/* *INDENT-OFF* */ +VNET_FEATURE_INIT (vxlan_gpe_transit_ioam, static) = +{ + .arc_name = "ip4-output", + .node_name = "vxlan-gpe-transit-ioam", + .runs_before = VNET_FEATURES ("interface-output"), +}; +/* *INDENT-ON* */ + +static uword +vxlan_gpe_transit_ioam (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * from_frame) +{ + u32 n_left_from, next_index, *from, *to_next; + + from = vlib_frame_vector_args (from_frame); + n_left_from = 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 > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0 = VXLAN_GPE_TRANSIT_IOAM_NEXT_OUTPUT; + + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + ip4_header_t *ip0; + u32 iph_offset = 0; + + b0 = vlib_get_buffer (vm, bi0); + iph_offset = vnet_buffer (b0)->ip.save_rewrite_length; + ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) + + iph_offset); + + /* just forward non ipv4 packets */ + if (PREDICT_FALSE + ((ip0->ip_version_and_header_length & 0xF0) == 0x40)) + { + /* ipv4 packets */ + udp_header_t *udp_hdr0 = (udp_header_t *) (ip0 + 1); + if (PREDICT_FALSE + ((ip0->protocol == IP_PROTOCOL_UDP) && + (clib_net_to_host_u16 (udp_hdr0->dst_port) == + UDP_DST_PORT_vxlan_gpe))) + { + + /* Check the iOAM header */ + vxlan_gpe_header_t *gpe_hdr0 = + (vxlan_gpe_header_t *) (udp_hdr0 + 1); + + if (PREDICT_FALSE + (gpe_hdr0->protocol == VXLAN_GPE_PROTOCOL_IOAM)) + { + uword *t = NULL; + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + fib_prefix_t key4; + memset (&key4, 0, sizeof (key4)); + key4.fp_proto = FIB_PROTOCOL_IP4; + key4.fp_addr.ip4.as_u32 = ip0->dst_address.as_u32; + t = hash_get_mem (hm->dst_by_ip4, &key4); + if (t) + { + + + vlib_buffer_advance (b0, + (word) (sizeof + (ethernet_header_t))); + vxlan_gpe_encap_decap_ioam_v4_one_inline (vm, node, + b0, + &next0, + VXLAN_GPE_TRANSIT_IOAM_NEXT_DROP, + 1 + /* use_adj */ + ); + vlib_buffer_advance (b0, + -(word) (sizeof + (ethernet_header_t))); + } + } + } + } + + 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); + } + + return from_frame->n_vectors; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (vxlan_gpe_transit_ioam_node) = { + .function = vxlan_gpe_transit_ioam, + .name = "vxlan-gpe-transit-ioam", + .vector_size = sizeof (u32), + .format_trace = format_vxlan_gpe_ioam_v4_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(vxlan_gpe_transit_ioam_error_strings), + .error_strings = vxlan_gpe_transit_ioam_error_strings, + + .n_next_nodes = VXLAN_GPE_TRANSIT_IOAM_N_NEXT, + + .next_nodes = { + [VXLAN_GPE_TRANSIT_IOAM_NEXT_OUTPUT] = "interface-output", + [VXLAN_GPE_TRANSIT_IOAM_NEXT_DROP] = "error-drop", + }, + +}; +/* *INDENT-ON* */ + + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/lib-vxlan-gpe/ioam_vxlan_gpe.api b/src/plugins/ioam/lib-vxlan-gpe/ioam_vxlan_gpe.api new file mode 100644 index 00000000..056529a4 --- /dev/null +++ b/src/plugins/ioam/lib-vxlan-gpe/ioam_vxlan_gpe.api @@ -0,0 +1,181 @@ +/* Hey Emacs use -*- mode: C -*- */ +/* + * 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. + */ + + +/** \brief iOAM Over VxLAN-GPE - Set iOAM transport for VxLAN-GPE + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param id - profile id + @param trace_ppc - Trace PPC (none/encap/decap) + @param pow_enable - Proof of Work enabled or not flag + @param trace_enable - iOAM Trace enabled or not flag + +*/ +define vxlan_gpe_ioam_enable { + u32 client_index; + u32 context; + u16 id; + u8 trace_ppc; + u8 pow_enable; + u8 trace_enable; +}; + +/** \brief iOAM Over VxLAN-GPE - Set iOAM transport for VXLAN-GPE reply + @param context - sender context, to match reply w/ request + @param retval - return value for request +*/ +define vxlan_gpe_ioam_enable_reply { + u32 context; + i32 retval; +}; + + +/** \brief iOAM for VxLAN-GPE disable + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param id - profile id +*/ +define vxlan_gpe_ioam_disable +{ + u32 client_index; + u32 context; + u16 id; +}; + +/** \brief vxlan_gpe_ioam disable response + @param context - sender context, to match reply w/ request + @param retval - return value for request +*/ +define vxlan_gpe_ioam_disable_reply +{ + u32 context; + i32 retval; +}; + +/** \brief Enable iOAM for a VNI (VXLAN-GPE) + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param vni - VXLAN-GPE VNI + @param local - IPv4/6 Address of the local VTEP + @param remote - IPv4/6 Address of the remote VTEP + +*/ +define vxlan_gpe_ioam_vni_enable { + u32 client_index; + u32 context; + u32 vni; + u8 local[16]; + u8 remote[16]; + u8 is_ipv6; +}; + +/** \brief Reply to enable iOAM for a VNI (VXLAN-GPE) + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param retval - return value for request + +*/ +define vxlan_gpe_ioam_vni_enable_reply { + u32 client_index; + u32 context; + i32 retval; +}; + +/** \brief Disable iOAM for a VNI (VXLAN-GPE) + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param vni - VXLAN-GPE VNI + @param local - IPv4/6 Address of the local VTEP + @param remote - IPv4/6 Address of the remote VTEP + +*/ +define vxlan_gpe_ioam_vni_disable { + u32 client_index; + u32 context; + u32 vni; + u8 local[16]; + u8 remote[16]; + u8 is_ipv6; +}; + +/** \brief Reply to disable iOAM for a VNI (VXLAN-GPE) + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param retval - return value for request + +*/ +define vxlan_gpe_ioam_vni_disable_reply { + u32 client_index; + u32 context; + i32 retval; +}; + + +/** \brief Enable iOAM for a VXLAN-GPE transit + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param dst_addr - IPv4/6 Address of the local VTEP + @param outer_fib_index- FIB index + +*/ +define vxlan_gpe_ioam_transit_enable { + u32 client_index; + u32 context; + u32 outer_fib_index; + u8 dst_addr[16]; + u8 is_ipv6; +}; + +/** \brief Reply to enable iOAM for VXLAN-GPE transit + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param retval - return value for request + +*/ +define vxlan_gpe_ioam_transit_enable_reply { + u32 client_index; + u32 context; + i32 retval; +}; + +/** \brief Disable iOAM for VXLAN-GPE transit + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param dst_addr - IPv4/6 Address of the local VTEP + @param outer_fib_index- FIB index + +*/ +define vxlan_gpe_ioam_transit_disable { + u32 client_index; + u32 context; + u32 outer_fib_index; + u8 dst_addr[16]; + u8 is_ipv6; +}; + +/** \brief Reply to disable iOAM for VXLAN-GPE transit + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param retval - return value for request + +*/ +define vxlan_gpe_ioam_transit_disable_reply { + u32 client_index; + u32 context; + i32 retval; +}; + + diff --git a/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_all_api_h.h b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_all_api_h.h new file mode 100644 index 00000000..06fa0d2c --- /dev/null +++ b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_all_api_h.h @@ -0,0 +1,16 @@ +/* + * 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. + */ +/* Include the generated file, see BUILT_SOURCES in Makefile.am */ +#include diff --git a/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_api.c b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_api.c new file mode 100644 index 00000000..68752365 --- /dev/null +++ b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_api.c @@ -0,0 +1,378 @@ +/* + * 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. + */ +/* + *------------------------------------------------------------------ + * vxlan_gpe_api.c - iOAM VxLAN-GPE related APIs to create + * and maintain profiles + *------------------------------------------------------------------ + */ + +#include +#include +#include + +#include +#include +#include + +/* define message IDs */ +#include + +/* define message structures */ +#define vl_typedefs +#include +#undef vl_typedefs + +/* define generated endian-swappers */ +#define vl_endianfun +#include +#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 +#undef vl_printfun + +/* Get the API version number */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#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 VXLAN_GPE_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); + +/* *INDENT-OFF* */ +#define VXLAN_GPE_REPLY_MACRO2(t, body) \ +do { \ + unix_shared_memory_queue_t * q; \ + rv = vl_msg_api_pd_handler (mp, rv); \ + 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)); \ + rmp->context = mp->context; \ + rmp->retval = ntohl(rv); \ + do {body;} while (0); \ + vl_msg_api_send_shmem (q, (u8 *)&rmp); \ +} while(0); +/* *INDENT-ON* */ + +/* List of message types that this plugin understands */ + +#define foreach_vxlan_gpe_plugin_api_msg \ +_(VXLAN_GPE_IOAM_ENABLE, vxlan_gpe_ioam_enable) \ +_(VXLAN_GPE_IOAM_DISABLE, vxlan_gpe_ioam_disable) \ +_(VXLAN_GPE_IOAM_VNI_ENABLE, vxlan_gpe_ioam_vni_enable) \ +_(VXLAN_GPE_IOAM_VNI_DISABLE, vxlan_gpe_ioam_vni_disable) \ +_(VXLAN_GPE_IOAM_TRANSIT_ENABLE, vxlan_gpe_ioam_transit_enable) \ +_(VXLAN_GPE_IOAM_TRANSIT_DISABLE, vxlan_gpe_ioam_transit_disable) \ + + +static void vl_api_vxlan_gpe_ioam_enable_t_handler + (vl_api_vxlan_gpe_ioam_enable_t * mp) +{ + int rv = 0; + vl_api_vxlan_gpe_ioam_enable_reply_t *rmp; + clib_error_t *error; + vxlan_gpe_ioam_main_t *sm = &vxlan_gpe_ioam_main; + + /* Ignoring the profile id as currently a single profile + * is supported */ + error = + vxlan_gpe_ioam_enable (mp->trace_enable, mp->pow_enable, mp->trace_ppc); + if (error) + { + clib_error_report (error); + rv = clib_error_get_code (error); + } + + VXLAN_GPE_REPLY_MACRO (VL_API_VXLAN_GPE_IOAM_ENABLE_REPLY); +} + +static void vl_api_vxlan_gpe_ioam_disable_t_handler + (vl_api_vxlan_gpe_ioam_disable_t * mp) +{ + int rv = 0; + vl_api_vxlan_gpe_ioam_disable_reply_t *rmp; + clib_error_t *error; + vxlan_gpe_ioam_main_t *sm = &vxlan_gpe_ioam_main; + + /* Ignoring the profile id as currently a single profile + * is supported */ + error = vxlan_gpe_ioam_disable (0, 0, 0); + if (error) + { + clib_error_report (error); + rv = clib_error_get_code (error); + } + + VXLAN_GPE_REPLY_MACRO (VL_API_VXLAN_GPE_IOAM_DISABLE_REPLY); +} + +static void vl_api_vxlan_gpe_ioam_vni_enable_t_handler + (vl_api_vxlan_gpe_ioam_vni_enable_t * mp) +{ + int rv = 0; + vl_api_vxlan_gpe_ioam_vni_enable_reply_t *rmp; + clib_error_t *error; + vxlan_gpe_ioam_main_t *sm = &vxlan_gpe_ioam_main; + vxlan4_gpe_tunnel_key_t key4; + uword *p = NULL; + vxlan_gpe_main_t *gm = &vxlan_gpe_main; + vxlan_gpe_tunnel_t *t = 0; + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + u32 vni; + + + if (!mp->is_ipv6) + { + clib_memcpy (&key4.local, &mp->local, sizeof (key4.local)); + clib_memcpy (&key4.remote, &mp->remote, sizeof (key4.remote)); + vni = clib_net_to_host_u32 (mp->vni); + key4.vni = clib_host_to_net_u32 (vni << 8); + key4.pad = 0; + + p = hash_get_mem (gm->vxlan4_gpe_tunnel_by_key, &key4); + } + else + { + return; + } + + if (!p) + return; + + t = pool_elt_at_index (gm->tunnels, p[0]); + + error = vxlan_gpe_ioam_set (t, hm->has_trace_option, + hm->has_pot_option, + hm->has_ppc_option, mp->is_ipv6); + + + if (error) + { + clib_error_report (error); + rv = clib_error_get_code (error); + } + + VXLAN_GPE_REPLY_MACRO (VL_API_VXLAN_GPE_IOAM_VNI_ENABLE_REPLY); +} + + +static void vl_api_vxlan_gpe_ioam_vni_disable_t_handler + (vl_api_vxlan_gpe_ioam_vni_disable_t * mp) +{ + int rv = 0; + vl_api_vxlan_gpe_ioam_vni_enable_reply_t *rmp; + clib_error_t *error; + vxlan_gpe_ioam_main_t *sm = &vxlan_gpe_ioam_main; + vxlan4_gpe_tunnel_key_t key4; + uword *p = NULL; + vxlan_gpe_main_t *gm = &vxlan_gpe_main; + vxlan_gpe_tunnel_t *t = 0; + u32 vni; + + + if (!mp->is_ipv6) + { + clib_memcpy (&key4.local, &mp->local, sizeof (key4.local)); + clib_memcpy (&key4.remote, &mp->remote, sizeof (key4.remote)); + vni = clib_net_to_host_u32 (mp->vni); + key4.vni = clib_host_to_net_u32 (vni << 8); + key4.pad = 0; + + p = hash_get_mem (gm->vxlan4_gpe_tunnel_by_key, &key4); + } + else + { + return; + } + + if (!p) + return; + + t = pool_elt_at_index (gm->tunnels, p[0]); + + error = vxlan_gpe_ioam_clear (t, 0, 0, 0, 0); + + + if (error) + { + clib_error_report (error); + rv = clib_error_get_code (error); + } + + + VXLAN_GPE_REPLY_MACRO (VL_API_VXLAN_GPE_IOAM_VNI_DISABLE_REPLY); +} + +static void vl_api_vxlan_gpe_ioam_transit_enable_t_handler + (vl_api_vxlan_gpe_ioam_transit_enable_t * mp) +{ + int rv = 0; + vl_api_vxlan_gpe_ioam_transit_enable_reply_t *rmp; + vxlan_gpe_ioam_main_t *sm = &vxlan_gpe_ioam_main; + ip46_address_t dst_addr; + + memset (&dst_addr.ip4, 0, sizeof (dst_addr.ip4)); + if (!mp->is_ipv6) + { + clib_memcpy (&dst_addr.ip4, &mp->dst_addr, sizeof (dst_addr.ip4)); + } + rv = vxlan_gpe_enable_disable_ioam_for_dest (sm->vlib_main, + dst_addr, + ntohl (mp->outer_fib_index), + mp->is_ipv6 ? 0 : 1, + 1 /* is_add */ ); + + VXLAN_GPE_REPLY_MACRO (VL_API_VXLAN_GPE_IOAM_TRANSIT_ENABLE_REPLY); +} + +static void vl_api_vxlan_gpe_ioam_transit_disable_t_handler + (vl_api_vxlan_gpe_ioam_transit_disable_t * mp) +{ + int rv = 0; + vl_api_vxlan_gpe_ioam_transit_disable_reply_t *rmp; + vxlan_gpe_ioam_main_t *sm = &vxlan_gpe_ioam_main; + ip46_address_t dst_addr; + + memset (&dst_addr.ip4, 0, sizeof (dst_addr.ip4)); + if (!mp->is_ipv6) + { + clib_memcpy (&dst_addr.ip4, &mp->dst_addr, sizeof (dst_addr.ip4)); + } + + rv = vxlan_gpe_ioam_disable_for_dest (sm->vlib_main, + dst_addr, + ntohl (mp->outer_fib_index), + mp->is_ipv6 ? 0 : 1); + VXLAN_GPE_REPLY_MACRO (VL_API_VXLAN_GPE_IOAM_TRANSIT_DISABLE_REPLY); +} + + +/* + * 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) +{ + vxlan_gpe_ioam_main_t *sm = &vxlan_gpe_ioam_main; + clib_error_t *error = 0; + + sm->vlib_main = vm; + sm->vnet_main = h->vnet_main; + sm->unix_time_0 = (u32) time (0); /* Store starting time */ + sm->vlib_time_0 = vlib_time_now (vm); + return error; +} + +/* Set up the API message handling tables */ +static clib_error_t * +vxlan_gpe_plugin_api_hookup (vlib_main_t * vm) +{ + vxlan_gpe_ioam_main_t *sm = &vxlan_gpe_ioam_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_vxlan_gpe_plugin_api_msg; +#undef _ + + return 0; +} + +static clib_error_t * +vxlan_gpe_init (vlib_main_t * vm) +{ + vxlan_gpe_ioam_main_t *sm = &vxlan_gpe_ioam_main; + clib_error_t *error = 0; + u8 *name; + u32 encap_node_index = vxlan_gpe_encap_ioam_v4_node.index; + u32 decap_node_index = vxlan_gpe_decap_ioam_v4_node.index; + vlib_node_t *vxlan_gpe_encap_node = NULL; + vlib_node_t *vxlan_gpe_decap_node = NULL; + uword next_node = 0; + + name = format (0, "ioam_vxlan_gpe_%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 = vxlan_gpe_plugin_api_hookup (vm); + + /* Hook the ioam-encap node to vxlan-gpe-encap */ + vxlan_gpe_encap_node = vlib_get_node_by_name (vm, (u8 *) "vxlan-gpe-encap"); + sm->encap_v4_next_node = + vlib_node_add_next (vm, vxlan_gpe_encap_node->index, encap_node_index); + + vxlan_gpe_decap_node = + vlib_get_node_by_name (vm, (u8 *) "vxlan4-gpe-input"); + next_node = + vlib_node_add_next (vm, vxlan_gpe_decap_node->index, decap_node_index); + vxlan_gpe_register_decap_protocol (VXLAN_GPE_PROTOCOL_IOAM, next_node); + + vec_new (vxlan_gpe_ioam_sw_interface_t, pool_elts (sm->sw_interfaces)); + sm->dst_by_ip4 = hash_create_mem (0, sizeof (fib_prefix_t), sizeof (uword)); + + sm->dst_by_ip6 = hash_create_mem (0, sizeof (fib_prefix_t), sizeof (uword)); + + vxlan_gpe_ioam_interface_init (); + vec_free (name); + + return error; +} + +VLIB_INIT_FUNCTION (vxlan_gpe_init); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.c b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.c new file mode 100644 index 00000000..6c04d9af --- /dev/null +++ b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.c @@ -0,0 +1,773 @@ +/* + * 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. + */ +#include +#include +#include +#include +#include +#include +#include + +vxlan_gpe_ioam_main_t vxlan_gpe_ioam_main; + +int +vxlan_gpe_ioam_set_rewrite (vxlan_gpe_tunnel_t * t, int has_trace_option, + int has_pot_option, int has_ppc_option, + u8 ipv6_set) +{ + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + u32 size; + vxlan_gpe_ioam_hdr_t *vxlan_gpe_ioam_hdr; + u8 *current; + u8 trace_data_size = 0; + u8 pot_data_size = 0; + + if (has_trace_option == 0 && has_pot_option == 0) + return -1; + + /* Work out how much space we need */ + size = sizeof (vxlan_gpe_ioam_hdr_t); + + if (has_trace_option + && hm->add_options[VXLAN_GPE_OPTION_TYPE_IOAM_TRACE] != 0) + { + size += sizeof (vxlan_gpe_ioam_option_t); + size += hm->options_size[VXLAN_GPE_OPTION_TYPE_IOAM_TRACE]; + } + if (has_pot_option + && hm->add_options[VXLAN_GPE_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT] != 0) + { + size += sizeof (vxlan_gpe_ioam_option_t); + size += hm->options_size[VXLAN_GPE_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT]; + } + + t->rewrite_size = size; + + if (!ipv6_set) + { + vxlan4_gpe_rewrite (t, size, VXLAN_GPE_PROTOCOL_IOAM, + hm->encap_v4_next_node); + vxlan_gpe_ioam_hdr = + (vxlan_gpe_ioam_hdr_t *) (t->rewrite + + sizeof (ip4_vxlan_gpe_header_t)); + } + else + { + vxlan6_gpe_rewrite (t, size, VXLAN_GPE_PROTOCOL_IOAM, + VXLAN_GPE_ENCAP_NEXT_IP6_LOOKUP); + vxlan_gpe_ioam_hdr = + (vxlan_gpe_ioam_hdr_t *) (t->rewrite + + sizeof (ip6_vxlan_gpe_header_t)); + } + + + vxlan_gpe_ioam_hdr->type = VXLAN_GPE_PROTOCOL_IOAM; + /* Length of the header in octets */ + vxlan_gpe_ioam_hdr->length = size; + vxlan_gpe_ioam_hdr->protocol = t->protocol; + current = (u8 *) vxlan_gpe_ioam_hdr + sizeof (vxlan_gpe_ioam_hdr_t); + + if (has_trace_option + && hm->add_options[VXLAN_GPE_OPTION_TYPE_IOAM_TRACE] != 0) + { + if (0 != hm->add_options[VXLAN_GPE_OPTION_TYPE_IOAM_TRACE] (current, + &trace_data_size)) + return -1; + current += trace_data_size; + } + if (has_pot_option + && hm->add_options[VXLAN_GPE_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT] != 0) + { + pot_data_size = + hm->options_size[VXLAN_GPE_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT]; + if (0 == + hm->add_options[VXLAN_GPE_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT] + (current, &pot_data_size)) + current += pot_data_size; + } + + return 0; +} + +int +vxlan_gpe_ioam_clear_rewrite (vxlan_gpe_tunnel_t * t, int has_trace_option, + int has_pot_option, int has_ppc_option, + u8 ipv6_set) +{ + + t->rewrite_size = 0; + + if (!ipv6_set) + { + vxlan4_gpe_rewrite (t, 0, 0, VXLAN_GPE_ENCAP_NEXT_IP4_LOOKUP); + } + else + { + vxlan6_gpe_rewrite (t, 0, 0, VXLAN_GPE_ENCAP_NEXT_IP6_LOOKUP); + } + + + return 0; +} + +clib_error_t * +vxlan_gpe_ioam_clear (vxlan_gpe_tunnel_t * t, + int has_trace_option, int has_pot_option, + int has_ppc_option, u8 ipv6_set) +{ + int rv; + rv = vxlan_gpe_ioam_clear_rewrite (t, 0, 0, 0, 0); + + if (rv == 0) + { + return (0); + } + else + { + return clib_error_return_code (0, rv, 0, + "vxlan_gpe_ioam_clear_rewrite returned %d", + rv); + } + +} + + +clib_error_t * +vxlan_gpe_ioam_set (vxlan_gpe_tunnel_t * t, + int has_trace_option, int has_pot_option, + int has_ppc_option, u8 ipv6_set) +{ + int rv; + rv = vxlan_gpe_ioam_set_rewrite (t, has_trace_option, + has_pot_option, has_ppc_option, ipv6_set); + + if (rv == 0) + { + return (0); + } + else + { + return clib_error_return_code (0, rv, 0, + "vxlan_gpe_ioam_set_rewrite returned %d", + rv); + } + +} + +static void +vxlan_gpe_set_clear_output_feature_on_intf (vlib_main_t * vm, + u32 sw_if_index0, u8 is_add) +{ + + + + vnet_feature_enable_disable ("ip4-output", "vxlan-gpe-transit-ioam", + sw_if_index0, is_add, + 0 /* void *feature_config */ , + 0 /* u32 n_feature_config_bytes */ ); + return; +} + +void +vxlan_gpe_clear_output_feature_on_all_intfs (vlib_main_t * vm) +{ + vnet_sw_interface_t *si = 0; + vnet_main_t *vnm = vnet_get_main (); + vnet_interface_main_t *im = &vnm->interface_main; + + pool_foreach (si, im->sw_interfaces, ( + { + vxlan_gpe_set_clear_output_feature_on_intf + (vm, si->sw_if_index, 0); + })); + return; +} + + +extern fib_forward_chain_type_t +fib_entry_get_default_chain_type (const fib_entry_t * fib_entry); + +int +vxlan_gpe_enable_disable_ioam_for_dest (vlib_main_t * vm, + ip46_address_t dst_addr, + u32 outer_fib_index, + u8 is_ipv4, u8 is_add) +{ + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + u32 fib_index0 = 0; + u32 sw_if_index0 = ~0; + + fib_node_index_t fei = ~0; + fib_entry_t *fib_entry; + u32 adj_index0; + ip_adjacency_t *adj0; + fib_prefix_t fib_prefix; + //fib_forward_chain_type_t fct; + load_balance_t *lb_m, *lb_b; + const dpo_id_t *dpo0, *dpo1; + u32 i, j; + //vnet_hw_interface_t *hw; + + if (is_ipv4) + { + memset (&fib_prefix, 0, sizeof (fib_prefix_t)); + fib_prefix.fp_len = 32; + fib_prefix.fp_proto = FIB_PROTOCOL_IP4; + fib_prefix.fp_addr = dst_addr; + } + else + { + return 0; + } + + fei = fib_table_lookup (fib_index0, &fib_prefix); + fib_entry = fib_entry_get (fei); + + //fct = fib_entry_get_default_chain_type (fib_entry); + + if (!dpo_id_is_valid (&fib_entry->fe_lb /*[fct] */ )) + { + return (-1); + } + + lb_m = load_balance_get (fib_entry->fe_lb /*[fct] */ .dpoi_index); + + for (i = 0; i < lb_m->lb_n_buckets; i++) + { + dpo0 = load_balance_get_bucket_i (lb_m, i); + + if (dpo0->dpoi_type == DPO_LOAD_BALANCE) + { + lb_b = load_balance_get (dpo0->dpoi_index); + + for (j = 0; j < lb_b->lb_n_buckets; j++) + { + dpo1 = load_balance_get_bucket_i (lb_b, j); + + if (dpo1->dpoi_type == DPO_ADJACENCY) + { + adj_index0 = dpo1->dpoi_index; + + if (ADJ_INDEX_INVALID == adj_index0) + { + continue; + } + + adj0 = + ip_get_adjacency (&(ip4_main.lookup_main), adj_index0); + sw_if_index0 = adj0->rewrite_header.sw_if_index; + + if (~0 == sw_if_index0) + { + continue; + } + + + if (is_add) + { + vnet_feature_enable_disable ("ip4-output", + "vxlan-gpe-transit-ioam", + sw_if_index0, is_add, 0 + /* void *feature_config */ + , 0 /* u32 n_feature_config_bytes */ + ); + + vec_validate_init_empty (hm->bool_ref_by_sw_if_index, + sw_if_index0, ~0); + hm->bool_ref_by_sw_if_index[sw_if_index0] = 1; + } + else + { + hm->bool_ref_by_sw_if_index[sw_if_index0] = ~0; + } + } + } + } + } + + if (is_ipv4) + { + + uword *t = NULL; + vxlan_gpe_ioam_dest_tunnels_t *t1; + fib_prefix_t key4, *key4_copy; + hash_pair_t *hp; + memset (&key4, 0, sizeof (key4)); + key4.fp_proto = FIB_PROTOCOL_IP4; + key4.fp_addr.ip4.as_u32 = fib_prefix.fp_addr.ip4.as_u32; + t = hash_get_mem (hm->dst_by_ip4, &key4); + if (is_add) + { + if (t) + { + return 0; + } + pool_get_aligned (hm->dst_tunnels, t1, CLIB_CACHE_LINE_BYTES); + memset (t1, 0, sizeof (*t1)); + t1->fp_proto = FIB_PROTOCOL_IP4; + t1->dst_addr.ip4.as_u32 = fib_prefix.fp_addr.ip4.as_u32; + key4_copy = clib_mem_alloc (sizeof (*key4_copy)); + clib_memcpy (key4_copy, &key4, sizeof (*key4_copy)); + hash_set_mem (hm->dst_by_ip4, key4_copy, t1 - hm->dst_tunnels); + /* + * Attach to the FIB entry for the VxLAN-GPE destination + * and become its child. The dest route will invoke a callback + * when the fib entry changes, it can be used to + * re-program the output feature on the egress interface. + */ + + const fib_prefix_t tun_dst_pfx = { + .fp_len = 32, + .fp_proto = FIB_PROTOCOL_IP4, + .fp_addr = {.ip4 = t1->dst_addr.ip4,} + }; + + t1->fib_entry_index = + fib_table_entry_special_add (outer_fib_index, + &tun_dst_pfx, + FIB_SOURCE_RR, + FIB_ENTRY_FLAG_NONE, + ADJ_INDEX_INVALID); + t1->sibling_index = + fib_entry_child_add (t1->fib_entry_index, + hm->fib_entry_type, t1 - hm->dst_tunnels); + t1->outer_fib_index = outer_fib_index; + + } + else + { + if (!t) + { + return 0; + } + t1 = pool_elt_at_index (hm->dst_tunnels, t[0]); + hp = hash_get_pair (hm->dst_by_ip4, &key4); + key4_copy = (void *) (hp->key); + hash_unset_mem (hm->dst_by_ip4, &key4); + clib_mem_free (key4_copy); + pool_put (hm->dst_tunnels, t1); + } + } + else + { + // TBD for IPv6 + } + + return 0; +} + +void +vxlan_gpe_refresh_output_feature_on_all_dest (void) +{ + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + vxlan_gpe_ioam_dest_tunnels_t *t; + u32 i; + if (pool_elts (hm->dst_tunnels) == 0) + return; + vxlan_gpe_clear_output_feature_on_all_intfs (hm->vlib_main); + i = vec_len (hm->bool_ref_by_sw_if_index); + vec_free (hm->bool_ref_by_sw_if_index); + vec_validate_init_empty (hm->bool_ref_by_sw_if_index, i, ~0); + pool_foreach (t, hm->dst_tunnels, ( + { + vxlan_gpe_enable_disable_ioam_for_dest + (hm->vlib_main, + t->dst_addr, + t->outer_fib_index, + (t->fp_proto == FIB_PROTOCOL_IP4), 1 + /* is_add */ + ); + } + )); + return; +} + +void +vxlan_gpe_clear_output_feature_on_select_intfs (void) +{ + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + u32 sw_if_index0 = 0; + for (sw_if_index0 = 0; + sw_if_index0 < vec_len (hm->bool_ref_by_sw_if_index); sw_if_index0++) + { + if (hm->bool_ref_by_sw_if_index[sw_if_index0] == 0xFF) + { + vxlan_gpe_set_clear_output_feature_on_intf + (hm->vlib_main, sw_if_index0, 0); + } + } + + return; +} + +static clib_error_t * +vxlan_gpe_set_ioam_rewrite_command_fn (vlib_main_t * + vm, + unformat_input_t + * input, vlib_cli_command_t * cmd) +{ + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + ip46_address_t local, remote; + u8 local_set = 0; + u8 remote_set = 0; + u8 ipv4_set = 0; + u8 ipv6_set = 0; + u32 vni; + u8 vni_set = 0; + u8 disable = 0; + clib_error_t *rv = 0; + vxlan4_gpe_tunnel_key_t key4; + vxlan6_gpe_tunnel_key_t key6; + uword *p; + vxlan_gpe_main_t *gm = &vxlan_gpe_main; + vxlan_gpe_tunnel_t *t = 0; + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "local %U", unformat_ip4_address, &local.ip4)) + { + local_set = 1; + ipv4_set = 1; + } + else + if (unformat (input, "remote %U", unformat_ip4_address, &remote.ip4)) + { + remote_set = 1; + ipv4_set = 1; + } + else if (unformat (input, "local %U", unformat_ip6_address, &local.ip6)) + { + local_set = 1; + ipv6_set = 1; + } + else + if (unformat (input, "remote %U", unformat_ip6_address, &remote.ip6)) + { + remote_set = 1; + ipv6_set = 1; + } + else if (unformat (input, "vni %d", &vni)) + vni_set = 1; + else if (unformat (input, "disable")) + disable = 1; + else + break; + } + + if (local_set == 0) + return clib_error_return (0, "tunnel local address not specified"); + if (remote_set == 0) + return clib_error_return (0, "tunnel remote address not specified"); + if (ipv4_set && ipv6_set) + return clib_error_return (0, "both IPv4 and IPv6 addresses specified"); + if ((ipv4_set + && memcmp (&local.ip4, &remote.ip4, + sizeof (local.ip4)) == 0) || (ipv6_set + && + memcmp + (&local.ip6, + &remote.ip6, + sizeof (local.ip6)) == 0)) + return clib_error_return (0, "src and dst addresses are identical"); + if (vni_set == 0) + return clib_error_return (0, "vni not specified"); + if (!ipv6_set) + { + key4.local = local.ip4.as_u32; + key4.remote = remote.ip4.as_u32; + key4.vni = clib_host_to_net_u32 (vni << 8); + key4.pad = 0; + p = hash_get_mem (gm->vxlan4_gpe_tunnel_by_key, &key4); + } + else + { + key6.local.as_u64[0] = local.ip6.as_u64[0]; + key6.local.as_u64[1] = local.ip6.as_u64[1]; + key6.remote.as_u64[0] = remote.ip6.as_u64[0]; + key6.remote.as_u64[1] = remote.ip6.as_u64[1]; + key6.vni = clib_host_to_net_u32 (vni << 8); + p = hash_get_mem (gm->vxlan6_gpe_tunnel_by_key, &key6); + } + + if (!p) + return clib_error_return (0, "VxLAN Tunnel not found"); + t = pool_elt_at_index (gm->tunnels, p[0]); + if (!disable) + { + rv = + vxlan_gpe_ioam_set (t, hm->has_trace_option, + hm->has_pot_option, hm->has_ppc_option, ipv6_set); + } + else + { + rv = vxlan_gpe_ioam_clear (t, 0, 0, 0, 0); + } + return rv; +} + + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (vxlan_gpe_set_ioam_rewrite_cmd, static) = { + .path = "set vxlan-gpe-ioam", + .short_help = "set vxlan-gpe-ioam vxlan [disable]", + .function = vxlan_gpe_set_ioam_rewrite_command_fn, +}; +/* *INDENT-ON* */ + + + +clib_error_t * +vxlan_gpe_ioam_enable (int has_trace_option, + int has_pot_option, int has_ppc_option) +{ + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + hm->has_trace_option = has_trace_option; + hm->has_pot_option = has_pot_option; + hm->has_ppc_option = has_ppc_option; + if (hm->has_trace_option) + { + vxlan_gpe_trace_profile_setup (); + } + + return 0; +} + +clib_error_t * +vxlan_gpe_ioam_disable (int + has_trace_option, + int has_pot_option, int has_ppc_option) +{ + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + hm->has_trace_option = has_trace_option; + hm->has_pot_option = has_pot_option; + hm->has_ppc_option = has_ppc_option; + if (!hm->has_trace_option) + { + vxlan_gpe_trace_profile_cleanup (); + } + + return 0; +} + +void +vxlan_gpe_set_next_override (uword next) +{ + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + hm->decap_v4_next_override = next; + return; +} + +static clib_error_t * +vxlan_gpe_set_ioam_flags_command_fn (vlib_main_t * vm, + unformat_input_t + * input, vlib_cli_command_t * cmd) +{ + int has_trace_option = 0; + int has_pot_option = 0; + int has_ppc_option = 0; + clib_error_t *rv = 0; + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "trace")) + has_trace_option = 1; + else if (unformat (input, "pot")) + has_pot_option = 1; + else if (unformat (input, "ppc encap")) + has_ppc_option = PPC_ENCAP; + else if (unformat (input, "ppc decap")) + has_ppc_option = PPC_DECAP; + else if (unformat (input, "ppc none")) + has_ppc_option = PPC_NONE; + else + break; + } + + + rv = + vxlan_gpe_ioam_enable (has_trace_option, has_pot_option, has_ppc_option); + return rv; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (vxlan_gpe_set_ioam_flags_cmd, static) = +{ +.path = "set vxlan-gpe-ioam rewrite", +.short_help = "set vxlan-gpe-ioam [trace] [pot] [ppc ]", +.function = vxlan_gpe_set_ioam_flags_command_fn,}; +/* *INDENT-ON* */ + + +int vxlan_gpe_ioam_disable_for_dest + (vlib_main_t * vm, ip46_address_t dst_addr, u32 outer_fib_index, + u8 ipv4_set) +{ + vxlan_gpe_ioam_dest_tunnels_t *t; + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + + vxlan_gpe_enable_disable_ioam_for_dest (hm->vlib_main, + dst_addr, outer_fib_index, ipv4_set, + 0); + if (pool_elts (hm->dst_tunnels) == 0) + { + vxlan_gpe_clear_output_feature_on_select_intfs (); + return 0; + } + + pool_foreach (t, hm->dst_tunnels, ( + { + vxlan_gpe_enable_disable_ioam_for_dest + (hm->vlib_main, + t->dst_addr, + t->outer_fib_index, + (t->fp_proto == + FIB_PROTOCOL_IP4), 1 /* is_add */ ); + } + )); + vxlan_gpe_clear_output_feature_on_select_intfs (); + return (0); + +} + +static clib_error_t *vxlan_gpe_set_ioam_transit_rewrite_command_fn + (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + ip46_address_t dst_addr; + u8 dst_addr_set = 0; + u8 ipv4_set = 0; + u8 ipv6_set = 0; + u8 disable = 0; + clib_error_t *rv = 0; + u32 outer_fib_index = 0; + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "dst-ip %U", unformat_ip4_address, &dst_addr.ip4)) + { + dst_addr_set = 1; + ipv4_set = 1; + } + else + if (unformat + (input, "dst-ip %U", unformat_ip6_address, &dst_addr.ip6)) + { + dst_addr_set = 1; + ipv6_set = 1; + } + else if (unformat (input, "outer-fib-index %d", &outer_fib_index)) + { + } + + else if (unformat (input, "disable")) + disable = 1; + else + break; + } + + if (dst_addr_set == 0) + return clib_error_return (0, "tunnel destination address not specified"); + if (ipv4_set && ipv6_set) + return clib_error_return (0, "both IPv4 and IPv6 addresses specified"); + if (!disable) + { + vxlan_gpe_enable_disable_ioam_for_dest (hm->vlib_main, + dst_addr, outer_fib_index, + ipv4_set, 1); + } + else + { + vxlan_gpe_ioam_disable_for_dest + (vm, dst_addr, outer_fib_index, ipv4_set); + } + return rv; +} + + /* *INDENT-OFF* */ +VLIB_CLI_COMMAND (vxlan_gpe_set_ioam_transit_rewrite_cmd, static) = { + .path = "set vxlan-gpe-ioam-transit", + .short_help = "set vxlan-gpe-ioam-transit dst-ip [outer-fib-index ] [disable]", + .function = vxlan_gpe_set_ioam_transit_rewrite_command_fn, +}; +/* *INDENT-ON* */ + +clib_error_t *clear_vxlan_gpe_ioam_rewrite_command_fn + (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) +{ + return (vxlan_gpe_ioam_disable (0, 0, 0)); +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (vxlan_gpe_clear_ioam_flags_cmd, static) = +{ +.path = "clear vxlan-gpe-ioam rewrite", +.short_help = "clear vxlan-gpe-ioam rewrite", +.function = clear_vxlan_gpe_ioam_rewrite_command_fn, +}; +/* *INDENT-ON* */ + + +/** + * Function definition to backwalk a FIB node + */ +static fib_node_back_walk_rc_t +vxlan_gpe_ioam_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx) +{ + vxlan_gpe_refresh_output_feature_on_all_dest (); + return (FIB_NODE_BACK_WALK_CONTINUE); +} + +/** + * Function definition to get a FIB node from its index + */ +static fib_node_t * +vxlan_gpe_ioam_fib_node_get (fib_node_index_t index) +{ + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + return (&hm->node); +} + +/** + * Function definition to inform the FIB node that its last lock has gone. + */ +static void +vxlan_gpe_ioam_last_lock_gone (fib_node_t * node) +{ + ASSERT (0); +} + + +/* + * Virtual function table registered by MPLS GRE tunnels + * for participation in the FIB object graph. + */ +const static fib_node_vft_t vxlan_gpe_ioam_vft = { + .fnv_get = vxlan_gpe_ioam_fib_node_get, + .fnv_last_lock = vxlan_gpe_ioam_last_lock_gone, + .fnv_back_walk = vxlan_gpe_ioam_back_walk, +}; + +void +vxlan_gpe_ioam_interface_init (void) +{ + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + hm->fib_entry_type = fib_node_register_new_type (&vxlan_gpe_ioam_vft); + return; +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.h b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.h new file mode 100644 index 00000000..0711b87a --- /dev/null +++ b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.h @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __included_vxlan_gpe_ioam_h__ +#define __included_vxlan_gpe_ioam_h__ + +#include +#include +#include +#include + + +typedef struct vxlan_gpe_sw_interface_ +{ + u32 sw_if_index; +} vxlan_gpe_ioam_sw_interface_t; + +typedef struct vxlan_gpe_dest_tunnels_ +{ + ip46_address_t dst_addr; + u32 fp_proto; + u32 sibling_index; + fib_node_index_t fib_entry_index; + u32 outer_fib_index; +} vxlan_gpe_ioam_dest_tunnels_t; + +typedef struct vxlan_gpe_ioam_main_ +{ + /** + * Linkage into the FIB object graph + */ + fib_node_t node; + + /* time scale transform. Joy. */ + u32 unix_time_0; + f64 vlib_time_0; + + + /* Trace option */ + u8 has_trace_option; + + /* Pot option */ + u8 has_pot_option; + +#define PPC_NONE 0 +#define PPC_ENCAP 1 +#define PPC_DECAP 2 + u8 has_ppc_option; + +#define TSP_SECONDS 0 +#define TSP_MILLISECONDS 1 +#define TSP_MICROSECONDS 2 +#define TSP_NANOSECONDS 3 + + /* Array of function pointers to ADD and POP VxLAN-GPE iOAM option handling routines */ + u8 options_size[256]; + int (*add_options[256]) (u8 * rewrite_string, u8 * rewrite_size); + int (*pop_options[256]) (ip4_header_t * ip, vxlan_gpe_ioam_option_t * opt); + + /* Array of function pointers to iOAM option handling routines */ + int (*options[256]) (vlib_buffer_t * b, vxlan_gpe_ioam_option_t * opt, + u8 is_ipv4, u8 use_adj); + u8 *(*trace[256]) (u8 * s, vxlan_gpe_ioam_option_t * opt); + + /* API message ID base */ + u16 msg_id_base; + + /* Override to export for iOAM */ + uword decap_v4_next_override; + uword decap_v6_next_override; + + /* sequence of node graph for encap */ + uword encap_v4_next_node; + uword encap_v6_next_node; + + /* Software interfaces. */ + vxlan_gpe_ioam_sw_interface_t *sw_interfaces; + + /* hash ip4/ip6 -> list of destinations for doing transit iOAM operation */ + vxlan_gpe_ioam_dest_tunnels_t *dst_tunnels; + uword *dst_by_ip4; + uword *dst_by_ip6; + + /** per sw_if_index, to maintain bitmap */ + u8 *bool_ref_by_sw_if_index; + fib_node_type_t fib_entry_type; + + /** State convenience vlib_main_t */ + vlib_main_t *vlib_main; + /** State convenience vnet_main_t */ + vnet_main_t *vnet_main; + + +} vxlan_gpe_ioam_main_t; +extern vxlan_gpe_ioam_main_t vxlan_gpe_ioam_main; + +/* + * Primary h-b-h handler trace support + */ +typedef struct +{ + u32 next_index; + u32 trace_len; + u8 option_data[256]; +} ioam_trace_t; + + +extern vlib_node_registration_t vxlan_gpe_encap_ioam_v4_node; +extern vlib_node_registration_t vxlan_gpe_decap_ioam_v4_node; +extern vlib_node_registration_t vxlan_gpe_transit_ioam_v4_node; + +clib_error_t *vxlan_gpe_ioam_enable (int has_trace_option, int has_pot_option, + int has_ppc_option); + +clib_error_t *vxlan_gpe_ioam_disable (int has_trace_option, + int has_pot_option, int has_ppc_option); + +clib_error_t *vxlan_gpe_ioam_set (vxlan_gpe_tunnel_t * t, + int has_trace_option, + int has_pot_option, + int has_ppc_option, u8 ipv6_set); +clib_error_t *vxlan_gpe_ioam_clear (vxlan_gpe_tunnel_t * t, + int has_trace_option, int has_pot_option, + int has_ppc_option, u8 ipv6_set); + +int vxlan_gpe_ioam_add_register_option (u8 option, + u8 size, + int rewrite_options (u8 * + rewrite_string, + u8 * + rewrite_size)); + +int vxlan_gpe_add_unregister_option (u8 option); + +int vxlan_gpe_ioam_register_option (u8 option, + int options (vlib_buffer_t * b, + vxlan_gpe_ioam_option_t * + opt, u8 is_ipv4, u8 use_adj), + u8 * trace (u8 * s, + vxlan_gpe_ioam_option_t * + opt)); +int vxlan_gpe_ioam_unregister_option (u8 option); + +int vxlan_gpe_trace_profile_setup (void); + +int vxlan_gpe_trace_profile_cleanup (void); +extern void vxlan_gpe_ioam_interface_init (void); +int +vxlan_gpe_enable_disable_ioam_for_dest (vlib_main_t * vm, + ip46_address_t dst_addr, + u32 outer_fib_index, + u8 is_ipv4, u8 is_add); +int vxlan_gpe_ioam_disable_for_dest + (vlib_main_t * vm, ip46_address_t dst_addr, u32 outer_fib_index, + u8 ipv4_set); + +typedef enum +{ + VXLAN_GPE_DECAP_IOAM_V4_NEXT_POP, + VXLAN_GPE_DECAP_IOAM_V4_NEXT_DROP, + VXLAN_GPE_DECAP_IOAM_V4_N_NEXT +} vxlan_gpe_decap_ioam_v4_next_t; + +#endif + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_packet.h b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_packet.h new file mode 100644 index 00000000..a7ef859e --- /dev/null +++ b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_packet.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __included_vxlan_gpe_ioam_packet_h__ +#define __included_vxlan_gpe_ioam_packet_h__ + +#include +#include +#include + + + +#define VXLAN_GPE_OPTION_TYPE_IOAM_TRACE 59 +#define VXLAN_GPE_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT 60 + +/** + * @brief VXLAN GPE Extension (iOAM) Header definition + */ +typedef struct +{ + u8 type; + u8 length; + /** Reserved */ + u8 reserved; + /** see vxlan_gpe_protocol_t */ + u8 protocol; +} vxlan_gpe_ioam_hdr_t; + +/* + * @brief VxLAN GPE iOAM Option definition + */ +typedef struct +{ + /* Option Type */ + u8 type; + /* Length in octets of the option data field */ + u8 length; +} vxlan_gpe_ioam_option_t; + + +#endif + + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_trace.c b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_trace.c new file mode 100644 index 00000000..e37b1642 --- /dev/null +++ b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_trace.c @@ -0,0 +1,552 @@ +/* + * 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. + */ +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +/* Timestamp precision multipliers for seconds, milliseconds, microseconds + * and nanoseconds respectively. + */ +static f64 trace_tsp_mul[4] = { 1, 1e3, 1e6, 1e9 }; + +typedef union +{ + u64 as_u64; + u32 as_u32[2]; +} time_u64_t; + + +/* *INDENT-OFF* */ +typedef CLIB_PACKED(struct { + vxlan_gpe_ioam_option_t hdr; + u8 ioam_trace_type; + u8 data_list_elts_left; + u32 elts[0]; /* Variable type. So keep it generic */ +}) vxlan_gpe_ioam_trace_option_t; +/* *INDENT-ON* */ + + +#define foreach_vxlan_gpe_ioam_trace_stats \ + _(SUCCESS, "Pkts updated with TRACE records") \ + _(FAILED, "Errors in TRACE due to lack of TRACE records") + +static char *vxlan_gpe_ioam_trace_stats_strings[] = { +#define _(sym,string) string, + foreach_vxlan_gpe_ioam_trace_stats +#undef _ +}; + +typedef enum +{ +#define _(sym,str) VXLAN_GPE_IOAM_TRACE_##sym, + foreach_vxlan_gpe_ioam_trace_stats +#undef _ + VXLAN_GPE_IOAM_TRACE_N_STATS, +} vxlan_gpe_ioam_trace_stats_t; + + +typedef struct +{ + /* stats */ + u64 counters[ARRAY_LEN (vxlan_gpe_ioam_trace_stats_strings)]; + + /* convenience */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} vxlan_gpe_ioam_trace_main_t; + +vxlan_gpe_ioam_trace_main_t vxlan_gpe_ioam_trace_main; + +int +vxlan_gpe_ioam_add_register_option (u8 option, + u8 size, + int rewrite_options (u8 * rewrite_string, + u8 * rewrite_size)) +{ + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + + ASSERT (option < ARRAY_LEN (hm->add_options)); + + /* Already registered */ + if (hm->add_options[option]) + return (-1); + + hm->add_options[option] = rewrite_options; + hm->options_size[option] = size; + + return (0); +} + +int +vxlan_gpe_add_unregister_option (u8 option) +{ + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + + ASSERT (option < ARRAY_LEN (hm->add_options)); + + /* Not registered */ + if (!hm->add_options[option]) + return (-1); + + hm->add_options[option] = NULL; + hm->options_size[option] = 0; + return (0); +} + + +int +vxlan_gpe_ioam_register_option (u8 option, + int options (vlib_buffer_t * b, + vxlan_gpe_ioam_option_t * opt, + u8 is_ipv4, u8 use_adj), + u8 * trace (u8 * s, + vxlan_gpe_ioam_option_t * opt)) +{ + vxlan_gpe_ioam_main_t *im = &vxlan_gpe_ioam_main; + + ASSERT (option < ARRAY_LEN (im->options)); + + /* Already registered */ + if (im->options[option]) + return (-1); + + im->options[option] = options; + im->trace[option] = trace; + + return (0); +} + +int +vxlan_gpe_ioam_unregister_option (u8 option) +{ + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + + ASSERT (option < ARRAY_LEN (hm->options)); + + /* Not registered */ + if (!hm->options[option]) + return (-1); + + hm->options[option] = NULL; + hm->trace[option] = NULL; + + return (0); +} + + +always_inline void +vxlan_gpe_ioam_trace_stats_increment_counter (u32 counter_index, + u64 increment) +{ + vxlan_gpe_ioam_trace_main_t *hm = &vxlan_gpe_ioam_trace_main; + + hm->counters[counter_index] += increment; +} + + +static u8 * +format_ioam_data_list_element (u8 * s, va_list * args) +{ + u32 *elt = va_arg (*args, u32 *); + u8 *trace_type_p = va_arg (*args, u8 *); + u8 trace_type = *trace_type_p; + + + if (trace_type & BIT_TTL_NODEID) + { + u32 ttl_node_id_host_byte_order = clib_net_to_host_u32 (*elt); + s = format (s, "ttl 0x%x node id 0x%x ", + ttl_node_id_host_byte_order >> 24, + ttl_node_id_host_byte_order & 0x00FFFFFF); + + elt++; + } + + if (trace_type & BIT_ING_INTERFACE && trace_type & BIT_ING_INTERFACE) + { + u32 ingress_host_byte_order = clib_net_to_host_u32 (*elt); + s = format (s, "ingress 0x%x egress 0x%x ", + ingress_host_byte_order >> 16, + ingress_host_byte_order & 0xFFFF); + elt++; + } + + if (trace_type & BIT_TIMESTAMP) + { + u32 ts_in_host_byte_order = clib_net_to_host_u32 (*elt); + s = format (s, "ts 0x%x \n", ts_in_host_byte_order); + elt++; + } + + if (trace_type & BIT_APPDATA) + { + u32 appdata_in_host_byte_order = clib_net_to_host_u32 (*elt); + s = format (s, "app 0x%x ", appdata_in_host_byte_order); + elt++; + } + + return s; +} + + + +int +vxlan_gpe_ioam_trace_rewrite_handler (u8 * rewrite_string, u8 * rewrite_size) +{ + vxlan_gpe_ioam_trace_option_t *trace_option = NULL; + u8 trace_data_size = 0; + u8 trace_option_elts = 0; + trace_profile *profile = NULL; + + + profile = trace_profile_find (); + + if (PREDICT_FALSE (!profile)) + { + return (-1); + } + + if (PREDICT_FALSE (!rewrite_string)) + return -1; + + trace_option_elts = profile->num_elts; + trace_data_size = fetch_trace_data_size (profile->trace_type); + trace_option = (vxlan_gpe_ioam_trace_option_t *) rewrite_string; + trace_option->hdr.type = VXLAN_GPE_OPTION_TYPE_IOAM_TRACE; + trace_option->hdr.length = 2 /*ioam_trace_type,data_list_elts_left */ + + trace_option_elts * trace_data_size; + trace_option->ioam_trace_type = profile->trace_type & TRACE_TYPE_MASK; + trace_option->data_list_elts_left = trace_option_elts; + *rewrite_size = + sizeof (vxlan_gpe_ioam_trace_option_t) + + (trace_option_elts * trace_data_size); + + return 0; +} + + +int +vxlan_gpe_ioam_trace_data_list_handler (vlib_buffer_t * b, + vxlan_gpe_ioam_option_t * opt, + u8 is_ipv4, u8 use_adj) +{ + u8 elt_index = 0; + vxlan_gpe_ioam_trace_option_t *trace = + (vxlan_gpe_ioam_trace_option_t *) opt; + time_u64_t time_u64; + u32 *elt; + int rv = 0; + trace_profile *profile = NULL; + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + + + profile = trace_profile_find (); + + if (PREDICT_FALSE (!profile)) + { + return (-1); + } + + + time_u64.as_u64 = 0; + + if (PREDICT_TRUE (trace->data_list_elts_left)) + { + trace->data_list_elts_left--; + /* fetch_trace_data_size returns in bytes. Convert it to 4-bytes + * to skip to this node's location. + */ + elt_index = + trace->data_list_elts_left * + fetch_trace_data_size (trace->ioam_trace_type) / 4; + elt = &trace->elts[elt_index]; + if (is_ipv4) + { + if (trace->ioam_trace_type & BIT_TTL_NODEID) + { + ip4_header_t *ip0 = vlib_buffer_get_current (b); + /* The transit case is the only case where the TTL decrement happens + * before iOAM processing. For now, use the use_adj flag as an overload. + * We can probably use a separate flag instead of overloading the use_adj flag. + */ + *elt = clib_host_to_net_u32 (((ip0->ttl - 1 + use_adj) << 24) | + profile->node_id); + elt++; + } + + if (trace->ioam_trace_type & BIT_ING_INTERFACE) + { + u16 tx_if = 0; + u32 adj_index = vnet_buffer (b)->ip.adj_index[VLIB_TX]; + ip4_main_t *im4 = &ip4_main; + ip_lookup_main_t *lm = &im4->lookup_main; + if (use_adj) + { + ip_adjacency_t *adj = ip_get_adjacency (lm, adj_index); + tx_if = adj->rewrite_header.sw_if_index & 0xFFFF; + } + + *elt = + (vnet_buffer (b)->sw_if_index[VLIB_RX] & 0xFFFF) << 16 | + tx_if; + *elt = clib_host_to_net_u32 (*elt); + elt++; + } + } + else + { + if (trace->ioam_trace_type & BIT_TTL_NODEID) + { + ip6_header_t *ip0 = vlib_buffer_get_current (b); + *elt = clib_host_to_net_u32 ((ip0->hop_limit << 24) | + profile->node_id); + elt++; + } + if (trace->ioam_trace_type & BIT_ING_INTERFACE) + { + u16 tx_if = 0; + u32 adj_index = vnet_buffer (b)->ip.adj_index[VLIB_TX]; + ip6_main_t *im6 = &ip6_main; + ip_lookup_main_t *lm = &im6->lookup_main; + if (use_adj) + { + ip_adjacency_t *adj = ip_get_adjacency (lm, adj_index); + tx_if = adj->rewrite_header.sw_if_index & 0xFFFF; + } + + *elt = + (vnet_buffer (b)->sw_if_index[VLIB_RX] & 0xFFFF) << 16 | + tx_if; + *elt = clib_host_to_net_u32 (*elt); + elt++; + } + } + + if (trace->ioam_trace_type & BIT_TIMESTAMP) + { + /* Send least significant 32 bits */ + f64 time_f64 = + (f64) (((f64) hm->unix_time_0) + + (vlib_time_now (hm->vlib_main) - hm->vlib_time_0)); + + time_u64.as_u64 = time_f64 * trace_tsp_mul[profile->trace_tsp]; + *elt = clib_host_to_net_u32 (time_u64.as_u32[0]); + elt++; + } + + if (trace->ioam_trace_type & BIT_APPDATA) + { + /* $$$ set elt0->app_data */ + *elt = clib_host_to_net_u32 (profile->app_data); + elt++; + } + vxlan_gpe_ioam_trace_stats_increment_counter + (VXLAN_GPE_IOAM_TRACE_SUCCESS, 1); + } + else + { + vxlan_gpe_ioam_trace_stats_increment_counter + (VXLAN_GPE_IOAM_TRACE_FAILED, 1); + } + return (rv); +} + +u8 * +vxlan_gpe_ioam_trace_data_list_trace_handler (u8 * s, + vxlan_gpe_ioam_option_t * opt) +{ + vxlan_gpe_ioam_trace_option_t *trace; + u8 trace_data_size_in_words = 0; + u32 *elt; + int elt_index = 0; + + trace = (vxlan_gpe_ioam_trace_option_t *) opt; + s = + format (s, " Trace Type 0x%x , %d elts left\n", trace->ioam_trace_type, + trace->data_list_elts_left); + trace_data_size_in_words = + fetch_trace_data_size (trace->ioam_trace_type) / 4; + elt = &trace->elts[0]; + while ((u8 *) elt < ((u8 *) (&trace->elts[0]) + trace->hdr.length - 2 + /* -2 accounts for ioam_trace_type,elts_left */ )) + { + s = format (s, " [%d] %U\n", elt_index, + format_ioam_data_list_element, + elt, &trace->ioam_trace_type); + elt_index++; + elt += trace_data_size_in_words; + } + return (s); +} + + +static clib_error_t * +vxlan_gpe_show_ioam_trace_cmd_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + vxlan_gpe_ioam_trace_main_t *hm = &vxlan_gpe_ioam_trace_main; + u8 *s = 0; + int i = 0; + + for (i = 0; i < VXLAN_GPE_IOAM_TRACE_N_STATS; i++) + { + s = format (s, " %s - %lu\n", vxlan_gpe_ioam_trace_stats_strings[i], + hm->counters[i]); + } + + vlib_cli_output (vm, "%v", s); + vec_free (s); + return 0; +} + + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (vxlan_gpe_show_ioam_trace_cmd, static) = { + .path = "show ioam vxlan-gpe trace", + .short_help = "iOAM trace statistics", + .function = vxlan_gpe_show_ioam_trace_cmd_fn, +}; +/* *INDENT-ON* */ + + +static clib_error_t * +vxlan_gpe_ioam_trace_init (vlib_main_t * vm) +{ + vxlan_gpe_ioam_trace_main_t *hm = &vxlan_gpe_ioam_trace_main; + clib_error_t *error; + + if ((error = vlib_call_init_function (vm, ip_main_init))) + return (error); + + if ((error = vlib_call_init_function (vm, ip6_lookup_init))) + return error; + + if ((error = vlib_call_init_function (vm, vxlan_gpe_init))) + return (error); + + hm->vlib_main = vm; + hm->vnet_main = vnet_get_main (); + memset (hm->counters, 0, sizeof (hm->counters)); + + if (vxlan_gpe_ioam_register_option + (VXLAN_GPE_OPTION_TYPE_IOAM_TRACE, + vxlan_gpe_ioam_trace_data_list_handler, + vxlan_gpe_ioam_trace_data_list_trace_handler) < 0) + return (clib_error_create + ("registration of VXLAN_GPE_OPTION_TYPE_IOAM_TRACE failed")); + + + if (vxlan_gpe_ioam_add_register_option + (VXLAN_GPE_OPTION_TYPE_IOAM_TRACE, + sizeof (vxlan_gpe_ioam_trace_option_t), + vxlan_gpe_ioam_trace_rewrite_handler) < 0) + return (clib_error_create + ("registration of VXLAN_GPE_OPTION_TYPE_IOAM_TRACE for rewrite failed")); + + + return (0); +} + +VLIB_INIT_FUNCTION (vxlan_gpe_ioam_trace_init); + +int +vxlan_gpe_trace_profile_cleanup (void) +{ + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + + hm->options_size[VXLAN_GPE_OPTION_TYPE_IOAM_TRACE] = 0; + + return 0; + +} + +static int +vxlan_gpe_ioam_trace_get_sizeof_handler (u32 * result) +{ + u16 size = 0; + u8 trace_data_size = 0; + trace_profile *profile = NULL; + + *result = 0; + + profile = trace_profile_find (); + + if (PREDICT_FALSE (!profile)) + { + return (-1); + } + + trace_data_size = fetch_trace_data_size (profile->trace_type); + if (PREDICT_FALSE (trace_data_size == 0)) + return VNET_API_ERROR_INVALID_VALUE; + + if (PREDICT_FALSE (profile->num_elts * trace_data_size > 254)) + return VNET_API_ERROR_INVALID_VALUE; + + size += + sizeof (vxlan_gpe_ioam_trace_option_t) + + profile->num_elts * trace_data_size; + *result = size; + + return 0; +} + + +int +vxlan_gpe_trace_profile_setup (void) +{ + u32 trace_size = 0; + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + + trace_profile *profile = NULL; + + + profile = trace_profile_find (); + + if (PREDICT_FALSE (!profile)) + { + return (-1); + } + + + if (vxlan_gpe_ioam_trace_get_sizeof_handler (&trace_size) < 0) + return (-1); + + hm->options_size[VXLAN_GPE_OPTION_TYPE_IOAM_TRACE] = trace_size; + + return (0); +} + + + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_util.h b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_util.h new file mode 100644 index 00000000..c0ad8d9d --- /dev/null +++ b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam_util.h @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __included_vxlan_gpe_ioam_util_h__ +#define __included_vxlan_gpe_ioam_util_h__ + +#include +#include +#include + + +typedef struct +{ + u32 tunnel_index; + ioam_trace_t fmt_trace; +} vxlan_gpe_ioam_v4_trace_t; + + +static u8 * +format_vxlan_gpe_ioam_v4_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 *); + vxlan_gpe_ioam_v4_trace_t *t1 = va_arg (*args, vxlan_gpe_ioam_v4_trace_t *); + ioam_trace_t *t = &(t1->fmt_trace); + vxlan_gpe_ioam_option_t *fmt_trace0; + vxlan_gpe_ioam_option_t *opt0, *limit0; + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + + u8 type0; + + fmt_trace0 = (vxlan_gpe_ioam_option_t *) t->option_data; + + s = format (s, "VXLAN-GPE-IOAM: next_index %d len %d traced %d", + t->next_index, fmt_trace0->length, t->trace_len); + + opt0 = (vxlan_gpe_ioam_option_t *) (fmt_trace0 + 1); + limit0 = (vxlan_gpe_ioam_option_t *) ((u8 *) fmt_trace0) + t->trace_len; + + while (opt0 < limit0) + { + type0 = opt0->type; + switch (type0) + { + case 0: /* Pad, just stop */ + opt0 = (vxlan_gpe_ioam_option_t *) ((u8 *) opt0) + 1; + break; + + default: + if (hm->trace[type0]) + { + s = (*hm->trace[type0]) (s, opt0); + } + else + { + s = + format (s, "\n unrecognized option %d length %d", type0, + opt0->length); + } + opt0 = + (vxlan_gpe_ioam_option_t *) (((u8 *) opt0) + opt0->length + + sizeof (vxlan_gpe_ioam_option_t)); + break; + } + } + + s = format (s, "VXLAN-GPE-IOAM: tunnel %d", t1->tunnel_index); + return s; +} + + +always_inline void +vxlan_gpe_encap_decap_ioam_v4_one_inline (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_buffer_t * b0, + u32 * next0, u32 drop_node_val, + u8 use_adj) +{ + ip4_header_t *ip0; + udp_header_t *udp_hdr0; + vxlan_gpe_header_t *gpe_hdr0; + vxlan_gpe_ioam_hdr_t *gpe_ioam0; + vxlan_gpe_ioam_option_t *opt0; + vxlan_gpe_ioam_option_t *limit0; + vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main; + + /* Populate the iOAM header */ + ip0 = vlib_buffer_get_current (b0); + udp_hdr0 = (udp_header_t *) (ip0 + 1); + gpe_hdr0 = (vxlan_gpe_header_t *) (udp_hdr0 + 1); + gpe_ioam0 = (vxlan_gpe_ioam_hdr_t *) (gpe_hdr0 + 1); + opt0 = (vxlan_gpe_ioam_option_t *) (gpe_ioam0 + 1); + limit0 = (vxlan_gpe_ioam_option_t *) ((u8 *) gpe_ioam0 + gpe_ioam0->length); + + /* + * Basic validity checks + */ + if (gpe_ioam0->length > clib_net_to_host_u16 (ip0->length)) + { + *next0 = drop_node_val; + return; + } + + /* Scan the set of h-b-h options, process ones that we understand */ + while (opt0 < limit0) + { + u8 type0; + type0 = opt0->type; + switch (type0) + { + case 0: /* Pad1 */ + opt0 = (vxlan_gpe_ioam_option_t *) ((u8 *) opt0) + 1; + continue; + case 1: /* PadN */ + break; + default: + if (hm->options[type0]) + { + if ((*hm->options[type0]) (b0, opt0, 1 /* is_ipv4 */ , + use_adj) < 0) + { + *next0 = drop_node_val; + return; + } + } + break; + } + opt0 = + (vxlan_gpe_ioam_option_t *) (((u8 *) opt0) + opt0->length + + sizeof (vxlan_gpe_ioam_hdr_t)); + } + + + if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) + { + vxlan_gpe_ioam_v4_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + u32 trace_len = gpe_ioam0->length; + t->fmt_trace.next_index = *next0; + /* Capture the ioam option verbatim */ + trace_len = + trace_len < + ARRAY_LEN (t->fmt_trace. + option_data) ? trace_len : ARRAY_LEN (t->fmt_trace. + option_data); + t->fmt_trace.trace_len = trace_len; + clib_memcpy (&(t->fmt_trace.option_data), gpe_ioam0, trace_len); + } + return; +} + + +#endif + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_msg_enum.h b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_msg_enum.h new file mode 100644 index 00000000..cc0a10a3 --- /dev/null +++ b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_msg_enum.h @@ -0,0 +1,28 @@ +/* + * 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. + */ +#ifndef included_vxlan_gpe_msg_enum_h +#define included_vxlan_gpe_msg_enum_h + +#include + +#define vl_msg_id(n,h) n, +typedef enum { +#include + /* 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_vxlan_gpe_msg_enum_h */ diff --git a/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_test.c b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_test.c new file mode 100644 index 00000000..47253eb6 --- /dev/null +++ b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_test.c @@ -0,0 +1,600 @@ +/* + * 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. + */ +/* + *------------------------------------------------------------------ + * vxlan_gpe_test.c - test harness for vxlan_gpe plugin + *------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include + +/* Declare message IDs */ +#include + +/* define message structures */ +#define vl_typedefs +#include +#undef vl_typedefs + +/* declare message handlers for each api */ + +#define vl_endianfun /* define message structures */ +#include +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) +#define vl_printfun +#include +#undef vl_printfun + +/* Get the API version number. */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#undef vl_api_version +#include +#include + +typedef struct +{ + /* API message ID base */ + u16 msg_id_base; + vat_main_t *vat_main; +} vxlan_gpe_test_main_t; + +vxlan_gpe_test_main_t vxlan_gpe_test_main; + +#define foreach_standard_reply_retval_handler \ +_(vxlan_gpe_ioam_enable_reply) \ +_(vxlan_gpe_ioam_disable_reply) \ +_(vxlan_gpe_ioam_vni_enable_reply) \ +_(vxlan_gpe_ioam_vni_disable_reply) \ +_(vxlan_gpe_ioam_transit_enable_reply) \ +_(vxlan_gpe_ioam_transit_disable_reply) + +#define _(n) \ + static void vl_api_##n##_t_handler \ + (vl_api_##n##_t * mp) \ + { \ + vat_main_t * vam = vxlan_gpe_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 \ +_(VXLAN_GPE_IOAM_ENABLE_REPLY, vxlan_gpe_ioam_enable_reply) \ +_(VXLAN_GPE_IOAM_DISABLE_REPLY, vxlan_gpe_ioam_disable_reply) \ +_(VXLAN_GPE_IOAM_VNI_ENABLE_REPLY, vxlan_gpe_ioam_vni_enable_reply) \ +_(VXLAN_GPE_IOAM_VNI_DISABLE_REPLY, vxlan_gpe_ioam_vni_disable_reply) \ +_(VXLAN_GPE_IOAM_TRANSIT_ENABLE_REPLY, vxlan_gpe_ioam_transit_enable_reply) \ +_(VXLAN_GPE_IOAM_TRANSIT_DISABLE_REPLY, vxlan_gpe_ioam_transit_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_vxlan_gpe_ioam_enable (vat_main_t * vam) +{ + vxlan_gpe_test_main_t *sm = &vxlan_gpe_test_main; + + unformat_input_t *input = vam->input; + vl_api_vxlan_gpe_ioam_enable_t *mp; + f64 timeout; + u32 id = 0; + int has_trace_option = 0; + int has_pow_option = 0; + int has_ppc_option = 0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "trace")) + has_trace_option = 1; + else if (unformat (input, "pow")) + has_pow_option = 1; + else if (unformat (input, "ppc encap")) + has_ppc_option = PPC_ENCAP; + else if (unformat (input, "ppc decap")) + has_ppc_option = PPC_DECAP; + else if (unformat (input, "ppc none")) + has_ppc_option = PPC_NONE; + else + break; + } + M (VXLAN_GPE_IOAM_ENABLE, vxlan_gpe_ioam_enable); + mp->id = htons (id); + mp->trace_ppc = has_ppc_option; + mp->pow_enable = has_pow_option; + mp->trace_enable = has_trace_option; + + + S; + W; + + return (0); +} + + +static int +api_vxlan_gpe_ioam_disable (vat_main_t * vam) +{ + vxlan_gpe_test_main_t *sm = &vxlan_gpe_test_main; + vl_api_vxlan_gpe_ioam_disable_t *mp; + f64 timeout; + + M (VXLAN_GPE_IOAM_DISABLE, vxlan_gpe_ioam_disable); + S; + W; + return 0; +} + +static int +api_vxlan_gpe_ioam_vni_enable (vat_main_t * vam) +{ + vxlan_gpe_test_main_t *sm = &vxlan_gpe_test_main; + + unformat_input_t *line_input = vam->input; + vl_api_vxlan_gpe_ioam_vni_enable_t *mp; + ip4_address_t local4, remote4; + ip6_address_t local6, remote6; + u8 ipv4_set = 0, ipv6_set = 0; + u8 local_set = 0; + u8 remote_set = 0; + u32 vni; + u8 vni_set = 0; + f64 timeout; + + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "local %U", unformat_ip4_address, &local4)) + { + local_set = 1; + ipv4_set = 1; + } + else if (unformat (line_input, "remote %U", + unformat_ip4_address, &remote4)) + { + remote_set = 1; + ipv4_set = 1; + } + else if (unformat (line_input, "local %U", + unformat_ip6_address, &local6)) + { + local_set = 1; + ipv6_set = 1; + } + else if (unformat (line_input, "remote %U", + unformat_ip6_address, &remote6)) + { + remote_set = 1; + ipv6_set = 1; + } + + else if (unformat (line_input, "vni %d", &vni)) + vni_set = 1; + else + { + errmsg ("parse error '%U'\n", format_unformat_error, line_input); + return -99; + } + } + + if (local_set == 0) + { + errmsg ("tunnel local address not specified\n"); + return -99; + } + if (remote_set == 0) + { + errmsg ("tunnel remote address not specified\n"); + return -99; + } + if (ipv4_set && ipv6_set) + { + errmsg ("both IPv4 and IPv6 addresses specified"); + return -99; + } + + if (vni_set == 0) + { + errmsg ("vni not specified\n"); + return -99; + } + + M (VXLAN_GPE_IOAM_VNI_ENABLE, vxlan_gpe_ioam_vni_enable); + + + if (ipv6_set) + { + clib_memcpy (&mp->local, &local6, sizeof (local6)); + clib_memcpy (&mp->remote, &remote6, sizeof (remote6)); + } + else + { + clib_memcpy (&mp->local, &local4, sizeof (local4)); + clib_memcpy (&mp->remote, &remote4, sizeof (remote4)); + } + + mp->vni = ntohl (vni); + mp->is_ipv6 = ipv6_set; + + S; + W; + + return (0); +} + +static int +api_vxlan_gpe_ioam_vni_disable (vat_main_t * vam) +{ + vxlan_gpe_test_main_t *sm = &vxlan_gpe_test_main; + + unformat_input_t *line_input = vam->input; + vl_api_vxlan_gpe_ioam_vni_disable_t *mp; + ip4_address_t local4, remote4; + ip6_address_t local6, remote6; + u8 ipv4_set = 0, ipv6_set = 0; + u8 local_set = 0; + u8 remote_set = 0; + u32 vni; + u8 vni_set = 0; + f64 timeout; + + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "local %U", unformat_ip4_address, &local4)) + { + local_set = 1; + ipv4_set = 1; + } + else if (unformat (line_input, "remote %U", + unformat_ip4_address, &remote4)) + { + remote_set = 1; + ipv4_set = 1; + } + else if (unformat (line_input, "local %U", + unformat_ip6_address, &local6)) + { + local_set = 1; + ipv6_set = 1; + } + else if (unformat (line_input, "remote %U", + unformat_ip6_address, &remote6)) + { + remote_set = 1; + ipv6_set = 1; + } + + else if (unformat (line_input, "vni %d", &vni)) + vni_set = 1; + else + { + errmsg ("parse error '%U'\n", format_unformat_error, line_input); + return -99; + } + } + + if (local_set == 0) + { + errmsg ("tunnel local address not specified\n"); + return -99; + } + if (remote_set == 0) + { + errmsg ("tunnel remote address not specified\n"); + return -99; + } + if (ipv4_set && ipv6_set) + { + errmsg ("both IPv4 and IPv6 addresses specified"); + return -99; + } + + if (vni_set == 0) + { + errmsg ("vni not specified\n"); + return -99; + } + + M (VXLAN_GPE_IOAM_VNI_DISABLE, vxlan_gpe_ioam_vni_disable); + + + if (ipv6_set) + { + clib_memcpy (&mp->local, &local6, sizeof (local6)); + clib_memcpy (&mp->remote, &remote6, sizeof (remote6)); + } + else + { + clib_memcpy (&mp->local, &local4, sizeof (local4)); + clib_memcpy (&mp->remote, &remote4, sizeof (remote4)); + } + + mp->vni = ntohl (vni); + mp->is_ipv6 = ipv6_set; + + S; + W; + + return 0; +} + +static int +api_vxlan_gpe_ioam_transit_enable (vat_main_t * vam) +{ + vxlan_gpe_test_main_t *sm = &vxlan_gpe_test_main; + + unformat_input_t *line_input = vam->input; + vl_api_vxlan_gpe_ioam_transit_enable_t *mp; + ip4_address_t local4; + ip6_address_t local6; + u8 ipv4_set = 0, ipv6_set = 0; + u8 local_set = 0; + u32 outer_fib_index = 0; + f64 timeout; + + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "dst-ip %U", unformat_ip4_address, &local4)) + { + local_set = 1; + ipv4_set = 1; + } + else if (unformat (line_input, "dst-ip %U", + unformat_ip6_address, &local6)) + { + local_set = 1; + ipv6_set = 1; + } + + else if (unformat (line_input, "outer-fib-index %d", &outer_fib_index)) + ; + else + { + errmsg ("parse error '%U'\n", format_unformat_error, line_input); + return -99; + } + } + + if (local_set == 0) + { + errmsg ("destination address not specified\n"); + return -99; + } + if (ipv4_set && ipv6_set) + { + errmsg ("both IPv4 and IPv6 addresses specified"); + return -99; + } + + + M (VXLAN_GPE_IOAM_TRANSIT_ENABLE, vxlan_gpe_ioam_transit_enable); + + + if (ipv6_set) + { + errmsg ("IPv6 currently unsupported"); + return -1; + } + else + { + clib_memcpy (&mp->dst_addr, &local4, sizeof (local4)); + } + + mp->outer_fib_index = htonl (outer_fib_index); + mp->is_ipv6 = ipv6_set; + + S; + W; + + return (0); +} + +static int +api_vxlan_gpe_ioam_transit_disable (vat_main_t * vam) +{ + vxlan_gpe_test_main_t *sm = &vxlan_gpe_test_main; + + unformat_input_t *line_input = vam->input; + vl_api_vxlan_gpe_ioam_transit_disable_t *mp; + ip4_address_t local4; + ip6_address_t local6; + u8 ipv4_set = 0, ipv6_set = 0; + u8 local_set = 0; + u32 outer_fib_index; + f64 timeout; + + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "dst-ip %U", unformat_ip4_address, &local4)) + { + local_set = 1; + ipv4_set = 1; + } + else if (unformat (line_input, "dst-ip %U", + unformat_ip6_address, &local6)) + { + local_set = 1; + ipv6_set = 1; + } + + else if (unformat (line_input, "outer-fib-index %d", &outer_fib_index)) + ; + else + { + errmsg ("parse error '%U'\n", format_unformat_error, line_input); + return -99; + } + } + + if (local_set == 0) + { + errmsg ("destination address not specified\n"); + return -99; + } + if (ipv4_set && ipv6_set) + { + errmsg ("both IPv4 and IPv6 addresses specified"); + return -99; + } + + + M (VXLAN_GPE_IOAM_TRANSIT_DISABLE, vxlan_gpe_ioam_transit_disable); + + + if (ipv6_set) + { + return -1; + } + else + { + clib_memcpy (&mp->dst_addr, &local4, sizeof (local4)); + } + + mp->outer_fib_index = htonl (outer_fib_index); + mp->is_ipv6 = ipv6_set; + + S; + W; + + + return (0); +} + +/* + * List of messages that the api test plugin sends, + * and that the data plane plugin processes + */ +#define foreach_vpe_api_msg \ +_(vxlan_gpe_ioam_enable, ""\ + "[trace] [pow] [ppc ]") \ +_(vxlan_gpe_ioam_disable, "") \ +_(vxlan_gpe_ioam_vni_enable, ""\ + "local remote vni ") \ +_(vxlan_gpe_ioam_vni_disable, ""\ + "local remote vni ") \ +_(vxlan_gpe_ioam_transit_enable, ""\ + "dst-ip [outer-fib-index ]") \ +_(vxlan_gpe_ioam_transit_disable, ""\ + "dst-ip [outer-fib-index ]") \ + + +void +vat_api_hookup (vat_main_t * vam) +{ + vxlan_gpe_test_main_t *sm = &vxlan_gpe_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) +{ + vxlan_gpe_test_main_t *sm = &vxlan_gpe_test_main; + u8 *name; + + sm->vat_main = vam; + + name = format (0, "ioam_vxlan_gpe_%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; +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/lb.am b/src/plugins/lb.am new file mode 100644 index 00000000..352358fa --- /dev/null +++ b/src/plugins/lb.am @@ -0,0 +1,42 @@ +# Copyright (c) 2016 Cisco Systems, Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +vppapitestplugins_LTLIBRARIES += lb_test_plugin.la +vppplugins_LTLIBRARIES += lb_plugin.la + +lb_plugin_la_SOURCES = \ + lb/lb.c \ + lb/node.c \ + lb/cli.c \ + lb/util.c \ + lb/refcount.c \ + lb/api.c + +BUILT_SOURCES += \ + lb/lb.api.h \ + lb/lb.api.json + +API_FILES += lb/lb.api + +noinst_HEADERS += \ + lb/lb.h \ + lb/util.h \ + lb/refcount.h \ + lb/lbhash.h \ + lb/lb.api.h + +lb_test_plugin_la_SOURCES = \ + lb/lb_test.c \ + lb/lb_plugin.api.h + +# vi:syntax=automake diff --git a/src/plugins/lb/api.c b/src/plugins/lb/api.c new file mode 100644 index 00000000..06c53fa1 --- /dev/null +++ b/src/plugins/lb/api.c @@ -0,0 +1,228 @@ +/* + * 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. + */ + +#include + +#include +#include +#include +#include +#include + +#define vl_msg_id(n,h) n, +typedef enum { +#include + /* We'll want to know how many messages IDs we need... */ + VL_MSG_FIRST_AVAILABLE, +} vl_msg_id_t; +#undef vl_msg_id + + +/* define message structures */ +#define vl_typedefs +#include +#undef vl_typedefs + +/* define generated endian-swappers */ +#define vl_endianfun +#include +#undef vl_endianfun + +#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) + +/* Get the API version number */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#undef vl_api_version + +#define vl_msg_name_crc_list +#include +#undef vl_msg_name_crc_list + +static void +setup_message_id_table (lb_main_t * lbm, api_main_t * am) +{ +#define _(id,n,crc) \ + vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + lbm->msg_id_base); + foreach_vl_msg_name_crc_lb; +#undef _ +} + +/* Macro to finish up custom dump fns */ +#define FINISH \ + vec_add1 (s, 0); \ + vl_print (handle, (char *)s); \ + vec_free (s); \ + return handle; + +/* + * 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)+lbm->msg_id_base); \ + rmp->context = mp->context; \ + rmp->retval = ntohl(rv); \ + \ + vl_msg_api_send_shmem (q, (u8 *)&rmp); \ +} while(0); + +static void +vl_api_lb_conf_t_handler +(vl_api_lb_conf_t * mp) +{ + lb_main_t *lbm = &lb_main; + vl_api_lb_conf_reply_t * rmp; + int rv = 0; + + rv = lb_conf((ip4_address_t *)&mp->ip4_src_address, + (ip6_address_t *)mp->ip6_src_address, + mp->sticky_buckets_per_core, + mp->flow_timeout); + + REPLY_MACRO (VL_API_LB_CONF_REPLY); +} + +static void *vl_api_lb_conf_t_print +(vl_api_lb_conf_t *mp, void * handle) +{ + u8 * s; + s = format (0, "SCRIPT: lb_conf "); + s = format (s, "%U ", format_ip4_address, (ip4_address_t *)&mp->ip4_src_address); + s = format (s, "%U ", format_ip6_address, (ip6_address_t *)mp->ip6_src_address); + s = format (s, "%u ", mp->sticky_buckets_per_core); + s = format (s, "%u ", mp->flow_timeout); + FINISH; +} + + +static void +vl_api_lb_add_del_vip_t_handler +(vl_api_lb_add_del_vip_t * mp) +{ + lb_main_t *lbm = &lb_main; + vl_api_lb_conf_reply_t * rmp; + int rv = 0; + ip46_address_t prefix; + memcpy(&prefix.ip6, mp->ip_prefix, sizeof(prefix.ip6)); + + if (mp->is_del) { + u32 vip_index; + if (!(rv = lb_vip_find_index(&prefix, mp->prefix_length, &vip_index))) + rv = lb_vip_del(vip_index); + } else { + u32 vip_index; + lb_vip_type_t type; + if (ip46_prefix_is_ip4(&prefix, mp->prefix_length)) { + type = mp->is_gre4?LB_VIP_TYPE_IP4_GRE4:LB_VIP_TYPE_IP4_GRE6; + } else { + type = mp->is_gre4?LB_VIP_TYPE_IP6_GRE4:LB_VIP_TYPE_IP6_GRE6; + } + + rv = lb_vip_add(&prefix, mp->prefix_length, type, + mp->new_flows_table_length, &vip_index); + } + REPLY_MACRO (VL_API_LB_CONF_REPLY); +} + +static void *vl_api_lb_add_del_vip_t_print +(vl_api_lb_add_del_vip_t *mp, void * handle) +{ + u8 * s; + s = format (0, "SCRIPT: lb_add_del_vip "); + s = format (s, "%U ", format_ip46_prefix, + (ip46_address_t *)mp->ip_prefix, mp->prefix_length, IP46_TYPE_ANY); + s = format (s, "%s ", mp->is_gre4?"gre4":"gre6"); + s = format (s, "%u ", mp->new_flows_table_length); + s = format (s, "%s ", mp->is_del?"del":"add"); + FINISH; +} + +static void +vl_api_lb_add_del_as_t_handler +(vl_api_lb_add_del_as_t * mp) +{ + lb_main_t *lbm = &lb_main; + vl_api_lb_conf_reply_t * rmp; + int rv = 0; + u32 vip_index; + if ((rv = lb_vip_find_index((ip46_address_t *)mp->vip_ip_prefix, + mp->vip_prefix_length, &vip_index))) + goto done; + + if (mp->is_del) + rv = lb_vip_del_ass(vip_index, (ip46_address_t *)mp->as_address, 1); + else + rv = lb_vip_add_ass(vip_index, (ip46_address_t *)mp->as_address, 1); + +done: + REPLY_MACRO (VL_API_LB_CONF_REPLY); +} + +static void *vl_api_lb_add_del_as_t_print +(vl_api_lb_add_del_as_t *mp, void * handle) +{ + u8 * s; + s = format (0, "SCRIPT: lb_add_del_as "); + s = format (s, "%U ", format_ip46_prefix, + (ip46_address_t *)mp->vip_ip_prefix, mp->vip_prefix_length, IP46_TYPE_ANY); + s = format (s, "%U ", format_ip46_address, + (ip46_address_t *)mp->as_address, IP46_TYPE_ANY); + s = format (s, "%s ", mp->is_del?"del":"add"); + FINISH; +} + +/* List of message types that this plugin understands */ +#define foreach_lb_plugin_api_msg \ +_(LB_CONF, lb_conf) \ +_(LB_ADD_DEL_VIP, lb_add_del_vip) \ +_(LB_ADD_DEL_AS, lb_add_del_as) + +static clib_error_t * lb_api_init (vlib_main_t * vm) +{ + lb_main_t *lbm = &lb_main; + u8 *name = format (0, "lb_%08x%c", api_version, 0); + lbm->msg_id_base = vl_msg_api_get_msg_ids + ((char *) name, VL_MSG_FIRST_AVAILABLE); + +#define _(N,n) \ + vl_msg_api_set_handlers((VL_API_##N + lbm->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_lb_plugin_api_msg; +#undef _ + + /* Add our API messages to the global name_crc hash table */ + setup_message_id_table (lbm, &api_main); + + return 0; +} + +VLIB_INIT_FUNCTION (lb_api_init); diff --git a/src/plugins/lb/cli.c b/src/plugins/lb/cli.c new file mode 100644 index 00000000..b59c6426 --- /dev/null +++ b/src/plugins/lb/cli.c @@ -0,0 +1,250 @@ +/* + * 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. + */ + +#include +#include + +static clib_error_t * +lb_vip_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + ip46_address_t prefix; + u8 plen; + u32 new_len = 1024; + u8 del = 0; + int ret; + u32 gre4 = 0; + lb_vip_type_t type; + + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + if (!unformat(line_input, "%U", unformat_ip46_prefix, &prefix, &plen, IP46_TYPE_ANY, &plen)) + return clib_error_return (0, "invalid vip prefix: '%U'", + format_unformat_error, line_input); + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat(line_input, "new_len %d", &new_len)) + ; + else if (unformat(line_input, "del")) + del = 1; + else if (unformat(line_input, "encap gre4")) + gre4 = 1; + else if (unformat(line_input, "encap gre6")) + gre4 = 0; + else + return clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + } + + unformat_free (line_input); + + + if (ip46_prefix_is_ip4(&prefix, plen)) { + type = (gre4)?LB_VIP_TYPE_IP4_GRE4:LB_VIP_TYPE_IP4_GRE6; + } else { + type = (gre4)?LB_VIP_TYPE_IP6_GRE4:LB_VIP_TYPE_IP6_GRE6; + } + + lb_garbage_collection(); + + u32 index; + if (!del) { + if ((ret = lb_vip_add(&prefix, plen, type, new_len, &index))) { + return clib_error_return (0, "lb_vip_add error %d", ret); + } else { + vlib_cli_output(vm, "lb_vip_add ok %d", index); + } + } else { + if ((ret = lb_vip_find_index(&prefix, plen, &index))) + return clib_error_return (0, "lb_vip_find_index error %d", ret); + else if ((ret = lb_vip_del(index))) + return clib_error_return (0, "lb_vip_del error %d", ret); + } + return NULL; +} + +VLIB_CLI_COMMAND (lb_vip_command, static) = +{ + .path = "lb vip", + .short_help = "lb vip [encap (gre6|gre4)] [new_len ] [del]", + .function = lb_vip_command_fn, +}; + +static clib_error_t * +lb_as_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + ip46_address_t vip_prefix, as_addr; + u8 vip_plen; + ip46_address_t *as_array = 0; + u32 vip_index; + u8 del = 0; + int ret; + + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + if (!unformat(line_input, "%U", unformat_ip46_prefix, &vip_prefix, &vip_plen, IP46_TYPE_ANY)) + return clib_error_return (0, "invalid as address: '%U'", + format_unformat_error, line_input); + + if ((ret = lb_vip_find_index(&vip_prefix, vip_plen, &vip_index))) + return clib_error_return (0, "lb_vip_find_index error %d", ret); + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat(line_input, "%U", unformat_ip46_address, &as_addr, IP46_TYPE_ANY)) { + vec_add1(as_array, as_addr); + } else if (unformat(line_input, "del")) { + del = 1; + } else { + vec_free(as_array); + return clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + } + } + + if (!vec_len(as_array)) { + vec_free(as_array); + return clib_error_return (0, "No AS address provided"); + } + + lb_garbage_collection(); + clib_warning("vip index is %d", vip_index); + + if (del) { + if ((ret = lb_vip_del_ass(vip_index, as_array, vec_len(as_array)))) { + vec_free(as_array); + return clib_error_return (0, "lb_vip_del_ass error %d", ret); + } + } else { + if ((ret = lb_vip_add_ass(vip_index, as_array, vec_len(as_array)))) { + vec_free(as_array); + return clib_error_return (0, "lb_vip_add_ass error %d", ret); + } + } + + vec_free(as_array); + return 0; +} + +VLIB_CLI_COMMAND (lb_as_command, static) = +{ + .path = "lb as", + .short_help = "lb as [
[
[...]]] [del]", + .function = lb_as_command_fn, +}; + +static clib_error_t * +lb_conf_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + lb_main_t *lbm = &lb_main; + unformat_input_t _line_input, *line_input = &_line_input; + ip4_address_t ip4 = lbm->ip4_src_address; + ip6_address_t ip6 = lbm->ip6_src_address; + u32 per_cpu_sticky_buckets = lbm->per_cpu_sticky_buckets; + u32 per_cpu_sticky_buckets_log2 = 0; + u32 flow_timeout = lbm->flow_timeout; + int ret; + + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat(line_input, "ip4-src-address %U", unformat_ip4_address, &ip4)) + ; + else if (unformat(line_input, "ip6-src-address %U", unformat_ip6_address, &ip6)) + ; + else if (unformat(line_input, "buckets %d", &per_cpu_sticky_buckets)) + ; + else if (unformat(line_input, "buckets-log2 %d", &per_cpu_sticky_buckets_log2)) { + if (per_cpu_sticky_buckets_log2 >= 32) + return clib_error_return (0, "buckets-log2 value is too high"); + per_cpu_sticky_buckets = 1 << per_cpu_sticky_buckets_log2; + } else if (unformat(line_input, "timeout %d", &flow_timeout)) + ; + else + return clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + } + + unformat_free (line_input); + + lb_garbage_collection(); + + if ((ret = lb_conf(&ip4, &ip6, per_cpu_sticky_buckets, flow_timeout))) + return clib_error_return (0, "lb_conf error %d", ret); + + return NULL; +} + +VLIB_CLI_COMMAND (lb_conf_command, static) = +{ + .path = "lb conf", + .short_help = "lb conf [ip4-src-address ] [ip6-src-address ] [buckets ] [timeout ]", + .function = lb_conf_command_fn, +}; + +static clib_error_t * +lb_show_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vlib_cli_output(vm, "%U", format_lb_main); + return NULL; +} + + +VLIB_CLI_COMMAND (lb_show_command, static) = +{ + .path = "show lb", + .short_help = "show lb", + .function = lb_show_command_fn, +}; + +static clib_error_t * +lb_show_vips_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + unformat_input_t line_input; + lb_main_t *lbm = &lb_main; + lb_vip_t *vip; + u8 verbose = 0; + + if (!unformat_user (input, unformat_line_input, &line_input)) + return 0; + + if (unformat(&line_input, "verbose")) + verbose = 1; + + pool_foreach(vip, lbm->vips, { + vlib_cli_output(vm, "%U\n", verbose?format_lb_vip_detailed:format_lb_vip, vip); + }); + + unformat_free (&line_input); + return NULL; +} + +VLIB_CLI_COMMAND (lb_show_vips_command, static) = +{ + .path = "show lb vips", + .short_help = "show lb vips [verbose]", + .function = lb_show_vips_command_fn, +}; diff --git a/src/plugins/lb/lb.api b/src/plugins/lb/lb.api new file mode 100644 index 00000000..39ee3c8f --- /dev/null +++ b/src/plugins/lb/lb.api @@ -0,0 +1,71 @@ +/** \brief Configure Load-Balancer global parameters + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param ip4_src_address - IPv4 address to be used as source for IPv4 GRE traffic. + @param ip6_src_address - IPv6 address to be used as source for IPv6 GRE traffic. + @param n_sticky_buckets - Number of buckets *per worker thread* in the + established flow table (must be power of 2). + @param flow_timeout - Time in seconds after which, if no packet is received + for a given flow, the flow is removed from the established flow table. +*/ +define lb_conf +{ + u32 client_index; + u32 context; + u32 ip4_src_address; + u8 ip6_src_address[16]; + u32 sticky_buckets_per_core; + u32 flow_timeout; +}; + +define lb_conf_reply { + u32 context; + i32 retval; +}; + +/** \brief Add a virtual address (or prefix) + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param ip_prefix - IP address (IPv4 in lower order 32 bits). + @param prefix_length - IP prefix length (96 + 'IPv4 prefix length' for IPv4). + @param is_gre4 - Encap is ip4 GRE (ip6 GRE otherwise). + @param new_flows_table_length - Size of the new connections flow table used + for this VIP (must be power of 2). + @param is_del - The VIP should be removed. +*/ +define lb_add_del_vip { + u32 client_index; + u32 context; + u8 ip_prefix[16]; + u8 prefix_length; + u8 is_gre4; + u32 new_flows_table_length; + u8 is_del; +}; + +define lb_add_del_vip_reply { + u32 context; + i32 retval; +}; + +/** \brief Add an application server for a given VIP + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param vip_ip_prefix - VIP IP address (IPv4 in lower order 32 bits). + @param vip_ip_prefix - VIP IP prefix length (96 + 'IPv4 prefix length' for IPv4). + @param as_address - The application server address (IPv4 in lower order 32 bits). + @param is_del - The AS should be removed. +*/ +define lb_add_del_as { + u32 client_index; + u32 context; + u8 vip_ip_prefix[16]; + u8 vip_prefix_length; + u8 as_address[16]; + u8 is_del; +}; + +define lb_add_del_as_reply { + u32 context; + i32 retval; +}; diff --git a/src/plugins/lb/lb.c b/src/plugins/lb/lb.c new file mode 100644 index 00000000..1d9b9870 --- /dev/null +++ b/src/plugins/lb/lb.c @@ -0,0 +1,844 @@ +/* + * 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. + */ + +#include +#include +#include + +//GC runs at most once every so many seconds +#define LB_GARBAGE_RUN 60 + +//After so many seconds. It is assumed that inter-core race condition will not occur. +#define LB_CONCURRENCY_TIMEOUT 10 + +lb_main_t lb_main; + +#define lb_get_writer_lock() do {} while(__sync_lock_test_and_set (lb_main.writer_lock, 1)) +#define lb_put_writer_lock() lb_main.writer_lock[0] = 0 + +static void lb_as_stack (lb_as_t *as); + + +const static char * const lb_dpo_gre4_ip4[] = { "lb4-gre4" , NULL }; +const static char * const lb_dpo_gre4_ip6[] = { "lb6-gre4" , NULL }; +const static char* const * const lb_dpo_gre4_nodes[DPO_PROTO_NUM] = + { + [DPO_PROTO_IP4] = lb_dpo_gre4_ip4, + [DPO_PROTO_IP6] = lb_dpo_gre4_ip6, + }; + +const static char * const lb_dpo_gre6_ip4[] = { "lb4-gre6" , NULL }; +const static char * const lb_dpo_gre6_ip6[] = { "lb6-gre6" , NULL }; +const static char* const * const lb_dpo_gre6_nodes[DPO_PROTO_NUM] = + { + [DPO_PROTO_IP4] = lb_dpo_gre6_ip4, + [DPO_PROTO_IP6] = lb_dpo_gre6_ip6, + }; + +u32 lb_hash_time_now(vlib_main_t * vm) +{ + return (u32) (vlib_time_now(vm) + 10000); +} + +u8 *format_lb_main (u8 * s, va_list * args) +{ + vlib_thread_main_t *tm = vlib_get_thread_main(); + lb_main_t *lbm = &lb_main; + s = format(s, "lb_main"); + s = format(s, " ip4-src-address: %U \n", format_ip4_address, &lbm->ip4_src_address); + s = format(s, " ip6-src-address: %U \n", format_ip6_address, &lbm->ip6_src_address); + s = format(s, " #vips: %u\n", pool_elts(lbm->vips)); + s = format(s, " #ass: %u\n", pool_elts(lbm->ass) - 1); + + u32 cpu_index; + for(cpu_index = 0; cpu_index < tm->n_vlib_mains; cpu_index++ ) { + lb_hash_t *h = lbm->per_cpu[cpu_index].sticky_ht; + if (h) { + s = format(s, "core %d\n", cpu_index); + s = format(s, " timeout: %ds\n", h->timeout); + s = format(s, " usage: %d / %d\n", lb_hash_elts(h, lb_hash_time_now(vlib_get_main())), lb_hash_size(h)); + } + } + + return s; +} + +static char *lb_vip_type_strings[] = { + [LB_VIP_TYPE_IP6_GRE6] = "ip6-gre6", + [LB_VIP_TYPE_IP6_GRE4] = "ip6-gre4", + [LB_VIP_TYPE_IP4_GRE6] = "ip4-gre6", + [LB_VIP_TYPE_IP4_GRE4] = "ip4-gre4", +}; + +u8 *format_lb_vip_type (u8 * s, va_list * args) +{ + lb_vip_type_t vipt = va_arg (*args, lb_vip_type_t); + u32 i; + for (i=0; itype, + format_ip46_prefix, &vip->prefix, vip->plen, IP46_TYPE_ANY, + vip->new_flow_table_mask + 1, + pool_elts(vip->as_indexes), + (vip->flags & LB_VIP_FLAGS_USED)?"":" removed"); +} + +u8 *format_lb_as (u8 * s, va_list * args) +{ + lb_as_t *as = va_arg (*args, lb_as_t *); + return format(s, "%U %s", format_ip46_address, + &as->address, IP46_TYPE_ANY, + (as->flags & LB_AS_FLAGS_USED)?"used":"removed"); +} + +u8 *format_lb_vip_detailed (u8 * s, va_list * args) +{ + lb_main_t *lbm = &lb_main; + lb_vip_t *vip = va_arg (*args, lb_vip_t *); + uword indent = format_get_indent (s); + + s = format(s, "%U %U [%u] %U%s\n" + "%U new_size:%u\n", + format_white_space, indent, + format_lb_vip_type, vip->type, + vip - lbm->vips, format_ip46_prefix, &vip->prefix, vip->plen, IP46_TYPE_ANY, + (vip->flags & LB_VIP_FLAGS_USED)?"":" removed", + format_white_space, indent, + vip->new_flow_table_mask + 1); + + //Print counters + s = format(s, "%U counters:\n", + format_white_space, indent); + u32 i; + for (i=0; ivip_counters[i].name, + vlib_get_simple_counter(&lbm->vip_counters[i], vip - lbm->vips)); + + + s = format(s, "%U #as:%u\n", + format_white_space, indent, + pool_elts(vip->as_indexes)); + + //Let's count the buckets for each AS + u32 *count = 0; + vec_validate(count, pool_len(lbm->ass)); //Possibly big alloc for not much... + lb_new_flow_entry_t *nfe; + vec_foreach(nfe, vip->new_flow_table) + count[nfe->as_index]++; + + lb_as_t *as; + u32 *as_index; + pool_foreach(as_index, vip->as_indexes, { + as = &lbm->ass[*as_index]; + s = format(s, "%U %U %d buckets %d flows dpo:%u %s\n", + format_white_space, indent, + format_ip46_address, &as->address, IP46_TYPE_ANY, + count[as - lbm->ass], + vlib_refcount_get(&lbm->as_refcount, as - lbm->ass), + as->dpo.dpoi_index, + (as->flags & LB_AS_FLAGS_USED)?"used":" removed"); + }); + + vec_free(count); + + /* + s = format(s, "%U new flows table:\n", format_white_space, indent); + lb_new_flow_entry_t *nfe; + vec_foreach(nfe, vip->new_flow_table) { + s = format(s, "%U %d: %d\n", format_white_space, indent, nfe - vip->new_flow_table, nfe->as_index); + } + */ + return s; +} + +typedef struct { + u32 as_index; + u32 last; + u32 skip; +} lb_pseudorand_t; + +static int lb_pseudorand_compare(void *a, void *b) +{ + lb_as_t *asa, *asb; + lb_main_t *lbm = &lb_main; + asa = &lbm->ass[((lb_pseudorand_t *)a)->as_index]; + asb = &lbm->ass[((lb_pseudorand_t *)b)->as_index]; + return memcmp(&asa->address, &asb->address, sizeof(asb->address)); +} + +static void lb_vip_garbage_collection(lb_vip_t *vip) +{ + lb_main_t *lbm = &lb_main; + ASSERT (lbm->writer_lock[0]); + + u32 now = (u32) vlib_time_now(vlib_get_main()); + if (!clib_u32_loop_gt(now, vip->last_garbage_collection + LB_GARBAGE_RUN)) + return; + + vip->last_garbage_collection = now; + lb_as_t *as; + u32 *as_index; + pool_foreach(as_index, vip->as_indexes, { + as = &lbm->ass[*as_index]; + if (!(as->flags & LB_AS_FLAGS_USED) && //Not used + clib_u32_loop_gt(now, as->last_used + LB_CONCURRENCY_TIMEOUT) && //Not recently used + (vlib_refcount_get(&lbm->as_refcount, as - lbm->ass) == 0)) + { //Not referenced + fib_entry_child_remove(as->next_hop_fib_entry_index, + as->next_hop_child_index); + fib_table_entry_delete_index(as->next_hop_fib_entry_index, + FIB_SOURCE_RR); + as->next_hop_fib_entry_index = FIB_NODE_INDEX_INVALID; + + pool_put(vip->as_indexes, as_index); + pool_put(lbm->ass, as); + } + }); +} + +void lb_garbage_collection() +{ + lb_main_t *lbm = &lb_main; + lb_get_writer_lock(); + lb_vip_t *vip; + u32 *to_be_removed_vips = 0, *i; + pool_foreach(vip, lbm->vips, { + lb_vip_garbage_collection(vip); + + if (!(vip->flags & LB_VIP_FLAGS_USED) && + (pool_elts(vip->as_indexes) == 0)) { + vec_add1(to_be_removed_vips, vip - lbm->vips); + } + }); + + vec_foreach(i, to_be_removed_vips) { + vip = &lbm->vips[*i]; + pool_put(lbm->vips, vip); + pool_free(vip->as_indexes); + } + + vec_free(to_be_removed_vips); + lb_put_writer_lock(); +} + +static void lb_vip_update_new_flow_table(lb_vip_t *vip) +{ + lb_main_t *lbm = &lb_main; + lb_new_flow_entry_t *old_table; + u32 i, *as_index; + lb_new_flow_entry_t *new_flow_table = 0; + lb_as_t *as; + lb_pseudorand_t *pr, *sort_arr = 0; + u32 count; + + ASSERT (lbm->writer_lock[0]); //We must have the lock + + //Check if some AS is configured or not + i = 0; + pool_foreach(as_index, vip->as_indexes, { + as = &lbm->ass[*as_index]; + if (as->flags & LB_AS_FLAGS_USED) { //Not used anymore + i = 1; + goto out; //Not sure 'break' works in this macro-loop + } + }); + +out: + if (i == 0) { + //Only the default. i.e. no AS + vec_validate(new_flow_table, vip->new_flow_table_mask); + for (i=0; ias_indexes)); + + i = 0; + pool_foreach(as_index, vip->as_indexes, { + as = &lbm->ass[*as_index]; + if (!(as->flags & LB_AS_FLAGS_USED)) //Not used anymore + continue; + + sort_arr[i].as_index = as - lbm->ass; + i++; + }); + _vec_len(sort_arr) = i; + + vec_sort_with_function(sort_arr, lb_pseudorand_compare); + + //Now let's pseudo-randomly generate permutations + vec_foreach(pr, sort_arr) { + lb_as_t *as = &lbm->ass[pr->as_index]; + + u64 seed = clib_xxhash(as->address.as_u64[0] ^ + as->address.as_u64[1]); + /* We have 2^n buckets. + * skip must be prime with 2^n. + * So skip must be odd. + * MagLev actually state that M should be prime, + * but this has a big computation cost (% operation). + * Using 2^n is more better (& operation). + */ + pr->skip = ((seed & 0xffffffff) | 1) & vip->new_flow_table_mask; + pr->last = (seed >> 32) & vip->new_flow_table_mask; + } + + //Let's create a new flow table + vec_validate(new_flow_table, vip->new_flow_table_mask); + for (i=0; ilast; + pr->last = (pr->last + pr->skip) & vip->new_flow_table_mask; + if (new_flow_table[last].as_index == ~0) { + new_flow_table[last].as_index = pr->as_index; + break; + } + } + done++; + if (done == vec_len(new_flow_table)) + goto finished; + } + } + + vec_free(sort_arr); + +finished: + +//Count number of changed entries + count = 0; + for (i=0; inew_flow_table == 0 || + new_flow_table[i].as_index != vip->new_flow_table[i].as_index) + count++; + + old_table = vip->new_flow_table; + vip->new_flow_table = new_flow_table; + vec_free(old_table); +} + +int lb_conf(ip4_address_t *ip4_address, ip6_address_t *ip6_address, + u32 per_cpu_sticky_buckets, u32 flow_timeout) +{ + lb_main_t *lbm = &lb_main; + + if (!is_pow2(per_cpu_sticky_buckets)) + return VNET_API_ERROR_INVALID_MEMORY_SIZE; + + lb_get_writer_lock(); //Not exactly necessary but just a reminder that it exists for my future self + lbm->ip4_src_address = *ip4_address; + lbm->ip6_src_address = *ip6_address; + lbm->per_cpu_sticky_buckets = per_cpu_sticky_buckets; + lbm->flow_timeout = flow_timeout; + lb_put_writer_lock(); + return 0; +} + +static +int lb_vip_find_index_with_lock(ip46_address_t *prefix, u8 plen, u32 *vip_index) +{ + lb_main_t *lbm = &lb_main; + lb_vip_t *vip; + ASSERT (lbm->writer_lock[0]); //This must be called with the lock owned + ip46_prefix_normalize(prefix, plen); + pool_foreach(vip, lbm->vips, { + if ((vip->flags & LB_AS_FLAGS_USED) && + vip->plen == plen && + vip->prefix.as_u64[0] == prefix->as_u64[0] && + vip->prefix.as_u64[1] == prefix->as_u64[1]) { + *vip_index = vip - lbm->vips; + return 0; + } + }); + return VNET_API_ERROR_NO_SUCH_ENTRY; +} + +int lb_vip_find_index(ip46_address_t *prefix, u8 plen, u32 *vip_index) +{ + int ret; + lb_get_writer_lock(); + ret = lb_vip_find_index_with_lock(prefix, plen, vip_index); + lb_put_writer_lock(); + return ret; +} + +static int lb_as_find_index_vip(lb_vip_t *vip, ip46_address_t *address, u32 *as_index) +{ + lb_main_t *lbm = &lb_main; + ASSERT (lbm->writer_lock[0]); //This must be called with the lock owned + lb_as_t *as; + u32 *asi; + pool_foreach(asi, vip->as_indexes, { + as = &lbm->ass[*asi]; + if (as->vip_index == (vip - lbm->vips) && + as->address.as_u64[0] == address->as_u64[0] && + as->address.as_u64[1] == address->as_u64[1]) { + *as_index = as - lbm->ass; + return 0; + } + }); + return -1; +} + +int lb_vip_add_ass(u32 vip_index, ip46_address_t *addresses, u32 n) +{ + lb_main_t *lbm = &lb_main; + lb_get_writer_lock(); + lb_vip_t *vip; + if (!(vip = lb_vip_get_by_index(vip_index))) { + lb_put_writer_lock(); + return VNET_API_ERROR_NO_SUCH_ENTRY; + } + + ip46_type_t type = lb_vip_is_gre4(vip)?IP46_TYPE_IP4:IP46_TYPE_IP6; + u32 *to_be_added = 0; + u32 *to_be_updated = 0; + u32 i; + u32 *ip; + + //Sanity check + while (n--) { + + if (!lb_as_find_index_vip(vip, &addresses[n], &i)) { + if (lbm->ass[i].flags & LB_AS_FLAGS_USED) { + vec_free(to_be_added); + vec_free(to_be_updated); + lb_put_writer_lock(); + return VNET_API_ERROR_VALUE_EXIST; + } + vec_add1(to_be_updated, i); + goto next; + } + + if (ip46_address_type(&addresses[n]) != type) { + vec_free(to_be_added); + vec_free(to_be_updated); + lb_put_writer_lock(); + return VNET_API_ERROR_INVALID_ADDRESS_FAMILY; + } + + if (n) { + u32 n2 = n; + while(n2--) //Check for duplicates + if (addresses[n2].as_u64[0] == addresses[n].as_u64[0] && + addresses[n2].as_u64[1] == addresses[n].as_u64[1]) + goto next; + } + + vec_add1(to_be_added, n); + +next: + continue; + } + + //Update reused ASs + vec_foreach(ip, to_be_updated) { + lbm->ass[*ip].flags = LB_AS_FLAGS_USED; + } + vec_free(to_be_updated); + + //Create those who have to be created + vec_foreach(ip, to_be_added) { + lb_as_t *as; + u32 *as_index; + pool_get(lbm->ass, as); + as->address = addresses[*ip]; + as->flags = LB_AS_FLAGS_USED; + as->vip_index = vip_index; + pool_get(vip->as_indexes, as_index); + *as_index = as - lbm->ass; + + /* + * become a child of the FIB entry + * so we are informed when its forwarding changes + */ + fib_prefix_t nh = {}; + if (lb_vip_is_gre4(vip)) { + nh.fp_addr.ip4 = as->address.ip4; + nh.fp_len = 32; + nh.fp_proto = FIB_PROTOCOL_IP4; + } else { + nh.fp_addr.ip6 = as->address.ip6; + nh.fp_len = 128; + nh.fp_proto = FIB_PROTOCOL_IP6; + } + + as->next_hop_fib_entry_index = + fib_table_entry_special_add(0, + &nh, + FIB_SOURCE_RR, + FIB_ENTRY_FLAG_NONE, + ADJ_INDEX_INVALID); + as->next_hop_child_index = + fib_entry_child_add(as->next_hop_fib_entry_index, + lbm->fib_node_type, + as - lbm->ass); + + lb_as_stack(as); + } + vec_free(to_be_added); + + //Recompute flows + lb_vip_update_new_flow_table(vip); + + //Garbage collection maybe + lb_vip_garbage_collection(vip); + + lb_put_writer_lock(); + return 0; +} + +int lb_vip_del_ass_withlock(u32 vip_index, ip46_address_t *addresses, u32 n) +{ + lb_main_t *lbm = &lb_main; + u32 now = (u32) vlib_time_now(vlib_get_main()); + u32 *ip = 0; + + lb_vip_t *vip; + if (!(vip = lb_vip_get_by_index(vip_index))) { + return VNET_API_ERROR_NO_SUCH_ENTRY; + } + + u32 *indexes = NULL; + while (n--) { + u32 i; + if (lb_as_find_index_vip(vip, &addresses[n], &i)) { + vec_free(indexes); + return VNET_API_ERROR_NO_SUCH_ENTRY; + } + + if (n) { //Check for duplicates + u32 n2 = n - 1; + while(n2--) { + if (addresses[n2].as_u64[0] == addresses[n].as_u64[0] && + addresses[n2].as_u64[1] == addresses[n].as_u64[1]) + goto next; + } + } + + vec_add1(indexes, i); +next: + continue; + } + + //Garbage collection maybe + lb_vip_garbage_collection(vip); + + if (indexes != NULL) { + vec_foreach(ip, indexes) { + lbm->ass[*ip].flags &= ~LB_AS_FLAGS_USED; + lbm->ass[*ip].last_used = now; + } + + //Recompute flows + lb_vip_update_new_flow_table(vip); + } + + vec_free(indexes); + return 0; +} + +int lb_vip_del_ass(u32 vip_index, ip46_address_t *addresses, u32 n) +{ + lb_get_writer_lock(); + int ret = lb_vip_del_ass_withlock(vip_index, addresses, n); + lb_put_writer_lock(); + return ret; +} + +/** + * Add the VIP adjacency to the ip4 or ip6 fib + */ +static void lb_vip_add_adjacency(lb_main_t *lbm, lb_vip_t *vip) +{ + dpo_proto_t proto = 0; + dpo_id_t dpo = DPO_INVALID; + fib_prefix_t pfx = {}; + if (lb_vip_is_ip4(vip)) { + pfx.fp_addr.ip4 = vip->prefix.ip4; + pfx.fp_len = vip->plen - 96; + pfx.fp_proto = FIB_PROTOCOL_IP4; + proto = DPO_PROTO_IP4; + } else { + pfx.fp_addr.ip6 = vip->prefix.ip6; + pfx.fp_len = vip->plen; + pfx.fp_proto = FIB_PROTOCOL_IP6; + proto = DPO_PROTO_IP6; + } + dpo_set(&dpo, lb_vip_is_gre4(vip)?lbm->dpo_gre4_type:lbm->dpo_gre6_type, + proto, vip - lbm->vips); + fib_table_entry_special_dpo_add(0, + &pfx, + FIB_SOURCE_PLUGIN_HI, + FIB_ENTRY_FLAG_EXCLUSIVE, + &dpo); + dpo_reset(&dpo); +} + +/** + * Deletes the adjacency associated with the VIP + */ +static void lb_vip_del_adjacency(lb_main_t *lbm, lb_vip_t *vip) +{ + fib_prefix_t pfx = {}; + if (lb_vip_is_ip4(vip)) { + pfx.fp_addr.ip4 = vip->prefix.ip4; + pfx.fp_len = vip->plen - 96; + pfx.fp_proto = FIB_PROTOCOL_IP4; + } else { + pfx.fp_addr.ip6 = vip->prefix.ip6; + pfx.fp_len = vip->plen; + pfx.fp_proto = FIB_PROTOCOL_IP6; + } + fib_table_entry_special_remove(0, &pfx, FIB_SOURCE_PLUGIN_HI); +} + +int lb_vip_add(ip46_address_t *prefix, u8 plen, lb_vip_type_t type, u32 new_length, u32 *vip_index) +{ + lb_main_t *lbm = &lb_main; + lb_vip_t *vip; + lb_get_writer_lock(); + ip46_prefix_normalize(prefix, plen); + + if (!lb_vip_find_index_with_lock(prefix, plen, vip_index)) { + lb_put_writer_lock(); + return VNET_API_ERROR_VALUE_EXIST; + } + + if (!is_pow2(new_length)) { + lb_put_writer_lock(); + return VNET_API_ERROR_INVALID_MEMORY_SIZE; + } + + if (ip46_prefix_is_ip4(prefix, plen) && + (type != LB_VIP_TYPE_IP4_GRE4) && + (type != LB_VIP_TYPE_IP4_GRE6)) + return VNET_API_ERROR_INVALID_ADDRESS_FAMILY; + + + //Allocate + pool_get(lbm->vips, vip); + + //Init + vip->prefix = *prefix; + vip->plen = plen; + vip->last_garbage_collection = (u32) vlib_time_now(vlib_get_main()); + vip->type = type; + vip->flags = LB_VIP_FLAGS_USED; + vip->as_indexes = 0; + + //Validate counters + u32 i; + for (i = 0; i < LB_N_VIP_COUNTERS; i++) { + vlib_validate_simple_counter(&lbm->vip_counters[i], vip - lbm->vips); + vlib_zero_simple_counter(&lbm->vip_counters[i], vip - lbm->vips); + } + + //Configure new flow table + vip->new_flow_table_mask = new_length - 1; + vip->new_flow_table = 0; + + //Create a new flow hash table full of the default entry + lb_vip_update_new_flow_table(vip); + + //Create adjacency to direct traffic + lb_vip_add_adjacency(lbm, vip); + + //Return result + *vip_index = vip - lbm->vips; + + lb_put_writer_lock(); + return 0; +} + +int lb_vip_del(u32 vip_index) +{ + lb_main_t *lbm = &lb_main; + lb_vip_t *vip; + lb_get_writer_lock(); + if (!(vip = lb_vip_get_by_index(vip_index))) { + lb_put_writer_lock(); + return VNET_API_ERROR_NO_SUCH_ENTRY; + } + + //FIXME: This operation is actually not working + //We will need to remove state before performing this. + + { + //Remove all ASs + ip46_address_t *ass = 0; + lb_as_t *as; + u32 *as_index; + pool_foreach(as_index, vip->as_indexes, { + as = &lbm->ass[*as_index]; + vec_add1(ass, as->address); + }); + if (vec_len(ass)) + lb_vip_del_ass_withlock(vip_index, ass, vec_len(ass)); + vec_free(ass); + } + + //Delete adjacency + lb_vip_del_adjacency(lbm, vip); + + //Set the VIP as unused + vip->flags &= ~LB_VIP_FLAGS_USED; + + lb_put_writer_lock(); + return 0; +} + +clib_error_t * +vlib_plugin_register (vlib_main_t * vm, + vnet_plugin_handoff_t * h, + int from_early_init) +{ + clib_error_t *error = 0; + return error; +} + + +u8 *format_lb_dpo (u8 * s, va_list * va) +{ + index_t index = va_arg (*va, index_t); + CLIB_UNUSED(u32 indent) = va_arg (*va, u32); + lb_main_t *lbm = &lb_main; + lb_vip_t *vip = pool_elt_at_index (lbm->vips, index); + return format (s, "%U", format_lb_vip, vip); +} + +static void lb_dpo_lock (dpo_id_t *dpo) {} +static void lb_dpo_unlock (dpo_id_t *dpo) {} + +static fib_node_t * +lb_fib_node_get_node (fib_node_index_t index) +{ + lb_main_t *lbm = &lb_main; + lb_as_t *as = pool_elt_at_index (lbm->ass, index); + return (&as->fib_node); +} + +static void +lb_fib_node_last_lock_gone (fib_node_t *node) +{ +} + +static lb_as_t * +lb_as_from_fib_node (fib_node_t *node) +{ + return ((lb_as_t*)(((char*)node) - + STRUCT_OFFSET_OF(lb_as_t, fib_node))); +} + +static void +lb_as_stack (lb_as_t *as) +{ + lb_main_t *lbm = &lb_main; + lb_vip_t *vip = &lbm->vips[as->vip_index]; + dpo_stack(lb_vip_is_gre4(vip)?lbm->dpo_gre4_type:lbm->dpo_gre6_type, + lb_vip_is_ip4(vip)?DPO_PROTO_IP4:DPO_PROTO_IP6, + &as->dpo, + fib_entry_contribute_ip_forwarding( + as->next_hop_fib_entry_index)); +} + +static fib_node_back_walk_rc_t +lb_fib_node_back_walk_notify (fib_node_t *node, + fib_node_back_walk_ctx_t *ctx) +{ + lb_as_stack(lb_as_from_fib_node(node)); + return (FIB_NODE_BACK_WALK_CONTINUE); +} + +clib_error_t * +lb_init (vlib_main_t * vm) +{ + vlib_thread_main_t *tm = vlib_get_thread_main (); + lb_main_t *lbm = &lb_main; + lb_as_t *default_as; + fib_node_vft_t lb_fib_node_vft = { + .fnv_get = lb_fib_node_get_node, + .fnv_last_lock = lb_fib_node_last_lock_gone, + .fnv_back_walk = lb_fib_node_back_walk_notify, + }; + dpo_vft_t lb_vft = { + .dv_lock = lb_dpo_lock, + .dv_unlock = lb_dpo_unlock, + .dv_format = format_lb_dpo, + }; + + lbm->vips = 0; + lbm->per_cpu = 0; + vec_validate(lbm->per_cpu, tm->n_vlib_mains - 1); + lbm->writer_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES); + lbm->writer_lock[0] = 0; + lbm->per_cpu_sticky_buckets = LB_DEFAULT_PER_CPU_STICKY_BUCKETS; + lbm->flow_timeout = LB_DEFAULT_FLOW_TIMEOUT; + lbm->ip4_src_address.as_u32 = 0xffffffff; + lbm->ip6_src_address.as_u64[0] = 0xffffffffffffffffL; + lbm->ip6_src_address.as_u64[1] = 0xffffffffffffffffL; + lbm->dpo_gre4_type = dpo_register_new_type(&lb_vft, lb_dpo_gre4_nodes); + lbm->dpo_gre6_type = dpo_register_new_type(&lb_vft, lb_dpo_gre6_nodes); + lbm->fib_node_type = fib_node_register_new_type(&lb_fib_node_vft); + + //Init AS reference counters + vlib_refcount_init(&lbm->as_refcount); + + //Allocate and init default AS. + lbm->ass = 0; + pool_get(lbm->ass, default_as); + default_as->flags = 0; + default_as->dpo.dpoi_next_node = LB_NEXT_DROP; + default_as->vip_index = ~0; + default_as->address.ip6.as_u64[0] = 0xffffffffffffffffL; + default_as->address.ip6.as_u64[1] = 0xffffffffffffffffL; + +#define _(a,b,c) lbm->vip_counters[c].name = b; + lb_foreach_vip_counter +#undef _ + return NULL; +} + +VLIB_INIT_FUNCTION (lb_init); diff --git a/src/plugins/lb/lb.h b/src/plugins/lb/lb.h new file mode 100644 index 00000000..882b9b30 --- /dev/null +++ b/src/plugins/lb/lb.h @@ -0,0 +1,333 @@ +/* + * 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. + */ + +/** + * lb-plugin implements a MagLev-like load balancer. + * http://research.google.com/pubs/pub44824.html + * + * It hasn't been tested for interoperability with the original MagLev + * but intends to provide similar functionality. + * The load-balancer receives traffic destined to VIP (Virtual IP) + * addresses from one or multiple(ECMP) routers. + * The load-balancer tunnels the traffic toward many application servers + * ensuring session stickyness (i.e. that a single sessions is tunneled + * towards a single application server). + * + */ + +#ifndef LB_PLUGIN_LB_LB_H_ +#define LB_PLUGIN_LB_LB_H_ + +#include +#include + +#include +#include +#include +#include + +#include + +#define LB_DEFAULT_PER_CPU_STICKY_BUCKETS 1 << 10 +#define LB_DEFAULT_FLOW_TIMEOUT 40 + +typedef enum { + LB_NEXT_DROP, + LB_N_NEXT, +} lb_next_t; + +/** + * Each VIP is configured with a set of + * application server. + */ +typedef struct { + /** + * Registration to FIB event. + */ + fib_node_t fib_node; + + /** + * Destination address used to tunnel traffic towards + * that application server. + * The address is also used as ID and pseudo-random + * seed for the load-balancing process. + */ + ip46_address_t address; + + /** + * ASs are indexed by address and VIP Index. + * Which means there will be duplicated if the same server + * address is used for multiple VIPs. + */ + u32 vip_index; + + /** + * Some per-AS flags. + * For now only LB_AS_FLAGS_USED is defined. + */ + u8 flags; + +#define LB_AS_FLAGS_USED 0x1 + + /** + * Rotating timestamp of when LB_AS_FLAGS_USED flag was last set. + * + * AS removal is based on garbage collection and reference counting. + * When an AS is removed, there is a race between configuration core + * and worker cores which may still add a reference while it should not + * be used. This timestamp is used to not remove the AS while a race condition + * may happen. + */ + u32 last_used; + + /** + * The FIB entry index for the next-hop + */ + fib_node_index_t next_hop_fib_entry_index; + + /** + * The child index on the FIB entry + */ + u32 next_hop_child_index; + + /** + * The next DPO in the graph to follow. + */ + dpo_id_t dpo; + +} lb_as_t; + +format_function_t format_lb_as; + +typedef struct { + u32 as_index; +} lb_new_flow_entry_t; + +#define lb_foreach_vip_counter \ + _(NEXT_PACKET, "packet from existing sessions", 0) \ + _(FIRST_PACKET, "first session packet", 1) \ + _(UNTRACKED_PACKET, "untracked packet", 2) \ + _(NO_SERVER, "no server configured", 3) + +typedef enum { +#define _(a,b,c) LB_VIP_COUNTER_##a = c, + lb_foreach_vip_counter +#undef _ + LB_N_VIP_COUNTERS +} lb_vip_counter_t; + +/** + * The load balancer supports IPv4 and IPv6 traffic + * and GRE4 and GRE6 encap. + */ +typedef enum { + LB_VIP_TYPE_IP6_GRE6, + LB_VIP_TYPE_IP6_GRE4, + LB_VIP_TYPE_IP4_GRE6, + LB_VIP_TYPE_IP4_GRE4, + LB_VIP_N_TYPES, +} lb_vip_type_t; + +format_function_t format_lb_vip_type; +unformat_function_t unformat_lb_vip_type; + +/** + * Load balancing service is provided per VIP. + * In this data model, a VIP can be a whole prefix. + * But load balancing only + * occurs on a per-source-address/port basis. Meaning that if a given source + * reuses the same port for multiple destinations within the same VIP, + * they will be considered as a single flow. + */ +typedef struct { + + //Runtime + + /** + * Vector mapping (flow-hash & new_connect_table_mask) to AS index. + * This is used for new flows. + */ + lb_new_flow_entry_t *new_flow_table; + + /** + * New flows table length - 1 + * (length MUST be a power of 2) + */ + u32 new_flow_table_mask; + + /** + * Last time garbage collection was run to free the ASs. + */ + u32 last_garbage_collection; + + //Not runtime + + /** + * A Virtual IP represents a given service delivered + * by a set of application servers. It can be a single + * address or a prefix. + * IPv4 prefixes are encoded using IPv4-in-IPv6 embedded address + * (i.e. ::/96 prefix). + */ + ip46_address_t prefix; + + /** + * The VIP prefix length. + * In case of IPv4, plen = 96 + ip4_plen. + */ + u8 plen; + + /** + * The type of traffic for this. + * LB_TYPE_UNDEFINED if unknown. + */ + lb_vip_type_t type; + + /** + * Flags related to this VIP. + * LB_VIP_FLAGS_USED means the VIP is active. + * When it is not set, the VIP in the process of being removed. + * We cannot immediately remove a VIP because the VIP index still may be stored + * in the adjacency index. + */ + u8 flags; +#define LB_VIP_FLAGS_USED 0x1 + + /** + * Pool of AS indexes used for this VIP. + * This also includes ASs that have been removed (but are still referenced). + */ + u32 *as_indexes; +} lb_vip_t; + +#define lb_vip_is_ip4(vip) ((vip)->type == LB_VIP_TYPE_IP4_GRE6 || (vip)->type == LB_VIP_TYPE_IP4_GRE4) +#define lb_vip_is_gre4(vip) ((vip)->type == LB_VIP_TYPE_IP6_GRE4 || (vip)->type == LB_VIP_TYPE_IP4_GRE4) +format_function_t format_lb_vip; +format_function_t format_lb_vip_detailed; + +typedef struct { + /** + * Each CPU has its own sticky flow hash table. + * One single table is used for all VIPs. + */ + lb_hash_t *sticky_ht; +} lb_per_cpu_t; + +typedef struct { + /** + * Pool of all Virtual IPs + */ + lb_vip_t *vips; + + /** + * Pool of ASs. + * ASs are referenced by address and vip index. + * The first element (index 0) is special and used only to fill + * new_flow_tables when no AS has been configured. + */ + lb_as_t *ass; + + /** + * Each AS has an associated reference counter. + * As ass[0] has a special meaning, its associated counter + * starts at 0 and is decremented instead. i.e. do not use it. + */ + vlib_refcount_t as_refcount; + + /** + * Some global data is per-cpu + */ + lb_per_cpu_t *per_cpu; + + /** + * Node next index for IP adjacencies, for each of the traffic types. + */ + u32 ip_lookup_next_index[LB_VIP_N_TYPES]; + + /** + * Source address used in IPv6 encapsulated traffic + */ + ip6_address_t ip6_src_address; + + /** + * Source address used for IPv4 encapsulated traffic + */ + ip4_address_t ip4_src_address; + + /** + * Number of buckets in the per-cpu sticky hash table. + */ + u32 per_cpu_sticky_buckets; + + /** + * Flow timeout in seconds. + */ + u32 flow_timeout; + + /** + * Per VIP counter + */ + vlib_simple_counter_main_t vip_counters[LB_N_VIP_COUNTERS]; + + /** + * DPO used to send packet from IP4/6 lookup to LB node. + */ + dpo_type_t dpo_gre4_type; + dpo_type_t dpo_gre6_type; + + /** + * Node type for registering to fib changes. + */ + fib_node_type_t fib_node_type; + + /** + * API dynamically registered base ID. + */ + u16 msg_id_base; + + volatile u32 *writer_lock; +} lb_main_t; + +extern lb_main_t lb_main; +extern vlib_node_registration_t lb6_node; +extern vlib_node_registration_t lb4_node; + +/** + * Fix global load-balancer parameters. + * @param ip4_address IPv4 source address used for encapsulated traffic + * @param ip6_address IPv6 source address used for encapsulated traffic + * @return 0 on success. VNET_LB_ERR_XXX on error + */ +int lb_conf(ip4_address_t *ip4_address, ip6_address_t *ip6_address, + u32 sticky_buckets, u32 flow_timeout); + +int lb_vip_add(ip46_address_t *prefix, u8 plen, lb_vip_type_t type, + u32 new_length, u32 *vip_index); +int lb_vip_del(u32 vip_index); + +int lb_vip_find_index(ip46_address_t *prefix, u8 plen, u32 *vip_index); + +#define lb_vip_get_by_index(index) (pool_is_free_index(lb_main.vips, index)?NULL:pool_elt_at_index(lb_main.vips, index)) + +int lb_vip_add_ass(u32 vip_index, ip46_address_t *addresses, u32 n); +int lb_vip_del_ass(u32 vip_index, ip46_address_t *addresses, u32 n); + +u32 lb_hash_time_now(vlib_main_t * vm); + +void lb_garbage_collection(); + +format_function_t format_lb_main; + +#endif /* LB_PLUGIN_LB_LB_H_ */ diff --git a/src/plugins/lb/lb_plugin_doc.md b/src/plugins/lb/lb_plugin_doc.md new file mode 100644 index 00000000..c7885ffb --- /dev/null +++ b/src/plugins/lb/lb_plugin_doc.md @@ -0,0 +1,141 @@ +# Load Balancer plugin for VPP {#lb_plugin_doc} + +## Version + +The load balancer plugin is currently in *beta* version. +Both CLIs and APIs are subject to *heavy* changes. +Wich also means feedback is really welcome regarding features, apis, etc... + +## Overview + +This plugin provides load balancing for VPP in a way that is largely inspired +from Google's MagLev: http://research.google.com/pubs/pub44824.html + +The load balancer is configured with a set of Virtual IPs (VIP, which can be +prefixes), and for each VIP, with a set of Application Server addresses (ASs). + +Traffic received for a given VIP (or VIP prefix) is tunneled using GRE towards +the different ASs in a way that (tries to) ensure that a given session will +always be tunneled to the same AS. + +Both VIPs or ASs can be IPv4 or IPv6, but for a given VIP, all ASs must be using +the same encap. type (i.e. IPv4+GRE or IPv6+GRE). Meaning that for a given VIP, +all AS addresses must be of the same family. + +## Performances + +The load balancer has been tested up to 1 millions flows and still forwards more +than 3Mpps per core in such circumstances. +Although 3Mpps seems already good, it is likely that performances will be improved +in next versions. + +## Configuration + +### Global LB parameters + +The load balancer needs to be configured with some parameters: + + lb conf [ip4-src-address ] [ip6-src-address ] + [buckets ] [timeout ] + +ip4-src-address: the source address used to send encap. packets using IPv4. + +ip6-src-address: the source address used to send encap. packets using IPv6. + +buckets: the *per-thread* established-connexions-table number of buckets. + +timeout: the number of seconds a connection will remain in the + established-connexions-table while no packet for this flow + is received. + + +### Configure the VIPs + + lb vip [encap (gre6|gre4)] [new_len ] [del] + +new_len is the size of the new-connection-table. It should be 1 or 2 orders of +magnitude bigger than the number of ASs for the VIP in order to ensure a good +load balancing. + +Examples: + + lb vip 2002::/16 encap gre6 new_len 1024 + lb vip 2003::/16 encap gre4 new_len 2048 + lb vip 80.0.0.0/8 encap gre6 new_len 16 + lb vip 90.0.0.0/8 encap gre4 new_len 1024 + +### Configure the ASs (for each VIP) + + lb as [
[
[...]]] [del] + +You can add (or delete) as many ASs at a time (for a single VIP). +Note that the AS address family must correspond to the VIP encap. IP family. + +Examples: + + lb as 2002::/16 2001::2 2001::3 2001::4 + lb as 2003::/16 10.0.0.1 10.0.0.2 + lb as 80.0.0.0/8 2001::2 + lb as 90.0.0.0/8 10.0.0.1 + + + +## Monitoring + +The plugin provides quite a bunch of counters and information. +These are still subject to quite significant changes. + + show lb + show lb vip + show lb vip verbose + + show node counters + + +## Design notes + +### Multi-Threading + +MagLev is a distributed system which pseudo-randomly generates a +new-connections-table based on AS names such that each server configured with +the same set of ASs ends up with the same table. Connection stickyness is then +ensured with an established-connections-table. Using ECMP, it is assumed (but +not relied on) that servers will mostly receive traffic for different flows. + +This implementation pushes the parallelism a little bit further by using +one established-connections table per thread. This is equivalent to assuming +that RSS will make a job similar to ECMP, and is pretty useful as threads don't +need to get a lock in order to write in the table. + +### Hash Table + +A load balancer requires an efficient read and write hash table. The hash table +used by ip6-forward is very read-efficient, but not so much for writing. In +addition, it is not a big deal if writing into the hash table fails (again, +MagLev uses a flow table but does not heaviliy relies on it). + +The plugin therefore uses a very specific (and stupid) hash table. + - Fixed (and power of 2) number of buckets (configured at runtime) + - Fixed (and power of 2) elements per buckets (configured at compilation time) + +### Reference counting + +When an AS is removed, there is two possible ways to react. + - Keep using the AS for established connections + - Change AS for established connections (likely to cause error for TCP) + +In the first case, although an AS is removed from the configuration, its +associated state needs to stay around as long as it is used by at least one +thread. + +In order to avoid locks, a specific reference counter is used. The design is quite +similar to clib counters but: + - It is possible to decrease the value + - Summing will not zero the per-thread counters + - Only the thread can reallocate its own counters vector (to avoid concurrency issues) + +This reference counter is lock free, but reading a count of 0 does not mean +the value can be freed unless it is ensured by *other* means that no other thread +is concurrently referencing the object. In the case of this plugin, it is assumed +that no concurrent event will take place after a few seconds. + diff --git a/src/plugins/lb/lb_test.c b/src/plugins/lb/lb_test.c new file mode 100644 index 00000000..8c2eaa91 --- /dev/null +++ b/src/plugins/lb/lb_test.c @@ -0,0 +1,293 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include + +//TODO: Move that to vat/plugin_api.c +////////////////////////// +uword unformat_ip46_address (unformat_input_t * input, va_list * args) +{ + ip46_address_t *ip46 = va_arg (*args, ip46_address_t *); + ip46_type_t type = va_arg (*args, ip46_type_t); + if ((type != IP46_TYPE_IP6) && + unformat(input, "%U", unformat_ip4_address, &ip46->ip4)) { + ip46_address_mask_ip4(ip46); + return 1; + } else if ((type != IP46_TYPE_IP4) && + unformat(input, "%U", unformat_ip6_address, &ip46->ip6)) { + return 1; + } + return 0; +} +uword unformat_ip46_prefix (unformat_input_t * input, va_list * args) +{ + ip46_address_t *ip46 = va_arg (*args, ip46_address_t *); + u8 *len = va_arg (*args, u8 *); + ip46_type_t type = va_arg (*args, ip46_type_t); + + u32 l; + if ((type != IP46_TYPE_IP6) && unformat(input, "%U/%u", unformat_ip4_address, &ip46->ip4, &l)) { + if (l > 32) + return 0; + *len = l + 96; + ip46->pad[0] = ip46->pad[1] = ip46->pad[2] = 0; + } else if ((type != IP46_TYPE_IP4) && unformat(input, "%U/%u", unformat_ip6_address, &ip46->ip6, &l)) { + if (l > 128) + return 0; + *len = l; + } else { + return 0; + } + return 1; +} +///////////////////////// + +#define vl_msg_id(n,h) n, +typedef enum { +#include + /* We'll want to know how many messages IDs we need... */ + VL_MSG_FIRST_AVAILABLE, +} vl_msg_id_t; +#undef vl_msg_id + +/* define message structures */ +#define vl_typedefs +#include +#undef vl_typedefs + +/* declare message handlers for each api */ + +#define vl_endianfun /* define message structures */ +#include +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) +#define vl_printfun +#include +#undef vl_printfun + +/* Get the API version number. */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#undef vl_api_version + +typedef struct { + /* API message ID base */ + u16 msg_id_base; + vat_main_t *vat_main; +} lb_test_main_t; + +lb_test_main_t lb_test_main; + +#define foreach_standard_reply_retval_handler \ +_(lb_conf_reply) \ +_(lb_add_del_vip_reply) \ +_(lb_add_del_as_reply) + +#define _(n) \ + static void vl_api_##n##_t_handler \ + (vl_api_##n##_t * mp) \ + { \ + vat_main_t * vam = lb_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 \ + _(LB_CONF_REPLY, lb_conf_reply) \ + _(LB_ADD_DEL_VIP_REPLY, lb_add_del_vip_reply) \ + _(LB_ADD_DEL_AS_REPLY, lb_add_del_as_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)); \ + memcpy (mp, &mps, sizeof (*mp)); \ + mp->_vl_msg_id = ntohs (VL_API_##T + lbtm->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_lb_conf (vat_main_t * vam) +{ + lb_test_main_t *lbtm = &lb_test_main; + unformat_input_t *i = vam->input; + f64 timeout; + vl_api_lb_conf_t mps, *mp; + + if (!unformat(i, "%U %U %u %u", + unformat_ip4_address, &mps.ip4_src_address, + unformat_ip6_address, mps.ip6_src_address, + &mps.sticky_buckets_per_core, + &mps.flow_timeout)) { + errmsg ("invalid arguments\n"); + return -99; + } + + M(LB_CONF, lb_conf); S; W; + + /* NOTREACHED */ + return 0; +} + +static int api_lb_add_del_vip (vat_main_t * vam) +{ + lb_test_main_t *lbtm = &lb_test_main; + unformat_input_t * i = vam->input; + f64 timeout; + vl_api_lb_add_del_vip_t mps, *mp; + mps.is_del = 0; + mps.is_gre4 = 0; + + if (!unformat(i, "%U", + unformat_ip46_prefix, mps.ip_prefix, &mps.prefix_length, IP46_TYPE_ANY)) { + errmsg ("invalid prefix\n"); + return -99; + } + + if (unformat(i, "gre4")) { + mps.is_gre4 = 1; + } else if (unformat(i, "gre6")) { + mps.is_gre4 = 0; + } else { + errmsg ("no encap\n"); + return -99; + } + + if (!unformat(i, "%d", &mps.new_flows_table_length)) { + errmsg ("no table lentgh\n"); + return -99; + } + + if (unformat(i, "del")) { + mps.is_del = 1; + } + + M(LB_ADD_DEL_VIP, lb_add_del_vip); S; W; + /* NOTREACHED */ + return 0; +} + +static int api_lb_add_del_as (vat_main_t * vam) +{ + lb_test_main_t *lbtm = &lb_test_main; + unformat_input_t * i = vam->input; + f64 timeout; + vl_api_lb_add_del_as_t mps, *mp; + mps.is_del = 0; + + if (!unformat(i, "%U %U", + unformat_ip46_prefix, mps.vip_ip_prefix, &mps.vip_prefix_length, IP46_TYPE_ANY, + unformat_ip46_address, mps.as_address)) { + errmsg ("invalid prefix or address\n"); + return -99; + } + + if (unformat(i, "del")) { + mps.is_del = 1; + } + + M(LB_ADD_DEL_AS, lb_add_del_as); S; W; + /* NOTREACHED */ + return 0; +} + +/* + * List of messages that the api test plugin sends, + * and that the data plane plugin processes + */ +#define foreach_vpe_api_msg \ +_(lb_conf, " ") \ +_(lb_add_del_vip, " [gre4|gre6] [del]") \ +_(lb_add_del_as, "
[del]") + +void vat_api_hookup (vat_main_t *vam) +{ + lb_test_main_t * lbtm = &lb_test_main; + /* Hook up handlers for replies from the data plane plug-in */ +#define _(N,n) \ + vl_msg_api_set_handlers((VL_API_##N + lbtm->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) +{ + lb_test_main_t * lbtm = &lb_test_main; + + u8 * name; + + lbtm->vat_main = vam; + + /* Ask the vpp engine for the first assigned message-id */ + name = format (0, "lb_%08x%c", api_version, 0); + lbtm->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name); + + if (lbtm->msg_id_base != (u16) ~0) + vat_api_hookup (vam); + + vec_free(name); + + return 0; +} diff --git a/src/plugins/lb/lbhash.h b/src/plugins/lb/lbhash.h new file mode 100644 index 00000000..ca3cc143 --- /dev/null +++ b/src/plugins/lb/lbhash.h @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2012 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. + */ + +/** + * vppinfra already includes tons of different hash tables. + * MagLev flow table is a bit different. It has to be very efficient + * for both writing and reading operations. But it does not need to + * be 100% reliable (write can fail). It also needs to recycle + * old entries in a lazy way. + * + * This hash table is the most dummy hash table you can do. + * Fixed total size, fixed bucket size. + * Advantage is that it could be very efficient (maybe). + * + */ + +#ifndef LB_PLUGIN_LB_LBHASH_H_ +#define LB_PLUGIN_LB_LBHASH_H_ + +#include + +#if defined (__SSE4_2__) +#include +#endif + +/* + * @brief Number of entries per bucket. + */ +#define LBHASH_ENTRY_PER_BUCKET 4 + +#define LB_HASH_DO_NOT_USE_SSE_BUCKETS 0 + +/* + * @brief One bucket contains 4 entries. + * Each bucket takes one 64B cache line in memory. + */ +typedef struct { + CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); + u32 hash[LBHASH_ENTRY_PER_BUCKET]; + u32 timeout[LBHASH_ENTRY_PER_BUCKET]; + u32 vip[LBHASH_ENTRY_PER_BUCKET]; + u32 value[LBHASH_ENTRY_PER_BUCKET]; +} lb_hash_bucket_t; + +typedef struct { + u32 buckets_mask; + u32 timeout; + lb_hash_bucket_t buckets[]; +} lb_hash_t; + +#define lb_hash_nbuckets(h) (((h)->buckets_mask) + 1) +#define lb_hash_size(h) ((h)->buckets_mask + LBHASH_ENTRY_PER_BUCKET) + +#define lb_hash_foreach_bucket(h, bucket) \ + for (bucket = (h)->buckets; \ + bucket < (h)->buckets + lb_hash_nbuckets(h); \ + bucket++) + +#define lb_hash_foreach_entry(h, bucket, i) \ + lb_hash_foreach_bucket(h, bucket) \ + for (i = 0; i < LBHASH_ENTRY_PER_BUCKET; i++) + +#define lb_hash_foreach_valid_entry(h, bucket, i, now) \ + lb_hash_foreach_entry(h, bucket, i) \ + if (!clib_u32_loop_gt((now), bucket->timeout[i])) + +static_always_inline +lb_hash_t *lb_hash_alloc(u32 buckets, u32 timeout) +{ + if (!is_pow2(buckets)) + return NULL; + + // Allocate 1 more bucket for prefetch + u32 size = ((u64)&((lb_hash_t *)(0))->buckets[0]) + + sizeof(lb_hash_bucket_t) * (buckets + 1); + u8 *mem = 0; + lb_hash_t *h; + vec_alloc_aligned(mem, size, CLIB_CACHE_LINE_BYTES); + h = (lb_hash_t *)mem; + h->buckets_mask = (buckets - 1); + h->timeout = timeout; + return h; +} + +static_always_inline +void lb_hash_free(lb_hash_t *h) +{ + u8 *mem = (u8 *)h; + vec_free(mem); +} + +#if __SSE4_2__ +static_always_inline +u32 lb_hash_hash(u64 k0, u64 k1, u64 k2, u64 k3, u64 k4) +{ + u64 val = 0; + val = _mm_crc32_u64(val, k0); + val = _mm_crc32_u64(val, k1); + val = _mm_crc32_u64(val, k2); + val = _mm_crc32_u64(val, k3); + val = _mm_crc32_u64(val, k4); + return (u32) val; +} +#else +static_always_inline +u32 lb_hash_hash(u64 k0, u64 k1, u64 k2, u64 k3, u64 k4) +{ + u64 tmp = k0 ^ k1 ^ k2 ^ k3 ^ k4; + return (u32)clib_xxhash (tmp); +} +#endif + +static_always_inline +void lb_hash_prefetch_bucket(lb_hash_t *ht, u32 hash) +{ + lb_hash_bucket_t *bucket = &ht->buckets[hash & ht->buckets_mask]; + CLIB_PREFETCH(bucket, sizeof(*bucket), READ); +} + +static_always_inline +void lb_hash_get(lb_hash_t *ht, u32 hash, u32 vip, u32 time_now, + u32 *available_index, u32 *found_value) +{ + lb_hash_bucket_t *bucket = &ht->buckets[hash & ht->buckets_mask]; + *found_value = ~0; + *available_index = ~0; +#if __SSE4_2__ && LB_HASH_DO_NOT_USE_SSE_BUCKETS == 0 + u32 bitmask, found_index; + __m128i mask; + + // mask[*] = timeout[*] > now + mask = _mm_cmpgt_epi32(_mm_loadu_si128 ((__m128i *) bucket->timeout), + _mm_set1_epi32 (time_now)); + // bitmask[*] = now <= timeout[*/4] + bitmask = (~_mm_movemask_epi8(mask)) & 0xffff; + // Get first index with now <= timeout[*], if any. + *available_index = (bitmask)?__builtin_ctz(bitmask)/4:*available_index; + + // mask[*] = (timeout[*] > now) && (hash[*] == hash) + mask = _mm_and_si128(mask, + _mm_cmpeq_epi32( + _mm_loadu_si128 ((__m128i *) bucket->hash), + _mm_set1_epi32 (hash))); + + // Load the array of vip values + // mask[*] = (timeout[*] > now) && (hash[*] == hash) && (vip[*] == vip) + mask = _mm_and_si128(mask, + _mm_cmpeq_epi32( + _mm_loadu_si128 ((__m128i *) bucket->vip), + _mm_set1_epi32 (vip))); + + // mask[*] = (timeout[*x4] > now) && (hash[*x4] == hash) && (vip[*x4] == vip) + bitmask = _mm_movemask_epi8(mask); + // Get first index, if any + found_index = (bitmask)?__builtin_ctzll(bitmask)/4:0; + ASSERT(found_index < 4); + *found_value = (bitmask)?bucket->value[found_index]:*found_value; + bucket->timeout[found_index] = + (bitmask)?time_now + ht->timeout:bucket->timeout[found_index]; +#else + u32 i; + for (i = 0; i < LBHASH_ENTRY_PER_BUCKET; i++) { + u8 cmp = (bucket->hash[i] == hash && bucket->vip[i] == vip); + u8 timeouted = clib_u32_loop_gt(time_now, bucket->timeout[i]); + *found_value = (cmp || timeouted)?*found_value:bucket->value[i]; + bucket->timeout[i] = (cmp || timeouted)?time_now + ht->timeout:bucket->timeout[i]; + *available_index = (timeouted && (*available_index == ~0))?i:*available_index; + + if (!cmp) + return; + } +#endif +} + +static_always_inline +u32 lb_hash_available_value(lb_hash_t *h, u32 hash, u32 available_index) +{ + return h->buckets[hash & h->buckets_mask].value[available_index]; +} + +static_always_inline +void lb_hash_put(lb_hash_t *h, u32 hash, u32 value, u32 vip, + u32 available_index, u32 time_now) +{ + lb_hash_bucket_t *bucket = &h->buckets[hash & h->buckets_mask]; + bucket->hash[available_index] = hash; + bucket->value[available_index] = value; + bucket->timeout[available_index] = time_now + h->timeout; + bucket->vip[available_index] = vip; +} + +static_always_inline +u32 lb_hash_elts(lb_hash_t *h, u32 time_now) +{ + u32 tot = 0; + lb_hash_bucket_t *bucket; + u32 i; + lb_hash_foreach_valid_entry(h, bucket, i, time_now) { + tot++; + } + return tot; +} + +#endif /* LB_PLUGIN_LB_LBHASH_H_ */ diff --git a/src/plugins/lb/node.c b/src/plugins/lb/node.c new file mode 100644 index 00000000..8b763c53 --- /dev/null +++ b/src/plugins/lb/node.c @@ -0,0 +1,419 @@ +/* + * 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. + */ + +#include + +#include +#include + +#define foreach_lb_error \ + _(NONE, "no error") \ + _(PROTO_NOT_SUPPORTED, "protocol not supported") + +typedef enum { +#define _(sym,str) LB_ERROR_##sym, + foreach_lb_error +#undef _ + LB_N_ERROR, +} lb_error_t; + +static char *lb_error_strings[] = { +#define _(sym,string) string, + foreach_lb_error +#undef _ +}; + +typedef struct { + u32 vip_index; + u32 as_index; +} lb_trace_t; + +u8 * +format_lb_trace (u8 * s, va_list * args) +{ + lb_main_t *lbm = &lb_main; + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + lb_trace_t *t = va_arg (*args, lb_trace_t *); + if (pool_is_free_index(lbm->vips, t->vip_index)) { + s = format(s, "lb vip[%d]: This VIP was freed since capture\n"); + } else { + s = format(s, "lb vip[%d]: %U\n", t->vip_index, format_lb_vip, &lbm->vips[t->vip_index]); + } + if (pool_is_free_index(lbm->ass, t->as_index)) { + s = format(s, "lb as[%d]: This AS was freed since capture\n"); + } else { + s = format(s, "lb as[%d]: %U\n", t->as_index, format_lb_as, &lbm->ass[t->as_index]); + } + return s; +} + +lb_hash_t *lb_get_sticky_table(u32 cpu_index) +{ + lb_main_t *lbm = &lb_main; + lb_hash_t *sticky_ht = lbm->per_cpu[cpu_index].sticky_ht; + //Check if size changed + if (PREDICT_FALSE(sticky_ht && (lbm->per_cpu_sticky_buckets != lb_hash_nbuckets(sticky_ht)))) + { + //Dereference everything in there + lb_hash_bucket_t *b; + u32 i; + lb_hash_foreach_entry(sticky_ht, b, i) { + vlib_refcount_add(&lbm->as_refcount, cpu_index, b->value[i], -1); + vlib_refcount_add(&lbm->as_refcount, cpu_index, 0, 1); + } + + lb_hash_free(sticky_ht); + sticky_ht = NULL; + } + + //Create if necessary + if (PREDICT_FALSE(sticky_ht == NULL)) { + lbm->per_cpu[cpu_index].sticky_ht = lb_hash_alloc(lbm->per_cpu_sticky_buckets, lbm->flow_timeout); + sticky_ht = lbm->per_cpu[cpu_index].sticky_ht; + clib_warning("Regenerated sticky table %p", sticky_ht); + } + + ASSERT(sticky_ht); + + //Update timeout + sticky_ht->timeout = lbm->flow_timeout; + return sticky_ht; +} + +u64 +lb_node_get_other_ports4(ip4_header_t *ip40) +{ + return 0; +} + +u64 +lb_node_get_other_ports6(ip6_header_t *ip60) +{ + return 0; +} + +static_always_inline u32 +lb_node_get_hash(vlib_buffer_t *p, u8 is_input_v4) +{ + u32 hash; + if (is_input_v4) + { + ip4_header_t *ip40; + u64 ports; + ip40 = vlib_buffer_get_current (p); + if (PREDICT_TRUE (ip40->protocol == IP_PROTOCOL_TCP || + ip40->protocol == IP_PROTOCOL_UDP)) + ports = ((u64)((udp_header_t *)(ip40 + 1))->src_port << 16) | + ((u64)((udp_header_t *)(ip40 + 1))->dst_port); + else + ports = lb_node_get_other_ports4(ip40); + + hash = lb_hash_hash(*((u64 *)&ip40->address_pair), ports, + 0, 0, 0); + } + else + { + ip6_header_t *ip60; + ip60 = vlib_buffer_get_current (p); + u64 ports; + if (PREDICT_TRUE (ip60->protocol == IP_PROTOCOL_TCP || + ip60->protocol == IP_PROTOCOL_UDP)) + ports = ((u64)((udp_header_t *)(ip60 + 1))->src_port << 16) | + ((u64)((udp_header_t *)(ip60 + 1))->dst_port); + else + ports = lb_node_get_other_ports6(ip60); + + hash = lb_hash_hash(ip60->src_address.as_u64[0], + ip60->src_address.as_u64[1], + ip60->dst_address.as_u64[0], + ip60->dst_address.as_u64[1], + ports); + } + return hash; +} + +static_always_inline uword +lb_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame, + u8 is_input_v4, //Compile-time parameter stating that is input is v4 (or v6) + u8 is_encap_v4) //Compile-time parameter stating that is GRE encap is v4 (or v6) +{ + lb_main_t *lbm = &lb_main; + u32 n_left_from, *from, next_index, *to_next, n_left_to_next; + u32 cpu_index = os_get_cpu_number(); + u32 lb_time = lb_hash_time_now(vm); + + lb_hash_t *sticky_ht = lb_get_sticky_table(cpu_index); + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + u32 nexthash0 = 0; + if (PREDICT_TRUE(n_left_from > 0)) + nexthash0 = lb_node_get_hash(vlib_get_buffer (vm, from[0]), is_input_v4); + + while (n_left_from > 0) + { + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 pi0; + vlib_buffer_t *p0; + lb_vip_t *vip0; + u32 asindex0; + u16 len0; + u32 available_index0; + u8 counter = 0; + u32 hash0 = nexthash0; + + if (PREDICT_TRUE(n_left_from > 1)) + { + vlib_buffer_t *p1 = vlib_get_buffer (vm, from[1]); + //Compute next hash and prefetch bucket + nexthash0 = lb_node_get_hash(p1, is_input_v4); + lb_hash_prefetch_bucket(sticky_ht, nexthash0); + //Prefetch for encap, next + CLIB_PREFETCH (vlib_buffer_get_current(p1) - 64, 64, STORE); + } + + if (PREDICT_TRUE(n_left_from > 2)) + { + vlib_buffer_t *p2; + p2 = vlib_get_buffer(vm, from[2]); + /* prefetch packet header and data */ + vlib_prefetch_buffer_header(p2, STORE); + CLIB_PREFETCH (vlib_buffer_get_current(p2), 64, STORE); + } + + pi0 = to_next[0] = from[0]; + from += 1; + n_left_from -= 1; + to_next += 1; + n_left_to_next -= 1; + + p0 = vlib_get_buffer (vm, pi0); + vip0 = pool_elt_at_index (lbm->vips, + vnet_buffer (p0)->ip.adj_index[VLIB_TX]); + + if (is_input_v4) + { + ip4_header_t *ip40; + ip40 = vlib_buffer_get_current (p0); + len0 = clib_net_to_host_u16(ip40->length); + } + else + { + ip6_header_t *ip60; + ip60 = vlib_buffer_get_current (p0); + len0 = clib_net_to_host_u16(ip60->payload_length) + sizeof(ip6_header_t); + } + + lb_hash_get(sticky_ht, hash0, vnet_buffer (p0)->ip.adj_index[VLIB_TX], + lb_time, &available_index0, &asindex0); + + if (PREDICT_TRUE(asindex0 != ~0)) + { + //Found an existing entry + counter = LB_VIP_COUNTER_NEXT_PACKET; + } + else if (PREDICT_TRUE(available_index0 != ~0)) + { + //There is an available slot for a new flow + asindex0 = vip0->new_flow_table[hash0 & vip0->new_flow_table_mask].as_index; + counter = LB_VIP_COUNTER_FIRST_PACKET; + counter = (asindex0 == 0)?LB_VIP_COUNTER_NO_SERVER:counter; + + //TODO: There are race conditions with as0 and vip0 manipulation. + //Configuration may be changed, vectors resized, etc... + + //Dereference previously used + vlib_refcount_add(&lbm->as_refcount, cpu_index, + lb_hash_available_value(sticky_ht, hash0, available_index0), -1); + vlib_refcount_add(&lbm->as_refcount, cpu_index, + asindex0, 1); + + //Add sticky entry + //Note that when there is no AS configured, an entry is configured anyway. + //But no configured AS is not something that should happen + lb_hash_put(sticky_ht, hash0, asindex0, + vnet_buffer (p0)->ip.adj_index[VLIB_TX], + available_index0, lb_time); + } + else + { + //Could not store new entry in the table + asindex0 = vip0->new_flow_table[hash0 & vip0->new_flow_table_mask].as_index; + counter = LB_VIP_COUNTER_UNTRACKED_PACKET; + } + + vlib_increment_simple_counter(&lbm->vip_counters[counter], + cpu_index, + vnet_buffer (p0)->ip.adj_index[VLIB_TX], + 1); + + //Now let's encap + { + gre_header_t *gre0; + if (is_encap_v4) + { + ip4_header_t *ip40; + vlib_buffer_advance(p0, - sizeof(ip4_header_t) - sizeof(gre_header_t)); + ip40 = vlib_buffer_get_current(p0); + gre0 = (gre_header_t *)(ip40 + 1); + ip40->src_address = lbm->ip4_src_address; + ip40->dst_address = lbm->ass[asindex0].address.ip4; + ip40->ip_version_and_header_length = 0x45; + ip40->ttl = 128; + ip40->length = clib_host_to_net_u16(len0 + sizeof(gre_header_t) + sizeof(ip4_header_t)); + ip40->protocol = IP_PROTOCOL_GRE; + ip40->checksum = ip4_header_checksum (ip40); + } + else + { + ip6_header_t *ip60; + vlib_buffer_advance(p0, - sizeof(ip6_header_t) - sizeof(gre_header_t)); + ip60 = vlib_buffer_get_current(p0); + gre0 = (gre_header_t *)(ip60 + 1); + ip60->dst_address = lbm->ass[asindex0].address.ip6; + ip60->src_address = lbm->ip6_src_address; + ip60->hop_limit = 128; + ip60->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (0x6<<28); + ip60->payload_length = clib_host_to_net_u16(len0 + sizeof(gre_header_t)); + ip60->protocol = IP_PROTOCOL_GRE; + } + + gre0->flags_and_version = 0; + gre0->protocol = (is_input_v4)? + clib_host_to_net_u16(0x0800): + clib_host_to_net_u16(0x86DD); + } + + if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) + { + lb_trace_t *tr = vlib_add_trace (vm, node, p0, sizeof (*tr)); + tr->as_index = asindex0; + tr->vip_index = vnet_buffer (p0)->ip.adj_index[VLIB_TX]; + } + + //Enqueue to next + //Note that this is going to error if asindex0 == 0 + vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbm->ass[asindex0].dpo.dpoi_index; + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, + n_left_to_next, pi0, + lbm->ass[asindex0].dpo.dpoi_next_node); + } + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + +static uword +lb6_gre6_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + return lb_node_fn(vm, node, frame, 0, 0); +} + +static uword +lb6_gre4_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + return lb_node_fn(vm, node, frame, 0, 1); +} + +static uword +lb4_gre6_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + return lb_node_fn(vm, node, frame, 1, 0); +} + +static uword +lb4_gre4_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + return lb_node_fn(vm, node, frame, 1, 1); +} + +VLIB_REGISTER_NODE (lb6_gre6_node) = +{ + .function = lb6_gre6_node_fn, + .name = "lb6-gre6", + .vector_size = sizeof (u32), + .format_trace = format_lb_trace, + + .n_errors = LB_N_ERROR, + .error_strings = lb_error_strings, + + .n_next_nodes = LB_N_NEXT, + .next_nodes = + { + [LB_NEXT_DROP] = "error-drop" + }, +}; + +VLIB_REGISTER_NODE (lb6_gre4_node) = +{ + .function = lb6_gre4_node_fn, + .name = "lb6-gre4", + .vector_size = sizeof (u32), + .format_trace = format_lb_trace, + + .n_errors = LB_N_ERROR, + .error_strings = lb_error_strings, + + .n_next_nodes = LB_N_NEXT, + .next_nodes = + { + [LB_NEXT_DROP] = "error-drop" + }, +}; + +VLIB_REGISTER_NODE (lb4_gre6_node) = +{ + .function = lb4_gre6_node_fn, + .name = "lb4-gre6", + .vector_size = sizeof (u32), + .format_trace = format_lb_trace, + + .n_errors = LB_N_ERROR, + .error_strings = lb_error_strings, + + .n_next_nodes = LB_N_NEXT, + .next_nodes = + { + [LB_NEXT_DROP] = "error-drop" + }, +}; + +VLIB_REGISTER_NODE (lb4_gre4_node) = +{ + .function = lb4_gre4_node_fn, + .name = "lb4-gre4", + .vector_size = sizeof (u32), + .format_trace = format_lb_trace, + + .n_errors = LB_N_ERROR, + .error_strings = lb_error_strings, + + .n_next_nodes = LB_N_NEXT, + .next_nodes = + { + [LB_NEXT_DROP] = "error-drop" + }, +}; + diff --git a/src/plugins/lb/refcount.c b/src/plugins/lb/refcount.c new file mode 100644 index 00000000..22415c88 --- /dev/null +++ b/src/plugins/lb/refcount.c @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#include + +void __vlib_refcount_resize(vlib_refcount_per_cpu_t *per_cpu, u32 size) +{ + u32 *new_counter = 0, *old_counter; + vec_validate(new_counter, size); + memcpy(new_counter, per_cpu->counters, per_cpu->length); + old_counter = per_cpu->counters; + per_cpu->counters = new_counter; + CLIB_MEMORY_BARRIER(); + per_cpu->length = vec_len(new_counter); + vec_free(old_counter); +} + +u64 vlib_refcount_get(vlib_refcount_t *r, u32 index) +{ + u64 count = 0; + vlib_thread_main_t *tm = vlib_get_thread_main (); + u32 cpu_index; + for (cpu_index = 0; cpu_index < tm->n_vlib_mains; cpu_index++) { + if (r->per_cpu[cpu_index].length > index) + count += r->per_cpu[cpu_index].counters[index]; + } + return count; +} + diff --git a/src/plugins/lb/refcount.h b/src/plugins/lb/refcount.h new file mode 100644 index 00000000..8c26e7be --- /dev/null +++ b/src/plugins/lb/refcount.h @@ -0,0 +1,67 @@ +/* + * 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. + */ + +/* + * vlib provides lock-free counters but those + * - Have 16bits per-CPU counter, which may overflow. + * - Would only increment. + * + * This is very similar to vlib counters, but may be used to count reference. + * Such a counter includes an arbitrary number of counters. Each counter + * is identified by its index. This is used to aggregate per-cpu memory. + * + * Warning: + * This reference counter is lock-free but is not race-condition free. + * The counting result is approximate and another mechanism needs to be used + * in order to ensure that an object may be freed. + * + */ + +#include + +typedef struct { + u32 *counters; + u32 length; + u32 *reader_lengths; + CLIB_CACHE_LINE_ALIGN_MARK(o); +} vlib_refcount_per_cpu_t; + +typedef struct { + vlib_refcount_per_cpu_t *per_cpu; +} vlib_refcount_t; + +void __vlib_refcount_resize(vlib_refcount_per_cpu_t *per_cpu, u32 size); + +static_always_inline +void vlib_refcount_add(vlib_refcount_t *r, u32 cpu_index, u32 counter_index, i32 v) +{ + vlib_refcount_per_cpu_t *per_cpu = &r->per_cpu[cpu_index]; + if (PREDICT_FALSE(counter_index >= per_cpu->length)) + __vlib_refcount_resize(per_cpu, clib_max(counter_index + 16, per_cpu->length * 2)); + + per_cpu->counters[counter_index] += v; +} + +u64 vlib_refcount_get(vlib_refcount_t *r, u32 index); + +static_always_inline +void vlib_refcount_init(vlib_refcount_t *r) +{ + vlib_thread_main_t *tm = vlib_get_thread_main (); + r->per_cpu = 0; + vec_validate (r->per_cpu, tm->n_vlib_mains - 1); +} + + diff --git a/src/plugins/lb/util.c b/src/plugins/lb/util.c new file mode 100644 index 00000000..d969d168 --- /dev/null +++ b/src/plugins/lb/util.c @@ -0,0 +1,72 @@ +/* + * 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. + */ + +#include + +void ip46_prefix_normalize(ip46_address_t *prefix, u8 plen) +{ + if (plen == 0) { + prefix->as_u64[0] = 0; + prefix->as_u64[1] = 0; + } else if (plen <= 64) { + prefix->as_u64[0] &= clib_host_to_net_u64(0xffffffffffffffffL << (64 - plen)); + prefix->as_u64[1] = 0; + } else { + prefix->as_u64[1] &= clib_host_to_net_u64(0xffffffffffffffffL << (128 - plen)); + } + +} + +uword unformat_ip46_prefix (unformat_input_t * input, va_list * args) +{ + ip46_address_t *ip46 = va_arg (*args, ip46_address_t *); + u8 *len = va_arg (*args, u8 *); + ip46_type_t type = va_arg (*args, ip46_type_t); + + u32 l; + if ((type != IP46_TYPE_IP6) && unformat(input, "%U/%u", unformat_ip4_address, &ip46->ip4, &l)) { + if (l > 32) + return 0; + *len = l + 96; + ip46->pad[0] = ip46->pad[1] = ip46->pad[2] = 0; + } else if ((type != IP46_TYPE_IP4) && unformat(input, "%U/%u", unformat_ip6_address, &ip46->ip6, &l)) { + if (l > 128) + return 0; + *len = l; + } else { + return 0; + } + return 1; +} + +u8 *format_ip46_prefix (u8 * s, va_list * args) +{ + ip46_address_t *ip46 = va_arg (*args, ip46_address_t *); + u32 len = va_arg (*args, u32); //va_arg cannot use u8 or u16 + ip46_type_t type = va_arg (*args, ip46_type_t); + + int is_ip4 = 0; + if (type == IP46_TYPE_IP4) + is_ip4 = 1; + else if (type == IP46_TYPE_IP6) + is_ip4 = 0; + else + is_ip4 = (len >= 96) && ip46_address_is_ip4(ip46); + + return is_ip4 ? + format(s, "%U/%d", format_ip4_address, &ip46->ip4, len - 96): + format(s, "%U/%d", format_ip6_address, &ip46->ip6, len); +} + diff --git a/src/plugins/lb/util.h b/src/plugins/lb/util.h new file mode 100644 index 00000000..3f082310 --- /dev/null +++ b/src/plugins/lb/util.h @@ -0,0 +1,40 @@ +/* + * 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. + */ + +/* + * Non-LB specific stuff comes here + */ + +#ifndef LB_PLUGIN_LB_UTIL_H_ +#define LB_PLUGIN_LB_UTIL_H_ + +#include +#include + +#define ip46_address_type(ip46) (ip46_address_is_ip4(ip46)?IP46_TYPE_IP4:IP46_TYPE_IP6) +#define ip46_prefix_is_ip4(ip46, len) ((len) >= 96 && ip46_address_is_ip4(ip46)) +#define ip46_prefix_type(ip46, len) (ip46_prefix_is_ip4(ip46, len)?IP46_TYPE_IP4:IP46_TYPE_IP6) + +void ip46_prefix_normalize(ip46_address_t *prefix, u8 plen); +uword unformat_ip46_prefix (unformat_input_t * input, va_list * args); +u8 *format_ip46_prefix (u8 * s, va_list * args); + +/** + * 32 bits integer comparison for running values. + * 1 > 0 is true. But 1 > 0xffffffff also is. + */ +#define clib_u32_loop_gt(a, b) (((u32)(a)) - ((u32)(b)) < 0x7fffffff) + +#endif /* LB_PLUGIN_LB_UTIL_H_ */ diff --git a/src/plugins/snat.am b/src/plugins/snat.am new file mode 100644 index 00000000..7ff2386e --- /dev/null +++ b/src/plugins/snat.am @@ -0,0 +1,33 @@ + +# Copyright (c) +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +vppapitestplugins_LTLIBRARIES += snat_test_plugin.la +vppplugins_LTLIBRARIES += snat_plugin.la + +snat_plugin_la_SOURCES = snat/snat.c \ + snat/in2out.c \ + snat/out2in.c \ + snat/snat_plugin.api.h + +API_FILES += snat/snat.api + +nobase_apiinclude_HEADERS += \ + snat/snat_all_api_h.h \ + snat/snat_msg_enum.h \ + snat/snat.api.h + +snat_test_plugin_la_SOURCES = \ + snat/snat_test.c snat/snat_plugin.api.h + +# vi:syntax=automake diff --git a/src/plugins/snat/in2out.c b/src/plugins/snat/in2out.c new file mode 100644 index 00000000..c78fdd76 --- /dev/null +++ b/src/plugins/snat/in2out.c @@ -0,0 +1,1597 @@ +/* + * 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. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +typedef struct { + u32 sw_if_index; + u32 next_index; + u32 session_index; + u32 is_slow_path; +} snat_in2out_trace_t; + +typedef struct { + u32 next_worker_index; + u8 do_handoff; +} snat_in2out_worker_handoff_trace_t; + +/* packet trace format function */ +static u8 * format_snat_in2out_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 *); + snat_in2out_trace_t * t = va_arg (*args, snat_in2out_trace_t *); + char * tag; + + tag = t->is_slow_path ? "SNAT_IN2OUT_SLOW_PATH" : "SNAT_IN2OUT_FAST_PATH"; + + s = format (s, "%s: sw_if_index %d, next index %d, session %d", tag, + t->sw_if_index, t->next_index, t->session_index); + + return s; +} + +static u8 * format_snat_in2out_fast_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 *); + snat_in2out_trace_t * t = va_arg (*args, snat_in2out_trace_t *); + + s = format (s, "SANT_IN2OUT_FAST: sw_if_index %d, next index %d", + t->sw_if_index, t->next_index); + + return s; +} + +static u8 * format_snat_in2out_worker_handoff_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 *); + snat_in2out_worker_handoff_trace_t * t = + va_arg (*args, snat_in2out_worker_handoff_trace_t *); + char * m; + + m = t->do_handoff ? "next worker" : "same worker"; + s = format (s, "SNAT_IN2OUT_WORKER_HANDOFF: %s %d", m, t->next_worker_index); + + return s; +} + +vlib_node_registration_t snat_in2out_node; +vlib_node_registration_t snat_in2out_slowpath_node; +vlib_node_registration_t snat_in2out_fast_node; +vlib_node_registration_t snat_in2out_worker_handoff_node; + +#define foreach_snat_in2out_error \ +_(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \ +_(IN2OUT_PACKETS, "Good in2out packets processed") \ +_(OUT_OF_PORTS, "Out of ports") \ +_(BAD_OUTSIDE_FIB, "Outside VRF ID not found") \ +_(BAD_ICMP_TYPE, "icmp type not echo-request") \ +_(NO_TRANSLATION, "No translation") + +typedef enum { +#define _(sym,str) SNAT_IN2OUT_ERROR_##sym, + foreach_snat_in2out_error +#undef _ + SNAT_IN2OUT_N_ERROR, +} snat_in2out_error_t; + +static char * snat_in2out_error_strings[] = { +#define _(sym,string) string, + foreach_snat_in2out_error +#undef _ +}; + +typedef enum { + SNAT_IN2OUT_NEXT_LOOKUP, + SNAT_IN2OUT_NEXT_DROP, + SNAT_IN2OUT_NEXT_SLOW_PATH, + SNAT_IN2OUT_N_NEXT, +} snat_in2out_next_t; + +static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, + ip4_header_t * ip0, + u32 rx_fib_index0, + snat_session_key_t * key0, + snat_session_t ** sessionp, + vlib_node_runtime_t * node, + u32 next0, + u32 cpu_index) +{ + snat_user_t *u; + snat_user_key_t user_key; + snat_session_t *s; + clib_bihash_kv_8_8_t kv0, value0; + u32 oldest_per_user_translation_list_index; + dlist_elt_t * oldest_per_user_translation_list_elt; + dlist_elt_t * per_user_translation_list_elt; + dlist_elt_t * per_user_list_head_elt; + u32 session_index; + snat_session_key_t key1; + u32 address_index = ~0; + u32 outside_fib_index; + uword * p; + snat_static_mapping_key_t worker_by_out_key; + + p = hash_get (sm->ip4_main->fib_index_by_table_id, sm->outside_vrf_id); + if (! p) + { + b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_OUTSIDE_FIB]; + return SNAT_IN2OUT_NEXT_DROP; + } + outside_fib_index = p[0]; + + user_key.addr = ip0->src_address; + user_key.fib_index = rx_fib_index0; + kv0.key = user_key.as_u64; + + /* Ever heard of the "user" = src ip4 address before? */ + if (clib_bihash_search_8_8 (&sm->user_hash, &kv0, &value0)) + { + /* no, make a new one */ + pool_get (sm->per_thread_data[cpu_index].users, u); + memset (u, 0, sizeof (*u)); + u->addr = ip0->src_address; + + pool_get (sm->per_thread_data[cpu_index].list_pool, per_user_list_head_elt); + + u->sessions_per_user_list_head_index = per_user_list_head_elt - + sm->per_thread_data[cpu_index].list_pool; + + clib_dlist_init (sm->per_thread_data[cpu_index].list_pool, + u->sessions_per_user_list_head_index); + + kv0.value = u - sm->per_thread_data[cpu_index].users; + + /* add user */ + clib_bihash_add_del_8_8 (&sm->user_hash, &kv0, 1 /* is_add */); + } + else + { + u = pool_elt_at_index (sm->per_thread_data[cpu_index].users, + value0.value); + } + + /* Over quota? Recycle the least recently used dynamic translation */ + if (u->nsessions >= sm->max_translations_per_user) + { + /* Remove the oldest dynamic translation */ + do { + oldest_per_user_translation_list_index = + clib_dlist_remove_head (sm->per_thread_data[cpu_index].list_pool, + u->sessions_per_user_list_head_index); + + ASSERT (oldest_per_user_translation_list_index != ~0); + + /* add it back to the end of the LRU list */ + clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, + u->sessions_per_user_list_head_index, + oldest_per_user_translation_list_index); + /* Get the list element */ + oldest_per_user_translation_list_elt = + pool_elt_at_index (sm->per_thread_data[cpu_index].list_pool, + oldest_per_user_translation_list_index); + + /* Get the session index from the list element */ + session_index = oldest_per_user_translation_list_elt->value; + + /* Get the session */ + s = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, + session_index); + } while (snat_is_session_static (s)); + + /* Remove in2out, out2in keys */ + kv0.key = s->in2out.as_u64; + if (clib_bihash_add_del_8_8 (&sm->in2out, &kv0, 0 /* is_add */)) + clib_warning ("in2out key delete failed"); + kv0.key = s->out2in.as_u64; + if (clib_bihash_add_del_8_8 (&sm->out2in, &kv0, 0 /* is_add */)) + clib_warning ("out2in key delete failed"); + + snat_free_outside_address_and_port + (sm, &s->out2in, s->outside_address_index); + s->outside_address_index = ~0; + + if (snat_alloc_outside_address_and_port (sm, &key1, &address_index)) + { + ASSERT(0); + + b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS]; + return SNAT_IN2OUT_NEXT_DROP; + } + s->outside_address_index = address_index; + } + else + { + u8 static_mapping = 1; + + /* First try to match static mapping by local address and port */ + if (snat_static_mapping_match (sm, *key0, &key1, 0)) + { + static_mapping = 0; + /* Try to create dynamic translation */ + if (snat_alloc_outside_address_and_port (sm, &key1, &address_index)) + { + b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS]; + return SNAT_IN2OUT_NEXT_DROP; + } + } + + /* Create a new session */ + pool_get (sm->per_thread_data[cpu_index].sessions, s); + memset (s, 0, sizeof (*s)); + + s->outside_address_index = address_index; + + if (static_mapping) + { + u->nstaticsessions++; + s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; + } + else + { + u->nsessions++; + } + + /* Create list elts */ + pool_get (sm->per_thread_data[cpu_index].list_pool, + per_user_translation_list_elt); + clib_dlist_init (sm->per_thread_data[cpu_index].list_pool, + per_user_translation_list_elt - + sm->per_thread_data[cpu_index].list_pool); + + per_user_translation_list_elt->value = + s - sm->per_thread_data[cpu_index].sessions; + s->per_user_index = per_user_translation_list_elt - + sm->per_thread_data[cpu_index].list_pool; + s->per_user_list_head_index = u->sessions_per_user_list_head_index; + + clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, + s->per_user_list_head_index, + per_user_translation_list_elt - + sm->per_thread_data[cpu_index].list_pool); + } + + s->in2out = *key0; + s->out2in = key1; + s->out2in.protocol = key0->protocol; + s->out2in.fib_index = outside_fib_index; + *sessionp = s; + + /* Add to translation hashes */ + kv0.key = s->in2out.as_u64; + kv0.value = s - sm->per_thread_data[cpu_index].sessions; + if (clib_bihash_add_del_8_8 (&sm->in2out, &kv0, 1 /* is_add */)) + clib_warning ("in2out key add failed"); + + kv0.key = s->out2in.as_u64; + kv0.value = s - sm->per_thread_data[cpu_index].sessions; + + if (clib_bihash_add_del_8_8 (&sm->out2in, &kv0, 1 /* is_add */)) + clib_warning ("out2in key add failed"); + + /* Add to translated packets worker lookup */ + worker_by_out_key.addr = s->out2in.addr; + worker_by_out_key.port = s->out2in.port; + worker_by_out_key.fib_index = s->out2in.fib_index; + kv0.key = worker_by_out_key.as_u64; + kv0.value = cpu_index; + clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv0, 1); + return next0; +} + +static inline u32 icmp_in2out_slow_path (snat_main_t *sm, + vlib_buffer_t * b0, + ip4_header_t * ip0, + icmp46_header_t * icmp0, + u32 sw_if_index0, + u32 rx_fib_index0, + vlib_node_runtime_t * node, + u32 next0, + f64 now, + u32 cpu_index) +{ + snat_session_key_t key0; + icmp_echo_header_t *echo0; + clib_bihash_kv_8_8_t kv0, value0; + snat_session_t * s0; + u32 new_addr0, old_addr0; + u16 old_id0, new_id0; + ip_csum_t sum0; + snat_runtime_t * rt = (snat_runtime_t *)node->runtime_data; + + if (PREDICT_FALSE(icmp0->type != ICMP4_echo_request)) + { + b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE]; + return SNAT_IN2OUT_NEXT_DROP; + } + + echo0 = (icmp_echo_header_t *)(icmp0+1); + + key0.addr = ip0->src_address; + key0.port = echo0->identifier; + key0.protocol = SNAT_PROTOCOL_ICMP; + key0.fib_index = rx_fib_index0; + + kv0.key = key0.as_u64; + + if (clib_bihash_search_8_8 (&sm->in2out, &kv0, &value0)) + { + ip4_address_t * first_int_addr; + + if (PREDICT_FALSE(rt->cached_sw_if_index != sw_if_index0)) + { + first_int_addr = + ip4_interface_first_address (sm->ip4_main, sw_if_index0, + 0 /* just want the address */); + rt->cached_sw_if_index = sw_if_index0; + rt->cached_ip4_address = first_int_addr->as_u32; + } + + /* Don't NAT packet aimed at the intfc address */ + if (PREDICT_FALSE(ip0->dst_address.as_u32 == + rt->cached_ip4_address)) + return next0; + + next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0, + &s0, node, next0, cpu_index); + + if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP)) + return next0; + } + else + s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, + value0.value); + + old_addr0 = ip0->src_address.as_u32; + ip0->src_address = s0->out2in.addr; + new_addr0 = ip0->src_address.as_u32; + vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index; + + sum0 = ip0->checksum; + sum0 = ip_csum_update (sum0, old_addr0, new_addr0, + ip4_header_t, + src_address /* changed member */); + ip0->checksum = ip_csum_fold (sum0); + + old_id0 = echo0->identifier; + new_id0 = s0->out2in.port; + echo0->identifier = new_id0; + + sum0 = icmp0->checksum; + sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t, + identifier); + icmp0->checksum = ip_csum_fold (sum0); + + /* Accounting */ + s0->last_heard = now; + s0->total_pkts++; + s0->total_bytes += vlib_buffer_length_in_chain (sm->vlib_main, b0); + /* Per-user LRU list maintenance for dynamic translations */ + if (!snat_is_session_static (s0)) + { + clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, + s0->per_user_index); + clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, + s0->per_user_list_head_index, + s0->per_user_index); + } + + return next0; +} + +/** + * @brief Hairpinning + * + * Hairpinning allows two endpoints on the internal side of the NAT to + * communicate even if they only use each other's external IP addresses + * and ports. + * + * @param sm SNAT main. + * @param b0 Vlib buffer. + * @param ip0 IP header. + * @param udp0 UDP header. + * @param tcp0 TCP header. + * @param proto0 SNAT protocol. + */ +static inline void +snat_hairpinning (snat_main_t *sm, + vlib_buffer_t * b0, + ip4_header_t * ip0, + udp_header_t * udp0, + tcp_header_t * tcp0, + u32 proto0) +{ + snat_session_key_t key0, sm0; + snat_static_mapping_key_t k0; + snat_session_t * s0; + clib_bihash_kv_8_8_t kv0, value0; + ip_csum_t sum0; + u32 new_dst_addr0 = 0, old_dst_addr0, ti = 0, si; + u16 new_dst_port0, old_dst_port0; + + key0.addr = ip0->dst_address; + key0.port = udp0->dst_port; + key0.protocol = proto0; + key0.fib_index = sm->outside_fib_index; + kv0.key = key0.as_u64; + + /* Check if destination is in active sessions */ + if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0)) + { + /* or static mappings */ + if (!snat_static_mapping_match(sm, key0, &sm0, 1)) + { + new_dst_addr0 = sm0.addr.as_u32; + new_dst_port0 = sm0.port; + vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index; + } + } + else + { + si = value0.value; + if (sm->num_workers > 1) + { + k0.addr = ip0->dst_address; + k0.port = udp0->dst_port; + k0.fib_index = sm->outside_fib_index; + kv0.key = k0.as_u64; + if (clib_bihash_search_8_8 (&sm->worker_by_out, &kv0, &value0)) + ASSERT(0); + else + ti = value0.value; + } + else + ti = sm->num_workers; + + s0 = pool_elt_at_index (sm->per_thread_data[ti].sessions, si); + new_dst_addr0 = s0->in2out.addr.as_u32; + new_dst_port0 = s0->in2out.port; + vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index; + } + + /* Destination is behind the same NAT, use internal address and port */ + if (new_dst_addr0) + { + old_dst_addr0 = ip0->dst_address.as_u32; + ip0->dst_address.as_u32 = new_dst_addr0; + sum0 = ip0->checksum; + sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0, + ip4_header_t, dst_address); + ip0->checksum = ip_csum_fold (sum0); + + old_dst_port0 = tcp0->ports.dst; + if (PREDICT_TRUE(new_dst_port0 != old_dst_port0)) + { + if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) + { + tcp0->ports.dst = new_dst_port0; + sum0 = tcp0->checksum; + sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0, + ip4_header_t, dst_address); + sum0 = ip_csum_update (sum0, old_dst_port0, new_dst_port0, + ip4_header_t /* cheat */, length); + tcp0->checksum = ip_csum_fold(sum0); + } + else + { + udp0->dst_port = new_dst_port0; + udp0->checksum = 0; + } + } + } +} + +static inline uword +snat_in2out_node_fn_inline (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame, int is_slow_path) +{ + u32 n_left_from, * from, * to_next; + snat_in2out_next_t next_index; + u32 pkts_processed = 0; + snat_main_t * sm = &snat_main; + snat_runtime_t * rt = (snat_runtime_t *)node->runtime_data; + f64 now = vlib_time_now (vm); + u32 stats_node_index; + u32 cpu_index = os_get_cpu_number (); + + stats_node_index = is_slow_path ? snat_in2out_slowpath_node.index : + snat_in2out_node.index; + + 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 bi0, bi1; + vlib_buffer_t * b0, * b1; + u32 next0, next1; + u32 sw_if_index0, sw_if_index1; + ip4_header_t * ip0, * ip1; + ip_csum_t sum0, sum1; + u32 new_addr0, old_addr0, new_addr1, old_addr1; + u16 old_port0, new_port0, old_port1, new_port1; + udp_header_t * udp0, * udp1; + tcp_header_t * tcp0, * tcp1; + icmp46_header_t * icmp0, * icmp1; + snat_session_key_t key0, key1; + u32 rx_fib_index0, rx_fib_index1; + u32 proto0, proto1; + snat_session_t * s0 = 0, * s1 = 0; + clib_bihash_kv_8_8_t kv0, value0, kv1, value1; + + /* 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); + + ip0 = vlib_buffer_get_current (b0); + udp0 = ip4_next_header (ip0); + tcp0 = (tcp_header_t *) udp0; + icmp0 = (icmp46_header_t *) udp0; + + sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; + rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, + sw_if_index0); + + next0 = next1 = SNAT_IN2OUT_NEXT_LOOKUP; + + proto0 = ~0; + proto0 = (ip0->protocol == IP_PROTOCOL_UDP) + ? SNAT_PROTOCOL_UDP : proto0; + proto0 = (ip0->protocol == IP_PROTOCOL_TCP) + ? SNAT_PROTOCOL_TCP : proto0; + proto0 = (ip0->protocol == IP_PROTOCOL_ICMP) + ? SNAT_PROTOCOL_ICMP : proto0; + + /* Next configured feature, probably ip4-lookup */ + if (is_slow_path) + { + if (PREDICT_FALSE (proto0 == ~0)) + goto trace00; + + if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) + { + next0 = icmp_in2out_slow_path + (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, + node, next0, now, cpu_index); + goto trace00; + } + } + else + { + if (PREDICT_FALSE (proto0 == ~0 || proto0 == SNAT_PROTOCOL_ICMP)) + { + next0 = SNAT_IN2OUT_NEXT_SLOW_PATH; + goto trace00; + } + } + + key0.addr = ip0->src_address; + key0.port = udp0->src_port; + key0.protocol = proto0; + key0.fib_index = rx_fib_index0; + + kv0.key = key0.as_u64; + + if (PREDICT_FALSE (clib_bihash_search_8_8 (&sm->in2out, &kv0, &value0) != 0)) + { + if (is_slow_path) + { + ip4_address_t * first_int_addr; + + if (PREDICT_FALSE(rt->cached_sw_if_index != sw_if_index0)) + { + first_int_addr = + ip4_interface_first_address (sm->ip4_main, sw_if_index0, + 0 /* just want the address */); + rt->cached_sw_if_index = sw_if_index0; + rt->cached_ip4_address = first_int_addr->as_u32; + } + + /* Don't NAT packet aimed at the intfc address */ + if (PREDICT_FALSE(ip0->dst_address.as_u32 == + rt->cached_ip4_address)) + goto trace00; + + next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0, + &s0, node, next0, cpu_index); + if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP)) + goto trace00; + } + else + { + next0 = SNAT_IN2OUT_NEXT_SLOW_PATH; + goto trace00; + } + } + else + s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, + value0.value); + + old_addr0 = ip0->src_address.as_u32; + ip0->src_address = s0->out2in.addr; + new_addr0 = ip0->src_address.as_u32; + vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index; + + sum0 = ip0->checksum; + sum0 = ip_csum_update (sum0, old_addr0, new_addr0, + ip4_header_t, + src_address /* changed member */); + ip0->checksum = ip_csum_fold (sum0); + + if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) + { + old_port0 = tcp0->ports.src; + tcp0->ports.src = s0->out2in.port; + new_port0 = tcp0->ports.src; + + sum0 = tcp0->checksum; + sum0 = ip_csum_update (sum0, old_addr0, new_addr0, + ip4_header_t, + dst_address /* changed member */); + sum0 = ip_csum_update (sum0, old_port0, new_port0, + ip4_header_t /* cheat */, + length /* changed member */); + tcp0->checksum = ip_csum_fold(sum0); + } + else + { + old_port0 = udp0->src_port; + udp0->src_port = s0->out2in.port; + udp0->checksum = 0; + } + + /* Hairpinning */ + snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0); + + /* Accounting */ + s0->last_heard = now; + s0->total_pkts++; + s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); + /* Per-user LRU list maintenance for dynamic translation */ + if (!snat_is_session_static (s0)) + { + clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, + s0->per_user_index); + clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, + s0->per_user_list_head_index, + s0->per_user_index); + } + trace00: + + if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + snat_in2out_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->is_slow_path = is_slow_path; + t->sw_if_index = sw_if_index0; + t->next_index = next0; + t->session_index = ~0; + if (s0) + t->session_index = s0 - sm->per_thread_data[cpu_index].sessions; + } + + pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP; + + ip1 = vlib_buffer_get_current (b1); + udp1 = ip4_next_header (ip1); + tcp1 = (tcp_header_t *) udp1; + icmp1 = (icmp46_header_t *) udp1; + + sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX]; + rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, + sw_if_index1); + + proto1 = ~0; + proto1 = (ip1->protocol == IP_PROTOCOL_UDP) + ? SNAT_PROTOCOL_UDP : proto1; + proto1 = (ip1->protocol == IP_PROTOCOL_TCP) + ? SNAT_PROTOCOL_TCP : proto1; + proto1 = (ip1->protocol == IP_PROTOCOL_ICMP) + ? SNAT_PROTOCOL_ICMP : proto1; + + /* Next configured feature, probably ip4-lookup */ + if (is_slow_path) + { + if (PREDICT_FALSE (proto1 == ~0)) + goto trace01; + + if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP)) + { + next1 = icmp_in2out_slow_path + (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node, + next1, now, cpu_index); + goto trace01; + } + } + else + { + if (PREDICT_FALSE (proto1 == ~0 || proto1 == SNAT_PROTOCOL_ICMP)) + { + next1 = SNAT_IN2OUT_NEXT_SLOW_PATH; + goto trace01; + } + } + + key1.addr = ip1->src_address; + key1.port = udp1->src_port; + key1.protocol = proto1; + key1.fib_index = rx_fib_index1; + + kv1.key = key1.as_u64; + + if (PREDICT_FALSE(clib_bihash_search_8_8 (&sm->in2out, &kv1, &value1) != 0)) + { + if (is_slow_path) + { + ip4_address_t * first_int_addr; + + if (PREDICT_FALSE(rt->cached_sw_if_index != sw_if_index1)) + { + first_int_addr = + ip4_interface_first_address (sm->ip4_main, sw_if_index1, + 0 /* just want the address */); + rt->cached_sw_if_index = sw_if_index1; + rt->cached_ip4_address = first_int_addr->as_u32; + } + + /* Don't NAT packet aimed at the intfc address */ + if (PREDICT_FALSE(ip1->dst_address.as_u32 == + rt->cached_ip4_address)) + goto trace01; + + next1 = slow_path (sm, b1, ip1, rx_fib_index1, &key1, + &s1, node, next1, cpu_index); + if (PREDICT_FALSE (next1 == SNAT_IN2OUT_NEXT_DROP)) + goto trace01; + } + else + { + next1 = SNAT_IN2OUT_NEXT_SLOW_PATH; + goto trace01; + } + } + else + s1 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, + value1.value); + + old_addr1 = ip1->src_address.as_u32; + ip1->src_address = s1->out2in.addr; + new_addr1 = ip1->src_address.as_u32; + vnet_buffer(b1)->sw_if_index[VLIB_TX] = s1->out2in.fib_index; + + sum1 = ip1->checksum; + sum1 = ip_csum_update (sum1, old_addr1, new_addr1, + ip4_header_t, + src_address /* changed member */); + ip1->checksum = ip_csum_fold (sum1); + + if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP)) + { + old_port1 = tcp1->ports.src; + tcp1->ports.src = s1->out2in.port; + new_port1 = tcp1->ports.src; + + sum1 = tcp1->checksum; + sum1 = ip_csum_update (sum1, old_addr1, new_addr1, + ip4_header_t, + dst_address /* changed member */); + sum1 = ip_csum_update (sum1, old_port1, new_port1, + ip4_header_t /* cheat */, + length /* changed member */); + tcp1->checksum = ip_csum_fold(sum1); + } + else + { + old_port1 = udp1->src_port; + udp1->src_port = s1->out2in.port; + udp1->checksum = 0; + } + + /* Hairpinning */ + snat_hairpinning (sm, b1, ip1, udp1, tcp1, proto1); + + /* Accounting */ + s1->last_heard = now; + s1->total_pkts++; + s1->total_bytes += vlib_buffer_length_in_chain (vm, b1); + /* Per-user LRU list maintenance for dynamic translation */ + if (!snat_is_session_static (s1)) + { + clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, + s1->per_user_index); + clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, + s1->per_user_list_head_index, + s1->per_user_index); + } + trace01: + + if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) + && (b1->flags & VLIB_BUFFER_IS_TRACED))) + { + snat_in2out_trace_t *t = + vlib_add_trace (vm, node, b1, sizeof (*t)); + t->sw_if_index = sw_if_index1; + t->next_index = next1; + t->session_index = ~0; + if (s1) + t->session_index = s1 - sm->per_thread_data[cpu_index].sessions; + } + + pkts_processed += next1 != SNAT_IN2OUT_NEXT_DROP; + + /* 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; + u32 sw_if_index0; + ip4_header_t * ip0; + ip_csum_t sum0; + u32 new_addr0, old_addr0; + u16 old_port0, new_port0; + udp_header_t * udp0; + tcp_header_t * tcp0; + icmp46_header_t * icmp0; + snat_session_key_t key0; + u32 rx_fib_index0; + u32 proto0; + snat_session_t * s0 = 0; + clib_bihash_kv_8_8_t kv0, value0; + + /* 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); + next0 = SNAT_IN2OUT_NEXT_LOOKUP; + + ip0 = vlib_buffer_get_current (b0); + udp0 = ip4_next_header (ip0); + tcp0 = (tcp_header_t *) udp0; + icmp0 = (icmp46_header_t *) udp0; + + sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; + rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, + sw_if_index0); + + proto0 = ~0; + proto0 = (ip0->protocol == IP_PROTOCOL_UDP) + ? SNAT_PROTOCOL_UDP : proto0; + proto0 = (ip0->protocol == IP_PROTOCOL_TCP) + ? SNAT_PROTOCOL_TCP : proto0; + proto0 = (ip0->protocol == IP_PROTOCOL_ICMP) + ? SNAT_PROTOCOL_ICMP : proto0; + + /* Next configured feature, probably ip4-lookup */ + if (is_slow_path) + { + if (PREDICT_FALSE (proto0 == ~0)) + goto trace0; + + if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) + { + next0 = icmp_in2out_slow_path + (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, + next0, now, cpu_index); + goto trace0; + } + } + else + { + if (PREDICT_FALSE (proto0 == ~0 || proto0 == SNAT_PROTOCOL_ICMP)) + { + next0 = SNAT_IN2OUT_NEXT_SLOW_PATH; + goto trace0; + } + } + + key0.addr = ip0->src_address; + key0.port = udp0->src_port; + key0.protocol = proto0; + key0.fib_index = rx_fib_index0; + + kv0.key = key0.as_u64; + + if (clib_bihash_search_8_8 (&sm->in2out, &kv0, &value0)) + { + if (is_slow_path) + { + ip4_address_t * first_int_addr; + + if (PREDICT_FALSE(rt->cached_sw_if_index != sw_if_index0)) + { + first_int_addr = + ip4_interface_first_address (sm->ip4_main, sw_if_index0, + 0 /* just want the address */); + rt->cached_sw_if_index = sw_if_index0; + rt->cached_ip4_address = first_int_addr->as_u32; + } + + /* Don't NAT packet aimed at the intfc address */ + if (PREDICT_FALSE(ip0->dst_address.as_u32 == + rt->cached_ip4_address)) + goto trace0; + + next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0, + &s0, node, next0, cpu_index); + if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP)) + goto trace0; + } + else + { + next0 = SNAT_IN2OUT_NEXT_SLOW_PATH; + goto trace0; + } + } + else + s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, + value0.value); + + old_addr0 = ip0->src_address.as_u32; + ip0->src_address = s0->out2in.addr; + new_addr0 = ip0->src_address.as_u32; + vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index; + + sum0 = ip0->checksum; + sum0 = ip_csum_update (sum0, old_addr0, new_addr0, + ip4_header_t, + src_address /* changed member */); + ip0->checksum = ip_csum_fold (sum0); + + if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) + { + old_port0 = tcp0->ports.src; + tcp0->ports.src = s0->out2in.port; + new_port0 = tcp0->ports.src; + + sum0 = tcp0->checksum; + sum0 = ip_csum_update (sum0, old_addr0, new_addr0, + ip4_header_t, + dst_address /* changed member */); + sum0 = ip_csum_update (sum0, old_port0, new_port0, + ip4_header_t /* cheat */, + length /* changed member */); + tcp0->checksum = ip_csum_fold(sum0); + } + else + { + old_port0 = udp0->src_port; + udp0->src_port = s0->out2in.port; + udp0->checksum = 0; + } + + /* Hairpinning */ + snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0); + + /* Accounting */ + s0->last_heard = now; + s0->total_pkts++; + s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); + /* Per-user LRU list maintenance for dynamic translation */ + if (!snat_is_session_static (s0)) + { + clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, + s0->per_user_index); + clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, + s0->per_user_list_head_index, + s0->per_user_index); + } + + trace0: + if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + snat_in2out_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->is_slow_path = is_slow_path; + t->sw_if_index = sw_if_index0; + t->next_index = next0; + t->session_index = ~0; + if (s0) + t->session_index = s0 - sm->per_thread_data[cpu_index].sessions; + } + + pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP; + + /* 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, stats_node_index, + SNAT_IN2OUT_ERROR_IN2OUT_PACKETS, + pkts_processed); + return frame->n_vectors; +} + +static uword +snat_in2out_fast_path_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return snat_in2out_node_fn_inline (vm, node, frame, 0 /* is_slow_path */); +} + +VLIB_REGISTER_NODE (snat_in2out_node) = { + .function = snat_in2out_fast_path_fn, + .name = "snat-in2out", + .vector_size = sizeof (u32), + .format_trace = format_snat_in2out_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(snat_in2out_error_strings), + .error_strings = snat_in2out_error_strings, + + .runtime_data_bytes = sizeof (snat_runtime_t), + + .n_next_nodes = SNAT_IN2OUT_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [SNAT_IN2OUT_NEXT_DROP] = "error-drop", + [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup", + [SNAT_IN2OUT_NEXT_SLOW_PATH] = "snat-in2out-slowpath", + }, +}; + +VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_node, snat_in2out_fast_path_fn); + +static uword +snat_in2out_slow_path_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return snat_in2out_node_fn_inline (vm, node, frame, 1 /* is_slow_path */); +} + +VLIB_REGISTER_NODE (snat_in2out_slowpath_node) = { + .function = snat_in2out_slow_path_fn, + .name = "snat-in2out-slowpath", + .vector_size = sizeof (u32), + .format_trace = format_snat_in2out_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(snat_in2out_error_strings), + .error_strings = snat_in2out_error_strings, + + .runtime_data_bytes = sizeof (snat_runtime_t), + + .n_next_nodes = SNAT_IN2OUT_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [SNAT_IN2OUT_NEXT_DROP] = "error-drop", + [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup", + [SNAT_IN2OUT_NEXT_SLOW_PATH] = "snat-in2out-slowpath", + }, +}; + +VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_slowpath_node, snat_in2out_slow_path_fn); + +static uword +snat_in2out_worker_handoff_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + snat_main_t *sm = &snat_main; + vlib_thread_main_t *tm = vlib_get_thread_main (); + u32 n_left_from, *from, *to_next = 0; + static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index; + static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index + = 0; + vlib_frame_queue_elt_t *hf = 0; + vlib_frame_t *f = 0; + int i; + u32 n_left_to_next_worker = 0, *to_next_worker = 0; + u32 next_worker_index = 0; + u32 current_worker_index = ~0; + u32 cpu_index = os_get_cpu_number (); + + ASSERT (vec_len (sm->workers)); + + if (PREDICT_FALSE (handoff_queue_elt_by_worker_index == 0)) + { + vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1); + + vec_validate_init_empty (congested_handoff_queue_by_worker_index, + sm->first_worker_index + sm->num_workers - 1, + (vlib_frame_queue_t *) (~0)); + } + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + + while (n_left_from > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 sw_if_index0; + u32 rx_fib_index0; + ip4_header_t * ip0; + snat_user_key_t key0; + clib_bihash_kv_8_8_t kv0, value0; + u8 do_handoff; + + bi0 = from[0]; + from += 1; + n_left_from -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0); + + ip0 = vlib_buffer_get_current (b0); + + key0.addr = ip0->src_address; + key0.fib_index = rx_fib_index0; + + kv0.key = key0.as_u64; + + /* Ever heard of of the "user" before? */ + if (clib_bihash_search_8_8 (&sm->worker_by_in, &kv0, &value0)) + { + /* No, assign next available worker (RR) */ + next_worker_index = sm->first_worker_index + + sm->workers[sm->next_worker++ % vec_len (sm->workers)]; + + /* add non-traslated packets worker lookup */ + kv0.value = next_worker_index; + clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv0, 1); + } + else + next_worker_index = value0.value; + + if (PREDICT_FALSE (next_worker_index != cpu_index)) + { + do_handoff = 1; + + if (next_worker_index != current_worker_index) + { + if (hf) + hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker; + + hf = vlib_get_worker_handoff_queue_elt (sm->fq_in2out_index, + next_worker_index, + handoff_queue_elt_by_worker_index); + + n_left_to_next_worker = VLIB_FRAME_SIZE - hf->n_vectors; + to_next_worker = &hf->buffer_index[hf->n_vectors]; + current_worker_index = next_worker_index; + } + + /* enqueue to correct worker thread */ + to_next_worker[0] = bi0; + to_next_worker++; + n_left_to_next_worker--; + + if (n_left_to_next_worker == 0) + { + hf->n_vectors = VLIB_FRAME_SIZE; + vlib_put_frame_queue_elt (hf); + current_worker_index = ~0; + handoff_queue_elt_by_worker_index[next_worker_index] = 0; + hf = 0; + } + } + else + { + do_handoff = 0; + /* if this is 1st frame */ + if (!f) + { + f = vlib_get_frame_to_node (vm, snat_in2out_node.index); + to_next = vlib_frame_vector_args (f); + } + + to_next[0] = bi0; + to_next += 1; + f->n_vectors++; + } + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + snat_in2out_worker_handoff_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->next_worker_index = next_worker_index; + t->do_handoff = do_handoff; + } + } + + if (f) + vlib_put_frame_to_node (vm, snat_in2out_node.index, f); + + if (hf) + hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker; + + /* Ship frames to the worker nodes */ + for (i = 0; i < vec_len (handoff_queue_elt_by_worker_index); i++) + { + if (handoff_queue_elt_by_worker_index[i]) + { + hf = handoff_queue_elt_by_worker_index[i]; + /* + * It works better to let the handoff node + * rate-adapt, always ship the handoff queue element. + */ + if (1 || hf->n_vectors == hf->last_n_vectors) + { + vlib_put_frame_queue_elt (hf); + handoff_queue_elt_by_worker_index[i] = 0; + } + else + hf->last_n_vectors = hf->n_vectors; + } + congested_handoff_queue_by_worker_index[i] = + (vlib_frame_queue_t *) (~0); + } + hf = 0; + current_worker_index = ~0; + return frame->n_vectors; +} + +VLIB_REGISTER_NODE (snat_in2out_worker_handoff_node) = { + .function = snat_in2out_worker_handoff_fn, + .name = "snat-in2out-worker-handoff", + .vector_size = sizeof (u32), + .format_trace = format_snat_in2out_worker_handoff_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_next_nodes = 1, + + .next_nodes = { + [0] = "error-drop", + }, +}; + +VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_worker_handoff_node, snat_in2out_worker_handoff_fn); + +static inline u32 icmp_in2out_static_map (snat_main_t *sm, + vlib_buffer_t * b0, + ip4_header_t * ip0, + icmp46_header_t * icmp0, + u32 sw_if_index0, + vlib_node_runtime_t * node, + u32 next0, + u32 rx_fib_index0) +{ + snat_session_key_t key0, sm0; + icmp_echo_header_t *echo0; + u32 new_addr0, old_addr0; + u16 old_id0, new_id0; + ip_csum_t sum0; + snat_runtime_t * rt = (snat_runtime_t *)node->runtime_data; + + echo0 = (icmp_echo_header_t *)(icmp0+1); + + key0.addr = ip0->src_address; + key0.port = echo0->identifier; + key0.fib_index = rx_fib_index0; + + if (snat_static_mapping_match(sm, key0, &sm0, 0)) + { + ip4_address_t * first_int_addr; + + if (PREDICT_FALSE(rt->cached_sw_if_index != sw_if_index0)) + { + first_int_addr = + ip4_interface_first_address (sm->ip4_main, sw_if_index0, + 0 /* just want the address */); + rt->cached_sw_if_index = sw_if_index0; + rt->cached_ip4_address = first_int_addr->as_u32; + } + + /* Don't NAT packet aimed at the intfc address */ + if (PREDICT_FALSE(ip0->dst_address.as_u32 == + rt->cached_ip4_address)) + return next0; + + b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION]; + return SNAT_IN2OUT_NEXT_DROP; + } + + new_addr0 = sm0.addr.as_u32; + new_id0 = sm0.port; + vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index; + old_addr0 = ip0->src_address.as_u32; + ip0->src_address.as_u32 = new_addr0; + + sum0 = ip0->checksum; + sum0 = ip_csum_update (sum0, old_addr0, new_addr0, + ip4_header_t, + src_address /* changed member */); + ip0->checksum = ip_csum_fold (sum0); + + if (PREDICT_FALSE(new_id0 != echo0->identifier)) + { + old_id0 = echo0->identifier; + echo0->identifier = new_id0; + + sum0 = icmp0->checksum; + sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t, + identifier); + icmp0->checksum = ip_csum_fold (sum0); + } + + return next0; +} + +static uword +snat_in2out_fast_static_map_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + u32 n_left_from, * from, * to_next; + snat_in2out_next_t next_index; + u32 pkts_processed = 0; + snat_main_t * sm = &snat_main; + snat_runtime_t * rt = (snat_runtime_t *)node->runtime_data; + u32 stats_node_index; + + stats_node_index = snat_in2out_fast_node.index; + + 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 > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t * b0; + u32 next0; + u32 sw_if_index0; + ip4_header_t * ip0; + ip_csum_t sum0; + u32 new_addr0, old_addr0; + u16 old_port0, new_port0; + udp_header_t * udp0; + tcp_header_t * tcp0; + icmp46_header_t * icmp0; + snat_session_key_t key0, sm0; + u32 proto0; + u32 rx_fib_index0; + + /* 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); + next0 = SNAT_IN2OUT_NEXT_LOOKUP; + + ip0 = vlib_buffer_get_current (b0); + udp0 = ip4_next_header (ip0); + tcp0 = (tcp_header_t *) udp0; + icmp0 = (icmp46_header_t *) udp0; + + sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; + rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0); + + proto0 = ~0; + proto0 = (ip0->protocol == IP_PROTOCOL_UDP) + ? SNAT_PROTOCOL_UDP : proto0; + proto0 = (ip0->protocol == IP_PROTOCOL_TCP) + ? SNAT_PROTOCOL_TCP : proto0; + proto0 = (ip0->protocol == IP_PROTOCOL_ICMP) + ? SNAT_PROTOCOL_ICMP : proto0; + + if (PREDICT_FALSE (proto0 == ~0)) + goto trace0; + + if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) + { + ip4_address_t * first_int_addr; + + if (PREDICT_FALSE(rt->cached_sw_if_index != sw_if_index0)) + { + first_int_addr = + ip4_interface_first_address (sm->ip4_main, sw_if_index0, + 0 /* just want the address */); + rt->cached_sw_if_index = sw_if_index0; + rt->cached_ip4_address = first_int_addr->as_u32; + } + + /* Don't NAT packet aimed at the intfc address */ + if (PREDICT_FALSE(ip0->dst_address.as_u32 == + rt->cached_ip4_address)) + goto trace0; + + next0 = icmp_in2out_static_map + (sm, b0, ip0, icmp0, sw_if_index0, node, next0, rx_fib_index0); + goto trace0; + } + + key0.addr = ip0->src_address; + key0.port = udp0->src_port; + key0.fib_index = rx_fib_index0; + + if (snat_static_mapping_match(sm, key0, &sm0, 0)) + { + b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION]; + next0= SNAT_IN2OUT_NEXT_DROP; + goto trace0; + } + + new_addr0 = sm0.addr.as_u32; + new_port0 = sm0.port; + vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index; + old_addr0 = ip0->src_address.as_u32; + ip0->src_address.as_u32 = new_addr0; + + sum0 = ip0->checksum; + sum0 = ip_csum_update (sum0, old_addr0, new_addr0, + ip4_header_t, + src_address /* changed member */); + ip0->checksum = ip_csum_fold (sum0); + + if (PREDICT_FALSE(new_port0 != udp0->dst_port)) + { + if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) + { + old_port0 = tcp0->ports.src; + tcp0->ports.src = new_port0; + + sum0 = tcp0->checksum; + sum0 = ip_csum_update (sum0, old_addr0, new_addr0, + ip4_header_t, + dst_address /* changed member */); + sum0 = ip_csum_update (sum0, old_port0, new_port0, + ip4_header_t /* cheat */, + length /* changed member */); + tcp0->checksum = ip_csum_fold(sum0); + } + else + { + old_port0 = udp0->src_port; + udp0->src_port = new_port0; + udp0->checksum = 0; + } + } + else + { + if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) + { + sum0 = tcp0->checksum; + sum0 = ip_csum_update (sum0, old_addr0, new_addr0, + ip4_header_t, + dst_address /* changed member */); + tcp0->checksum = ip_csum_fold(sum0); + } + } + + /* Hairpinning */ + snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0); + + trace0: + if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + snat_in2out_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + t->next_index = next0; + } + + pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP; + + /* 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, stats_node_index, + SNAT_IN2OUT_ERROR_IN2OUT_PACKETS, + pkts_processed); + return frame->n_vectors; +} + + +VLIB_REGISTER_NODE (snat_in2out_fast_node) = { + .function = snat_in2out_fast_static_map_fn, + .name = "snat-in2out-fast", + .vector_size = sizeof (u32), + .format_trace = format_snat_in2out_fast_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(snat_in2out_error_strings), + .error_strings = snat_in2out_error_strings, + + .runtime_data_bytes = sizeof (snat_runtime_t), + + .n_next_nodes = SNAT_IN2OUT_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [SNAT_IN2OUT_NEXT_DROP] = "error-drop", + [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup", + [SNAT_IN2OUT_NEXT_SLOW_PATH] = "snat-in2out-slowpath", + }, +}; + +VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_fast_node, snat_in2out_fast_static_map_fn); diff --git a/src/plugins/snat/out2in.c b/src/plugins/snat/out2in.c new file mode 100644 index 00000000..f1f4159c --- /dev/null +++ b/src/plugins/snat/out2in.c @@ -0,0 +1,1261 @@ +/* + * 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. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +typedef struct { + u32 sw_if_index; + u32 next_index; + u32 session_index; +} snat_out2in_trace_t; + +typedef struct { + u32 next_worker_index; + u8 do_handoff; +} snat_out2in_worker_handoff_trace_t; + +/* packet trace format function */ +static u8 * format_snat_out2in_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 *); + snat_out2in_trace_t * t = va_arg (*args, snat_out2in_trace_t *); + + s = format (s, "SNAT_OUT2IN: sw_if_index %d, next index %d, session index %d", + t->sw_if_index, t->next_index, t->session_index); + return s; +} + +static u8 * format_snat_out2in_fast_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 *); + snat_out2in_trace_t * t = va_arg (*args, snat_out2in_trace_t *); + + s = format (s, "SNAT_OUT2IN_FAST: sw_if_index %d, next index %d", + t->sw_if_index, t->next_index); + return s; +} + +static u8 * format_snat_out2in_worker_handoff_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 *); + snat_out2in_worker_handoff_trace_t * t = + va_arg (*args, snat_out2in_worker_handoff_trace_t *); + char * m; + + m = t->do_handoff ? "next worker" : "same worker"; + s = format (s, "SNAT_OUT2IN_WORKER_HANDOFF: %s %d", m, t->next_worker_index); + + return s; +} + +vlib_node_registration_t snat_out2in_node; +vlib_node_registration_t snat_out2in_fast_node; +vlib_node_registration_t snat_out2in_worker_handoff_node; + +#define foreach_snat_out2in_error \ +_(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \ +_(OUT2IN_PACKETS, "Good out2in packets processed") \ +_(BAD_ICMP_TYPE, "icmp type not echo-reply") \ +_(NO_TRANSLATION, "No translation") + +typedef enum { +#define _(sym,str) SNAT_OUT2IN_ERROR_##sym, + foreach_snat_out2in_error +#undef _ + SNAT_OUT2IN_N_ERROR, +} snat_out2in_error_t; + +static char * snat_out2in_error_strings[] = { +#define _(sym,string) string, + foreach_snat_out2in_error +#undef _ +}; + +typedef enum { + SNAT_OUT2IN_NEXT_DROP, + SNAT_OUT2IN_NEXT_LOOKUP, + SNAT_OUT2IN_N_NEXT, +} snat_out2in_next_t; + +/** + * @brief Create session for static mapping. + * + * Create NAT session initiated by host from external network with static + * mapping. + * + * @param sm SNAT main. + * @param b0 Vlib buffer. + * @param in2out In2out SNAT session key. + * @param out2in Out2in SNAT session key. + * @param node Vlib node. + * + * @returns SNAT session if successfully created otherwise 0. + */ +static inline snat_session_t * +create_session_for_static_mapping (snat_main_t *sm, + vlib_buffer_t *b0, + snat_session_key_t in2out, + snat_session_key_t out2in, + vlib_node_runtime_t * node, + u32 cpu_index) +{ + snat_user_t *u; + snat_user_key_t user_key; + snat_session_t *s; + clib_bihash_kv_8_8_t kv0, value0; + dlist_elt_t * per_user_translation_list_elt; + dlist_elt_t * per_user_list_head_elt; + + user_key.addr = in2out.addr; + user_key.fib_index = in2out.fib_index; + kv0.key = user_key.as_u64; + + /* Ever heard of the "user" = inside ip4 address before? */ + if (clib_bihash_search_8_8 (&sm->user_hash, &kv0, &value0)) + { + /* no, make a new one */ + pool_get (sm->per_thread_data[cpu_index].users, u); + memset (u, 0, sizeof (*u)); + u->addr = in2out.addr; + + pool_get (sm->per_thread_data[cpu_index].list_pool, + per_user_list_head_elt); + + u->sessions_per_user_list_head_index = per_user_list_head_elt - + sm->per_thread_data[cpu_index].list_pool; + + clib_dlist_init (sm->per_thread_data[cpu_index].list_pool, + u->sessions_per_user_list_head_index); + + kv0.value = u - sm->per_thread_data[cpu_index].users; + + /* add user */ + clib_bihash_add_del_8_8 (&sm->user_hash, &kv0, 1 /* is_add */); + + /* add non-traslated packets worker lookup */ + kv0.value = cpu_index; + clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv0, 1); + } + else + { + u = pool_elt_at_index (sm->per_thread_data[cpu_index].users, + value0.value); + } + + pool_get (sm->per_thread_data[cpu_index].sessions, s); + memset (s, 0, sizeof (*s)); + + s->outside_address_index = ~0; + s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; + u->nstaticsessions++; + + /* Create list elts */ + pool_get (sm->per_thread_data[cpu_index].list_pool, + per_user_translation_list_elt); + clib_dlist_init (sm->per_thread_data[cpu_index].list_pool, + per_user_translation_list_elt - + sm->per_thread_data[cpu_index].list_pool); + + per_user_translation_list_elt->value = + s - sm->per_thread_data[cpu_index].sessions; + s->per_user_index = + per_user_translation_list_elt - sm->per_thread_data[cpu_index].list_pool; + s->per_user_list_head_index = u->sessions_per_user_list_head_index; + + clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, + s->per_user_list_head_index, + per_user_translation_list_elt - + sm->per_thread_data[cpu_index].list_pool); + + s->in2out = in2out; + s->out2in = out2in; + s->in2out.protocol = out2in.protocol; + + /* Add to translation hashes */ + kv0.key = s->in2out.as_u64; + kv0.value = s - sm->per_thread_data[cpu_index].sessions; + if (clib_bihash_add_del_8_8 (&sm->in2out, &kv0, 1 /* is_add */)) + clib_warning ("in2out key add failed"); + + kv0.key = s->out2in.as_u64; + kv0.value = s - sm->per_thread_data[cpu_index].sessions; + + if (clib_bihash_add_del_8_8 (&sm->out2in, &kv0, 1 /* is_add */)) + clib_warning ("out2in key add failed"); + + return s; +} + +static inline u32 icmp_out2in_slow_path (snat_main_t *sm, + vlib_buffer_t * b0, + ip4_header_t * ip0, + icmp46_header_t * icmp0, + u32 sw_if_index0, + u32 rx_fib_index0, + vlib_node_runtime_t * node, + u32 next0, f64 now, + u32 cpu_index) +{ + snat_session_key_t key0, sm0; + icmp_echo_header_t *echo0; + clib_bihash_kv_8_8_t kv0, value0; + snat_session_t * s0; + u32 new_addr0, old_addr0; + u16 old_id0, new_id0; + ip_csum_t sum0; + snat_runtime_t * rt = (snat_runtime_t *)node->runtime_data; + + echo0 = (icmp_echo_header_t *)(icmp0+1); + + key0.addr = ip0->dst_address; + key0.port = echo0->identifier; + key0.protocol = SNAT_PROTOCOL_ICMP; + key0.fib_index = rx_fib_index0; + + kv0.key = key0.as_u64; + + if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0)) + { + /* Try to match static mapping by external address and port, + destination address and port in packet */ + if (snat_static_mapping_match(sm, key0, &sm0, 1)) + { + ip4_address_t * first_int_addr; + + if (PREDICT_FALSE(rt->cached_sw_if_index != sw_if_index0)) + { + first_int_addr = + ip4_interface_first_address (sm->ip4_main, sw_if_index0, + 0 /* just want the address */); + rt->cached_sw_if_index = sw_if_index0; + rt->cached_ip4_address = first_int_addr->as_u32; + } + + /* Don't NAT packet aimed at the intfc address */ + if (PREDICT_FALSE(ip0->dst_address.as_u32 == + rt->cached_ip4_address)) + return next0; + + b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; + return SNAT_OUT2IN_NEXT_DROP; + } + + /* Create session initiated by host from external network */ + s0 = create_session_for_static_mapping(sm, b0, sm0, key0, + node, cpu_index); + if (!s0) + return SNAT_OUT2IN_NEXT_DROP; + } + else + s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, + value0.value); + + old_addr0 = ip0->dst_address.as_u32; + ip0->dst_address = s0->in2out.addr; + new_addr0 = ip0->dst_address.as_u32; + vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index; + + sum0 = ip0->checksum; + sum0 = ip_csum_update (sum0, old_addr0, new_addr0, + ip4_header_t, + dst_address /* changed member */); + ip0->checksum = ip_csum_fold (sum0); + + old_id0 = echo0->identifier; + new_id0 = s0->in2out.port; + echo0->identifier = new_id0; + + sum0 = icmp0->checksum; + sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t, + identifier); + icmp0->checksum = ip_csum_fold (sum0); + + /* Accounting */ + s0->last_heard = now; + s0->total_pkts++; + s0->total_bytes += vlib_buffer_length_in_chain (sm->vlib_main, b0); + /* Per-user LRU list maintenance for dynamic translation */ + if (!snat_is_session_static (s0)) + { + clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, + s0->per_user_index); + clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, + s0->per_user_list_head_index, + s0->per_user_index); + } + + return next0; +} + +static uword +snat_out2in_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + u32 n_left_from, * from, * to_next; + snat_out2in_next_t next_index; + u32 pkts_processed = 0; + snat_main_t * sm = &snat_main; + f64 now = vlib_time_now (vm); + u32 cpu_index = os_get_cpu_number (); + + 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 bi0, bi1; + vlib_buffer_t * b0, * b1; + u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP; + u32 next1 = SNAT_OUT2IN_NEXT_LOOKUP; + u32 sw_if_index0, sw_if_index1; + ip4_header_t * ip0, *ip1; + ip_csum_t sum0, sum1; + u32 new_addr0, old_addr0; + u16 new_port0, old_port0; + u32 new_addr1, old_addr1; + u16 new_port1, old_port1; + udp_header_t * udp0, * udp1; + tcp_header_t * tcp0, * tcp1; + icmp46_header_t * icmp0, * icmp1; + snat_session_key_t key0, key1, sm0, sm1; + u32 rx_fib_index0, rx_fib_index1; + u32 proto0, proto1; + snat_session_t * s0 = 0, * s1 = 0; + clib_bihash_kv_8_8_t kv0, kv1, value0, value1; + + /* 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); + + ip0 = vlib_buffer_get_current (b0); + udp0 = ip4_next_header (ip0); + tcp0 = (tcp_header_t *) udp0; + icmp0 = (icmp46_header_t *) udp0; + + sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; + rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, + sw_if_index0); + + proto0 = ~0; + proto0 = (ip0->protocol == IP_PROTOCOL_UDP) + ? SNAT_PROTOCOL_UDP : proto0; + proto0 = (ip0->protocol == IP_PROTOCOL_TCP) + ? SNAT_PROTOCOL_TCP : proto0; + proto0 = (ip0->protocol == IP_PROTOCOL_ICMP) + ? SNAT_PROTOCOL_ICMP : proto0; + + if (PREDICT_FALSE (proto0 == ~0)) + goto trace0; + + if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) + { + next0 = icmp_out2in_slow_path + (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, + next0, now, cpu_index); + goto trace0; + } + + key0.addr = ip0->dst_address; + key0.port = udp0->dst_port; + key0.protocol = proto0; + key0.fib_index = rx_fib_index0; + + kv0.key = key0.as_u64; + + if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0)) + { + /* Try to match static mapping by external address and port, + destination address and port in packet */ + if (snat_static_mapping_match(sm, key0, &sm0, 1)) + { + b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; + goto trace0; + } + + /* Create session initiated by host from external network */ + s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node, + cpu_index); + if (!s0) + goto trace0; + } + else + s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, + value0.value); + + old_addr0 = ip0->dst_address.as_u32; + ip0->dst_address = s0->in2out.addr; + new_addr0 = ip0->dst_address.as_u32; + vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index; + + sum0 = ip0->checksum; + sum0 = ip_csum_update (sum0, old_addr0, new_addr0, + ip4_header_t, + dst_address /* changed member */); + ip0->checksum = ip_csum_fold (sum0); + + if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) + { + old_port0 = tcp0->ports.dst; + tcp0->ports.dst = s0->in2out.port; + new_port0 = tcp0->ports.dst; + + sum0 = tcp0->checksum; + sum0 = ip_csum_update (sum0, old_addr0, new_addr0, + ip4_header_t, + dst_address /* changed member */); + + sum0 = ip_csum_update (sum0, old_port0, new_port0, + ip4_header_t /* cheat */, + length /* changed member */); + tcp0->checksum = ip_csum_fold(sum0); + } + else + { + old_port0 = udp0->dst_port; + udp0->dst_port = s0->in2out.port; + udp0->checksum = 0; + } + + /* Accounting */ + s0->last_heard = now; + s0->total_pkts++; + s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); + /* Per-user LRU list maintenance for dynamic translation */ + if (!snat_is_session_static (s0)) + { + clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, + s0->per_user_index); + clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, + s0->per_user_list_head_index, + s0->per_user_index); + } + trace0: + + if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + snat_out2in_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + t->next_index = next0; + t->session_index = ~0; + if (s0) + t->session_index = s0 - sm->per_thread_data[cpu_index].sessions; + } + + pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP; + + + ip1 = vlib_buffer_get_current (b1); + udp1 = ip4_next_header (ip1); + tcp1 = (tcp_header_t *) udp1; + icmp1 = (icmp46_header_t *) udp1; + + sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX]; + rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, + sw_if_index1); + + proto1 = ~0; + proto1 = (ip1->protocol == IP_PROTOCOL_UDP) + ? SNAT_PROTOCOL_UDP : proto1; + proto1 = (ip1->protocol == IP_PROTOCOL_TCP) + ? SNAT_PROTOCOL_TCP : proto1; + proto1 = (ip1->protocol == IP_PROTOCOL_ICMP) + ? SNAT_PROTOCOL_ICMP : proto1; + + if (PREDICT_FALSE (proto1 == ~0)) + goto trace1; + + if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP)) + { + next1 = icmp_out2in_slow_path + (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node, + next1, now, cpu_index); + goto trace1; + } + + key1.addr = ip1->dst_address; + key1.port = udp1->dst_port; + key1.protocol = proto1; + key1.fib_index = rx_fib_index1; + + kv1.key = key1.as_u64; + + if (clib_bihash_search_8_8 (&sm->out2in, &kv1, &value1)) + { + /* Try to match static mapping by external address and port, + destination address and port in packet */ + if (snat_static_mapping_match(sm, key1, &sm1, 1)) + { + b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; + goto trace1; + } + + /* Create session initiated by host from external network */ + s1 = create_session_for_static_mapping(sm, b1, sm1, key1, node, + cpu_index); + if (!s1) + goto trace1; + } + else + s1 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, + value1.value); + + old_addr1 = ip1->dst_address.as_u32; + ip1->dst_address = s1->in2out.addr; + new_addr1 = ip1->dst_address.as_u32; + vnet_buffer(b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index; + + sum1 = ip1->checksum; + sum1 = ip_csum_update (sum1, old_addr1, new_addr1, + ip4_header_t, + dst_address /* changed member */); + ip1->checksum = ip_csum_fold (sum1); + + if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP)) + { + old_port1 = tcp1->ports.dst; + tcp1->ports.dst = s1->in2out.port; + new_port1 = tcp1->ports.dst; + + sum1 = tcp1->checksum; + sum1 = ip_csum_update (sum1, old_addr1, new_addr1, + ip4_header_t, + dst_address /* changed member */); + + sum1 = ip_csum_update (sum1, old_port1, new_port1, + ip4_header_t /* cheat */, + length /* changed member */); + tcp1->checksum = ip_csum_fold(sum1); + } + else + { + old_port1 = udp1->dst_port; + udp1->dst_port = s1->in2out.port; + udp1->checksum = 0; + } + + /* Accounting */ + s1->last_heard = now; + s1->total_pkts++; + s1->total_bytes += vlib_buffer_length_in_chain (vm, b1); + /* Per-user LRU list maintenance for dynamic translation */ + if (!snat_is_session_static (s1)) + { + clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, + s1->per_user_index); + clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, + s1->per_user_list_head_index, + s1->per_user_index); + } + trace1: + + if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) + && (b1->flags & VLIB_BUFFER_IS_TRACED))) + { + snat_out2in_trace_t *t = + vlib_add_trace (vm, node, b1, sizeof (*t)); + t->sw_if_index = sw_if_index1; + t->next_index = next1; + t->session_index = ~0; + if (s1) + t->session_index = s1 - sm->per_thread_data[cpu_index].sessions; + } + + pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP; + + /* 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 = SNAT_OUT2IN_NEXT_LOOKUP; + u32 sw_if_index0; + ip4_header_t * ip0; + ip_csum_t sum0; + u32 new_addr0, old_addr0; + u16 new_port0, old_port0; + udp_header_t * udp0; + tcp_header_t * tcp0; + icmp46_header_t * icmp0; + snat_session_key_t key0, sm0; + u32 rx_fib_index0; + u32 proto0; + snat_session_t * s0 = 0; + clib_bihash_kv_8_8_t kv0, value0; + + /* 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); + + ip0 = vlib_buffer_get_current (b0); + udp0 = ip4_next_header (ip0); + tcp0 = (tcp_header_t *) udp0; + icmp0 = (icmp46_header_t *) udp0; + + sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; + rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, + sw_if_index0); + + proto0 = ~0; + proto0 = (ip0->protocol == IP_PROTOCOL_UDP) + ? SNAT_PROTOCOL_UDP : proto0; + proto0 = (ip0->protocol == IP_PROTOCOL_TCP) + ? SNAT_PROTOCOL_TCP : proto0; + proto0 = (ip0->protocol == IP_PROTOCOL_ICMP) + ? SNAT_PROTOCOL_ICMP : proto0; + + if (PREDICT_FALSE (proto0 == ~0)) + goto trace00; + + if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) + { + next0 = icmp_out2in_slow_path + (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, + next0, now, cpu_index); + goto trace00; + } + + key0.addr = ip0->dst_address; + key0.port = udp0->dst_port; + key0.protocol = proto0; + key0.fib_index = rx_fib_index0; + + kv0.key = key0.as_u64; + + if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0)) + { + /* Try to match static mapping by external address and port, + destination address and port in packet */ + if (snat_static_mapping_match(sm, key0, &sm0, 1)) + { + b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; + goto trace00; + } + + /* Create session initiated by host from external network */ + s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node, + cpu_index); + if (!s0) + goto trace00; + } + else + s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, + value0.value); + + old_addr0 = ip0->dst_address.as_u32; + ip0->dst_address = s0->in2out.addr; + new_addr0 = ip0->dst_address.as_u32; + vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index; + + sum0 = ip0->checksum; + sum0 = ip_csum_update (sum0, old_addr0, new_addr0, + ip4_header_t, + dst_address /* changed member */); + ip0->checksum = ip_csum_fold (sum0); + + if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) + { + old_port0 = tcp0->ports.dst; + tcp0->ports.dst = s0->in2out.port; + new_port0 = tcp0->ports.dst; + + sum0 = tcp0->checksum; + sum0 = ip_csum_update (sum0, old_addr0, new_addr0, + ip4_header_t, + dst_address /* changed member */); + + sum0 = ip_csum_update (sum0, old_port0, new_port0, + ip4_header_t /* cheat */, + length /* changed member */); + tcp0->checksum = ip_csum_fold(sum0); + } + else + { + old_port0 = udp0->dst_port; + udp0->dst_port = s0->in2out.port; + udp0->checksum = 0; + } + + /* Accounting */ + s0->last_heard = now; + s0->total_pkts++; + s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); + /* Per-user LRU list maintenance for dynamic translation */ + if (!snat_is_session_static (s0)) + { + clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, + s0->per_user_index); + clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, + s0->per_user_list_head_index, + s0->per_user_index); + } + trace00: + + if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + snat_out2in_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + t->next_index = next0; + t->session_index = ~0; + if (s0) + t->session_index = s0 - sm->per_thread_data[cpu_index].sessions; + } + + pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP; + + /* 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, snat_out2in_node.index, + SNAT_OUT2IN_ERROR_OUT2IN_PACKETS, + pkts_processed); + return frame->n_vectors; +} + +VLIB_REGISTER_NODE (snat_out2in_node) = { + .function = snat_out2in_node_fn, + .name = "snat-out2in", + .vector_size = sizeof (u32), + .format_trace = format_snat_out2in_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(snat_out2in_error_strings), + .error_strings = snat_out2in_error_strings, + + .runtime_data_bytes = sizeof (snat_runtime_t), + + .n_next_nodes = SNAT_OUT2IN_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [SNAT_OUT2IN_NEXT_DROP] = "error-drop", + [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup", + }, +}; +VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_node, snat_out2in_node_fn); + +static uword +snat_out2in_worker_handoff_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + snat_main_t *sm = &snat_main; + vlib_thread_main_t *tm = vlib_get_thread_main (); + u32 n_left_from, *from, *to_next = 0; + static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index; + static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index + = 0; + vlib_frame_queue_elt_t *hf = 0; + vlib_frame_t *f = 0; + int i; + u32 n_left_to_next_worker = 0, *to_next_worker = 0; + u32 next_worker_index = 0; + u32 current_worker_index = ~0; + u32 cpu_index = os_get_cpu_number (); + + ASSERT (vec_len (sm->workers)); + + if (PREDICT_FALSE (handoff_queue_elt_by_worker_index == 0)) + { + vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1); + + vec_validate_init_empty (congested_handoff_queue_by_worker_index, + sm->first_worker_index + sm->num_workers - 1, + (vlib_frame_queue_t *) (~0)); + } + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + + while (n_left_from > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 sw_if_index0; + u32 rx_fib_index0; + ip4_header_t * ip0; + udp_header_t * udp0; + snat_static_mapping_key_t key0; + clib_bihash_kv_8_8_t kv0, value0; + u8 do_handoff; + + bi0 = from[0]; + from += 1; + n_left_from -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0); + + ip0 = vlib_buffer_get_current (b0); + udp0 = ip4_next_header (ip0); + + key0.addr = ip0->dst_address; + key0.port = udp0->dst_port; + key0.fib_index = rx_fib_index0; + + kv0.key = key0.as_u64; + + /* Ever heard of of the "user" before? */ + if (clib_bihash_search_8_8 (&sm->worker_by_out, &kv0, &value0)) + { + key0.port = 0; + kv0.key = key0.as_u64; + + if (clib_bihash_search_8_8 (&sm->worker_by_out, &kv0, &value0)) + { + /* No, assign next available worker (RR) */ + next_worker_index = sm->first_worker_index + + sm->workers[sm->next_worker++ % vec_len (sm->workers)]; + } + else + { + /* Static mapping without port */ + next_worker_index = value0.value; + } + + /* Add to translated packets worker lookup */ + kv0.value = next_worker_index; + clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv0, 1); + } + else + next_worker_index = value0.value; + + if (PREDICT_FALSE (next_worker_index != cpu_index)) + { + do_handoff = 1; + + if (next_worker_index != current_worker_index) + { + if (hf) + hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker; + + hf = vlib_get_worker_handoff_queue_elt (sm->fq_out2in_index, + next_worker_index, + handoff_queue_elt_by_worker_index); + + n_left_to_next_worker = VLIB_FRAME_SIZE - hf->n_vectors; + to_next_worker = &hf->buffer_index[hf->n_vectors]; + current_worker_index = next_worker_index; + } + + /* enqueue to correct worker thread */ + to_next_worker[0] = bi0; + to_next_worker++; + n_left_to_next_worker--; + + if (n_left_to_next_worker == 0) + { + hf->n_vectors = VLIB_FRAME_SIZE; + vlib_put_frame_queue_elt (hf); + current_worker_index = ~0; + handoff_queue_elt_by_worker_index[next_worker_index] = 0; + hf = 0; + } + } + else + { + do_handoff = 0; + /* if this is 1st frame */ + if (!f) + { + f = vlib_get_frame_to_node (vm, snat_out2in_node.index); + to_next = vlib_frame_vector_args (f); + } + + to_next[0] = bi0; + to_next += 1; + f->n_vectors++; + } + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + snat_out2in_worker_handoff_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->next_worker_index = next_worker_index; + t->do_handoff = do_handoff; + } + } + + if (f) + vlib_put_frame_to_node (vm, snat_out2in_node.index, f); + + if (hf) + hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker; + + /* Ship frames to the worker nodes */ + for (i = 0; i < vec_len (handoff_queue_elt_by_worker_index); i++) + { + if (handoff_queue_elt_by_worker_index[i]) + { + hf = handoff_queue_elt_by_worker_index[i]; + /* + * It works better to let the handoff node + * rate-adapt, always ship the handoff queue element. + */ + if (1 || hf->n_vectors == hf->last_n_vectors) + { + vlib_put_frame_queue_elt (hf); + handoff_queue_elt_by_worker_index[i] = 0; + } + else + hf->last_n_vectors = hf->n_vectors; + } + congested_handoff_queue_by_worker_index[i] = + (vlib_frame_queue_t *) (~0); + } + hf = 0; + current_worker_index = ~0; + return frame->n_vectors; +} + +VLIB_REGISTER_NODE (snat_out2in_worker_handoff_node) = { + .function = snat_out2in_worker_handoff_fn, + .name = "snat-out2in-worker-handoff", + .vector_size = sizeof (u32), + .format_trace = format_snat_out2in_worker_handoff_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_next_nodes = 1, + + .next_nodes = { + [0] = "error-drop", + }, +}; + +VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_worker_handoff_node, snat_out2in_worker_handoff_fn); + +static inline u32 icmp_out2in_fast (snat_main_t *sm, + vlib_buffer_t * b0, + ip4_header_t * ip0, + icmp46_header_t * icmp0, + u32 sw_if_index0, + vlib_node_runtime_t * node, + u32 next0, + u32 rx_fib_index0) +{ + snat_session_key_t key0, sm0; + icmp_echo_header_t *echo0; + u32 new_addr0, old_addr0; + u16 old_id0, new_id0; + ip_csum_t sum0; + snat_runtime_t * rt = (snat_runtime_t *)node->runtime_data; + + echo0 = (icmp_echo_header_t *)(icmp0+1); + + key0.addr = ip0->dst_address; + key0.port = echo0->identifier; + key0.fib_index = rx_fib_index0; + + if (snat_static_mapping_match(sm, key0, &sm0, 1)) + { + ip4_address_t * first_int_addr; + + if (PREDICT_FALSE(rt->cached_sw_if_index != sw_if_index0)) + { + first_int_addr = + ip4_interface_first_address (sm->ip4_main, sw_if_index0, + 0 /* just want the address */); + rt->cached_sw_if_index = sw_if_index0; + rt->cached_ip4_address = first_int_addr->as_u32; + } + + /* Don't NAT packet aimed at the intfc address */ + if (PREDICT_FALSE(ip0->dst_address.as_u32 == + rt->cached_ip4_address)) + return next0; + + b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; + return SNAT_OUT2IN_NEXT_DROP; + } + + new_addr0 = sm0.addr.as_u32; + new_id0 = sm0.port; + vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index; + + old_addr0 = ip0->dst_address.as_u32; + ip0->dst_address.as_u32 = new_addr0; + + sum0 = ip0->checksum; + sum0 = ip_csum_update (sum0, old_addr0, new_addr0, + ip4_header_t, + dst_address /* changed member */); + ip0->checksum = ip_csum_fold (sum0); + + if (PREDICT_FALSE(new_id0 != echo0->identifier)) + { + old_id0 = echo0->identifier; + echo0->identifier = new_id0; + + sum0 = icmp0->checksum; + sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t, + identifier); + icmp0->checksum = ip_csum_fold (sum0); + } + + return next0; +} + +static uword +snat_out2in_fast_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + u32 n_left_from, * from, * to_next; + snat_out2in_next_t next_index; + u32 pkts_processed = 0; + snat_main_t * sm = &snat_main; + + 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 > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t * b0; + u32 next0 = SNAT_OUT2IN_NEXT_DROP; + u32 sw_if_index0; + ip4_header_t * ip0; + ip_csum_t sum0; + u32 new_addr0, old_addr0; + u16 new_port0, old_port0; + udp_header_t * udp0; + tcp_header_t * tcp0; + icmp46_header_t * icmp0; + snat_session_key_t key0, sm0; + u32 proto0; + u32 rx_fib_index0; + + /* 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); + + ip0 = vlib_buffer_get_current (b0); + udp0 = ip4_next_header (ip0); + tcp0 = (tcp_header_t *) udp0; + icmp0 = (icmp46_header_t *) udp0; + + sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; + rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0); + + vnet_feature_next (sw_if_index0, &next0, b0); + + proto0 = ~0; + proto0 = (ip0->protocol == IP_PROTOCOL_UDP) + ? SNAT_PROTOCOL_UDP : proto0; + proto0 = (ip0->protocol == IP_PROTOCOL_TCP) + ? SNAT_PROTOCOL_TCP : proto0; + proto0 = (ip0->protocol == IP_PROTOCOL_ICMP) + ? SNAT_PROTOCOL_ICMP : proto0; + + if (PREDICT_FALSE (proto0 == ~0)) + goto trace00; + + if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) + { + next0 = icmp_out2in_fast + (sm, b0, ip0, icmp0, sw_if_index0, node, next0, rx_fib_index0); + goto trace00; + } + + key0.addr = ip0->dst_address; + key0.port = udp0->dst_port; + key0.fib_index = rx_fib_index0; + + if (snat_static_mapping_match(sm, key0, &sm0, 1)) + { + b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; + goto trace00; + } + + new_addr0 = sm0.addr.as_u32; + new_port0 = sm0.port; + vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index; + old_addr0 = ip0->dst_address.as_u32; + ip0->dst_address.as_u32 = new_addr0; + + sum0 = ip0->checksum; + sum0 = ip_csum_update (sum0, old_addr0, new_addr0, + ip4_header_t, + dst_address /* changed member */); + ip0->checksum = ip_csum_fold (sum0); + + if (PREDICT_FALSE(new_port0 != udp0->dst_port)) + { + if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) + { + old_port0 = tcp0->ports.dst; + tcp0->ports.dst = new_port0; + + sum0 = tcp0->checksum; + sum0 = ip_csum_update (sum0, old_addr0, new_addr0, + ip4_header_t, + dst_address /* changed member */); + + sum0 = ip_csum_update (sum0, old_port0, new_port0, + ip4_header_t /* cheat */, + length /* changed member */); + tcp0->checksum = ip_csum_fold(sum0); + } + else + { + old_port0 = udp0->dst_port; + udp0->dst_port = new_port0; + udp0->checksum = 0; + } + } + else + { + if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) + { + sum0 = tcp0->checksum; + sum0 = ip_csum_update (sum0, old_addr0, new_addr0, + ip4_header_t, + dst_address /* changed member */); + + tcp0->checksum = ip_csum_fold(sum0); + } + } + + trace00: + + if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + snat_out2in_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + t->next_index = next0; + } + + pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP; + + /* 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, snat_out2in_fast_node.index, + SNAT_OUT2IN_ERROR_OUT2IN_PACKETS, + pkts_processed); + return frame->n_vectors; +} + +VLIB_REGISTER_NODE (snat_out2in_fast_node) = { + .function = snat_out2in_fast_node_fn, + .name = "snat-out2in-fast", + .vector_size = sizeof (u32), + .format_trace = format_snat_out2in_fast_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(snat_out2in_error_strings), + .error_strings = snat_out2in_error_strings, + + .runtime_data_bytes = sizeof (snat_runtime_t), + + .n_next_nodes = SNAT_OUT2IN_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup", + [SNAT_OUT2IN_NEXT_DROP] = "error-drop", + }, +}; +VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_fast_node, snat_out2in_fast_node_fn); diff --git a/src/plugins/snat/snat.api b/src/plugins/snat/snat.api new file mode 100644 index 00000000..a191eed5 --- /dev/null +++ b/src/plugins/snat/snat.api @@ -0,0 +1,283 @@ +/* + * 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. + */ +/** + * @file snat.api + * @brief VPP control-plane API messages. + * + * This file defines VPP control-plane API messages which are generally + * called through a shared memory interface. + */ + +/** \brief Add/del S-NAT address range + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param is_ip4 - 1 if address type is IPv4 + @first_ip_address - first IP address + @last_ip_address - last IP address + @is_add - 1 if add, 0 if delete +*/ +define snat_add_address_range { + u32 client_index; + u32 context; + u8 is_ip4; + u8 first_ip_address[16]; + u8 last_ip_address[16]; + u8 is_add; +}; + +/** \brief Add S-NAT address range reply + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param retval - return code +*/ +define snat_add_address_range_reply { + u32 context; + i32 retval; +}; + +/** \brief Dump S-NAT addresses + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define snat_address_dump { + u32 client_index; + u32 context; +}; + +/** \brief S-NAT address details response + @param context - sender context, to match reply w/ request + @param is_ip4 - 1 if address type is IPv4 + @param ip_address - IP address +*/ +define snat_address_details { + u32 context; + u8 is_ip4; + u8 ip_address[16]; +}; + +/** \brief Enable/disable S-NAT feature on the interface + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param is_add - 1 if add, 0 if delete + @param is_inside - 1 if inside, 0 if outside + @param sw_if_index - software index of the interface +*/ +define snat_interface_add_del_feature { + u32 client_index; + u32 context; + u8 is_add; + u8 is_inside; + u32 sw_if_index; +}; + +/** \brief Enable/disable S-NAT feature on the interface reply + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param retval - return code +*/ +define snat_interface_add_del_feature_reply { + u32 context; + i32 retval; +}; + +/** \brief Dump interfaces with S-NAT feature + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define snat_interface_dump { + u32 client_index; + u32 context; +}; + +/** \brief S-NAT interface details response + @param context - sender context, to match reply w/ request + @param is_inside - 1 if inside, 0 if outside + @param sw_if_index - software index of the interface +*/ +define snat_interface_details { + u32 context; + u8 is_inside; + u32 sw_if_index; +}; + +/** \brief Add/delete S-NAT static mapping + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param is_add - 1 if add, 0 if delete + @param is_ip4 - 1 if address type is IPv4 + @param addr_only - 1 if address only mapping + @param local_ip_address - local IP address + @param external_ip_address - external IP address + @param local_port - local port number + @param external_port - external port number + @param vfr_id - VRF ID +*/ +define snat_add_static_mapping { + u32 client_index; + u32 context; + u8 is_add; + u8 is_ip4; + u8 addr_only; + u8 local_ip_address[16]; + u8 external_ip_address[16]; + u16 local_port; + u16 external_port; + u32 vrf_id; +}; + +/** \brief Add/delete S-NAT static mapping reply + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param retval - return code +*/ +define snat_add_static_mapping_reply { + u32 context; + i32 retval; +}; + +/** \brief Dump S-NAT static mappings + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define snat_static_mapping_dump { + u32 client_index; + u32 context; +}; + +/** \brief S-NAT static mapping details response + @param context - sender context, to match reply w/ request + @param is_ip4 - 1 if address type is IPv4 + @param addr_only - 1 if address only mapping + @param local_ip_address - local IP address + @param external_ip_address - external IP address + @param local_port - local port number + @param external_port - external port number + @param vfr_id - VRF ID +*/ +define snat_static_mapping_details { + u32 context; + u8 is_ip4; + u8 addr_only; + u8 local_ip_address[16]; + u8 external_ip_address[16]; + u16 local_port; + u16 external_port; + u32 vrf_id; +}; + +/** \brief Control ping from client to api server request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define snat_control_ping +{ + u32 client_index; + u32 context; +}; + +/** \brief Control ping from the client to the server response + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param retval - return code for the request + @param vpe_pid - the pid of the vpe, returned by the server +*/ +define snat_control_ping_reply +{ + u32 context; + i32 retval; + u32 client_index; + u32 vpe_pid; +}; + +/** \brief Show S-NAT plugin startup config + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define snat_show_config +{ + u32 client_index; + u32 context; +}; + +/** \brief Show S-NAT plugin startup config reply + @param context - sender context, to match reply w/ request + @param retval - return code for the request + @param static_mapping_only - if 1 dynamic translations disabled + @param static_mapping_connection_tracking - if 1 create session data + @param translation_buckets - number of translation hash buckets + @param translation_memory_size - translation hash memory size + @param user_buckets - number of user hash buckets + @param user_memory_size - user hash memory size + @param max_translations_per_user - maximum number of translations per user + @param outside_vrf_id - outside VRF id + @param inside_vrf_id - default inside VRF id +*/ +define snat_show_config_reply +{ + u32 context; + i32 retval; + u8 static_mapping_only; + u8 static_mapping_connection_tracking; + u32 translation_buckets; + u32 translation_memory_size; + u32 user_buckets; + u32 user_memory_size; + u32 max_translations_per_user; + u32 outside_vrf_id; + u32 inside_vrf_id; +}; + +/** \brief Set S-NAT workers + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param worker_mask - S-NAT workers mask +*/ +define snat_set_workers { + u32 client_index; + u32 context; + u64 worker_mask; +}; + +/** \brief Set S-NAT workers reply + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param retval - return code +*/ +define snat_set_workers_reply { + u32 context; + i32 retval; +}; + +/** \brief Dump S-NAT workers + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define snat_worker_dump { + u32 client_index; + u32 context; +}; + +/** \brief S-NAT workers details response + @param context - sender context, to match reply w/ request + @param worker_index - worker index + @param lcore_id - lcore ID + @param name - worker name +*/ +define snat_worker_details { + u32 context; + u32 worker_index; + u32 lcore_id; + u8 name[64]; +}; diff --git a/src/plugins/snat/snat.c b/src/plugins/snat/snat.c new file mode 100644 index 00000000..bc995684 --- /dev/null +++ b/src/plugins/snat/snat.c @@ -0,0 +1,1957 @@ +/* + * snat.c - simple nat plugin + * + * 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. + */ + +#include +#include +#include +#include + +#include +#include +#include + +snat_main_t snat_main; + +/* define message IDs */ +#include + +/* define message structures */ +#define vl_typedefs +#include +#undef vl_typedefs + +/* define generated endian-swappers */ +#define vl_endianfun +#include +#undef vl_endianfun + +#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) + +/* Get the API version number */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#undef vl_api_version + +/* Macro to finish up custom dump fns */ +#define FINISH \ + vec_add1 (s, 0); \ + vl_print (handle, (char *)s); \ + vec_free (s); \ + return handle; + +/* + * 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); + +#define REPLY_MACRO2(t, body) \ +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); \ + do {body;} while (0); \ + vl_msg_api_send_shmem (q, (u8 *)&rmp); \ +} while(0); + + +/* Hook up input features */ +VNET_FEATURE_INIT (ip4_snat_in2out, static) = { + .arc_name = "ip4-unicast", + .node_name = "snat-in2out", + .runs_before = VNET_FEATURES ("snat-out2in"), +}; +VNET_FEATURE_INIT (ip4_snat_out2in, static) = { + .arc_name = "ip4-unicast", + .node_name = "snat-out2in", + .runs_before = VNET_FEATURES ("ip4-lookup"), +}; +VNET_FEATURE_INIT (ip4_snat_in2out_worker_handoff, static) = { + .arc_name = "ip4-unicast", + .node_name = "snat-in2out-worker-handoff", + .runs_before = VNET_FEATURES ("snat-out2in-worker-handoff"), +}; +VNET_FEATURE_INIT (ip4_snat_out2in_worker_handoff, static) = { + .arc_name = "ip4-unicast", + .node_name = "snat-out2in-worker-handoff", + .runs_before = VNET_FEATURES ("ip4-lookup"), +}; +VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = { + .arc_name = "ip4-unicast", + .node_name = "snat-in2out-fast", + .runs_before = VNET_FEATURES ("snat-out2in-fast"), +}; +VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = { + .arc_name = "ip4-unicast", + .node_name = "snat-out2in-fast", + .runs_before = VNET_FEATURES ("ip4-lookup"), +}; + + +/* + * 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) +{ + snat_main_t * sm = &snat_main; + clib_error_t * error = 0; + + sm->vlib_main = vm; + sm->vnet_main = h->vnet_main; + sm->ethernet_main = h->ethernet_main; + + return error; +} + +/*$$$$$ move to an installed header file */ +#if (1 || CLIB_DEBUG > 0) /* "trust, but verify" */ + +#define VALIDATE_SW_IF_INDEX(mp) \ + do { u32 __sw_if_index = ntohl(mp->sw_if_index); \ + vnet_main_t *__vnm = vnet_get_main(); \ + if (pool_is_free_index(__vnm->interface_main.sw_interfaces, \ + __sw_if_index)) { \ + rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; \ + goto bad_sw_if_index; \ + } \ +} while(0); + +#define BAD_SW_IF_INDEX_LABEL \ +do { \ +bad_sw_if_index: \ + ; \ +} while (0); + +#define VALIDATE_RX_SW_IF_INDEX(mp) \ + do { u32 __rx_sw_if_index = ntohl(mp->rx_sw_if_index); \ + vnet_main_t *__vnm = vnet_get_main(); \ + if (pool_is_free_index(__vnm->interface_main.sw_interfaces, \ + __rx_sw_if_index)) { \ + rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; \ + goto bad_rx_sw_if_index; \ + } \ +} while(0); + +#define BAD_RX_SW_IF_INDEX_LABEL \ +do { \ +bad_rx_sw_if_index: \ + ; \ +} while (0); + +#define VALIDATE_TX_SW_IF_INDEX(mp) \ + do { u32 __tx_sw_if_index = ntohl(mp->tx_sw_if_index); \ + vnet_main_t *__vnm = vnet_get_main(); \ + if (pool_is_free_index(__vnm->interface_main.sw_interfaces, \ + __tx_sw_if_index)) { \ + rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; \ + goto bad_tx_sw_if_index; \ + } \ +} while(0); + +#define BAD_TX_SW_IF_INDEX_LABEL \ +do { \ +bad_tx_sw_if_index: \ + ; \ +} while (0); + +#else + +#define VALIDATE_SW_IF_INDEX(mp) +#define BAD_SW_IF_INDEX_LABEL +#define VALIDATE_RX_SW_IF_INDEX(mp) +#define BAD_RX_SW_IF_INDEX_LABEL +#define VALIDATE_TX_SW_IF_INDEX(mp) +#define BAD_TX_SW_IF_INDEX_LABEL + +#endif /* CLIB_DEBUG > 0 */ + +void snat_add_address (snat_main_t *sm, ip4_address_t *addr) +{ + snat_address_t * ap; + + /* Check if address already exists */ + vec_foreach (ap, sm->addresses) + { + if (ap->addr.as_u32 == addr->as_u32) + return; + } + + vec_add2 (sm->addresses, ap, 1); + ap->addr = *addr; + clib_bitmap_alloc (ap->busy_port_bitmap, 65535); +} + +static int is_snat_address_used_in_static_mapping (snat_main_t *sm, + ip4_address_t addr) +{ + snat_static_mapping_t *m; + pool_foreach (m, sm->static_mappings, + ({ + if (m->external_addr.as_u32 == addr.as_u32) + return 1; + })); + + return 0; +} + +int snat_del_address (snat_main_t *sm, ip4_address_t addr) +{ + snat_address_t *a = 0; + snat_session_t *ses; + u32 *ses_to_be_removed = 0, *ses_index; + clib_bihash_kv_8_8_t kv, value; + snat_user_key_t user_key; + snat_user_t *u; + snat_main_per_thread_data_t *tsm; + + int i; + + /* Find SNAT address */ + for (i=0; i < vec_len (sm->addresses); i++) + { + if (sm->addresses[i].addr.as_u32 == addr.as_u32) + { + a = sm->addresses + i; + break; + } + } + if (!a) + return VNET_API_ERROR_NO_SUCH_ENTRY; + + /* Check if address is used in some static mapping */ + if (is_snat_address_used_in_static_mapping(sm, addr)) + { + clib_warning ("address used in static mapping"); + return VNET_API_ERROR_UNSPECIFIED; + } + + /* Delete sessions using address */ + if (a->busy_ports) + { + vec_foreach (tsm, sm->per_thread_data) + { + pool_foreach (ses, tsm->sessions, ({ + if (ses->out2in.addr.as_u32 == addr.as_u32) + { + vec_add1 (ses_to_be_removed, ses - tsm->sessions); + kv.key = ses->in2out.as_u64; + clib_bihash_add_del_8_8 (&sm->in2out, &kv, 0); + kv.key = ses->out2in.as_u64; + clib_bihash_add_del_8_8 (&sm->out2in, &kv, 0); + clib_dlist_remove (tsm->list_pool, ses->per_user_index); + user_key.addr = ses->in2out.addr; + user_key.fib_index = ses->in2out.fib_index; + kv.key = user_key.as_u64; + if (!clib_bihash_search_8_8 (&sm->user_hash, &kv, &value)) + { + u = pool_elt_at_index (tsm->users, value.value); + u->nsessions--; + } + } + })); + + vec_foreach (ses_index, ses_to_be_removed) + pool_put_index (tsm->sessions, ses_index[0]); + + vec_free (ses_to_be_removed); + } + } + + vec_del1 (sm->addresses, i); + + return 0; +} + +static void increment_v4_address (ip4_address_t * a) +{ + u32 v; + + v = clib_net_to_host_u32(a->as_u32) + 1; + a->as_u32 = clib_host_to_net_u32(v); +} + +/** + * @brief Add static mapping. + * + * Create static mapping between local addr+port and external addr+port. + * + * @param l_addr Local IPv4 address. + * @param e_addr External IPv4 address. + * @param l_port Local port number. + * @param e_port External port number. + * @param vrf_id VRF ID. + * @param addr_only If 0 address port and pair mapping, otherwise address only. + * @param is_add If 0 delete static mapping, otherwise add. + * + * @returns + */ +int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, + u16 l_port, u16 e_port, u32 vrf_id, int addr_only, + int is_add) +{ + snat_main_t * sm = &snat_main; + snat_static_mapping_t *m; + snat_static_mapping_key_t m_key; + clib_bihash_kv_8_8_t kv, value; + snat_address_t *a = 0; + u32 fib_index = ~0; + uword * p; + int i; + + /* If outside FIB index is not resolved yet */ + if (sm->outside_fib_index == ~0) + { + p = hash_get (sm->ip4_main->fib_index_by_table_id, sm->outside_vrf_id); + if (!p) + return VNET_API_ERROR_NO_SUCH_FIB; + sm->outside_fib_index = p[0]; + } + + m_key.addr = e_addr; + m_key.port = addr_only ? 0 : e_port; + m_key.fib_index = sm->outside_fib_index; + kv.key = m_key.as_u64; + if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value)) + m = 0; + else + m = pool_elt_at_index (sm->static_mappings, value.value); + + if (is_add) + { + if (m) + return VNET_API_ERROR_VALUE_EXIST; + + /* Convert VRF id to FIB index */ + if (vrf_id != ~0) + { + p = hash_get (sm->ip4_main->fib_index_by_table_id, vrf_id); + if (!p) + return VNET_API_ERROR_NO_SUCH_FIB; + fib_index = p[0]; + } + /* If not specified use inside VRF id from SNAT plugin startup config */ + else + { + if (sm->inside_fib_index == ~0) + { + p = hash_get (sm->ip4_main->fib_index_by_table_id, sm->inside_vrf_id); + if (!p) + return VNET_API_ERROR_NO_SUCH_FIB; + fib_index = p[0]; + sm->inside_fib_index = fib_index; + } + else + fib_index = sm->inside_fib_index; + + vrf_id = sm->inside_vrf_id; + } + + /* Find external address in allocated addresses and reserve port for + address and port pair mapping when dynamic translations enabled */ + if (!addr_only && !(sm->static_mapping_only)) + { + for (i = 0; i < vec_len (sm->addresses); i++) + { + if (sm->addresses[i].addr.as_u32 == e_addr.as_u32) + { + a = sm->addresses + i; + /* External port must be unused */ + if (clib_bitmap_get_no_check (a->busy_port_bitmap, e_port)) + return VNET_API_ERROR_INVALID_VALUE; + clib_bitmap_set_no_check (a->busy_port_bitmap, e_port, 1); + if (e_port > 1024) + a->busy_ports++; + + break; + } + } + /* External address must be allocated */ + if (!a) + return VNET_API_ERROR_NO_SUCH_ENTRY; + } + + pool_get (sm->static_mappings, m); + memset (m, 0, sizeof (*m)); + m->local_addr = l_addr; + m->external_addr = e_addr; + m->addr_only = addr_only; + m->vrf_id = vrf_id; + m->fib_index = fib_index; + if (!addr_only) + { + m->local_port = l_port; + m->external_port = e_port; + } + + m_key.addr = m->local_addr; + m_key.port = m->local_port; + m_key.fib_index = m->fib_index; + kv.key = m_key.as_u64; + kv.value = m - sm->static_mappings; + clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1); + + m_key.addr = m->external_addr; + m_key.port = m->external_port; + m_key.fib_index = sm->outside_fib_index; + kv.key = m_key.as_u64; + kv.value = m - sm->static_mappings; + clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1); + + /* Assign worker */ + if (sm->workers) + { + snat_user_key_t w_key0; + snat_static_mapping_key_t w_key1; + + w_key0.addr = m->local_addr; + w_key0.fib_index = m->fib_index; + kv.key = w_key0.as_u64; + + if (clib_bihash_search_8_8 (&sm->worker_by_in, &kv, &value)) + { + kv.value = sm->first_worker_index + + sm->workers[sm->next_worker++ % vec_len (sm->workers)]; + + clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv, 1); + } + else + { + kv.value = value.value; + } + + w_key1.addr = m->external_addr; + w_key1.port = clib_host_to_net_u16 (m->external_port); + w_key1.fib_index = sm->outside_fib_index; + kv.key = w_key1.as_u64; + clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv, 1); + } + } + else + { + if (!m) + return VNET_API_ERROR_NO_SUCH_ENTRY; + + /* Free external address port */ + if (!addr_only && !(sm->static_mapping_only)) + { + for (i = 0; i < vec_len (sm->addresses); i++) + { + if (sm->addresses[i].addr.as_u32 == e_addr.as_u32) + { + a = sm->addresses + i; + clib_bitmap_set_no_check (a->busy_port_bitmap, e_port, 0); + a->busy_ports--; + + break; + } + } + } + + m_key.addr = m->local_addr; + m_key.port = m->local_port; + m_key.fib_index = m->fib_index; + kv.key = m_key.as_u64; + clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0); + + m_key.addr = m->external_addr; + m_key.port = m->external_port; + m_key.fib_index = sm->outside_fib_index; + kv.key = m_key.as_u64; + clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0); + + /* Delete session(s) for static mapping if exist */ + if (!(sm->static_mapping_only) || + (sm->static_mapping_only && sm->static_mapping_connection_tracking)) + { + snat_user_key_t u_key; + snat_user_t *u; + dlist_elt_t * head, * elt; + u32 elt_index, head_index, del_elt_index; + u32 ses_index; + u64 user_index; + snat_session_t * s; + snat_main_per_thread_data_t *tsm; + + u_key.addr = m->local_addr; + u_key.fib_index = m->fib_index; + kv.key = u_key.as_u64; + if (!clib_bihash_search_8_8 (&sm->user_hash, &kv, &value)) + { + user_index = value.value; + if (!clib_bihash_search_8_8 (&sm->worker_by_in, &kv, &value)) + tsm = vec_elt_at_index (sm->per_thread_data, value.value); + else + tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); + u = pool_elt_at_index (tsm->users, user_index); + if (u->nstaticsessions) + { + head_index = u->sessions_per_user_list_head_index; + head = pool_elt_at_index (tsm->list_pool, head_index); + elt_index = head->next; + elt = pool_elt_at_index (tsm->list_pool, elt_index); + ses_index = elt->value; + while (ses_index != ~0) + { + s = pool_elt_at_index (tsm->sessions, ses_index); + del_elt_index = elt_index; + elt_index = elt->next; + elt = pool_elt_at_index (tsm->list_pool, elt_index); + ses_index = elt->value; + + if (!addr_only) + { + if ((s->out2in.addr.as_u32 != e_addr.as_u32) && + (clib_net_to_host_u16 (s->out2in.port) != e_port)) + continue; + } + + value.key = s->in2out.as_u64; + clib_bihash_add_del_8_8 (&sm->in2out, &value, 0); + value.key = s->out2in.as_u64; + clib_bihash_add_del_8_8 (&sm->out2in, &value, 0); + pool_put (tsm->sessions, s); + + clib_dlist_remove (tsm->list_pool, del_elt_index); + pool_put_index (tsm->list_pool, del_elt_index); + u->nstaticsessions--; + + if (!addr_only) + break; + } + if (addr_only) + { + pool_put (tsm->users, u); + clib_bihash_add_del_8_8 (&sm->user_hash, &kv, 0); + } + } + } + } + + /* Delete static mapping from pool */ + pool_put (sm->static_mappings, m); + } + + return 0; +} + +static int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del) +{ + snat_main_t *sm = &snat_main; + snat_interface_t *i; + const char * feature_name; + + if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)) + feature_name = is_inside ? "snat-in2out-fast" : "snat-out2in-fast"; + else + { + if (sm->num_workers > 1) + feature_name = is_inside ? "snat-in2out-worker-handoff" : "snat-out2in-worker-handoff"; + else + feature_name = is_inside ? "snat-in2out" : "snat-out2in"; + } + + vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, + !is_del, 0, 0); + + if (sm->fq_in2out_index == ~0) + sm->fq_in2out_index = vlib_frame_queue_main_init (snat_in2out_node.index, 0); + + if (sm->fq_out2in_index == ~0) + sm->fq_out2in_index = vlib_frame_queue_main_init (snat_out2in_node.index, 0); + + pool_foreach (i, sm->interfaces, + ({ + if (i->sw_if_index == sw_if_index) + { + if (is_del) + pool_put (sm->interfaces, i); + else + return VNET_API_ERROR_VALUE_EXIST; + + return 0; + } + })); + + if (is_del) + return VNET_API_ERROR_NO_SUCH_ENTRY; + + pool_get (sm->interfaces, i); + i->sw_if_index = sw_if_index; + i->is_inside = is_inside; + + return 0; +} + +static int snat_set_workers (uword * bitmap) +{ + snat_main_t *sm = &snat_main; + int i; + + if (sm->num_workers < 2) + return VNET_API_ERROR_FEATURE_DISABLED; + + if (clib_bitmap_last_set (bitmap) >= sm->num_workers) + return VNET_API_ERROR_INVALID_WORKER; + + vec_free (sm->workers); + clib_bitmap_foreach (i, bitmap, + ({ + vec_add1(sm->workers, i); + })); + + return 0; +} + +static void +vl_api_snat_add_address_range_t_handler +(vl_api_snat_add_address_range_t * mp) +{ + snat_main_t * sm = &snat_main; + vl_api_snat_add_address_range_reply_t * rmp; + ip4_address_t this_addr; + u32 start_host_order, end_host_order; + int i, count; + int rv = 0; + u32 * tmp; + + if (mp->is_ip4 != 1) + { + rv = VNET_API_ERROR_UNIMPLEMENTED; + goto send_reply; + } + + if (sm->static_mapping_only) + { + rv = VNET_API_ERROR_FEATURE_DISABLED; + goto send_reply; + } + + tmp = (u32 *) mp->first_ip_address; + start_host_order = clib_host_to_net_u32 (tmp[0]); + tmp = (u32 *) mp->last_ip_address; + end_host_order = clib_host_to_net_u32 (tmp[0]); + + count = (end_host_order - start_host_order) + 1; + + if (count > 1024) + clib_warning ("%U - %U, %d addresses...", + format_ip4_address, mp->first_ip_address, + format_ip4_address, mp->last_ip_address, + count); + + memcpy (&this_addr.as_u8, mp->first_ip_address, 4); + + for (i = 0; i < count; i++) + { + if (mp->is_add) + snat_add_address (sm, &this_addr); + else + rv = snat_del_address (sm, this_addr); + + if (rv) + goto send_reply; + + increment_v4_address (&this_addr); + } + + send_reply: + REPLY_MACRO (VL_API_SNAT_ADD_ADDRESS_RANGE_REPLY); +} + +static void *vl_api_snat_add_address_range_t_print +(vl_api_snat_add_address_range_t *mp, void * handle) +{ + u8 * s; + + s = format (0, "SCRIPT: snat_add_address_range "); + s = format (s, "%U ", format_ip4_address, mp->first_ip_address); + if (memcmp (mp->first_ip_address, mp->last_ip_address, 4)) + { + s = format (s, " - %U ", format_ip4_address, mp->last_ip_address); + } + FINISH; +} + +static void +send_snat_address_details +(snat_address_t * a, unix_shared_memory_queue_t * q, u32 context) +{ + vl_api_snat_address_details_t *rmp; + snat_main_t * sm = &snat_main; + + rmp = vl_msg_api_alloc (sizeof (*rmp)); + memset (rmp, 0, sizeof (*rmp)); + rmp->_vl_msg_id = ntohs (VL_API_SNAT_ADDRESS_DETAILS+sm->msg_id_base); + rmp->is_ip4 = 1; + clib_memcpy (rmp->ip_address, &(a->addr), 4); + rmp->context = context; + + vl_msg_api_send_shmem (q, (u8 *) & rmp); +} + +static void +vl_api_snat_address_dump_t_handler +(vl_api_snat_address_dump_t * mp) +{ + unix_shared_memory_queue_t *q; + snat_main_t * sm = &snat_main; + snat_address_t * a; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + return; + + vec_foreach (a, sm->addresses) + send_snat_address_details (a, q, mp->context); +} + +static void *vl_api_snat_address_dump_t_print +(vl_api_snat_address_dump_t *mp, void * handle) +{ + u8 *s; + + s = format (0, "SCRIPT: snat_address_dump "); + + FINISH; +} + +static void +vl_api_snat_interface_add_del_feature_t_handler +(vl_api_snat_interface_add_del_feature_t * mp) +{ + snat_main_t * sm = &snat_main; + vl_api_snat_interface_add_del_feature_reply_t * rmp; + u8 is_del = mp->is_add == 0; + u32 sw_if_index = ntohl(mp->sw_if_index); + int rv = 0; + + VALIDATE_SW_IF_INDEX(mp); + + rv = snat_interface_add_del (sw_if_index, mp->is_inside, is_del); + + BAD_SW_IF_INDEX_LABEL; + + REPLY_MACRO(VL_API_SNAT_INTERFACE_ADD_DEL_FEATURE_REPLY); +} + +static void *vl_api_snat_interface_add_del_feature_t_print +(vl_api_snat_interface_add_del_feature_t * mp, void *handle) +{ + u8 * s; + + s = format (0, "SCRIPT: snat_interface_add_del_feature "); + s = format (s, "sw_if_index %d %s %s", + clib_host_to_net_u32(mp->sw_if_index), + mp->is_inside ? "in":"out", + mp->is_add ? "" : "del"); + + FINISH; +} + +static void +send_snat_interface_details +(snat_interface_t * i, unix_shared_memory_queue_t * q, u32 context) +{ + vl_api_snat_interface_details_t *rmp; + snat_main_t * sm = &snat_main; + + rmp = vl_msg_api_alloc (sizeof (*rmp)); + memset (rmp, 0, sizeof (*rmp)); + rmp->_vl_msg_id = ntohs (VL_API_SNAT_INTERFACE_DETAILS+sm->msg_id_base); + rmp->sw_if_index = ntohl (i->sw_if_index); + rmp->is_inside = i->is_inside; + rmp->context = context; + + vl_msg_api_send_shmem (q, (u8 *) & rmp); +} + +static void +vl_api_snat_interface_dump_t_handler +(vl_api_snat_interface_dump_t * mp) +{ + unix_shared_memory_queue_t *q; + snat_main_t * sm = &snat_main; + snat_interface_t * i; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + return; + + pool_foreach (i, sm->interfaces, + ({ + send_snat_interface_details(i, q, mp->context); + })); +} + +static void *vl_api_snat_interface_dump_t_print +(vl_api_snat_interface_dump_t *mp, void * handle) +{ + u8 *s; + + s = format (0, "SCRIPT: snat_interface_dump "); + + FINISH; +}static void + +vl_api_snat_add_static_mapping_t_handler +(vl_api_snat_add_static_mapping_t * mp) +{ + snat_main_t * sm = &snat_main; + vl_api_snat_add_static_mapping_reply_t * rmp; + ip4_address_t local_addr, external_addr; + u16 local_port = 0, external_port = 0; + u32 vrf_id; + int rv = 0; + + if (mp->is_ip4 != 1) + { + rv = VNET_API_ERROR_UNIMPLEMENTED; + goto send_reply; + } + + memcpy (&local_addr.as_u8, mp->local_ip_address, 4); + memcpy (&external_addr.as_u8, mp->external_ip_address, 4); + if (mp->addr_only == 0) + { + local_port = clib_net_to_host_u16 (mp->local_port); + external_port = clib_net_to_host_u16 (mp->external_port); + } + vrf_id = clib_net_to_host_u32 (mp->vrf_id); + + rv = snat_add_static_mapping(local_addr, external_addr, local_port, + external_port, vrf_id, mp->addr_only, + mp->is_add); + + send_reply: + REPLY_MACRO (VL_API_SNAT_ADD_ADDRESS_RANGE_REPLY); +} + +static void *vl_api_snat_add_static_mapping_t_print +(vl_api_snat_add_static_mapping_t *mp, void * handle) +{ + u8 * s; + + s = format (0, "SCRIPT: snat_add_static_mapping "); + s = format (s, "local_addr %U external_addr %U ", + format_ip4_address, mp->local_ip_address, + format_ip4_address, mp->external_ip_address); + + if (mp->addr_only == 0) + s = format (s, "local_port %d external_port %d ", + clib_net_to_host_u16 (mp->local_port), + clib_net_to_host_u16 (mp->external_port)); + + if (mp->vrf_id != ~0) + s = format (s, "vrf %d", clib_net_to_host_u32 (mp->vrf_id)); + + FINISH; +} + +static void +send_snat_static_mapping_details +(snat_static_mapping_t * m, unix_shared_memory_queue_t * q, u32 context) +{ + vl_api_snat_static_mapping_details_t *rmp; + snat_main_t * sm = &snat_main; + + rmp = vl_msg_api_alloc (sizeof (*rmp)); + memset (rmp, 0, sizeof (*rmp)); + rmp->_vl_msg_id = ntohs (VL_API_SNAT_STATIC_MAPPING_DETAILS+sm->msg_id_base); + rmp->is_ip4 = 1; + rmp->addr_only = m->addr_only; + clib_memcpy (rmp->local_ip_address, &(m->local_addr), 4); + clib_memcpy (rmp->external_ip_address, &(m->external_addr), 4); + rmp->local_port = htons (m->local_port); + rmp->external_port = htons (m->external_port); + rmp->vrf_id = htonl (m->vrf_id); + rmp->context = context; + + vl_msg_api_send_shmem (q, (u8 *) & rmp); +} + +static void +vl_api_snat_static_mapping_dump_t_handler +(vl_api_snat_static_mapping_dump_t * mp) +{ + unix_shared_memory_queue_t *q; + snat_main_t * sm = &snat_main; + snat_static_mapping_t * m; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + return; + + pool_foreach (m, sm->static_mappings, + ({ + send_snat_static_mapping_details (m, q, mp->context); + })); +} + +static void *vl_api_snat_static_mapping_dump_t_print +(vl_api_snat_static_mapping_dump_t *mp, void * handle) +{ + u8 *s; + + s = format (0, "SCRIPT: snat_static_mapping_dump "); + + FINISH; +} + +static void +vl_api_snat_control_ping_t_handler +(vl_api_snat_control_ping_t * mp) +{ + vl_api_snat_control_ping_reply_t *rmp; + snat_main_t * sm = &snat_main; + int rv = 0; + + REPLY_MACRO2(VL_API_SNAT_CONTROL_PING_REPLY, + ({ + rmp->vpe_pid = ntohl (getpid()); + })); +} + +static void *vl_api_snat_control_ping_t_print +(vl_api_snat_control_ping_t *mp, void * handle) +{ + u8 *s; + + s = format (0, "SCRIPT: snat_control_ping "); + + FINISH; +} + +static void +vl_api_snat_show_config_t_handler +(vl_api_snat_show_config_t * mp) +{ + vl_api_snat_show_config_reply_t *rmp; + snat_main_t * sm = &snat_main; + int rv = 0; + + REPLY_MACRO2(VL_API_SNAT_SHOW_CONFIG_REPLY, + ({ + rmp->translation_buckets = htonl (sm->translation_buckets); + rmp->translation_memory_size = htonl (sm->translation_memory_size); + rmp->user_buckets = htonl (sm->user_buckets); + rmp->user_memory_size = htonl (sm->user_memory_size); + rmp->max_translations_per_user = htonl (sm->max_translations_per_user); + rmp->outside_vrf_id = htonl (sm->outside_vrf_id); + rmp->inside_vrf_id = htonl (sm->inside_vrf_id); + rmp->static_mapping_only = sm->static_mapping_only; + rmp->static_mapping_connection_tracking = + sm->static_mapping_connection_tracking; + })); +} + +static void *vl_api_snat_show_config_t_print +(vl_api_snat_show_config_t *mp, void * handle) +{ + u8 *s; + + s = format (0, "SCRIPT: snat_show_config "); + + FINISH; +} + +static void +vl_api_snat_set_workers_t_handler +(vl_api_snat_set_workers_t * mp) +{ + snat_main_t * sm = &snat_main; + vl_api_snat_set_workers_reply_t * rmp; + int rv = 0; + uword *bitmap = 0; + u64 mask = clib_net_to_host_u64 (mp->worker_mask); + + if (sm->num_workers < 2) + { + rv = VNET_API_ERROR_FEATURE_DISABLED; + goto send_reply; + } + + bitmap = clib_bitmap_set_multiple (bitmap, 0, mask, BITS (mask)); + rv = snat_set_workers(bitmap); + clib_bitmap_free (bitmap); + + send_reply: + REPLY_MACRO (VL_API_SNAT_SET_WORKERS_REPLY); +} + +static void *vl_api_snat_set_workers_t_print +(vl_api_snat_set_workers_t *mp, void * handle) +{ + u8 * s; + uword *bitmap = 0; + u8 first = 1; + int i; + u64 mask = clib_net_to_host_u64 (mp->worker_mask); + + s = format (0, "SCRIPT: snat_set_workers "); + bitmap = clib_bitmap_set_multiple (bitmap, 0, mask, BITS (mask)); + clib_bitmap_foreach (i, bitmap, + ({ + if (first) + s = format (s, "%d", i); + else + s = format (s, ",%d", i); + first = 0; + })); + clib_bitmap_free (bitmap); + FINISH; +} + +static void +send_snat_worker_details +(u32 worker_index, unix_shared_memory_queue_t * q, u32 context) +{ + vl_api_snat_worker_details_t *rmp; + snat_main_t * sm = &snat_main; + vlib_worker_thread_t *w = + vlib_worker_threads + worker_index + sm->first_worker_index; + + rmp = vl_msg_api_alloc (sizeof (*rmp)); + memset (rmp, 0, sizeof (*rmp)); + rmp->_vl_msg_id = ntohs (VL_API_SNAT_WORKER_DETAILS+sm->msg_id_base); + rmp->context = context; + rmp->worker_index = htonl (worker_index); + rmp->lcore_id = htonl (w->lcore_id); + strncpy ((char *) rmp->name, (char *) w->name, ARRAY_LEN (rmp->name) - 1); + + vl_msg_api_send_shmem (q, (u8 *) & rmp); +} + +static void +vl_api_snat_worker_dump_t_handler +(vl_api_snat_worker_dump_t * mp) +{ + unix_shared_memory_queue_t *q; + snat_main_t * sm = &snat_main; + u32 * worker_index; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + return; + + vec_foreach (worker_index, sm->workers) + { + send_snat_worker_details(*worker_index, q, mp->context); + } +} + +static void *vl_api_snat_worker_dump_t_print +(vl_api_snat_worker_dump_t *mp, void * handle) +{ + u8 *s; + + s = format (0, "SCRIPT: snat_worker_dump "); + + FINISH; +} + +/* List of message types that this plugin understands */ +#define foreach_snat_plugin_api_msg \ +_(SNAT_ADD_ADDRESS_RANGE, snat_add_address_range) \ +_(SNAT_INTERFACE_ADD_DEL_FEATURE, snat_interface_add_del_feature) \ +_(SNAT_ADD_STATIC_MAPPING, snat_add_static_mapping) \ +_(SNAT_CONTROL_PING, snat_control_ping) \ +_(SNAT_STATIC_MAPPING_DUMP, snat_static_mapping_dump) \ +_(SNAT_SHOW_CONFIG, snat_show_config) \ +_(SNAT_ADDRESS_DUMP, snat_address_dump) \ +_(SNAT_INTERFACE_DUMP, snat_interface_dump) \ +_(SNAT_SET_WORKERS, snat_set_workers) \ +_(SNAT_WORKER_DUMP, snat_worker_dump) + +/* Set up the API message handling tables */ +static clib_error_t * +snat_plugin_api_hookup (vlib_main_t *vm) +{ + snat_main_t * sm __attribute__ ((unused)) = &snat_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_snat_plugin_api_msg; +#undef _ + + return 0; +} + +#define vl_msg_name_crc_list +#include +#undef vl_msg_name_crc_list + +static void +setup_message_id_table (snat_main_t * sm, api_main_t * am) +{ +#define _(id,n,crc) \ + vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base); + foreach_vl_msg_name_crc_snat; +#undef _ +} + +static void plugin_custom_dump_configure (snat_main_t * sm) +{ +#define _(n,f) sm->api_main->msg_print_handlers \ + [VL_API_##n + sm->msg_id_base] \ + = (void *) vl_api_##f##_t_print; + foreach_snat_plugin_api_msg; +#undef _ +} + +static clib_error_t * snat_init (vlib_main_t * vm) +{ + snat_main_t * sm = &snat_main; + clib_error_t * error = 0; + ip4_main_t * im = &ip4_main; + ip_lookup_main_t * lm = &im->lookup_main; + u8 * name; + uword *p; + vlib_thread_registration_t *tr; + vlib_thread_main_t *tm = vlib_get_thread_main (); + uword *bitmap = 0; + u32 i; + + name = format (0, "snat_%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); + + sm->vlib_main = vm; + sm->vnet_main = vnet_get_main(); + sm->ip4_main = im; + sm->ip4_lookup_main = lm; + sm->api_main = &api_main; + sm->first_worker_index = 0; + sm->next_worker = 0; + sm->num_workers = 0; + sm->workers = 0; + sm->fq_in2out_index = ~0; + sm->fq_out2in_index = ~0; + + p = hash_get_mem (tm->thread_registrations_by_name, "workers"); + if (p) + { + tr = (vlib_thread_registration_t *) p[0]; + if (tr) + { + sm->num_workers = tr->count; + sm->first_worker_index = tr->first_index; + } + } + + /* Use all available workers by default */ + if (sm->num_workers > 1) + { + for (i=0; i < sm->num_workers; i++) + bitmap = clib_bitmap_set (bitmap, i, 1); + snat_set_workers(bitmap); + clib_bitmap_free (bitmap); + } + + error = snat_plugin_api_hookup (vm); + + /* Add our API messages to the global name_crc hash table */ + setup_message_id_table (sm, &api_main); + + plugin_custom_dump_configure (sm); + vec_free(name); + + return error; +} + +VLIB_INIT_FUNCTION (snat_init); + +void snat_free_outside_address_and_port (snat_main_t * sm, + snat_session_key_t * k, + u32 address_index) +{ + snat_address_t *a; + u16 port_host_byte_order = clib_net_to_host_u16 (k->port); + + ASSERT (address_index < vec_len (sm->addresses)); + + a = sm->addresses + address_index; + + ASSERT (clib_bitmap_get_no_check (a->busy_port_bitmap, + port_host_byte_order) == 1); + + clib_bitmap_set_no_check (a->busy_port_bitmap, port_host_byte_order, 0); + a->busy_ports--; +} + +/** + * @brief Match SNAT static mapping. + * + * @param sm SNAT main. + * @param match Address and port to match. + * @param mapping External or local address and port of the matched mapping. + * @param by_external If 0 match by local address otherwise match by external + * address. + * + * @returns 0 if match found otherwise 1. + */ +int snat_static_mapping_match (snat_main_t * sm, + snat_session_key_t match, + snat_session_key_t * mapping, + u8 by_external) +{ + clib_bihash_kv_8_8_t kv, value; + snat_static_mapping_t *m; + snat_static_mapping_key_t m_key; + clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local; + + if (by_external) + mapping_hash = &sm->static_mapping_by_external; + + m_key.addr = match.addr; + m_key.port = clib_net_to_host_u16 (match.port); + m_key.fib_index = match.fib_index; + + kv.key = m_key.as_u64; + + if (clib_bihash_search_8_8 (mapping_hash, &kv, &value)) + { + /* Try address only mapping */ + m_key.port = 0; + kv.key = m_key.as_u64; + if (clib_bihash_search_8_8 (mapping_hash, &kv, &value)) + return 1; + } + + m = pool_elt_at_index (sm->static_mappings, value.value); + + if (by_external) + { + mapping->addr = m->local_addr; + /* Address only mapping doesn't change port */ + mapping->port = m->addr_only ? match.port + : clib_host_to_net_u16 (m->local_port); + mapping->fib_index = m->fib_index; + } + else + { + mapping->addr = m->external_addr; + /* Address only mapping doesn't change port */ + mapping->port = m->addr_only ? match.port + : clib_host_to_net_u16 (m->external_port); + mapping->fib_index = sm->outside_fib_index; + } + + return 0; +} + +int snat_alloc_outside_address_and_port (snat_main_t * sm, + snat_session_key_t * k, + u32 * address_indexp) +{ + int i; + snat_address_t *a; + u32 portnum; + + for (i = 0; i < vec_len (sm->addresses); i++) + { + if (sm->addresses[i].busy_ports < (65535-1024)) + { + a = sm->addresses + i; + + while (1) + { + portnum = random_u32 (&sm->random_seed); + portnum &= 0xFFFF; + if (portnum < 1024) + continue; + if (clib_bitmap_get_no_check (a->busy_port_bitmap, portnum)) + continue; + clib_bitmap_set_no_check (a->busy_port_bitmap, portnum, 1); + a->busy_ports++; + /* Caller sets protocol and fib index */ + k->addr = a->addr; + k->port = clib_host_to_net_u16(portnum); + *address_indexp = i; + return 0; + } + } + } + /* Totally out of translations to use... */ + return 1; +} + + +static clib_error_t * +add_address_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + snat_main_t * sm = &snat_main; + ip4_address_t start_addr, end_addr, this_addr; + u32 start_host_order, end_host_order; + int i, count; + int is_add = 1; + int rv = 0; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "%U - %U", + unformat_ip4_address, &start_addr, + unformat_ip4_address, &end_addr)) + ; + else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr)) + end_addr = start_addr; + else if (unformat (line_input, "del")) + is_add = 0; + else + return clib_error_return (0, "unknown input '%U'", + format_unformat_error, input); + } + unformat_free (line_input); + + if (sm->static_mapping_only) + return clib_error_return (0, "static mapping only mode"); + + start_host_order = clib_host_to_net_u32 (start_addr.as_u32); + end_host_order = clib_host_to_net_u32 (end_addr.as_u32); + + if (end_host_order < start_host_order) + return clib_error_return (0, "end address less than start address"); + + count = (end_host_order - start_host_order) + 1; + + if (count > 1024) + clib_warning ("%U - %U, %d addresses...", + format_ip4_address, &start_addr, + format_ip4_address, &end_addr, + count); + + this_addr = start_addr; + + for (i = 0; i < count; i++) + { + if (is_add) + snat_add_address (sm, &this_addr); + else + rv = snat_del_address (sm, this_addr); + + switch (rv) + { + case VNET_API_ERROR_NO_SUCH_ENTRY: + return clib_error_return (0, "S-NAT address not exist."); + break; + case VNET_API_ERROR_UNSPECIFIED: + return clib_error_return (0, "S-NAT address used in static mapping."); + break; + default: + break; + } + + increment_v4_address (&this_addr); + } + + return 0; +} + +VLIB_CLI_COMMAND (add_address_command, static) = { + .path = "snat add address", + .short_help = "snat add addresses [- ] [del]", + .function = add_address_command_fn, +}; + +static clib_error_t * +snat_feature_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + vnet_main_t * vnm = vnet_get_main(); + clib_error_t * error = 0; + u32 sw_if_index; + u32 * inside_sw_if_indices = 0; + u32 * outside_sw_if_indices = 0; + int is_del = 0; + int i; + + sw_if_index = ~0; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "in %U", unformat_vnet_sw_interface, + vnm, &sw_if_index)) + vec_add1 (inside_sw_if_indices, sw_if_index); + else if (unformat (line_input, "out %U", unformat_vnet_sw_interface, + vnm, &sw_if_index)) + vec_add1 (outside_sw_if_indices, sw_if_index); + else if (unformat (line_input, "del")) + is_del = 1; + else + return clib_error_return (0, "unknown input '%U'", + format_unformat_error, input); + } + unformat_free (line_input); + + if (vec_len (inside_sw_if_indices)) + { + for (i = 0; i < vec_len(inside_sw_if_indices); i++) + { + sw_if_index = inside_sw_if_indices[i]; + snat_interface_add_del (sw_if_index, 1, is_del); + } + } + + if (vec_len (outside_sw_if_indices)) + { + for (i = 0; i < vec_len(outside_sw_if_indices); i++) + { + sw_if_index = outside_sw_if_indices[i]; + snat_interface_add_del (sw_if_index, 0, is_del); + } + } + + vec_free (inside_sw_if_indices); + vec_free (outside_sw_if_indices); + + return error; +} + +VLIB_CLI_COMMAND (set_interface_snat_command, static) = { + .path = "set interface snat", + .function = snat_feature_command_fn, + .short_help = "set interface snat in out [del]", +}; + +static clib_error_t * +add_static_mapping_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + clib_error_t * error = 0; + ip4_address_t l_addr, e_addr; + u32 l_port = 0, e_port = 0, vrf_id = ~0; + int is_add = 1; + int addr_only = 1; + int rv; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr, + &l_port)) + addr_only = 0; + else if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr)) + ; + else if (unformat (line_input, "external %U %u", unformat_ip4_address, + &e_addr, &e_port)) + addr_only = 0; + else if (unformat (line_input, "external %U", unformat_ip4_address, + &e_addr)) + ; + else if (unformat (line_input, "vrf %u", &vrf_id)) + ; + else if (unformat (line_input, "del")) + is_add = 0; + else + return clib_error_return (0, "unknown input: '%U'", + format_unformat_error, line_input); + } + unformat_free (line_input); + + rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port, + vrf_id, addr_only, is_add); + + switch (rv) + { + case VNET_API_ERROR_INVALID_VALUE: + return clib_error_return (0, "External port already in use."); + break; + case VNET_API_ERROR_NO_SUCH_ENTRY: + if (is_add) + return clib_error_return (0, "External addres must be allocated."); + else + return clib_error_return (0, "Mapping not exist."); + break; + case VNET_API_ERROR_NO_SUCH_FIB: + return clib_error_return (0, "No such VRF id."); + case VNET_API_ERROR_VALUE_EXIST: + return clib_error_return (0, "Mapping already exist."); + default: + break; + } + + return error; +} + +/*? + * @cliexpar + * @cliexstart{snat add static mapping} + * Static mapping allows hosts on the external network to initiate connection + * to to the local network host. + * To create static mapping between local host address 10.0.0.3 port 6303 and + * external address 4.4.4.4 port 3606 use: + * vpp# snat add static mapping local 10.0.0.3 6303 external 4.4.4.4 3606 + * If not runnig "static mapping only" S-NAT plugin mode use before: + * vpp# snat add address 4.4.4.4 + * To create static mapping between local and external address use: + * vpp# snat add static mapping local 10.0.0.3 external 4.4.4.4 + * @cliexend +?*/ +VLIB_CLI_COMMAND (add_static_mapping_command, static) = { + .path = "snat add static mapping", + .function = add_static_mapping_command_fn, + .short_help = + "snat add static mapping local [] external [] [vrf ] [del]", +}; + +static clib_error_t * +set_workers_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + uword *bitmap = 0; + int rv = 0; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap)) + ; + else + return clib_error_return (0, "unknown input '%U'", + format_unformat_error, input); + } + unformat_free (line_input); + + if (bitmap == 0) + return clib_error_return (0, "List of workers must be specified."); + + rv = snat_set_workers(bitmap); + + clib_bitmap_free (bitmap); + + switch (rv) + { + case VNET_API_ERROR_INVALID_WORKER: + return clib_error_return (0, "Invalid worker(s)."); + break; + case VNET_API_ERROR_FEATURE_DISABLED: + return clib_error_return (0, + "Supported only if 2 or more workes available."); + break; + default: + break; + } + + return 0; +} + +/*? + * @cliexpar + * @cliexstart{set snat workers} + * Set SNAT workers if 2 or more workers available, use: + * vpp# set snat workers 0-2,5 + * @cliexend +?*/ +VLIB_CLI_COMMAND (set_workers_command, static) = { + .path = "set snat workers", + .function = set_workers_command_fn, + .short_help = + "set snat workers ", +}; + +static clib_error_t * +snat_config (vlib_main_t * vm, unformat_input_t * input) +{ + snat_main_t * sm = &snat_main; + u32 translation_buckets = 1024; + u32 translation_memory_size = 128<<20; + u32 user_buckets = 128; + u32 user_memory_size = 64<<20; + u32 max_translations_per_user = 100; + u32 outside_vrf_id = 0; + u32 inside_vrf_id = 0; + u32 static_mapping_buckets = 1024; + u32 static_mapping_memory_size = 64<<20; + u8 static_mapping_only = 0; + u8 static_mapping_connection_tracking = 0; + vlib_thread_main_t *tm = vlib_get_thread_main (); + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "translation hash buckets %d", &translation_buckets)) + ; + else if (unformat (input, "translation hash memory %d", + &translation_memory_size)); + else if (unformat (input, "user hash buckets %d", &user_buckets)) + ; + else if (unformat (input, "user hash memory %d", + &user_memory_size)) + ; + else if (unformat (input, "max translations per user %d", + &max_translations_per_user)) + ; + else if (unformat (input, "outside VRF id %d", + &outside_vrf_id)) + ; + else if (unformat (input, "inside VRF id %d", + &inside_vrf_id)) + ; + else if (unformat (input, "static mapping only")) + { + static_mapping_only = 1; + if (unformat (input, "connection tracking")) + static_mapping_connection_tracking = 1; + } + else + return clib_error_return (0, "unknown input '%U'", + format_unformat_error, input); + } + + /* for show commands, etc. */ + sm->translation_buckets = translation_buckets; + sm->translation_memory_size = translation_memory_size; + sm->user_buckets = user_buckets; + sm->user_memory_size = user_memory_size; + sm->max_translations_per_user = max_translations_per_user; + sm->outside_vrf_id = outside_vrf_id; + sm->outside_fib_index = ~0; + sm->inside_vrf_id = inside_vrf_id; + sm->inside_fib_index = ~0; + sm->static_mapping_only = static_mapping_only; + sm->static_mapping_connection_tracking = static_mapping_connection_tracking; + + if (!static_mapping_only || + (static_mapping_only && static_mapping_connection_tracking)) + { + clib_bihash_init_8_8 (&sm->worker_by_in, "worker-by-in", user_buckets, + user_memory_size); + + clib_bihash_init_8_8 (&sm->worker_by_out, "worker-by-out", user_buckets, + user_memory_size); + + vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1); + + clib_bihash_init_8_8 (&sm->in2out, "in2out", translation_buckets, + translation_memory_size); + + clib_bihash_init_8_8 (&sm->out2in, "out2in", translation_buckets, + translation_memory_size); + + clib_bihash_init_8_8 (&sm->user_hash, "users", user_buckets, + user_memory_size); + } + clib_bihash_init_8_8 (&sm->static_mapping_by_local, + "static_mapping_by_local", static_mapping_buckets, + static_mapping_memory_size); + + clib_bihash_init_8_8 (&sm->static_mapping_by_external, + "static_mapping_by_external", static_mapping_buckets, + static_mapping_memory_size); + return 0; +} + +VLIB_CONFIG_FUNCTION (snat_config, "snat"); + +u8 * format_snat_key (u8 * s, va_list * args) +{ + snat_session_key_t * key = va_arg (*args, snat_session_key_t *); + char * protocol_string = "unknown"; + static char *protocol_strings[] = { + "UDP", + "TCP", + "ICMP", + }; + + if (key->protocol < ARRAY_LEN(protocol_strings)) + protocol_string = protocol_strings[key->protocol]; + + s = format (s, "%U proto %s port %d fib %d", + format_ip4_address, &key->addr, protocol_string, + clib_net_to_host_u16 (key->port), key->fib_index); + return s; +} + +u8 * format_snat_session (u8 * s, va_list * args) +{ + snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *); + snat_session_t * sess = va_arg (*args, snat_session_t *); + + s = format (s, " i2o %U\n", format_snat_key, &sess->in2out); + s = format (s, " o2i %U\n", format_snat_key, &sess->out2in); + s = format (s, " last heard %.2f\n", sess->last_heard); + s = format (s, " total pkts %d, total bytes %lld\n", + sess->total_pkts, sess->total_bytes); + if (snat_is_session_static (sess)) + s = format (s, " static translation\n"); + else + s = format (s, " dynamic translation\n"); + + return s; +} + +u8 * format_snat_user (u8 * s, va_list * args) +{ + snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *); + snat_user_t * u = va_arg (*args, snat_user_t *); + int verbose = va_arg (*args, int); + dlist_elt_t * head, * elt; + u32 elt_index, head_index; + u32 session_index; + snat_session_t * sess; + + s = format (s, "%U: %d dynamic translations, %d static translations\n", + format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions); + + if (verbose == 0) + return s; + + if (u->nsessions || u->nstaticsessions) + { + head_index = u->sessions_per_user_list_head_index; + head = pool_elt_at_index (sm->list_pool, head_index); + + elt_index = head->next; + elt = pool_elt_at_index (sm->list_pool, elt_index); + session_index = elt->value; + + while (session_index != ~0) + { + sess = pool_elt_at_index (sm->sessions, session_index); + + s = format (s, " %U\n", format_snat_session, sm, sess); + + elt_index = elt->next; + elt = pool_elt_at_index (sm->list_pool, elt_index); + session_index = elt->value; + } + } + + return s; +} + +u8 * format_snat_static_mapping (u8 * s, va_list * args) +{ + snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *); + + if (m->addr_only) + s = format (s, "local %U external %U vrf %d", + format_ip4_address, &m->local_addr, + format_ip4_address, &m->external_addr, + m->vrf_id); + else + s = format (s, "local %U:%d external %U:%d vrf %d", + format_ip4_address, &m->local_addr, m->local_port, + format_ip4_address, &m->external_addr, m->external_port, + m->vrf_id); + + return s; +} + +static clib_error_t * +show_snat_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + int verbose = 0; + snat_main_t * sm = &snat_main; + snat_user_t * u; + snat_static_mapping_t *m; + snat_interface_t *i; + snat_address_t * ap; + vnet_main_t *vnm = vnet_get_main(); + snat_main_per_thread_data_t *tsm; + u32 users_num = 0, sessions_num = 0, *worker; + uword j = 0; + + if (unformat (input, "detail")) + verbose = 1; + else if (unformat (input, "verbose")) + verbose = 2; + + if (sm->static_mapping_only) + { + if (sm->static_mapping_connection_tracking) + vlib_cli_output (vm, "SNAT mode: static mapping only connection " + "tracking"); + else + vlib_cli_output (vm, "SNAT mode: static mapping only"); + } + else + { + vlib_cli_output (vm, "SNAT mode: dynamic translations enabled"); + } + + if (verbose > 0) + { + pool_foreach (i, sm->interfaces, + ({ + vlib_cli_output (vm, "%U %s", format_vnet_sw_interface_name, vnm, + vnet_get_sw_interface (vnm, i->sw_if_index), + i->is_inside ? "in" : "out"); + })); + + vec_foreach (ap, sm->addresses) + { + u8 * s = format (0, ""); + vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr); + clib_bitmap_foreach (j, ap->busy_port_bitmap, + ({ + s = format (s, " %d", j); + })); + vlib_cli_output (vm, " %d busy ports:%v", ap->busy_ports, s); + } + } + + if (sm->num_workers > 1) + { + vlib_cli_output (vm, "%d workers", vec_len (sm->workers)); + if (verbose > 0) + { + vec_foreach (worker, sm->workers) + { + vlib_worker_thread_t *w = + vlib_worker_threads + *worker + sm->first_worker_index; + vlib_cli_output (vm, " %v", w->name); + } + } + } + + if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)) + { + vlib_cli_output (vm, "%d static mappings", + pool_elts (sm->static_mappings)); + + if (verbose > 0) + { + pool_foreach (m, sm->static_mappings, + ({ + vlib_cli_output (vm, "%U", format_snat_static_mapping, m); + })); + } + } + else + { + vec_foreach (tsm, sm->per_thread_data) + { + users_num += pool_elts (tsm->users); + sessions_num += pool_elts (tsm->sessions); + } + + vlib_cli_output (vm, "%d users, %d outside addresses, %d active sessions," + " %d static mappings", + users_num, + vec_len (sm->addresses), + sessions_num, + pool_elts (sm->static_mappings)); + + if (verbose > 0) + { + vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->in2out, + verbose - 1); + vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->out2in, + verbose - 1); + vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_in, + verbose - 1); + vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_out, + verbose - 1); + vec_foreach_index (j, sm->per_thread_data) + { + tsm = vec_elt_at_index (sm->per_thread_data, j); + + if (pool_elts (tsm->users) == 0) + continue; + + vlib_worker_thread_t *w = vlib_worker_threads + j; + vlib_cli_output (vm, "Thread %d (%v at lcore %u):", j, w->name, + w->lcore_id); + vlib_cli_output (vm, " %d list pool elements", + pool_elts (tsm->list_pool)); + + pool_foreach (u, tsm->users, + ({ + vlib_cli_output (vm, " %U", format_snat_user, tsm, u, + verbose - 1); + })); + } + + if (pool_elts (sm->static_mappings)) + { + vlib_cli_output (vm, "static mappings:"); + pool_foreach (m, sm->static_mappings, + ({ + vlib_cli_output (vm, "%U", format_snat_static_mapping, m); + })); + } + } + } + + return 0; +} + +VLIB_CLI_COMMAND (show_snat_command, static) = { + .path = "show snat", + .short_help = "show snat", + .function = show_snat_command_fn, +}; diff --git a/src/plugins/snat/snat.h b/src/plugins/snat/snat.h new file mode 100644 index 00000000..cb31dc51 --- /dev/null +++ b/src/plugins/snat/snat.h @@ -0,0 +1,259 @@ + +/* + * snat.h - simple nat definitions + * + * 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. + */ +#ifndef __included_snat_h__ +#define __included_snat_h__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Key */ +typedef struct { + union + { + struct + { + ip4_address_t addr; + u16 port; + u16 protocol:3, + fib_index:13; + }; + u64 as_u64; + }; +} snat_session_key_t; + +typedef struct { + union + { + struct + { + ip4_address_t addr; + u32 fib_index; + }; + u64 as_u64; + }; +} snat_user_key_t; + +typedef struct { + union + { + struct + { + ip4_address_t addr; + u16 port; + u16 fib_index; + }; + u64 as_u64; + }; +} snat_static_mapping_key_t; + + +typedef enum { + SNAT_PROTOCOL_UDP = 0, + SNAT_PROTOCOL_TCP, + SNAT_PROTOCOL_ICMP, +} snat_protocol_t; + + +#define SNAT_SESSION_FLAG_STATIC_MAPPING 1 + +typedef CLIB_PACKED(struct { + snat_session_key_t out2in; /* 0-15 */ + + snat_session_key_t in2out; /* 16-31 */ + + u32 flags; /* 32-35 */ + + /* per-user translations */ + u32 per_user_index; /* 36-39 */ + + u32 per_user_list_head_index; /* 40-43 */ + + /* Last heard timer */ + f64 last_heard; /* 44-51 */ + + u64 total_bytes; /* 52-59 */ + + u32 total_pkts; /* 60-63 */ + + /* Outside address */ + u32 outside_address_index; /* 64-67 */ + +}) snat_session_t; + + +typedef struct { + ip4_address_t addr; + u32 sessions_per_user_list_head_index; + u32 nsessions; + u32 nstaticsessions; +} snat_user_t; + +typedef struct { + ip4_address_t addr; + u32 busy_ports; + uword * busy_port_bitmap; +} snat_address_t; + +typedef struct { + ip4_address_t local_addr; + ip4_address_t external_addr; + u16 local_port; + u16 external_port; + u8 addr_only; + u32 vrf_id; + u32 fib_index; +} snat_static_mapping_t; + +typedef struct { + u32 sw_if_index; + u8 is_inside; +} snat_interface_t; + +typedef struct { + /* User pool */ + snat_user_t * users; + + /* Session pool */ + snat_session_t * sessions; + + /* Pool of doubly-linked list elements */ + dlist_elt_t * list_pool; +} snat_main_per_thread_data_t; + +typedef struct { + /* Main lookup tables */ + clib_bihash_8_8_t out2in; + clib_bihash_8_8_t in2out; + + /* Find-a-user => src address lookup */ + clib_bihash_8_8_t user_hash; + + /* Non-translated packets worker lookup => src address + VRF */ + clib_bihash_8_8_t worker_by_in; + + /* Translated packets worker lookup => IP address + port number */ + clib_bihash_8_8_t worker_by_out; + + u32 num_workers; + u32 first_worker_index; + u32 next_worker; + u32 * workers; + + /* Per thread data */ + snat_main_per_thread_data_t * per_thread_data; + + /* Find a static mapping by local */ + clib_bihash_8_8_t static_mapping_by_local; + + /* Find a static mapping by external */ + clib_bihash_8_8_t static_mapping_by_external; + + /* Static mapping pool */ + snat_static_mapping_t * static_mappings; + + /* Interface pool */ + snat_interface_t * interfaces; + + /* Vector of outside addresses */ + snat_address_t * addresses; + + /* Randomize port allocation order */ + u32 random_seed; + + /* Worker handoff index */ + u32 fq_in2out_index; + u32 fq_out2in_index; + + /* Config parameters */ + u8 static_mapping_only; + u8 static_mapping_connection_tracking; + u32 translation_buckets; + u32 translation_memory_size; + u32 user_buckets; + u32 user_memory_size; + u32 max_translations_per_user; + u32 outside_vrf_id; + u32 outside_fib_index; + u32 inside_vrf_id; + u32 inside_fib_index; + + /* API message ID base */ + u16 msg_id_base; + + /* convenience */ + vlib_main_t * vlib_main; + vnet_main_t * vnet_main; + ip4_main_t * ip4_main; + ip_lookup_main_t * ip4_lookup_main; + ethernet_main_t * ethernet_main; + api_main_t * api_main; +} snat_main_t; + +extern snat_main_t snat_main; +extern vlib_node_registration_t snat_in2out_node; +extern vlib_node_registration_t snat_out2in_node; +extern vlib_node_registration_t snat_in2out_fast_node; +extern vlib_node_registration_t snat_out2in_fast_node; +extern vlib_node_registration_t snat_in2out_worker_handoff_node; +extern vlib_node_registration_t snat_out2in_worker_handoff_node; + +void snat_free_outside_address_and_port (snat_main_t * sm, + snat_session_key_t * k, + u32 address_index); + +int snat_alloc_outside_address_and_port (snat_main_t * sm, + snat_session_key_t * k, + u32 * address_indexp); + +int snat_static_mapping_match (snat_main_t * sm, + snat_session_key_t match, + snat_session_key_t * mapping, + u8 by_external); + +format_function_t format_snat_user; + +typedef struct { + u32 cached_sw_if_index; + u32 cached_ip4_address; +} snat_runtime_t; + +/** \brief Check if SNAT session is created from static mapping. + @param s SNAT session + @return 1 if SNAT session is created from static mapping otherwise 0 +*/ +#define snat_is_session_static(s) s->flags & SNAT_SESSION_FLAG_STATIC_MAPPING + +/* + * Why is this here? Because we don't need to touch this layer to + * simply reply to an icmp. We need to change id to a unique + * value to NAT an echo request/reply. + */ + +typedef struct { + u16 identifier; + u16 sequence; +} icmp_echo_header_t; + +#endif /* __included_snat_h__ */ diff --git a/src/plugins/snat/snat_all_api_h.h b/src/plugins/snat/snat_all_api_h.h new file mode 100644 index 00000000..49017700 --- /dev/null +++ b/src/plugins/snat/snat_all_api_h.h @@ -0,0 +1,19 @@ + +/* + * snat_all_api_h.h - skeleton vpp engine plug-in api #include file + * + * Copyright (c) + * 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 diff --git a/src/plugins/snat/snat_msg_enum.h b/src/plugins/snat/snat_msg_enum.h new file mode 100644 index 00000000..2c76fd51 --- /dev/null +++ b/src/plugins/snat/snat_msg_enum.h @@ -0,0 +1,31 @@ + +/* + * snat_msg_enum.h - skeleton vpp engine plug-in message enumeration + * + * Copyright (c) + * 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_snat_msg_enum_h +#define included_snat_msg_enum_h + +#include + +#define vl_msg_id(n,h) n, +typedef enum { +#include + /* 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_snat_msg_enum_h */ diff --git a/src/plugins/snat/snat_test.c b/src/plugins/snat/snat_test.c new file mode 100644 index 00000000..2a003ba6 --- /dev/null +++ b/src/plugins/snat/snat_test.c @@ -0,0 +1,602 @@ + +/* + * snat.c - skeleton vpp-api-test plug-in + * + * Copyright (c) + * 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 +#include +#include +#include +#include +#include + +uword unformat_sw_if_index (unformat_input_t * input, va_list * args); + +/* Declare message IDs */ +#include + +/* define message structures */ +#define vl_typedefs +#include +#undef vl_typedefs + +/* declare message handlers for each api */ + +#define vl_endianfun /* define message structures */ +#include +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) +#define vl_printfun +#include +#undef vl_printfun + +/* Get the API version number. */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#undef vl_api_version + +typedef struct { + /* API message ID base */ + u16 msg_id_base; + vat_main_t *vat_main; +} snat_test_main_t; + +snat_test_main_t snat_test_main; + +#define foreach_standard_reply_retval_handler \ +_(snat_add_address_range_reply) \ +_(snat_interface_add_del_feature_reply) \ +_(snat_add_static_mapping_reply) \ +_(snat_set_workers_reply) + +#define _(n) \ + static void vl_api_##n##_t_handler \ + (vl_api_##n##_t * mp) \ + { \ + vat_main_t * vam = snat_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 \ +_(SNAT_ADD_ADDRESS_RANGE_REPLY, snat_add_address_range_reply) \ +_(SNAT_INTERFACE_ADD_DEL_FEATURE_REPLY, \ + snat_interface_add_del_feature_reply) \ +_(SNAT_ADD_STATIC_MAPPING_REPLY, snat_add_static_mapping_reply) \ +_(SNAT_CONTROL_PING_REPLY, snat_control_ping_reply) \ +_(SNAT_STATIC_MAPPING_DETAILS, snat_static_mapping_details) \ +_(SNAT_SHOW_CONFIG_REPLY, snat_show_config_reply) \ +_(SNAT_ADDRESS_DETAILS, snat_address_details) \ +_(SNAT_INTERFACE_DETAILS, snat_interface_details) \ +_(SNAT_SET_WORKERS_REPLY, snat_set_workers_reply) \ +_(SNAT_WORKER_DETAILS, snat_worker_details) + +/* 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_snat_add_address_range (vat_main_t * vam) +{ + snat_test_main_t * sm = &snat_test_main; + unformat_input_t * i = vam->input; + f64 timeout; + ip4_address_t start_addr, end_addr; + u32 start_host_order, end_host_order; + vl_api_snat_add_address_range_t * mp; + u8 is_add = 1; + int count; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U - %U", + unformat_ip4_address, &start_addr, + unformat_ip4_address, &end_addr)) + ; + else if (unformat (i, "%U", unformat_ip4_address, &start_addr)) + end_addr = start_addr; + else if (unformat (i, "del")) + is_add = 0; + else + { + clib_warning("unknown input '%U'", format_unformat_error, i); + return -99; + } + } + + start_host_order = clib_host_to_net_u32 (start_addr.as_u32); + end_host_order = clib_host_to_net_u32 (end_addr.as_u32); + + if (end_host_order < start_host_order) + { + errmsg ("end address less than start address\n"); + return -99; + } + + count = (end_host_order - start_host_order) + 1; + + if (count > 1024) + { + errmsg ("%U - %U, %d addresses...\n", + format_ip4_address, &start_addr, + format_ip4_address, &end_addr, + count); + } + + M(SNAT_ADD_ADDRESS_RANGE, snat_add_address_range); + + memcpy (mp->first_ip_address, &start_addr, 4); + memcpy (mp->last_ip_address, &end_addr, 4); + mp->is_ip4 = 1; + mp->is_add = is_add; + + S; W; + + /* NOTREACHED */ + return 0; +} + +static int api_snat_interface_add_del_feature (vat_main_t * vam) +{ + snat_test_main_t * sm = &snat_test_main; + unformat_input_t * i = vam->input; + f64 timeout; + vl_api_snat_interface_add_del_feature_t * mp; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 is_inside = 1; + u8 is_add = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "out")) + is_inside = 0; + else if (unformat (i, "in")) + is_inside = 1; + else if (unformat (i, "del")) + is_add = 0; + else + { + clib_warning("unknown input '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("interface / sw_if_index required\n"); + return -99; + } + + M(SNAT_INTERFACE_ADD_DEL_FEATURE, snat_interface_add_del_feature); + mp->sw_if_index = ntohl(sw_if_index); + mp->is_add = is_add; + mp->is_inside = is_inside; + + S; W; + /* NOTREACHED */ + return 0; +} + +static int api_snat_add_static_mapping(vat_main_t * vam) +{ + snat_test_main_t * sm = &snat_test_main; + unformat_input_t * i = vam->input; + f64 timeout; + vl_api_snat_add_static_mapping_t * mp; + u8 addr_set_n = 0; + u8 is_add = 1; + u8 addr_only = 1; + ip4_address_t local_addr, external_addr; + u32 local_port = 0, external_port = 0, vrf_id = ~0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "local_addr %U", unformat_ip4_address, &local_addr)) + addr_set_n++; + else if (unformat (i, "external_addr %U", unformat_ip4_address, + &external_addr)) + addr_set_n++; + else if (unformat (i, "local_port %u", &local_port)) + addr_only = 0; + else if (unformat (i, "external_port %u", &external_port)) + addr_only = 0; + else if (unformat (i, "vrf %u", &vrf_id)) + ; + else if (unformat (i, "del")) + is_add = 0; + else + { + clib_warning("unknown input '%U'", format_unformat_error, i); + return -99; + } + } + + if (addr_set_n != 2) + { + errmsg ("local_addr and remote_addr required\n"); + return -99; + } + + M(SNAT_ADD_STATIC_MAPPING, snat_add_static_mapping); + mp->is_add = is_add; + mp->is_ip4 = 1; + mp->addr_only = addr_only; + mp->local_port = ntohs ((u16) local_port); + mp->external_port = ntohs ((u16) external_port); + mp->vrf_id = ntohl (vrf_id); + memcpy (mp->local_ip_address, &local_addr, 4); + memcpy (mp->external_ip_address, &external_addr, 4); + + S; W; + /* NOTREACHED */ + return 0; +} + +static void vl_api_snat_control_ping_reply_t_handler + (vl_api_snat_control_ping_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + vam->result_ready = 1; + } +} + +static void vl_api_snat_static_mapping_details_t_handler + (vl_api_snat_static_mapping_details_t *mp) +{ + snat_test_main_t * sm = &snat_test_main; + vat_main_t *vam = sm->vat_main; + + if (mp->addr_only) + fformat (vam->ofp, "%15U%6s%15U%6s%11d\n", + format_ip4_address, &mp->local_ip_address, "", + format_ip4_address, &mp->external_ip_address, "", + ntohl (mp->vrf_id)); + else + fformat (vam->ofp, "%15U%6d%15U%6d%11d\n", + format_ip4_address, &mp->local_ip_address, + ntohs (mp->local_port), + format_ip4_address, &mp->external_ip_address, + ntohs (mp->external_port), + ntohl (mp->vrf_id)); + +} + +static int api_snat_static_mapping_dump(vat_main_t * vam) +{ + snat_test_main_t * sm = &snat_test_main; + f64 timeout; + vl_api_snat_static_mapping_dump_t * mp; + + if (vam->json_output) + { + clib_warning ("JSON output not supported for snat_static_mapping_dump"); + return -99; + } + + fformat (vam->ofp, "%21s%21s\n", "local", "external"); + fformat (vam->ofp, "%15s%6s%15s%6s%11s\n", "address", "port", "address", + "port", "vrf"); + + M(SNAT_STATIC_MAPPING_DUMP, snat_static_mapping_dump); + S; + /* Use a control ping for synchronization */ + { + vl_api_snat_control_ping_t *mp; + M (SNAT_CONTROL_PING, snat_control_ping); + S; + } + W; + /* NOTREACHED */ + return 0; +} + +static void vl_api_snat_show_config_reply_t_handler + (vl_api_snat_show_config_reply_t *mp) +{ + snat_test_main_t * sm = &snat_test_main; + vat_main_t *vam = sm->vat_main; + i32 retval = ntohl (mp->retval); + + if (retval >= 0) + { + fformat (vam->ofp, "translation hash buckets %d\n", + ntohl (mp->translation_buckets)); + fformat (vam->ofp, "translation hash memory %d\n", + ntohl (mp->translation_memory_size)); + fformat (vam->ofp, "user hash buckets %d\n", ntohl (mp->user_buckets)); + fformat (vam->ofp, "user hash memory %d\n", ntohl (mp->user_memory_size)); + fformat (vam->ofp, "max translations per user %d\n", + ntohl (mp->max_translations_per_user)); + fformat (vam->ofp, "outside VRF id %d\n", ntohl (mp->outside_vrf_id)); + fformat (vam->ofp, "inside VRF id %d\n", ntohl (mp->inside_vrf_id)); + if (mp->static_mapping_only) + { + fformat (vam->ofp, "static mapping only"); + if (mp->static_mapping_connection_tracking) + fformat (vam->ofp, " connection tracking"); + fformat (vam->ofp, "\n"); + } + } + vam->retval = retval; + vam->result_ready = 1; +} + +static int api_snat_show_config(vat_main_t * vam) +{ + snat_test_main_t * sm = &snat_test_main; + f64 timeout; + vl_api_snat_show_config_t * mp; + + if (vam->json_output) + { + clib_warning ("JSON output not supported for snat_show_config"); + return -99; + } + + M(SNAT_SHOW_CONFIG, snat_show_config); + S; W; + /* NOTREACHED */ + return 0; +} + +static void vl_api_snat_address_details_t_handler + (vl_api_snat_address_details_t *mp) +{ + snat_test_main_t * sm = &snat_test_main; + vat_main_t *vam = sm->vat_main; + + fformat (vam->ofp, "%U\n", format_ip4_address, &mp->ip_address); +} + +static int api_snat_address_dump(vat_main_t * vam) +{ + snat_test_main_t * sm = &snat_test_main; + f64 timeout; + vl_api_snat_address_dump_t * mp; + + if (vam->json_output) + { + clib_warning ("JSON output not supported for snat_address_dump"); + return -99; + } + + M(SNAT_ADDRESS_DUMP, snat_address_dump); + S; + /* Use a control ping for synchronization */ + { + vl_api_snat_control_ping_t *mp; + M (SNAT_CONTROL_PING, snat_control_ping); + S; + } + W; + /* NOTREACHED */ + return 0; +} + +static void vl_api_snat_interface_details_t_handler + (vl_api_snat_interface_details_t *mp) +{ + snat_test_main_t * sm = &snat_test_main; + vat_main_t *vam = sm->vat_main; + + fformat (vam->ofp, "sw_if_index %d %s\n", ntohl (mp->sw_if_index), + mp->is_inside ? "in" : "out"); +} + +static int api_snat_interface_dump(vat_main_t * vam) +{ + snat_test_main_t * sm = &snat_test_main; + f64 timeout; + vl_api_snat_interface_dump_t * mp; + + if (vam->json_output) + { + clib_warning ("JSON output not supported for snat_address_dump"); + return -99; + } + + M(SNAT_INTERFACE_DUMP, snat_interface_dump); + S; + /* Use a control ping for synchronization */ + { + vl_api_snat_control_ping_t *mp; + M (SNAT_CONTROL_PING, snat_control_ping); + S; + } + W; + /* NOTREACHED */ + return 0; +} + +static int api_snat_set_workers (vat_main_t * vam) +{ + snat_test_main_t * sm = &snat_test_main; + unformat_input_t * i = vam->input; + f64 timeout; + vl_api_snat_set_workers_t * mp; + uword *bitmap; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", unformat_bitmap_list, &bitmap)) + ; + else + { + clib_warning("unknown input '%U'", format_unformat_error, i); + return -99; + } + } + + M(SNAT_SET_WORKERS, snat_set_workers); + mp->worker_mask = clib_host_to_net_u64 (bitmap[0]); + + S; W; + + /* NOTREACHED */ + return 0; +} + +static void vl_api_snat_worker_details_t_handler + (vl_api_snat_worker_details_t *mp) +{ + snat_test_main_t * sm = &snat_test_main; + vat_main_t *vam = sm->vat_main; + + fformat (vam->ofp, "worker_index %d (%s at lcore %u)\n", + ntohl (mp->worker_index), mp->name, ntohl (mp->lcore_id)); +} + +static int api_snat_worker_dump(vat_main_t * vam) +{ + snat_test_main_t * sm = &snat_test_main; + f64 timeout; + vl_api_snat_worker_dump_t * mp; + + if (vam->json_output) + { + clib_warning ("JSON output not supported for snat_address_dump"); + return -99; + } + + M(SNAT_WORKER_DUMP, snat_worker_dump); + S; + /* Use a control ping for synchronization */ + { + vl_api_snat_control_ping_t *mp; + M (SNAT_CONTROL_PING, snat_control_ping); + S; + } + W; + /* NOTREACHED */ + return 0; +} + +/* + * List of messages that the api test plugin sends, + * and that the data plane plugin processes + */ +#define foreach_vpe_api_msg \ +_(snat_add_address_range, " [- | sw_if_index [in] [out] [del]") \ +_(snat_add_static_mapping, "local_addr external_addr " \ + "[local_port ] [external_port ] [vrf ] [del]") \ +_(snat_set_workers, "") \ +_(snat_static_mapping_dump, "") \ +_(snat_show_config, "") \ +_(snat_address_dump, "") \ +_(snat_interface_dump, "") \ +_(snat_worker_dump, "") + +void vat_api_hookup (vat_main_t *vam) +{ + snat_test_main_t * sm __attribute__((unused)) = &snat_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) +{ + snat_test_main_t * sm = &snat_test_main; + u8 * name; + + sm->vat_main = vam; + + /* Ask the vpp engine for the first assigned message-id */ + name = format (0, "snat_%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/src/suffix-rules.mk b/src/suffix-rules.mk index e3eeb922..f97b2276 100644 --- a/src/suffix-rules.mk +++ b/src/suffix-rules.mk @@ -18,10 +18,10 @@ @echo " APIGEN " $@ ; \ mkdir -p `dirname $@` ; \ $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ - | vppapigen --input - --output $@ --show-name $@ + | vppapigen --input - --output $@ --show-name $@ > /dev/null %.api.json: %.api - @echo " JSON APIGEN " $@ ; \ + @echo " JSON API" $@ ; \ mkdir -p `dirname $@` ; \ $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ - | vppapigen --input - --json $@ + | vppapigen --input - --json $@ > /dev/null diff --git a/src/tools/g2/configure.ac b/src/tools/g2/configure.ac deleted file mode 100644 index c8af7747..00000000 --- a/src/tools/g2/configure.ac +++ /dev/null @@ -1,12 +0,0 @@ -AC_INIT(g2, 3.0) -AM_INIT_AUTOMAKE -AM_SILENT_RULES([yes]) - -AC_CHECK_LIB([vppinfra], [clib_mem_get_page_size],, - AC_MSG_ERROR([Please install the vpp-lib package])) -AC_CHECK_HEADER([vppinfra/clib.h],, - AC_MSG_ERROR([Please install the vpp-dev package])) - -PKG_CHECK_MODULES(g2, gtk+-2.0) - -AC_OUTPUT([Makefile]) diff --git a/src/tools/perftool/configure.ac b/src/tools/perftool/configure.ac deleted file mode 100644 index f4a98697..00000000 --- a/src/tools/perftool/configure.ac +++ /dev/null @@ -1,12 +0,0 @@ -AC_INIT(perftool, 2.0) -AM_INIT_AUTOMAKE -AM_SILENT_RULES([yes]) - -AC_CHECK_LIB([vppinfra], [clib_mem_get_page_size],, - AC_MSG_ERROR([Please install the vpp-lib package])) -AC_CHECK_HEADER([vppinfra/clib.h],, - AC_MSG_ERROR([Please install the vpp-dev package])) - -AM_PROG_LIBTOOL - -AC_OUTPUT([Makefile]) diff --git a/src/tools/vppapigen/configure.ac b/src/tools/vppapigen/configure.ac deleted file mode 100644 index 16ad59d2..00000000 --- a/src/tools/vppapigen/configure.ac +++ /dev/null @@ -1,14 +0,0 @@ -# -*- Autoconf -*- -# Copyright (c) 2008 by cisco Systems, Inc. -# All rights reserved. -# Process this file with autoconf to produce a configure script. - -AC_INIT(vppapigen, 1.0) -AM_INIT_AUTOMAKE -AM_SILENT_RULES([yes]) - -# Checks for programs. -AC_PROG_CC -AC_PROG_YACC - -AC_OUTPUT([Makefile]) diff --git a/src/vpp-api/java/Makefile.am b/src/vpp-api/java/Makefile.am new file mode 100644 index 00000000..c7051ec1 --- /dev/null +++ b/src/vpp-api/java/Makefile.am @@ -0,0 +1,199 @@ +# 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. + +AUTOMAKE_OPTIONS = foreign +ACLOCAL_AMFLAGS = -I m4 + +AM_CFLAGS = -Wall -I${top_srcdir} -I${top_builddir} \ + -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux \ + -I@top_srcdir@/plugins -I@top_builddir@/plugins + +AM_LDFLAGS = -module -shared -avoid-version -rpath /none -no-undefined + +BUILT_SOURCES = +bin_PROGRAMS = +noinst_LTLIBRARIES = +JAR_FILES = +CLEANDIRS = + +# +# jvpp-common +# + +noinst_LTLIBRARIES += libjvpp_common.la +libjvpp_common_la_SOURCES = jvpp-common/jvpp_common.c +libjvpp_common_la_LDFLAGS = + +# +# jvpp-registry (connection management + plugin registry) +# + +noinst_LTLIBRARIES += libjvpp_registry.la + +libjvpp_registry_la_SOURCES = jvpp-registry/jvpp_registry.c +libjvpp_registry_la_CPPFLAGS = -Ijvpp-registry +libjvpp_registry_la_LIBAD = libjvpp_common.la + +packagedir_jvpp_registry = io/fd/vpp/jvpp +jvpp_registry_src_files := \ + $(wildcard @srcdir@/jvpp-registry/$(packagedir_jvpp_registry)/*.java) \ + $(wildcard @srcdir@/jvpp-registry/$(packagedir_jvpp_registry)/**/*.java) + +BUILT_SOURCES += jvpp-registry/io_fd_vpp_jvpp_VppJNIConnection.h +CLEANDIRS += jvpp-registry/target +JAR_FILES += jvpp-registry-$(PACKAGE_VERSION).jar + +jvpp_registry_ok = jvpp-registry/io_fd_vpp_jvpp_VppJNIConnection.h + +jvpp-registry/io_fd_vpp_jvpp_VppJNIConnection.h: $(jvpp_registry_src_files) + @echo " JAPIGEN $@" + @rm -rf jvpp-registry/target + @mkdir -p jvpp-registry/target + @$(JAVAC) -d jvpp-registry/target $^ + @$(JAVAH) -force -classpath jvpp-registry/target -d jvpp-registry io.fd.vpp.jvpp.VppJNIConnection + @$(JAVAH) -force -classpath jvpp-registry/target -d jvpp-registry io.fd.vpp.jvpp.JVppRegistryImpl + @touch jvpp-registry.ok + +define japigen + @echo " JAPIGEN $@" + @rm -rf jvpp-$(1)/target + @ @srcdir@/jvpp/gen/jvpp_gen.py --plugin_name $(1) --root_dir jvpp-$(1) \ + -i $(jvpp_$(1)_json_files) > /dev/null + @find jvpp-$(1)/target -name \*.java > jvpp-$(1).files + @$(JAVAC) -classpath jvpp-registry/target \ + -d jvpp-$(1)/target @jvpp-$(1).files + @$(JAVAH) -force \ + -classpath jvpp-registry/target:jvpp-$(1)/target \ + -d jvpp-$(1) io.fd.vpp.jvpp.$(1).$(2) +endef + +# +# jvpp-core (Java wrapper for vpe.api) +# +noinst_LTLIBRARIES += libjvpp_core.la +libjvpp_core_la_SOURCES = jvpp-core/jvpp_core.c jvpp-core/jvpp_core_gen.h +libjvpp_core_la_CPPFLAGS = -Ijvpp-registry -Ijvpp-core +BUILT_SOURCES += jvpp-core/io_fd_vpp_jvpp_core_JVppCoreImpl.h + +JAR_FILES += jvpp-core-$(PACKAGE_VERSION).jar +CLEANDIRS += jvpp-core/target +jvpp_core_json_files = $(shell find @top_builddir@/vnet/ -type f -name '*.api.json') + +jvpp-core/io_fd_vpp_jvpp_core_JVppCoreImpl.h: $(jvpp_registry_ok) $(jvpp_core_json_files) + $(call japigen,core,JVppCoreImpl) + +# +# ACL Plugin +# +if ENABLE_ACL_PLUGIN +noinst_LTLIBRARIES += libjvpp_acl.la +libjvpp_acl_la_SOURCES = jvpp-acl/jvpp_acl.c +libjvpp_acl_la_CPPFLAGS = -Ijvpp-acl + +BUILT_SOURCES += jvpp-acl/io_fd_vpp_jvpp_acl_JVppAclImpl.h + +JAR_FILES += jvpp-acl-$(PACKAGE_VERSION).jar +CLEANDIRS += jvpp-acl/target + +jvpp_acl_json_files = @top_builddir@/plugins/acl/acl.api.json + +jvpp-acl/io_fd_vpp_jvpp_acl_JVppAclImpl.h: $(jvpp_registry_ok) $(jvpp_acl_json_files) + $(call japigen,acl,JVppAclImpl) +endif + +# +# SNAT Plugin +# +if ENABLE_SNAT_PLUGIN +noinst_LTLIBRARIES += libjvpp_snat.la +libjvpp_snat_la_SOURCES = jvpp-snat/jvpp_snat.c +libjvpp_snat_la_CPPFLAGS = -Ijvpp-snat + +BUILT_SOURCES += jvpp-snat/io_fd_vpp_jvpp_snat_JVppSnatImpl.h + +JAR_FILES += jvpp-snat-$(PACKAGE_VERSION).jar +CLEANDIRS += jvpp-snat/target + +jvpp_snat_json_files = @top_builddir@/plugins/snat/snat.api.json + +jvpp-snat/io_fd_vpp_jvpp_snat_JVppSnatImpl.h: $(jvpp_registry_ok) $(jvpp_snat_json_files) + $(call japigen,snat,JVppSnatImpl) +endif + +# +# iOAM Trace Plugin +# +if ENABLE_IOAM_PLUGIN +noinst_LTLIBRARIES += libjvpp_ioamtrace.la +libjvpp_ioamtrace_la_SOURCES = jvpp-ioamtrace/jvpp_ioam_trace.c + +BUILT_SOURCES += jvpp-ioamtrace/io_fd_vpp_jvpp_ioamtrace_JVppIoamtraceImpl.h +JAR_FILES += jvpp-ioamtrace-$(PACKAGE_VERSION).jar +CLEANDIRS += jvpp-ioamtrace/target + +jvpp_ioamtrace_json_files = @top_builddir@/plugins/ioam/lib-trace/trace.api.json + +jvpp-ioamtrace/io_fd_vpp_jvpp_ioamtrace_JVppIoamtraceImpl.h: $(jvpp_registry_ok) $(jvpp_ioamtrace_json_files) + $(call japigen,ioamtrace,JVppIoamtraceImpl) + +# +# iOAM POT Plugin +# +noinst_LTLIBRARIES += libjvpp_ioampot.la +libjvpp_ioampot_la_SOURCES = jvpp-ioampot/jvpp_ioam_pot.c + +BUILT_SOURCES += jvpp-ioampot/io_fd_vpp_jvpp_ioampot_JVppIoampotImpl.h +JAR_FILES += jvpp-ioampot-$(PACKAGE_VERSION).jar +CLEANDIRS += jvpp-ioampot/target + +jvpp_ioampot_json_files = @top_builddir@/plugins/ioam/lib-pot/pot.api.json + +jvpp-ioampot/io_fd_vpp_jvpp_ioampot_JVppIoampotImpl.h: $(jvpp_registry_ok) $(jvpp_ioampot_json_files) + $(call japigen,ioampot,JVppIoampotImpl) + +# +# iOAM Export Plugin +# +noinst_LTLIBRARIES += libjvpp_ioamexport.la +libjvpp_ioamexport_la_SOURCES = jvpp-ioamexport/jvpp_ioam_export.c + +BUILT_SOURCES += jvpp-ioamexport/io_fd_vpp_jvpp_ioamexport_JVppIoamexportImpl.h +JAR_FILES += jvpp-ioamexport-$(PACKAGE_VERSION).jar +CLEANDIRS += jvpp-ioamexport/target + +jvpp_ioamexport_json_files = @top_builddir@/plugins/ioam/export/ioam_export.api.json + +jvpp-ioamexport/io_fd_vpp_jvpp_ioamexport_JVppIoamexportImpl.h: $(jvpp_registry_ok) $(jvpp_ioamexport_json_files) + $(call japigen,ioamexport,JVppIoamexportImpl) +endif + +# +# JAR creation +# +jvpp-%-$(PACKAGE_VERSION).jar: libjvpp_%.la + @echo " JAR $@" + @cp .libs/libjvpp_$*.so jvpp-$*/target + @$(JAR) cf $(JARFLAGS) $@ -C jvpp-$*/target . + +jardir = $(prefix)/share/java +jar_DATA = $(JAR_FILES) + +all-local: $(JAR_FILES) + +# +# Cleanup +# +CLEANFILES = jvpp-registry.ok $(JAR_FILES) $(BUILT_SOURCES) + +clean-local: + rm -rf $(CLEANDIRS) diff --git a/src/vpp-api/java/Readme.txt b/src/vpp-api/java/Readme.txt new file mode 100644 index 00000000..689b9b37 --- /dev/null +++ b/src/vpp-api/java/Readme.txt @@ -0,0 +1,236 @@ += JVpp + +JVpp is JNI based Java API for VPP. + +== Features +It is: + +* Asynchronous +* Fully generated +* Lightweight + +== Architecture + +=== Plugin support + + /-------------\ /--------------\ /---------------\ + | JvppPlugin1 +<-------+ JVppRegistry +--------->+ VppConnection | + \-------------/ inits \--+-----------/ uses \---------------/ + | + /-------------\ | + | JvppPlugin2 +<----------+ inits + \-------------/ | + | + ... | + | + /----------\ | + | JVppCore +<-------------+ + \----------/ + + +VppRegistry opens connection to vpp (VppConnection) and manages jvpp plugins. +Each plugin needs to be registered in the VppRegistry. Registration involves +plugin initialization (providing JNI implementation with JVppCallback reference, +vpp client identifier and vpp shared memory queue address). + +API user sends message by calling a method of appropriate plugin interface. +The call is delegated to JNI implementation provided by the particular plugin. +When JNI code receives reply, it invokes callback method of JVppCallback +that corresponds to the received message reply. + +=== JVppCore as an example of JVpp plugin architecture + + JVpp Java + + /--------------\ /----------\ /------------\ /------\ + | JVppRegistry | | JVppCore | | Callbacks | | DTOs | + \----+---------/ \----+-----/ \------+-----/ \------/ + ^ ^ ^ + | implements | implements | implements + /----+--------------\ /---+----------\ /-----+---------\ + | JVppRegistryImpl* +-------->+ JVppCoreImpl | | JVppCallback | + \-------+-----------/ inits \---+----------/ \-------+-------/ + | | ^ + | | uses | calls back + | | | +----------|--------------------------|-----------------------|--------------------- + | | | + C JNI | +-------------------+ | /-----------------\ + v | | +-->+ jvpp_core_gen.h | + /--------+--------\ | | | \-----------------/ + | jpp_registry.c* +---+ /--------+----+----\ | | | + \-----------------/ | | << shared lib >> | /-+--+---+------\ + + ->+ jvpp_common* <--------+ jvpp_core.c* | + uses \------------------/ uses \---------------/ + + +* Components marked with an asterisk contain manually crafted code, which in addition +to generated classes form jvpp. Exception applies to Callbacks and DTOs, since there are +manually crafted marker interfaces in callback and dto package (dto/JVppRequest, dto/JVppReply, +dto/JVppDump, dto/JVppReplyDump, callback/JVppCallback) + +Note: jvpp_core.c calls back the JVppCallback instance with every response. An instance of the +JVppCallback is provided to jvpp_core.c by JVppRegistryImpl on JVppCoreImpl initialization. + +Part of the JVpp is also Future facade. It is asynchronous API returning Future objects +on top of low level JVpp. It wraps dump reply messages in one DTO using control_ping message +(provided by JVppRegistry). + + +Future facade + + /----------------\ /---------------\ + | FutureJVppCore | +-->+ JVppRegistry* | + \-----+----------/ | \---------------/ + ^ | + | implements | uses + | | + /--------+-------------\ | /------------------------------\ + | FutureJVppCoreFacade +---+--->+ FutureJVppCoreFacadeCallback | + \---------+------------/ uses \-------+----------------------/ + | | +---------------|-----------------------------|------------------------------- + | uses | implements +JVpp Java | | + | | + /----------\ | | + | JVppCore +<-+ | + \----+-----/ | + ^ | + | implements v + /----+---------\ /--------+---------------\ + | JVppCoreImpl | | JVppCoreGlobalCallback | + \--------------/ \------------------------/ + + + +Another useful utility of the JVpp is Callback facade. It is asynchronous API +capable of calling specific callback instance (provided when performing a call) +per call. + + +Callback facade + + /------------------\ /---------------\ + | CallbackJVppCore | +-->+ JVppRegistry* | + \-----+------------/ | \---------------/ + ^ | + | implements | uses + | | + /--------+---------------\ | /--------------------------\ + | CallbackJVppCoreFacade +---+--->+ CallbackJVppCoreCallback | + \---------+--------------/ uses \-----+--------------------/ + | | +---------------|-----------------------------|------------------------------- + | uses | implements +JVpp Java | | + | | + /----------\ | | + | JVppCore +<-+ | + \----+-----/ | + ^ | + | implements v + /----+---------\ /----------+-------------\ + | JVppCoreImpl | | JVppCoreGlobalCallback | + \--------------/ \------------------------/ + + +== Package structure + +* *io.fd.vpp.jvpp* - top level package for generated JVpp interface+ implementation and hand-crafted +VppConnection interface + implementation - packaged as jvpp-registry-version.jar + +* *io.fd.vpp.jvpp.[plugin]* - top level package for generated JVpp interface + implementation ++ plugin's API tests - packaged as jvpp-[plugin]-version.jar + +** *dto* - package for DTOs generated from VPP API structures + base/marker hand-crafted interfaces +(in case of jvpp-registry) +** *callback* - package for low-level JVpp callbacks and a global callback interface implementing each of +the low-level JVppcallbacks +** *future* - package for future based facade on top of JVpp and callbacks +** *callfacade* - package for callback based facade on top of JVpp and callbacks. Allowing +users to provide callback per request +** *test* - package for JVpp standalone tests. Can also serve as samples for JVpp. + +C code is structured into modules: + +* *jvpp_common* - shared library that provides jvpp_main_t reference used by jvpp_registry and plugins. + +* *jvpp_registry* - native library used by JVppRegistryImpl, responsible for: + +** VPP connection open/close +** Rx thread to java thread attach +** control ping message handling + +* *jvpp_core* - native library used by jvpp core plugin: +** *jvpp_core.c* - contains hand crafted code for core plugin initialization +** *jvpp_core_gen.h* - contains generated JNI compatible handlers for all requests and replies defined in vpe.api + +== Code generators +All of the required code except the base/marker interfaces is generated using +simple python2 code generators. The generators use __defs_vpp_papi.py__ input +file produced by __vppapigen__ from vpe.api file. + +=== JNI compatible C code +Produces __jvpp_[plugin]_gen.h__ file containing JNI compatible handlers for each VPP +request and reply. + +[NOTE] +==== +Source: jvpp_c_gen.py +==== + +=== Request/Reply DTOs +For all the structures in __defs_vpp_papi.py__ a POJO DTO is produced. Logically, +there are 4 types of DTOs: + +* Request - requests that can be sent to VPP and only a single response is expected +* DumpRequest - requests that can be sent to VPP and a stream of responses is expected +* Reply - reply to a simple request or a single response from dump triggered response stream +* ReplyDump - collection of replies from a single dump request +* Notifications/Events - Not implemented yet + +[NOTE] +==== +Source: dto_gen.py +==== + +=== JVpp +Produces __JVpp.java__ and __JVppImpl.java__. This is the layer right above JNI compatible C +code. + +[NOTE] +==== +Source: jvpp_impl_gen.py +==== + +=== Callbacks +Produces callback interface for each VPP reply + a global callback interface called +__JVpp[plugin]GlobalCallback.java__ aggregating all of the callback interfaces. The JNI +compatible C code expects only a single instance of this global callback and calls +it with every reply. + +[NOTE] +==== +Source: callback_gen.py +==== + +=== Future facade +Produces an asynchronous facade on top of JVpp and callbacks, which returns a Future that provides +matching reply once VPP invocation finishes. Sources produced: +__FutureJVpp[plugin].java, FutureJVpp[plugin]Facade.java and FutureJVpp[plugin]Callback.java__ + +[NOTE] +==== +Source: jvpp_future_facade_gen.py +==== + +=== Callback facade +Similar to future facade, only this facade takes callback objects as part of the invocation +and the callback is called with result once VPP invocation finishes. Sources produced: +__CallbackJVpp[plugin].java, CallbackJVpp[plugin]Facade.java and CallbackJVpp[plugin]Callback.java__ + +[NOTE] +==== +Source: jvpp_callback_facade_gen.py +==== diff --git a/src/vpp-api/java/jvpp-acl/io/fd/vpp/jvpp/acl/test/AclExpectedDumpData.java b/src/vpp-api/java/jvpp-acl/io/fd/vpp/jvpp/acl/test/AclExpectedDumpData.java new file mode 100644 index 00000000..979edbc4 --- /dev/null +++ b/src/vpp-api/java/jvpp-acl/io/fd/vpp/jvpp/acl/test/AclExpectedDumpData.java @@ -0,0 +1,135 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.acl.test; + + +import static io.fd.vpp.jvpp.acl.test.AclTestData.FIRST_RULE_ADDRESS_2_AS_ARRAY; +import static io.fd.vpp.jvpp.acl.test.AclTestData.FIRST_RULE_ADDRESS_AS_ARRAY; +import static io.fd.vpp.jvpp.acl.test.AclTestData.FIRST_RULE_DST_ICMP_TYPE_END; +import static io.fd.vpp.jvpp.acl.test.AclTestData.FIRST_RULE_DST_ICMP_TYPE_START; +import static io.fd.vpp.jvpp.acl.test.AclTestData.FIRST_RULE_MAC; +import static io.fd.vpp.jvpp.acl.test.AclTestData.FIRST_RULE_MAC_MASK; +import static io.fd.vpp.jvpp.acl.test.AclTestData.FIRST_RULE_PREFIX; +import static io.fd.vpp.jvpp.acl.test.AclTestData.FIRST_RULE_PREFIX_2; +import static io.fd.vpp.jvpp.acl.test.AclTestData.FIRST_RULE_SRC_ICMP_TYPE_END; +import static io.fd.vpp.jvpp.acl.test.AclTestData.FIRST_RULE_SRC_ICMP_TYPE_START; +import static io.fd.vpp.jvpp.acl.test.AclTestData.ICMP_PROTOCOL; +import static io.fd.vpp.jvpp.acl.test.AclTestData.SECOND_RULE_ADDRESS_2_AS_ARRAY; +import static io.fd.vpp.jvpp.acl.test.AclTestData.SECOND_RULE_ADDRESS_AS_ARRAY; +import static io.fd.vpp.jvpp.acl.test.AclTestData.SECOND_RULE_DST_PORT_RANGE_END; +import static io.fd.vpp.jvpp.acl.test.AclTestData.SECOND_RULE_DST_PORT_RANGE_START; +import static io.fd.vpp.jvpp.acl.test.AclTestData.SECOND_RULE_MAC; +import static io.fd.vpp.jvpp.acl.test.AclTestData.SECOND_RULE_MAC_MASK; +import static io.fd.vpp.jvpp.acl.test.AclTestData.SECOND_RULE_PREFIX; +import static io.fd.vpp.jvpp.acl.test.AclTestData.SECOND_RULE_PREFIX_2; +import static io.fd.vpp.jvpp.acl.test.AclTestData.SECOND_RULE_SRC_PORT_RANGE_END; +import static io.fd.vpp.jvpp.acl.test.AclTestData.SECOND_RULE_SRC_PORT_RANGE_START; +import static io.fd.vpp.jvpp.acl.test.AclTestData.UDP_PROTOCOL; + +import io.fd.vpp.jvpp.acl.dto.AclDetails; +import io.fd.vpp.jvpp.acl.dto.AclInterfaceListDetails; +import io.fd.vpp.jvpp.acl.dto.MacipAclDetails; +import io.fd.vpp.jvpp.acl.types.AclRule; +import io.fd.vpp.jvpp.acl.types.MacipAclRule; +import java.util.Arrays; + +class AclExpectedDumpData { + + static void verifyMacIpDump(final MacipAclDetails macipAclDetails) { + // asserting data create by previous call + assertEquals(0, macipAclDetails.aclIndex); + assertEquals(2, macipAclDetails.count); + + final MacipAclRule currentIpv4Rule = macipAclDetails.r[0]; + final MacipAclRule currentIpv6Rule = macipAclDetails.r[1]; + + // Comparing one property at the time to better pointer if something is wrong + //Ipv4 rule + assertEquals(0, currentIpv4Rule.isIpv6); + assertEquals(1, currentIpv4Rule.isPermit); + + // cutting expected ipv4 to 4 bytes,vpp sends it as 16 always + assertArrays(FIRST_RULE_ADDRESS_AS_ARRAY, Arrays.copyOfRange(currentIpv4Rule.srcIpAddr, 0, 4)); + assertEquals(FIRST_RULE_PREFIX, currentIpv4Rule.srcIpPrefixLen); + assertArrays(FIRST_RULE_MAC, currentIpv4Rule.srcMac); + assertArrays(FIRST_RULE_MAC_MASK, currentIpv4Rule.srcMacMask); + + //Ipv6 rule + assertEquals(1, currentIpv6Rule.isIpv6); + assertEquals(0, currentIpv6Rule.isPermit); + assertArrays(SECOND_RULE_ADDRESS_AS_ARRAY, currentIpv6Rule.srcIpAddr); + assertEquals(SECOND_RULE_PREFIX, currentIpv6Rule.srcIpPrefixLen); + assertArrays(SECOND_RULE_MAC, currentIpv6Rule.srcMac); + assertArrays(SECOND_RULE_MAC_MASK, currentIpv6Rule.srcMacMask); + } + + static void verifyAclDump(final AclDetails aclDetails) { + assertEquals(0, aclDetails.aclIndex); + assertEquals(2, aclDetails.count); + + final AclRule currentIpv4Rule = aclDetails.r[0]; + final AclRule currentIpv6Rule = aclDetails.r[1]; + + // Comparing one property at the time to better pointer if something is wrong + //Ipv4 rule + assertEquals(0, currentIpv4Rule.isIpv6); + assertEquals(1, currentIpv4Rule.isPermit); + + // cutting expected ipv4 to 4 bytes,vpp sends it as 16 always + assertArrays(FIRST_RULE_ADDRESS_AS_ARRAY, Arrays.copyOfRange(currentIpv4Rule.srcIpAddr, 0, 4)); + assertEquals(FIRST_RULE_PREFIX, currentIpv4Rule.srcIpPrefixLen); + assertArrays(FIRST_RULE_ADDRESS_2_AS_ARRAY, Arrays.copyOfRange(currentIpv4Rule.dstIpAddr, 0, 4)); + assertEquals(FIRST_RULE_PREFIX_2, currentIpv4Rule.dstIpPrefixLen); + + assertEquals(ICMP_PROTOCOL, currentIpv4Rule.proto); + assertEquals(FIRST_RULE_SRC_ICMP_TYPE_START, currentIpv4Rule.srcportOrIcmptypeFirst); + assertEquals(FIRST_RULE_SRC_ICMP_TYPE_END, currentIpv4Rule.srcportOrIcmptypeLast); + assertEquals(FIRST_RULE_DST_ICMP_TYPE_START, currentIpv4Rule.dstportOrIcmpcodeFirst); + assertEquals(FIRST_RULE_DST_ICMP_TYPE_END, currentIpv4Rule.dstportOrIcmpcodeLast); + + assertArrays(SECOND_RULE_ADDRESS_AS_ARRAY, currentIpv6Rule.srcIpAddr); + assertEquals(SECOND_RULE_PREFIX, currentIpv6Rule.srcIpPrefixLen); + assertArrays(SECOND_RULE_ADDRESS_2_AS_ARRAY, currentIpv6Rule.dstIpAddr); + assertEquals(SECOND_RULE_PREFIX_2, currentIpv6Rule.dstIpPrefixLen); + + assertEquals(UDP_PROTOCOL, currentIpv6Rule.proto); + assertEquals(SECOND_RULE_SRC_PORT_RANGE_START, currentIpv6Rule.srcportOrIcmptypeFirst); + assertEquals(SECOND_RULE_SRC_PORT_RANGE_END, currentIpv6Rule.srcportOrIcmptypeLast); + assertEquals(SECOND_RULE_DST_PORT_RANGE_START, currentIpv6Rule.dstportOrIcmpcodeFirst); + assertEquals(SECOND_RULE_DST_PORT_RANGE_END, currentIpv6Rule.dstportOrIcmpcodeLast); + } + + static void verifyAclInterfaceList(final AclInterfaceListDetails aclInterfaceListDetails) { + assertEquals(1, aclInterfaceListDetails.count); + assertEquals(1, aclInterfaceListDetails.acls[0]); + assertEquals(0, aclInterfaceListDetails.nInput); + assertEquals(0, aclInterfaceListDetails.swIfIndex); + } + + private static void assertArrays(final byte[] expected, final byte[] actual) { + if (!Arrays.equals(expected, actual)) { + throw new IllegalArgumentException( + String.format("Expected[%s]/Actual[%s]", Arrays.toString(expected), Arrays.toString(actual))); + } + } + + private static void assertEquals(final int expected, final int actual) { + if (expected != actual) { + throw new IllegalArgumentException(String.format("Expected[%s]/Actual[%s]", expected, actual)); + } + } +} diff --git a/src/vpp-api/java/jvpp-acl/io/fd/vpp/jvpp/acl/test/AclTestData.java b/src/vpp-api/java/jvpp-acl/io/fd/vpp/jvpp/acl/test/AclTestData.java new file mode 100644 index 00000000..5d228eea --- /dev/null +++ b/src/vpp-api/java/jvpp-acl/io/fd/vpp/jvpp/acl/test/AclTestData.java @@ -0,0 +1,101 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.acl.test; + + +import io.fd.vpp.jvpp.acl.types.AclRule; +import io.fd.vpp.jvpp.acl.types.MacipAclRule; + +class AclTestData { + + static final byte[] FIRST_RULE_ADDRESS_AS_ARRAY = {-64, -88, 2, 1}; + static final byte[] FIRST_RULE_ADDRESS_2_AS_ARRAY = {-64, -88, 2, 3}; + static final byte[] SECOND_RULE_ADDRESS_AS_ARRAY = + {32, 1, 13, -72, 10, 11, 18, -16, 0, 0, 0, 0, 0, 0, 0, 1}; + static final byte[] SECOND_RULE_ADDRESS_2_AS_ARRAY = + {32, 1, 13, -72, 10, 11, 18, -16, 0, 0, 0, 0, 0, 0, 0, 1}; + static final byte[] FIRST_RULE_MAC = {11, 11, 11, 11, 11, 11}; + static final byte[] FIRST_RULE_MAC_MASK = {0, 0, 0, 0, 0, 0}; + static final byte[] SECOND_RULE_MAC = {11, 12, 11, 11, 12, 11}; + static final byte[] SECOND_RULE_MAC_MASK = {(byte) 170, 0, 0, 0, 0, 0}; + static final int FIRST_RULE_PREFIX = 32; + static final int FIRST_RULE_PREFIX_2 = 24; + static final int SECOND_RULE_PREFIX = 64; + static final int SECOND_RULE_PREFIX_2 = 62; + static final int FIRST_RULE_DST_ICMP_TYPE_START = 0; + static final int FIRST_RULE_DST_ICMP_TYPE_END = 8; + static final int FIRST_RULE_SRC_ICMP_TYPE_START = 1; + static final int FIRST_RULE_SRC_ICMP_TYPE_END = 7; + static final int ICMP_PROTOCOL = 1; + static final int SECOND_RULE_DST_PORT_RANGE_START = 2000; + static final int SECOND_RULE_DST_PORT_RANGE_END = 6000; + static final int SECOND_RULE_SRC_PORT_RANGE_START = 400; + static final int SECOND_RULE_SRC_PORT_RANGE_END = 2047; + static final int UDP_PROTOCOL = 17; + + + static MacipAclRule[] createMacipRules() { + MacipAclRule ruleOne = new MacipAclRule(); + ruleOne.isIpv6 = 0; + ruleOne.isPermit = 1; + ruleOne.srcIpAddr = FIRST_RULE_ADDRESS_AS_ARRAY; + ruleOne.srcIpPrefixLen = FIRST_RULE_PREFIX; + ruleOne.srcMac = FIRST_RULE_MAC; + ruleOne.srcMacMask = FIRST_RULE_MAC_MASK;// no mask + + MacipAclRule ruleTwo = new MacipAclRule(); + ruleTwo.isIpv6 = 1; + ruleTwo.isPermit = 0; + ruleTwo.srcIpAddr = SECOND_RULE_ADDRESS_AS_ARRAY; + ruleTwo.srcIpPrefixLen = SECOND_RULE_PREFIX; + ruleTwo.srcMac = SECOND_RULE_MAC; + ruleTwo.srcMacMask = SECOND_RULE_MAC_MASK; + + return new MacipAclRule[]{ruleOne, ruleTwo}; + } + + static AclRule[] createAclRules() { + AclRule ruleOne = new AclRule(); + + ruleOne.isIpv6 = 0; + ruleOne.isPermit = 1; + ruleOne.srcIpAddr = FIRST_RULE_ADDRESS_AS_ARRAY; + ruleOne.srcIpPrefixLen = FIRST_RULE_PREFIX; + ruleOne.dstIpAddr = FIRST_RULE_ADDRESS_2_AS_ARRAY; + ruleOne.dstIpPrefixLen = FIRST_RULE_PREFIX_2; + ruleOne.dstportOrIcmpcodeFirst = FIRST_RULE_DST_ICMP_TYPE_START; + ruleOne.dstportOrIcmpcodeLast = FIRST_RULE_DST_ICMP_TYPE_END; + ruleOne.srcportOrIcmptypeFirst = FIRST_RULE_SRC_ICMP_TYPE_START; + ruleOne.srcportOrIcmptypeLast = FIRST_RULE_SRC_ICMP_TYPE_END; + ruleOne.proto = ICMP_PROTOCOL; //ICMP + + AclRule ruleTwo = new AclRule(); + ruleTwo.isIpv6 = 1; + ruleTwo.isPermit = 0; + ruleTwo.srcIpAddr = SECOND_RULE_ADDRESS_AS_ARRAY; + ruleTwo.srcIpPrefixLen = SECOND_RULE_PREFIX; + ruleTwo.dstIpAddr = SECOND_RULE_ADDRESS_2_AS_ARRAY; + ruleTwo.dstIpPrefixLen = SECOND_RULE_PREFIX_2; + ruleTwo.dstportOrIcmpcodeFirst = SECOND_RULE_DST_PORT_RANGE_START; + ruleTwo.dstportOrIcmpcodeLast = SECOND_RULE_DST_PORT_RANGE_END; + ruleTwo.srcportOrIcmptypeFirst = SECOND_RULE_SRC_PORT_RANGE_START; + ruleTwo.srcportOrIcmptypeLast = SECOND_RULE_SRC_PORT_RANGE_END; + ruleTwo.proto = UDP_PROTOCOL; //UDP + + return new AclRule[]{ruleOne, ruleTwo}; + } +} diff --git a/src/vpp-api/java/jvpp-acl/io/fd/vpp/jvpp/acl/test/AclTestRequests.java b/src/vpp-api/java/jvpp-acl/io/fd/vpp/jvpp/acl/test/AclTestRequests.java new file mode 100644 index 00000000..b580ee8c --- /dev/null +++ b/src/vpp-api/java/jvpp-acl/io/fd/vpp/jvpp/acl/test/AclTestRequests.java @@ -0,0 +1,141 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.acl.test; + +import static io.fd.vpp.jvpp.acl.test.AclTestData.createAclRules; +import static io.fd.vpp.jvpp.acl.test.AclTestData.createMacipRules; + +import io.fd.vpp.jvpp.VppInvocationException; +import io.fd.vpp.jvpp.acl.dto.AclAddReplace; +import io.fd.vpp.jvpp.acl.dto.AclAddReplaceReply; +import io.fd.vpp.jvpp.acl.dto.AclDel; +import io.fd.vpp.jvpp.acl.dto.AclDelReply; +import io.fd.vpp.jvpp.acl.dto.AclDetailsReplyDump; +import io.fd.vpp.jvpp.acl.dto.AclDump; +import io.fd.vpp.jvpp.acl.dto.AclInterfaceListDetailsReplyDump; +import io.fd.vpp.jvpp.acl.dto.AclInterfaceListDump; +import io.fd.vpp.jvpp.acl.dto.AclInterfaceSetAclList; +import io.fd.vpp.jvpp.acl.dto.AclInterfaceSetAclListReply; +import io.fd.vpp.jvpp.acl.dto.MacipAclAdd; +import io.fd.vpp.jvpp.acl.dto.MacipAclAddReply; +import io.fd.vpp.jvpp.acl.dto.MacipAclDel; +import io.fd.vpp.jvpp.acl.dto.MacipAclDelReply; +import io.fd.vpp.jvpp.acl.dto.MacipAclDetailsReplyDump; +import io.fd.vpp.jvpp.acl.dto.MacipAclDump; +import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; +import java.util.concurrent.ExecutionException; + +class AclTestRequests { + + static MacipAclDetailsReplyDump sendMacIpDumpRequest(final FutureJVppAclFacade jvpp) + throws ExecutionException, InterruptedException { + System.out.println("Sending MacipAclDump request..."); + MacipAclDetailsReplyDump dump = jvpp.macipAclDump(new MacipAclDump()).toCompletableFuture().get(); + System.out.println("MacipAclDump returned"); + return dump; + } + + static void sendMacIpAddRequest(final FutureJVppAclFacade jvpp) throws InterruptedException, ExecutionException { + final MacipAclAdd request = createMacIpAddRequest(); + System.out.printf("Sending MacipAclAdd request %s%n", request.toString()); + final MacipAclAddReply reply = jvpp.macipAclAdd(createMacIpAddRequest()).toCompletableFuture().get(); + System.out.printf("MacipAclAdd send result = %s%n", reply); + } + + static void sendMacIpDelRequest(final FutureJVppAclFacade jvpp) throws InterruptedException, ExecutionException { + final MacipAclDel request = new MacipAclDel(); + request.aclIndex = 0; + System.out.printf("Sending MacipAclDel request %s%n", request.toString()); + final MacipAclDelReply reply = jvpp.macipAclDel(request).toCompletableFuture().get(); + System.out.printf("MacipAclDel send result = %s%n", reply); + } + + static void sendAclAddRequest(final FutureJVppAclFacade jvpp) throws InterruptedException, ExecutionException { + final AclAddReplace request = createAclAddRequest(); + System.out.printf("Sending AclAddReplace request %s%n", request.toString()); + final AclAddReplaceReply reply = jvpp.aclAddReplace(request).toCompletableFuture().get(); + System.out.printf("AclAddReplace send result = %s%n", reply); + } + + static AclDetailsReplyDump sendAclDumpRequest(final FutureJVppAclFacade jvpp) + throws InterruptedException, VppInvocationException, ExecutionException { + System.out.println("Sending AclDump request..."); + final AclDetailsReplyDump dump = jvpp.aclDump(new AclDump()).toCompletableFuture().get(); + System.out.printf("AclDump send result = %s%n", dump); + return dump; + } + + static void sendAclDelRequest(final FutureJVppAclFacade jvpp) throws InterruptedException, ExecutionException { + final AclDel request = new AclDel(); + request.aclIndex = 0; + System.out.printf("Sending AclDel request %s%n", request.toString()); + final AclDelReply reply = jvpp.aclDel(request).toCompletableFuture().get(); + System.out.printf("AclDel send result = %s%n", reply); + } + + static AclInterfaceListDetailsReplyDump sendAclInterfaceListDumpRequest(final FutureJVppAclFacade jvpp) + throws InterruptedException, ExecutionException { + final AclInterfaceListDump request = new AclInterfaceListDump(); + request.swIfIndex = 0; + System.out.printf("Sending AclInterfaceListDump request %s%n", request.toString()); + final AclInterfaceListDetailsReplyDump dump = jvpp.aclInterfaceListDump(request).toCompletableFuture().get(); + System.out.printf("AclInterfaceListDump send result = %s%n", dump); + return dump; + } + + static void sendAclInterfaceSetAclList(final FutureJVppAclFacade jvpp) + throws InterruptedException, ExecutionException { + final AclInterfaceSetAclList request = new AclInterfaceSetAclList(); + request.count = 1; + request.acls = new int[]{1}; + request.swIfIndex = 0; + request.nInput = 0; + System.out.printf("Sending AclInterfaceSetAclList request %s%n", request.toString()); + final AclInterfaceSetAclListReply reply = jvpp.aclInterfaceSetAclList(request).toCompletableFuture().get(); + System.out.printf("AclInterfaceSetAclList send result = %s%n", reply); + } + + static void sendAclInterfaceDeleteList(final FutureJVppAclFacade jvpp) + throws InterruptedException, ExecutionException { + // uses same api but sets list to empty + final AclInterfaceSetAclList request = new AclInterfaceSetAclList(); + request.count = 0; + request.acls = new int[]{}; + request.swIfIndex = 0; + request.nInput = 0; + System.out.printf("Sending AclInterfaceSetAclList(Delete) request %s%n", request.toString()); + final AclInterfaceSetAclListReply reply = jvpp.aclInterfaceSetAclList(request).toCompletableFuture().get(); + System.out.printf("AclInterfaceSetAclList(Delete) send result = %s%n", reply); + } + + private static MacipAclAdd createMacIpAddRequest() { + MacipAclAdd request = new MacipAclAdd(); + + request.count = 2; + request.r = createMacipRules(); + return request; + } + + private static AclAddReplace createAclAddRequest() { + AclAddReplace request = new AclAddReplace(); + + request.aclIndex = -1;// to define new one + request.count = 2; + request.r = createAclRules(); + return request; + } +} diff --git a/src/vpp-api/java/jvpp-acl/io/fd/vpp/jvpp/acl/test/FutureApiTest.java b/src/vpp-api/java/jvpp-acl/io/fd/vpp/jvpp/acl/test/FutureApiTest.java new file mode 100644 index 00000000..94490193 --- /dev/null +++ b/src/vpp-api/java/jvpp-acl/io/fd/vpp/jvpp/acl/test/FutureApiTest.java @@ -0,0 +1,68 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.acl.test; + +import static io.fd.vpp.jvpp.acl.test.AclExpectedDumpData.verifyAclDump; +import static io.fd.vpp.jvpp.acl.test.AclExpectedDumpData.verifyAclInterfaceList; +import static io.fd.vpp.jvpp.acl.test.AclExpectedDumpData.verifyMacIpDump; +import static io.fd.vpp.jvpp.acl.test.AclTestRequests.sendAclAddRequest; +import static io.fd.vpp.jvpp.acl.test.AclTestRequests.sendAclDelRequest; +import static io.fd.vpp.jvpp.acl.test.AclTestRequests.sendAclDumpRequest; +import static io.fd.vpp.jvpp.acl.test.AclTestRequests.sendAclInterfaceDeleteList; +import static io.fd.vpp.jvpp.acl.test.AclTestRequests.sendAclInterfaceListDumpRequest; +import static io.fd.vpp.jvpp.acl.test.AclTestRequests.sendAclInterfaceSetAclList; +import static io.fd.vpp.jvpp.acl.test.AclTestRequests.sendMacIpAddRequest; +import static io.fd.vpp.jvpp.acl.test.AclTestRequests.sendMacIpDelRequest; +import static io.fd.vpp.jvpp.acl.test.AclTestRequests.sendMacIpDumpRequest; + +import io.fd.vpp.jvpp.JVppRegistry; +import io.fd.vpp.jvpp.JVppRegistryImpl; +import io.fd.vpp.jvpp.acl.JVppAclImpl; +import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; + +public class FutureApiTest { + + public static void main(String[] args) throws Exception { + testCallbackApi(); + } + + private static void testCallbackApi() throws Exception { + System.out.println("Testing Java callback API for acl plugin"); + try (final JVppRegistry registry = new JVppRegistryImpl("macipAclAddTest"); + final FutureJVppAclFacade jvpp = new FutureJVppAclFacade(registry, new JVppAclImpl())) { + + // adds,dump and verifies Mac-Ip acl + sendMacIpAddRequest(jvpp); + verifyMacIpDump(sendMacIpDumpRequest(jvpp).macipAclDetails.get(0)); + + // adds,dumps and verifies Acl acl + sendAclAddRequest(jvpp); + verifyAclDump(sendAclDumpRequest(jvpp).aclDetails.get(0)); + + // adds,dumps and verifies Interface for acl + sendAclInterfaceSetAclList(jvpp); + verifyAclInterfaceList(sendAclInterfaceListDumpRequest(jvpp).aclInterfaceListDetails.get(0)); + + // deletes all created data + sendAclInterfaceDeleteList(jvpp); + sendAclDelRequest(jvpp); + sendMacIpDelRequest(jvpp); + + System.out.println("Disconnecting..."); + } + } +} diff --git a/src/vpp-api/java/jvpp-acl/io/fd/vpp/jvpp/acl/test/Readme.txt b/src/vpp-api/java/jvpp-acl/io/fd/vpp/jvpp/acl/test/Readme.txt new file mode 100644 index 00000000..f68e7aba --- /dev/null +++ b/src/vpp-api/java/jvpp-acl/io/fd/vpp/jvpp/acl/test/Readme.txt @@ -0,0 +1 @@ +sudo java -cp build-vpp-native/vpp-api/java/jvpp-registry-17.01.jar:build-vpp-native/plugins/acl-plugin/jvpp-acl-1.0.jar io.fd.vpp.jvpp.acl.test.FutureApiTest diff --git a/src/vpp-api/java/jvpp-acl/jvpp_acl.c b/src/vpp-api/java/jvpp-acl/jvpp_acl.c new file mode 100644 index 00000000..d56abe3d --- /dev/null +++ b/src/vpp-api/java/jvpp-acl/jvpp_acl.c @@ -0,0 +1,124 @@ +/* + * 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. + */ + +#include + +#include +#define vl_typedefs /* define message structures */ +#include +#undef vl_typedefs + +#define vl_endianfun +#include +#undef vl_endianfun + +#define vl_print(handle, ...) +#define vl_printfun +#include +#undef vl_printfun + +/* Get the API version number */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#undef vl_api_version + +#include +#include +#include + +#if VPPJNI_DEBUG == 1 + #define DEBUG_LOG(...) clib_warning(__VA_ARGS__) +#else + #define DEBUG_LOG(...) +#endif + +#include + +#include "jvpp-acl/io_fd_vpp_jvpp_acl_JVppAclImpl.h" +#include "jvpp_acl.h" +#include "jvpp-acl/jvpp_acl_gen.h" + +/* + * Class: io_fd_vpp_jvpp_acl_JVppaclImpl + * Method: init0 + * Signature: (JI)V + */ +JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_acl_JVppAclImpl_init0 + (JNIEnv *env, jclass clazz, jobject callback, jlong queue_address, jint my_client_index) { + acl_main_t * plugin_main = &acl_main; + u8 * name; + clib_warning ("Java_io_fd_vpp_jvpp_acl_JVppAclImpl_init0"); + + plugin_main->my_client_index = my_client_index; + plugin_main->vl_input_queue = (unix_shared_memory_queue_t *)queue_address; + + name = format (0, "acl_%08x%c", api_version, 0); + plugin_main->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name); + + if (plugin_main->msg_id_base == (u16) ~0) { + jclass exClass = (*env)->FindClass(env, "java/lang/IllegalStateException"); + (*env)->ThrowNew(env, exClass, "acl plugin is not loaded in VPP"); + } else { + plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback); + plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback)); + + #define _(N,n) \ + vl_msg_api_set_handlers(VL_API_##N + plugin_main->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_api_reply_handler; + #undef _ + } +} + +JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_acl_JVppAclImpl_close0 +(JNIEnv *env, jclass clazz) { + acl_main_t * plugin_main = &acl_main; + + // cleanup: + (*env)->DeleteGlobalRef(env, plugin_main->callbackClass); + (*env)->DeleteGlobalRef(env, plugin_main->callbackObject); + + plugin_main->callbackClass = NULL; + plugin_main->callbackObject = NULL; +} + +/* Attach thread to JVM and cache class references when initiating JVPP ACL */ +jint JNI_OnLoad(JavaVM *vm, void *reserved) { + JNIEnv* env; + + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { + return JNI_EVERSION; + } + + if (cache_class_references(env) != 0) { + clib_warning ("Failed to cache class references\n"); + return JNI_ERR; + } + + return JNI_VERSION_1_8; +} + +/* Clean up cached references when disposing JVPP ACL */ +void JNI_OnUnload(JavaVM *vm, void *reserved) { + JNIEnv* env; + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { + return; + } + delete_class_references(env); +} diff --git a/src/vpp-api/java/jvpp-acl/jvpp_acl.h b/src/vpp-api/java/jvpp-acl/jvpp_acl.h new file mode 100644 index 00000000..2b73d672 --- /dev/null +++ b/src/vpp-api/java/jvpp-acl/jvpp_acl.h @@ -0,0 +1,45 @@ +/* + * 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. + */ +#ifndef __included_jvpp_acl_h__ +#define __included_jvpp_acl_h__ + +#include +#include +#include +#include +#include +#include + +/* Global state for JVPP-acl */ +typedef struct { + /* Base message index for the acl plugin */ + u16 msg_id_base; + + /* Pointer to shared memory queue */ + unix_shared_memory_queue_t * vl_input_queue; + + /* VPP api client index */ + u32 my_client_index; + + /* Callback object and class references enabling asynchronous Java calls */ + jobject callbackObject; + jclass callbackClass; + +} acl_main_t; + +acl_main_t acl_main __attribute__((aligned (64))); + + +#endif /* __included_jvpp_acl_h__ */ diff --git a/src/vpp-api/java/jvpp-common/jvpp_common.c b/src/vpp-api/java/jvpp-common/jvpp_common.c new file mode 100644 index 00000000..a161c09c --- /dev/null +++ b/src/vpp-api/java/jvpp-common/jvpp_common.c @@ -0,0 +1,65 @@ +/* + * 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. + */ +#define _GNU_SOURCE /* for strcasestr(3) */ + +#include "jvpp_common.h" + +#ifndef JVPP_DEBUG +#define JVPP_DEBUG 0 +#endif + +#if JVPP_DEBUG == 1 +#define DEBUG_LOG(...) clib_warning(__VA_ARGS__) +#else +#define DEBUG_LOG(...) +#endif + +/* shared jvpp main structure */ +jvpp_main_t jvpp_main __attribute__((aligned (64))); + +void call_on_error(const char* callName, int contextId, int retval, + jclass callbackClass, jobject callbackObject, + jclass callbackExceptionClass) { + DEBUG_LOG("\nCallOnError : callback=%s, retval=%d, context=%d\n", callName, + clib_net_to_host_u32(retval), clib_net_to_host_u32(context)); + JNIEnv *env = jvpp_main.jenv; + if (!callbackClass) { + DEBUG_LOG("CallOnError : jm->callbackClass is null!\n"); + return; + } + jmethodID excConstructor = (*env)->GetMethodID(env, callbackExceptionClass, + "", "(Ljava/lang/String;II)V"); + if (!excConstructor) { + DEBUG_LOG("CallOnError : excConstructor is null!\n"); + return; + } + jmethodID callbackExcMethod = (*env)->GetMethodID(env, callbackClass, + "onError", "(Lio/fd/vpp/jvpp/VppCallbackException;)V"); + if (!callbackExcMethod) { + DEBUG_LOG("CallOnError : callbackExcMethod is null!\n"); + return; + } + + jobject excObject = (*env)->NewObject(env, callbackExceptionClass, + excConstructor, (*env)->NewStringUTF(env, callName), + clib_net_to_host_u32(contextId), clib_net_to_host_u32(retval)); + if (!excObject) { + DEBUG_LOG("CallOnError : excObject is null!\n"); + return; + } + + (*env)->CallVoidMethod(env, callbackObject, callbackExcMethod, excObject); + DEBUG_LOG("CallOnError : Response sent\n"); +} diff --git a/src/vpp-api/java/jvpp-common/jvpp_common.h b/src/vpp-api/java/jvpp-common/jvpp_common.h new file mode 100644 index 00000000..bbb203ed --- /dev/null +++ b/src/vpp-api/java/jvpp-common/jvpp_common.h @@ -0,0 +1,67 @@ +/* + * 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. + */ +#ifndef __included_jvpp_common_h__ +#define __included_jvpp_common_h__ +// +#include +#include +#include +#include + +typedef struct { + /* Unique identifier used for matching replays with requests */ + volatile u32 context_id; + + /* Spinlock */ + volatile u32 lock; + u32 tag; + + /* JNI Native Method Interface pointer for message handlers */ + JNIEnv *jenv; + + /* JNI Invoke Interface pointer for attachment of rx thread to java thread */ + JavaVM *jvm; + + /* Convenience */ + unix_shared_memory_queue_t * vl_input_queue; + u32 my_client_index; +} jvpp_main_t; + +extern jvpp_main_t jvpp_main __attribute__((aligned (64))); + +static_always_inline u32 vppjni_get_context_id(jvpp_main_t * jm) { + return __sync_add_and_fetch(&jm->context_id, 1); +} + +static_always_inline void vppjni_lock(jvpp_main_t * jm, u32 tag) { + while (__sync_lock_test_and_set(&jm->lock, 1)) + ; + jm->tag = tag; +} + +static_always_inline void vppjni_unlock(jvpp_main_t * jm) { + jm->tag = 0; + CLIB_MEMORY_BARRIER(); + jm->lock = 0; +} + +/** + * Calls onError callback on callbackObject reference. Passes instance of callbackExceptionClass as parameter. + */ +void call_on_error(const char* callName, int contextId, int retval, + jclass callbackClass, jobject callbackObject, + jclass callbackExceptionClass); + +#endif /* __included_jvpp_common_h__ */ diff --git a/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackApiTest.java b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackApiTest.java new file mode 100644 index 00000000..986993b8 --- /dev/null +++ b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackApiTest.java @@ -0,0 +1,96 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.core.test; + +import io.fd.vpp.jvpp.JVpp; +import io.fd.vpp.jvpp.JVppRegistry; +import io.fd.vpp.jvpp.JVppRegistryImpl; +import io.fd.vpp.jvpp.VppCallbackException; +import io.fd.vpp.jvpp.core.JVppCoreImpl; +import io.fd.vpp.jvpp.core.callback.GetNodeIndexCallback; +import io.fd.vpp.jvpp.core.callback.ShowVersionCallback; +import io.fd.vpp.jvpp.core.callback.SwInterfaceCallback; +import io.fd.vpp.jvpp.core.dto.GetNodeIndex; +import io.fd.vpp.jvpp.core.dto.GetNodeIndexReply; +import io.fd.vpp.jvpp.core.dto.ShowVersion; +import io.fd.vpp.jvpp.core.dto.ShowVersionReply; +import io.fd.vpp.jvpp.core.dto.SwInterfaceDetails; +import io.fd.vpp.jvpp.core.dto.SwInterfaceDump; + +public class CallbackApiTest { + + public static void main(String[] args) throws Exception { + testCallbackApi(); + } + + private static void testCallbackApi() throws Exception { + System.out.println("Testing Java callback API with JVppRegistry"); + try (final JVppRegistry registry = new JVppRegistryImpl("CallbackApiTest"); + final JVpp jvpp = new JVppCoreImpl()) { + registry.register(jvpp, new TestCallback()); + + System.out.println("Sending ShowVersion request..."); + final int result = jvpp.send(new ShowVersion()); + System.out.printf("ShowVersion send result = %d%n", result); + + System.out.println("Sending GetNodeIndex request..."); + GetNodeIndex getNodeIndexRequest = new GetNodeIndex(); + getNodeIndexRequest.nodeName = "non-existing-node".getBytes(); + jvpp.send(getNodeIndexRequest); + + System.out.println("Sending SwInterfaceDump request..."); + SwInterfaceDump swInterfaceDumpRequest = new SwInterfaceDump(); + swInterfaceDumpRequest.nameFilterValid = 0; + swInterfaceDumpRequest.nameFilter = "".getBytes(); + jvpp.send(swInterfaceDumpRequest); + + Thread.sleep(1000); + System.out.println("Disconnecting..."); + } + Thread.sleep(1000); + } + + static class TestCallback implements GetNodeIndexCallback, ShowVersionCallback, SwInterfaceCallback { + + @Override + public void onGetNodeIndexReply(final GetNodeIndexReply msg) { + System.out.printf("Received GetNodeIndexReply: %s%n", msg); + } + + @Override + public void onShowVersionReply(final ShowVersionReply msg) { + System.out.printf("Received ShowVersionReply: context=%d, program=%s, version=%s, " + + "buildDate=%s, buildDirectory=%s%n", + msg.context, new String(msg.program), new String(msg.version), + new String(msg.buildDate), new String(msg.buildDirectory)); + } + + @Override + public void onSwInterfaceDetails(final SwInterfaceDetails msg) { + System.out.printf("Received SwInterfaceDetails: interfaceName=%s, l2AddressLength=%d, adminUpDown=%d, " + + "linkUpDown=%d, linkSpeed=%d, linkMtu=%d%n", + new String(msg.interfaceName), msg.l2AddressLength, msg.adminUpDown, + msg.linkUpDown, msg.linkSpeed, (int) msg.linkMtu); + } + + @Override + public void onError(VppCallbackException ex) { + System.out.printf("Received onError exception: call=%s, context=%d, retval=%d%n", ex.getMethodName(), + ex.getCtxId(), ex.getErrorCode()); + } + } +} diff --git a/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackJVppFacadeNotificationTest.java b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackJVppFacadeNotificationTest.java new file mode 100644 index 00000000..d84cb034 --- /dev/null +++ b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackJVppFacadeNotificationTest.java @@ -0,0 +1,87 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.core.test; + +import io.fd.vpp.jvpp.JVppRegistry; +import io.fd.vpp.jvpp.JVppRegistryImpl; +import io.fd.vpp.jvpp.VppCallbackException; +import io.fd.vpp.jvpp.core.JVppCore; +import io.fd.vpp.jvpp.core.JVppCoreImpl; +import io.fd.vpp.jvpp.core.callback.WantInterfaceEventsCallback; +import io.fd.vpp.jvpp.core.callfacade.CallbackJVppCoreFacade; +import io.fd.vpp.jvpp.core.dto.WantInterfaceEventsReply; + +public class CallbackJVppFacadeNotificationTest { + + private static void testCallbackFacade() throws Exception { + System.out.println("Testing CallbackJVppFacade for notifications"); + + try (final JVppRegistry registry = new JVppRegistryImpl("CallbackFacadeTest"); + final JVppCore jvpp = new JVppCoreImpl()) { + final CallbackJVppCoreFacade jvppCallbackFacade = new CallbackJVppCoreFacade(registry, jvpp); + System.out.println("Successfully connected to VPP"); + + final AutoCloseable notificationListenerReg = + jvppCallbackFacade.getNotificationRegistry().registerSwInterfaceSetFlagsNotificationCallback( + NotificationUtils::printNotification + ); + + jvppCallbackFacade.wantInterfaceEvents(NotificationUtils.getEnableInterfaceNotificationsReq(), + new WantInterfaceEventsCallback() { + @Override + public void onWantInterfaceEventsReply(final WantInterfaceEventsReply reply) { + System.out.println("Interface events started"); + } + + @Override + public void onError(final VppCallbackException ex) { + System.out.printf("Received onError exception: call=%s, context=%d, retval=%d%n", + ex.getMethodName(), ex.getCtxId(), ex.getErrorCode()); + } + }); + + System.out.println("Changing interface configuration"); + NotificationUtils.getChangeInterfaceState().send(jvpp); + + Thread.sleep(1000); + + jvppCallbackFacade.wantInterfaceEvents(NotificationUtils.getDisableInterfaceNotificationsReq(), + new WantInterfaceEventsCallback() { + @Override + public void onWantInterfaceEventsReply(final WantInterfaceEventsReply reply) { + System.out.println("Interface events stopped"); + } + + @Override + public void onError(final VppCallbackException ex) { + System.out.printf("Received onError exception: call=%s, context=%d, retval=%d%n", + ex.getMethodName(), ex.getCtxId(), ex.getErrorCode()); + } + }); + + notificationListenerReg.close(); + + Thread.sleep(2000); + System.out.println("Disconnecting..."); + } + Thread.sleep(1000); + } + + public static void main(String[] args) throws Exception { + testCallbackFacade(); + } +} diff --git a/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackJVppFacadeTest.java b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackJVppFacadeTest.java new file mode 100644 index 00000000..9f7cb8de --- /dev/null +++ b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackJVppFacadeTest.java @@ -0,0 +1,103 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.core.test; + +import io.fd.vpp.jvpp.JVppRegistry; +import io.fd.vpp.jvpp.JVppRegistryImpl; +import io.fd.vpp.jvpp.VppCallbackException; +import io.fd.vpp.jvpp.core.JVppCoreImpl; +import io.fd.vpp.jvpp.core.callback.GetNodeIndexCallback; +import io.fd.vpp.jvpp.core.callback.ShowVersionCallback; +import io.fd.vpp.jvpp.core.callfacade.CallbackJVppCoreFacade; +import io.fd.vpp.jvpp.core.dto.GetNodeIndex; +import io.fd.vpp.jvpp.core.dto.GetNodeIndexReply; +import io.fd.vpp.jvpp.core.dto.ShowVersionReply; + +/** + * CallbackJVppFacade together with CallbackJVppFacadeCallback allow for setting different callback for each request. + * This is more convenient than the approach shown in CallbackApiTest. + */ +public class CallbackJVppFacadeTest { + + private static ShowVersionCallback showVersionCallback1 = new ShowVersionCallback() { + @Override + public void onShowVersionReply(final ShowVersionReply msg) { + System.out.printf("ShowVersionCallback1 received ShowVersionReply: context=%d, program=%s," + + "version=%s, buildDate=%s, buildDirectory=%s%n", msg.context, new String(msg.program), + new String(msg.version), new String(msg.buildDate), new String(msg.buildDirectory)); + } + + @Override + public void onError(VppCallbackException ex) { + System.out.printf("Received onError exception in showVersionCallback1: call=%s, reply=%d, context=%d%n", + ex.getMethodName(), ex.getErrorCode(), ex.getCtxId()); + } + }; + + private static ShowVersionCallback showVersionCallback2 = new ShowVersionCallback() { + @Override + public void onShowVersionReply(final ShowVersionReply msg) { + System.out.printf("ShowVersionCallback2 received ShowVersionReply: context=%d, program=%s," + + "version=%s, buildDate=%s, buildDirectory=%s%n", msg.context, new String(msg.program), + new String(msg.version), new String(msg.buildDate), new String(msg.buildDirectory)); + } + + @Override + public void onError(VppCallbackException ex) { + System.out.printf("Received onError exception in showVersionCallback2: call=%s, reply=%d, context=%d%n", + ex.getMethodName(), ex.getErrorCode(), ex.getCtxId()); + } + + }; + + private static GetNodeIndexCallback getNodeIndexCallback = new GetNodeIndexCallback() { + @Override + public void onGetNodeIndexReply(final GetNodeIndexReply msg) { + System.out.printf("Received GetNodeIndexReply: %s%n", msg); + } + + @Override + public void onError(VppCallbackException ex) { + System.out.printf("Received onError exception in getNodeIndexCallback: call=%s, reply=%d, context=%d%n", + ex.getMethodName(), ex.getErrorCode(), ex.getCtxId()); + } + }; + + private static void testCallbackFacade() throws Exception { + System.out.println("Testing CallbackJVppFacade"); + + try (final JVppRegistry registry = new JVppRegistryImpl("CallbackFacadeTest"); + final CallbackJVppCoreFacade callbackFacade = new CallbackJVppCoreFacade(registry, new JVppCoreImpl())) { + System.out.println("Successfully connected to VPP"); + + callbackFacade.showVersion(showVersionCallback1); + callbackFacade.showVersion(showVersionCallback2); + + GetNodeIndex getNodeIndexRequest = new GetNodeIndex(); + getNodeIndexRequest.nodeName = "dummyNode".getBytes(); + callbackFacade.getNodeIndex(getNodeIndexRequest, getNodeIndexCallback); + + Thread.sleep(2000); + System.out.println("Disconnecting..."); + } + Thread.sleep(1000); + } + + public static void main(String[] args) throws Exception { + testCallbackFacade(); + } +} diff --git a/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackNotificationApiTest.java b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackNotificationApiTest.java new file mode 100644 index 00000000..a9f71f11 --- /dev/null +++ b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackNotificationApiTest.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.core.test; + +import static io.fd.vpp.jvpp.core.test.NotificationUtils.getChangeInterfaceState; +import static io.fd.vpp.jvpp.core.test.NotificationUtils.getDisableInterfaceNotificationsReq; +import static io.fd.vpp.jvpp.core.test.NotificationUtils.getEnableInterfaceNotificationsReq; +import static io.fd.vpp.jvpp.core.test.NotificationUtils.printNotification; + +import io.fd.vpp.jvpp.JVpp; +import io.fd.vpp.jvpp.JVppRegistry; +import io.fd.vpp.jvpp.JVppRegistryImpl; +import io.fd.vpp.jvpp.VppCallbackException; +import io.fd.vpp.jvpp.core.JVppCoreImpl; +import io.fd.vpp.jvpp.core.callback.SwInterfaceSetFlagsCallback; +import io.fd.vpp.jvpp.core.callback.SwInterfaceSetFlagsNotificationCallback; +import io.fd.vpp.jvpp.core.callback.WantInterfaceEventsCallback; +import io.fd.vpp.jvpp.core.dto.SwInterfaceSetFlagsNotification; +import io.fd.vpp.jvpp.core.dto.SwInterfaceSetFlagsReply; +import io.fd.vpp.jvpp.core.dto.WantInterfaceEventsReply; + +public class CallbackNotificationApiTest { + + private static void testCallbackApi() throws Exception { + System.out.println("Testing Java callback API for notifications"); + try (final JVppRegistry registry = new JVppRegistryImpl("CallbackNotificationTest"); + final JVpp jvpp = new JVppCoreImpl()) { + registry.register(jvpp, new TestCallback()); + System.out.println("Successfully connected to VPP"); + + getEnableInterfaceNotificationsReq().send(jvpp); + System.out.println("Interface notifications started"); + // TODO test ifc dump which also triggers interface flags send + + System.out.println("Changing interface configuration"); + getChangeInterfaceState().send(jvpp); + + // Notifications are received + Thread.sleep(500); + + getDisableInterfaceNotificationsReq().send(jvpp); + System.out.println("Interface events stopped"); + + Thread.sleep(2000); + System.out.println("Disconnecting..."); + } + Thread.sleep(1000); + } + + public static void main(String[] args) throws Exception { + testCallbackApi(); + } + + private static class TestCallback implements SwInterfaceSetFlagsNotificationCallback, + WantInterfaceEventsCallback, SwInterfaceSetFlagsCallback { + + @Override + public void onSwInterfaceSetFlagsNotification( + final SwInterfaceSetFlagsNotification msg) { + printNotification(msg); + } + + @Override + public void onWantInterfaceEventsReply(final WantInterfaceEventsReply wantInterfaceEventsReply) { + System.out.println("Interface notification stream updated"); + } + + @Override + public void onSwInterfaceSetFlagsReply(final SwInterfaceSetFlagsReply swInterfaceSetFlagsReply) { + System.out.println("Interface flags set successfully"); + } + + @Override + public void onError(VppCallbackException ex) { + System.out.printf("Received onError exception in getNodeIndexCallback: call=%s, reply=%d, context=%d%n", + ex.getMethodName(), ex.getErrorCode(), ex.getCtxId()); + + } + } +} diff --git a/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/ControlPingTest.java b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/ControlPingTest.java new file mode 100644 index 00000000..e97f4e3a --- /dev/null +++ b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/ControlPingTest.java @@ -0,0 +1,68 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.core.test; + +import io.fd.vpp.jvpp.JVpp; +import io.fd.vpp.jvpp.JVppRegistry; +import io.fd.vpp.jvpp.JVppRegistryImpl; +import io.fd.vpp.jvpp.VppCallbackException; +import io.fd.vpp.jvpp.callback.ControlPingCallback; +import io.fd.vpp.jvpp.core.JVppCoreImpl; +import io.fd.vpp.jvpp.dto.ControlPing; +import io.fd.vpp.jvpp.dto.ControlPingReply; + +public class ControlPingTest { + + private static void testControlPing() throws Exception { + System.out.println("Testing ControlPing using Java callback API"); + try (JVppRegistry registry = new JVppRegistryImpl("ControlPingTest"); + JVpp jvpp = new JVppCoreImpl()) { + + registry.register(jvpp, new ControlPingCallback() { + @Override + public void onControlPingReply(final ControlPingReply reply) { + System.out.printf("Received ControlPingReply: %s%n", reply); + } + + @Override + public void onError(VppCallbackException ex) { + System.out.printf("Received onError exception: call=%s, reply=%d, context=%d ", ex.getMethodName(), + ex.getErrorCode(), ex.getCtxId()); + } + + }); + System.out.println("Successfully connected to VPP"); + Thread.sleep(1000); + + System.out.println("Sending control ping using JVppRegistry"); + registry.controlPing(jvpp.getClass()); + + Thread.sleep(2000); + + System.out.println("Sending control ping using JVpp plugin"); + jvpp.send(new ControlPing()); + + Thread.sleep(2000); + System.out.println("Disconnecting..."); + } + Thread.sleep(1000); + } + + public static void main(String[] args) throws Exception { + testControlPing(); + } +} diff --git a/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CreateSubInterfaceTest.java b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CreateSubInterfaceTest.java new file mode 100644 index 00000000..a96258f4 --- /dev/null +++ b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CreateSubInterfaceTest.java @@ -0,0 +1,120 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.core.test; + +import static java.util.Objects.requireNonNull; + +import io.fd.vpp.jvpp.JVppRegistry; +import io.fd.vpp.jvpp.JVppRegistryImpl; +import io.fd.vpp.jvpp.core.JVppCoreImpl; +import io.fd.vpp.jvpp.core.dto.CreateSubif; +import io.fd.vpp.jvpp.core.dto.CreateSubifReply; +import io.fd.vpp.jvpp.core.dto.SwInterfaceDetailsReplyDump; +import io.fd.vpp.jvpp.core.dto.SwInterfaceDump; +import io.fd.vpp.jvpp.core.future.FutureJVppCoreFacade; + +/** + *

Tests sub-interface creation.
Equivalent to:
+ * + *

{@code
+ * vppctl create sub GigabitEthernet0/9/0 1 dot1q 100 inner-dot1q any
+ * }
+ * 
+ * + * To verify invoke:
+ *
{@code
+ * vpp_api_test json
+ * vat# sw_interface_dump
+ * }
+ */
+public class CreateSubInterfaceTest {
+
+    private static SwInterfaceDump createSwInterfaceDumpRequest(final String ifaceName) {
+        SwInterfaceDump request = new SwInterfaceDump();
+        request.nameFilter = ifaceName.getBytes();
+        request.nameFilterValid = 1;
+        return request;
+    }
+
+    private static void requireSingleIface(final SwInterfaceDetailsReplyDump response, final String ifaceName) {
+        if (response.swInterfaceDetails.size() != 1) {
+            throw new IllegalStateException(
+                String.format("Expected one interface matching filter %s but was %d", ifaceName,
+                    response.swInterfaceDetails.size()));
+        }
+    }
+
+    private static CreateSubif createSubifRequest(final int swIfIndex, final int subId) {
+        CreateSubif request = new CreateSubif();
+        request.swIfIndex = swIfIndex; // super interface id
+        request.subId = subId;
+        request.noTags = 0;
+        request.oneTag = 0;
+        request.twoTags = 1;
+        request.dot1Ad = 0;
+        request.exactMatch = 1;
+        request.defaultSub = 0;
+        request.outerVlanIdAny = 0;
+        request.innerVlanIdAny = 1;
+        request.outerVlanId = 100;
+        request.innerVlanId = 0;
+        return request;
+    }
+
+    private static void print(CreateSubifReply reply) {
+        System.out.printf("CreateSubifReply: %s%n", reply);
+    }
+
+    private static void testCreateSubInterface() throws Exception {
+        System.out.println("Testing sub-interface creation using Java callback API");
+        try (final JVppRegistry registry = new JVppRegistryImpl("CreateSubInterface");
+             final FutureJVppCoreFacade jvppFacade = new FutureJVppCoreFacade(registry, new JVppCoreImpl())) {
+            System.out.println("Successfully connected to VPP");
+            Thread.sleep(1000);
+
+            final String ifaceName = "GigabitEthernet0/8/0";
+
+            final SwInterfaceDetailsReplyDump swInterfaceDetails =
+                jvppFacade.swInterfaceDump(createSwInterfaceDumpRequest(ifaceName)).toCompletableFuture().get();
+
+            requireNonNull(swInterfaceDetails, "swInterfaceDump returned null");
+            requireNonNull(swInterfaceDetails.swInterfaceDetails, "swInterfaceDetails is null");
+            requireSingleIface(swInterfaceDetails, ifaceName);
+
+            final int swIfIndex = swInterfaceDetails.swInterfaceDetails.get(0).swIfIndex;
+            final int subId = 1;
+
+            final CreateSubifReply createSubifReply =
+                jvppFacade.createSubif(createSubifRequest(swIfIndex, subId)).toCompletableFuture().get();
+            print(createSubifReply);
+
+            final String subIfaceName = "GigabitEthernet0/8/0." + subId;
+            final SwInterfaceDetailsReplyDump subIface =
+                jvppFacade.swInterfaceDump(createSwInterfaceDumpRequest(subIfaceName)).toCompletableFuture().get();
+            requireNonNull(swInterfaceDetails, "swInterfaceDump returned null");
+            requireNonNull(subIface.swInterfaceDetails, "swInterfaceDump returned null");
+            requireSingleIface(swInterfaceDetails, ifaceName);
+
+            System.out.println("Disconnecting...");
+        }
+        Thread.sleep(1000);
+    }
+
+    public static void main(String[] args) throws Exception {
+        testCreateSubInterface();
+    }
+}
diff --git a/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/FutureApiNotificationTest.java b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/FutureApiNotificationTest.java
new file mode 100644
index 00000000..9efeae19
--- /dev/null
+++ b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/FutureApiNotificationTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+package io.fd.vpp.jvpp.core.test;
+
+import static io.fd.vpp.jvpp.core.test.NotificationUtils.getChangeInterfaceState;
+import static io.fd.vpp.jvpp.core.test.NotificationUtils.getDisableInterfaceNotificationsReq;
+import static io.fd.vpp.jvpp.core.test.NotificationUtils.getEnableInterfaceNotificationsReq;
+
+import io.fd.vpp.jvpp.JVppRegistry;
+import io.fd.vpp.jvpp.JVppRegistryImpl;
+import io.fd.vpp.jvpp.core.JVppCoreImpl;
+import io.fd.vpp.jvpp.core.future.FutureJVppCoreFacade;
+
+public class FutureApiNotificationTest {
+
+    private static void testFutureApi() throws Exception {
+        System.out.println("Testing Java future API for notifications");
+        try (final JVppRegistry registry = new JVppRegistryImpl("FutureApiNotificationTest");
+             final FutureJVppCoreFacade jvppFacade = new FutureJVppCoreFacade(registry, new JVppCoreImpl());
+             final AutoCloseable notificationListenerReg =
+                 jvppFacade.getNotificationRegistry()
+                     .registerSwInterfaceSetFlagsNotificationCallback(NotificationUtils::printNotification)) {
+            System.out.println("Successfully connected to VPP");
+            jvppFacade.wantInterfaceEvents(getEnableInterfaceNotificationsReq()).toCompletableFuture().get();
+            System.out.println("Interface events started");
+
+            System.out.println("Changing interface configuration");
+            jvppFacade.swInterfaceSetFlags(getChangeInterfaceState()).toCompletableFuture().get();
+
+            Thread.sleep(1000);
+
+            jvppFacade.wantInterfaceEvents(getDisableInterfaceNotificationsReq()).toCompletableFuture().get();
+            System.out.println("Interface events stopped");
+            System.out.println("Disconnecting...");
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        testFutureApi();
+    }
+}
diff --git a/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/FutureApiTest.java b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/FutureApiTest.java
new file mode 100644
index 00000000..f478bab4
--- /dev/null
+++ b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/FutureApiTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+package io.fd.vpp.jvpp.core.test;
+
+import io.fd.vpp.jvpp.JVppRegistry;
+import io.fd.vpp.jvpp.JVppRegistryImpl;
+import io.fd.vpp.jvpp.core.JVppCoreImpl;
+import io.fd.vpp.jvpp.core.dto.BridgeDomainDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.BridgeDomainDump;
+import io.fd.vpp.jvpp.core.dto.GetNodeIndex;
+import io.fd.vpp.jvpp.core.dto.GetNodeIndexReply;
+import io.fd.vpp.jvpp.core.dto.ShowVersion;
+import io.fd.vpp.jvpp.core.dto.ShowVersionReply;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceDetails;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCoreFacade;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Future;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class FutureApiTest {
+
+    private static final Logger LOG = Logger.getLogger(FutureApiTest.class.getName());
+
+    private static void testShowVersion(final FutureJVppCoreFacade jvpp) throws Exception {
+        LOG.info("Sending ShowVersion request...");
+        final Future replyFuture = jvpp.showVersion(new ShowVersion()).toCompletableFuture();
+        final ShowVersionReply reply = replyFuture.get();
+        LOG.info(
+            String.format(
+                "Received ShowVersionReply: context=%d, program=%s, version=%s, buildDate=%s, buildDirectory=%s%n",
+                reply.context, new String(reply.program), new String(reply.version), new String(reply.buildDate),
+                new String(reply.buildDirectory)));
+    }
+
+    private static void testEmptyBridgeDomainDump(final FutureJVppCoreFacade jvpp) throws Exception {
+        LOG.info("Sending ShowVersion request...");
+        final BridgeDomainDump request = new BridgeDomainDump();
+        request.bdId = -1; // dump call
+
+        final CompletableFuture
+            replyFuture = jvpp.bridgeDomainDump(request).toCompletableFuture();
+        final BridgeDomainDetailsReplyDump reply = replyFuture.get();
+
+        if (reply == null || reply.bridgeDomainDetails == null) {
+            LOG.severe("Received null response for empty dump: " + reply);
+        } else {
+            LOG.info(
+                String.format(
+                    "Received empty bridge-domain dump reply with list of bridge-domains: %s, %s",
+                    reply.bridgeDomainDetails, reply.bridgeDomainSwIfDetails));
+        }
+    }
+
+    private static void testGetNodeIndex(final FutureJVppCoreFacade jvpp) {
+        LOG.info("Sending GetNodeIndex request...");
+        final GetNodeIndex request = new GetNodeIndex();
+        request.nodeName = "non-existing-node".getBytes();
+        final Future replyFuture = jvpp.getNodeIndex(request).toCompletableFuture();
+        try {
+            final GetNodeIndexReply reply = replyFuture.get();
+            LOG.info(
+                String.format(
+                    "Received GetNodeIndexReply: context=%d, nodeIndex=%d%n", reply.context, reply.nodeIndex));
+        } catch (Exception e) {
+            LOG.log(Level.SEVERE, "GetNodeIndex request failed", e);
+        }
+    }
+
+    private static void testSwInterfaceDump(final FutureJVppCoreFacade jvpp) throws Exception {
+        LOG.info("Sending SwInterfaceDump request...");
+        final SwInterfaceDump request = new SwInterfaceDump();
+        request.nameFilterValid = 0;
+        request.nameFilter = "".getBytes();
+
+        final Future replyFuture = jvpp.swInterfaceDump(request).toCompletableFuture();
+        final SwInterfaceDetailsReplyDump reply = replyFuture.get();
+        for (SwInterfaceDetails details : reply.swInterfaceDetails) {
+            Objects.requireNonNull(details, "reply.swInterfaceDetails contains null element!");
+            LOG.info(
+                String.format("Received SwInterfaceDetails: interfaceName=%s, l2AddressLength=%d, adminUpDown=%d, "
+                        + "linkUpDown=%d, linkSpeed=%d, linkMtu=%d%n",
+                    new String(details.interfaceName), details.l2AddressLength, details.adminUpDown,
+                    details.linkUpDown, details.linkSpeed, (int) details.linkMtu));
+        }
+    }
+
+    private static void testFutureApi() throws Exception {
+        LOG.info("Testing Java future API");
+        try (final JVppRegistry registry = new JVppRegistryImpl("FutureApiTest");
+             final FutureJVppCoreFacade jvppFacade = new FutureJVppCoreFacade(registry, new JVppCoreImpl())) {
+            LOG.info("Successfully connected to VPP");
+
+            testEmptyBridgeDomainDump(jvppFacade);
+            testShowVersion(jvppFacade);
+            testGetNodeIndex(jvppFacade);
+            testSwInterfaceDump(jvppFacade);
+
+            LOG.info("Disconnecting...");
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        testFutureApi();
+    }
+}
diff --git a/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/L2AclTest.java b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/L2AclTest.java
new file mode 100644
index 00000000..6b3fa993
--- /dev/null
+++ b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/L2AclTest.java
@@ -0,0 +1,195 @@
+/*
+ * 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.
+ */
+
+package io.fd.vpp.jvpp.core.test;
+
+import io.fd.vpp.jvpp.JVppRegistry;
+import io.fd.vpp.jvpp.JVppRegistryImpl;
+import io.fd.vpp.jvpp.core.JVppCoreImpl;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSessionReply;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTableReply;
+import io.fd.vpp.jvpp.core.dto.ClassifySessionDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.ClassifySessionDump;
+import io.fd.vpp.jvpp.core.dto.ClassifyTableByInterface;
+import io.fd.vpp.jvpp.core.dto.ClassifyTableByInterfaceReply;
+import io.fd.vpp.jvpp.core.dto.ClassifyTableIds;
+import io.fd.vpp.jvpp.core.dto.ClassifyTableIdsReply;
+import io.fd.vpp.jvpp.core.dto.ClassifyTableInfo;
+import io.fd.vpp.jvpp.core.dto.ClassifyTableInfoReply;
+import io.fd.vpp.jvpp.core.dto.InputAclSetInterface;
+import io.fd.vpp.jvpp.core.dto.InputAclSetInterfaceReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCoreFacade;
+import javax.xml.bind.DatatypeConverter;
+
+/**
+ * 

Tests L2 ACL creation and read.
Equivalent to the following vppctl commands:
+ * + *

{@code
+ * vppctl classify table mask l2 src
+ * vppctl classify session acl-hit-next deny opaque-index 0 table-index 0 match l2 src 01:02:03:04:05:06
+ * vppctl set int input acl intfc local0 l2-table 0
+ * vppctl sh class table verbose
+ * }
+ * 
+ */ +public class L2AclTest { + + private static final int LOCAL0_IFACE_ID = 0; + + private static ClassifyAddDelTable createClassifyTable() { + ClassifyAddDelTable request = new ClassifyAddDelTable(); + request.isAdd = 1; + request.tableIndex = ~0; // default + request.nbuckets = 2; + request.memorySize = 2 << 20; + request.nextTableIndex = ~0; // default + request.missNextIndex = ~0; // default + request.skipNVectors = 0; + request.matchNVectors = 1; + request.mask = + new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, 0x00, 0x00, 0x00, 0x00}; + return request; + } + + private static ClassifyTableInfo createClassifyTableInfoRequest(final int tableId) { + ClassifyTableInfo request = new ClassifyTableInfo(); + request.tableId = tableId; + return request; + } + + private static ClassifyAddDelSession createClassifySession(final int tableIndex) { + ClassifyAddDelSession request = new ClassifyAddDelSession(); + request.isAdd = 1; + request.tableIndex = tableIndex; + request.hitNextIndex = 0; // deny + request.opaqueIndex = 0; + request.advance = 0; // default + // match 01:02:03:04:05:06 mac address + request.match = + new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, + (byte) 0x05, (byte) 0x06, 0x00, 0x00, 0x00, 0x00}; + return request; + } + + private static ClassifySessionDump createClassifySessionDumpRequest(final int newTableIndex) { + ClassifySessionDump request = new ClassifySessionDump(); + request.tableId = newTableIndex; + return request; + } + + private static InputAclSetInterface aclSetInterface() { + InputAclSetInterface request = new InputAclSetInterface(); + request.isAdd = 1; + request.swIfIndex = LOCAL0_IFACE_ID; + request.ip4TableIndex = ~0; // skip + request.ip6TableIndex = ~0; // skip + request.l2TableIndex = 0; + return request; + } + + private static ClassifyTableByInterface createClassifyTableByInterfaceRequest() { + ClassifyTableByInterface request = new ClassifyTableByInterface(); + request.swIfIndex = LOCAL0_IFACE_ID; + return request; + } + + private static void print(ClassifyAddDelTableReply reply) { + System.out.printf("ClassifyAddDelTableReply: %s%n", reply); + } + + private static void print(ClassifyTableIdsReply reply) { + System.out.printf("ClassifyTableIdsReply: %s%n", reply); + } + + private static void print(final ClassifyTableInfoReply reply) { + System.out.println(reply); + if (reply != null) { + System.out.println("Mask hex: " + DatatypeConverter.printHexBinary(reply.mask)); + } + } + + private static void print(ClassifyAddDelSessionReply reply) { + System.out.printf("ClassifyAddDelSessionReply: context=%s%n", reply); + } + + private static void print(final ClassifySessionDetailsReplyDump reply) { + System.out.println(reply); + reply.classifySessionDetails.forEach(detail -> { + System.out.println(detail); + System.out.println("Match hex: " + DatatypeConverter.printHexBinary(detail.match)); + }); + } + + private static void print(final InputAclSetInterfaceReply reply) { + System.out.printf("InputAclSetInterfaceReply: context=%s%n", reply); + } + + private static void print(final ClassifyTableByInterfaceReply reply) { + System.out.printf("ClassifyAddDelTableReply: %s%n", reply); + } + + private static void testL2Acl() throws Exception { + System.out.println("Testing L2 ACLs using Java callback API"); + try (final JVppRegistry registry = new JVppRegistryImpl("L2AclTest"); + final FutureJVppCoreFacade jvppFacade = new FutureJVppCoreFacade(registry, new JVppCoreImpl())) { + + System.out.println("Successfully connected to VPP"); + Thread.sleep(1000); + + final ClassifyAddDelTableReply classifyAddDelTableReply = + jvppFacade.classifyAddDelTable(createClassifyTable()).toCompletableFuture().get(); + print(classifyAddDelTableReply); + + final ClassifyTableIdsReply classifyTableIdsReply = + jvppFacade.classifyTableIds(new ClassifyTableIds()).toCompletableFuture().get(); + print(classifyTableIdsReply); + + final ClassifyTableInfoReply classifyTableInfoReply = + jvppFacade.classifyTableInfo(createClassifyTableInfoRequest(classifyAddDelTableReply.newTableIndex)) + .toCompletableFuture().get(); + print(classifyTableInfoReply); + + final ClassifyAddDelSessionReply classifyAddDelSessionReply = + jvppFacade.classifyAddDelSession(createClassifySession(classifyAddDelTableReply.newTableIndex)) + .toCompletableFuture().get(); + print(classifyAddDelSessionReply); + + final ClassifySessionDetailsReplyDump classifySessionDetailsReplyDump = + jvppFacade.classifySessionDump(createClassifySessionDumpRequest(classifyAddDelTableReply.newTableIndex)) + .toCompletableFuture().get(); + print(classifySessionDetailsReplyDump); + + final InputAclSetInterfaceReply inputAclSetInterfaceReply = + jvppFacade.inputAclSetInterface(aclSetInterface()).toCompletableFuture().get(); + print(inputAclSetInterfaceReply); + + final ClassifyTableByInterfaceReply classifyTableByInterfaceReply = + jvppFacade.classifyTableByInterface(createClassifyTableByInterfaceRequest()).toCompletableFuture() + .get(); + print(classifyTableByInterfaceReply); + + System.out.println("Disconnecting..."); + } + Thread.sleep(1000); + } + + public static void main(String[] args) throws Exception { + testL2Acl(); + } +} diff --git a/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/LispAdjacencyTest.java b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/LispAdjacencyTest.java new file mode 100644 index 00000000..d7f5039b --- /dev/null +++ b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/LispAdjacencyTest.java @@ -0,0 +1,124 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.core.test; + +import io.fd.vpp.jvpp.JVppRegistry; +import io.fd.vpp.jvpp.JVppRegistryImpl; +import io.fd.vpp.jvpp.core.JVppCoreImpl; +import io.fd.vpp.jvpp.core.dto.LispAddDelAdjacency; +import io.fd.vpp.jvpp.core.dto.LispAddDelLocalEid; +import io.fd.vpp.jvpp.core.dto.LispAddDelLocatorSet; +import io.fd.vpp.jvpp.core.dto.LispAddDelRemoteMapping; +import io.fd.vpp.jvpp.core.dto.LispAdjacenciesGet; +import io.fd.vpp.jvpp.core.dto.LispAdjacenciesGetReply; +import io.fd.vpp.jvpp.core.dto.LispEnableDisable; +import io.fd.vpp.jvpp.core.future.FutureJVppCoreFacade; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.ExecutionException; +import java.util.logging.Logger; + +/** + * Tests lisp adjacency creation and read (custom vpe.api type support showcase). + */ +public class LispAdjacencyTest { + + private static final Logger LOG = Logger.getLogger(LispAdjacencyTest.class.getName()); + + private static void enableLisp(final FutureJVppCoreFacade jvpp) throws ExecutionException, InterruptedException { + final LispEnableDisable request = new LispEnableDisable(); + request.isEn = 1; + jvpp.lispEnableDisable(request).toCompletableFuture().get(); + LOG.info("Lisp enabled successfully"); + } + + private static void addLocatorSet(final FutureJVppCoreFacade jvpp) throws ExecutionException, InterruptedException { + final LispAddDelLocatorSet request = new LispAddDelLocatorSet(); + request.isAdd = 1; + request.locatorSetName = "ls1".getBytes(StandardCharsets.UTF_8); + jvpp.lispAddDelLocatorSet(request).toCompletableFuture().get(); + LOG.info("Locator set created successfully:" + request.toString()); + } + + private static void addLocalEid(final FutureJVppCoreFacade jvpp) throws ExecutionException, InterruptedException { + final LispAddDelLocalEid request = new LispAddDelLocalEid(); + request.isAdd = 1; + request.locatorSetName = "ls1".getBytes(StandardCharsets.UTF_8); + request.eid = new byte[] {1, 2, 1, 10}; + request.eidType = 0; // ip4 + request.vni = 0; + request.prefixLen = 32; + jvpp.lispAddDelLocalEid(request).toCompletableFuture().get(); + LOG.info("Local EID created successfully:" + request.toString()); + } + + private static void addRemoteMapping(final FutureJVppCoreFacade jvpp) + throws ExecutionException, InterruptedException { + final LispAddDelRemoteMapping request = new LispAddDelRemoteMapping(); + request.isAdd = 1; + request.vni = 0; + request.eid = new byte[] {1, 2, 1, 20}; + request.eidLen = 32; + request.rlocNum = 1; + request.rlocs = new byte[] {1, 1, 1, 1, 2, 1, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + jvpp.lispAddDelRemoteMapping(request).toCompletableFuture().get(); + LOG.info("Remote mapping created successfully:" + request.toString()); + } + + private static void addAdjacency(final FutureJVppCoreFacade jvpp) throws ExecutionException, InterruptedException { + final LispAddDelAdjacency request = new LispAddDelAdjacency(); + request.isAdd = 1; + request.leid = new byte[] {1, 2, 1, 10}; + request.leidLen = 32; + request.reid = new byte[] {1, 2, 1, 20}; + request.reidLen = 32; + request.eidType = 0; // ip4 + request.vni = 0; + jvpp.lispAddDelAdjacency(request).toCompletableFuture().get(); + LOG.info("Lisp adjacency created successfully:" + request.toString()); + } + + private static void showAdjacencies(final FutureJVppCoreFacade jvpp) + throws ExecutionException, InterruptedException { + final LispAdjacenciesGetReply reply = + jvpp.lispAdjacenciesGet(new LispAdjacenciesGet()).toCompletableFuture().get(); + LOG.info("Lisp adjacency received successfully:" + reply.toString()); + } + + private static void testAdjacency(final FutureJVppCoreFacade jvpp) throws Exception { + enableLisp(jvpp); + addLocatorSet(jvpp); + addLocalEid(jvpp); + addRemoteMapping(jvpp); + addAdjacency(jvpp); + showAdjacencies(jvpp); + } + + private static void testFutureApi() throws Exception { + LOG.info("Create lisp adjacency test"); + try (final JVppRegistry registry = new JVppRegistryImpl("LispAdjacencyTest"); + final FutureJVppCoreFacade jvppFacade = new FutureJVppCoreFacade(registry, new JVppCoreImpl())) { + LOG.info("Successfully connected to VPP"); + + testAdjacency(jvppFacade); + LOG.info("Disconnecting..."); + } + } + + public static void main(String[] args) throws Exception { + testFutureApi(); + } +} diff --git a/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/NotificationUtils.java b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/NotificationUtils.java new file mode 100644 index 00000000..f82946c3 --- /dev/null +++ b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/NotificationUtils.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.core.test; + +import java.io.PrintStream; +import io.fd.vpp.jvpp.core.dto.SwInterfaceSetFlags; +import io.fd.vpp.jvpp.core.dto.SwInterfaceSetFlagsNotification; +import io.fd.vpp.jvpp.core.dto.WantInterfaceEvents; + +final class NotificationUtils { + + private NotificationUtils() {} + + static PrintStream printNotification(final SwInterfaceSetFlagsNotification msg) { + return System.out.printf("Received interface notification: ifc: %s%n", msg); + } + + static SwInterfaceSetFlags getChangeInterfaceState() { + final SwInterfaceSetFlags swInterfaceSetFlags = new SwInterfaceSetFlags(); + swInterfaceSetFlags.swIfIndex = 0; + swInterfaceSetFlags.adminUpDown = 1; + swInterfaceSetFlags.deleted = 0; + return swInterfaceSetFlags; + } + + static WantInterfaceEvents getEnableInterfaceNotificationsReq() { + WantInterfaceEvents wantInterfaceEvents = new WantInterfaceEvents(); + wantInterfaceEvents.pid = 1; + wantInterfaceEvents.enableDisable = 1; + return wantInterfaceEvents; + } + + static WantInterfaceEvents getDisableInterfaceNotificationsReq() { + WantInterfaceEvents wantInterfaceEvents = new WantInterfaceEvents(); + wantInterfaceEvents.pid = 1; + wantInterfaceEvents.enableDisable = 0; + return wantInterfaceEvents; + } +} diff --git a/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/Readme.txt b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/Readme.txt new file mode 100644 index 00000000..1344dc9e --- /dev/null +++ b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/Readme.txt @@ -0,0 +1,17 @@ +This package contains basic tests for jvpp. To run the tests: + +- Make sure VPP is running +- From VPP's build-root/ folder execute: + - sudo java -cp build-vpp-native/vpp-api/java/jvpp-registry-17.01.jar:build-vpp-native/vpp-api/java/jvpp-core-17.01.jar io.fd.vpp.jvpp.core.test.[test name] + +Available tests: +CallbackApiTest - Similar to ControlPingTest, invokes more complex calls (e.g. interface dump) using low level JVpp APIs +CallbackJVppFacadeNotificationTest - Tests interface notifications using Callback based JVpp facade +CallbackJVppFacadeTest - Execution of more complex calls using Callback based JVpp facade +CallbackNotificationApiTest - Tests interface notifications using low level JVpp APIs +ControlPingTest - Simple test executing a single control ping using low level JVpp APIs +CreateSubInterfaceTest - Tests sub-interface creation +FutureApiNotificationTest - Tests interface notifications using Future based JVpp facade +FutureApiTest - Execution of more complex calls using Future based JVpp facade +L2AclTest - Tests L2 ACL creation +LispAdjacencyTest - Tests lisp adjacency creation and read (custom vpe.api type support showcase) diff --git a/src/vpp-api/java/jvpp-core/jvpp_core.c b/src/vpp-api/java/jvpp-core/jvpp_core.c new file mode 100644 index 00000000..ef4cb8e3 --- /dev/null +++ b/src/vpp-api/java/jvpp-core/jvpp_core.c @@ -0,0 +1,117 @@ +/* + * 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. + */ + +#include + +#include +#define vl_typedefs /* define message structures */ +#include +#undef vl_typedefs + +#define vl_endianfun +#include +#undef vl_endianfun + +#define vl_print(handle, ...) +#define vl_printfun +#include +#undef vl_printfun + +#include +#include +#include +#include + +#include + +// TODO: generate jvpp_plugin_name.c files (or at least reuse plugin's main structure) +typedef struct { + /* Base message index for the jvpp-core plugin */ + u16 msg_id_base; + + /* Pointer to shared memory queue */ + unix_shared_memory_queue_t * vl_input_queue; + + /* VPP api client index */ + u32 my_client_index; + + /* Callback object and class references enabling asynchronous Java calls */ + jobject callbackObject; + jclass callbackClass; + +} core_main_t; + +core_main_t core_main __attribute__((aligned (64))); + +#include "io_fd_vpp_jvpp_core_JVppCoreImpl.h" +#include "jvpp_core_gen.h" + +JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_core_JVppCoreImpl_init0 +(JNIEnv * env, jclass clazz, jobject callback, jlong queue_address, jint my_client_index) { + core_main_t * plugin_main = &core_main; + plugin_main->my_client_index = my_client_index; + plugin_main->vl_input_queue = (unix_shared_memory_queue_t *)queue_address; + + plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback); + plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback)); + + #define _(N,n) \ + vl_msg_api_set_handlers(VL_API_##N, #n, \ + vl_api_##n##_t_handler, \ + vl_noop_handler, \ + vl_noop_handler, \ + vl_noop_handler, \ + sizeof(vl_api_##n##_t), 1); + foreach_api_reply_handler; + #undef _ +} + +JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_core_JVppCoreImpl_close0 +(JNIEnv *env, jclass clazz) { + core_main_t * plugin_main = &core_main; + + // cleanup: + (*env)->DeleteGlobalRef(env, plugin_main->callbackClass); + (*env)->DeleteGlobalRef(env, plugin_main->callbackObject); + + plugin_main->callbackClass = NULL; + plugin_main->callbackObject = NULL; +} + +jint JNI_OnLoad(JavaVM *vm, void *reserved) { + JNIEnv* env; + + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { + return JNI_EVERSION; + } + + if (cache_class_references(env) != 0) { + clib_warning ("Failed to cache class references\n"); + return JNI_ERR; + } + + return JNI_VERSION_1_8; +} + +void JNI_OnUnload(JavaVM *vm, void *reserved) { + JNIEnv* env; + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { + return; + } + delete_class_references(env); +} + + + diff --git a/src/vpp-api/java/jvpp-ioamexport/io/fd/vpp/jvpp/ioamexport/test/IoamExportApiTest.java b/src/vpp-api/java/jvpp-ioamexport/io/fd/vpp/jvpp/ioamexport/test/IoamExportApiTest.java new file mode 100644 index 00000000..cb85f005 --- /dev/null +++ b/src/vpp-api/java/jvpp-ioamexport/io/fd/vpp/jvpp/ioamexport/test/IoamExportApiTest.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.ioamexport.test; + +import java.net.InetAddress; + +import io.fd.vpp.jvpp.JVpp; +import io.fd.vpp.jvpp.JVppRegistry; +import io.fd.vpp.jvpp.JVppRegistryImpl; +import io.fd.vpp.jvpp.VppCallbackException; +import io.fd.vpp.jvpp.ioamexport.JVppIoamexportImpl; +import io.fd.vpp.jvpp.ioamexport.future.FutureJVppIoamexportFacade; +import io.fd.vpp.jvpp.ioamexport.dto.IoamExportIp6EnableDisable; +import io.fd.vpp.jvpp.ioamexport.dto.IoamExportIp6EnableDisableReply; + +public class IoamExportApiTest { + + public static void main(String[] args) throws Exception { + ioamExportTestApi(); + } + + private static void ioamExportTestApi() throws Exception { + System.out.println("Testing Java API for ioam export plugin"); + try (final JVppRegistry registry = new JVppRegistryImpl("ioamExportApiTest"); + final JVpp jvpp = new JVppIoamexportImpl()) { + FutureJVppIoamexportFacade ioamexportJvpp = new FutureJVppIoamexportFacade(registry,jvpp); + System.out.println("Sending ioam export request..."); + IoamExportIp6EnableDisable request = new IoamExportIp6EnableDisable(); + request.isDisable = 0; + InetAddress collectorAddress = InetAddress.getByName("2001:0DB8:AC10:FE01:0000:0000:0000:0000"); + InetAddress srcAddress = InetAddress.getByName("2001:0DB8:AC10:FE01:0000:0000:0000:0001"); + request.collectorAddress = collectorAddress.getAddress(); + request.srcAddress = srcAddress.getAddress(); + IoamExportIp6EnableDisableReply reply = ioamexportJvpp.ioamExportIp6EnableDisable(request).toCompletableFuture().get(); + System.out.printf("IoamExportIp6EnableDisableReply = "+reply.toString()+"%n"); + + Thread.sleep(1000); + + System.out.println("Disconnecting..."); + } + } +} diff --git a/src/vpp-api/java/jvpp-ioamexport/io/fd/vpp/jvpp/ioamexport/test/Readme.txt b/src/vpp-api/java/jvpp-ioamexport/io/fd/vpp/jvpp/ioamexport/test/Readme.txt new file mode 100644 index 00000000..1b38c285 --- /dev/null +++ b/src/vpp-api/java/jvpp-ioamexport/io/fd/vpp/jvpp/ioamexport/test/Readme.txt @@ -0,0 +1 @@ +sudo java -cp build-vpp_debug-native/vpp-api/java/jvpp-registry-17.01.jar:build-vpp_debug-native/plugins/ioam-plugin/jvpp-ioam-export-1.0.jar io.fd.vpp.jvpp.ioamexport.test.IoamExportApiTest diff --git a/src/vpp-api/java/jvpp-ioamexport/jvpp_ioam_export.c b/src/vpp-api/java/jvpp-ioamexport/jvpp_ioam_export.c new file mode 100644 index 00000000..5cda89d1 --- /dev/null +++ b/src/vpp-api/java/jvpp-ioamexport/jvpp_ioam_export.c @@ -0,0 +1,124 @@ +/* + * 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. + */ + +#include + +#include +#define vl_typedefs /* define message structures */ +#include +#undef vl_typedefs + +#define vl_endianfun +#include +#undef vl_endianfun + +#define vl_print(handle, ...) +#define vl_printfun +#include +#undef vl_printfun + +/* Get the API version number */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#undef vl_api_version + +#include +#include +#include + +#if VPPJNI_DEBUG == 1 + #define DEBUG_LOG(...) clib_warning(__VA_ARGS__) +#else + #define DEBUG_LOG(...) +#endif + +#include + +#include "jvpp-ioamexport/io_fd_vpp_jvpp_ioamexport_JVppIoamexportImpl.h" +#include "jvpp_ioam_export.h" +#include "jvpp-ioamexport/jvpp_ioamexport_gen.h" + +/* + * Class: io_fd_vpp_jvpp_ioamexport_JVppIoamexportImpl + * Method: init0 + * Signature: (JI)V + */ +JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_ioamexport_JVppIoamexportImpl_init0 + (JNIEnv *env, jclass clazz, jobject callback, jlong queue_address, jint my_client_index) { + ioamexport_main_t * plugin_main = &ioamexport_main; + u8 * name; + clib_warning ("Java_io_fd_vpp_jvpp_ioamexport_JVppIoamexportImpl_init0"); + + plugin_main->my_client_index = my_client_index; + plugin_main->vl_input_queue = (unix_shared_memory_queue_t *)queue_address; + + name = format (0, "ioam_export_%08x%c", api_version, 0); + plugin_main->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name); + + if (plugin_main->msg_id_base == (u16) ~0) { + jclass exClass = (*env)->FindClass(env, "java/lang/IllegalStateException"); + (*env)->ThrowNew(env, exClass, "ioam_export plugin is not loaded in VPP"); + } else { + plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback); + plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback)); + + #define _(N,n) \ + vl_msg_api_set_handlers(VL_API_##N + plugin_main->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_api_reply_handler; + #undef _ + } +} + +JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_ioamexport_JVppIoamexportImpl_close0 +(JNIEnv *env, jclass clazz) { + ioamexport_main_t * plugin_main = &ioamexport_main; + + // cleanup: + (*env)->DeleteGlobalRef(env, plugin_main->callbackClass); + (*env)->DeleteGlobalRef(env, plugin_main->callbackObject); + + plugin_main->callbackClass = NULL; + plugin_main->callbackObject = NULL; +} + +/* Attach thread to JVM and cache class references when initiating JVPP iOAM EXPORT */ +jint JNI_OnLoad(JavaVM *vm, void *reserved) { + JNIEnv* env; + + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { + return JNI_EVERSION; + } + + if (cache_class_references(env) != 0) { + clib_warning ("Failed to cache class references\n"); + return JNI_ERR; + } + + return JNI_VERSION_1_8; +} + +/* Clean up cached references when disposing JVPP iOAM EXPORT */ +void JNI_OnUnload(JavaVM *vm, void *reserved) { + JNIEnv* env; + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { + return; + } + delete_class_references(env); +} diff --git a/src/vpp-api/java/jvpp-ioamexport/jvpp_ioam_export.h b/src/vpp-api/java/jvpp-ioamexport/jvpp_ioam_export.h new file mode 100644 index 00000000..b6c0c16e --- /dev/null +++ b/src/vpp-api/java/jvpp-ioamexport/jvpp_ioam_export.h @@ -0,0 +1,45 @@ +/* + * 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. + */ +#ifndef __included_jvpp_ioam_export_h__ +#define __included_jvpp_ioam_export_h__ + +#include +#include +#include +#include +#include +#include + +/* Global state for JVPP-IOAM-EXPORT */ +typedef struct { + /* Base message index for the export plugin */ + u16 msg_id_base; + + /* Pointer to shared memory queue */ + unix_shared_memory_queue_t * vl_input_queue; + + /* VPP api client index */ + u32 my_client_index; + + /* Callback object and class references enabling asynchronous Java calls */ + jobject callbackObject; + jclass callbackClass; + +} ioamexport_main_t; + +ioamexport_main_t ioamexport_main __attribute__((aligned (64))); + + +#endif /* __included_jvpp_ioam_export_h__ */ diff --git a/src/vpp-api/java/jvpp-ioampot/io/fd/vpp/jvpp/ioampot/test/IoamPotApiTest.java b/src/vpp-api/java/jvpp-ioampot/io/fd/vpp/jvpp/ioampot/test/IoamPotApiTest.java new file mode 100644 index 00000000..74eb86a1 --- /dev/null +++ b/src/vpp-api/java/jvpp-ioampot/io/fd/vpp/jvpp/ioampot/test/IoamPotApiTest.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.ioampot.test; + +import io.fd.vpp.jvpp.JVpp; +import io.fd.vpp.jvpp.JVppRegistry; +import io.fd.vpp.jvpp.JVppRegistryImpl; +import io.fd.vpp.jvpp.VppCallbackException; +import io.fd.vpp.jvpp.ioampot.JVppIoampotImpl; +import io.fd.vpp.jvpp.ioampot.callback.PotProfileAddCallback; +import io.fd.vpp.jvpp.ioampot.dto.PotProfileAdd; +import io.fd.vpp.jvpp.ioampot.dto.PotProfileAddReply; + +public class IoamPotApiTest { + + static class IoamPotTestCallback implements PotProfileAddCallback { + + @Override + public void onPotProfileAddReply(final PotProfileAddReply reply) { + System.out.printf("Received PotProfileAddReply reply: context=%d%n", + reply.context); + } + + @Override + public void onError(VppCallbackException ex) { + System.out.printf("Received onError exception: call=%s, context=%d, retval=%d%n", ex.getMethodName(), + ex.getCtxId(), ex.getErrorCode()); + } + } + + public static void main(String[] args) throws Exception { + ioamPotTestApi(); + } + + private static void ioamPotTestApi() throws Exception { + System.out.println("Testing Java API for ioam pot plugin"); + try (final JVppRegistry registry = new JVppRegistryImpl("ioamPotApiTest"); + final JVpp jvpp = new JVppIoampotImpl()) { + registry.register(jvpp, new IoamPotTestCallback()); + + System.out.println("Sending ioam pot profile add request..."); + PotProfileAdd request = new PotProfileAdd(); + request.id = 0; + request.validator = 4; + request.secretKey = 1; + request.secretShare = 2; + request.prime = 1234; + request.maxBits = 53; + request.lpc = 1234; + request.polynomialPublic = 1234; + request.listNameLen = (byte)"test pot profile".getBytes().length; + request.listName = "test pot profile".getBytes(); + final int result = jvpp.send(request); + System.out.printf("PotProfileAdd send result = %d%n", result); + + Thread.sleep(1000); + + System.out.println("Disconnecting..."); + } + } +} diff --git a/src/vpp-api/java/jvpp-ioampot/io/fd/vpp/jvpp/ioampot/test/Readme.txt b/src/vpp-api/java/jvpp-ioampot/io/fd/vpp/jvpp/ioampot/test/Readme.txt new file mode 100644 index 00000000..2323494d --- /dev/null +++ b/src/vpp-api/java/jvpp-ioampot/io/fd/vpp/jvpp/ioampot/test/Readme.txt @@ -0,0 +1 @@ +sudo java -cp build-vpp_debug-native/vpp-api/java/jvpp-registry-16.12.jar:build-vpp_debug-native/plugins/ioam-plugin/jvpp-ioam-pot-1.0.jar io.fd.vpp.jvpp.ioampot.test.IoamPotApiTest diff --git a/src/vpp-api/java/jvpp-ioampot/jvpp_ioam_pot.c b/src/vpp-api/java/jvpp-ioampot/jvpp_ioam_pot.c new file mode 100644 index 00000000..9291dbba --- /dev/null +++ b/src/vpp-api/java/jvpp-ioampot/jvpp_ioam_pot.c @@ -0,0 +1,124 @@ +/* + * 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. + */ + +#include + +#include +#define vl_typedefs /* define message structures */ +#include +#undef vl_typedefs + +#define vl_endianfun +#include +#undef vl_endianfun + +#define vl_print(handle, ...) +#define vl_printfun +#include +#undef vl_printfun + +/* Get the API version number */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#undef vl_api_version + +#include +#include +#include + +#if VPPJNI_DEBUG == 1 + #define DEBUG_LOG(...) clib_warning(__VA_ARGS__) +#else + #define DEBUG_LOG(...) +#endif + +#include + +#include "jvpp-ioampot/io_fd_vpp_jvpp_ioampot_JVppIoampotImpl.h" +#include "jvpp_ioam_pot.h" +#include "jvpp-ioampot/jvpp_ioampot_gen.h" + +/* + * Class: io_fd_vpp_jvpp_ioampot_JVppIoampotImpl + * Method: init0 + * Signature: (JI)V + */ +JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_ioampot_JVppIoampotImpl_init0 + (JNIEnv *env, jclass clazz, jobject callback, jlong queue_address, jint my_client_index) { + ioampot_main_t * plugin_main = &ioampot_main; + u8 * name; + clib_warning ("Java_io_fd_vpp_jvpp_ioampot_JVppIoampotImpl_init0"); + + plugin_main->my_client_index = my_client_index; + plugin_main->vl_input_queue = (unix_shared_memory_queue_t *)queue_address; + + name = format (0, "ioam_pot_%08x%c", api_version, 0); + plugin_main->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name); + + if (plugin_main->msg_id_base == (u16) ~0) { + jclass exClass = (*env)->FindClass(env, "java/lang/IllegalStateException"); + (*env)->ThrowNew(env, exClass, "ioam_pot plugin is not loaded in VPP"); + } else { + plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback); + plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback)); + + #define _(N,n) \ + vl_msg_api_set_handlers(VL_API_##N + plugin_main->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_api_reply_handler; + #undef _ + } +} + +JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_ioampot_JVppIoampotImpl_close0 +(JNIEnv *env, jclass clazz) { + ioampot_main_t * plugin_main = &ioampot_main; + + // cleanup: + (*env)->DeleteGlobalRef(env, plugin_main->callbackClass); + (*env)->DeleteGlobalRef(env, plugin_main->callbackObject); + + plugin_main->callbackClass = NULL; + plugin_main->callbackObject = NULL; +} + +/* Attach thread to JVM and cache class references when initiating JVPP iOAM POT */ +jint JNI_OnLoad(JavaVM *vm, void *reserved) { + JNIEnv* env; + + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { + return JNI_EVERSION; + } + + if (cache_class_references(env) != 0) { + clib_warning ("Failed to cache class references\n"); + return JNI_ERR; + } + + return JNI_VERSION_1_8; +} + +/* Clean up cached references when disposing JVPP iOAM POT */ +void JNI_OnUnload(JavaVM *vm, void *reserved) { + JNIEnv* env; + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { + return; + } + delete_class_references(env); +} diff --git a/src/vpp-api/java/jvpp-ioampot/jvpp_ioam_pot.h b/src/vpp-api/java/jvpp-ioampot/jvpp_ioam_pot.h new file mode 100644 index 00000000..00aa51db --- /dev/null +++ b/src/vpp-api/java/jvpp-ioampot/jvpp_ioam_pot.h @@ -0,0 +1,45 @@ +/* + * 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. + */ +#ifndef __included_jvpp_ioam_pot_h__ +#define __included_jvpp_ioam_pot_h__ + +#include +#include +#include +#include +#include +#include + +/* Global state for JVPP-IOAM-POT */ +typedef struct { + /* Base message index for the pot plugin */ + u16 msg_id_base; + + /* Pointer to shared memory queue */ + unix_shared_memory_queue_t * vl_input_queue; + + /* VPP api client index */ + u32 my_client_index; + + /* Callback object and class references enabling asynchronous Java calls */ + jobject callbackObject; + jclass callbackClass; + +} ioampot_main_t; + +ioampot_main_t ioampot_main __attribute__((aligned (64))); + + +#endif /* __included_jvpp_ioam_pot_h__ */ diff --git a/src/vpp-api/java/jvpp-ioamtrace/io/fd/vpp/jvpp/ioamtrace/test/IoamTraceApiTest.java b/src/vpp-api/java/jvpp-ioamtrace/io/fd/vpp/jvpp/ioamtrace/test/IoamTraceApiTest.java new file mode 100644 index 00000000..bc8c1c3a --- /dev/null +++ b/src/vpp-api/java/jvpp-ioamtrace/io/fd/vpp/jvpp/ioamtrace/test/IoamTraceApiTest.java @@ -0,0 +1,77 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.ioamtrace.test; + +import io.fd.vpp.jvpp.JVpp; +import io.fd.vpp.jvpp.JVppRegistry; +import io.fd.vpp.jvpp.JVppRegistryImpl; +import io.fd.vpp.jvpp.VppCallbackException; +import io.fd.vpp.jvpp.ioamtrace.future.FutureJVppIoamtraceFacade; +import io.fd.vpp.jvpp.ioamtrace.JVppIoamtraceImpl; +import io.fd.vpp.jvpp.ioamtrace.callback.TraceProfileAddCallback; +import io.fd.vpp.jvpp.ioamtrace.dto.TraceProfileAdd; +import io.fd.vpp.jvpp.ioamtrace.dto.TraceProfileAddReply; +import io.fd.vpp.jvpp.ioamtrace.dto.TraceProfileShowConfig; +import io.fd.vpp.jvpp.ioamtrace.dto.TraceProfileShowConfigReply; + +public class IoamTraceApiTest { + + static class IoamTraceTestCallback implements TraceProfileAddCallback { + + @Override + public void onTraceProfileAddReply(final TraceProfileAddReply reply) { + System.out.printf("Received TraceProfileAddReply reply: context=%d%n", + reply.context); + } + + @Override + public void onError(VppCallbackException ex) { + System.out.printf("Received onError exception: call=%s, context=%d, retval=%d%n", ex.getMethodName(), + ex.getCtxId(), ex.getErrorCode()); + } + } + + public static void main(String[] args) throws Exception { + ioamTraceTestApi(); + } + + private static void ioamTraceTestApi() throws Exception { + System.out.println("Testing Java API for ioam trace plugin"); + try (final JVppRegistry registry = new JVppRegistryImpl("ioamTraceApiTest"); + final JVpp jvpp = new JVppIoamtraceImpl()) { + FutureJVppIoamtraceFacade ioamtraceJvpp = new FutureJVppIoamtraceFacade(registry,jvpp); + + System.out.println("Sending ioam trace profile add request..."); + TraceProfileAdd request = new TraceProfileAdd(); + request.traceType = 0x1f; + request.numElts = 4; + request.nodeId = 1; + request.traceTsp = 2; + request.appData = 1234; + final int result = jvpp.send(request); + System.out.printf("TraceProfileAdd send result = %d%n", result); + + Thread.sleep(1000); + + TraceProfileShowConfig showRequest = new TraceProfileShowConfig(); + TraceProfileShowConfigReply reply = ioamtraceJvpp.traceProfileShowConfig(showRequest).toCompletableFuture().get(); + System.out.printf("TraceProfileShowConfig result = "+ reply.toString()); + + System.out.println("Disconnecting..."); + } + } +} diff --git a/src/vpp-api/java/jvpp-ioamtrace/io/fd/vpp/jvpp/ioamtrace/test/Readme.txt b/src/vpp-api/java/jvpp-ioamtrace/io/fd/vpp/jvpp/ioamtrace/test/Readme.txt new file mode 100644 index 00000000..17e45a81 --- /dev/null +++ b/src/vpp-api/java/jvpp-ioamtrace/io/fd/vpp/jvpp/ioamtrace/test/Readme.txt @@ -0,0 +1 @@ +sudo java -cp build-vpp-native/vpp-api/java/jvpp-registry-17.01.jar:build-vpp-native/plugins/ioam-plugin/jvpp-ioam-trace-1.0.jar io.fd.vpp.jvpp.ioamtrace.test.IoamTraceApiTest diff --git a/src/vpp-api/java/jvpp-ioamtrace/jvpp_ioam_trace.c b/src/vpp-api/java/jvpp-ioamtrace/jvpp_ioam_trace.c new file mode 100644 index 00000000..0bf17889 --- /dev/null +++ b/src/vpp-api/java/jvpp-ioamtrace/jvpp_ioam_trace.c @@ -0,0 +1,124 @@ +/* + * 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. + */ + +#include + +#include +#define vl_typedefs /* define message structures */ +#include +#undef vl_typedefs + +#define vl_endianfun +#include +#undef vl_endianfun + +#define vl_print(handle, ...) +#define vl_printfun +#include +#undef vl_printfun + +/* Get the API version number */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#undef vl_api_version + +#include +#include +#include + +#if VPPJNI_DEBUG == 1 + #define DEBUG_LOG(...) clib_warning(__VA_ARGS__) +#else + #define DEBUG_LOG(...) +#endif + +#include + +#include "jvpp-ioamtrace/io_fd_vpp_jvpp_ioamtrace_JVppIoamtraceImpl.h" +#include "jvpp_ioam_trace.h" +#include "jvpp-ioamtrace/jvpp_ioamtrace_gen.h" + +/* + * Class: io_fd_vpp_jvpp_ioamtrace_JVppIoamtraceImpl + * Method: init0 + * Signature: (JI)V + */ +JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_ioamtrace_JVppIoamtraceImpl_init0 + (JNIEnv *env, jclass clazz, jobject callback, jlong queue_address, jint my_client_index) { + ioamtrace_main_t * plugin_main = &ioamtrace_main; + u8 * name; + clib_warning ("Java_io_fd_vpp_jvpp_ioamtrace_JVppIoamtraceImpl_init0"); + + plugin_main->my_client_index = my_client_index; + plugin_main->vl_input_queue = (unix_shared_memory_queue_t *)queue_address; + + name = format (0, "ioam_trace_%08x%c", api_version, 0); + plugin_main->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name); + + if (plugin_main->msg_id_base == (u16) ~0) { + jclass exClass = (*env)->FindClass(env, "java/lang/IllegalStateException"); + (*env)->ThrowNew(env, exClass, "ioam_trace plugin is not loaded in VPP"); + } else { + plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback); + plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback)); + + #define _(N,n) \ + vl_msg_api_set_handlers(VL_API_##N + plugin_main->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_api_reply_handler; + #undef _ + } +} + +JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_ioamtrace_JVppIoamtraceImpl_close0 +(JNIEnv *env, jclass clazz) { + ioamtrace_main_t * plugin_main = &ioamtrace_main; + + // cleanup: + (*env)->DeleteGlobalRef(env, plugin_main->callbackClass); + (*env)->DeleteGlobalRef(env, plugin_main->callbackObject); + + plugin_main->callbackClass = NULL; + plugin_main->callbackObject = NULL; +} + +/* Attach thread to JVM and cache class references when initiating JVPP iOAM Trace */ +jint JNI_OnLoad(JavaVM *vm, void *reserved) { + JNIEnv* env; + + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { + return JNI_EVERSION; + } + + if (cache_class_references(env) != 0) { + clib_warning ("Failed to cache class references\n"); + return JNI_ERR; + } + + return JNI_VERSION_1_8; +} + +/* Clean up cached references when disposing JVPP iOAM Trace */ +void JNI_OnUnload(JavaVM *vm, void *reserved) { + JNIEnv* env; + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { + return; + } + delete_class_references(env); +} diff --git a/src/vpp-api/java/jvpp-ioamtrace/jvpp_ioam_trace.h b/src/vpp-api/java/jvpp-ioamtrace/jvpp_ioam_trace.h new file mode 100644 index 00000000..9fc16c15 --- /dev/null +++ b/src/vpp-api/java/jvpp-ioamtrace/jvpp_ioam_trace.h @@ -0,0 +1,45 @@ +/* + * 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. + */ +#ifndef __included_jvpp_ioam_trace_h__ +#define __included_jvpp_ioam_trace_h__ + +#include +#include +#include +#include +#include +#include + +/* Global state for JVPP-IOAM-TRACE */ +typedef struct { + /* Base message index for the trace plugin */ + u16 msg_id_base; + + /* Pointer to shared memory queue */ + unix_shared_memory_queue_t * vl_input_queue; + + /* VPP api client index */ + u32 my_client_index; + + /* Callback object and class references enabling asynchronous Java calls */ + jobject callbackObject; + jclass callbackClass; + +} ioamtrace_main_t; + +ioamtrace_main_t ioamtrace_main __attribute__((aligned (64))); + + +#endif /* __included_jvpp_ioam_trace_h__ */ diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVpp.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVpp.java new file mode 100644 index 00000000..55f25a7b --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVpp.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp; + +import io.fd.vpp.jvpp.callback.JVppCallback; +import io.fd.vpp.jvpp.dto.ControlPing; +import io.fd.vpp.jvpp.dto.JVppRequest; + +/** + * Base interface for plugin's Java API. + */ +public interface JVpp extends AutoCloseable { + + /** + * Sends request to vpp. + * + * @param request request to be sent + * @return unique identifer of message in message queue + * @throws VppInvocationException when message could not be sent + */ + int send(final JVppRequest request) throws VppInvocationException; + + /** + * Initializes plugin's Java API. + * + * @param registry plugin registry + * @param callback called by vpe.api message handlers + * @param queueAddress address of vpp shared memory queue + * @param clientIndex vpp client identifier + */ + void init(final JVppRegistry registry, final JVppCallback callback, final long queueAddress, + final int clientIndex); + + /** + * Sends control_ping message. + * + * @param controlPing request DTO + * @return unique identifer of message in message queue + * @throws VppInvocationException when message could not be sent + */ + int controlPing(final ControlPing controlPing) throws VppInvocationException; +} diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVppRegistry.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVppRegistry.java new file mode 100644 index 00000000..6535db02 --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVppRegistry.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp; + +import io.fd.vpp.jvpp.callback.JVppCallback; + +/** + * Manages VPP connection and stores plugin callbacks. + */ +public interface JVppRegistry extends AutoCloseable { + + /** + * Vpp connection managed by the registry. + * + * @return representation of vpp connection + */ + VppConnection getConnection(); + + /** + * Registers callback and initializes Java API for given plugin. + * + * @param jvpp plugin name + * @param callback callback provided by the plugin + * @throws NullPointerException if name or callback is null + * @throws IllegalArgumentException if plugin was already registered + */ + void register(final JVpp jvpp, final JVppCallback callback); + + /** + * Unregisters callback for the given plugin. + * + * @param name plugin name + * @throws NullPointerException if name is null + * @throws IllegalArgumentException if plugin was not registered + */ + void unregister(final String name); + + /** + * Returns callback registered for the plugin. + * + * @param name plugin name + * @return callback provided by the plugin + * @throws NullPointerException if name is null + * @throws IllegalArgumentException if plugin was not registered + */ + JVppCallback get(final String name); + + /** + * Sends control ping. Reply handler calls callback registered for give plugin. + * + * Control ping is used for initial RX thread to Java thread attachment + * that takes place in the plugin's JNI lib + * and to wrap dump message replies in one list. + * + * VPP plugins don't have to provide special control ping, therefore + * it is necessary to providing control ping support in JVppRegistry. + + * @param clazz identifies plugin that should receive ping callback + * @return unique identifier of message in message queue + */ + int controlPing(final Class clazz) throws VppInvocationException; +} diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVppRegistryImpl.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVppRegistryImpl.java new file mode 100644 index 00000000..98ef1c15 --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVppRegistryImpl.java @@ -0,0 +1,147 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp; + +import static java.util.Objects.requireNonNull; + +import io.fd.vpp.jvpp.callback.ControlPingCallback; +import io.fd.vpp.jvpp.callback.JVppCallback; +import io.fd.vpp.jvpp.dto.ControlPingReply; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Default implementation of JVppRegistry. + */ +public final class JVppRegistryImpl implements JVppRegistry, ControlPingCallback { + + private static final Logger LOG = Logger.getLogger(JVppRegistryImpl.class.getName()); + + private final VppJNIConnection connection; + // Unguarded concurrent map, no race conditions expected on top of that + private final Map pluginRegistry; + // Guarded by self + private final Map pingCalls; + + public JVppRegistryImpl(final String clientName) throws IOException { + connection = new VppJNIConnection(clientName); + connection.connect(); + pluginRegistry = new ConcurrentHashMap<>(); + pingCalls = new HashMap<>(); + } + + @Override + public VppConnection getConnection() { + return connection; + } + + @Override + public void register(final JVpp jvpp, final JVppCallback callback) { + requireNonNull(jvpp, "jvpp should not be null"); + requireNonNull(callback, "Callback should not be null"); + final String name = jvpp.getClass().getName(); + if (pluginRegistry.containsKey(name)) { + throw new IllegalArgumentException( + String.format("Callback for plugin %s was already registered", name)); + } + jvpp.init(this, callback, connection.getConnectionInfo().queueAddress, + connection.getConnectionInfo().clientIndex); + pluginRegistry.put(name, callback); + } + + @Override + public void unregister(final String name) { + requireNonNull(name, "Plugin name should not be null"); + final JVppCallback previous = pluginRegistry.remove(name); + assertPluginWasRegistered(name, previous); + } + + @Override + public JVppCallback get(final String name) { + requireNonNull(name, "Plugin name should not be null"); + JVppCallback value = pluginRegistry.get(name); + assertPluginWasRegistered(name, value); + return value; + } + + private native int controlPing0() throws VppInvocationException; + + @Override + public int controlPing(final Class clazz) throws VppInvocationException { + connection.checkActive(); + final String name = clazz.getName(); + + final ControlPingCallback callback = (ControlPingCallback) pluginRegistry.get(clazz.getName()); + assertPluginWasRegistered(name, callback); + + synchronized (pingCalls) { + int context = controlPing0(); + if (context < 0) { + throw new VppInvocationException("controlPing", context); + } + + pingCalls.put(context, callback); + return context; + } + } + + @Override + public void onControlPingReply(final ControlPingReply reply) { + final ControlPingCallback callback; + synchronized (pingCalls) { + callback = pingCalls.remove(reply.context); + if (callback == null) { + LOG.log(Level.WARNING, "No callback was registered for reply context=" + reply.context + " Contexts waiting=" + + pingCalls.keySet()); + return; + } + } + // pass the reply to the callback registered by the ping caller + callback.onControlPingReply(reply); + } + + @Override + public void onError(final VppCallbackException ex) { + final int ctxId = ex.getCtxId(); + final ControlPingCallback callback; + + synchronized (pingCalls) { + callback = pingCalls.get(ctxId); + } + if (callback == null) { + LOG.log(Level.WARNING, "No callback was registered for reply id={0} ", ctxId); + return; + } + // pass the error to the callback registered by the ping caller + callback.onError(ex); + } + + private static void assertPluginWasRegistered(final String name, final JVppCallback value) { + if (value == null) { + throw new IllegalArgumentException(String.format("Callback for plugin %s is not registered", name)); + } + } + + @Override + public void close() throws Exception { + connection.close(); + } +} diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/NativeLibraryLoader.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/NativeLibraryLoader.java new file mode 100644 index 00000000..ce6d1bfc --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/NativeLibraryLoader.java @@ -0,0 +1,73 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Utility class for loading JNI libraries. + */ +public final class NativeLibraryLoader { + + private static final Logger LOG = Logger.getLogger(NativeLibraryLoader.class.getName()); + + private NativeLibraryLoader() { + throw new UnsupportedOperationException("This utility class cannot be instantiated."); + } + + /** + * Loads JNI library using class loader of the given class. + * + * @param libName name of the library to be loaded + */ + public static void loadLibrary(final String libName, final Class clazz) throws IOException { + java.util.Objects.requireNonNull(libName, "libName should not be null"); + java.util.Objects.requireNonNull(clazz, "clazz should not be null"); + try (final InputStream is = clazz.getResourceAsStream('/' + libName)) { + if (is == null) { + throw new IOException("Failed to open library resource " + libName); + } + loadStream(libName, is); + } + } + + private static void loadStream(final String libName, final InputStream is) throws IOException { + final Set perms = PosixFilePermissions.fromString("rwxr-x---"); + final Path p = Files.createTempFile(libName, null, PosixFilePermissions.asFileAttribute(perms)); + try { + Files.copy(is, p, StandardCopyOption.REPLACE_EXISTING); + Runtime.getRuntime().load(p.toString()); + } catch (Exception e) { + throw new IOException("Failed to load library " + p, e); + } finally { + try { + Files.deleteIfExists(p); + } catch (IOException e) { + LOG.log(Level.WARNING, String.format("Failed to delete temporary file %s.", p), e); + } + } + } +} diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppBaseCallException.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppBaseCallException.java new file mode 100644 index 00000000..d71e3055 --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppBaseCallException.java @@ -0,0 +1,60 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp; + +/** + * Base exception representing failed operation of JVpp request call + */ +public abstract class VppBaseCallException extends Exception { + private final String methodName; + private final int errorCode; + + /** + * Constructs an VppCallbackException with the specified api method name and error code. + * + * @param methodName name of a method, which invocation or execution failed + * @param errorCode negative error code value associated with this failure + * @throws NullPointerException if apiMethodName is null + */ + public VppBaseCallException(final String methodName, final int errorCode) { + super(String.format("vppApi.%s failed with error code: %d", methodName, errorCode)); + this.methodName = java.util.Objects.requireNonNull(methodName, "apiMethodName is null!"); + this.errorCode = errorCode; + if(errorCode >= 0) { + throw new IllegalArgumentException("Error code must be < 0. Was " + errorCode + + " for " + methodName ); + } + } + + /** + * Returns name of a method, which invocation failed. + * + * @return method name + */ + public String getMethodName() { + return methodName; + } + + /** + * Returns the error code associated with this failure. + * + * @return a negative integer error code + */ + public int getErrorCode() { + return errorCode; + } +} diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppCallbackException.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppCallbackException.java new file mode 100644 index 00000000..ccfcbd3c --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppCallbackException.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp; + +/** + * Callback Exception representing failed operation of JVpp request call + */ +public class VppCallbackException extends VppBaseCallException { + private final int ctxId; + + /** + * Constructs an VppCallbackException with the specified api method name and error code. + * + * @param methodName name of a method, which invocation failed. + * @param ctxId api request context identifier + * @param errorCode negative error code value associated with this failure + * @throws NullPointerException if apiMethodName is null + */ + public VppCallbackException(final String methodName, final int ctxId, final int errorCode ){ + super(methodName, errorCode); + this.ctxId = ctxId; + } + + /** + * Returns api request context identifier. + * + * @return value of context identifier + */ + public int getCtxId() { + return ctxId; + } + +} diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppConnection.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppConnection.java new file mode 100644 index 00000000..e6fd3bdb --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppConnection.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp; + +import java.io.IOException; + +/** + * Representation of a management connection to VPP. + */ +public interface VppConnection extends AutoCloseable { + + /** + * Opens VppConnection for communication with VPP. + * + * @throws IOException if connection is not established + */ + void connect() throws IOException; + + /** + * Checks if this instance connection is active. + * + * @throws IllegalStateException if this instance was disconnected. + */ + void checkActive(); + + /** + * Closes Vpp connection. + */ + @Override + void close(); +} diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppInvocationException.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppInvocationException.java new file mode 100644 index 00000000..a7ccb197 --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppInvocationException.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp; + +/** + * Exception thrown when Vpp jAPI method invocation failed. + */ +public class VppInvocationException extends VppBaseCallException { + /** + * Constructs an VppApiInvocationFailedException with the specified api method name and error code. + * + * @param methodName name of a method, which invocation failed. + * @param errorCode negative error code value associated with this failure + * @throws NullPointerException if apiMethodName is null + */ + public VppInvocationException(final String methodName, final int errorCode) { + super(methodName, errorCode); + } +} diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppJNIConnection.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppJNIConnection.java new file mode 100644 index 00000000..320c1283 --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppJNIConnection.java @@ -0,0 +1,137 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp; + +import static io.fd.vpp.jvpp.NativeLibraryLoader.loadLibrary; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * JNI based representation of a management connection to VPP. + */ +public final class VppJNIConnection implements VppConnection { + private static final Logger LOG = Logger.getLogger(VppJNIConnection.class.getName()); + + static { + final String libName = "libjvpp_registry.so"; + try { + loadLibrary(libName, VppJNIConnection.class); + } catch (IOException e) { + LOG.log(Level.SEVERE, String.format("Can't find vpp jni library: %s", libName), e); + throw new ExceptionInInitializerError(e); + } + } + + private ConnectionInfo connectionInfo; + + private final String clientName; + private volatile boolean disconnected = false; + + /** + * Create VPPJNIConnection instance for client connecting to VPP. + * + * @param clientName client name instance to be used for communication. Single connection per clientName is + * allowed. + */ + public VppJNIConnection(final String clientName) { + this.clientName = Objects.requireNonNull(clientName, "Null clientName"); + } + + /** + * Guarded by VppJNIConnection.class + */ + private static final Map connections = new HashMap<>(); + + /** + * Initiate VPP connection for current instance + * + * Multiple instances are allowed since this class is not a singleton (VPP allows multiple management connections). + * + * However only a single connection per clientName is allowed. + * + * @throws IOException in case the connection could not be established + */ + + @Override + public void connect() throws IOException { + _connect(); + } + + private void _connect() throws IOException { + synchronized (VppJNIConnection.class) { + if (connections.containsKey(clientName)) { + throw new IOException("Client " + clientName + " already connected"); + } + + connectionInfo = clientConnect(clientName); + if (connectionInfo.status != 0) { + throw new IOException("Connection returned error " + connectionInfo.status); + } + connections.put(clientName, this); + } + } + + @Override + public final void checkActive() { + if (disconnected) { + throw new IllegalStateException("Disconnected client " + clientName); + } + } + + @Override + public final synchronized void close() { + if (!disconnected) { + disconnected = true; + try { + clientDisconnect(); + } finally { + synchronized (VppJNIConnection.class) { + connections.remove(clientName); + } + } + } + } + + public ConnectionInfo getConnectionInfo() { + return connectionInfo; + } + + /** + * VPP connection information used by plugins to reuse the connection. + */ + public static final class ConnectionInfo { + public final long queueAddress; + public final int clientIndex; + public final int status; // FIXME throw exception instead + + public ConnectionInfo(long queueAddress, int clientIndex, int status) { + this.queueAddress = queueAddress; + this.clientIndex = clientIndex; + this.status = status; + } + } + + private static native ConnectionInfo clientConnect(String clientName); + + private static native void clientDisconnect(); + +} diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/ControlPingCallback.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/ControlPingCallback.java new file mode 100644 index 00000000..efddfdbb --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/ControlPingCallback.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.callback; + +import io.fd.vpp.jvpp.dto.ControlPingReply; + +/** + * Represents callback for control_ping message. + */ +public interface ControlPingCallback extends JVppCallback { + + void onControlPingReply(ControlPingReply reply); + +} + diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/JVppCallback.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/JVppCallback.java new file mode 100644 index 00000000..ae02063b --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/JVppCallback.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.callback; +import io.fd.vpp.jvpp.VppCallbackException; + +/** + * Base JVppCallback interface + */ +public interface JVppCallback { + /** + * onError callback handler used to report failing operation + * @param ex VppCallbackException object containing details about failing operation + */ + void onError(VppCallbackException ex); +} diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/JVppNotificationCallback.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/JVppNotificationCallback.java new file mode 100644 index 00000000..8ab0cb21 --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/JVppNotificationCallback.java @@ -0,0 +1,24 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.callback; + +/** +* Notification callback +*/ +public interface JVppNotificationCallback { + +} diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/ControlPing.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/ControlPing.java new file mode 100644 index 00000000..984e1674 --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/ControlPing.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.dto; + +import io.fd.vpp.jvpp.JVpp; +import io.fd.vpp.jvpp.VppInvocationException; + +/** + * Represents request DTO for control_ping message. + */ +public final class ControlPing implements JVppRequest { + + @Override + public int send(final JVpp jvpp) throws VppInvocationException { + return jvpp.controlPing(this); + } + +} + + diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/ControlPingReply.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/ControlPingReply.java new file mode 100644 index 00000000..61e4d0e4 --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/ControlPingReply.java @@ -0,0 +1,58 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.dto; + +import java.util.Objects; + +/** + * Represents reply DTO for control_ping message. + */ +public final class ControlPingReply implements JVppReply { + + public int context; + public int clientIndex; + public int vpePid; + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final ControlPingReply that = (ControlPingReply) o; + return context == that.context && + clientIndex == that.clientIndex && + vpePid == that.vpePid; + } + + @Override + public int hashCode() { + return Objects.hash(context, clientIndex, vpePid); + } + + @Override + public String toString() { + return "ControlPingReply{" + + "context=" + context + + ", clientIndex=" + clientIndex + + ", vpePid=" + vpePid + + '}'; + } +} + diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppDump.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppDump.java new file mode 100644 index 00000000..60b98984 --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppDump.java @@ -0,0 +1,24 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.dto; + +/** +* Base interface for all dump requests +*/ +public interface JVppDump extends JVppRequest { + +} diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppNotification.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppNotification.java new file mode 100644 index 00000000..5554f501 --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppNotification.java @@ -0,0 +1,23 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.dto; + +/** +* Base interface for all notification DTOs +*/ +public interface JVppNotification { +} diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppReply.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppReply.java new file mode 100644 index 00000000..73f512d4 --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppReply.java @@ -0,0 +1,24 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.dto; + +/** +* Base interface for all reply DTOs +*/ +public interface JVppReply { + +} diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppReplyDump.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppReplyDump.java new file mode 100644 index 00000000..15111395 --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppReplyDump.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.dto; + +/** +* Base interface for all dump replies +*/ +public interface JVppReplyDump> + extends JVppReply { + +} diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppRequest.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppRequest.java new file mode 100644 index 00000000..9b301da2 --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppRequest.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.dto; + +import io.fd.vpp.jvpp.JVpp; +import io.fd.vpp.jvpp.VppInvocationException; + +/** +* Base interface for all request DTOs +*/ +public interface JVppRequest { + + /** + * Invoke current operation asynchronously on VPP + * + * @return context id of this request. Can be used to track incoming response + */ + int send(JVpp jvpp) throws VppInvocationException; + +} diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/future/AbstractFutureJVppInvoker.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/future/AbstractFutureJVppInvoker.java new file mode 100644 index 00000000..e7df528a --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/future/AbstractFutureJVppInvoker.java @@ -0,0 +1,141 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.future; + + +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import io.fd.vpp.jvpp.JVpp; +import io.fd.vpp.jvpp.JVppRegistry; +import io.fd.vpp.jvpp.VppInvocationException; +import io.fd.vpp.jvpp.dto.JVppDump; +import io.fd.vpp.jvpp.dto.JVppReply; +import io.fd.vpp.jvpp.dto.JVppReplyDump; +import io.fd.vpp.jvpp.dto.JVppRequest; + +/** + * Future facade on top of JVpp + */ +public abstract class AbstractFutureJVppInvoker implements FutureJVppInvoker { + + private final JVpp jvpp; + private final JVppRegistry registry; + + /** + * Guarded by self + */ + private final Map>> requests; + + protected AbstractFutureJVppInvoker(final JVpp jvpp, final JVppRegistry registry, + final Map>> requestMap) { + this.jvpp = Objects.requireNonNull(jvpp, "jvpp should not be null"); + this.registry = Objects.requireNonNull(registry, "registry should not be null"); + // Request map represents the shared state between this facade and it's callback + // where facade puts futures in and callback completes + removes them + this.requests = Objects.requireNonNull(requestMap, "Null requestMap"); + } + + protected final Map>> getRequests() { + synchronized (requests) { + return requests; + } + } + + // TODO use Optional in Future, java8 + + @Override + @SuppressWarnings("unchecked") + public > CompletionStage send(REQ req) { + synchronized(requests) { + try { + final CompletableFuture replyCompletableFuture; + final int contextId = jvpp.send(req); + + if(req instanceof JVppDump) { + throw new IllegalArgumentException("Send with empty reply dump has to be used in case of dump calls"); + } + replyCompletableFuture = new CompletableFuture<>(); + requests.put(contextId, replyCompletableFuture); + + // TODO in case of timeouts/missing replies, requests from the map are not removed + // consider adding cancel method, that would remove requests from the map and cancel + // associated replyCompletableFuture + + return replyCompletableFuture; + } catch (VppInvocationException ex) { + final CompletableFuture replyCompletableFuture = new CompletableFuture<>(); + replyCompletableFuture.completeExceptionally(ex); + return replyCompletableFuture; + } + } + } + + @Override + @SuppressWarnings("unchecked") + public , DUMP extends JVppReplyDump> CompletionStage send( + REQ req, DUMP emptyReplyDump) { + synchronized(requests) { + try { + final CompletableDumpFuture replyCompletableFuture; + final int contextId = jvpp.send(req); + + if(!(req instanceof JVppDump)) { + throw new IllegalArgumentException("Send without empty reply dump has to be used in case of regular calls"); + } + replyCompletableFuture = new CompletableDumpFuture<>(contextId, emptyReplyDump); + + requests.put(contextId, replyCompletableFuture); + requests.put(registry.controlPing(jvpp.getClass()), replyCompletableFuture); + + // TODO in case of timeouts/missing replies, requests from the map are not removed + // consider adding cancel method, that would remove requests from the map and cancel + // associated replyCompletableFuture + + return replyCompletableFuture; + } catch (VppInvocationException ex) { + final CompletableFuture replyCompletableFuture = new CompletableFuture<>(); + replyCompletableFuture.completeExceptionally(ex); + return replyCompletableFuture; + } + } + } + + public static final class CompletableDumpFuture> extends CompletableFuture { + private final T replyDump; + private final int contextId; + + public CompletableDumpFuture(final int contextId, final T emptyDump) { + this.contextId = contextId; + this.replyDump = emptyDump; + } + + public int getContextId() { + return contextId; + } + + public T getReplyDump() { + return replyDump; + } + } + + @Override + public void close() throws Exception { + jvpp.close(); + } +} diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/future/FutureJVppInvoker.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/future/FutureJVppInvoker.java new file mode 100644 index 00000000..7a48e418 --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/future/FutureJVppInvoker.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.future; + + +import io.fd.vpp.jvpp.dto.JVppReply; +import io.fd.vpp.jvpp.dto.JVppReplyDump; +import io.fd.vpp.jvpp.dto.JVppRequest; + +import java.util.concurrent.CompletionStage; +import io.fd.vpp.jvpp.notification.NotificationRegistryProvider; + +/** +* Future facade on top of JVpp +*/ +public interface FutureJVppInvoker extends NotificationRegistryProvider, AutoCloseable { + + /** + * Invoke asynchronous operation on VPP + * + * @return CompletionStage with future result of an async VPP call + * @throws io.fd.vpp.jvpp.VppInvocationException when send request failed with details + */ + > CompletionStage send(REQ req); + + + /** + * Invoke asynchronous dump operation on VPP + * + * @return CompletionStage with aggregated future result of an async VPP dump call + * @throws io.fd.vpp.jvpp.VppInvocationException when send request failed with details + */ + , DUMP extends JVppReplyDump> CompletionStage send( + REQ req, DUMP emptyReplyDump); +} diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/notification/NotificationRegistry.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/notification/NotificationRegistry.java new file mode 100644 index 00000000..3c72ff79 --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/notification/NotificationRegistry.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.notification; + +/** + * Base registry for notification callbacks. + */ +public interface NotificationRegistry extends AutoCloseable { + + void close(); +} diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/notification/NotificationRegistryProvider.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/notification/NotificationRegistryProvider.java new file mode 100644 index 00000000..4a6e06b7 --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/notification/NotificationRegistryProvider.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.notification; + +/** + * Provides notification registry + */ +public interface NotificationRegistryProvider { + + /** + * Get current notification registry instance + */ + NotificationRegistry getNotificationRegistry(); +} diff --git a/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/test/ConnectionTest.java b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/test/ConnectionTest.java new file mode 100644 index 00000000..27b4d29f --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/test/ConnectionTest.java @@ -0,0 +1,44 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.test; + +import io.fd.vpp.jvpp.JVppRegistry; +import io.fd.vpp.jvpp.JVppRegistryImpl; + +/** + * Run using: + * sudo java -cp build-vpp-native/vpp-api/java/jvpp-registry-16.09.jar io.fd.vpp.jvpp.test.ConnectionTest + */ +public class ConnectionTest { + + private static void testConnect() throws Exception { + System.out.println("Testing JNI connection with JVppRegistry"); + final JVppRegistry registry = new JVppRegistryImpl("ConnectionTest"); + try { + System.out.println("Successfully connected to vpp"); + Thread.sleep(5000); + System.out.println("Disconnecting..."); + Thread.sleep(1000); + } finally { + registry.close(); + } + } + + public static void main(String[] args) throws Exception { + testConnect(); + } +} diff --git a/src/vpp-api/java/jvpp-registry/jvpp_registry.c b/src/vpp-api/java/jvpp-registry/jvpp_registry.c new file mode 100644 index 00000000..cbd5e0ab --- /dev/null +++ b/src/vpp-api/java/jvpp-registry/jvpp_registry.c @@ -0,0 +1,352 @@ +/* + * 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. + */ +#define _GNU_SOURCE /* for strcasestr(3) */ +#include + +#define vl_api_version(n,v) static u32 vpe_api_version = (v); +#include +#undef vl_api_version + + +#include +#include +#include "io_fd_vpp_jvpp_VppJNIConnection.h" +#include "io_fd_vpp_jvpp_JVppRegistryImpl.h" + +#include +#define vl_typedefs /* define message structures */ +#include +#undef vl_typedefs + +#define vl_endianfun +#include +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) +#define vl_printfun +#include +#undef vl_printfun + +vlib_main_t vlib_global_main; +vlib_main_t **vlib_mains; + +/* + * The Java runtime isn't compile w/ -fstack-protector, + * so we have to supply missing external references for the + * regular vpp libraries. + */ +void __stack_chk_guard(void) __attribute__((weak)); +void __stack_chk_guard(void) { +} + +typedef struct { + /* UThread attachment */ + volatile u32 control_ping_result_ready; + volatile i32 control_ping_retval; + + /* Control poing callback */ + jobject registryObject; + jclass registryClass; + jclass controlPingReplyClass; + jclass callbackExceptionClass; + + /* Thread cleanup */ + pthread_key_t cleanup_rx_thread_key; + + /* Connected indication */ + volatile u8 is_connected; +} jvpp_registry_main_t; + +jvpp_registry_main_t jvpp_registry_main __attribute__((aligned (64))); + +void vl_client_add_api_signatures(vl_api_memclnt_create_t *mp) { + /* + * Send the main API signature in slot 0. This bit of code must + * match the checks in ../vpe/api/api.c: vl_msg_api_version_check(). + */ + mp->api_versions[0] = clib_host_to_net_u32(vpe_api_version); +} + +/* cleanup handler for RX thread */ +static_always_inline void cleanup_rx_thread(void *arg) { + jvpp_main_t * jm = &jvpp_main; + jvpp_registry_main_t * rm = &jvpp_registry_main; + + vppjni_lock(jm, 99); + + int getEnvStat = (*jm->jvm)->GetEnv(jm->jvm, (void **) &(jm->jenv), + JNI_VERSION_1_8); + if (getEnvStat == JNI_EVERSION) { + clib_warning("Unsupported JNI version\n"); + rm->control_ping_retval = VNET_API_ERROR_UNSUPPORTED_JNI_VERSION; + goto out; + } else if (getEnvStat != JNI_EDETACHED) { + (*jm->jvm)->DetachCurrentThread(jm->jvm); + } + out: vppjni_unlock(jm); +} + +static void vl_api_control_ping_reply_t_handler( + vl_api_control_ping_reply_t * mp) { + jvpp_main_t * jm = &jvpp_main; + jvpp_registry_main_t * rm = &jvpp_registry_main; + char was_thread_connected = 0; + + // attach to java thread if not attached + int getEnvStat = (*jm->jvm)->GetEnv(jm->jvm, (void **) &(jm->jenv), + JNI_VERSION_1_8); + if (getEnvStat == JNI_EDETACHED) { + if ((*jm->jvm)->AttachCurrentThread(jm->jvm, (void **) &(jm->jenv), + NULL) != 0) { + clib_warning("Failed to attach thread\n"); + rm->control_ping_retval = + VNET_API_ERROR_FAILED_TO_ATTACH_TO_JAVA_THREAD; + goto out; + } + + // workaround as we can't use pthread_cleanup_push + pthread_key_create(&rm->cleanup_rx_thread_key, cleanup_rx_thread); + // destructor is only called if the value of key is non null + pthread_setspecific(rm->cleanup_rx_thread_key, (void *) 1); + was_thread_connected = 1; + } else if (getEnvStat == JNI_EVERSION) { + clib_warning("Unsupported JNI version\n"); + rm->control_ping_retval = VNET_API_ERROR_UNSUPPORTED_JNI_VERSION; + goto out; + } + + if (was_thread_connected == 0) { + JNIEnv *env = jm->jenv; + if (mp->retval < 0) { + call_on_error("controlPing", mp->context, mp->retval, + rm->registryClass, rm->registryObject, + rm->callbackExceptionClass); + } else { + jmethodID constructor = (*env)->GetMethodID(env, + rm->controlPingReplyClass, "", "()V"); + jmethodID callbackMethod = (*env)->GetMethodID(env, + rm->registryClass, "onControlPingReply", + "(Lio/fd/vpp/jvpp/dto/ControlPingReply;)V"); + + jobject dto = (*env)->NewObject(env, rm->controlPingReplyClass, + constructor); + + jfieldID contextFieldId = (*env)->GetFieldID(env, + rm->controlPingReplyClass, "context", "I"); + (*env)->SetIntField(env, dto, contextFieldId, + clib_net_to_host_u32(mp->context)); + + jfieldID clientIndexFieldId = (*env)->GetFieldID(env, + rm->controlPingReplyClass, "clientIndex", "I"); + (*env)->SetIntField(env, dto, clientIndexFieldId, + clib_net_to_host_u32(mp->client_index)); + + jfieldID vpePidFieldId = (*env)->GetFieldID(env, + rm->controlPingReplyClass, "vpePid", "I"); + (*env)->SetIntField(env, dto, vpePidFieldId, + clib_net_to_host_u32(mp->vpe_pid)); + + (*env)->CallVoidMethod(env, rm->registryObject, callbackMethod, + dto); + (*env)->DeleteLocalRef(env, dto); + } + } + + out: rm->control_ping_result_ready = 1; +} + +static int send_initial_control_ping() { + f64 timeout; + clib_time_t clib_time; + vl_api_control_ping_t * mp; + jvpp_main_t * jm = &jvpp_main; + jvpp_registry_main_t * rm = &jvpp_registry_main; + + clib_time_init(&clib_time); + + rm->control_ping_result_ready = 0; + mp = vl_msg_api_alloc(sizeof(*mp)); + memset(mp, 0, sizeof(*mp)); + mp->_vl_msg_id = ntohs(VL_API_CONTROL_PING); + mp->client_index = jm->my_client_index; + + // send message: + vl_msg_api_send_shmem(jm->vl_input_queue, (u8 *) &mp); + + // wait for results: Current time + 10 seconds is the timeout + timeout = clib_time_now(&clib_time) + 10.0; + int rv = VNET_API_ERROR_RESPONSE_NOT_READY; + while (clib_time_now(&clib_time) < timeout) { + if (rm->control_ping_result_ready == 1) { + rv = rm->control_ping_retval; + break; + } + } + + if (rv != 0) { + clib_warning("common: first control ping failed: %d", rv); + } + + return rv; +} + +static int connect_to_vpe(char *name) { + jvpp_main_t * jm = &jvpp_main; + api_main_t * am = &api_main; + + if (vl_client_connect_to_vlib("/vpe-api", name, 32) < 0) + return -1; + + jm->my_client_index = am->my_client_index; + + jm->vl_input_queue = am->shmem_hdr->vl_input_queue; + + vl_msg_api_set_handlers(VL_API_CONTROL_PING_REPLY, "control_ping_reply", + vl_api_control_ping_reply_t_handler, vl_noop_handler, + vl_api_control_ping_reply_t_endian, + vl_api_control_ping_reply_t_print, + sizeof(vl_api_control_ping_reply_t), 1); + + return send_initial_control_ping(); +} + +JNIEXPORT jobject JNICALL Java_io_fd_vpp_jvpp_VppJNIConnection_clientConnect( + JNIEnv *env, jclass obj, jstring clientName) { + int rv; + const char *client_name; + void vl_msg_reply_handler_hookup(void); + jvpp_main_t * jm = &jvpp_main; + jvpp_registry_main_t * rm = &jvpp_registry_main; + + jclass connectionInfoClass = (*env)->FindClass(env, + "io/fd/vpp/jvpp/VppJNIConnection$ConnectionInfo"); + jmethodID connectionInfoConstructor = (*env)->GetMethodID(env, + connectionInfoClass, "", "(JII)V"); + + /* + * Bail out now if we're not running as root + */ + if (geteuid() != 0) { + return (*env)->NewObject(env, connectionInfoClass, + connectionInfoConstructor, 0, 0, + VNET_API_ERROR_NOT_RUNNING_AS_ROOT); + } + + if (rm->is_connected) { + return (*env)->NewObject(env, connectionInfoClass, + connectionInfoConstructor, 0, 0, + VNET_API_ERROR_ALREADY_CONNECTED); + } + + client_name = (*env)->GetStringUTFChars(env, clientName, 0); + if (!client_name) { + return (*env)->NewObject(env, connectionInfoClass, + connectionInfoConstructor, 0, 0, VNET_API_ERROR_INVALID_VALUE); + } + + rv = connect_to_vpe((char *) client_name); + + if (rv < 0) + clib_warning("connection failed, rv %d", rv); + + (*env)->ReleaseStringUTFChars(env, clientName, client_name); + + return (*env)->NewObject(env, connectionInfoClass, + connectionInfoConstructor, (jlong) jm->vl_input_queue, + (jint) jm->my_client_index, (jint) rv); +} + +JNIEXPORT jint JNICALL Java_io_fd_vpp_jvpp_JVppRegistryImpl_controlPing0( + JNIEnv *env, jobject regstryObject) { + jvpp_main_t * jm = &jvpp_main; + vl_api_control_ping_t * mp; + u32 my_context_id = vppjni_get_context_id(&jvpp_main); + jvpp_registry_main_t * rm = &jvpp_registry_main; + + if (rm->registryObject == 0) { + rm->registryObject = (*env)->NewGlobalRef(env, regstryObject); + } + if (rm->registryClass == 0) { + rm->registryClass = (jclass) (*env)->NewGlobalRef(env, + (*env)->GetObjectClass(env, regstryObject)); + } + + mp = vl_msg_api_alloc(sizeof(*mp)); + memset(mp, 0, sizeof(*mp)); + mp->_vl_msg_id = ntohs(VL_API_CONTROL_PING); + mp->client_index = jm->my_client_index; + mp->context = clib_host_to_net_u32(my_context_id); + + // send message: + vl_msg_api_send_shmem(jm->vl_input_queue, (u8 *) &mp); + return my_context_id; +} + +JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_VppJNIConnection_clientDisconnect( + JNIEnv *env, jclass clazz) { + jvpp_registry_main_t * rm = &jvpp_registry_main; + rm->is_connected = 0; // TODO make thread safe + vl_client_disconnect_from_vlib(); + + // cleanup: + if (rm->registryObject) { + (*env)->DeleteGlobalRef(env, rm->registryObject); + rm->registryObject = 0; + } + if (rm->registryClass) { + (*env)->DeleteGlobalRef(env, rm->registryClass); + rm->registryClass = 0; + } +} + +jint JNI_OnLoad(JavaVM *vm, void *reserved) { + jvpp_main_t * jm = &jvpp_main; + jvpp_registry_main_t * rm = &jvpp_registry_main; + JNIEnv* env; + + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { + return JNI_EVERSION; + } + + rm->controlPingReplyClass = (jclass) (*env)->NewGlobalRef(env, + (*env)->FindClass(env, "io/fd/vpp/jvpp/dto/ControlPingReply")); + if ((*env)->ExceptionCheck(env)) { + (*env)->ExceptionDescribe(env); + clib_warning("Failed to cache class references\n"); + return JNI_ERR; + } + + rm->callbackExceptionClass = (jclass) (*env)->NewGlobalRef(env, + (*env)->FindClass(env, "io/fd/vpp/jvpp/VppCallbackException")); + if ((*env)->ExceptionCheck(env)) { + (*env)->ExceptionDescribe(env); + return JNI_ERR; + } + + jm->jvm = vm; + return JNI_VERSION_1_8; +} + +void JNI_OnUnload(JavaVM *vm, void *reserved) { + jvpp_main_t * jm = &jvpp_main; + JNIEnv* env; + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { + return; + } + + jm->jenv = NULL; + jm->jvm = NULL; +} diff --git a/src/vpp-api/java/jvpp-snat/io/fd/vpp/jvpp/snat/test/CallbackApiTest.java b/src/vpp-api/java/jvpp-snat/io/fd/vpp/jvpp/snat/test/CallbackApiTest.java new file mode 100644 index 00000000..32165d96 --- /dev/null +++ b/src/vpp-api/java/jvpp-snat/io/fd/vpp/jvpp/snat/test/CallbackApiTest.java @@ -0,0 +1,68 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.snat.test; + +import io.fd.vpp.jvpp.JVpp; +import io.fd.vpp.jvpp.JVppRegistry; +import io.fd.vpp.jvpp.JVppRegistryImpl; +import io.fd.vpp.jvpp.VppCallbackException; +import io.fd.vpp.jvpp.snat.JVppSnatImpl; +import io.fd.vpp.jvpp.snat.callback.SnatInterfaceAddDelFeatureCallback; +import io.fd.vpp.jvpp.snat.dto.SnatInterfaceAddDelFeature; +import io.fd.vpp.jvpp.snat.dto.SnatInterfaceAddDelFeatureReply; + +public class CallbackApiTest { + + static class TestCallback implements SnatInterfaceAddDelFeatureCallback { + + @Override + public void onSnatInterfaceAddDelFeatureReply(final SnatInterfaceAddDelFeatureReply msg) { + System.out.printf("Received SnatInterfaceAddDelFeatureReply: context=%d%n", + msg.context); + } + + @Override + public void onError(VppCallbackException ex) { + System.out.printf("Received onError exception: call=%s, context=%d, retval=%d%n", ex.getMethodName(), + ex.getCtxId(), ex.getErrorCode()); + } + } + + public static void main(String[] args) throws Exception { + testCallbackApi(); + } + + private static void testCallbackApi() throws Exception { + System.out.println("Testing Java callback API for snat plugin"); + try (final JVppRegistry registry = new JVppRegistryImpl("SnatCallbackApiTest"); + final JVpp jvpp = new JVppSnatImpl()) { + registry.register(jvpp, new TestCallback()); + + System.out.println("Sending SnatInterfaceAddDelFeature request..."); + SnatInterfaceAddDelFeature request = new SnatInterfaceAddDelFeature(); + request.isAdd = 1; + request.isInside = 1; + request.swIfIndex = 1; + final int result = jvpp.send(request); + System.out.printf("SnatInterfaceAddDelFeature send result = %d%n", result); + + Thread.sleep(1000); + + System.out.println("Disconnecting..."); + } + } +} diff --git a/src/vpp-api/java/jvpp-snat/io/fd/vpp/jvpp/snat/test/Readme.txt b/src/vpp-api/java/jvpp-snat/io/fd/vpp/jvpp/snat/test/Readme.txt new file mode 100644 index 00000000..a2b0c41f --- /dev/null +++ b/src/vpp-api/java/jvpp-snat/io/fd/vpp/jvpp/snat/test/Readme.txt @@ -0,0 +1 @@ +sudo java -cp build-vpp-native/vpp-api/java/jvpp-registry-17.01.jar:build-vpp-native/plugins/snat-plugin/jvpp-snat-1.0.jar io.fd.vpp.jvpp.snat.test.CallbackApiTest diff --git a/src/vpp-api/java/jvpp-snat/jvpp_snat.c b/src/vpp-api/java/jvpp-snat/jvpp_snat.c new file mode 100644 index 00000000..1095b6eb --- /dev/null +++ b/src/vpp-api/java/jvpp-snat/jvpp_snat.c @@ -0,0 +1,124 @@ +/* + * 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. + */ + +#include + +#include +#define vl_typedefs /* define message structures */ +#include +#undef vl_typedefs + +#define vl_endianfun +#include +#undef vl_endianfun + +#define vl_print(handle, ...) +#define vl_printfun +#include +#undef vl_printfun + +/* Get the API version number */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#undef vl_api_version + +#include +#include +#include + +#if VPPJNI_DEBUG == 1 + #define DEBUG_LOG(...) clib_warning(__VA_ARGS__) +#else + #define DEBUG_LOG(...) +#endif + +#include + +#include "jvpp-snat/io_fd_vpp_jvpp_snat_JVppSnatImpl.h" +#include "jvpp_snat.h" +#include "jvpp-snat/jvpp_snat_gen.h" + +/* + * Class: io_fd_vpp_jvpp_snat_JVppsnatImpl + * Method: init0 + * Signature: (JI)V + */ +JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_snat_JVppSnatImpl_init0 + (JNIEnv *env, jclass clazz, jobject callback, jlong queue_address, jint my_client_index) { + snat_main_t * plugin_main = &snat_main; + u8 * name; + clib_warning ("Java_io_fd_vpp_jvpp_snat_JVppSnatImpl_init0"); + + plugin_main->my_client_index = my_client_index; + plugin_main->vl_input_queue = (unix_shared_memory_queue_t *)queue_address; + + name = format (0, "snat_%08x%c", api_version, 0); + plugin_main->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name); + + if (plugin_main->msg_id_base == (u16) ~0) { + jclass exClass = (*env)->FindClass(env, "java/lang/IllegalStateException"); + (*env)->ThrowNew(env, exClass, "snat plugin is not loaded in VPP"); + } else { + plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback); + plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback)); + + #define _(N,n) \ + vl_msg_api_set_handlers(VL_API_##N + plugin_main->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_api_reply_handler; + #undef _ + } +} + +JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_snat_JVppSnatImpl_close0 +(JNIEnv *env, jclass clazz) { + snat_main_t * plugin_main = &snat_main; + + // cleanup: + (*env)->DeleteGlobalRef(env, plugin_main->callbackClass); + (*env)->DeleteGlobalRef(env, plugin_main->callbackObject); + + plugin_main->callbackClass = NULL; + plugin_main->callbackObject = NULL; +} + +/* Attach thread to JVM and cache class references when initiating JVPP SNAT */ +jint JNI_OnLoad(JavaVM *vm, void *reserved) { + JNIEnv* env; + + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { + return JNI_EVERSION; + } + + if (cache_class_references(env) != 0) { + clib_warning ("Failed to cache class references\n"); + return JNI_ERR; + } + + return JNI_VERSION_1_8; +} + +/* Clean up cached references when disposing JVPP SNAT */ +void JNI_OnUnload(JavaVM *vm, void *reserved) { + JNIEnv* env; + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { + return; + } + delete_class_references(env); +} diff --git a/src/vpp-api/java/jvpp-snat/jvpp_snat.h b/src/vpp-api/java/jvpp-snat/jvpp_snat.h new file mode 100644 index 00000000..6426bda8 --- /dev/null +++ b/src/vpp-api/java/jvpp-snat/jvpp_snat.h @@ -0,0 +1,45 @@ +/* + * 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. + */ +#ifndef __included_jvpp_snat_h__ +#define __included_jvpp_snat_h__ + +#include +#include +#include +#include +#include +#include + +/* Global state for JVPP-SNAT */ +typedef struct { + /* Base message index for the nsh plugin */ + u16 msg_id_base; + + /* Pointer to shared memory queue */ + unix_shared_memory_queue_t * vl_input_queue; + + /* VPP api client index */ + u32 my_client_index; + + /* Callback object and class references enabling asynchronous Java calls */ + jobject callbackObject; + jclass callbackClass; + +} snat_main_t; + +snat_main_t snat_main __attribute__((aligned (64))); + + +#endif /* __included_jvpp_snat_h__ */ diff --git a/src/vpp-api/java/jvpp/gen/jvpp_gen.py b/src/vpp-api/java/jvpp/gen/jvpp_gen.py new file mode 100755 index 00000000..f51b11d0 --- /dev/null +++ b/src/vpp-api/java/jvpp/gen/jvpp_gen.py @@ -0,0 +1,185 @@ +#!/usr/bin/env python +# +# 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 +# l +# 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. +# + +import argparse +import importlib +import sys +import os +import json + +from jvppgen import types_gen +from jvppgen import callback_gen +from jvppgen import notification_gen +from jvppgen import dto_gen +from jvppgen import jvpp_callback_facade_gen +from jvppgen import jvpp_future_facade_gen +from jvppgen import jvpp_impl_gen +from jvppgen import jvpp_c_gen +from jvppgen import util + +blacklist = [ "memclnt.api", "flowperpkt.api" ] + +# Invocation: +# ~/Projects/vpp/vpp-api/jvpp/gen$ mkdir -p java/io/fd/vpp/jvpp && cd java/io/fd/vpp/jvpp +# ~/Projects/vpp/vpp-api/jvpp/gen/java/io/fd/vpp/jvpp$ ../../../../jvpp_gen.py -idefs_api_vpp_papi.py +# +# Compilation: +# ~/Projects/vpp/vpp-api/jvpp/gen/java/io/fd/vpp/jvpp$ javac *.java dto/*.java callback/*.java +# +# where +# defs_api_vpp_papi.py - vpe.api in python format (generated by vppapigen) + +parser = argparse.ArgumentParser(description='VPP Java API generator') +parser.add_argument('-i', action="store", dest="inputfiles", nargs='+') +parser.add_argument('--plugin_name', action="store", dest="plugin_name") +parser.add_argument('--root_dir', action="store", dest="root_dir") +args = parser.parse_args() + +sys.path.append(".") +cwd = os.getcwd() + +print "Generating Java API for %s" % args.inputfiles +print "inputfiles %s" % args.inputfiles +plugin_name = args.plugin_name +print "plugin_name %s" % plugin_name + +cfg = {} + +base_package = 'io.fd.vpp.jvpp' +plugin_package = base_package + '.' + plugin_name +root_dir = os.path.abspath(args.root_dir) +print "root_dir %s" % root_dir +work_dir = root_dir + "/target/" + plugin_package.replace(".","/") + +try: + os.makedirs(work_dir) +except OSError: + if not os.path.isdir(work_dir): + raise + +os.chdir(work_dir) + +for inputfile in args.inputfiles: + if any(substring in inputfile for substring in blacklist): + print "WARNING: Imput file %s blacklisted" % inputfile + continue + _cfg = json.load(open(cwd + "/" + inputfile, 'r')) + if 'types' in cfg: + cfg['types'].extend(_cfg['types']) + else: + cfg['types'] = _cfg['types'] + if 'messages' in cfg: + cfg['messages'].extend(_cfg['messages']) + else: + cfg['messages'] = _cfg['messages'] + + +def is_request_field(field_name): + return field_name not in {'_vl_msg_id', 'client_index', 'context'} + + +def is_response_field(field_name): + return field_name not in {'_vl_msg_id'} + + +def get_args(t, filter): + arg_list = [] + for i in t: + if is_crc(i): + continue + if not filter(i[1]): + continue + arg_list.append(i[1]) + return arg_list + + +def get_types(t, filter): + types_list = [] + lengths_list = [] + crc = None + for i in t: + if is_crc(i): + crc = ('crc', i['crc'][2:]) + continue + if not filter(i[1]): + continue + if len(i) is 3: # array type + types_list.append(i[0] + '[]') + lengths_list.append((i[2], False)) + elif len(i) is 4: # variable length array type + types_list.append(i[0] + '[]') + lengths_list.append((i[3], True)) + else: # primitive type + types_list.append(i[0]) + lengths_list.append((0, False)) + return types_list, lengths_list, crc + + +def is_crc(arg): + """ Check whether the argument inside message definition is just crc """ + return 'crc' in arg + + +def get_definitions(defs): + # Pass 1 + func_list = [] + func_name = {} + for a in defs: + java_name = util.underscore_to_camelcase(a[0]) + + # For replies include all the arguments except message_id + if util.is_reply(java_name): + types, lengths, crc = get_types(a[1:], is_response_field) + func_name[a[0]] = dict( + [('name', a[0]), ('java_name', java_name), + ('args', get_args(a[1:], is_response_field)), ('full_args', get_args(a[1:], lambda x: True)), + ('types', types), ('lengths', lengths), crc]) + # For requests skip message_id, client_id and context + else: + types, lengths, crc = get_types(a[1:], is_request_field) + func_name[a[0]] = dict( + [('name', a[0]), ('java_name', java_name), + ('args', get_args(a[1:], is_request_field)), ('full_args', get_args(a[1:], lambda x: True)), + ('types', types), ('lengths', lengths), crc]) + + # Indexed by name + func_list.append(func_name[a[0]]) + return func_list, func_name + + +types_package = 'types' +dto_package = 'dto' +callback_package = 'callback' +notification_package = 'notification' +future_package = 'future' +# TODO find better package name +callback_facade_package = 'callfacade' + +types_list, types_name = get_definitions(cfg['types']) + +types_gen.generate_types(types_list, plugin_package, types_package, args.inputfiles) + +func_list, func_name = get_definitions(cfg['messages']) + +dto_gen.generate_dtos(func_list, base_package, plugin_package, plugin_name.title(), dto_package, args.inputfiles) +jvpp_impl_gen.generate_jvpp(func_list, base_package, plugin_package, plugin_name, dto_package, args.inputfiles) +callback_gen.generate_callbacks(func_list, base_package, plugin_package, plugin_name.title(), callback_package, dto_package, args.inputfiles) +notification_gen.generate_notification_registry(func_list, base_package, plugin_package, plugin_name.title(), notification_package, callback_package, dto_package, args.inputfiles) +jvpp_c_gen.generate_jvpp(func_list, plugin_name, args.inputfiles, root_dir) +jvpp_future_facade_gen.generate_jvpp(func_list, base_package, plugin_package, plugin_name.title(), dto_package, callback_package, notification_package, future_package, args.inputfiles) +jvpp_callback_facade_gen.generate_jvpp(func_list, base_package, plugin_package, plugin_name.title(), dto_package, callback_package, notification_package, callback_facade_package, args.inputfiles) + +print "Java API for %s generated successfully" % args.inputfiles diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/__init__.py b/src/vpp-api/java/jvpp/gen/jvppgen/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/callback_gen.py b/src/vpp-api/java/jvpp/gen/jvppgen/callback_gen.py new file mode 100644 index 00000000..b3024b9c --- /dev/null +++ b/src/vpp-api/java/jvpp/gen/jvppgen/callback_gen.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +# +# 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. + +import os +import util +from string import Template + +from util import remove_suffix + +callback_suffix = "Callback" + +callback_template = Template(""" +package $plugin_package.$callback_package; + +/** + *

Represents callback for plugin's api file message. + *
It was generated by callback_gen.py based on $inputfile preparsed data: + *

+$docs
+ * 
+ */ +public interface $cls_name extends $base_package.$callback_package.$callback_type { + + $callback_method + +} +""") + +global_callback_template = Template(""" +package $plugin_package.$callback_package; + +/** + *

Global aggregated callback interface. + *
It was generated by callback_gen.py based on $inputfile + *
(python representation of api file generated by vppapigen). + */ +public interface JVpp${plugin_name}GlobalCallback extends $base_package.$callback_package.ControlPingCallback, $callbacks { +} +""") + + +def generate_callbacks(func_list, base_package, plugin_package, plugin_name, callback_package, dto_package, inputfile): + """ Generates callback interfaces """ + print "Generating Callback interfaces" + + if not os.path.exists(callback_package): + os.mkdir(callback_package) + + callbacks = [] + for func in func_list: + + camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name']) + + if util.is_ignored(func['name']) or util.is_control_ping(camel_case_name_with_suffix): + continue + if not util.is_reply(camel_case_name_with_suffix) and not util.is_notification(func['name']): + continue + + if util.is_reply(camel_case_name_with_suffix): + camel_case_name = util.remove_reply_suffix(camel_case_name_with_suffix) + callback_type = "JVppCallback" + else: + camel_case_name_with_suffix = util.add_notification_suffix(camel_case_name_with_suffix) + camel_case_name = camel_case_name_with_suffix + callback_type = "JVppNotificationCallback" + + callbacks.append("{0}.{1}.{2}".format(plugin_package, callback_package, camel_case_name + callback_suffix)) + callback_path = os.path.join(callback_package, camel_case_name + callback_suffix + ".java") + callback_file = open(callback_path, 'w') + + reply_type = "%s.%s.%s" % (plugin_package, dto_package, camel_case_name_with_suffix) + method = "void on{0}({1} reply);".format(camel_case_name_with_suffix, reply_type) + callback_file.write( + callback_template.substitute(inputfile=inputfile, + docs=util.api_message_to_javadoc(func), + cls_name=camel_case_name + callback_suffix, + callback_method=method, + base_package=base_package, + plugin_package=plugin_package, + callback_package=callback_package, + callback_type=callback_type)) + callback_file.flush() + callback_file.close() + + callback_file = open(os.path.join(callback_package, "JVpp%sGlobalCallback.java" % plugin_name), 'w') + callback_file.write(global_callback_template.substitute(inputfile=inputfile, + callbacks=", ".join(callbacks), + base_package=base_package, + plugin_package=plugin_package, + plugin_name=plugin_name, + callback_package=callback_package)) + callback_file.flush() + callback_file.close() diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py b/src/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py new file mode 100644 index 00000000..cfddb9ef --- /dev/null +++ b/src/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py @@ -0,0 +1,308 @@ +#!/usr/bin/env python +# +# 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. + +import os +from string import Template + +import util + +dto_template = Template(""" +package $plugin_package.$dto_package; + +/** + *

This class represents $description. + *
It was generated by dto_gen.py based on $inputfile preparsed data: + *

+$docs
+ * 
+ */ +public final class $cls_name implements $base_package.$dto_package.$base_type { + +$fields +$methods +} +""") + +field_template = Template(""" public $type $name;\n""") + +send_template = Template(""" @Override + public int send(final $base_package.JVpp jvpp) throws io.fd.vpp.jvpp.VppInvocationException { + return (($plugin_package.JVpp${plugin_name})jvpp).$method_name($args); + }""") + + +def generate_dtos(func_list, base_package, plugin_package, plugin_name, dto_package, inputfile): + """ Generates dto objects in a dedicated package """ + print "Generating DTOs" + + if not os.path.exists(dto_package): + os.mkdir(dto_package) + + for func in func_list: + camel_case_dto_name = util.underscore_to_camelcase_upper(func['name']) + camel_case_method_name = util.underscore_to_camelcase(func['name']) + dto_path = os.path.join(dto_package, camel_case_dto_name + ".java") + + if util.is_ignored(func['name']) or util.is_control_ping(camel_case_dto_name): + continue + + fields = generate_dto_fields(camel_case_dto_name, func) + methods = generate_dto_base_methods(camel_case_dto_name, func) + base_type = "" + + # Generate request/reply or dump/dumpReply even if structure can be used as notification + if not util.is_just_notification(func["name"]): + if util.is_reply(camel_case_dto_name): + description = "reply DTO" + request_dto_name = get_request_name(camel_case_dto_name, func['name']) + if util.is_details(camel_case_dto_name): + # FIXME assumption that dump calls end with "Dump" suffix. Not enforced in vpe.api + base_type += "JVppReply<%s.%s.%s>" % (plugin_package, dto_package, request_dto_name + "Dump") + generate_dump_reply_dto(request_dto_name, base_package, plugin_package, dto_package, + camel_case_dto_name, camel_case_method_name, func) + else: + base_type += "JVppReply<%s.%s.%s>" % (plugin_package, dto_package, request_dto_name) + else: + args = "" if fields is "" else "this" + methods += send_template.substitute(method_name=camel_case_method_name, + base_package=base_package, + plugin_package=plugin_package, + plugin_name=plugin_name, + args=args) + if util.is_dump(camel_case_dto_name): + base_type += "JVppDump" + description = "dump request DTO" + else: + base_type += "JVppRequest" + description = "request DTO" + + write_dto_file(base_package, plugin_package, base_type, camel_case_dto_name, description, dto_package, + dto_path, fields, func, inputfile, methods) + + # for structures that are also used as notifications, generate dedicated notification DTO + if util.is_notification(func["name"]): + base_type = "JVppNotification" + description = "notification DTO" + camel_case_dto_name = util.add_notification_suffix(camel_case_dto_name) + dto_path = os.path.join(dto_package, camel_case_dto_name + ".java") + methods = generate_dto_base_methods(camel_case_dto_name, func) + write_dto_file(base_package, plugin_package, base_type, camel_case_dto_name, description, dto_package, + dto_path, fields, func, inputfile, methods) + + flush_dump_reply_dtos(inputfile) + + +def generate_dto_base_methods(camel_case_dto_name, func): + methods = generate_dto_hash(func) + methods += generate_dto_equals(camel_case_dto_name, func) + methods += generate_dto_tostring(camel_case_dto_name, func) + return methods + + +def generate_dto_fields(camel_case_dto_name, func): + fields = "" + for t in zip(func['types'], func['args']): + # for retval don't generate dto field in Reply + field_name = util.underscore_to_camelcase(t[1]) + if util.is_reply(camel_case_dto_name) and util.is_retval_field(field_name): + continue + fields += field_template.substitute(type=util.jni_2_java_type_mapping[t[0]], + name=field_name) + return fields + + +tostring_field_template = Template(""" \"$field_name=\" + $field_name + ", " +\n""") +tostring_array_field_template = Template(""" \"$field_name=\" + java.util.Arrays.toString($field_name) + ", " +\n""") +tostring_template = Template(""" @Override + public String toString() { + return "$cls_name{" + +$fields_tostring "}"; + }\n\n""") + + +def generate_dto_tostring(camel_case_dto_name, func): + tostring_fields = "" + for t in zip(func['types'], func['args']): + + field_name = util.underscore_to_camelcase(t[1]) + # for retval don't generate dto field in Reply + if util.is_retval_field(field_name): + continue + + # handle array types + if util.is_array(util.jni_2_java_type_mapping[t[0]]): + tostring_fields += tostring_array_field_template.substitute(field_name=field_name) + else: + tostring_fields += tostring_field_template.substitute(field_name=field_name) + + return tostring_template.substitute(cls_name=camel_case_dto_name, + fields_tostring=tostring_fields[:-8]) + +equals_other_template = Template(""" + final $cls_name other = ($cls_name) o; +\n""") +equals_field_template = Template(""" if (!java.util.Objects.equals(this.$field_name, other.$field_name)) { + return false; + }\n""") +equals_array_field_template = Template(""" if (!java.util.Arrays.equals(this.$field_name, other.$field_name)) { + return false; + }\n""") +equals_template = Template(""" @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } +$comparisons + return true; + }\n\n""") + + +def generate_dto_equals(camel_case_dto_name, func): + equals_fields = "" + for t in zip(func['types'], func['args']): + field_name = util.underscore_to_camelcase(t[1]) + # for retval don't generate dto field in Reply + if util.is_retval_field(field_name): + continue + + # handle array types + if util.is_array(util.jni_2_java_type_mapping[t[0]]): + equals_fields += equals_array_field_template.substitute(field_name=field_name) + else: + equals_fields += equals_field_template.substitute(field_name=field_name) + + if equals_fields != "": + equals_fields = equals_other_template.substitute(cls_name=camel_case_dto_name) + equals_fields + + return equals_template.substitute(comparisons=equals_fields) + + +hash_template = Template(""" @Override + public int hashCode() { + return java.util.Objects.hash($fields); + }\n\n""") +hash_single_array_type_template = Template(""" @Override + public int hashCode() { + return java.util.Arrays.hashCode($fields); + }\n\n""") + + +def generate_dto_hash(func): + hash_fields = "" + + # Special handling for hashCode in case just a single array field is present. Cannot use Objects.equals since the + # array is mistaken for a varargs parameter. Instead use Arrays.hashCode in such case. + if len(func['args']) == 1: + single_type = func['types'][0] + single_type_name = func['args'][0] + if util.is_array(util.jni_2_java_type_mapping[single_type]): + return hash_single_array_type_template.substitute(fields=util.underscore_to_camelcase(single_type_name)) + + for t in zip(func['types'], func['args']): + field_name = util.underscore_to_camelcase(t[1]) + # for retval don't generate dto field in Reply + if util.is_retval_field(field_name): + continue + + hash_fields += field_name + ", " + + return hash_template.substitute(fields=hash_fields[:-2]) + + +def write_dto_file(base_package, plugin_package, base_type, camel_case_dto_name, description, dto_package, dto_path, + fields, func, inputfile, methods): + dto_file = open(dto_path, 'w') + dto_file.write(dto_template.substitute(inputfile=inputfile, + description=description, + docs=util.api_message_to_javadoc(func), + cls_name=camel_case_dto_name, + fields=fields, + methods=methods, + base_package=base_package, + plugin_package=plugin_package, + base_type=base_type, + dto_package=dto_package)) + dto_file.flush() + dto_file.close() + + +dump_dto_suffix = "ReplyDump" +dump_reply_artificial_dtos = {} + + +# Returns request name or special one from unconventional_naming_rep_req map +def get_request_name(camel_case_dto_name, func_name): + return util.underscore_to_camelcase_upper( + util.unconventional_naming_rep_req[func_name]) if func_name in util.unconventional_naming_rep_req \ + else util.remove_reply_suffix(camel_case_dto_name) + + +def flush_dump_reply_dtos(inputfile): + for dump_reply_artificial_dto in dump_reply_artificial_dtos.values(): + dto_path = os.path.join(dump_reply_artificial_dto['dto_package'], + dump_reply_artificial_dto['cls_name'] + ".java") + dto_file = open(dto_path, 'w') + dto_file.write(dto_template.substitute(inputfile=inputfile, + description="dump reply wrapper", + docs=dump_reply_artificial_dto['docs'], + cls_name=dump_reply_artificial_dto['cls_name'], + fields=dump_reply_artificial_dto['fields'], + methods=dump_reply_artificial_dto['methods'], + plugin_package=dump_reply_artificial_dto['plugin_package'], + base_package=dump_reply_artificial_dto['base_package'], + base_type=dump_reply_artificial_dto['base_type'], + dto_package=dump_reply_artificial_dto['dto_package'])) + dto_file.flush() + dto_file.close() + + +def generate_dump_reply_dto(request_dto_name, base_package, plugin_package, dto_package, camel_case_dto_name, + camel_case_method_name, func): + base_type = "JVppReplyDump<%s.%s.%s, %s.%s.%s>" % ( + plugin_package, dto_package, util.remove_reply_suffix(camel_case_dto_name) + "Dump", + plugin_package, dto_package, camel_case_dto_name) + fields = " public java.util.List<%s> %s = new java.util.ArrayList<>();" % (camel_case_dto_name, camel_case_method_name) + cls_name = camel_case_dto_name + dump_dto_suffix + # using artificial type for fields, just to bypass the is_array check in base methods generators + # the type is not really used + artificial_type = 'u8' + + # In case of already existing artificial reply dump DTO, just update it + # Used for sub-dump dtos + if request_dto_name in dump_reply_artificial_dtos.keys(): + dump_reply_artificial_dtos[request_dto_name]['fields'] += '\n' + fields + dump_reply_artificial_dtos[request_dto_name]['field_names'].append(func['name']) + dump_reply_artificial_dtos[request_dto_name]['field_types'].append(artificial_type) + methods = '\n' + generate_dto_base_methods(dump_reply_artificial_dtos[request_dto_name]['cls_name'], + {'args': dump_reply_artificial_dtos[request_dto_name]['field_names'], + 'types': dump_reply_artificial_dtos[request_dto_name]['field_types']}) + dump_reply_artificial_dtos[request_dto_name]['methods'] = methods + else: + methods = '\n' + generate_dto_base_methods(cls_name, {'args': [func['name']], + 'types': [artificial_type]}) + dump_reply_artificial_dtos[request_dto_name] = ({'docs': util.api_message_to_javadoc(func), + 'cls_name': cls_name, + 'fields': fields, + 'field_names': [func['name']], + 'field_types': [artificial_type], + # strip too many newlines at the end of base method block + 'methods': methods, + 'plugin_package': plugin_package, + 'base_package': base_package, + 'base_type': base_type, + 'dto_package': dto_package}) diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/jni_gen.py b/src/vpp-api/java/jvpp/gen/jvppgen/jni_gen.py new file mode 100644 index 00000000..328cc8d3 --- /dev/null +++ b/src/vpp-api/java/jvpp/gen/jvppgen/jni_gen.py @@ -0,0 +1,295 @@ +#!/usr/bin/env python +# +# 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. + +from string import Template + +import util + +variable_length_array_value_template = Template("""mp->${length_var_name}""") +variable_length_array_template = Template("""clib_net_to_host_${length_field_type}(${value})""") + +dto_field_id_template = Template(""" + jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${field_name}", "${jni_signature}");""") + +default_dto_field_setter_template = Template(""" + (*env)->Set${jni_setter}(env, ${object_name}, ${field_reference_name}FieldId, mp->${c_name}); +""") + +variable_length_array_value_template = Template("""mp->${length_var_name}""") +variable_length_array_template = Template("""clib_net_to_host_${length_field_type}(${value})""") + +u16_dto_field_setter_template = Template(""" + (*env)->Set${jni_setter}(env, ${object_name}, ${field_reference_name}FieldId, clib_net_to_host_u16(mp->${c_name})); +""") + +u32_dto_field_setter_template = Template(""" + (*env)->Set${jni_setter}(env, ${object_name}, ${field_reference_name}FieldId, clib_net_to_host_u32(mp->${c_name})); +""") + +u64_dto_field_setter_template = Template(""" + (*env)->Set${jni_setter}(env, ${object_name}, ${field_reference_name}FieldId, clib_net_to_host_u64(mp->${c_name})); +""") + +u8_array_dto_field_setter_template = Template(""" + jbyteArray ${field_reference_name} = (*env)->NewByteArray(env, ${field_length}); + (*env)->SetByteArrayRegion(env, ${field_reference_name}, 0, ${field_length}, (const jbyte*)mp->${c_name}); + (*env)->SetObjectField(env, ${object_name}, ${field_reference_name}FieldId, ${field_reference_name}); + (*env)->DeleteLocalRef(env, ${field_reference_name}); +""") + +u16_array_dto_field_setter_template = Template(""" + { + jshortArray ${field_reference_name} = (*env)->NewShortArray(env, ${field_length}); + jshort * ${field_reference_name}ArrayElements = (*env)->GetShortArrayElements(env, ${field_reference_name}, NULL); + unsigned int _i; + for (_i = 0; _i < ${field_length}; _i++) { + ${field_reference_name}ArrayElements[_i] = clib_net_to_host_u16(mp->${c_name}[_i]); + } + + (*env)->ReleaseShortArrayElements(env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0); + (*env)->SetObjectField(env, ${object_name}, ${field_reference_name}FieldId, ${field_reference_name}); + (*env)->DeleteLocalRef(env, ${field_reference_name}); + } +""") + +u32_array_dto_field_setter_template = Template(""" + { + jintArray ${field_reference_name} = (*env)->NewIntArray(env, ${field_length}); + jint * ${field_reference_name}ArrayElements = (*env)->GetIntArrayElements(env, ${field_reference_name}, NULL); + unsigned int _i; + for (_i = 0; _i < ${field_length}; _i++) { + ${field_reference_name}ArrayElements[_i] = clib_net_to_host_u32(mp->${c_name}[_i]); + } + + (*env)->ReleaseIntArrayElements(env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0); + (*env)->SetObjectField(env, ${object_name}, ${field_reference_name}FieldId, ${field_reference_name}); + (*env)->DeleteLocalRef(env, ${field_reference_name}); + } +""") + +# For each u64 array we get its elements. Then we convert values to host byte order. +# All changes to jlong* buffer are written to jlongArray (isCopy is set to NULL) +u64_array_dto_field_setter_template = Template(""" + { + jlongArray ${field_reference_name} = (*env)->NewLongArray(env, ${field_length}); + jlong * ${field_reference_name}ArrayElements = (*env)->GetLongArrayElements(env, ${field_reference_name}, NULL); + unsigned int _i; + for (_i = 0; _i < ${field_length}; _i++) { + ${field_reference_name}ArrayElements[_i] = clib_net_to_host_u64(mp->${c_name}[_i]); + } + + (*env)->ReleaseLongArrayElements(env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0); + (*env)->SetObjectField(env, ${object_name}, ${field_reference_name}FieldId, ${field_reference_name}); + (*env)->DeleteLocalRef(env, ${field_reference_name}); + } +""") + +dto_field_setter_templates = {'u8': default_dto_field_setter_template, + 'u16': u16_dto_field_setter_template, + 'u32': u32_dto_field_setter_template, + 'i32': u32_dto_field_setter_template, + 'u64': u64_dto_field_setter_template, + 'f64': default_dto_field_setter_template, # fixme + 'u8[]': u8_array_dto_field_setter_template, + 'u16[]': u16_array_dto_field_setter_template, + 'u32[]': u32_array_dto_field_setter_template, + 'u64[]': u64_array_dto_field_setter_template + } + + +def jni_reply_handler_for_type(handler_name, ref_name, field_type, c_name, field_reference_name, + field_name, field_length, is_variable_len_array, length_field_type, + object_name="dto"): + """ + Generates jni code that initializes a field of java object (dto or custom type). + To be used in reply message handlers. + :param field_type: type of the field to be initialized (as defined in vpe.api) + :param c_name: name of the message struct member that stores initialization value + :param field_reference_name: name of the field reference in generated code + :param field_name: name of the field (camelcase) + :param field_length: integer or name of variable that stores field length + :param object_name: name of the object to be initialized + """ + + # todo move validation to vppapigen + if field_type.endswith('[]') and field_length == '0': + raise Exception('Variable array \'%s\' defined in \'%s\' ' + 'should have defined length (e.g. \'%s[%s_length]\'' + % (c_name, handler_name, c_name, c_name)) + + if is_variable_len_array: + length_var_name = field_length + field_length = variable_length_array_value_template.substitute(length_var_name=length_var_name) + if length_field_type != 'u8': # we need net to host conversion: + field_length = variable_length_array_template.substitute( + length_field_type=length_field_type, value=field_length) + + # for retval don't generate setters + if util.is_retval_field(c_name): + return "" + + jni_signature = util.jni_2_signature_mapping[field_type] + jni_setter = util.jni_field_accessors[field_type] + + result = dto_field_id_template.substitute( + field_reference_name=field_reference_name, + field_name=field_name, + class_ref_name=ref_name, + jni_signature=jni_signature) + + dto_setter_template = dto_field_setter_templates[field_type] + + result += dto_setter_template.substitute( + jni_signature=jni_signature, + object_name=object_name, + field_reference_name=field_reference_name, + c_name=c_name, + jni_setter=jni_setter, + field_length=field_length) + return result + + +request_field_identifier_template = Template(""" + jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${object_name}Class, "${field_name}", "${jni_signature}"); + ${jni_type} ${field_reference_name} = (*env)->Get${jni_getter}(env, ${object_name}, ${field_reference_name}FieldId); + """) + +array_length_enforcement_template = Template(""" + size_t max_size = ${field_length}; + if (cnt > max_size) cnt = max_size;""") + +u8_struct_setter_template = Template(""" + mp->${c_name} = ${field_reference_name};""") + +u16_struct_setter_template = Template(""" + mp->${c_name} = clib_host_to_net_u16(${field_reference_name});""") + +u32_struct_setter_template = Template(""" + mp->${c_name} = clib_host_to_net_u32(${field_reference_name});""") + +i32_struct_setter_template = Template(""" + mp->${c_name} = clib_host_to_net_i32(${field_reference_name});!""") + +u64_struct_setter_template = Template(""" + mp->${c_name} = clib_host_to_net_u64(${field_reference_name});""") + +array_length_enforcement_template = Template(""" + size_t max_size = ${field_length}; + if (cnt > max_size) cnt = max_size;""") + +u8_array_struct_setter_template = Template(""" + if (${field_reference_name}) { + jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name}); + ${field_length_check} + (*env)->GetByteArrayRegion(env, ${field_reference_name}, 0, cnt, (jbyte *)mp->${c_name}); + } +""") + +u16_array_struct_setter_template = Template(""" + if (${field_reference_name}) { + jshort * ${field_reference_name}ArrayElements = (*env)->GetShortArrayElements(env, ${field_reference_name}, NULL); + size_t _i; + jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name}); + ${field_length_check} + for (_i = 0; _i < cnt; _i++) { + mp->${c_name}[_i] = clib_host_to_net_u16(${field_reference_name}ArrayElements[_i]); + } + (*env)->ReleaseShortArrayElements (env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0); + } + """) + +u32_array_struct_setter_template = Template(""" + if (${field_reference_name}) { + jint * ${field_reference_name}ArrayElements = (*env)->GetIntArrayElements(env, ${field_reference_name}, NULL); + size_t _i; + jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name}); + ${field_length_check} + for (_i = 0; _i < cnt; _i++) { + mp->${c_name}[_i] = clib_host_to_net_u32(${field_reference_name}ArrayElements[_i]); + } + (*env)->ReleaseIntArrayElements (env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0); + } + """) + +u64_array_struct_setter_template = Template(""" + if (${field_reference_name}) { + jlong * ${field_reference_name}ArrayElements = (*env)->GetLongArrayElements(env, ${field_reference_name}, NULL); + size_t _i; + jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name}); + ${field_length_check} + for (_i = 0; _i < cnt; _i++) { + mp->${c_name}[_i] = clib_host_to_net_u64(${field_reference_name}ArrayElements[_i]); + } + (*env)->ReleaseLongArrayElements (env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0); + } + """) + +struct_setter_templates = {'u8': u8_struct_setter_template, + 'u16': u16_struct_setter_template, + 'u32': u32_struct_setter_template, + 'i32': u32_struct_setter_template, + 'u64': u64_struct_setter_template, + 'u8[]': u8_array_struct_setter_template, + 'u16[]': u16_array_struct_setter_template, + 'u32[]': u32_array_struct_setter_template, + 'u64[]': u64_array_struct_setter_template + } + + +def jni_request_binding_for_type(field_type, c_name, field_reference_name, field_name, field_length, + is_variable_len_array, object_name="request"): + """ + Generates jni code that initializes C structure that corresponds to a field of java object + (dto or custom type). To be used in request message handlers. + :param field_type: type of the field to be initialized (as defined in vpe.api) + :param c_name: name of the message struct member to be initialized + :param field_reference_name: name of the field reference in generated code + :param field_name: name of the field (camelcase) + :param field_length: integer or name of variable that stores field length + :param object_name: name of the object to be initialized + """ + # field identifiers + jni_type = util.vpp_2_jni_type_mapping[field_type] + jni_signature = util.jni_2_signature_mapping[field_type] + jni_getter = util.jni_field_accessors[field_type] + + # field identifier + msg_initialization = request_field_identifier_template.substitute( + jni_type=jni_type, + field_reference_name=field_reference_name, + field_name=field_name, + jni_signature=jni_signature, + jni_getter=jni_getter, + object_name=object_name) + + # field setter + field_length_check = "" + + # check if we are processing variable length array: + if is_variable_len_array: + field_length = util.underscore_to_camelcase(field_length) + + # enforce max length if array has fixed length or uses variable length syntax + if str(field_length) != "0": + field_length_check = array_length_enforcement_template.substitute(field_length=field_length) + + struct_setter_template = struct_setter_templates[field_type] + + msg_initialization += struct_setter_template.substitute( + c_name=c_name, + field_reference_name=field_reference_name, + field_length_check=field_length_check) + + return msg_initialization diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py b/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py new file mode 100644 index 00000000..611171c4 --- /dev/null +++ b/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py @@ -0,0 +1,343 @@ +#!/usr/bin/env python +# +# 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 +# l +# 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. +# + +import os, util +from string import Template + +import jni_gen + + +def is_manually_generated(f_name, plugin_name): + return f_name in {'control_ping_reply'} + + +class_reference_template = Template("""jclass ${ref_name}Class; +""") + +find_class_invocation_template = Template(""" + ${ref_name}Class = (jclass)(*env)->NewGlobalRef(env, (*env)->FindClass(env, "io/fd/vpp/jvpp/${plugin_name}/dto/${class_name}")); + if ((*env)->ExceptionCheck(env)) { + (*env)->ExceptionDescribe(env); + return JNI_ERR; + }""") + +find_class_template = Template(""" + ${ref_name}Class = (jclass)(*env)->NewGlobalRef(env, (*env)->FindClass(env, "${class_name}")); + if ((*env)->ExceptionCheck(env)) { + (*env)->ExceptionDescribe(env); + return JNI_ERR; + }""") + +delete_class_invocation_template = Template(""" + if (${ref_name}Class) { + (*env)->DeleteGlobalRef(env, ${ref_name}Class); + }""") + +class_cache_template = Template(""" +$class_references +static int cache_class_references(JNIEnv* env) { + $find_class_invocations + return 0; +} + +static void delete_class_references(JNIEnv* env) { + $delete_class_invocations +}""") + + +def generate_class_cache(func_list, plugin_name): + class_references = [] + find_class_invocations = [] + delete_class_invocations = [] + for f in func_list: + c_name = f['name'] + class_name = util.underscore_to_camelcase_upper(c_name) + ref_name = util.underscore_to_camelcase(c_name) + + if util.is_ignored(c_name) or util.is_control_ping(class_name): + continue + + if util.is_reply(class_name): + class_references.append(class_reference_template.substitute( + ref_name=ref_name)) + find_class_invocations.append(find_class_invocation_template.substitute( + plugin_name=plugin_name, + ref_name=ref_name, + class_name=class_name)) + delete_class_invocations.append(delete_class_invocation_template.substitute(ref_name=ref_name)) + elif util.is_notification(c_name): + class_references.append(class_reference_template.substitute( + ref_name=util.add_notification_suffix(ref_name))) + find_class_invocations.append(find_class_invocation_template.substitute( + plugin_name=plugin_name, + ref_name=util.add_notification_suffix(ref_name), + class_name=util.add_notification_suffix(class_name))) + delete_class_invocations.append(delete_class_invocation_template.substitute( + ref_name=util.add_notification_suffix(ref_name))) + + # add exception class to class cache + ref_name = 'callbackException' + class_name = 'io/fd/vpp/jvpp/VppCallbackException' + class_references.append(class_reference_template.substitute( + ref_name=ref_name)) + find_class_invocations.append(find_class_template.substitute( + ref_name=ref_name, + class_name=class_name)) + delete_class_invocations.append(delete_class_invocation_template.substitute(ref_name=ref_name)) + + return class_cache_template.substitute( + class_references="".join(class_references), find_class_invocations="".join(find_class_invocations), + delete_class_invocations="".join(delete_class_invocations)) + + +# TODO: cache method and field identifiers to achieve better performance +# https://jira.fd.io/browse/HONEYCOMB-42 +request_class_template = Template(""" + jclass requestClass = (*env)->FindClass(env, "io/fd/vpp/jvpp/${plugin_name}/dto/${java_name_upper}");""") + +request_field_identifier_template = Template(""" + jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${object_name}Class, "${field_name}", "${jni_signature}"); + ${jni_type} ${field_reference_name} = (*env)->Get${jni_getter}(env, ${object_name}, ${field_reference_name}FieldId); + """) + + +jni_impl_template = Template(""" +/** + * JNI binding for sending ${c_name} message. + * Generated based on $inputfile preparsed data: +$api_data + */ +JNIEXPORT jint JNICALL Java_io_fd_vpp_jvpp_${plugin_name}_JVpp${java_plugin_name}Impl_${field_name}0 +(JNIEnv * env, jclass clazz$args) { + ${plugin_name}_main_t *plugin_main = &${plugin_name}_main; + vl_api_${c_name}_t * mp; + u32 my_context_id = vppjni_get_context_id (&jvpp_main); + $request_class + + // create message: + mp = vl_msg_api_alloc(sizeof(*mp)); + memset (mp, 0, sizeof (*mp)); + mp->_vl_msg_id = ntohs (VL_API_${c_name_uppercase} + plugin_main->msg_id_base); + mp->client_index = plugin_main->my_client_index; + mp->context = clib_host_to_net_u32 (my_context_id); + + $msg_initialization + + // send message: + vl_msg_api_send_shmem (plugin_main->vl_input_queue, (u8 *)&mp); + if ((*env)->ExceptionCheck(env)) { + return JNI_ERR; + } + return my_context_id; +}""") + +def generate_jni_impl(func_list, plugin_name, inputfile): + jni_impl = [] + for f in func_list: + f_name = f['name'] + camel_case_function_name = util.underscore_to_camelcase(f_name) + if is_manually_generated(f_name, plugin_name) or util.is_reply(camel_case_function_name) \ + or util.is_ignored(f_name) or util.is_just_notification(f_name): + continue + + arguments = '' + request_class = '' + msg_initialization = '' + f_name_uppercase = f_name.upper() + + if f['args']: + arguments = ', jobject request' + camel_case_function_name_upper = util.underscore_to_camelcase_upper(f_name) + + request_class = request_class_template.substitute( + java_name_upper=camel_case_function_name_upper, + plugin_name=plugin_name) + + for t in zip(f['types'], f['args'], f['lengths']): + field_name = util.underscore_to_camelcase(t[1]) + msg_initialization += jni_gen.jni_request_binding_for_type(field_type=t[0], c_name=t[1], + field_reference_name=field_name, + field_name=field_name, + field_length=t[2][0], + is_variable_len_array=t[2][1]) + + jni_impl.append(jni_impl_template.substitute( + inputfile=inputfile, + api_data=util.api_message_to_javadoc(f), + field_reference_name=camel_case_function_name, + field_name=camel_case_function_name, + c_name_uppercase=f_name_uppercase, + c_name=f_name, + plugin_name=plugin_name, + java_plugin_name=plugin_name.title(), + request_class=request_class, + msg_initialization=msg_initialization, + args=arguments)) + + return "\n".join(jni_impl) + +# code fragment for checking result of the operation before sending request reply +callback_err_handler_template = Template(""" + // for negative result don't send callback message but send error callback + if (mp->retval<0) { + call_on_error("${handler_name}", mp->context, mp->retval, plugin_main->callbackClass, plugin_main->callbackObject, callbackExceptionClass); + return; + } + if (mp->retval == VNET_API_ERROR_IN_PROGRESS) { + clib_warning("Result in progress"); + return; + } +""") + +msg_handler_template = Template(""" +/** + * Handler for ${handler_name} message. + * Generated based on $inputfile preparsed data: +$api_data + */ +static void vl_api_${handler_name}_t_handler (vl_api_${handler_name}_t * mp) +{ + ${plugin_name}_main_t *plugin_main = &${plugin_name}_main; + JNIEnv *env = jvpp_main.jenv; + + $err_handler + + jmethodID constructor = (*env)->GetMethodID(env, ${class_ref_name}Class, "", "()V"); + jmethodID callbackMethod = (*env)->GetMethodID(env, plugin_main->callbackClass, "on${dto_name}", "(Lio/fd/vpp/jvpp/${plugin_name}/dto/${dto_name};)V"); + + jobject dto = (*env)->NewObject(env, ${class_ref_name}Class, constructor); + $dto_setters + + (*env)->CallVoidMethod(env, plugin_main->callbackObject, callbackMethod, dto); + // free DTO as per http://stackoverflow.com/questions/1340938/memory-leak-when-calling-java-code-from-c-using-jni + (*env)->DeleteLocalRef(env, dto); +}""") + + +def generate_msg_handlers(func_list, plugin_name, inputfile): + handlers = [] + for f in func_list: + handler_name = f['name'] + dto_name = util.underscore_to_camelcase_upper(handler_name) + ref_name = util.underscore_to_camelcase(handler_name) + + if is_manually_generated(handler_name, plugin_name) or util.is_ignored(handler_name): + continue + + if not util.is_reply(dto_name) and not util.is_notification(handler_name): + continue + + if util.is_notification(handler_name): + dto_name = util.add_notification_suffix(dto_name) + ref_name = util.add_notification_suffix(ref_name) + + dto_setters = '' + err_handler = '' + # dto setters + for t in zip(f['types'], f['args'], f['lengths']): + c_name = t[1] + java_name = util.underscore_to_camelcase(c_name) + field_length = t[2][0] + is_variable_len_array = t[2][1] + length_field_type = None + if is_variable_len_array: + length_field_type = f['types'][f['args'].index(field_length)] + dto_setters += jni_gen.jni_reply_handler_for_type(handler_name=handler_name, ref_name=ref_name, + field_type=t[0], c_name=t[1], + field_reference_name=java_name, + field_name=java_name, field_length=field_length, + is_variable_len_array=is_variable_len_array, + length_field_type=length_field_type) + + # for retval don't generate setters and generate retval check + if util.is_retval_field(c_name): + err_handler = callback_err_handler_template.substitute( + handler_name=handler_name + ) + continue + + handlers.append(msg_handler_template.substitute( + inputfile=inputfile, + api_data=util.api_message_to_javadoc(f), + handler_name=handler_name, + plugin_name=plugin_name, + dto_name=dto_name, + class_ref_name=ref_name, + dto_setters=dto_setters, + err_handler=err_handler)) + + return "\n".join(handlers) + + +handler_registration_template = Template("""_(${upercase_name}, ${name}) \\ +""") + + +def generate_handler_registration(func_list): + handler_registration = ["#define foreach_api_reply_handler \\\n"] + for f in func_list: + name = f['name'] + camelcase_name = util.underscore_to_camelcase(f['name']) + + if (not util.is_reply(camelcase_name) and not util.is_notification(name)) or util.is_ignored(name) \ + or util.is_control_ping(camelcase_name): + continue + + handler_registration.append(handler_registration_template.substitute( + name=name, + upercase_name=name.upper())) + + return "".join(handler_registration) + + +jvpp_c_template = Template("""/** + * This file contains JNI bindings for jvpp Java API. + * It was generated by jvpp_c_gen.py based on $inputfile + * (python representation of api file generated by vppapigen). + */ + +// JAVA class reference cache +$class_cache + +// JNI bindings +$jni_implementations + +// Message handlers +$msg_handlers + +// Registration of message handlers in vlib +$handler_registration +""") + +def generate_jvpp(func_list, plugin_name, inputfile, path): + """ Generates jvpp C file """ + print "Generating jvpp C" + + class_cache = generate_class_cache(func_list, plugin_name) + jni_impl = generate_jni_impl(func_list, plugin_name, inputfile) + msg_handlers = generate_msg_handlers(func_list, plugin_name, inputfile) + handler_registration = generate_handler_registration(func_list) + + jvpp_c_file = open("%s/jvpp_%s_gen.h" % (path, plugin_name), 'w') + jvpp_c_file.write(jvpp_c_template.substitute( + inputfile=inputfile, + class_cache=class_cache, + jni_implementations=jni_impl, + msg_handlers=msg_handlers, + handler_registration=handler_registration)) + jvpp_c_file.flush() + jvpp_c_file.close() + diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py b/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py new file mode 100644 index 00000000..ac096a71 --- /dev/null +++ b/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py @@ -0,0 +1,324 @@ +#!/usr/bin/env python +# +# 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. + +import os, util +from string import Template + +import callback_gen +import dto_gen + +jvpp_ifc_template = Template(""" +package $plugin_package.$callback_facade_package; + +/** + *

Callback Java API representation of $plugin_package plugin. + *
It was generated by jvpp_callback_facade_gen.py based on $inputfile + *
(python representation of api file generated by vppapigen). + */ +public interface CallbackJVpp${plugin_name} extends $base_package.$notification_package.NotificationRegistryProvider, java.lang.AutoCloseable { + + // TODO add send + +$methods +} +""") + +jvpp_impl_template = Template(""" +package $plugin_package.$callback_facade_package; + +/** + *

Default implementation of Callback${plugin_name}JVpp interface. + *
It was generated by jvpp_callback_facade_gen.py based on $inputfile + *
(python representation of api file generated by vppapigen). + */ +public final class CallbackJVpp${plugin_name}Facade implements CallbackJVpp${plugin_name} { + + private final $plugin_package.JVpp${plugin_name} jvpp; + private final java.util.Map callbacks; + private final $plugin_package.$notification_package.${plugin_name}NotificationRegistryImpl notificationRegistry = new $plugin_package.$notification_package.${plugin_name}NotificationRegistryImpl(); + /** + *

Create CallbackJVpp${plugin_name}Facade object for provided JVpp instance. + * Constructor internally creates CallbackJVppFacadeCallback class for processing callbacks + * and then connects to provided JVpp instance + * + * @param jvpp provided $base_package.JVpp instance + * + * @throws java.io.IOException in case instance cannot connect to JVPP + */ + public CallbackJVpp${plugin_name}Facade(final $base_package.JVppRegistry registry, final $plugin_package.JVpp${plugin_name} jvpp) throws java.io.IOException { + this.jvpp = java.util.Objects.requireNonNull(jvpp,"jvpp is null"); + this.callbacks = new java.util.HashMap<>(); + java.util.Objects.requireNonNull(registry, "JVppRegistry should not be null"); + registry.register(jvpp, new CallbackJVpp${plugin_name}FacadeCallback(this.callbacks, notificationRegistry)); + } + + @Override + public $plugin_package.$notification_package.${plugin_name}NotificationRegistry getNotificationRegistry() { + return notificationRegistry; + } + + @Override + public void close() throws Exception { + jvpp.close(); + } + + // TODO add send() + +$methods +} +""") + +method_template = Template( + """ void $name($plugin_package.$dto_package.$request request, $plugin_package.$callback_package.$callback callback) throws $base_package.VppInvocationException;""") + +method_impl_template = Template(""" public final void $name($plugin_package.$dto_package.$request request, $plugin_package.$callback_package.$callback callback) throws $base_package.VppInvocationException { + synchronized (callbacks) { + callbacks.put(jvpp.$name(request), callback); + } + } +""") + +no_arg_method_template = Template(""" void $name($plugin_package.$callback_package.$callback callback) throws $base_package.VppInvocationException;""") +no_arg_method_impl_template = Template(""" public final void $name($plugin_package.$callback_package.$callback callback) throws $base_package.VppInvocationException { + synchronized (callbacks) { + callbacks.put(jvpp.$name(), callback); + } + } +""") + + +def generate_jvpp(func_list, base_package, plugin_package, plugin_name, dto_package, callback_package, notification_package, callback_facade_package, inputfile): + """ Generates callback facade """ + print "Generating JVpp callback facade" + + if os.path.exists(callback_facade_package): + util.remove_folder(callback_facade_package) + + os.mkdir(callback_facade_package) + + methods = [] + methods_impl = [] + for func in func_list: + + if util.is_notification(func['name']) or util.is_ignored(func['name']): + continue + + camel_case_name = util.underscore_to_camelcase(func['name']) + camel_case_name_upper = util.underscore_to_camelcase_upper(func['name']) + if util.is_reply(camel_case_name) or util.is_control_ping(camel_case_name): + continue + + # Strip suffix for dump calls + callback_type = get_request_name(camel_case_name_upper, func['name']) + callback_gen.callback_suffix + + if len(func['args']) == 0: + methods.append(no_arg_method_template.substitute(name=camel_case_name, + base_package=base_package, + plugin_package=plugin_package, + dto_package=dto_package, + callback_package=callback_package, + callback=callback_type)) + methods_impl.append(no_arg_method_impl_template.substitute(name=camel_case_name, + base_package=base_package, + plugin_package=plugin_package, + dto_package=dto_package, + callback_package=callback_package, + callback=callback_type)) + else: + methods.append(method_template.substitute(name=camel_case_name, + request=camel_case_name_upper, + base_package=base_package, + plugin_package=plugin_package, + dto_package=dto_package, + callback_package=callback_package, + callback=callback_type)) + methods_impl.append(method_impl_template.substitute(name=camel_case_name, + request=camel_case_name_upper, + base_package=base_package, + plugin_package=plugin_package, + dto_package=dto_package, + callback_package=callback_package, + callback=callback_type)) + + join = os.path.join(callback_facade_package, "CallbackJVpp%s.java" % plugin_name) + jvpp_file = open(join, 'w') + jvpp_file.write( + jvpp_ifc_template.substitute(inputfile=inputfile, + methods="\n".join(methods), + base_package=base_package, + plugin_package=plugin_package, + plugin_name=plugin_name, + dto_package=dto_package, + notification_package=notification_package, + callback_facade_package=callback_facade_package)) + jvpp_file.flush() + jvpp_file.close() + + jvpp_file = open(os.path.join(callback_facade_package, "CallbackJVpp%sFacade.java" % plugin_name), 'w') + jvpp_file.write(jvpp_impl_template.substitute(inputfile=inputfile, + methods="\n".join(methods_impl), + base_package=base_package, + plugin_package=plugin_package, + plugin_name=plugin_name, + dto_package=dto_package, + notification_package=notification_package, + callback_package=callback_package, + callback_facade_package=callback_facade_package)) + jvpp_file.flush() + jvpp_file.close() + + generate_callback(func_list, base_package, plugin_package, plugin_name, dto_package, callback_package, notification_package, callback_facade_package, inputfile) + + +jvpp_facade_callback_template = Template(""" +package $plugin_package.$callback_facade_package; + +/** + *

Implementation of JVppGlobalCallback interface for Java Callback API. + *
It was generated by jvpp_callback_facade_gen.py based on $inputfile + *
(python representation of api file generated by vppapigen). + */ +public final class CallbackJVpp${plugin_name}FacadeCallback implements $plugin_package.$callback_package.JVpp${plugin_name}GlobalCallback { + + private final java.util.Map requests; + private final $plugin_package.$notification_package.Global${plugin_name}NotificationCallback notificationCallback; + private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(CallbackJVpp${plugin_name}FacadeCallback.class.getName()); + + public CallbackJVpp${plugin_name}FacadeCallback(final java.util.Map requestMap, + final $plugin_package.$notification_package.Global${plugin_name}NotificationCallback notificationCallback) { + this.requests = requestMap; + this.notificationCallback = notificationCallback; + } + + @Override + public void onError($base_package.VppCallbackException reply) { + + $base_package.$callback_package.JVppCallback failedCall; + synchronized(requests) { + failedCall = requests.remove(reply.getCtxId()); + } + + if(failedCall != null) { + try { + failedCall.onError(reply); + } catch(RuntimeException ex) { + ex.addSuppressed(reply); + LOG.log(java.util.logging.Level.WARNING, String.format("Callback: %s failed while handling exception: %s", failedCall, reply), ex); + } + } + } + + @Override + @SuppressWarnings("unchecked") + public void onControlPingReply($base_package.$dto_package.ControlPingReply reply) { + + $base_package.$callback_package.ControlPingCallback callback; + synchronized(requests) { + callback = ($base_package.$callback_package.ControlPingCallback) requests.remove(reply.context); + } + + if(callback != null) { + callback.onControlPingReply(reply); + } + } + +$methods +} +""") + +jvpp_facade_callback_method_template = Template(""" + @Override + @SuppressWarnings("unchecked") + public void on$callback_dto($plugin_package.$dto_package.$callback_dto reply) { + + $plugin_package.$callback_package.$callback callback; + synchronized(requests) { + callback = ($plugin_package.$callback_package.$callback) requests.remove(reply.context); + } + + if(callback != null) { + callback.on$callback_dto(reply); + } + } +""") + +jvpp_facade_callback_notification_method_template = Template(""" + @Override + @SuppressWarnings("unchecked") + public void on$callback_dto($plugin_package.$dto_package.$callback_dto notification) { + notificationCallback.on$callback_dto(notification); + } +""") + + +def generate_callback(func_list, base_package, plugin_package, plugin_name, dto_package, callback_package, notification_package, callback_facade_package, inputfile): + callbacks = [] + for func in func_list: + + camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name']) + + if util.is_ignored(func['name']) or util.is_control_ping(camel_case_name_with_suffix): + continue + + if util.is_reply(camel_case_name_with_suffix): + callbacks.append(jvpp_facade_callback_method_template.substitute(plugin_package=plugin_package, + dto_package=dto_package, + callback_package=callback_package, + callback=util.remove_reply_suffix(camel_case_name_with_suffix) + callback_gen.callback_suffix, + callback_dto=camel_case_name_with_suffix)) + + if util.is_notification(func["name"]): + with_notification_suffix = util.add_notification_suffix(camel_case_name_with_suffix) + callbacks.append(jvpp_facade_callback_notification_method_template.substitute(plugin_package=plugin_package, + dto_package=dto_package, + callback_package=callback_package, + callback=with_notification_suffix + callback_gen.callback_suffix, + callback_dto=with_notification_suffix)) + + jvpp_file = open(os.path.join(callback_facade_package, "CallbackJVpp%sFacadeCallback.java" % plugin_name), 'w') + jvpp_file.write(jvpp_facade_callback_template.substitute(inputfile=inputfile, + base_package=base_package, + plugin_package=plugin_package, + plugin_name=plugin_name, + dto_package=dto_package, + notification_package=notification_package, + callback_package=callback_package, + methods="".join(callbacks), + callback_facade_package=callback_facade_package)) + jvpp_file.flush() + jvpp_file.close() + + +# Returns request name or special one from unconventional_naming_rep_req map +def get_request_name(camel_case_dto_name, func_name): + if func_name in reverse_dict(util.unconventional_naming_rep_req): + request_name = util.underscore_to_camelcase_upper(reverse_dict(util.unconventional_naming_rep_req)[func_name]) + else: + request_name = camel_case_dto_name + return remove_suffix(request_name) + + +def reverse_dict(map): + return dict((v, k) for k, v in map.iteritems()) + + +def remove_suffix(name): + if util.is_reply(name): + return util.remove_reply_suffix(name) + else: + if util.is_dump(name): + return util.remove_suffix(name, util.dump_suffix) + else: + return name diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py b/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py new file mode 100644 index 00000000..26b31e22 --- /dev/null +++ b/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py @@ -0,0 +1,331 @@ +#!/usr/bin/env python +# +# 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. + +import os +from string import Template + +import dto_gen +import util + +jvpp_facade_callback_template = Template(""" +package $plugin_package.$future_package; + +/** + *

Async facade callback setting values to future objects + *
It was generated by jvpp_future_facade_gen.py based on $inputfile + *
(python representation of api file generated by vppapigen). + */ +public final class FutureJVpp${plugin_name}FacadeCallback implements $plugin_package.$callback_package.JVpp${plugin_name}GlobalCallback { + + private final java.util.Map>> requests; + private final $plugin_package.$notification_package.Global${plugin_name}NotificationCallback notificationCallback; + + public FutureJVpp${plugin_name}FacadeCallback( + final java.util.Map>> requestMap, + final $plugin_package.$notification_package.Global${plugin_name}NotificationCallback notificationCallback) { + this.requests = requestMap; + this.notificationCallback = notificationCallback; + } + + @Override + @SuppressWarnings("unchecked") + public void onError($base_package.VppCallbackException reply) { + final java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply> completableFuture; + + synchronized(requests) { + completableFuture = (java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply>) requests.get(reply.getCtxId()); + } + + if(completableFuture != null) { + completableFuture.completeExceptionally(reply); + + synchronized(requests) { + requests.remove(reply.getCtxId()); + } + } + } + + @Override + @SuppressWarnings("unchecked") + public void onControlPingReply($base_package.$dto_package.ControlPingReply reply) { + final java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply> completableFuture; + + synchronized(requests) { + completableFuture = (java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply>) requests.get(reply.context); + } + + if(completableFuture != null) { + // Finish dump call + if (completableFuture instanceof $base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture) { + completableFuture.complete((($base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture) completableFuture).getReplyDump()); + // Remove future mapped to dump call context id + synchronized(requests) { + requests.remove((($base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture) completableFuture).getContextId()); + } + } else { + completableFuture.complete(reply); + } + + synchronized(requests) { + requests.remove(reply.context); + } + } + } + +$methods +} +""") + +jvpp_facade_callback_method_template = Template(""" + @Override + @SuppressWarnings("unchecked") + public void on$callback_dto($plugin_package.$dto_package.$callback_dto reply) { + final java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply> completableFuture; + + synchronized(requests) { + completableFuture = (java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply>) requests.get(reply.context); + } + + if(completableFuture != null) { + completableFuture.complete(reply); + + synchronized(requests) { + requests.remove(reply.context); + } + } + } +""") + +jvpp_facade_callback_notification_method_template = Template(""" + @Override + public void on$callback_dto($plugin_package.$dto_package.$callback_dto notification) { + notificationCallback.on$callback_dto(notification); + } +""") + +jvpp_facade_details_callback_method_template = Template(""" + @Override + @SuppressWarnings("unchecked") + public void on$callback_dto($plugin_package.$dto_package.$callback_dto reply) { + final $base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture<$plugin_package.$dto_package.$callback_dto_reply_dump> completableFuture; + + synchronized(requests) { + completableFuture = ($base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture<$plugin_package.$dto_package.$callback_dto_reply_dump>) requests.get(reply.context); + } + + if(completableFuture != null) { + completableFuture.getReplyDump().$callback_dto_field.add(reply); + } + } +""") + + +def generate_jvpp(func_list, base_package, plugin_package, plugin_name, dto_package, callback_package, notification_package, future_facade_package, inputfile): + """ Generates JVpp interface and JNI implementation """ + print "Generating JVpp future facade" + + if not os.path.exists(future_facade_package): + os.mkdir(future_facade_package) + + methods = [] + methods_impl = [] + callbacks = [] + for func in func_list: + camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name']) + + if util.is_ignored(func['name']) or util.is_control_ping(camel_case_name_with_suffix): + continue + + if not util.is_reply(camel_case_name_with_suffix) and not util.is_notification(func['name']): + continue + + camel_case_method_name = util.underscore_to_camelcase(func['name']) + + if not util.is_notification(func["name"]): + camel_case_request_method_name = util.remove_reply_suffix(util.underscore_to_camelcase(func['name'])) + if util.is_details(camel_case_name_with_suffix): + camel_case_reply_name = get_standard_dump_reply_name(util.underscore_to_camelcase_upper(func['name']), + func['name']) + callbacks.append(jvpp_facade_details_callback_method_template.substitute(base_package=base_package, + plugin_package=plugin_package, + dto_package=dto_package, + callback_dto=camel_case_name_with_suffix, + callback_dto_field=camel_case_method_name, + callback_dto_reply_dump=camel_case_reply_name + dto_gen.dump_dto_suffix, + future_package=future_facade_package)) + + methods.append(future_jvpp_method_template.substitute(plugin_package=plugin_package, + dto_package=dto_package, + method_name=camel_case_request_method_name + + util.underscore_to_camelcase_upper(util.dump_suffix), + reply_name=camel_case_reply_name + dto_gen.dump_dto_suffix, + request_name=util.remove_reply_suffix(camel_case_reply_name) + + util.underscore_to_camelcase_upper(util.dump_suffix))) + methods_impl.append(future_jvpp_dump_method_impl_template.substitute(plugin_package=plugin_package, + dto_package=dto_package, + method_name=camel_case_request_method_name + + util.underscore_to_camelcase_upper(util.dump_suffix), + reply_name=camel_case_reply_name + dto_gen.dump_dto_suffix, + request_name=util.remove_reply_suffix(camel_case_reply_name) + + util.underscore_to_camelcase_upper(util.dump_suffix))) + else: + request_name = util.underscore_to_camelcase_upper(util.unconventional_naming_rep_req[func['name']]) \ + if func['name'] in util.unconventional_naming_rep_req else util.remove_reply_suffix(camel_case_name_with_suffix) + + methods.append(future_jvpp_method_template.substitute(plugin_package=plugin_package, + dto_package=dto_package, + method_name=camel_case_request_method_name, + reply_name=camel_case_name_with_suffix, + request_name=request_name)) + methods_impl.append(future_jvpp_method_impl_template.substitute(plugin_package=plugin_package, + dto_package=dto_package, + method_name=camel_case_request_method_name, + reply_name=camel_case_name_with_suffix, + request_name=request_name)) + + callbacks.append(jvpp_facade_callback_method_template.substitute(base_package=base_package, + plugin_package=plugin_package, + dto_package=dto_package, + callback_dto=camel_case_name_with_suffix)) + + if util.is_notification(func["name"]): + callbacks.append(jvpp_facade_callback_notification_method_template.substitute(plugin_package=plugin_package, + dto_package=dto_package, + callback_dto=util.add_notification_suffix(camel_case_name_with_suffix))) + + jvpp_file = open(os.path.join(future_facade_package, "FutureJVpp%sFacadeCallback.java" % plugin_name), 'w') + jvpp_file.write(jvpp_facade_callback_template.substitute(inputfile=inputfile, + base_package=base_package, + plugin_package=plugin_package, + plugin_name=plugin_name, + dto_package=dto_package, + notification_package=notification_package, + callback_package=callback_package, + methods="".join(callbacks), + future_package=future_facade_package)) + jvpp_file.flush() + jvpp_file.close() + + jvpp_file = open(os.path.join(future_facade_package, "FutureJVpp%s.java" % plugin_name), 'w') + jvpp_file.write(future_jvpp_template.substitute(inputfile=inputfile, + base_package=base_package, + plugin_package=plugin_package, + plugin_name=plugin_name, + notification_package=notification_package, + methods="".join(methods), + future_package=future_facade_package)) + jvpp_file.flush() + jvpp_file.close() + + jvpp_file = open(os.path.join(future_facade_package, "FutureJVpp%sFacade.java" % plugin_name), 'w') + jvpp_file.write(future_jvpp_facade_template.substitute(inputfile=inputfile, + base_package=base_package, + plugin_package=plugin_package, + plugin_name=plugin_name, + dto_package=dto_package, + notification_package=notification_package, + methods="".join(methods_impl), + future_package=future_facade_package)) + jvpp_file.flush() + jvpp_file.close() + + +future_jvpp_template = Template(''' +package $plugin_package.$future_package; + +/** + *

Async facade extension adding specific methods for each request invocation + *
It was generated by jvpp_future_facade_gen.py based on $inputfile + *
(python representation of api file generated by vppapigen). + */ +public interface FutureJVpp${plugin_name} extends $base_package.$future_package.FutureJVppInvoker { +$methods + + @Override + public $plugin_package.$notification_package.${plugin_name}NotificationRegistry getNotificationRegistry(); + +} +''') + +future_jvpp_method_template = Template(''' + java.util.concurrent.CompletionStage<$plugin_package.$dto_package.$reply_name> $method_name($plugin_package.$dto_package.$request_name request); +''') + + +future_jvpp_facade_template = Template(''' +package $plugin_package.$future_package; + +/** + *

Implementation of FutureJVpp based on AbstractFutureJVppInvoker + *
It was generated by jvpp_future_facade_gen.py based on $inputfile + *
(python representation of api file generated by vppapigen). + */ +public class FutureJVpp${plugin_name}Facade extends $base_package.$future_package.AbstractFutureJVppInvoker implements FutureJVpp${plugin_name} { + + private final $plugin_package.$notification_package.${plugin_name}NotificationRegistryImpl notificationRegistry = new $plugin_package.$notification_package.${plugin_name}NotificationRegistryImpl(); + + /** + *

Create FutureJVpp${plugin_name}Facade object for provided JVpp instance. + * Constructor internally creates FutureJVppFacadeCallback class for processing callbacks + * and then connects to provided JVpp instance + * + * @param jvpp provided $base_package.JVpp instance + * + * @throws java.io.IOException in case instance cannot connect to JVPP + */ + public FutureJVpp${plugin_name}Facade(final $base_package.JVppRegistry registry, final $base_package.JVpp jvpp) throws java.io.IOException { + super(jvpp, registry, new java.util.HashMap<>()); + java.util.Objects.requireNonNull(registry, "JVppRegistry should not be null"); + registry.register(jvpp, new FutureJVpp${plugin_name}FacadeCallback(getRequests(), notificationRegistry)); + } + + @Override + public $plugin_package.$notification_package.${plugin_name}NotificationRegistry getNotificationRegistry() { + return notificationRegistry; + } + +$methods +} +''') + +future_jvpp_method_impl_template = Template(''' + @Override + public java.util.concurrent.CompletionStage<$plugin_package.$dto_package.$reply_name> $method_name($plugin_package.$dto_package.$request_name request) { + return send(request); + } +''') + +future_jvpp_dump_method_impl_template = Template(''' + @Override + public java.util.concurrent.CompletionStage<$plugin_package.$dto_package.$reply_name> $method_name($plugin_package.$dto_package.$request_name request) { + return send(request, new $plugin_package.$dto_package.$reply_name()); + } +''') + + +# Returns request name or special one from unconventional_naming_rep_req map +def get_standard_dump_reply_name(camel_case_dto_name, func_name): + # FIXME this is a hotfix for sub-details callbacks + # FIXME also for L2FibTableEntry + # It's all because unclear mapping between + # request -> reply, + # dump -> reply, details, + # notification_start -> reply, notifications + + # vpe.api needs to be "standardized" so we can parse the information and create maps before generating java code + suffix = func_name.split("_")[-1] + return util.underscore_to_camelcase_upper( + util.unconventional_naming_rep_req[func_name]) + util.underscore_to_camelcase_upper(suffix) if func_name in util.unconventional_naming_rep_req \ + else camel_case_dto_name diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_impl_gen.py b/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_impl_gen.py new file mode 100644 index 00000000..7bf91138 --- /dev/null +++ b/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_impl_gen.py @@ -0,0 +1,219 @@ +#!/usr/bin/env python +# +# 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. + +import os, util +from string import Template + +jvpp_ifc_template = Template(""" +package $plugin_package; + +/** + *

Java representation of plugin's api file. + *
It was generated by jvpp_impl_gen.py based on $inputfile + *
(python representation of api file generated by vppapigen). + */ +public interface JVpp${plugin_name} extends $base_package.JVpp { + + /** + * Generic dispatch method for sending requests to VPP + * + * @throws io.fd.vpp.jvpp.VppInvocationException if send request had failed + */ + int send($base_package.$dto_package.JVppRequest request) throws io.fd.vpp.jvpp.VppInvocationException; + +$methods +} +""") + +jvpp_impl_template = Template(""" +package $plugin_package; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; +import java.util.Set; +import java.util.logging.Logger; +import $base_package.callback.JVppCallback; +import $base_package.VppConnection; +import $base_package.JVppRegistry; + +/** + *

Default implementation of JVpp interface. + *
It was generated by jvpp_impl_gen.py based on $inputfile + *
(python representation of api file generated by vppapigen). + */ +public final class JVpp${plugin_name}Impl implements $plugin_package.JVpp${plugin_name} { + + private final static Logger LOG = Logger.getLogger(JVpp${plugin_name}Impl.class.getName()); + private static final String LIBNAME = "libjvpp_${plugin_name_underscore}.so"; + + // FIXME using NativeLibraryLoader makes load fail could not find (WantInterfaceEventsReply). + static { + try { + loadLibrary(); + } catch (Exception e) { + LOG.severe("Can't find jvpp jni library: " + LIBNAME); + throw new ExceptionInInitializerError(e); + } + } + + private static void loadStream(final InputStream is) throws IOException { + final Set perms = PosixFilePermissions.fromString("rwxr-x---"); + final Path p = Files.createTempFile(LIBNAME, null, PosixFilePermissions.asFileAttribute(perms)); + try { + Files.copy(is, p, StandardCopyOption.REPLACE_EXISTING); + + try { + Runtime.getRuntime().load(p.toString()); + } catch (UnsatisfiedLinkError e) { + throw new IOException("Failed to load library " + p, e); + } + } finally { + try { + Files.deleteIfExists(p); + } catch (IOException e) { + } + } + } + + private static void loadLibrary() throws IOException { + try (final InputStream is = JVpp${plugin_name}Impl.class.getResourceAsStream('/' + LIBNAME)) { + if (is == null) { + throw new IOException("Failed to open library resource " + LIBNAME); + } + loadStream(is); + } + } + + private VppConnection connection; + private JVppRegistry registry; + + private static native void init0(final JVppCallback callback, final long queueAddress, final int clientIndex); + @Override + public void init(final JVppRegistry registry, final JVppCallback callback, final long queueAddress, final int clientIndex) { + this.registry = java.util.Objects.requireNonNull(registry, "registry should not be null"); + this.connection = java.util.Objects.requireNonNull(registry.getConnection(), "connection should not be null"); + connection.checkActive(); + init0(callback, queueAddress, clientIndex); + } + + private static native void close0(); + @Override + public void close() { + close0(); + } + + @Override + public int send($base_package.$dto_package.JVppRequest request) throws io.fd.vpp.jvpp.VppInvocationException { + return request.send(this); + } + + @Override + public final int controlPing(final io.fd.vpp.jvpp.dto.ControlPing controlPing) throws io.fd.vpp.jvpp.VppInvocationException { + return registry.controlPing(JVpp${plugin_name}Impl.class); + } + +$methods +} +""") + +method_template = Template(""" int $name($plugin_package.$dto_package.$request request) throws io.fd.vpp.jvpp.VppInvocationException;""") +method_native_template = Template( + """ private static native int ${name}0($plugin_package.$dto_package.$request request);""") +method_impl_template = Template(""" public final int $name($plugin_package.$dto_package.$request request) throws io.fd.vpp.jvpp.VppInvocationException { + java.util.Objects.requireNonNull(request,"Null request object"); + connection.checkActive(); + int result=${name}0(request); + if(result<0){ + throw new io.fd.vpp.jvpp.VppInvocationException("${name}",result); + } + return result; + } +""") + +no_arg_method_template = Template(""" int $name() throws io.fd.vpp.jvpp.VppInvocationException;""") +no_arg_method_native_template = Template(""" private static native int ${name}0() throws io.fd.vpp.jvpp.VppInvocationException;""") +no_arg_method_impl_template = Template(""" public final int $name() throws io.fd.vpp.jvpp.VppInvocationException { + connection.checkActive(); + int result=${name}0(); + if(result<0){ + throw new io.fd.vpp.jvpp.VppInvocationException("${name}",result); + } + return result; + } +""") + + +def generate_jvpp(func_list, base_package, plugin_package, plugin_name_underscore, dto_package, inputfile): + """ Generates JVpp interface and JNI implementation """ + print "Generating JVpp" + plugin_name = util.underscore_to_camelcase_upper(plugin_name_underscore) + + methods = [] + methods_impl = [] + for func in func_list: + + # Skip structures that are used only as notifications + if util.is_just_notification(func['name']) or util.is_ignored(func['name']): + continue + + camel_case_name = util.underscore_to_camelcase(func['name']) + camel_case_name_upper = util.underscore_to_camelcase_upper(func['name']) + if util.is_reply(camel_case_name): + continue + + if len(func['args']) == 0: + methods.append(no_arg_method_template.substitute(name=camel_case_name)) + methods_impl.append(no_arg_method_native_template.substitute(name=camel_case_name)) + methods_impl.append(no_arg_method_impl_template.substitute(name=camel_case_name)) + else: + methods.append(method_template.substitute(name=camel_case_name, + request=camel_case_name_upper, + plugin_package=plugin_package, + dto_package=dto_package)) + methods_impl.append(method_native_template.substitute(name=camel_case_name, + request=camel_case_name_upper, + plugin_package=plugin_package, + dto_package=dto_package)) + methods_impl.append(method_impl_template.substitute(name=camel_case_name, + request=camel_case_name_upper, + plugin_package=plugin_package, + dto_package=dto_package)) + + jvpp_file = open("JVpp%s.java" % plugin_name, 'w') + jvpp_file.write( + jvpp_ifc_template.substitute(inputfile=inputfile, + methods="\n".join(methods), + base_package=base_package, + plugin_package=plugin_package, + plugin_name=plugin_name, + dto_package=dto_package)) + jvpp_file.flush() + jvpp_file.close() + + jvpp_file = open("JVpp%sImpl.java" % plugin_name, 'w') + jvpp_file.write(jvpp_impl_template.substitute(inputfile=inputfile, + methods="\n".join(methods_impl), + base_package=base_package, + plugin_package=plugin_package, + plugin_name=plugin_name, + plugin_name_underscore=plugin_name_underscore, + dto_package=dto_package)) + jvpp_file.flush() + jvpp_file.close() diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/notification_gen.py b/src/vpp-api/java/jvpp/gen/jvppgen/notification_gen.py new file mode 100644 index 00000000..94302d56 --- /dev/null +++ b/src/vpp-api/java/jvpp/gen/jvppgen/notification_gen.py @@ -0,0 +1,199 @@ +#!/usr/bin/env python +# +# 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. + +import os + +import callback_gen +import util +from string import Template + +notification_registry_template = Template(""" +package $plugin_package.$notification_package; + +/** + *

Registry for notification callbacks defined in ${plugin_name}. + *
It was generated by notification_gen.py based on $inputfile + *
(python representation of api file generated by vppapigen). + */ +public interface ${plugin_name}NotificationRegistry extends $base_package.$notification_package.NotificationRegistry { + + $register_callback_methods + + @Override + void close(); +} +""") + +global_notification_callback_template = Template(""" +package $plugin_package.$notification_package; + +/** + *

Aggregated callback interface for notifications only. + *
It was generated by notification_gen.py based on $inputfile + *
(python representation of api file generated by vppapigen). + */ +public interface Global${plugin_name}NotificationCallback$callbacks { + +} +""") + +notification_registry_impl_template = Template(""" +package $plugin_package.$notification_package; + +/** + *

Notification registry delegating notification processing to registered callbacks. + *
It was generated by notification_gen.py based on $inputfile + *
(python representation of api file generated by vppapigen). + */ +public final class ${plugin_name}NotificationRegistryImpl implements ${plugin_name}NotificationRegistry, Global${plugin_name}NotificationCallback { + + // TODO add a special NotificationCallback interface and only allow those to be registered + private final java.util.concurrent.ConcurrentMap, $base_package.$callback_package.JVppNotificationCallback> registeredCallbacks = + new java.util.concurrent.ConcurrentHashMap<>(); + + $register_callback_methods + $handler_methods + + @Override + public void close() { + registeredCallbacks.clear(); + } +} +""") + +register_callback_impl_template = Template(""" + public java.lang.AutoCloseable register$callback(final $plugin_package.$callback_package.$callback callback){ + if(null != registeredCallbacks.putIfAbsent($plugin_package.$dto_package.$notification.class, callback)){ + throw new IllegalArgumentException("Callback for " + $plugin_package.$dto_package.$notification.class + + "notification already registered"); + } + return () -> registeredCallbacks.remove($plugin_package.$dto_package.$notification.class); + } +""") + +handler_impl_template = Template(""" + @Override + public void on$notification( + final $plugin_package.$dto_package.$notification notification) { + final $base_package.$callback_package.JVppNotificationCallback jVppNotificationCallback = registeredCallbacks.get($plugin_package.$dto_package.$notification.class); + if (null != jVppNotificationCallback) { + (($plugin_package.$callback_package.$callback) registeredCallbacks + .get($plugin_package.$dto_package.$notification.class)) + .on$notification(notification); + } + } +""") + +notification_provider_template = Template(""" +package $plugin_package.$notification_package; + + /** + * Provides ${plugin_name}NotificationRegistry. + *
The file was generated by notification_gen.py based on $inputfile + *
(python representation of api file generated by vppapigen). + */ +public interface ${plugin_name}NotificationRegistryProvider extends $base_package.$notification_package.NotificationRegistryProvider { + + @Override + public ${plugin_name}NotificationRegistry getNotificationRegistry(); +} +""") + + +def generate_notification_registry(func_list, base_package, plugin_package, plugin_name, notification_package, callback_package, dto_package, inputfile): + """ Generates notification registry interface and implementation """ + print "Generating Notification interfaces and implementation" + + if not os.path.exists(notification_package): + os.mkdir(notification_package) + + callbacks = [] + register_callback_methods = [] + register_callback_methods_impl = [] + handler_methods = [] + for func in func_list: + + if not util.is_notification(func['name']): + continue + + camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name']) + notification_dto = util.add_notification_suffix(camel_case_name_with_suffix) + callback_ifc = notification_dto + callback_gen.callback_suffix + fully_qualified_callback_ifc = "{0}.{1}.{2}".format(plugin_package, callback_package, callback_ifc) + callbacks.append(fully_qualified_callback_ifc) + + # TODO create NotificationListenerRegistration and return that instead of AutoCloseable to better indicate + # that the registration should be closed + register_callback_methods.append("java.lang.AutoCloseable register{0}({1} callback);" + .format(callback_ifc, fully_qualified_callback_ifc)) + register_callback_methods_impl.append(register_callback_impl_template.substitute(plugin_package=plugin_package, + callback_package=callback_package, + dto_package=dto_package, + notification=notification_dto, + callback=callback_ifc)) + handler_methods.append(handler_impl_template.substitute(base_package=base_package, + plugin_package=plugin_package, + callback_package=callback_package, + dto_package=dto_package, + notification=notification_dto, + callback=callback_ifc)) + + + callback_file = open(os.path.join(notification_package, "%sNotificationRegistry.java" % plugin_name), 'w') + callback_file.write(notification_registry_template.substitute(inputfile=inputfile, + register_callback_methods="\n ".join(register_callback_methods), + base_package=base_package, + plugin_package=plugin_package, + plugin_name=plugin_name, + notification_package=notification_package)) + callback_file.flush() + callback_file.close() + + callback_file = open(os.path.join(notification_package, "Global%sNotificationCallback.java" % plugin_name), 'w') + + global_notification_callback_callbacks = "" + if (callbacks): + global_notification_callback_callbacks = " extends " + ", ".join(callbacks) + + callback_file.write(global_notification_callback_template.substitute(inputfile=inputfile, + callbacks=global_notification_callback_callbacks, + plugin_package=plugin_package, + plugin_name=plugin_name, + notification_package=notification_package)) + callback_file.flush() + callback_file.close() + + callback_file = open(os.path.join(notification_package, "%sNotificationRegistryImpl.java" % plugin_name), 'w') + callback_file.write(notification_registry_impl_template.substitute(inputfile=inputfile, + callback_package=callback_package, + dto_package=dto_package, + register_callback_methods="".join(register_callback_methods_impl), + handler_methods="".join(handler_methods), + base_package=base_package, + plugin_package=plugin_package, + plugin_name=plugin_name, + notification_package=notification_package)) + callback_file.flush() + callback_file.close() + + callback_file = open(os.path.join(notification_package, "%sNotificationRegistryProvider.java" % plugin_name), 'w') + callback_file.write(notification_provider_template.substitute(inputfile=inputfile, + base_package=base_package, + plugin_package=plugin_package, + plugin_name=plugin_name, + notification_package=notification_package)) + callback_file.flush() + callback_file.close() + diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/types_gen.py b/src/vpp-api/java/jvpp/gen/jvppgen/types_gen.py new file mode 100644 index 00000000..7a5eec37 --- /dev/null +++ b/src/vpp-api/java/jvpp/gen/jvppgen/types_gen.py @@ -0,0 +1,227 @@ +#!/usr/bin/env python +# +# 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. + +import os +from string import Template + +import util +import jni_gen +import dto_gen + +type_template = Template(""" +package $plugin_package.$type_package; + +/** + *

This class represents $c_type_name type definition. + *
It was generated by types_gen.py based on $inputfile preparsed data: + *

+$docs
+ * 
+ */ +public final class $java_type_name { +$fields +$methods +} +""") + +field_template = Template(""" public $type $name;\n""") + + +def generate_type_fields(type_definition): + """ + Generates fields for class representing typeonly definition + :param type_definition: python representation of typeonly definition + :return: string representing class fields + """ + fields = "" + for t in zip(type_definition['types'], type_definition['args']): + field_name = util.underscore_to_camelcase(t[1]) + fields += field_template.substitute(type=util.jni_2_java_type_mapping[t[0]], + name=field_name) + return fields + +object_struct_setter_template = Template(""" + { + jclass ${field_reference_name}Class = (*env)->FindClass(env, "${class_FQN}"); + memset (&(mp->${c_name}), 0, sizeof (mp->${c_name})); + ${struct_initialization} + } +""") + +object_array_struct_setter_template = Template(""" + { + jclass ${field_reference_name}ArrayElementClass = (*env)->FindClass(env, "${class_FQN}"); + if (${field_reference_name}) { + size_t _i; + jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name}); + ${field_length_check} + for (_i = 0; _i < cnt; _i++) { + jobject ${field_reference_name}ArrayElement = (*env)->GetObjectArrayElement(env, ${field_reference_name}, _i); + memset (&(mp->${c_name}[_i]), 0, sizeof (mp->${c_name}[_i])); + ${struct_initialization} + } + } + } +""") + +object_dto_field_setter_template = Template(""" + { + jclass ${field_reference_name}Class = (*env)->FindClass(env, "${class_FQN}"); + jmethodID ${field_reference_name}Constructor = (*env)->GetMethodID(env, ${field_reference_name}Class, "", "()V"); + jobject ${field_reference_name} = (*env)->NewObject(env, ${field_reference_name}Class, ${field_reference_name}Constructor); + ${type_initialization} + (*env)->SetObjectField(env, dto, ${field_reference_name}FieldId, ${field_reference_name}); + } +""") + +object_array_dto_field_setter_template = Template(""" + { + jclass ${field_reference_name}Class = (*env)->FindClass(env, "${class_FQN}"); + jobjectArray ${field_reference_name} = (*env)->NewObjectArray(env, ${field_length}, ${field_reference_name}Class, 0); + unsigned int _i; + for (_i = 0; _i < ${field_length}; _i++) { + jmethodID ${field_reference_name}Constructor = (*env)->GetMethodID(env, ${field_reference_name}Class, "", "()V"); + jobject ${field_reference_name}ArrayElement = (*env)->NewObject(env, ${field_reference_name}Class, ${field_reference_name}Constructor); + ${type_initialization} + (*env)->SetObjectArrayElement(env, ${field_reference_name}, _i, ${field_reference_name}ArrayElement); + } + (*env)->SetObjectField(env, dto, ${field_reference_name}FieldId, ${field_reference_name}); + } +""") + + +def generate_struct_initialization(type_def, c_name_prefix, object_name, indent): + struct_initialization = "" + # field identifiers + for t in zip(type_def['types'], type_def['args'], type_def['lengths']): + field_reference_name = "${c_name}" + util.underscore_to_camelcase_upper(t[1]) + field_name = util.underscore_to_camelcase(t[1]) + struct_initialization += jni_gen.jni_request_binding_for_type(field_type=t[0], c_name=c_name_prefix + t[1], + field_reference_name=field_reference_name, + field_name=field_name, + field_length=t[2][0], + is_variable_len_array=t[2][1], + object_name=object_name) + return indent + struct_initialization.replace('\n', '\n' + indent) + + +def generate_type_setter(handler_name, type_def, c_name_prefix, object_name, indent): + type_initialization = "" + for t in zip(type_def['types'], type_def['args'], type_def['lengths']): + field_length = t[2][0] + is_variable_len_array = t[2][1] + length_field_type = None + if is_variable_len_array: + length_field_type = type_def['types'][type_def['args'].index(field_length)] + type_initialization += jni_gen.jni_reply_handler_for_type(handler_name=handler_name, + ref_name="${field_reference_name}", + field_type=t[0], c_name=c_name_prefix + t[1], + field_reference_name="${c_name}" + util.underscore_to_camelcase_upper(t[1]), + field_name=util.underscore_to_camelcase(t[1]), + field_length=field_length, + is_variable_len_array=is_variable_len_array, + length_field_type=length_field_type, + object_name=object_name) + return indent + type_initialization.replace('\n', '\n' + indent) + + +def generate_types(types_list, plugin_package, types_package, inputfile): + """ + Generates Java representation of custom types defined in api file. + """ + + # + if not types_list: + print "Skipping custom types generation (%s does not define custom types)." % inputfile + return + + print "Generating custom types" + + if not os.path.exists(types_package): + os.mkdir(types_package) + + for type in types_list: + c_type_name = type['name'] + java_type_name = util.underscore_to_camelcase_upper(type['name']) + dto_path = os.path.join(types_package, java_type_name + ".java") + + fields = generate_type_fields(type) + + dto_file = open(dto_path, 'w') + dto_file.write(type_template.substitute(plugin_package=plugin_package, + type_package=types_package, + c_type_name=c_type_name, + inputfile=inputfile, + docs=util.api_message_to_javadoc(type), + java_type_name=java_type_name, + fields=fields, + methods=dto_gen.generate_dto_base_methods(java_type_name, type) + )) + + # update type mappings: + # todo fix vpe.api to use type_name instead of vl_api_type_name_t + type_name = "vl_api_" + c_type_name + "_t" + java_fqn = "%s.%s.%s" % (plugin_package, types_package, java_type_name) + util.vpp_2_jni_type_mapping[type_name] = "jobject" + util.vpp_2_jni_type_mapping[type_name + "[]"] = "jobjectArray" + util.jni_2_java_type_mapping[type_name] = java_fqn + util.jni_2_java_type_mapping[type_name + "[]"] = java_fqn + "[]" + jni_name = java_fqn.replace('.', "/") + jni_signature = "L" + jni_name + ";" + util.jni_2_signature_mapping[type_name] = "L" + jni_name + ";" + util.jni_2_signature_mapping[type_name + "[]"] = "[" + jni_signature + util.jni_field_accessors[type_name] = "ObjectField" + util.jni_field_accessors[type_name + "[]"] = "ObjectField" + + jni_gen.struct_setter_templates[type_name] = Template( + object_struct_setter_template.substitute( + c_name="${c_name}", + field_reference_name="${field_reference_name}", + class_FQN=jni_name, + struct_initialization=generate_struct_initialization(type, "${c_name}.", + "${field_reference_name}", ' ' * 4)) + ) + + jni_gen.struct_setter_templates[type_name+ "[]"] = Template( + object_array_struct_setter_template.substitute( + c_name="${c_name}", + field_reference_name="${field_reference_name}", + field_length_check="${field_length_check}", + class_FQN=jni_name, + struct_initialization=generate_struct_initialization(type, "${c_name}[_i].", + "${field_reference_name}ArrayElement", ' ' * 8)) + ) + + jni_gen.dto_field_setter_templates[type_name] = Template( + object_dto_field_setter_template.substitute( + field_reference_name="${field_reference_name}", + field_length="${field_length}", + class_FQN=jni_name, + type_initialization=generate_type_setter(c_type_name, type, "${c_name}.", + "${field_reference_name}", ' ' * 4)) + ) + + jni_gen.dto_field_setter_templates[type_name + "[]"] = Template( + object_array_dto_field_setter_template.substitute( + field_reference_name="${field_reference_name}", + field_length="${field_length}", + class_FQN=jni_name, + type_initialization=generate_type_setter(c_type_name, type, "${c_name}[_i].", + "${field_reference_name}ArrayElement", ' ' * 8)) + ) + + dto_file.flush() + dto_file.close() + diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/util.py b/src/vpp-api/java/jvpp/gen/jvppgen/util.py new file mode 100644 index 00000000..fc971c17 --- /dev/null +++ b/src/vpp-api/java/jvpp/gen/jvppgen/util.py @@ -0,0 +1,220 @@ +#!/usr/bin/env python +# +# 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. + +import os, pprint +from os import removedirs + + +def underscore_to_camelcase(name): + name = name.title().replace("_", "") + return name[0].lower() + name[1:] + + +def underscore_to_camelcase_upper(name): + name = name.title().replace("_", "") + return name[0].upper() + name[1:] + + +def remove_folder(folder): + """ Remove folder with all its files """ + for root, dirs, files in os.walk(folder, topdown=False): + for name in files: + os.remove(os.path.join(root, name)) + removedirs(folder) + + +reply_suffixes = ("reply", "details", "l2fibtableentry") + + +def is_reply(name): + return name.lower().endswith(reply_suffixes) + + +def is_details(name): + return name.lower().endswith(reply_suffixes[1]) or name.lower().endswith(reply_suffixes[2]) + + +def is_retval_field(name): + return name == 'retval' + +dump_suffix = "dump" + + +def is_dump(name): + return name.lower().endswith(dump_suffix) + + +def get_reply_suffix(name): + for reply_suffix in reply_suffixes: + if name.lower().endswith(reply_suffix): + if reply_suffix == reply_suffixes[2]: + # FIXME workaround for l2_fib_table_entry + return 'entry' + else: + return reply_suffix + +# Mapping according to: +# http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html +# +# Unsigned types are converted to signed java types that have the same size. +# It is the API user responsibility to interpret them correctly. +jni_2_java_type_mapping = {'u8': 'byte', + 'u8[]': 'byte[]', + 'i8': 'byte', + 'i8[]': 'byte[]', + 'u16': 'short', + 'u16[]': 'short[]', + 'i16': 'short', + 'i16[]': 'short[]', + 'u32': 'int', + 'u32[]': 'int[]', + 'i32': 'int', + 'i32[]': 'int[]', + 'u64': 'long', + 'u64[]': 'long[]', + 'i64': 'long', + 'i64[]': 'long[]', + 'f64': 'double', + 'f64[]': 'double[]' + } + +vpp_2_jni_type_mapping = {'u8': 'jbyte', + 'u8[]': 'jbyteArray', + 'i8': 'jbyte', + 'u8[]': 'jbyteArray', + 'u16': 'jshort', + 'u16[]': 'jshortArray', + 'i16': 'jshort', + 'i16[]': 'jshortArray', + 'u32': 'jint', + 'u32[]': 'jintArray', + 'i32': 'jint', + 'i32[]': 'jintArray', + 'u64': 'jlong', + 'u64[]': 'jlongArray', + 'i64': 'jlong', + 'i64[]': 'jlongArray', + 'f64': 'jdouble', + 'f64[]': 'jdoubleArray' + } + +# https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/types.html#type_signatures +jni_2_signature_mapping = {'u8': 'B', + 'u8[]': '[B', + 'i8': 'B', + 'i8[]': '[B', + 'u16': 'S', + 'u16[]': '[S', + 'i16': 'S', + 'i16[]': '[S', + 'u32': 'I', + 'u32[]': '[I', + 'i32': 'I', + 'i32[]': '[I', + 'u64': 'J', + 'u64[]': '[J', + 'i64': 'J', + 'i64[]': '[J', + 'f64': 'D', + 'f64[]': '[D' + } + +# https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#Get_type_Field_routines +jni_field_accessors = {'u8': 'ByteField', + 'u8[]': 'ObjectField', + 'i8': 'ByteField', + 'i8[]': 'ObjectField', + 'u16': 'ShortField', + 'u16[]': 'ObjectField', + 'i16': 'ShortField', + 'i16[]': 'ObjectField', + 'u32': 'IntField', + 'u32[]': 'ObjectField', + 'i32': 'IntField', + 'i32[]': 'ObjectField', + 'u64': 'LongField', + 'u64[]': 'ObjectField', + 'i64': 'LongField', + 'i64[]': 'ObjectField', + 'f64': 'DoubleField', + 'f64[]': 'ObjectField' + } + + +# vpe.api calls that do not follow naming conventions and have to be handled exceptionally when finding reply -> request mapping +# FIXME in vpe.api +unconventional_naming_rep_req = { + 'cli_reply': 'cli_request', + 'vnet_summary_stats_reply': 'vnet_get_summary_stats', + # This below is actually a sub-details callback. We cannot derive the mapping of dump request + # belonging to this sub-details from naming conventions. We need special mapping + 'bridge_domain_sw_if_details': 'bridge_domain', + # This is standard dump call + details reply. However it's not called details but entry + 'l2_fib_table_entry': 'l2_fib_table' + } + +# +# FIXME no convention in the naming of events (notifications) in vpe.api +notifications_message_suffixes = ("event", "counters") +notification_messages_reused = ["sw_interface_set_flags"] + +# messages that must be ignored. These messages are INSUFFICIENTLY marked as disabled in vpe.api +# FIXME +ignored_messages = ["is_address_reachable"] + + +def is_notification(name): + """ Returns true if the structure is a notification regardless of its no other use """ + return is_just_notification(name) or name.lower() in notification_messages_reused + + +def is_just_notification(name): + """ Returns true if the structure is just a notification and has no other use """ + return name.lower().endswith(notifications_message_suffixes) + + +def is_ignored(param): + return param.lower() in ignored_messages + + +def remove_reply_suffix(camel_case_name_with_suffix): + return remove_suffix(camel_case_name_with_suffix, get_reply_suffix(camel_case_name_with_suffix)) + + +def remove_suffix(camel_case_name_with_suffix, suffix): + suffix_length = len(suffix) + return camel_case_name_with_suffix[:-suffix_length] if suffix_length != 0 else camel_case_name_with_suffix + + +def is_control_ping(camel_case_name_with_suffix): + return camel_case_name_with_suffix.lower().startswith("controlping"); + + +def api_message_to_javadoc(api_message): + """ Converts vpe.api message description to javadoc """ + str = pprint.pformat(api_message, indent=4, width=120, depth=None) + return " * " + str.replace("\n", "\n * ") + + +notification_dto_suffix = "Notification" + + +def add_notification_suffix(camel_case_dto_name): + camel_case_dto_name += notification_dto_suffix + return camel_case_dto_name + + +def is_array(java_type_as_string): + return java_type_as_string.endswith("[]") diff --git a/src/vpp-api/lua/README.md b/src/vpp-api/lua/README.md new file mode 100644 index 00000000..4ecdb34d --- /dev/null +++ b/src/vpp-api/lua/README.md @@ -0,0 +1,50 @@ +This is the experimental version of Lua API, aimed for the luajit use. + +Please take a look and send the feedback to ayourtch@gmail.com. + +To run the examples here: + +1) install luajit - "sudo apt-get install luajit" on ubuntu + +2) "make build-vpp-api" in the top VPP directory + +3) "make run" in a separate terminal window + This ensures you have an instance of VPP running + +4) sudo luajit examples/example-cli.lua + +This will result in something like this: + +Version: +00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + +{ [1] = { ["luaapi_message_name"] = show_version_reply,["program"] = vpe,["version"] = ,["build_date"] = Fri Nov 25 10:58:48 UTC 2016,["retval"] = 0,["build_directory"] = /home/ubuntu/vpp,["_vl_msg_id"] = 170,["context"] = 0,} ,} +--- +{ [1] = { ["luaapi_message_name"] = cli_inband_reply,["_vl_msg_id"] = 94,["length"] = 66,["reply"] = vpp v built by ubuntu on vpp-toys at Fri Nov 25 10:58:48 UTC 2016 +,["retval"] = 0,["context"] = 0,} ,} +--- + +5) You can also run the performance test bench: + +$ sudo luajit bench.lua +10001 iterations, average speed 5624LL per second +10001 iterations, average speed 6650LL per second +10001 iterations, average speed 6053LL per second +10001 iterations, average speed 7056LL per second +10001 iterations, average speed 6388LL per second +10001 iterations, average speed 5849LL per second +10001 iterations, average speed 6321LL per second +10001 iterations, average speed 6368LL per second +10001 iterations, average speed 5958LL per second +10001 iterations, average speed 6482LL per second +Average tps across the tests: 6274LL + +Note: the above is run in an lxd container running inside 2-core +xhyve VM on a Macbook Pro, so I would not take the performance numbers for granted :) + +The "examples" directory contains a few naive examples, as well as a couple of more +advanced ones - a tab-completing CLI for VPP that can call both the APIs and CLI, +and also a small test utility which I use for automating some small tests using +VPP. + diff --git a/src/vpp-api/lua/bench.lua b/src/vpp-api/lua/bench.lua new file mode 100644 index 00000000..8e5a0b4b --- /dev/null +++ b/src/vpp-api/lua/bench.lua @@ -0,0 +1,70 @@ +--[[ +/* + * 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. + */ +]] + +local vpp = require "vpp-lapi" + +local ffi = require "ffi" + +ffi.cdef([[ + struct timespec { + long tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ + }; + + int clock_gettime(int clk_id, struct timespec *tp); +]]) + + +local time_cache = ffi.new("struct timespec[1]") +local time_cache_1 = time_cache[0] +function get_ns() + ffi.C.clock_gettime(0, time_cache) + return time_cache_1.tv_nsec + 1000000000 * time_cache_1.tv_sec +end + +function do_bench() + local cycle_start = get_ns() + local n_iterations = 10000 + local count = 1 + for i = 1,n_iterations do + -- print(i) + vpp:api_call("show_version") + count = count + 1 + -- print(i, "done") + end + cycle_end = get_ns() + local tps = n_iterations*1000000000LL/(cycle_end - cycle_start) + print (tostring(count) .. " iterations, average speed " .. tostring(tps) .. " per second") + return tps +end + +root_dir = "/home/ubuntu/vpp" +pneum_path = root_dir .. "/build-root/install-vpp_lite_debug-native/vpp-api/lib64/libpneum.so" +vpp:init({ pneum_path = pneum_path }) +vpp:json_api(root_dir .. "/build-root/install-vpp_lite_debug-native/vpp/vpp-api/vpe.api.json") + +vpp:connect("lua-bench") +local n_tests = 10 +local tps_acc = 0LL +for i=1,n_tests do + tps_acc = tps_acc + do_bench() +end +print("Average tps across the tests: " .. tostring(tps_acc/n_tests)) + +vpp:disconnect() + + diff --git a/src/vpp-api/lua/examples/cli/README.md b/src/vpp-api/lua/examples/cli/README.md new file mode 100644 index 00000000..3a5f8ee9 --- /dev/null +++ b/src/vpp-api/lua/examples/cli/README.md @@ -0,0 +1,5 @@ +This is a small experiment to have a wrapper CLI which can call both API functions as well as debug CLI. + +To facilitate tab completion and help, the API call names are broken up with spaces replacing the underscores. + + diff --git a/src/vpp-api/lua/examples/cli/lua-cli.lua b/src/vpp-api/lua/examples/cli/lua-cli.lua new file mode 100644 index 00000000..b3a24d7d --- /dev/null +++ b/src/vpp-api/lua/examples/cli/lua-cli.lua @@ -0,0 +1,747 @@ +--[[ +/* + * 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. + */ +]] + +-- Experimental prototype CLI using API to VPP, with tab completion +-- +-- Written by Andrew Yourtchenko (ayourtch@cisco.com) 2010,2016 +-- + +vpp = require "vpp-lapi" + + +local dotdotdot = "..." + +-- First the "readline" routine + +readln = { +split = function(str, pat) + local t = {} -- NOTE: use {n = 0} in Lua-5.0 + local fpat = "(.-)" .. pat + local last_end = 1 + if str then + local s, e, cap = str:find(fpat, 1) + while s do + if s ~= 1 or cap ~= "" then + table.insert(t,cap) + end + last_end = e+1 + s, e, cap = str:find(fpat, last_end) + end + if last_end <= #str then + cap = str:sub(last_end) + table.insert(t, cap) + end + end + return t +end, + +reader = function() + local rl = {} + + rl.init = function() + os.execute("stty -icanon min 1 -echo") + rl.rawmode = true + end + + rl.done = function() + os.execute("stty icanon echo") + rl.rawmode = false + end + + rl.prompt = ">" + rl.history = { "" } + rl.history_index = 1 + rl.history_length = 1 + + rl.hide_cmd = function() + local bs = string.char(8) .. " " .. string.char(8) + for i = 1, #rl.command do + io.stdout:write(bs) + end + end + + rl.show_cmd = function() + if rl.command then + io.stdout:write(rl.command) + end + end + + rl.store_history = function(cmd) + if cmd == "" then + return + end + rl.history[rl.history_length] = cmd + rl.history_length = rl.history_length + 1 + rl.history_index = rl.history_length + rl.history[rl.history_length] = "" + end + + rl.readln = function() + local done = false + local need_prompt = true + rl.command = "" + + if not rl.rawmode then + rl.init() + end + + while not done do + if need_prompt then + io.stdout:write(rl.prompt) + io.stdout:write(rl.command) + need_prompt = false + end + + local ch = io.stdin:read(1) + if ch:byte(1) == 27 then + -- CONTROL + local ch2 = io.stdin:read(1) + -- arrows + if ch2:byte(1) == 91 then + local ch3 = io.stdin:read(1) + local b = ch3:byte(1) + if b == 65 then + ch = "UP" + elseif b == 66 then + ch = "DOWN" + elseif b == 67 then + ch = "RIGHT" + elseif b == 68 then + ch = "LEFT" + end + -- print("Byte: " .. ch3:byte(1)) + -- if ch3:byte(1) + end + end + + if ch == "?" then + io.stdout:write(ch) + io.stdout:write("\n") + if rl.help then + rl.help(rl) + end + need_prompt = true + elseif ch == "\t" then + if rl.tab_complete then + rl.tab_complete(rl) + end + io.stdout:write("\n") + need_prompt = true + elseif ch == "\n" then + io.stdout:write(ch) + done = true + elseif ch == "\004" then + io.stdout:write("\n") + rl.command = nil + done = true + elseif ch == string.char(127) then + if rl.command ~= "" then + io.stdout:write(string.char(8) .. " " .. string.char(8)) + rl.command = string.sub(rl.command, 1, -2) + end + elseif #ch > 1 then + -- control char + if ch == "UP" then + rl.hide_cmd() + if rl.history_index == #rl.history then + rl.history[rl.history_index] = rl.command + end + if rl.history_index > 1 then + rl.history_index = rl.history_index - 1 + rl.command = rl.history[rl.history_index] + end + rl.show_cmd() + elseif ch == "DOWN" then + rl.hide_cmd() + if rl.history_index < rl.history_length then + rl.history_index = rl.history_index + 1 + rl.command = rl.history[rl.history_index] + end + rl.show_cmd() + end + else + io.stdout:write(ch) + rl.command = rl.command .. ch + end + end + if rl.command then + rl.store_history(rl.command) + end + return rl.command + end + return rl +end + +} + +--[[ + +r = reader() + +local done = false + +while not done do + local cmd = r.readln() + print("Command: " .. tostring(cmd)) + if not cmd or cmd == "quit" then + done = true + end +end + +r.done() + +]] + +--------- MDS show tech parser + +local print_section = nil +local list_sections = false + +local curr_section = "---" +local curr_parser = nil + +-- by default operate in batch mode +local batch_mode = true + +local db = {} +local device = {} +device.output = {} +local seen_section = {} + +function start_collection(name) + device = {} + seen_section = {} +end + +function print_error(errmsg) + print("@#$:" .. errmsg) +end + +function keys(tbl) + local t = {} + for k, v in pairs(tbl) do + table.insert(t, k) + end + return t +end + +function tset (parent, ...) + + -- print ('set', ...) + + local len = select ('#', ...) + local key, value = select (len-1, ...) + local cutpoint, cutkey + + for i=1,len-2 do + + local key = select (i, ...) + local child = parent[key] + + if value == nil then + if child == nil then return + elseif next (child, next (child)) then cutpoint = nil cutkey = nil + elseif cutpoint == nil then cutpoint = parent cutkey = key end + + elseif child == nil then child = {} parent[key] = child end + + parent = child + end + + if value == nil and cutpoint then cutpoint[cutkey] = nil + else parent[key] = value return value end + end + + +function tget (parent, ...) + local len = select ('#', ...) + for i=1,len do + parent = parent[select (i, ...)] + if parent == nil then break end + end + return parent + end + + +local pager_lines = 23 +local pager_printed = 0 +local pager_skipping = false +local pager_filter_pipe = nil + +function pager_reset() + pager_printed = 0 + pager_skipping = false + if pager_filter_pipe then + pager_filter_pipe:close() + pager_filter_pipe = nil + end +end + + +function print_more() + io.stdout:write(" --More-- ") +end + +function print_nomore() + local bs = string.char(8) + local bs10 = bs .. bs .. bs .. bs .. bs .. bs .. bs .. bs .. bs .. bs + io.stdout:write(bs10 .. " " .. bs10) +end + +function print_line(txt) + if pager_filter_pipe then + pager_filter_pipe:write(txt .. "\n") + return + end + if pager_printed >= pager_lines then + print_more() + local ch = io.stdin:read(1) + if ch == " " then + pager_printed = 0 + elseif ch == "\n" then + pager_printed = pager_printed - 1 + elseif ch == "q" then + pager_printed = 0 + pager_skipping = true + end + print_nomore() + end + if not pager_skipping then + print(txt) + pager_printed = pager_printed + 1 + else + -- skip printing + end +end + +function paged_write(text) + local t = readln.split(text, "[\n]") + if string.sub(text, -1) == "\n" then + table.insert(t, "") + end + for i, v in ipairs(t) do + if i < #t then + print_line(v) + else + if pager_filter_pipe then + pager_filter_pipe:write(v) + else + io.stdout:write(v) + end + end + end +end + + + + + +function get_choices(tbl, key) + local res = {} + for k, v in pairs(tbl) do + if string.sub(k, 1, #key) == key then + table.insert(res, k) + elseif 0 < #key and dotdotdot == k then + table.insert(res, k) + end + end + return res +end + +function get_exact_choice(choices, val) + local exact_idx = nil + local substr_idx = nil + local substr_seen = false + + if #choices == 1 then + if choices[1] == dotdotdot then + return 1 + elseif string.sub(choices[1], 1, #val) == val then + return 1 + else + return nil + end + else + for i, v in ipairs(choices) do + if v == val then + exact_idx = i + substr_seen = true + elseif choices[i] ~= dotdotdot and string.sub(choices[i], 1, #val) == val then + if substr_seen then + substr_idx = nil + else + substr_idx = i + substr_seen = true + end + elseif choices[i] == dotdotdot then + if substr_seen then + substr_idx = nil + else + substr_idx = i + substr_seen = true + end + end + end + end + return exact_idx or substr_idx +end + +function device_cli_help(rl) + local key = readln.split(rl.command, "[ ]+") + local tree = rl.tree + local keylen = #key + local fullcmd = "" + local error = false + local terse = true + + if ((#rl.command >= 1) and (string.sub(rl.command, -1) == " ")) or (#rl.command == 0) then + table.insert(key, "") + terse = false + end + + for i, v in ipairs(key) do + local choices = get_choices(tree, v) + local idx = get_exact_choice(choices, v) + if idx then + local choice = choices[idx] + tree = tree[choice] + fullcmd = fullcmd .. choice .. " " + else + if i < #key then + error = true + end + end + + if i == #key and not error then + for j, w in ipairs(choices) do + if terse then + paged_write(w .. "\t") + else + paged_write(" " .. w .. "\n") + end + end + paged_write("\n") + if terse then + paged_write(" \n") + end + end + end + pager_reset() +end + +function device_cli_tab_complete(rl) + local key = readln.split(rl.command, "[ ]+") + local tree = rl.tree + local keylen = #key + local fullcmd = "" + local error = false + + for i, v in ipairs(key) do + local choices = get_choices(tree, v) + local idx = get_exact_choice(choices, v) + if idx and choices[idx] ~= dotdotdot then + local choice = choices[idx] + tree = tree[choice] + -- print("level " .. i .. " '" .. choice .. "'") + fullcmd = fullcmd .. choice .. " " + else + -- print("level " .. i .. " : " .. table.concat(choices, " ") .. " ") + error = true + end + end + if not error then + rl.command = fullcmd + else + -- print("\n\nerror\n") + end + pager_reset() +end + +function device_cli_exec(rl) + + local cmd_nopipe = rl.command + local cmd_pipe = nil + + local pipe1, pipe2 = string.find(rl.command, "[|]") + if pipe1 then + cmd_nopipe = string.sub(rl.command, 1, pipe1-1) + cmd_pipe = string.sub(rl.command, pipe2+1, -1) + end + + local key = readln.split(cmd_nopipe .. " ", "[ ]+") + local tree = rl.tree + local keylen = #key + local fullcmd = "" + local error = false + local func = nil + + if cmd_pipe then + pager_filter_pipe = io.popen(cmd_pipe, "w") + end + + + rl.choices = {} + + for i, v in ipairs(key) do + local choices = get_choices(tree, v) + local idx = get_exact_choice(choices, v) + if idx then + local choice = choices[idx] + if i == #key then + func = tree[choice] + else + if choice == dotdotdot then + -- keep the tree the same, update the choice value to match the input string + choices[idx] = v + choice = v + else + tree = tree[choice] + end + end + -- print("level " .. i .. " '" .. choice .. "'") + table.insert(rl.choices, choice) + else + -- print("level " .. i .. " : " .. table.concat(choices, " ") .. " ") + error = true + return nil + end + end + return func +end + +function populate_tree(commands) + local tree = {} + + for k, v in pairs(commands) do + local key = readln.split(k .. " ", "[ ]+") + local xtree = tree + for i, kk in ipairs(key) do + if i == 1 and kk == "sh" then + kk = "show" + end + if i == #key then + if type(v) == "function" then + xtree[kk] = v + else + xtree[kk] = function(rl) paged_write(table.concat(v, "\n") .. "\n") end + end + else + if not xtree[kk] then + xtree[kk] = {} + end + xtree = xtree[kk] + end + end + end + return tree +end + +function trim (s) + return (string.gsub(s, "^%s*(.-)%s*$", "%1")) +end + + +function init_vpp(vpp) + local root_dir = "/home/ubuntu/vpp" + local pneum_path = root_dir .. "/build-root/install-vpp_lite_debug-native/vpp-api/lib64/libpneum.so" + + vpp:init({ pneum_path = pneum_path }) + + vpp:init({ pneum_path = pneum_path }) + vpp:json_api(root_dir .. "/build-root/install-vpp_lite_debug-native/vpp/vpp-api/vpe.api.json") + + + + vpp:connect("lua_cli") +end + +function run_cli(vpp, cli) + local reply = vpp:api_call("cli_inband", { cmd = cli }) + if reply and #reply == 1 then + local rep = reply[1] + if 0 == rep.retval then + return rep.reply + else + return "XXXXXLUACLI: API RETVAL ERROR : " .. tostring(rep.retval) + end + else + return "XXXXXLUACLI ERROR, RAW REPLY: " .. vpp.dump(reply) + end +end + + +function toprintablestring(s) + if type(s) == "string" then + return "\n"..vpp.hex_dump(s) + else + return tostring(s) + end +end + +function interactive_cli(r) + while not done do + pager_reset() + local cmd = r.readln() + if not cmd then + done = true + elseif cmd == "quit" or cmd == "exit" then + done = true + else + local func = device_cli_exec(r) + if func then + func(r) + else + if trim(cmd) == "" then + else + for i = 1, #r.prompt do + paged_write(" ") + end + paged_write("^\n% Invalid input detected at '^' marker.\n\n") + end + end + end + end +end + +device = {} +device.output = {} + +init_vpp(vpp) +cmds_str = run_cli(vpp, "?") +vpp_cmds = readln.split(cmds_str, "\n") +vpp_clis = {} + +for linenum, line in ipairs(vpp_cmds) do + local m,h = string.match(line, "^ (.-) (.*)$") + if m and #m > 0 then + table.insert(vpp_clis, m) + device.output["vpp debug cli " .. m] = function(rl) + -- print("ARBITRARY CLI" .. vpp.dump(rl.choices)) + print("LUACLI command: " .. table.concat(rl.choices, " ")) + local sub = {} + -- + for i=4, #rl.choices -1 do + table.insert(sub, rl.choices[i]) + end + local cli = table.concat(sub, " ") + print("Running CLI: " .. tostring(cli)) + paged_write(run_cli(vpp, cli)) + end + device.output["vpp debug cli " .. m .. " " .. dotdotdot] = function(rl) + print("ARGH") + end + + local ret = run_cli(vpp, "help " .. m) + device.output["help vpp debug cli " .. m] = { ret } + end +end + +for linenum, line in ipairs(vpp_clis) do + -- print(line, ret) +end + +for msgnum, msgname in pairs(vpp.msg_number_to_name) do + local cli, numspaces = string.gsub(msgname, "_", " ") + device.output["call " .. cli .. " " .. dotdotdot] = function(rl) + print("ARGH") + end + device.output["call " .. cli] = function(rl) + print("LUACLI command: " .. table.concat(rl.choices, " ")) + print("Running API: " .. msgname) -- vpp.dump(rl.choices)) + local out = {} + local args = {} + local ntaken = 0 + local argname = "" + for i=(1+1+numspaces+1), #rl.choices-1 do + -- print(i, rl.choices[i]) + if ntaken > 0 then + ntaken = ntaken -1 + else + local fieldname = rl.choices[i] + local field = vpp.msg_name_to_fields[msgname][fieldname] + if field then + local s = rl.choices[i+1] + s=s:gsub("\\x(%x%x)",function (x) return string.char(tonumber(x,16)) end) + args[fieldname] = s + ntaken = 1 + end + end + end + -- print("ARGS: ", vpp.dump(args)) + local ret = vpp:api_call(msgname, args) + for i, reply in ipairs(ret) do + table.insert(out, "=================== Entry #" .. tostring(i)) + for k, v in pairs(reply) do + table.insert(out, " " .. tostring(k) .. " : " .. toprintablestring(v)) + end + end + -- paged_write(vpp.dump(ret) .. "\n\n") + paged_write(table.concat(out, "\n").."\n\n") + end + device.output["call " .. cli .. " help"] = function(rl) + local out = {} + for k, v in pairs(vpp.msg_name_to_fields[msgname]) do + table.insert(out, tostring(k) .. " : " .. v["ctype"] .. " ; " .. tostring(vpp.dump(v)) ) + end + -- paged_write(vpp.dump(vpp.msg_name_to_fields[msgname]) .. "\n\n") + paged_write(table.concat(out, "\n").."\n\n") + end +-- vpp.msg_name_to_number = {} +end + + + +local r = readln.reader() +local done = false + +r.prompt = "VPP(luaCLI)#" + +r.help = device_cli_help +r.tab_complete = device_cli_tab_complete +print("===== CLI view, use ^D to end =====") + +r.tree = populate_tree(device.output) +-- readln.pretty("xxxx", r.tree) + + +for idx, an_arg in ipairs(arg) do + local fname = an_arg + if fname == "-i" then + pager_lines = 23 + interactive_cli(r) + else + pager_lines = 100000000 + for line in io.lines(fname) do + r.command = line + local func = device_cli_exec(r) + if func then + func(r) + end + end + end +end + +if #arg == 0 then + print("You should specify '-i' as an argument for the interactive session,") + print("but with no other sources of commands, we start interactive session now anyway") + interactive_cli(r) +end + +vpp:disconnect() +r.done() + + diff --git a/src/vpp-api/lua/examples/example-acl-plugin.lua b/src/vpp-api/lua/examples/example-acl-plugin.lua new file mode 100644 index 00000000..ca01f18d --- /dev/null +++ b/src/vpp-api/lua/examples/example-acl-plugin.lua @@ -0,0 +1,110 @@ +--[[ +/* + * 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. + */ +]] + + +vpp = require "vpp-lapi" + +root_dir = "/home/ubuntu/vpp" +pneum_path = root_dir .. "/build-root/install-vpp_debug-native/vpp-api/lib64/libpneum.so" + +vpp:init({ pneum_path = pneum_path }) + +vpp:consume_api(root_dir .. "/build-root/install-vpp_debug-native/vlib-api/vlibmemory/memclnt.api") +vpp:consume_api(root_dir .. "/build-root/install-vpp_debug-native/vpp/vpp-api/vpe.api") +vpp:connect("aytest") +vpp:consume_api(root_dir .. "/plugins/acl-plugin/acl/acl.api", "acl") + +-- api calls +reply = vpp:api_call("show_version") +print("Version: ", reply[1].version) +print(vpp.hex_dump(reply[1].version)) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_del", { context = 42, acl_index = 230 }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_del", { context = 42, acl_index = 8 }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_del", { context = 42, acl_index = 15 }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_add", { context = 42, count = 2, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 } } }) +print(vpp.dump(reply)) +print("---") +interface_acl_in = reply[1].acl_index + +reply = vpp:api_call("acl_add", { context = 42, count = 3, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 }, { is_permit = 1, is_ipv6 = 0 } } }) +print(vpp.dump(reply)) +print("---") +interface_acl_out = reply[1].acl_index + + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 1, acl_index = interface_acl_in }) +print(vpp.dump(reply)) +print("---") +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 1, acl_index = interface_acl_in }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 0, acl_index = interface_acl_out }) +print(vpp.dump(reply)) +print("---") +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 0, acl_index = interface_acl_out }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_add", { context = 42, count = 0 }) +print(vpp.dump(reply)) +print("---") + +acl_index_to_delete = reply[1].acl_index +print("Deleting " .. tostring(acl_index_to_delete)) +reply = vpp:api_call("acl_del", { context = 42, acl_index = acl_index_to_delete }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 0}) +for ri, rv in ipairs(reply) do + print("Reply message #" .. tostring(ri)) + print(vpp.dump(rv)) + for ai, av in ipairs(rv.r) do + print("ACL rule #" .. tostring(ai) .. " : " .. vpp.dump(av)) + end + +end +print("---") + +reply = vpp:api_call("acl_del", { context = 42, acl_index = interface_acl_out }) +print(vpp.dump(reply)) +print("---") +reply = vpp:api_call("acl_del", { context = 42, acl_index = interface_acl_in }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 0}) +print(vpp.dump(reply)) +print("---") + + +vpp:disconnect() + + diff --git a/src/vpp-api/lua/examples/example-classifier.lua b/src/vpp-api/lua/examples/example-classifier.lua new file mode 100644 index 00000000..ec9c3d3e --- /dev/null +++ b/src/vpp-api/lua/examples/example-classifier.lua @@ -0,0 +1,51 @@ +--[[ +/* + * 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. + */ +]] + + +local vpp = require "vpp-lapi" +local bit = require("bit") + +root_dir = "/home/ubuntu/vpp" +pneum_path = root_dir .. "/build-root/install-vpp_lite_debug-native/vpp-api/lib64/libpneum.so" + + +vpp:init({ pneum_path = pneum_path }) + +vpp:json_api(root_dir .. "/build-root/install-vpp_lite_debug-native/vpp/vpp-api/vpe.api.json") + +vpp:connect("aytest") + +-- api calls + +print("Calling API to add a new classifier table") +reply = vpp:api_call("classify_add_del_table", { + context = 43, + memory_size = bit.lshift(2, 20), + client_index = 42, + is_add = 1, + nbuckets = 32, + skip_n_vectors = 0, + match_n_vectors = 1, + mask = "\255\255\255\255\255\255\255\255" .. "\255\255\255\255\255\255\255\255" +}) +print(vpp.dump(reply)) +print("---") + + +vpp:disconnect() + + diff --git a/src/vpp-api/lua/examples/example-cli.lua b/src/vpp-api/lua/examples/example-cli.lua new file mode 100644 index 00000000..8b84989f --- /dev/null +++ b/src/vpp-api/lua/examples/example-cli.lua @@ -0,0 +1,44 @@ +--[[ +/* + * 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. + */ +]] + +vpp = require "vpp-lapi" + +root_dir = "/home/ubuntu/vpp" +pneum_path = root_dir .. "/build-root/install-vpp_lite_debug-native/vpp-api/lib64/libpneum.so" + +vpp:init({ pneum_path = pneum_path }) + +vpp:json_api(root_dir .. "/build-root/install-vpp_lite_debug-native/vpp/vpp-api/vpe.api.json") + +vpp:connect("aytest") + +-- api calls +reply = vpp:api_call("show_version") +print("Version: ", reply[1].version) +print(vpp.hex_dump(reply[1].version)) +print(vpp.dump(reply)) +print("---") + + +reply = vpp:api_call("cli_inband", { cmd = "show vers" }) +print(vpp.dump(reply)) +print("---") + + +vpp:disconnect() + + diff --git a/src/vpp-api/lua/examples/lute/README.md b/src/vpp-api/lua/examples/lute/README.md new file mode 100644 index 00000000..8d37250a --- /dev/null +++ b/src/vpp-api/lua/examples/lute/README.md @@ -0,0 +1,66 @@ +LUTE: Lua Unit Test Environment + +This is a small helper utility to automate some simple tests +that one might need to do. + +Think of it as a hybrid of a screen and expect who +also took some habits from HTML inline code. + +It is quite probably useless for building anything serious, +but practice shows it is quite efficient at allowing +convenient temporary quick tests, and for something +that was written over a course of a couple of evenings it +is quite a nice little helper tool. + +It allows do launch and drive multiple shell sessions, +and by virtue of having been written in Lua, it of course +also allows to add the business logic using the Lua code. + +If you launch the lute without parameters, it gives you +the interactive shell to execute the commands in. + +If you launch it with an argument, it will attempt to +read and execute the commands from the file. + +Commands: + +shell FOO + + spawn a shell in a new PTY under the label FOO. + +run FOO bar + + Send "bar" keystrokes followed by "ENTER" to the session FOO + + Special case: "break" word on its own gets translated into ^C being sent. + +cd FOO + + "change domain" into session FOO. All subsequent inputs will go, + line-buffered, into the session FOO. To jump back up, use ^D (Control-D), + or within the file, use ^D^D^D (caret D caret D caret D on its own line) + +expect FOO blablabla + + Pause further interpretation of the batch mode until you see "blablabla" + in the output of session FOO, or until timeout happens. + +sleep N + + Sleep an integer N seconds, if you are in batch mode. + +echo blabla + + Echo the remainder of the line to standard output. + +For Lua code, there is a pre-existing pseudo-session called "lua", +which accepts "run lua" command which does what you would expect +(evaluate the rest of the string in Lua context - being the same +as lute itself). Also you can do "cd lua" and get into a +multiline-enabled interpreter shell. + +This way for the VPP case you can automate some of the things in your routine +that you would have to have done manually, and test drive API as well +as use the realistic native OS components to create the environment around it. + + diff --git a/src/vpp-api/lua/examples/lute/lute.lua b/src/vpp-api/lua/examples/lute/lute.lua new file mode 100644 index 00000000..89b9924b --- /dev/null +++ b/src/vpp-api/lua/examples/lute/lute.lua @@ -0,0 +1,777 @@ +--[[ +version = 1 +/* + * 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. + */ +]] + +-- LUTE: Lua Unit Test Environment +-- AKA what happens when screen tries to marry with lua and expect, +-- but escapes mid-ceremony. +-- +-- comments: @ayourtch + +ffi = require("ffi") + +vpp = {} +function vpp.dump(o) + if type(o) == 'table' then + local s = '{ ' + for k,v in pairs(o) do + if type(k) ~= 'number' then k = '"'..k..'"' end + s = s .. '['..k..'] = ' .. vpp.dump(v) .. ',' + end + return s .. '} ' + else + return tostring(o) + end +end + + +ffi.cdef([[ + +int posix_openpt(int flags); +int grantpt(int fd); +int unlockpt(int fd); +char *ptsname(int fd); + +typedef long pid_t; +typedef long ssize_t; +typedef long size_t; +typedef int nfds_t; +typedef long time_t; +typedef long suseconds_t; + +pid_t fork(void); +pid_t setsid(void); + +int close(int fd); +int open(char *pathname, int flags); + +int dup2(int oldfd, int newfd); + +ssize_t read(int fd, void *buf, size_t count); +ssize_t write(int fd, const void *buf, size_t count); + +struct pollfd { + int fd; /* file descriptor */ + short events; /* requested events */ + short revents; /* returned events */ + }; + +int poll(struct pollfd *fds, nfds_t nfds, int timeout); + +struct timeval { + time_t tv_sec; /* seconds */ + suseconds_t tv_usec; /* microseconds */ + }; + +int gettimeofday(struct timeval *tv, struct timezone *tz); + +int inet_pton(int af, const char *src, void *dst); + +]]) + +ffi.cdef([[ +void *memset(void *s, int c, size_t n); +void *memcpy(void *dest, void *src, size_t n); +void *memmove(void *dest, const void *src, size_t n); +void *memmem(const void *haystack, size_t haystacklen, + const void *needle, size_t needlelen); +]]) + + + +local O_RDWR = 2 + + +function os_time() + local tv = ffi.new("struct timeval[1]") + local ret = ffi.C.gettimeofday(tv, nil) + return tonumber(tv[0].tv_sec) + (tonumber(tv[0].tv_usec)/1000000.0) +end + +function sleep(n) + local when_wakeup = os_time() + n + while os_time() <= when_wakeup do + ffi.C.poll(nil, 0, 10) + end +end + + +function c_str(text_in) + local text = text_in + local c_str = ffi.new("char[?]", #text+1) + ffi.copy(c_str, text) + return c_str +end + +function ip46(addr_text) + local out = ffi.new("char [200]") + local AF_INET6 = 10 + local AF_INET = 2 + local is_ip6 = ffi.C.inet_pton(AF_INET6, c_str(addr_text), out) + if is_ip6 == 1 then + return ffi.string(out, 16), true + end + local is_ip4 = ffi.C.inet_pton(AF_INET, c_str(addr_text), out) + if is_ip4 then + return (string.rep("4", 12).. ffi.string(out, 4)), false + end +end + +function pty_master_open() + local fd = ffi.C.posix_openpt(O_RDWR) + ffi.C.grantpt(fd) + ffi.C.unlockpt(fd) + local p = ffi.C.ptsname(fd) + print("PTS:" .. ffi.string(p)) + return fd, ffi.string(p) +end + +function pty_run(cmd) + local master_fd, pts_name = pty_master_open() + local child_pid = ffi.C.fork() + if (child_pid == -1) then + print("Error fork()ing") + return -1 + end + + if child_pid ~= 0 then + -- print("Parent") + return master_fd, child_pid + end + + -- print("Child") + if (ffi.C.setsid() == -1) then + print("Child error setsid") + os.exit(-1) + end + + ffi.C.close(master_fd) + + local slave_fd = ffi.C.open(c_str(pts_name), O_RDWR) + if slave_fd == -1 then + print("Child can not open slave fd") + os.exit(-2) + end + + ffi.C.dup2(slave_fd, 0) + ffi.C.dup2(slave_fd, 1) + ffi.C.dup2(slave_fd, 2) + os.execute(cmd) +end + +function readch() + local buf = ffi.new("char[1]") + local nread= ffi.C.read(0, buf, 1) + -- print("\nREADCH : " .. string.char(buf[0])) + return string.char(buf[0]) +end + +function stdout_write(str) + ffi.C.write(1, c_str(str), #str) +end + + +readln = { +split = function(str, pat) + local t = {} -- NOTE: use {n = 0} in Lua-5.0 + local fpat = "(.-)" .. pat + local last_end = 1 + if str then + local s, e, cap = str:find(fpat, 1) + while s do + if s ~= 1 or cap ~= "" then + table.insert(t,cap) + end + last_end = e+1 + s, e, cap = str:find(fpat, last_end) + end + if last_end <= #str then + cap = str:sub(last_end) + table.insert(t, cap) + end + end + return t +end, + +reader = function() + local rl = {} + + rl.init = function() + os.execute("stty -icanon min 1 -echo") + rl.rawmode = true + end + + rl.done = function() + os.execute("stty icanon echo") + rl.rawmode = false + end + + rl.prompt = ">" + rl.history = { "" } + rl.history_index = 1 + rl.history_length = 1 + + rl.hide_cmd = function() + local bs = string.char(8) .. " " .. string.char(8) + for i = 1, #rl.command do + stdout_write(bs) + end + end + + rl.show_cmd = function() + if rl.command then + stdout_write(rl.command) + end + end + + rl.store_history = function(cmd) + if cmd == "" then + return + end + rl.history[rl.history_length] = cmd + rl.history_length = rl.history_length + 1 + rl.history_index = rl.history_length + rl.history[rl.history_length] = "" + end + + rl.readln = function(stdin_select_fn, batch_cmd, batch_when, batch_expect) + local done = false + local need_prompt = true + rl.command = "" + + if not rl.rawmode then + rl.init() + end + + while not done do + local indent_value = #rl.prompt + #rl.command + if need_prompt then + stdout_write(rl.prompt) + stdout_write(rl.command) + need_prompt = false + end + if type(stdin_select_fn) == "function" then + while not stdin_select_fn(indent_value, batch_cmd, batch_when, batch_expect) do + stdout_write(rl.prompt) + stdout_write(rl.command) + indent_value = #rl.prompt + #rl.command + end + if batch_cmd and ((os_time() > batch_when) or (batch_expect and expect_success(batch_expect, buf, 0))) then + stdout_write("\n" .. rl.prompt .. batch_cmd .. "\n") + if batch_expect then + expect_done(batch_expect) + end + return batch_cmd, batch_expect + end + end + local ch = readch() + if ch:byte(1) == 27 then + -- CONTROL + local ch2 = readch() + -- arrows + if ch2:byte(1) == 91 then + local ch3 = readch() + local b = ch3:byte(1) + if b == 65 then + ch = "UP" + elseif b == 66 then + ch = "DOWN" + elseif b == 67 then + ch = "RIGHT" + elseif b == 68 then + ch = "LEFT" + end + -- print("Byte: " .. ch3:byte(1)) + -- if ch3:byte(1) + end + end + + if ch == "?" then + stdout_write(ch) + stdout_write("\n") + if rl.help then + rl.help(rl) + end + need_prompt = true + elseif ch == "\t" then + if rl.tab_complete then + rl.tab_complete(rl) + end + stdout_write("\n") + need_prompt = true + elseif ch == "\n" then + stdout_write(ch) + done = true + elseif ch == "\004" then + stdout_write("\n") + rl.command = nil + done = true + elseif ch == string.char(127) then + if rl.command ~= "" then + stdout_write(string.char(8) .. " " .. string.char(8)) + rl.command = string.sub(rl.command, 1, -2) + end + elseif #ch > 1 then + -- control char + if ch == "UP" then + rl.hide_cmd() + if rl.history_index == #rl.history then + rl.history[rl.history_index] = rl.command + end + if rl.history_index > 1 then + rl.history_index = rl.history_index - 1 + rl.command = rl.history[rl.history_index] + end + rl.show_cmd() + elseif ch == "DOWN" then + rl.hide_cmd() + if rl.history_index < rl.history_length then + rl.history_index = rl.history_index + 1 + rl.command = rl.history[rl.history_index] + end + rl.show_cmd() + end + else + stdout_write(ch) + rl.command = rl.command .. ch + end + end + if rl.command then + rl.store_history(rl.command) + end + return rl.command + end + return rl +end + +} + +local select_fds = {} +local sessions = {} + +local line_erased = false + +function erase_line(indent) + if not line_erased then + line_erased = true + stdout_write(string.rep(string.char(8), indent)..string.rep(" ", indent)..string.rep(string.char(8), indent)) + end +end + +function do_select_stdin(indent, batch_cmd, batch_when, batch_expect) + while true do + local nfds = 1+#select_fds + local pfds = ffi.new("struct pollfd[?]", nfds) + pfds[0].fd = 0; + pfds[0].events = 1; + pfds[0].revents = 0; + for i = 1,#select_fds do + pfds[i].fd = select_fds[i].fd + pfds[i].events = 1 + pfds[i].revents = 0 + end + if batch_cmd and ((os_time() > batch_when) or (batch_expect and expect_success(batch_expect, buf, 0))) then + return true + end + while ffi.C.poll(pfds, nfds, 10) == 0 do + if batch_cmd and ((os_time() > batch_when) or (batch_expect and expect_success(batch_expect, buf, 0))) then + return true + end + if line_erased then + line_erased = false + return false + end + end + if pfds[0].revents == 1 then + return true + end + for i = 1,#select_fds do + if(pfds[i].revents > 0) then + if pfds[i].fd ~= select_fds[i].fd then + print("File descriptors unequal", pfds[i].fd, select_fds[i].fd) + end + select_fds[i].cb(select_fds[i], pfds[i].revents, indent) + end + end + end +end + +local buf = ffi.new("char [32768]") + +function session_stdout_write(prefix, data) + data = prefix .. data:gsub("\n", "\n"..prefix):gsub("\n"..prefix.."$", "\n") + + stdout_write(data) +end + +function expect_success(sok, buf, nread) + local expect_buf_sz = ffi.sizeof(sok.expect_buf) - 128 + local expect_buf_avail = expect_buf_sz - sok.expect_buf_idx + -- print("EXPECT_SUCCESS: nread ".. tostring(nread).. " expect_buf_idx: " .. tostring(sok.expect_buf_idx) .. " expect_buf_avail: " .. tostring(expect_buf_avail) ) + if expect_buf_avail < 0 then + print "EXPECT BUFFER OVERRUN ALREADY" + os.exit(1) + end + if expect_buf_avail < nread then + if (nread >= ffi.sizeof(sok.expect_buf)) then + print("Read too large of a chunk to fit into expect buffer") + return nil + end + local delta = nread - expect_buf_avail + + ffi.C.memmove(sok.expect_buf, sok.expect_buf + delta, expect_buf_sz - delta) + sok.expect_buf_idx = sok.expect_buf_idx - delta + expect_buf_avail = nread + end + if sok.expect_buf_idx + nread > expect_buf_sz then + print("ERROR, I have just overrun the buffer !") + os.exit(1) + end + ffi.C.memcpy(sok.expect_buf + sok.expect_buf_idx, buf, nread) + sok.expect_buf_idx = sok.expect_buf_idx + nread + if sok.expect_str == nil then + return true + end + local match_p = ffi.C.memmem(sok.expect_buf, sok.expect_buf_idx, sok.expect_str, sok.expect_str_len) + if match_p ~= nil then + return true + end + return false +end + +function expect_done(sok) + local expect_buf_sz = ffi.sizeof(sok.expect_buf) - 128 + if not sok.expect_str then + return false + end + local match_p = ffi.C.memmem(sok.expect_buf, sok.expect_buf_idx, sok.expect_str, sok.expect_str_len) + if match_p ~= nil then + if sok.expect_cb then + sok.expect_cb(sok) + end + local match_idx = ffi.cast("char *", match_p) - ffi.cast("char *", sok.expect_buf) + ffi.C.memmove(sok.expect_buf, ffi.cast("char *", match_p) + sok.expect_str_len, expect_buf_sz - match_idx - sok.expect_str_len) + sok.expect_buf_idx = match_idx + sok.expect_str_len + sok.expect_success = true + + sok.expect_str = nil + sok.expect_str_len = 0 + return true + end +end + +function slave_events(sok, revents, indent) + local fd = sok.fd + local nread = ffi.C.read(fd, buf, ffi.sizeof(buf)-128) + local idx = nread - 1 + while idx >= 0 and buf[idx] ~= 10 do + idx = idx - 1 + end + if idx >= 0 then + erase_line(indent) + session_stdout_write(sok.prefix, sok.buf .. ffi.string(buf, idx+1)) + sok.buf = "" + end + sok.buf = sok.buf .. ffi.string(buf+idx+1, nread-idx-1) + -- print("\nRead: " .. tostring(nread)) + -- stdout_write(ffi.string(buf, nread)) + if expect_success(sok, buf, nread) then + return true + end + return false +end + + +function start_session(name) + local mfd, cpid = pty_run("/bin/bash") + local sok = { ["fd"] = mfd, ["cb"] = slave_events, ["buf"] = "", ["prefix"] = name .. ":", ["expect_buf"] = ffi.new("char [165536]"), ["expect_buf_idx"] = 0, ["expect_str"] = nil } + table.insert(select_fds, sok) + sessions[name] = sok +end + +function command_transform(exe) + if exe == "break" then + exe = string.char(3) + end + return exe +end + +function session_write(a_session, a_str) + if has_session(a_session) then + return tonumber(ffi.C.write(sessions[a_session].fd, c_str(a_str), #a_str)) + else + return 0 + end +end + +function session_exec(a_session, a_cmd) + local exe = command_transform(a_cmd) .. "\n" + session_write(a_session, exe) +end + +function session_cmd(ui, a_session, a_cmd) + if not has_session(a_session) then + stdout_write("ERR: No such session '" .. tostring(a_session) .. "'\n") + return nil + end + if a_session == "lua" then + local func, msg = loadstring(ui.lua_acc .. a_cmd) + -- stdout_write("LOADSTR: " .. vpp.dump({ ret, msg }) .. "\n") + if not func and string.match(msg, "") then + if a_session ~= ui.in_session then + stdout_write("ERR LOADSTR: " .. tostring(msg) .. "\n") + return nil + end + ui.lua_acc = ui.lua_acc .. a_cmd .. "\n" + return true + end + ui.lua_acc = "" + local ret, msg = pcall(func) + if ret then + return true + else + stdout_write("ERR: " .. msg .. "\n") + return nil + end + else + session_exec(a_session, a_cmd) + if ui.session_cmd_delay then + return { "delay", ui.session_cmd_delay } + end + return true + end +end + +function has_session(a_session) + if a_session == "lua" then + return true + end + return (sessions[a_session] ~= nil) +end + +function command_match(list, input, output) + for i, v in ipairs(list) do + local m = {} + m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9] = string.match(input, v[1]) + -- print("MATCH: ", vpp.dump(m)) + if m[1] then + output["result"] = m + output["result_index"] = i + return m + end + end + return nil +end + +function cmd_spawn_shell(ui, a_arg) + start_session(a_arg[1]) + return true +end + +function cmd_run_cmd(ui, a_arg) + local a_sess = a_arg[1] + local a_cmd = a_arg[2] + return session_cmd(ui, a_sess, a_cmd) +end + +function cmd_cd(ui, a_arg) + local a_sess = a_arg[1] + if has_session(a_sess) then + ui.in_session = a_sess + return true + else + stdout_write("ERR: Unknown session '".. tostring(a_sess) .. "'\n") + return nil + end +end + +function cmd_sleep(ui, a_arg) + return { "delay", tonumber(a_arg[1]) } +end + +function cmd_expect(ui, a_arg) + local a_sess = a_arg[1] + local a_expect = a_arg[2] + local sok = sessions[a_sess] + if not sok then + stdout_write("ERR: unknown session '" .. tostring(a_sess) .. "'\n") + return nil + end + sok.expect_str = c_str(a_expect) + sok.expect_str_len = #a_expect + return { "expect", a_sess } +end + +function cmd_info(ui, a_arg) + local a_sess = a_arg[1] + local sok = sessions[a_sess] + if not sok then + stdout_write("ERR: unknown session '" .. tostring(a_sess) .. "'\n") + return nil + end + print("Info for session " .. tostring(a_sess) .. "\n") + print("Expect buffer index: " .. tostring(sok.expect_buf_idx)) + print("Expect buffer: '" .. tostring(ffi.string(sok.expect_buf, sok.expect_buf_idx)) .. "'\n") + if sok.expect_str then + print("Expect string: '" .. tostring(ffi.string(sok.expect_str, sok.expect_str_len)) .. "'\n") + else + print("Expect string not set\n") + end +end + +function cmd_echo(ui, a_arg) + local a_data = a_arg[1] + print("ECHO: " .. tostring(a_data)) +end + +main_command_table = { + { "^shell ([a-zA-Z0-9_]+)$", cmd_spawn_shell }, + { "^run ([a-zA-Z0-9_]+) (.+)$", cmd_run_cmd }, + { "^cd ([a-zA-Z0-9_]+)$", cmd_cd }, + { "^sleep ([0-9]+)$", cmd_sleep }, + { "^expect ([a-zA-Z0-9_]+) (.-)$", cmd_expect }, + { "^info ([a-zA-Z0-9_]+)$", cmd_info }, + { "^echo (.-)$", cmd_echo } +} + + + +function ui_set_prompt(ui) + if ui.in_session then + if ui.in_session == "lua" then + if #ui.lua_acc > 0 then + ui.r.prompt = ui.in_session .. ">>" + else + ui.r.prompt = ui.in_session .. ">" + end + else + ui.r.prompt = ui.in_session .. "> " + end + else + ui.r.prompt = "> " + end + return ui.r.prompt +end + +function ui_run_command(ui, cmd) + -- stdout_write("Command: " .. tostring(cmd) .. "\n") + local ret = false + if ui.in_session then + if cmd then + if cmd == "^D^D^D" then + ui.in_session = nil + ret = true + else + ret = session_cmd(ui, ui.in_session, cmd) + end + else + ui.in_session = nil + ret = true + end + else + if cmd then + local out = {} + if cmd == "" then + ret = true + end + if command_match(main_command_table, cmd, out) then + local i = out.result_index + local m = out.result + if main_command_table[i][2] then + ret = main_command_table[i][2](ui, m) + end + end + end + if not cmd or cmd == "quit" then + return "quit" + end + end + return ret +end + +local ui = {} +ui.in_session = nil +ui.r = readln.reader() +ui.lua_acc = "" +ui.session_cmd_delay = 0.3 + +local lines = "" + +local done = false +-- a helper function which always returns nil +local no_next_line = function() return nil end + +-- a function which returns the next batch line +local next_line = no_next_line + +local batchfile = arg[1] + +if batchfile then + local f = io.lines(batchfile) + next_line = function() + local line = f() + if line then + return line + else + next_line = no_next_line + session_stdout_write(batchfile .. ":", "End of batch\n") + return nil + end + end +end + + +local batch_when = 0 +local batch_expect = nil +while not done do + local prompt = ui_set_prompt(ui) + local batch_cmd = next_line() + local cmd, expect_sok = ui.r.readln(do_select_stdin, batch_cmd, batch_when, batch_expect) + if expect_sok and not expect_success(expect_sok, buf, 0) then + if not cmd_ret and next_line ~= no_next_line then + print("ERR: expect timeout\n") + next_line = no_next_line + end + else + local cmd_ret = ui_run_command(ui, cmd) + if not cmd_ret and next_line ~= no_next_line then + print("ERR: Error during batch execution\n") + next_line = no_next_line + end + + if cmd_ret == "quit" then + done = true + end + batch_expect = nil + batch_when = 0 + if type(cmd_ret) == "table" then + if cmd_ret[1] == "delay" then + batch_when = os_time() + tonumber(cmd_ret[2]) + end + if cmd_ret[1] == "expect" then + batch_expect = sessions[cmd_ret[2]] + batch_when = os_time() + 15 + end + end + end +end +ui.r.done() + +os.exit(1) + + + diff --git a/src/vpp-api/lua/examples/lute/script-inout-acl-noacl.lute b/src/vpp-api/lua/examples/lute/script-inout-acl-noacl.lute new file mode 100644 index 00000000..a24d04bf --- /dev/null +++ b/src/vpp-api/lua/examples/lute/script-inout-acl-noacl.lute @@ -0,0 +1,329 @@ +shell vppbuild +run vppbuild stty -echo +run vppbuild sudo -u ubuntu -i bash -c "(cd vpp && make plugins && echo ALLGOOD)" +expect vppbuild ALLGOOD + +shell s0 +shell s1 +shell s2 + + +cd s1 +unshare -n /bin/bash +/sbin/ifconfig -a +^D^D^D + +cd s2 +unshare -n /bin/bash +/sbin/ifconfig -a +^D^D^D + + +cd lua + +function session_get_bash_pid(s) + if not has_session(s) then + return nil + end + local fname = "/tmp/lute-"..s.."-pid.txt" + + session_exec(s, "echo $$ >" .. fname) + -- it's a dirty hack but it's quick + sleep(0.5) + local pid = io.lines(fname)() + print("Got pid for " .. s .. " : " .. tostring(pid)) + return(tonumber(pid)) +end + +function session_connect_with(s0, s1) + -- local pid0 = tostring(session_get_bash_pid(s0)) + local pid1 = tostring(session_get_bash_pid(s1)) + local eth_options = { "rx", "tx", "sg", "tso", "ufo", "gso", "gro", "lro", "rxvlan", "txvlan", "rxhash" } + local this_end = s0 .. "_" .. s1 + local other_end = s1 .. "_" .. s0 + session_exec(s0, "ip link add name " .. this_end .. " type veth peer name " .. other_end) + session_exec(s0, "ip link set dev " .. this_end .. " up promisc on") + for i, option in ipairs(eth_options) do + session_exec(s0, "/sbin/ethtool --offload " .. this_end .. " " .. option .. " off") + session_exec(s0, "/sbin/ethtool --offload " .. other_end .. " " .. option .. " off") + end + session_exec(s0, "ip link set dev " .. other_end .. " up promisc on netns /proc/" .. pid1 .. "/ns/net") + sleep(0.5) +end + +^D^D^D +run lua session_connect_with("s0", "s1") +run lua session_connect_with("s0", "s2") + +cd s1 +ip -6 addr add dev s1_s0 2001:db8:1::1/64 +ip -4 addr add dev s1_s0 192.0.2.1/24 +ip link set dev s1_s0 up promisc on +^D^D^D + +cd s2 +ip -6 addr add dev s2_s0 2001:db8:1::2/64 +ip -6 addr add dev s2_s0 2001:db8:1::3/64 +ip -6 addr add dev s2_s0 2001:db8:1::4/64 +ip -4 addr add dev s2_s0 192.0.2.2/24 +ip -4 addr add dev s2_s0:1 192.0.2.3/24 +ip -4 addr add dev s2_s0:2 192.0.2.4/24 +ip link set dev s2_s0 up promisc on +^D^D^D + +run s1 ip addr +run s2 ip addr +shell VPP +cd VPP +cd /home/ubuntu/vpp +make debug +r +^D^D^D +expect VPP DBGvpp# + +cd lua +-- Initialization of the Lua environment for talking to VPP +vpp = require("vpp-lapi") +root_dir = "/home/ubuntu/vpp" +pneum_path = root_dir .. "/build-root/install-vpp_debug-native/vpp-api/lib64/libpneum.so" +vpp:init({ pneum_path = pneum_path }) +vpp:consume_api(root_dir .. "/build-root/install-vpp_debug-native/vlib-api/vlibmemory/memclnt.api") +vpp:consume_api(root_dir .. "/build-root/install-vpp_debug-native/vpp/vpp-api/vpe.api") +vpp:connect("aytest") +vpp:consume_api(root_dir .. "/plugins/acl-plugin/acl/acl.api", "acl") + +^D^D^D + +cd lua + +reply = vpp:api_call("af_packet_create", { host_if_name = "s0_s1", hw_addr = "AAAAAA" }) +vpp_if_to_s1 = reply[1].sw_if_index + +reply = vpp:api_call("af_packet_create", { host_if_name = "s0_s2", hw_addr = "AAAAAA" }) +vpp_if_to_s2 = reply[1].sw_if_index + +ifaces = { vpp_if_to_s1, vpp_if_to_s2 } + +reply = vpp:api_call("sw_interface_set_flags", { sw_if_index = vpp_if_to_s1, admin_up_down = 1, link_up_down = 1 }) +print(vpp.dump(reply)) +reply = vpp:api_call("sw_interface_set_flags", { sw_if_index = vpp_if_to_s2, admin_up_down = 1, link_up_down = 1 }) +print(vpp.dump(reply)) + +bd_id = 42 + +reply = vpp:api_call("bridge_domain_add_del", { bd_id = bd_id, flood = 1, uu_flood = 1, forward = 1, learn = 1, arp_term = 0, is_add = 1 }) +print(vpp.dump(reply)) + +for i, v in ipairs(ifaces) do + reply = vpp:api_call("sw_interface_set_l2_bridge", { rx_sw_if_index = v, bd_id = bd_id, shg = 0, bvi = 0, enable = 1 } ) + print(vpp.dump(reply)) +end + +^D^D^D + +run s1 ping -c 3 192.0.2.2 +expect s1 packet loss +run s1 ping -c 3 192.0.2.3 +expect s1 packet loss +run s1 ping -c 3 192.0.2.4 +expect s1 packet loss +run s1 ping6 -c 3 2001:db8:1::2 +expect s1 packet loss +run s1 ping6 -c 3 2001:db8:1::3 +expect s1 packet loss +run s1 ping6 -c 3 2001:db8:1::4 +expect s1 packet loss + + +cd lua +--- ACL testing + +--[[ temporary comment out + +reply = vpp:api_call("acl_del", { context = 42, acl_index = 230 }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_del", { context = 42, acl_index = 8 }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_del", { context = 42, acl_index = 15 }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_add_replace", { context = 42, count = 2, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 } } }) +print(vpp.dump(reply)) +print("---") +interface_acl_in = reply[1].acl_index + +reply = vpp:api_call("acl_add_replace", { context = 42, count = 3, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 }, { is_permit = 1, is_ipv6 = 0 } } }) +print(vpp.dump(reply)) +print("---") +interface_acl_out = reply[1].acl_index + + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 1, acl_index = interface_acl_in }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 1, acl_index = interface_acl_in }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 0, acl_index = interface_acl_out }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 0, acl_index = interface_acl_out }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_add_replace", { context = 42, count = 0 }) +print(vpp.dump(reply)) +print("---") + +acl_index_to_delete = reply[1].acl_index +print("Deleting " .. tostring(acl_index_to_delete)) +reply = vpp:api_call("acl_del", { context = 42, acl_index = acl_index_to_delete }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 0}) +for ri, rv in ipairs(reply) do + print("Reply message #" .. tostring(ri)) + print(vpp.dump(rv)) + for ai, av in ipairs(rv.r) do + print("ACL rule #" .. tostring(ai) .. " : " .. vpp.dump(av)) + end + +end +print("---") + +reply = vpp:api_call("acl_del", { context = 42, acl_index = interface_acl_out }) +print(vpp.dump(reply)) +print("---") +reply = vpp:api_call("acl_del", { context = 42, acl_index = interface_acl_in }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 0}) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 4294967295 }) +print(vpp.dump(reply)) +print("---") + + +]] -- end of comment out + +---- Should be nothing ^^ +r = { + { is_permit = 1, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8:1::2"), dst_ip_prefix_len = 128 }, + { is_permit = 0, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8:1::3"), dst_ip_prefix_len = 128 }, + { is_permit = 1, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8::"), dst_ip_prefix_len = 32 }, + { is_permit = 1, is_ipv6 = 0, dst_ip_addr = ip46("192.0.2.2"), dst_ip_prefix_len = 32}, + { is_permit = 0, is_ipv6 = 0, dst_ip_addr = ip46("192.0.2.3"), dst_ip_prefix_len = 32 }, +} + +reply = vpp:api_call("acl_add_replace", { context = 42, count = 5, r = r }) +print(vpp.dump(reply)) +print("---") +interface_acl_in = reply[1].acl_index + +reply = vpp:api_call("acl_add_replace", { context = 42, count = 3, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 }, { is_permit = 1, is_ipv6 = 0 } } }) +print(vpp.dump(reply)) +print("---") +interface_acl_out = reply[1].acl_in + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s1, is_add = 1, is_input = 1, acl_index = interface_acl_in }) +print(vpp.dump(reply)) +print("---") + +--reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s2, is_add = 1, is_input = 0, acl_index = interface_acl_out }) +-- print(vpp.dump(reply)) +--print("---") + +^D^D^D + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping6 -c 3 2001:db8:1::2 +expect s1 packet loss +run VPP show trace +expect VPP match: inacl 0 rule 0 + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping6 -c 3 2001:db8:1::3 +expect s1 packet loss +run VPP show trace +expect VPP match: inacl 0 rule 1 + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping6 -c 3 2001:db8:1::4 +expect s1 packet loss +run VPP show trace +expect VPP match: inacl 0 rule 2 + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping -c 3 192.0.2.2 +expect s1 packet loss +run VPP show trace +expect VPP match: inacl 0 rule 3 + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping -c 3 192.0.2.3 +expect s1 packet loss +run VPP show trace +expect VPP match: inacl 0 rule 4 + + +cd lua + +--- TEST OUTBOUND ACL + +r1 = { + { is_permit = 1, is_ipv6 = 1, src_ip_addr = ip46("2001:db8:1::1"), src_ip_prefix_len = 128, dst_ip_addr = ip46("2001:db8:1::2"), dst_ip_prefix_len = 128 }, + { is_permit = 0, is_ipv6 = 1, src_ip_addr = ip46("2001:db8:1::1"), src_ip_prefix_len = 128, dst_ip_addr = ip46("2001:db8:1::4"), dst_ip_prefix_len = 128 } +} + +reply = vpp:api_call("acl_add_replace", { context = 42, count = 3, r = r1 }) +print(vpp.dump(reply)) +print("---") +interface_acl_out = reply[1].acl_index + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s2, is_add = 1, is_input = 0, acl_index = interface_acl_out }) +print(vpp.dump(reply)) +print("---") + + +^D^D^D + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping6 -c 3 2001:db8:1::2 +expect s1 packet loss +run VPP show trace +expect VPP match: outacl 2 rule 0 + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping6 -c 3 2001:db8:1::3 +expect s1 packet loss +run VPP show trace +expect VPP match: inacl 0 rule 1 + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping6 -c 3 2001:db8:1::4 +expect s1 packet loss +run VPP show trace +expect VPP match: outacl 2 rule 1 + +run lua print("ALL GOOD!") + diff --git a/src/vpp-api/lua/examples/lute/script-inout-acl-old.lute b/src/vpp-api/lua/examples/lute/script-inout-acl-old.lute new file mode 100644 index 00000000..9edebf02 --- /dev/null +++ b/src/vpp-api/lua/examples/lute/script-inout-acl-old.lute @@ -0,0 +1,329 @@ +shell vppbuild +run vppbuild stty -echo +run vppbuild sudo -u ubuntu -i bash -c "(cd vpp && make plugins && echo ALLGOOD)" +expect vppbuild ALLGOOD + +shell s0 +shell s1 +shell s2 + + +cd s1 +unshare -n /bin/bash +/sbin/ifconfig -a +^D^D^D + +cd s2 +unshare -n /bin/bash +/sbin/ifconfig -a +^D^D^D + + +cd lua + +function session_get_bash_pid(s) + if not has_session(s) then + return nil + end + local fname = "/tmp/lute-"..s.."-pid.txt" + + session_exec(s, "echo $$ >" .. fname) + -- it's a dirty hack but it's quick + sleep(0.5) + local pid = io.lines(fname)() + print("Got pid for " .. s .. " : " .. tostring(pid)) + return(tonumber(pid)) +end + +function session_connect_with(s0, s1) + -- local pid0 = tostring(session_get_bash_pid(s0)) + local pid1 = tostring(session_get_bash_pid(s1)) + local eth_options = { "rx", "tx", "sg", "tso", "ufo", "gso", "gro", "lro", "rxvlan", "txvlan", "rxhash" } + local this_end = s0 .. "_" .. s1 + local other_end = s1 .. "_" .. s0 + session_exec(s0, "ip link add name " .. this_end .. " type veth peer name " .. other_end) + session_exec(s0, "ip link set dev " .. this_end .. " up promisc on") + for i, option in ipairs(eth_options) do + session_exec(s0, "/sbin/ethtool --offload " .. this_end .. " " .. option .. " off") + session_exec(s0, "/sbin/ethtool --offload " .. other_end .. " " .. option .. " off") + end + session_exec(s0, "ip link set dev " .. other_end .. " up promisc on netns /proc/" .. pid1 .. "/ns/net") + sleep(0.5) +end + +^D^D^D +run lua session_connect_with("s0", "s1") +run lua session_connect_with("s0", "s2") + +cd s1 +ip -6 addr add dev s1_s0 2001:db8:1::1/64 +ip -4 addr add dev s1_s0 192.0.2.1/24 +ip link set dev s1_s0 up promisc on +^D^D^D + +cd s2 +ip -6 addr add dev s2_s0 2001:db8:1::2/64 +ip -6 addr add dev s2_s0 2001:db8:1::3/64 +ip -6 addr add dev s2_s0 2001:db8:1::4/64 +ip -4 addr add dev s2_s0 192.0.2.2/24 +ip -4 addr add dev s2_s0:1 192.0.2.3/24 +ip -4 addr add dev s2_s0:2 192.0.2.4/24 +ip link set dev s2_s0 up promisc on +^D^D^D + +run s1 ip addr +run s2 ip addr +shell VPP +cd VPP +cd /home/ubuntu/vpp +make debug +r +^D^D^D +expect VPP DBGvpp# + +cd lua +-- Initialization of the Lua environment for talking to VPP +vpp = require("vpp-lapi") +root_dir = "/home/ubuntu/vpp" +pneum_path = root_dir .. "/build-root/install-vpp_debug-native/vpp-api/lib64/libpneum.so" +vpp:init({ pneum_path = pneum_path }) +vpp:consume_api(root_dir .. "/build-root/install-vpp_debug-native/vlib-api/vlibmemory/memclnt.api") +vpp:consume_api(root_dir .. "/build-root/install-vpp_debug-native/vpp/vpp-api/vpe.api") +vpp:connect("aytest") +vpp:consume_api(root_dir .. "/plugins/acl-plugin/acl/acl.api", "acl") + +^D^D^D + +cd lua + +reply = vpp:api_call("af_packet_create", { host_if_name = "s0_s1", hw_addr = "AAAAAA" }) +vpp_if_to_s1 = reply[1].sw_if_index + +reply = vpp:api_call("af_packet_create", { host_if_name = "s0_s2", hw_addr = "AAAAAA" }) +vpp_if_to_s2 = reply[1].sw_if_index + +ifaces = { vpp_if_to_s1, vpp_if_to_s2 } + +reply = vpp:api_call("sw_interface_set_flags", { sw_if_index = vpp_if_to_s1, admin_up_down = 1, link_up_down = 1 }) +print(vpp.dump(reply)) +reply = vpp:api_call("sw_interface_set_flags", { sw_if_index = vpp_if_to_s2, admin_up_down = 1, link_up_down = 1 }) +print(vpp.dump(reply)) + +bd_id = 42 + +reply = vpp:api_call("bridge_domain_add_del", { bd_id = bd_id, flood = 1, uu_flood = 1, forward = 1, learn = 1, arp_term = 0, is_add = 1 }) +print(vpp.dump(reply)) + +for i, v in ipairs(ifaces) do + reply = vpp:api_call("sw_interface_set_l2_bridge", { rx_sw_if_index = v, bd_id = bd_id, shg = 0, bvi = 0, enable = 1 } ) + print(vpp.dump(reply)) +end + +^D^D^D + +run s1 ping -c 3 192.0.2.2 +expect s1 packet loss +run s1 ping -c 3 192.0.2.3 +expect s1 packet loss +run s1 ping -c 3 192.0.2.4 +expect s1 packet loss +run s1 ping6 -c 3 2001:db8:1::2 +expect s1 packet loss +run s1 ping6 -c 3 2001:db8:1::3 +expect s1 packet loss +run s1 ping6 -c 3 2001:db8:1::4 +expect s1 packet loss + + +cd lua +--- ACL testing + +--[[ temporary comment out + +reply = vpp:api_call("acl_del", { context = 42, acl_index = 230 }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_del", { context = 42, acl_index = 8 }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_del", { context = 42, acl_index = 15 }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_add", { context = 42, count = 2, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 } } }) +print(vpp.dump(reply)) +print("---") +interface_acl_in = reply[1].acl_index + +reply = vpp:api_call("acl_add", { context = 42, count = 3, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 }, { is_permit = 1, is_ipv6 = 0 } } }) +print(vpp.dump(reply)) +print("---") +interface_acl_out = reply[1].acl_index + + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 1, acl_index = interface_acl_in }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 1, acl_index = interface_acl_in }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 0, acl_index = interface_acl_out }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 0, acl_index = interface_acl_out }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_add", { context = 42, count = 0 }) +print(vpp.dump(reply)) +print("---") + +acl_index_to_delete = reply[1].acl_index +print("Deleting " .. tostring(acl_index_to_delete)) +reply = vpp:api_call("acl_del", { context = 42, acl_index = acl_index_to_delete }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 0}) +for ri, rv in ipairs(reply) do + print("Reply message #" .. tostring(ri)) + print(vpp.dump(rv)) + for ai, av in ipairs(rv.r) do + print("ACL rule #" .. tostring(ai) .. " : " .. vpp.dump(av)) + end + +end +print("---") + +reply = vpp:api_call("acl_del", { context = 42, acl_index = interface_acl_out }) +print(vpp.dump(reply)) +print("---") +reply = vpp:api_call("acl_del", { context = 42, acl_index = interface_acl_in }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 0}) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 4294967295 }) +print(vpp.dump(reply)) +print("---") + + +]] -- end of comment out + +---- Should be nothing ^^ +r = { + { is_permit = 1, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8:1::2"), dst_ip_prefix_len = 128 }, + { is_permit = 0, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8:1::3"), dst_ip_prefix_len = 128 }, + { is_permit = 1, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8::"), dst_ip_prefix_len = 32 }, + { is_permit = 1, is_ipv6 = 0, dst_ip_addr = ip46("192.0.2.2"), dst_ip_prefix_len = 32}, + { is_permit = 0, is_ipv6 = 0, dst_ip_addr = ip46("192.0.2.3"), dst_ip_prefix_len = 32 }, +} + +reply = vpp:api_call("acl_add", { context = 42, count = 5, r = r }) +print(vpp.dump(reply)) +print("---") +interface_acl_in = reply[1].acl_index + +reply = vpp:api_call("acl_add", { context = 42, count = 3, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 }, { is_permit = 1, is_ipv6 = 0 } } }) +print(vpp.dump(reply)) +print("---") +interface_acl_out = reply[1].acl_in + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s1, is_add = 1, is_input = 1, acl_index = interface_acl_in }) +print(vpp.dump(reply)) +print("---") + +--reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s2, is_add = 1, is_input = 0, acl_index = interface_acl_out }) +-- print(vpp.dump(reply)) +--print("---") + +^D^D^D + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping6 -c 3 2001:db8:1::2 +expect s1 packet loss +run VPP show trace +expect VPP match: inacl 0 rule 0 + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping6 -c 3 2001:db8:1::3 +expect s1 packet loss +run VPP show trace +expect VPP match: inacl 0 rule 1 + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping6 -c 3 2001:db8:1::4 +expect s1 packet loss +run VPP show trace +expect VPP match: inacl 0 rule 2 + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping -c 3 192.0.2.2 +expect s1 packet loss +run VPP show trace +expect VPP match: inacl 0 rule 3 + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping -c 3 192.0.2.3 +expect s1 packet loss +run VPP show trace +expect VPP match: inacl 0 rule 4 + + +cd lua + +--- TEST OUTBOUND ACL + +r1 = { + { is_permit = 1, is_ipv6 = 1, src_ip_addr = ip46("2001:db8:1::1"), src_ip_prefix_len = 128, dst_ip_addr = ip46("2001:db8:1::2"), dst_ip_prefix_len = 128 }, + { is_permit = 0, is_ipv6 = 1, src_ip_addr = ip46("2001:db8:1::1"), src_ip_prefix_len = 128, dst_ip_addr = ip46("2001:db8:1::4"), dst_ip_prefix_len = 128 } +} + +reply = vpp:api_call("acl_add", { context = 42, count = 3, r = r1 }) +print(vpp.dump(reply)) +print("---") +interface_acl_out = reply[1].acl_index + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s2, is_add = 1, is_input = 0, acl_index = interface_acl_out }) +print(vpp.dump(reply)) +print("---") + + +^D^D^D + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping6 -c 3 2001:db8:1::2 +expect s1 packet loss +run VPP show trace +expect VPP match: outacl 2 rule 0 + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping6 -c 3 2001:db8:1::3 +expect s1 packet loss +run VPP show trace +expect VPP match: inacl 0 rule 1 + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping6 -c 3 2001:db8:1::4 +expect s1 packet loss +run VPP show trace +expect VPP match: outacl 2 rule 1 + +run lua print("ALL GOOD!") + diff --git a/src/vpp-api/lua/examples/lute/script-inout-acl.lute b/src/vpp-api/lua/examples/lute/script-inout-acl.lute new file mode 100644 index 00000000..d7e7423c --- /dev/null +++ b/src/vpp-api/lua/examples/lute/script-inout-acl.lute @@ -0,0 +1,329 @@ +shell vppbuild +run vppbuild stty -echo +run vppbuild sudo -u ubuntu -i bash -c "(cd vpp && make plugins && echo ALLGOOD)" +expect vppbuild ALLGOOD + +shell s0 +shell s1 +shell s2 + + +cd s1 +unshare -n /bin/bash +/sbin/ifconfig -a +^D^D^D + +cd s2 +unshare -n /bin/bash +/sbin/ifconfig -a +^D^D^D + + +cd lua + +function session_get_bash_pid(s) + if not has_session(s) then + return nil + end + local fname = "/tmp/lute-"..s.."-pid.txt" + + session_exec(s, "echo $$ >" .. fname) + -- it's a dirty hack but it's quick + sleep(0.5) + local pid = io.lines(fname)() + print("Got pid for " .. s .. " : " .. tostring(pid)) + return(tonumber(pid)) +end + +function session_connect_with(s0, s1) + -- local pid0 = tostring(session_get_bash_pid(s0)) + local pid1 = tostring(session_get_bash_pid(s1)) + local eth_options = { "rx", "tx", "sg", "tso", "ufo", "gso", "gro", "lro", "rxvlan", "txvlan", "rxhash" } + local this_end = s0 .. "_" .. s1 + local other_end = s1 .. "_" .. s0 + session_exec(s0, "ip link add name " .. this_end .. " type veth peer name " .. other_end) + session_exec(s0, "ip link set dev " .. this_end .. " up promisc on") + for i, option in ipairs(eth_options) do + session_exec(s0, "/sbin/ethtool --offload " .. this_end .. " " .. option .. " off") + session_exec(s0, "/sbin/ethtool --offload " .. other_end .. " " .. option .. " off") + end + session_exec(s0, "ip link set dev " .. other_end .. " up promisc on netns /proc/" .. pid1 .. "/ns/net") + sleep(0.5) +end + +^D^D^D +run lua session_connect_with("s0", "s1") +run lua session_connect_with("s0", "s2") + +cd s1 +ip -6 addr add dev s1_s0 2001:db8:1::1/64 +ip -4 addr add dev s1_s0 192.0.2.1/24 +ip link set dev s1_s0 up promisc on +^D^D^D + +cd s2 +ip -6 addr add dev s2_s0 2001:db8:1::2/64 +ip -6 addr add dev s2_s0 2001:db8:1::3/64 +ip -6 addr add dev s2_s0 2001:db8:1::4/64 +ip -4 addr add dev s2_s0 192.0.2.2/24 +ip -4 addr add dev s2_s0:1 192.0.2.3/24 +ip -4 addr add dev s2_s0:2 192.0.2.4/24 +ip link set dev s2_s0 up promisc on +^D^D^D + +run s1 ip addr +run s2 ip addr +shell VPP +cd VPP +cd /home/ubuntu/vpp +make debug +r +^D^D^D +expect VPP DBGvpp# + +cd lua +-- Initialization of the Lua environment for talking to VPP +vpp = require("vpp-lapi") +root_dir = "/home/ubuntu/vpp" +pneum_path = root_dir .. "/build-root/install-vpp_debug-native/vpp-api/lib64/libpneum.so" +vpp:init({ pneum_path = pneum_path }) +vpp:consume_api(root_dir .. "/build-root/install-vpp_debug-native/vlib-api/vlibmemory/memclnt.api") +vpp:consume_api(root_dir .. "/build-root/install-vpp_debug-native/vpp/vpp-api/vpe.api") +vpp:connect("aytest") +vpp:consume_api(root_dir .. "/plugins/acl-plugin/acl/acl.api", "acl") + +^D^D^D + +cd lua + +reply = vpp:api_call("af_packet_create", { host_if_name = "s0_s1", hw_addr = "AAAAAA" }) +vpp_if_to_s1 = reply[1].sw_if_index + +reply = vpp:api_call("af_packet_create", { host_if_name = "s0_s2", hw_addr = "AAAAAA" }) +vpp_if_to_s2 = reply[1].sw_if_index + +ifaces = { vpp_if_to_s1, vpp_if_to_s2 } + +reply = vpp:api_call("sw_interface_set_flags", { sw_if_index = vpp_if_to_s1, admin_up_down = 1, link_up_down = 1 }) +print(vpp.dump(reply)) +reply = vpp:api_call("sw_interface_set_flags", { sw_if_index = vpp_if_to_s2, admin_up_down = 1, link_up_down = 1 }) +print(vpp.dump(reply)) + +bd_id = 42 + +reply = vpp:api_call("bridge_domain_add_del", { bd_id = bd_id, flood = 1, uu_flood = 1, forward = 1, learn = 1, arp_term = 0, is_add = 1 }) +print(vpp.dump(reply)) + +for i, v in ipairs(ifaces) do + reply = vpp:api_call("sw_interface_set_l2_bridge", { rx_sw_if_index = v, bd_id = bd_id, shg = 0, bvi = 0, enable = 1 } ) + print(vpp.dump(reply)) +end + +^D^D^D + +run s1 ping -c 3 192.0.2.2 +expect s1 packet loss +run s1 ping -c 3 192.0.2.3 +expect s1 packet loss +run s1 ping -c 3 192.0.2.4 +expect s1 packet loss +run s1 ping6 -c 3 2001:db8:1::2 +expect s1 packet loss +run s1 ping6 -c 3 2001:db8:1::3 +expect s1 packet loss +run s1 ping6 -c 3 2001:db8:1::4 +expect s1 packet loss + + +cd lua +--- ACL testing + +--[[ temporary comment out + +reply = vpp:api_call("acl_del", { context = 42, acl_index = 230 }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_del", { context = 42, acl_index = 8 }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_del", { context = 42, acl_index = 15 }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_add_replace", { context = 42, acl_index = -1, count = 2, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 } } }) +print(vpp.dump(reply)) +print("---") +interface_acl_in = reply[1].acl_index + +reply = vpp:api_call("acl_add_replace", { context = 42, acl_index = -1, count = 3, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 }, { is_permit = 1, is_ipv6 = 0 } } }) +print(vpp.dump(reply)) +print("---") +interface_acl_out = reply[1].acl_index + + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 1, acl_index = interface_acl_in }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 1, acl_index = interface_acl_in }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 0, acl_index = interface_acl_out }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 0, acl_index = interface_acl_out }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_add_replace", { context = 42, acl_index = -1, count = 0 }) +print(vpp.dump(reply)) +print("---") + +acl_index_to_delete = reply[1].acl_index +print("Deleting " .. tostring(acl_index_to_delete)) +reply = vpp:api_call("acl_del", { context = 42, acl_index = acl_index_to_delete }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 0}) +for ri, rv in ipairs(reply) do + print("Reply message #" .. tostring(ri)) + print(vpp.dump(rv)) + for ai, av in ipairs(rv.r) do + print("ACL rule #" .. tostring(ai) .. " : " .. vpp.dump(av)) + end + +end +print("---") + +reply = vpp:api_call("acl_del", { context = 42, acl_index = interface_acl_out }) +print(vpp.dump(reply)) +print("---") +reply = vpp:api_call("acl_del", { context = 42, acl_index = interface_acl_in }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 0}) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 4294967295 }) +print(vpp.dump(reply)) +print("---") + + +]] -- end of comment out + +---- Should be nothing ^^ +r = { + { is_permit = 1, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8:1::2"), dst_ip_prefix_len = 128 }, + { is_permit = 0, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8:1::3"), dst_ip_prefix_len = 128 }, + { is_permit = 1, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8::"), dst_ip_prefix_len = 32 }, + { is_permit = 1, is_ipv6 = 0, dst_ip_addr = ip46("192.0.2.2"), dst_ip_prefix_len = 32}, + { is_permit = 0, is_ipv6 = 0, dst_ip_addr = ip46("192.0.2.3"), dst_ip_prefix_len = 32 }, +} + +reply = vpp:api_call("acl_add_replace", { context = 42, acl_index = -1, count = 5, r = r }) +print(vpp.dump(reply)) +print("---") +interface_acl_in = reply[1].acl_index + +reply = vpp:api_call("acl_add_replace", { context = 42, acl_index = -1, count = 3, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 }, { is_permit = 1, is_ipv6 = 0 } } }) +print(vpp.dump(reply)) +print("---") +interface_acl_out = reply[1].acl_in + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s1, is_add = 1, is_input = 1, acl_index = interface_acl_in }) +print(vpp.dump(reply)) +print("---") + +--reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s2, is_add = 1, is_input = 0, acl_index = interface_acl_out }) +-- print(vpp.dump(reply)) +--print("---") + +^D^D^D + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping6 -c 3 2001:db8:1::2 +expect s1 packet loss +run VPP show trace +expect VPP match: inacl 0 rule 0 + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping6 -c 3 2001:db8:1::3 +expect s1 packet loss +run VPP show trace +expect VPP match: inacl 0 rule 1 + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping6 -c 3 2001:db8:1::4 +expect s1 packet loss +run VPP show trace +expect VPP match: inacl 0 rule 2 + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping -c 3 192.0.2.2 +expect s1 packet loss +run VPP show trace +expect VPP match: inacl 0 rule 3 + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping -c 3 192.0.2.3 +expect s1 packet loss +run VPP show trace +expect VPP match: inacl 0 rule 4 + + +cd lua + +--- TEST OUTBOUND ACL + +r1 = { + { is_permit = 1, is_ipv6 = 1, src_ip_addr = ip46("2001:db8:1::1"), src_ip_prefix_len = 128, dst_ip_addr = ip46("2001:db8:1::2"), dst_ip_prefix_len = 128 }, + { is_permit = 0, is_ipv6 = 1, src_ip_addr = ip46("2001:db8:1::1"), src_ip_prefix_len = 128, dst_ip_addr = ip46("2001:db8:1::4"), dst_ip_prefix_len = 128 } +} + +reply = vpp:api_call("acl_add_replace", { context = 42, acl_index = -1, count = 3, r = r1 }) +print(vpp.dump(reply)) +print("---") +interface_acl_out = reply[1].acl_index + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s2, is_add = 1, is_input = 0, acl_index = interface_acl_out }) +print(vpp.dump(reply)) +print("---") + + +^D^D^D + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping6 -c 3 2001:db8:1::2 +expect s1 packet loss +run VPP show trace +expect VPP match: outacl 2 rule 0 + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping6 -c 3 2001:db8:1::3 +expect s1 packet loss +run VPP show trace +expect VPP match: inacl 0 rule 1 + +run VPP clear trace +run VPP trace add af-packet-input 100 +run s1 ping6 -c 3 2001:db8:1::4 +expect s1 packet loss +run VPP show trace +expect VPP match: outacl 2 rule 1 + +run lua print("ALL GOOD!") + diff --git a/src/vpp-api/lua/examples/lute/script.lute b/src/vpp-api/lua/examples/lute/script.lute new file mode 100644 index 00000000..c3dd90f2 --- /dev/null +++ b/src/vpp-api/lua/examples/lute/script.lute @@ -0,0 +1,7 @@ +shell s1 +expect s1 $ +run s1 echo testing123 +expect s1 $ +run s1 echo done +quit + diff --git a/src/vpp-api/lua/examples/lute/sessions-acl.lute b/src/vpp-api/lua/examples/lute/sessions-acl.lute new file mode 100644 index 00000000..ac237ef9 --- /dev/null +++ b/src/vpp-api/lua/examples/lute/sessions-acl.lute @@ -0,0 +1,308 @@ +run lua -- collectgarbage("stop") + +shell vppbuild +run vppbuild stty -echo +run vppbuild sudo -u ubuntu -i bash -c "(cd vpp && make plugins && echo ALLGOOD)" +expect vppbuild ALLGOOD + +shell s0 +shell s1 +shell s2 + + +cd s1 +unshare -n /bin/bash +/sbin/ifconfig -a +^D^D^D + +cd s2 +unshare -n /bin/bash +/sbin/ifconfig -a +^D^D^D + + +cd lua + +function session_get_bash_pid(s) + if not has_session(s) then + return nil + end + local fname = "/tmp/lute-"..s.."-pid.txt" + + session_exec(s, "echo $$ >" .. fname) + -- it's a dirty hack but it's quick + sleep(0.5) + local pid = io.lines(fname)() + print("Got pid for " .. s .. " : " .. tostring(pid)) + return(tonumber(pid)) +end + +function session_connect_with(s0, s1) + -- local pid0 = tostring(session_get_bash_pid(s0)) + local pid1 = tostring(session_get_bash_pid(s1)) + local eth_options = { "rx", "tx", "sg", "tso", "ufo", "gso", "gro", "lro", "rxvlan", "txvlan", "rxhash" } + local this_end = s0 .. "_" .. s1 + local other_end = s1 .. "_" .. s0 + session_exec(s0, "ip link add name " .. this_end .. " type veth peer name " .. other_end) + session_exec(s0, "ip link set dev " .. this_end .. " up promisc on") + for i, option in ipairs(eth_options) do + session_exec(s0, "/sbin/ethtool --offload " .. this_end .. " " .. option .. " off") + session_exec(s0, "/sbin/ethtool --offload " .. other_end .. " " .. option .. " off") + end + session_exec(s0, "ip link set dev " .. other_end .. " up promisc on netns /proc/" .. pid1 .. "/ns/net") + sleep(0.5) +end + +^D^D^D +run lua session_connect_with("s0", "s1") +run lua session_connect_with("s0", "s2") + +cd s1 +ip -6 addr add dev s1_s0 2001:db8:1::1/64 +ip -4 addr add dev s1_s0 192.0.2.1/24 +ip link set dev s1_s0 up promisc on +^D^D^D + +cd s2 +ip -6 addr add dev s2_s0 2001:db8:1::2/64 +ip -6 addr add dev s2_s0 2001:db8:1::3/64 +ip -6 addr add dev s2_s0 2001:db8:1::4/64 +ip -4 addr add dev s2_s0 192.0.2.2/24 +ip -4 addr add dev s2_s0:1 192.0.2.3/24 +ip -4 addr add dev s2_s0:2 192.0.2.4/24 +ip link set dev s2_s0 up promisc on +^D^D^D + +run s1 ip addr +run s2 ip addr +shell VPP +cd VPP +cd /home/ubuntu/vpp +make debug +r +^D^D^D +expect VPP DBGvpp# + +cd lua +-- Initialization of the Lua environment for talking to VPP +vpp = require("vpp-lapi") +root_dir = "/home/ubuntu/vpp" +pneum_path = root_dir .. "/build-root/install-vpp_debug-native/vpp-api/lib64/libpneum.so" +vpp:init({ pneum_path = pneum_path }) +vpp:consume_api(root_dir .. "/build-root/install-vpp_debug-native/vlib-api/vlibmemory/memclnt.api") +vpp:consume_api(root_dir .. "/build-root/install-vpp_debug-native/vpp/vpp-api/vpe.api") +vpp:connect("aytest") +vpp:consume_api(root_dir .. "/plugins/acl-plugin/acl/acl.api", "acl") + +^D^D^D + +cd lua + +reply = vpp:api_call("af_packet_create", { host_if_name = "s0_s1", hw_addr = "AAAAAA" }) +vpp_if_to_s1 = reply[1].sw_if_index + +reply = vpp:api_call("af_packet_create", { host_if_name = "s0_s2", hw_addr = "AAAAAA" }) +vpp_if_to_s2 = reply[1].sw_if_index + +ifaces = { vpp_if_to_s1, vpp_if_to_s2 } + +reply = vpp:api_call("sw_interface_set_flags", { sw_if_index = vpp_if_to_s1, admin_up_down = 1, link_up_down = 1 }) +print(vpp.dump(reply)) +reply = vpp:api_call("sw_interface_set_flags", { sw_if_index = vpp_if_to_s2, admin_up_down = 1, link_up_down = 1 }) +print(vpp.dump(reply)) + +bd_id = 42 + +reply = vpp:api_call("bridge_domain_add_del", { bd_id = bd_id, flood = 1, uu_flood = 1, forward = 1, learn = 1, arp_term = 0, is_add = 1 }) +print(vpp.dump(reply)) + +for i, v in ipairs(ifaces) do + reply = vpp:api_call("sw_interface_set_l2_bridge", { rx_sw_if_index = v, bd_id = bd_id, shg = 0, bvi = 0, enable = 1 } ) + print(vpp.dump(reply)) +end + +^D^D^D + +run s1 ping -c 3 192.0.2.2 +expect s1 packet loss +run s1 ping -c 3 192.0.2.3 +expect s1 packet loss +run s1 ping -c 3 192.0.2.4 +expect s1 packet loss +run s1 ping6 -c 3 2001:db8:1::2 +expect s1 packet loss +run s1 ping6 -c 3 2001:db8:1::3 +expect s1 packet loss +run s1 ping6 -c 3 2001:db8:1::4 +expect s1 packet loss + + +cd lua +--- ACL testing + +--[[ temporary comment out + +reply = vpp:api_call("acl_del", { context = 42, acl_index = 230 }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_del", { context = 42, acl_index = 8 }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_del", { context = 42, acl_index = 15 }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_add", { context = 42, count = 2, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 } } }) +print(vpp.dump(reply)) +print("---") +interface_acl_in = reply[1].acl_index + +reply = vpp:api_call("acl_add", { context = 42, count = 3, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 }, { is_permit = 1, is_ipv6 = 0 } } }) +print(vpp.dump(reply)) +print("---") +interface_acl_out = reply[1].acl_index + + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 1, acl_index = interface_acl_in }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 1, acl_index = interface_acl_in }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 0, acl_index = interface_acl_out }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 0, acl_index = interface_acl_out }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_add", { context = 42, count = 0 }) +print(vpp.dump(reply)) +print("---") + +acl_index_to_delete = reply[1].acl_index +print("Deleting " .. tostring(acl_index_to_delete)) +reply = vpp:api_call("acl_del", { context = 42, acl_index = acl_index_to_delete }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 0}) +for ri, rv in ipairs(reply) do + print("Reply message #" .. tostring(ri)) + print(vpp.dump(rv)) + for ai, av in ipairs(rv.r) do + print("ACL rule #" .. tostring(ai) .. " : " .. vpp.dump(av)) + end + +end +print("---") + +reply = vpp:api_call("acl_del", { context = 42, acl_index = interface_acl_out }) +print(vpp.dump(reply)) +print("---") +reply = vpp:api_call("acl_del", { context = 42, acl_index = interface_acl_in }) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 0}) +print(vpp.dump(reply)) +print("---") + +reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 4294967295 }) +print(vpp.dump(reply)) +print("---") + + +]] -- end of comment out + +---- Should be nothing ^^ +r = { + { is_permit = 1, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8:1::2"), dst_ip_prefix_len = 128 }, + { is_permit = 0, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8:1::3"), dst_ip_prefix_len = 128 }, + { is_permit = 1, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8::"), dst_ip_prefix_len = 32 }, + { is_permit = 1, is_ipv6 = 0, dst_ip_addr = ip46("192.0.2.2"), dst_ip_prefix_len = 32}, + { is_permit = 0, is_ipv6 = 0, dst_ip_addr = ip46("192.0.2.3"), dst_ip_prefix_len = 32 }, +} + +reply = vpp:api_call("acl_add", { context = 42, count = 5, r = r }) +print(vpp.dump(reply)) +print("---") +interface_acl_in = reply[1].acl_index + +reply = vpp:api_call("acl_add", { context = 42, count = 3, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 }, { is_permit = 1, is_ipv6 = 0 } } }) +print(vpp.dump(reply)) +print("---") +interface_acl_out = reply[1].acl_in + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s1, is_add = 1, is_input = 1, acl_index = interface_acl_in }) +print(vpp.dump(reply)) +print("---") + +--- TEST OUTBOUND ACL + +r1 = { + { is_permit = 1, is_ipv6 = 1, src_ip_addr = ip46("2001:db8:1::1"), src_ip_prefix_len = 128, dst_ip_addr = ip46("2001:db8:1::2"), dst_ip_prefix_len = 128 }, + { is_permit = 0, is_ipv6 = 1, src_ip_addr = ip46("2001:db8:1::1"), src_ip_prefix_len = 128, dst_ip_addr = ip46("2001:db8:1::4"), dst_ip_prefix_len = 128 }, + { is_permit = 2, is_ipv6 = 0 } +} + +reply = vpp:api_call("acl_add", { context = 42, count = 3, r = r1 }) +print(vpp.dump(reply)) +print("---") +interface_acl_out = reply[1].acl_index + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s2, is_add = 1, is_input = 0, acl_index = interface_acl_out }) +print(vpp.dump(reply)) +print("---") + +r2 = { + { is_permit = 1, is_ipv6 = 1 }, + { is_permit = 0, is_ipv6 = 0 } +} + +reply = vpp:api_call("acl_add", { context = 42, count = 2, r = r2 }) +print(vpp.dump(reply)) +print("---") +second_interface_acl_in = reply[1].acl_index + +reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s2, is_add = 1, is_input = 1, acl_index = second_interface_acl_in }) +print(vpp.dump(reply)) +print("---") + +^D^D^D + +run VPP show classify tables +run VPP clear trace +run VPP trace add af-packet-input 100 +run s2 nc -v -l -p 22 +run s1 nc 192.0.2.2 22 +run s1 echo +sleep 1 +run s1 break +sleep 1 +run VPP show trace +expect VPP match: outacl 2 rule 2 +run VPP show classify tables + + +run VPP show classify tables +run VPP clear trace +run VPP trace add af-packet-input 100 +run s2 nc -v -l -p 22 +run s1 nc 192.0.2.2 22 +run s1 echo +sleep 1 +run s1 break +sleep 1 +run VPP show trace +expect VPP match: outacl 2 rule 2 +run VPP show classify tables + + +run lua print("ALL GOOD!") + diff --git a/src/vpp-api/lua/vpp-lapi.lua b/src/vpp-api/lua/vpp-lapi.lua new file mode 100644 index 00000000..ebfd032b --- /dev/null +++ b/src/vpp-api/lua/vpp-lapi.lua @@ -0,0 +1,989 @@ +--[[ +/* + * 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. + */ +]] + +-- json decode/encode from https://gist.github.com/tylerneylon/59f4bcf316be525b30ab +-- licensed by the author tylerneylon into public domain. Thanks! + +local json = {} + +-- Internal functions. + +local function kind_of(obj) + if type(obj) ~= 'table' then return type(obj) end + local i = 1 + for _ in pairs(obj) do + if obj[i] ~= nil then i = i + 1 else return 'table' end + end + if i == 1 then return 'table' else return 'array' end +end + +local function escape_str(s) + local in_char = {'\\', '"', '/', '\b', '\f', '\n', '\r', '\t'} + local out_char = {'\\', '"', '/', 'b', 'f', 'n', 'r', 't'} + for i, c in ipairs(in_char) do + s = s:gsub(c, '\\' .. out_char[i]) + end + return s +end + +-- Returns pos, did_find; there are two cases: +-- 1. Delimiter found: pos = pos after leading space + delim; did_find = true. +-- 2. Delimiter not found: pos = pos after leading space; did_find = false. +-- This throws an error if err_if_missing is true and the delim is not found. +local function skip_delim(str, pos, delim, err_if_missing) + pos = pos + #str:match('^%s*', pos) + if str:sub(pos, pos) ~= delim then + if err_if_missing then + error('Expected ' .. delim .. ' near position ' .. pos) + end + return pos, false + end + return pos + 1, true +end + +-- Expects the given pos to be the first character after the opening quote. +-- Returns val, pos; the returned pos is after the closing quote character. +local function parse_str_val(str, pos, val) + val = val or '' + local early_end_error = 'End of input found while parsing string.' + if pos > #str then error(early_end_error) end + local c = str:sub(pos, pos) + if c == '"' then return val, pos + 1 end + if c ~= '\\' then return parse_str_val(str, pos + 1, val .. c) end + -- We must have a \ character. + local esc_map = {b = '\b', f = '\f', n = '\n', r = '\r', t = '\t'} + local nextc = str:sub(pos + 1, pos + 1) + if not nextc then error(early_end_error) end + return parse_str_val(str, pos + 2, val .. (esc_map[nextc] or nextc)) +end + +-- Returns val, pos; the returned pos is after the number's final character. +local function parse_num_val(str, pos) + local num_str = str:match('^-?%d+%.?%d*[eE]?[+-]?%d*', pos) + local val = tonumber(num_str) + if not val then error('Error parsing number at position ' .. pos .. '.') end + return val, pos + #num_str +end + + +-- Public values and functions. + +function json.stringify(obj, as_key) + local s = {} -- We'll build the string as an array of strings to be concatenated. + local kind = kind_of(obj) -- This is 'array' if it's an array or type(obj) otherwise. + if kind == 'array' then + if as_key then error('Can\'t encode array as key.') end + s[#s + 1] = '[' + for i, val in ipairs(obj) do + if i > 1 then s[#s + 1] = ', ' end + s[#s + 1] = json.stringify(val) + end + s[#s + 1] = ']' + elseif kind == 'table' then + if as_key then error('Can\'t encode table as key.') end + s[#s + 1] = '{' + for k, v in pairs(obj) do + if #s > 1 then s[#s + 1] = ', ' end + s[#s + 1] = json.stringify(k, true) + s[#s + 1] = ':' + s[#s + 1] = json.stringify(v) + end + s[#s + 1] = '}' + elseif kind == 'string' then + return '"' .. escape_str(obj) .. '"' + elseif kind == 'number' then + if as_key then return '"' .. tostring(obj) .. '"' end + return tostring(obj) + elseif kind == 'boolean' then + return tostring(obj) + elseif kind == 'nil' then + return 'null' + else + error('Unjsonifiable type: ' .. kind .. '.') + end + return table.concat(s) +end + +json.null = {} -- This is a one-off table to represent the null value. + +function json.parse(str, pos, end_delim) + pos = pos or 1 + if pos > #str then error('Reached unexpected end of input.') end + local pos = pos + #str:match('^%s*', pos) -- Skip whitespace. + local first = str:sub(pos, pos) + if first == '{' then -- Parse an object. + local obj, key, delim_found = {}, true, true + pos = pos + 1 + while true do + key, pos = json.parse(str, pos, '}') + if key == nil then return obj, pos end + if not delim_found then error('Comma missing between object items.') end + pos = skip_delim(str, pos, ':', true) -- true -> error if missing. + obj[key], pos = json.parse(str, pos) + pos, delim_found = skip_delim(str, pos, ',') + end + elseif first == '[' then -- Parse an array. + local arr, val, delim_found = {}, true, true + pos = pos + 1 + while true do + val, pos = json.parse(str, pos, ']') + if val == nil then return arr, pos end + if not delim_found then error('Comma missing between array items.') end + arr[#arr + 1] = val + pos, delim_found = skip_delim(str, pos, ',') + end + elseif first == '"' then -- Parse a string. + return parse_str_val(str, pos + 1) + elseif first == '-' or first:match('%d') then -- Parse a number. + return parse_num_val(str, pos) + elseif first == end_delim then -- End of an object or array. + return nil, pos + 1 + else -- Parse true, false, or null. + local literals = {['true'] = true, ['false'] = false, ['null'] = json.null} + for lit_str, lit_val in pairs(literals) do + local lit_end = pos + #lit_str - 1 + if str:sub(pos, lit_end) == lit_str then return lit_val, lit_end + 1 end + end + local pos_info_str = 'position ' .. pos .. ': ' .. str:sub(pos, pos + 10) + error('Invalid json syntax starting at ' .. pos_info_str) + end +end + + +local vpp = {} + +local ffi = require("ffi") + +--[[ + +The basic type definitions. A bit of weird gymnastic with +unionization of the hton* and ntoh* functions results +is to make handling of signed and unsigned types a bit cleaner, +essentially building typecasting into a C union. + +The vl_api_opaque_message_t is a synthetic type assumed to have +enough storage to hold the entire API message regardless of the type. +During the operation it is casted to the specific message struct types. + +]] + + +ffi.cdef([[ + +typedef uint8_t u8; +typedef int8_t i8; +typedef uint16_t u16; +typedef int16_t i16; +typedef uint32_t u32; +typedef int32_t i32; +typedef uint64_t u64; +typedef int64_t i64; +typedef double f64; +typedef float f32; + +#pragma pack(1) +typedef union { + u16 u16; + i16 i16; +} lua_ui16t; + +#pragma pack(1) +typedef union { + u32 u32; + i32 i32; +} lua_ui32t; + +u16 ntohs(uint16_t hostshort); +u16 htons(uint16_t hostshort); +u32 htonl(uint32_t along); +u32 ntohl(uint32_t along); +void *memset(void *s, int c, size_t n); +void *memcpy(void *dest, void *src, size_t n); + +#pragma pack(1) +typedef struct _vl_api_opaque_message { + u16 _vl_msg_id; + u8 data[65536]; +} vl_api_opaque_message_t; +]]) + + +-- CRC-based version stuff + +local crc32c_table = ffi.new('const uint32_t[256]', + { 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, + 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, + 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, + 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, + 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, + 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, + 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, + 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, + 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, + 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, + 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, + 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, + 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, + 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, + 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, + 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, + 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, + 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, + 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, + 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, + 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, + 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, + 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, + 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, + 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, + 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, + 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, + 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, + 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, + 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, + 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, + 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, + 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, + 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, + 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, + 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, + 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, + 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, + 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, + 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, + 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, + 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, + 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, + 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, + 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, + 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, + 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, + 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, + 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, + 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, + 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, + 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, + 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, + 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, + 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, + 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, + 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, + 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, + 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, + 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, + 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, + 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, + 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, + 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351 } +); + +local function CRC8(crc, d) + return bit.bxor(bit.rshift(crc, 8), crc32c_table[bit.band(0xff, bit.bxor(crc, d))]) +end + +local function CRC16(crc, d) + crc = CRC8(crc, bit.band(d, 0xFF)) + d = bit.rshift(d, 8) + crc = CRC8(crc, bit.band(d, 0xFF)) + return crc +end + +local function string_crc(str, crc) + for i=1,#str do + -- print("S", i, string.byte(str, i), string.char(string.byte(str, i))) + crc = CRC8(crc, string.byte(str, i)) + end + return crc +end + +local tokens = { + { ["match"] =' ', ["act"] = { } }, + { ["match"] ='\n', ["act"] = { } }, + { ["match"] ="manual_endian", ["act"] = { "NODE_MANUAL_ENDIAN", "MANUAL_ENDIAN", 276 } }, + { ["match"] ="define", ["act"] = { "NODE_DEFINE", "DEFINE", 267 } }, + { ["match"] ="dont_trace", ["act"] = { "NODE_DONT_TRACE", "DONT_TRACE", 279 } }, + { ["match"] ="f64", ["act"] = { "NODE_F64", "PRIMTYPE", string_crc } }, + { ["match"] ="i16", ["act"] = { "NODE_I16", "PRIMTYPE", string_crc } }, + { ["match"] ="i32", ["act"] = { "NODE_I32", "PRIMTYPE", string_crc } }, + { ["match"] ="i64", ["act"] = { "NODE_I64", "PRIMTYPE", string_crc } }, + { ["match"] ="i8", ["act"] = { "NODE_I8", "PRIMTYPE", string_crc } }, + { ["match"] ="manual_print", ["act"] = { "NODE_MANUAL_PRINT", "MANUAL_PRINT", 275 } }, + { ["match"] ="noversion", ["act"] = { "NODE_NOVERSION", "NOVERSION", 274 } }, + { ["match"] ="packed", ["act"] = { "NODE_PACKED", "TPACKED", 266 } }, + { ["match"] ="typeonly", ["act"] = { "NODE_TYPEONLY", "TYPEONLY", 278 } }, + { ["match"] ="u16", ["act"] = { "NODE_U16", "PRIMTYPE", string_crc } }, + { ["match"] ="u32", ["act"] = { "NODE_U32", "PRIMTYPE", string_crc } }, + { ["match"] ="u64", ["act"] = { "NODE_U64", "PRIMTYPE", string_crc } }, + { ["match"] ="u8", ["act"] = { "NODE_U8", "PRIMTYPE", string_crc } }, + { ["match"] ="union", ["act"] = { "NODE_UNION", "UNION", 271 } }, + { ["match"] ="uword", ["act"] = { "NODE_UWORD", "PRIMTYPE", string_crc } }, + { ["match"] ="%(", ["act"] = { "NODE_LPAR", "LPAR", 259 } }, + { ["match"] ="%)", ["act"] = { "NODE_RPAR", "RPAR", 258 } }, + { ["match"] =";", ["act"] = { "NODE_SEMI", "SEMI", 260 } }, + { ["match"] ="%[", ["act"] = { "NODE_LBRACK", "LBRACK", 261 } }, + { ["match"] ="%]", ["act"] = { "NODE_RBRACK", "RBRACK", 262 } }, + { ["match"] ="%{", ["act"] = { "NODE_LCURLY", "LCURLY", 268 } }, + { ["match"] ="%}", ["act"] = { "NODE_RCURLY", "RCURLY", 269 } }, + { ["match"] ='%b""', ["act"] = { "NODE_STRING", "STRING", string_crc } }, + { ["match"] ='%b@@', ["act"] = { "NODE_HELPER", "HELPER_STRING", string_crc } }, + -- TODO: \ must be consumed + { ["match"] ='[_a-zA-Z][_a-zA-Z0-9]*', + ["act"] = { "NODE_NAME", "NAME", string_crc } }, + { ["match"] ='[0-9]+', ["act"] = { "NODE_NUMBER", "NUMBER", string_crc } }, + { ["match"] ='#[^\n]+', ["act"] = { "NODE_PRAGMA", "PRAGMA", nil } }, +} + + +function vpp.crc_version_string(data) + local input_crc = 0 + -- Get rid of comments + data = data:gsub("/%*.-%*/", "") + data = data:gsub("//[^\n]+", "") + -- print(data) + idx = 1 + while (true) do + local matched = nil + for k, v in ipairs(tokens) do + if not matched then + local x, y, cap = string.find(data, v["match"], idx) + if x == idx then + matched = { ["node"] = v["act"], ["x"] = x, ["y"] = y, ["cap"] = cap, ["chars"] = string.sub(data, x, y) } + -- print(k, v, x, y, cap, matched.chars, matched.node[0] ) + end + end + end + if matched then + idx = idx + (matched.y - matched.x + 1) + if matched.node[1] then + local act = matched.node[3] + if type(act) == "function" then + input_crc = act(matched.chars, input_crc) + elseif type(act) == "number" then + input_crc = CRC16(input_crc, act) + end + -- print(vpp.dump(matched)) + end + else + -- print("NOT MATCHED!") + local crc = CRC16(input_crc, 0xFFFFFFFF) + return string.sub(string.format("%x", crc), -8) + end + end +end + + +function vpp.dump(o) + if type(o) == 'table' then + local s = '{ ' + for k,v in pairs(o) do + if type(k) ~= 'number' then k = '"'..k..'"' end + s = s .. '['..k..'] = ' .. vpp.dump(v) .. ',' + end + return s .. '} ' + else + return tostring(o) + end +end + +function vpp.hex_dump(buf) + local ret = {} + for i=1,math.ceil(#buf/16) * 16 do + if (i-1) % 16 == 0 then table.insert(ret, string.format('%08X ', i-1)) end + table.insert(ret, ( i > #buf and ' ' or string.format('%02X ', buf:byte(i)) )) + if i % 8 == 0 then table.insert(ret, ' ') end + if i % 16 == 0 then table.insert(ret, buf:sub(i-16+1, i):gsub('%c','.')..'\n' ) end + end + return table.concat(ret) +end + + +function vpp.c_str(text_in) + local text = text_in -- \000 will be helpfully added by ffi.copy + local c_str = ffi.new("char[?]", #text+1) + ffi.copy(c_str, text) + return c_str +end + + +function vpp.init(vpp, args) + local pneum_api = args.pneum_api or [[ + int cough_pneum_attach(char *pneum_path, char *cough_path); + int pneum_connect(char *name, char *chroot_prefix, void *cb); + int pneum_disconnect(void); + int pneum_read(char **data, int *l); + int pneum_write(char *data, int len); + void pneum_free(char *data); + uint32_t pneum_get_msg_index(unsigned char * name); +]] + + vpp.pneum_path = args.pneum_path + ffi.cdef(pneum_api) + local init_res = 0 + vpp.pneum = ffi.load(vpp.pneum_path) + if (init_res < 0) then + return nil + end + + vpp.next_msg_num = 1 + vpp.msg_name_to_number = {} + vpp.msg_name_to_fields = {} + vpp.msg_number_to_name = {} + vpp.msg_number_to_type = {} + vpp.msg_number_to_pointer_type = {} + vpp.msg_name_to_crc = {} + vpp.c_type_to_fields = {} + vpp.events = {} + vpp.plugin_version = {} + vpp.is_connected = false + + + vpp.t_lua2c = {} + vpp.t_c2lua = {} + vpp.t_lua2c["u8"] = function(c_type, src, dst_c_ptr) + if type(src) == "string" then + -- ffi.copy adds a zero byte at the end. Grrr. + -- ffi.copy(dst_c_ptr, src) + ffi.C.memcpy(dst_c_ptr, vpp.c_str(src), #src) + return(#src) + elseif type(src) == "table" then + for i,v in ipairs(src) do + ffi.cast("u8 *", dst_c_ptr)[i-1] = v + end + return(#src) + else + return 1, src -- ffi.cast("u8", src) + end + end + vpp.t_c2lua["u8"] = function(c_type, src_ptr, src_len) + if src_len then + return ffi.string(src_ptr, src_len) + else + return (tonumber(src_ptr)) + end + end + + vpp.t_lua2c["u16"] = function(c_type, src, dst_c_ptr) + if type(src) == "table" then + for i,v in ipairs(src) do + ffi.cast("u16 *", dst_c_ptr)[i-1] = ffi.C.htons(v) + end + return(2 * #src) + else + return 2, (ffi.C.htons(src)) + end + end + vpp.t_c2lua["u16"] = function(c_type, src_ptr, src_len) + if src_len then + local out = {} + for i = 0,src_len-1 do + out[i+1] = tonumber(ffi.C.ntohs(src_ptr[i])) + end + return out + else + return (tonumber(ffi.C.ntohs(src_ptr))) + end + end + + vpp.t_lua2c["u32"] = function(c_type, src, dst_c_ptr) + if type(src) == "table" then + for i,v in ipairs(src) do + ffi.cast("u32 *", dst_c_ptr)[i-1] = ffi.C.htonl(v) + end + return(4 * #src) + else + return 4, (ffi.C.htonl(src)) + end + end + vpp.t_c2lua["u32"] = function(c_type, src_ptr, src_len) + if src_len then + local out = {} + for i = 0,src_len-1 do + out[i+1] = tonumber(ffi.C.ntohl(src_ptr[i])) + end + return out + else + return (tonumber(ffi.C.ntohl(src_ptr))) + end + end + vpp.t_lua2c["i32"] = function(c_type, src, dst_c_ptr) + if type(src) == "table" then + for i,v in ipairs(src) do + ffi.cast("i32 *", dst_c_ptr)[i-1] = ffi.C.htonl(v) + end + return(4 * #src) + else + return 4, (ffi.C.htonl(src)) + end + end + vpp.t_c2lua["i32"] = function(c_type, src_ptr, src_len) + local ntohl = function(src) + local u32val = ffi.cast("u32", src) + local ntohlval = (ffi.C.ntohl(u32val)) + local out = tonumber(ffi.cast("i32", ntohlval + 0LL)) + return out + end + if src_len then + local out = {} + for i = 0,src_len-1 do + out[i+1] = tonumber(ntohl(src_ptr[i])) + end + else + return (tonumber(ntohl(src_ptr))) + end + end + + vpp.t_lua2c["u64"] = function(c_type, src, dst_c_ptr) + if type(src) == "table" then + for i,v in ipairs(src) do + ffi.cast("u64 *", dst_c_ptr)[i-1] = v --- FIXME ENDIAN + end + return(8 * #src) + else + return 8, ffi.cast("u64", src) --- FIXME ENDIAN + end + end + vpp.t_c2lua["u64"] = function(c_type, src_ptr, src_len) + if src_len then + local out = {} + for i = 0,src_len-1 do + out[i+1] = tonumber(src_ptr[i]) -- FIXME ENDIAN + end + return out + else + return (tonumber(src_ptr)) --FIXME ENDIAN + end + end + + + + + vpp.t_lua2c["__MSG__"] = function(c_type, src, dst_c_ptr) + local dst = ffi.cast(c_type .. " *", dst_c_ptr) + local additional_len = 0 + local fields_info = vpp.c_type_to_fields[c_type] + -- print("__MSG__ type: " .. tostring(c_type)) + ffi.C.memset(dst_c_ptr, 0, ffi.sizeof(dst[0])) + -- print(vpp.dump(fields_info)) + -- print(vpp.dump(src)) + for k,v in pairs(src) do + local field = fields_info[k] + if not field then + print("ERROR: field " .. tostring(k) .. " in message " .. tostring(c_type) .. " is unknown") + end + local lua2c = vpp.t_lua2c[field.c_type] + -- print("__MSG__ field " .. tostring(k) .. " : " .. vpp.dump(field)) + -- if the field is not an array type, try to coerce the argument to a number + if not field.array and type(v) == "string" then + v = tonumber(v) + end + if not lua2c then + print("__MSG__ " .. tostring(c_type) .. " t_lua2c: can not store field " .. field.name .. + " type " .. field.c_type .. " dst " .. tostring(dst[k])) + return 0 + end + local len = 0 + local val = nil + if field.array and (type(v) == "table") then + -- print("NTFY: field " .. tostring(k) .. " in message " .. tostring(c_type) .. " is an array") + for field_i, field_v in ipairs(v) do + -- print("NTFY: setting member#" .. tostring(field_i) .. " to value " .. vpp.dump(field_v)) + local field_len, field_val = lua2c(field.c_type, field_v, dst[k][field_i-1]) + len = len + field_len + end + else + len, val = lua2c(field.c_type, v, dst[k]) + end + if not field.array then + dst[k] = val + else + if 0 == field.array then + additional_len = additional_len + len + -- print("Adding " .. tostring(len) .. " bytes due to field " .. tostring(field.name)) + -- If there is a variable storing the length + -- and the input table does not set it, do magic + if field.array_size and not src[field.array_size] then + local size_field = fields_info[field.array_size] + if size_field then + dst[field.array_size] = vpp.t_c2lua[size_field.c_type](size_field.c_type, len) + end + end + end + end + -- print("Full message:\n" .. vpp.hex_dump(ffi.string(ffi.cast('void *', req_store_cache), 64))) + end + return (ffi.sizeof(dst[0])+additional_len) + end + + vpp.t_c2lua["__MSG__"] = function(c_type, src_ptr, src_len) + local out = {} + local reply_typed_ptr = ffi.cast(c_type .. " *", src_ptr) + local field_desc = vpp.c_type_to_fields[c_type] + if src_len then + for i = 0,src_len-1 do + out[i+1] = vpp.t_c2lua[c_type](c_type, src_ptr[i]) + end + return out + end + + for k, v in pairs(field_desc) do + local v_c2lua = vpp.t_c2lua[v.c_type] + if v_c2lua then + local len = v.array + -- print(dump(v)) + if len then + local len_field_name = k .. "_length" + local len_field = field_desc[len_field_name] + if (len_field) then + local real_len = vpp.t_c2lua[len_field.c_type](len_field.c_type, reply_typed_ptr[len_field_name]) + out[k] = v_c2lua(v.c_type, reply_typed_ptr[k], real_len) + elseif len == 0 then + -- check if len = 0, then must be a field which contains the size + len_field = field_desc[v.array_size] + local real_len = vpp.t_c2lua[len_field.c_type](len_field.c_type, reply_typed_ptr[v.array_size]) + -- print("REAL length: " .. vpp.dump(v) .. " : " .. tostring(real_len)) + out[k] = v_c2lua(v.c_type, reply_typed_ptr[k], real_len) + else + -- alas, just stuff the entire array + out[k] = v_c2lua(v.c_type, reply_typed_ptr[k], len) + end + else + out[k] = v_c2lua(v.c_type, reply_typed_ptr[k]) + end + else + out[k] = "" + end + -- print(k, out[k]) + end + return out + end + + return vpp +end + +function vpp.resolve_message_number(msgname) + local name = msgname .. "_" .. vpp.msg_name_to_crc[msgname] + local idx = vpp.pneum.pneum_get_msg_index(vpp.c_str(name)) + if vpp.debug_dump then + print("Index for " .. tostring(name) .. " is " .. tostring(idx)) + end + vpp.msg_name_to_number[msgname] = idx + vpp.msg_number_to_name[idx] = msgname + vpp.msg_number_to_type[idx] = "vl_api_" .. msgname .. "_t" + vpp.msg_number_to_pointer_type[idx] = vpp.msg_number_to_type[idx] .. " *" + ffi.cdef("\n\n enum { vl_msg_" .. msgname .. " = " .. idx .. " };\n\n") +end + +function vpp.connect(vpp, client_name) + local name = "lua_client" + if client_name then + name = client_name + end + local ret = vpp.pneum.pneum_connect(vpp.c_str(client_name), nil, nil) + if tonumber(ret) == 0 then + vpp.is_connected = true + end + for k, v in pairs(vpp.msg_name_to_number) do + vpp.resolve_message_number(k) + end + end + +function vpp.disconnect(vpp) + vpp.pneum.pneum_disconnect() + end + +function vpp.json_api(vpp, path, plugin_name) + -- print("Consuming the VPP api from "..path) + local ffii = {} + local f = io.open(path, "r") + if not f then + print("Could not open " .. path) + return nil + end + local data = f:read("*all") + local json = json.parse(data) + if not (json.types or json.messages) then + print("Can not parse " .. path) + return nil + end + + local all_types = {} + + for i, v in ipairs(json.types) do + table.insert(all_types, { typeonly = 1, desc = v }) + end + for i, v in ipairs(json.messages) do + table.insert(all_types, { typeonly = 0, desc = v }) + end + for i, v in ipairs(all_types) do + local typeonly = v.typeonly + local name = v.desc[1] + local c_type = "vl_api_" .. name .. "_t" + + local fields = {} + -- vpp.msg_name_to_fields[name] = fields + -- print("CTYPE " .. c_type) + vpp.c_type_to_fields[c_type] = fields + vpp.t_lua2c[c_type] = vpp.t_lua2c["__MSG__"] + vpp.t_c2lua[c_type] = vpp.t_c2lua["__MSG__"] + + local cdef = { "\n\n#pragma pack(1)\ntypedef struct _vl_api_", name, " {\n" } + for ii, vv in ipairs(v.desc) do + if type(vv) == "table" then + if vv.crc then + vpp.msg_name_to_crc[name] = string.sub(vv.crc, 3) -- strip the leading 0x + else + local fieldtype = vv[1] + local fieldname = vv[2] + local fieldcount = vv[3] + local fieldcountvar = vv[4] + local fieldrec = { name = fieldname, c_type = fieldtype, array = fieldcount, array_size = fieldcountvar } + if fieldcount then + table.insert(cdef, " " .. fieldtype .. " " .. fieldname .. "[" .. fieldcount .. "];\n") + if fieldtype == "u8" then + -- any array of bytes is treated as a string + elseif vpp.t_lua2c[fieldtype] then + -- print("Array of " .. fieldtype .. " is ok!") + else + print("Unknown array type: ", name, " : " , fieldname, " : ", fieldtype, ":", fieldcount, ":", fieldcountvar) + end + else + table.insert(cdef, " " .. fieldtype .. " " .. fieldname .. ";\n") + end + fields[fieldname] = fieldrec + end + end + end + + table.insert(cdef, "} vl_api_" .. name .. "_t;") + table.insert(ffii, table.concat(cdef)) + + if typeonly == 0 then + -- we will want to resolve this later + if vpp.debug_dump then + print("Remember to resolve " .. name) + end + vpp.msg_name_to_number[name] = -1 + if vpp.is_connected then + vpp.resolve_message_number(name) + end + end + + end + local cdef_full = table.concat(ffii) + ffi.cdef(cdef_full) +end + +function vpp.consume_api(vpp, path, plugin_name) + -- print("Consuming the VPP api from "..path) + local ffii = {} + local f = io.open(path, "r") + if not f then + print("Could not open " .. path) + return nil + end + local data = f:read("*all") + -- Remove all C comments + data = data:gsub("/%*.-%*/", "") + if vpp.is_connected and not plugin_name then + print(path .. ": must specify plugin name!") + return + end + if plugin_name then + vpp.plugin_version[plugin_name] = vpp.crc_version_string(data) + local full_plugin_name = plugin_name .. "_" .. vpp.plugin_version[plugin_name] + local reply = vpp:api_call("get_first_msg_id", { name = full_plugin_name } ) + vpp.next_msg_num = tonumber(reply[1].first_msg_id) + print("Plugin " .. full_plugin_name .. " first message is " .. tostring(vpp.next_msg_num)) + end + -- print ("data len: ", #data) + data = data:gsub("\n(.-)(%S+)%s*{([^}]*)}", function (preamble, name, members) + local _, typeonly = preamble:gsub("typeonly", "") + local maybe_msg_id_field = { [0] = "u16 _vl_msg_id;", "" } + local onedef = "\n\n#pragma pack(1)\ntypedef struct _vl_api_"..name.. " {\n" .. + -- " u16 _vl_msg_id;" .. + maybe_msg_id_field[typeonly] .. + members:gsub("%[[a-zA-Z_]+]", "[0]") .. + "} vl_api_" .. name .. "_t;" + + local c_type = "vl_api_" .. name .. "_t" + + local fields = {} + -- vpp.msg_name_to_fields[name] = fields + -- print("CTYPE " .. c_type) + vpp.c_type_to_fields[c_type] = fields + vpp.t_lua2c[c_type] = vpp.t_lua2c["__MSG__"] + vpp.t_c2lua[c_type] = vpp.t_c2lua["__MSG__"] + local mirec = { name = "_vl_msg_id", c_type = "u16", array = nil, array_size = nil } + if typeonly == 0 then + fields[mirec.name] = mirec + end + + -- populate the field reflection table for the message + -- sets the various type information as well as the accessors for lua<->C conversion + members:gsub("(%S+)%s+(%S+);", function (fieldtype, fieldname) + local fieldcount = nil + local fieldcountvar = nil + -- data = data:gsub("%[[a-zA-Z_]+]", "[0]") + fieldname = fieldname:gsub("(%b[])", function(cnt) + fieldcount = tonumber(cnt:sub(2, -2)); + if not fieldcount then + fieldcount = 0 + fieldcountvar = cnt:sub(2, -2) + end + return "" + end) + local fieldrec = { name = fieldname, c_type = fieldtype, array = fieldcount, array_size = fieldcountvar } + if fieldcount then + if fieldtype == "u8" then + -- any array of bytes is treated as a string + elseif vpp.t_lua2c[fieldtype] then + -- print("Array of " .. fieldtype .. " is ok!") + else + print("Unknown array type: ", name, " : " , fieldname, " : ", fieldtype, ":", fieldcount, ":", fieldcountvar) + end + end + fields[fieldname] = fieldrec + end) + + -- print(dump(fields)) + + if typeonly == 0 then + local this_message_number = vpp.next_msg_num + vpp.next_msg_num = vpp.next_msg_num + 1 + vpp.msg_name_to_number[name] = this_message_number + vpp.msg_number_to_name[this_message_number] = name + vpp.msg_number_to_type[this_message_number] = "vl_api_" .. name .. "_t" + vpp.msg_number_to_pointer_type[this_message_number] = vpp.msg_number_to_type[this_message_number] .. " *" + onedef = onedef .. "\n\n enum { vl_msg_" .. name .. " = " .. this_message_number .. " };\n\n" + end + table.insert(ffii, onedef); + return ""; + end) + local cdef = table.concat(ffii) + -- print(cdef) + ffi.cdef(cdef) + end + + +function vpp.lua2c(vpp, c_type, src, dst_c_ptr) + -- returns the number of bytes written to memory pointed by dst + local lua2c = vpp.t_lua2c[c_type] + if lua2c then + return(lua2c(c_type, src, dst_c_ptr)) + else + print("vpp.lua2c: do not know how to store type " .. tostring(c_type)) + local x = "a" .. nil + return 0 + end +end + +function vpp.c2lua(vpp, c_type, src_ptr, src_len) + -- returns the lua data structure + local c2lua = vpp.t_c2lua[c_type] + if c2lua then + return(c2lua(c_type, src_ptr, src_len)) + else + print("vpp.c2lua: do not know how to load type " .. c_type) + return nil + end +end + +local req_store_cache = ffi.new("vl_api_opaque_message_t[1]") + +function vpp.api_write(vpp, api_name, req_table) + local msg_num = vpp.msg_name_to_number[api_name] + if not msg_num then + print ("API call "..api_name.." is not known") + return nil + end + + if not req_table then + req_table = {} + end + req_table._vl_msg_id = msg_num + + local packed_len = vpp:lua2c(vpp.msg_number_to_type[msg_num], req_table, req_store_cache) + if vpp.debug_dump then + print("Write Message length: " .. tostring(packed_len) .. "\n" .. vpp.hex_dump(ffi.string(ffi.cast('void *', req_store_cache), packed_len))) + end + + res = vpp.pneum.pneum_write(ffi.cast('void *', req_store_cache), packed_len) + return res + end + +local rep_store_cache = ffi.new("vl_api_opaque_message_t *[1]") +local rep_len_cache = ffi.new("int[1]") + +function vpp.api_read(vpp) + local rep_type = "vl_api_opaque_message_t" + local rep = rep_store_cache + local replen = rep_len_cache + res = vpp.pneum.pneum_read(ffi.cast("void *", rep), replen) + if vpp.debug_dump then + print("Read Message length: " .. tostring(replen[0]) .. "\n" .. vpp.hex_dump(ffi.string(ffi.cast('void *', rep[0]), replen[0]))) + end + + local reply_msg_num = ffi.C.ntohs(rep[0]._vl_msg_id) + local reply_msg_name = vpp.msg_number_to_name[reply_msg_num] + + local reply_typed_ptr = ffi.cast(vpp.msg_number_to_pointer_type[reply_msg_num], rep[0]) + local out = vpp:c2lua(vpp.msg_number_to_type[reply_msg_num], rep[0], nil, replen[0]) + if type(out) == "table" then + out["luaapi_message_name"] = reply_msg_name + end + + vpp.pneum.pneum_free(ffi.cast('void *',rep[0])) + + return reply_msg_name, out + end + +function vpp.api_call(vpp, api_name, req_table, options_in) + local msg_num = vpp.msg_name_to_number[api_name] + local end_message_name = api_name .."_reply" + local replies = {} + local cstruct = "" + local options = options_in or {} + if msg_num then + if vpp.debug_dump then + print("Message #" .. tostring(msg_num) .. " for name " .. tostring(api_name)) + end + vpp:api_write(api_name, req_table) + if not vpp.msg_name_to_number[end_message_name] or options.force_ping then + end_message_name = "control_ping_reply" + vpp:api_write("control_ping") + end + repeat + reply_message_name, reply = vpp:api_read() + if reply and not reply.context then + -- there may be async events inbetween + table.insert(vpp.events, reply) + else + if reply_message_name ~= "control_ping_reply" then + -- do not insert the control ping encapsulation + table.insert(replies, reply) + end + end + -- print(reply) + until reply_message_name == end_message_name + else + print(api_name .. " is an unknown API call") + return nil + end + return replies + end + +return vpp diff --git a/src/vpp.am b/src/vpp.am index a02206f8..1d07b90a 100644 --- a/src/vpp.am +++ b/src/vpp.am @@ -74,7 +74,7 @@ PLUGIN_DPDK_ARG="" endif vpp_plugin_configure: - @echo "PLUGIN CONFIGURE " $@ + @echo "PLUGIN CFG" $@ @echo "#!/bin/bash" > $@ @echo " " >> $@ @echo "set +eu" >> $@ diff --git a/src/vppapigen.am b/src/vppapigen.am index 083ee537..edde339d 100644 --- a/src/vppapigen.am +++ b/src/vppapigen.am @@ -16,9 +16,9 @@ bin_PROGRAMS += vppapigen BUILT_SOURCES += tools/vppapigen/gram.h tools/vppapigen/gram.h: tools/vppapigen/gram.y - $(YACC) -d @srcdir@/tools/vppapigen/gram.y - mv y.tab.h tools/vppapigen/gram.h - rm y.tab.c + @$(YACC) -d @srcdir@/tools/vppapigen/gram.y + @mv y.tab.h tools/vppapigen/gram.h + @rm y.tab.c vppapigen_SOURCES = tools/vppapigen/gram.y tools/vppapigen/lex.c tools/vppapigen/node.c vppapigen_LDADD = libvppinfra.la diff --git a/vpp-api/Makefile.am b/vpp-api/Makefile.am deleted file mode 100644 index b50522ef..00000000 --- a/vpp-api/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -AUTOMAKE_OPTIONS = foreign -SUBDIRS = java - -# vi:syntax=automake diff --git a/vpp-api/configure.ac b/vpp-api/configure.ac deleted file mode 100644 index 278041c7..00000000 --- a/vpp-api/configure.ac +++ /dev/null @@ -1,12 +0,0 @@ -AC_INIT(vpp-api, 1.1.0) -LT_INIT -AC_CONFIG_MACRO_DIR([m4]) -AC_CONFIG_SUBDIRS([java]) -AM_INIT_AUTOMAKE -AM_SILENT_RULES([yes]) - -AC_PROG_CC - -AC_CONFIG_FILES([Makefile]) -AC_OUTPUT - diff --git a/vpp-api/java/Makefile.am b/vpp-api/java/Makefile.am deleted file mode 100644 index b0551965..00000000 --- a/vpp-api/java/Makefile.am +++ /dev/null @@ -1,116 +0,0 @@ -# Copyright (c) 2015 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -AUTOMAKE_OPTIONS = foreign subdir-objects -ACLOCAL_AMFLAGS = -I m4 -AM_CFLAGS = -Wall - -noinst_PROGRAMS = -BUILT_SOURCES = -bin_PROGRAMS = -CLEANFILES = -lib_LTLIBRARIES = - -# -# jvpp-common -# - -nobase_include_HEADERS = \ - jvpp-common/jvpp_common.h - -lib_LTLIBRARIES += libjvpp_common.la - -libjvpp_common_la_SOURCES = jvpp-common/jvpp_common.c -libjvpp_common_la_LIBADD = -lvlibmemoryclient -lvlibapi -lsvm -lvppinfra \ - -lpthread -lm -lrt -libjvpp_common_la_LDFLAGS = -module -libjvpp_common_la_CPPFLAGS = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux - - -# -# jvpp-registry (connection management + plugin registry) -# -lib_LTLIBRARIES += libjvpp_registry.la - -libjvpp_registry_la_SOURCES = jvpp-registry/jvpp_registry.c -libjvpp_registry_la_LIBADD = -lvlibmemoryclient -lvlibapi -lsvm -lvppinfra \ - -lpthread -lm -lrt -ljvpp_common -libjvpp_registry_la_LDFLAGS = -module -libjvpp_registry_la_CPPFLAGS = -Ijvpp-registry -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -EXTRA_libjvpp_registry_la_DEPENDENCIES=libjvpp_common.la - -jarfile_jvpp_registry = jvpp-registry-$(PACKAGE_VERSION).jar -packagedir_jvpp_registry = io/fd/vpp/jvpp - -BUILT_SOURCES += jvpp-registry/io_fd_vpp_jvpp_VppJNIConnection.h - -jvpp_registry_src_files := $(wildcard @srcdir@/jvpp-registry/$(packagedir_jvpp_registry)/*.java) $(wildcard @srcdir@/jvpp-registry/$(packagedir_jvpp_registry)/**/*.java) - -jvpp-registry/io_fd_vpp_jvpp_VppJNIConnection.h: $(jvpp_registry_src_files) - @echo " jvpp-registry.jar generation" - mkdir -p jvpp-registry/target - $(JAVAC) -d jvpp-registry/target $(jvpp_registry_src_files) - $(JAVAH) -force -classpath jvpp-registry/target -d jvpp-registry io.fd.vpp.jvpp.VppJNIConnection - $(JAVAH) -force -classpath jvpp-registry/target -d jvpp-registry io.fd.vpp.jvpp.JVppRegistryImpl - -$(jarfile_jvpp_registry): libjvpp_registry.la - cp .libs/libjvpp_registry.so.0.0.0 jvpp-registry/target; \ - $(JAR) cf $(JARFLAGS) $@ -C jvpp-registry/target .; - -# -# jvpp-core (Java wrapper for vpe.api) -# -lib_LTLIBRARIES += libjvpp_core.la - -libjvpp_core_la_SOURCES = jvpp-core/jvpp_core.c jvpp-core/jvpp_core_gen.h -libjvpp_core_la_LIBADD = -lvlibmemoryclient -lvlibapi -lsvm -lvppinfra \ - -lpthread -lm -lrt -ljvpp_common -libjvpp_core_la_LDFLAGS = -module -libjvpp_core_la_CPPFLAGS = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux - -jarfile_jvpp_core = jvpp-core-$(PACKAGE_VERSION).jar -packagedir_jvpp_core = io/fd/vpp/jvpp/core - -BUILT_SOURCES += jvpp-core/io_fd_vpp_jvpp_core_JVppCoreImpl.h - -JSON_FILES = \ - $(wildcard $(prefix)/../vpp/share/vpp/api/core/*.api.json) - -jvpp-core/io_fd_vpp_jvpp_core_JVppCoreImpl.h: \ - jvpp-registry/io_fd_vpp_jvpp_VppJNIConnection.h \ - $(JSON_FILES) - cp -rf @srcdir@/jvpp-core/* -t jvpp-core/ - mkdir -p jvpp-core/target - cd jvpp-core \ - && mkdir -p types dto future callfacade callback notification \ - && @srcdir@/jvpp/gen/jvpp_gen.py --plugin_name core \ - -i $(JSON_FILES) \ - && cp -rf types dto future callfacade callback notification *.java -t $(packagedir_jvpp_core) \ - && rm -rf types dto future callfacade callback notification *.java - - $(JAVAC) -classpath jvpp-registry/target -d jvpp-core/target jvpp-core/$(packagedir_jvpp_core)/*.java \ - jvpp-core/$(packagedir_jvpp_core)/types/*.java \ - jvpp-core/$(packagedir_jvpp_core)/dto/*.java \ - jvpp-core/$(packagedir_jvpp_core)/callback/*.java \ - jvpp-core/$(packagedir_jvpp_core)/notification/*.java \ - jvpp-core/$(packagedir_jvpp_core)/future/*.java \ - jvpp-core/$(packagedir_jvpp_core)/callfacade/*.java \ - jvpp-core/$(packagedir_jvpp_core)/test/*.java \ - || (echo "jvpp-core compilation failed: $$?"; exit 1) - $(JAVAH) -force -classpath jvpp-registry/target:jvpp-core/target -d jvpp-core io.fd.vpp.jvpp.core.JVppCoreImpl - -$(jarfile_jvpp_core): libjvpp_core.la - cp .libs/libjvpp_core.so.0.0.0 jvpp-core/target - $(JAR) cf $(JARFLAGS) $@ -C jvpp-core/target . - -all-local: $(jarfile_jvpp_registry) $(jarfile_jvpp_core) diff --git a/vpp-api/java/Readme.txt b/vpp-api/java/Readme.txt deleted file mode 100644 index 689b9b37..00000000 --- a/vpp-api/java/Readme.txt +++ /dev/null @@ -1,236 +0,0 @@ -= JVpp - -JVpp is JNI based Java API for VPP. - -== Features -It is: - -* Asynchronous -* Fully generated -* Lightweight - -== Architecture - -=== Plugin support - - /-------------\ /--------------\ /---------------\ - | JvppPlugin1 +<-------+ JVppRegistry +--------->+ VppConnection | - \-------------/ inits \--+-----------/ uses \---------------/ - | - /-------------\ | - | JvppPlugin2 +<----------+ inits - \-------------/ | - | - ... | - | - /----------\ | - | JVppCore +<-------------+ - \----------/ - - -VppRegistry opens connection to vpp (VppConnection) and manages jvpp plugins. -Each plugin needs to be registered in the VppRegistry. Registration involves -plugin initialization (providing JNI implementation with JVppCallback reference, -vpp client identifier and vpp shared memory queue address). - -API user sends message by calling a method of appropriate plugin interface. -The call is delegated to JNI implementation provided by the particular plugin. -When JNI code receives reply, it invokes callback method of JVppCallback -that corresponds to the received message reply. - -=== JVppCore as an example of JVpp plugin architecture - - JVpp Java - - /--------------\ /----------\ /------------\ /------\ - | JVppRegistry | | JVppCore | | Callbacks | | DTOs | - \----+---------/ \----+-----/ \------+-----/ \------/ - ^ ^ ^ - | implements | implements | implements - /----+--------------\ /---+----------\ /-----+---------\ - | JVppRegistryImpl* +-------->+ JVppCoreImpl | | JVppCallback | - \-------+-----------/ inits \---+----------/ \-------+-------/ - | | ^ - | | uses | calls back - | | | -----------|--------------------------|-----------------------|--------------------- - | | | - C JNI | +-------------------+ | /-----------------\ - v | | +-->+ jvpp_core_gen.h | - /--------+--------\ | | | \-----------------/ - | jpp_registry.c* +---+ /--------+----+----\ | | | - \-----------------/ | | << shared lib >> | /-+--+---+------\ - + ->+ jvpp_common* <--------+ jvpp_core.c* | - uses \------------------/ uses \---------------/ - - -* Components marked with an asterisk contain manually crafted code, which in addition -to generated classes form jvpp. Exception applies to Callbacks and DTOs, since there are -manually crafted marker interfaces in callback and dto package (dto/JVppRequest, dto/JVppReply, -dto/JVppDump, dto/JVppReplyDump, callback/JVppCallback) - -Note: jvpp_core.c calls back the JVppCallback instance with every response. An instance of the -JVppCallback is provided to jvpp_core.c by JVppRegistryImpl on JVppCoreImpl initialization. - -Part of the JVpp is also Future facade. It is asynchronous API returning Future objects -on top of low level JVpp. It wraps dump reply messages in one DTO using control_ping message -(provided by JVppRegistry). - - -Future facade - - /----------------\ /---------------\ - | FutureJVppCore | +-->+ JVppRegistry* | - \-----+----------/ | \---------------/ - ^ | - | implements | uses - | | - /--------+-------------\ | /------------------------------\ - | FutureJVppCoreFacade +---+--->+ FutureJVppCoreFacadeCallback | - \---------+------------/ uses \-------+----------------------/ - | | ----------------|-----------------------------|------------------------------- - | uses | implements -JVpp Java | | - | | - /----------\ | | - | JVppCore +<-+ | - \----+-----/ | - ^ | - | implements v - /----+---------\ /--------+---------------\ - | JVppCoreImpl | | JVppCoreGlobalCallback | - \--------------/ \------------------------/ - - - -Another useful utility of the JVpp is Callback facade. It is asynchronous API -capable of calling specific callback instance (provided when performing a call) -per call. - - -Callback facade - - /------------------\ /---------------\ - | CallbackJVppCore | +-->+ JVppRegistry* | - \-----+------------/ | \---------------/ - ^ | - | implements | uses - | | - /--------+---------------\ | /--------------------------\ - | CallbackJVppCoreFacade +---+--->+ CallbackJVppCoreCallback | - \---------+--------------/ uses \-----+--------------------/ - | | ----------------|-----------------------------|------------------------------- - | uses | implements -JVpp Java | | - | | - /----------\ | | - | JVppCore +<-+ | - \----+-----/ | - ^ | - | implements v - /----+---------\ /----------+-------------\ - | JVppCoreImpl | | JVppCoreGlobalCallback | - \--------------/ \------------------------/ - - -== Package structure - -* *io.fd.vpp.jvpp* - top level package for generated JVpp interface+ implementation and hand-crafted -VppConnection interface + implementation - packaged as jvpp-registry-version.jar - -* *io.fd.vpp.jvpp.[plugin]* - top level package for generated JVpp interface + implementation -+ plugin's API tests - packaged as jvpp-[plugin]-version.jar - -** *dto* - package for DTOs generated from VPP API structures + base/marker hand-crafted interfaces -(in case of jvpp-registry) -** *callback* - package for low-level JVpp callbacks and a global callback interface implementing each of -the low-level JVppcallbacks -** *future* - package for future based facade on top of JVpp and callbacks -** *callfacade* - package for callback based facade on top of JVpp and callbacks. Allowing -users to provide callback per request -** *test* - package for JVpp standalone tests. Can also serve as samples for JVpp. - -C code is structured into modules: - -* *jvpp_common* - shared library that provides jvpp_main_t reference used by jvpp_registry and plugins. - -* *jvpp_registry* - native library used by JVppRegistryImpl, responsible for: - -** VPP connection open/close -** Rx thread to java thread attach -** control ping message handling - -* *jvpp_core* - native library used by jvpp core plugin: -** *jvpp_core.c* - contains hand crafted code for core plugin initialization -** *jvpp_core_gen.h* - contains generated JNI compatible handlers for all requests and replies defined in vpe.api - -== Code generators -All of the required code except the base/marker interfaces is generated using -simple python2 code generators. The generators use __defs_vpp_papi.py__ input -file produced by __vppapigen__ from vpe.api file. - -=== JNI compatible C code -Produces __jvpp_[plugin]_gen.h__ file containing JNI compatible handlers for each VPP -request and reply. - -[NOTE] -==== -Source: jvpp_c_gen.py -==== - -=== Request/Reply DTOs -For all the structures in __defs_vpp_papi.py__ a POJO DTO is produced. Logically, -there are 4 types of DTOs: - -* Request - requests that can be sent to VPP and only a single response is expected -* DumpRequest - requests that can be sent to VPP and a stream of responses is expected -* Reply - reply to a simple request or a single response from dump triggered response stream -* ReplyDump - collection of replies from a single dump request -* Notifications/Events - Not implemented yet - -[NOTE] -==== -Source: dto_gen.py -==== - -=== JVpp -Produces __JVpp.java__ and __JVppImpl.java__. This is the layer right above JNI compatible C -code. - -[NOTE] -==== -Source: jvpp_impl_gen.py -==== - -=== Callbacks -Produces callback interface for each VPP reply + a global callback interface called -__JVpp[plugin]GlobalCallback.java__ aggregating all of the callback interfaces. The JNI -compatible C code expects only a single instance of this global callback and calls -it with every reply. - -[NOTE] -==== -Source: callback_gen.py -==== - -=== Future facade -Produces an asynchronous facade on top of JVpp and callbacks, which returns a Future that provides -matching reply once VPP invocation finishes. Sources produced: -__FutureJVpp[plugin].java, FutureJVpp[plugin]Facade.java and FutureJVpp[plugin]Callback.java__ - -[NOTE] -==== -Source: jvpp_future_facade_gen.py -==== - -=== Callback facade -Similar to future facade, only this facade takes callback objects as part of the invocation -and the callback is called with result once VPP invocation finishes. Sources produced: -__CallbackJVpp[plugin].java, CallbackJVpp[plugin]Facade.java and CallbackJVpp[plugin]Callback.java__ - -[NOTE] -==== -Source: jvpp_callback_facade_gen.py -==== diff --git a/vpp-api/java/configure.ac b/vpp-api/java/configure.ac deleted file mode 100644 index 3082781e..00000000 --- a/vpp-api/java/configure.ac +++ /dev/null @@ -1,24 +0,0 @@ -AC_INIT(jvpp, 17.04) -LT_INIT -AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE -AM_SILENT_RULES([yes]) - -AC_PROG_CC - -if test -f /usr/bin/lsb_release && test `lsb_release -si` == "Ubuntu" && test `lsb_release -sr` == "14.04" && test -d /usr/lib/jvm/java-8-openjdk-amd64/ ; then - JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/ - JAVAC=${JAVA_HOME}/bin/javac - PATH=${JAVA_HOME}/bin/:${PATH} - break -fi - -AX_CHECK_JAVA_HOME -AX_PROG_JAVAC -AX_PROG_JAVAH -AX_PROG_JAR -AX_PROG_JAVADOC -AX_PROG_JAVA - -AC_OUTPUT([Makefile]) - diff --git a/vpp-api/java/jvpp-common/jvpp_common.c b/vpp-api/java/jvpp-common/jvpp_common.c deleted file mode 100644 index a161c09c..00000000 --- a/vpp-api/java/jvpp-common/jvpp_common.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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. - */ -#define _GNU_SOURCE /* for strcasestr(3) */ - -#include "jvpp_common.h" - -#ifndef JVPP_DEBUG -#define JVPP_DEBUG 0 -#endif - -#if JVPP_DEBUG == 1 -#define DEBUG_LOG(...) clib_warning(__VA_ARGS__) -#else -#define DEBUG_LOG(...) -#endif - -/* shared jvpp main structure */ -jvpp_main_t jvpp_main __attribute__((aligned (64))); - -void call_on_error(const char* callName, int contextId, int retval, - jclass callbackClass, jobject callbackObject, - jclass callbackExceptionClass) { - DEBUG_LOG("\nCallOnError : callback=%s, retval=%d, context=%d\n", callName, - clib_net_to_host_u32(retval), clib_net_to_host_u32(context)); - JNIEnv *env = jvpp_main.jenv; - if (!callbackClass) { - DEBUG_LOG("CallOnError : jm->callbackClass is null!\n"); - return; - } - jmethodID excConstructor = (*env)->GetMethodID(env, callbackExceptionClass, - "", "(Ljava/lang/String;II)V"); - if (!excConstructor) { - DEBUG_LOG("CallOnError : excConstructor is null!\n"); - return; - } - jmethodID callbackExcMethod = (*env)->GetMethodID(env, callbackClass, - "onError", "(Lio/fd/vpp/jvpp/VppCallbackException;)V"); - if (!callbackExcMethod) { - DEBUG_LOG("CallOnError : callbackExcMethod is null!\n"); - return; - } - - jobject excObject = (*env)->NewObject(env, callbackExceptionClass, - excConstructor, (*env)->NewStringUTF(env, callName), - clib_net_to_host_u32(contextId), clib_net_to_host_u32(retval)); - if (!excObject) { - DEBUG_LOG("CallOnError : excObject is null!\n"); - return; - } - - (*env)->CallVoidMethod(env, callbackObject, callbackExcMethod, excObject); - DEBUG_LOG("CallOnError : Response sent\n"); -} diff --git a/vpp-api/java/jvpp-common/jvpp_common.h b/vpp-api/java/jvpp-common/jvpp_common.h deleted file mode 100644 index bbb203ed..00000000 --- a/vpp-api/java/jvpp-common/jvpp_common.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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. - */ -#ifndef __included_jvpp_common_h__ -#define __included_jvpp_common_h__ -// -#include -#include -#include -#include - -typedef struct { - /* Unique identifier used for matching replays with requests */ - volatile u32 context_id; - - /* Spinlock */ - volatile u32 lock; - u32 tag; - - /* JNI Native Method Interface pointer for message handlers */ - JNIEnv *jenv; - - /* JNI Invoke Interface pointer for attachment of rx thread to java thread */ - JavaVM *jvm; - - /* Convenience */ - unix_shared_memory_queue_t * vl_input_queue; - u32 my_client_index; -} jvpp_main_t; - -extern jvpp_main_t jvpp_main __attribute__((aligned (64))); - -static_always_inline u32 vppjni_get_context_id(jvpp_main_t * jm) { - return __sync_add_and_fetch(&jm->context_id, 1); -} - -static_always_inline void vppjni_lock(jvpp_main_t * jm, u32 tag) { - while (__sync_lock_test_and_set(&jm->lock, 1)) - ; - jm->tag = tag; -} - -static_always_inline void vppjni_unlock(jvpp_main_t * jm) { - jm->tag = 0; - CLIB_MEMORY_BARRIER(); - jm->lock = 0; -} - -/** - * Calls onError callback on callbackObject reference. Passes instance of callbackExceptionClass as parameter. - */ -void call_on_error(const char* callName, int contextId, int retval, - jclass callbackClass, jobject callbackObject, - jclass callbackExceptionClass); - -#endif /* __included_jvpp_common_h__ */ diff --git a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackApiTest.java b/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackApiTest.java deleted file mode 100644 index 986993b8..00000000 --- a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackApiTest.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.core.test; - -import io.fd.vpp.jvpp.JVpp; -import io.fd.vpp.jvpp.JVppRegistry; -import io.fd.vpp.jvpp.JVppRegistryImpl; -import io.fd.vpp.jvpp.VppCallbackException; -import io.fd.vpp.jvpp.core.JVppCoreImpl; -import io.fd.vpp.jvpp.core.callback.GetNodeIndexCallback; -import io.fd.vpp.jvpp.core.callback.ShowVersionCallback; -import io.fd.vpp.jvpp.core.callback.SwInterfaceCallback; -import io.fd.vpp.jvpp.core.dto.GetNodeIndex; -import io.fd.vpp.jvpp.core.dto.GetNodeIndexReply; -import io.fd.vpp.jvpp.core.dto.ShowVersion; -import io.fd.vpp.jvpp.core.dto.ShowVersionReply; -import io.fd.vpp.jvpp.core.dto.SwInterfaceDetails; -import io.fd.vpp.jvpp.core.dto.SwInterfaceDump; - -public class CallbackApiTest { - - public static void main(String[] args) throws Exception { - testCallbackApi(); - } - - private static void testCallbackApi() throws Exception { - System.out.println("Testing Java callback API with JVppRegistry"); - try (final JVppRegistry registry = new JVppRegistryImpl("CallbackApiTest"); - final JVpp jvpp = new JVppCoreImpl()) { - registry.register(jvpp, new TestCallback()); - - System.out.println("Sending ShowVersion request..."); - final int result = jvpp.send(new ShowVersion()); - System.out.printf("ShowVersion send result = %d%n", result); - - System.out.println("Sending GetNodeIndex request..."); - GetNodeIndex getNodeIndexRequest = new GetNodeIndex(); - getNodeIndexRequest.nodeName = "non-existing-node".getBytes(); - jvpp.send(getNodeIndexRequest); - - System.out.println("Sending SwInterfaceDump request..."); - SwInterfaceDump swInterfaceDumpRequest = new SwInterfaceDump(); - swInterfaceDumpRequest.nameFilterValid = 0; - swInterfaceDumpRequest.nameFilter = "".getBytes(); - jvpp.send(swInterfaceDumpRequest); - - Thread.sleep(1000); - System.out.println("Disconnecting..."); - } - Thread.sleep(1000); - } - - static class TestCallback implements GetNodeIndexCallback, ShowVersionCallback, SwInterfaceCallback { - - @Override - public void onGetNodeIndexReply(final GetNodeIndexReply msg) { - System.out.printf("Received GetNodeIndexReply: %s%n", msg); - } - - @Override - public void onShowVersionReply(final ShowVersionReply msg) { - System.out.printf("Received ShowVersionReply: context=%d, program=%s, version=%s, " - + "buildDate=%s, buildDirectory=%s%n", - msg.context, new String(msg.program), new String(msg.version), - new String(msg.buildDate), new String(msg.buildDirectory)); - } - - @Override - public void onSwInterfaceDetails(final SwInterfaceDetails msg) { - System.out.printf("Received SwInterfaceDetails: interfaceName=%s, l2AddressLength=%d, adminUpDown=%d, " - + "linkUpDown=%d, linkSpeed=%d, linkMtu=%d%n", - new String(msg.interfaceName), msg.l2AddressLength, msg.adminUpDown, - msg.linkUpDown, msg.linkSpeed, (int) msg.linkMtu); - } - - @Override - public void onError(VppCallbackException ex) { - System.out.printf("Received onError exception: call=%s, context=%d, retval=%d%n", ex.getMethodName(), - ex.getCtxId(), ex.getErrorCode()); - } - } -} diff --git a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackJVppFacadeNotificationTest.java b/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackJVppFacadeNotificationTest.java deleted file mode 100644 index d84cb034..00000000 --- a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackJVppFacadeNotificationTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.core.test; - -import io.fd.vpp.jvpp.JVppRegistry; -import io.fd.vpp.jvpp.JVppRegistryImpl; -import io.fd.vpp.jvpp.VppCallbackException; -import io.fd.vpp.jvpp.core.JVppCore; -import io.fd.vpp.jvpp.core.JVppCoreImpl; -import io.fd.vpp.jvpp.core.callback.WantInterfaceEventsCallback; -import io.fd.vpp.jvpp.core.callfacade.CallbackJVppCoreFacade; -import io.fd.vpp.jvpp.core.dto.WantInterfaceEventsReply; - -public class CallbackJVppFacadeNotificationTest { - - private static void testCallbackFacade() throws Exception { - System.out.println("Testing CallbackJVppFacade for notifications"); - - try (final JVppRegistry registry = new JVppRegistryImpl("CallbackFacadeTest"); - final JVppCore jvpp = new JVppCoreImpl()) { - final CallbackJVppCoreFacade jvppCallbackFacade = new CallbackJVppCoreFacade(registry, jvpp); - System.out.println("Successfully connected to VPP"); - - final AutoCloseable notificationListenerReg = - jvppCallbackFacade.getNotificationRegistry().registerSwInterfaceSetFlagsNotificationCallback( - NotificationUtils::printNotification - ); - - jvppCallbackFacade.wantInterfaceEvents(NotificationUtils.getEnableInterfaceNotificationsReq(), - new WantInterfaceEventsCallback() { - @Override - public void onWantInterfaceEventsReply(final WantInterfaceEventsReply reply) { - System.out.println("Interface events started"); - } - - @Override - public void onError(final VppCallbackException ex) { - System.out.printf("Received onError exception: call=%s, context=%d, retval=%d%n", - ex.getMethodName(), ex.getCtxId(), ex.getErrorCode()); - } - }); - - System.out.println("Changing interface configuration"); - NotificationUtils.getChangeInterfaceState().send(jvpp); - - Thread.sleep(1000); - - jvppCallbackFacade.wantInterfaceEvents(NotificationUtils.getDisableInterfaceNotificationsReq(), - new WantInterfaceEventsCallback() { - @Override - public void onWantInterfaceEventsReply(final WantInterfaceEventsReply reply) { - System.out.println("Interface events stopped"); - } - - @Override - public void onError(final VppCallbackException ex) { - System.out.printf("Received onError exception: call=%s, context=%d, retval=%d%n", - ex.getMethodName(), ex.getCtxId(), ex.getErrorCode()); - } - }); - - notificationListenerReg.close(); - - Thread.sleep(2000); - System.out.println("Disconnecting..."); - } - Thread.sleep(1000); - } - - public static void main(String[] args) throws Exception { - testCallbackFacade(); - } -} diff --git a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackJVppFacadeTest.java b/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackJVppFacadeTest.java deleted file mode 100644 index 9f7cb8de..00000000 --- a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackJVppFacadeTest.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.core.test; - -import io.fd.vpp.jvpp.JVppRegistry; -import io.fd.vpp.jvpp.JVppRegistryImpl; -import io.fd.vpp.jvpp.VppCallbackException; -import io.fd.vpp.jvpp.core.JVppCoreImpl; -import io.fd.vpp.jvpp.core.callback.GetNodeIndexCallback; -import io.fd.vpp.jvpp.core.callback.ShowVersionCallback; -import io.fd.vpp.jvpp.core.callfacade.CallbackJVppCoreFacade; -import io.fd.vpp.jvpp.core.dto.GetNodeIndex; -import io.fd.vpp.jvpp.core.dto.GetNodeIndexReply; -import io.fd.vpp.jvpp.core.dto.ShowVersionReply; - -/** - * CallbackJVppFacade together with CallbackJVppFacadeCallback allow for setting different callback for each request. - * This is more convenient than the approach shown in CallbackApiTest. - */ -public class CallbackJVppFacadeTest { - - private static ShowVersionCallback showVersionCallback1 = new ShowVersionCallback() { - @Override - public void onShowVersionReply(final ShowVersionReply msg) { - System.out.printf("ShowVersionCallback1 received ShowVersionReply: context=%d, program=%s," - + "version=%s, buildDate=%s, buildDirectory=%s%n", msg.context, new String(msg.program), - new String(msg.version), new String(msg.buildDate), new String(msg.buildDirectory)); - } - - @Override - public void onError(VppCallbackException ex) { - System.out.printf("Received onError exception in showVersionCallback1: call=%s, reply=%d, context=%d%n", - ex.getMethodName(), ex.getErrorCode(), ex.getCtxId()); - } - }; - - private static ShowVersionCallback showVersionCallback2 = new ShowVersionCallback() { - @Override - public void onShowVersionReply(final ShowVersionReply msg) { - System.out.printf("ShowVersionCallback2 received ShowVersionReply: context=%d, program=%s," - + "version=%s, buildDate=%s, buildDirectory=%s%n", msg.context, new String(msg.program), - new String(msg.version), new String(msg.buildDate), new String(msg.buildDirectory)); - } - - @Override - public void onError(VppCallbackException ex) { - System.out.printf("Received onError exception in showVersionCallback2: call=%s, reply=%d, context=%d%n", - ex.getMethodName(), ex.getErrorCode(), ex.getCtxId()); - } - - }; - - private static GetNodeIndexCallback getNodeIndexCallback = new GetNodeIndexCallback() { - @Override - public void onGetNodeIndexReply(final GetNodeIndexReply msg) { - System.out.printf("Received GetNodeIndexReply: %s%n", msg); - } - - @Override - public void onError(VppCallbackException ex) { - System.out.printf("Received onError exception in getNodeIndexCallback: call=%s, reply=%d, context=%d%n", - ex.getMethodName(), ex.getErrorCode(), ex.getCtxId()); - } - }; - - private static void testCallbackFacade() throws Exception { - System.out.println("Testing CallbackJVppFacade"); - - try (final JVppRegistry registry = new JVppRegistryImpl("CallbackFacadeTest"); - final CallbackJVppCoreFacade callbackFacade = new CallbackJVppCoreFacade(registry, new JVppCoreImpl())) { - System.out.println("Successfully connected to VPP"); - - callbackFacade.showVersion(showVersionCallback1); - callbackFacade.showVersion(showVersionCallback2); - - GetNodeIndex getNodeIndexRequest = new GetNodeIndex(); - getNodeIndexRequest.nodeName = "dummyNode".getBytes(); - callbackFacade.getNodeIndex(getNodeIndexRequest, getNodeIndexCallback); - - Thread.sleep(2000); - System.out.println("Disconnecting..."); - } - Thread.sleep(1000); - } - - public static void main(String[] args) throws Exception { - testCallbackFacade(); - } -} diff --git a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackNotificationApiTest.java b/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackNotificationApiTest.java deleted file mode 100644 index a9f71f11..00000000 --- a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CallbackNotificationApiTest.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.core.test; - -import static io.fd.vpp.jvpp.core.test.NotificationUtils.getChangeInterfaceState; -import static io.fd.vpp.jvpp.core.test.NotificationUtils.getDisableInterfaceNotificationsReq; -import static io.fd.vpp.jvpp.core.test.NotificationUtils.getEnableInterfaceNotificationsReq; -import static io.fd.vpp.jvpp.core.test.NotificationUtils.printNotification; - -import io.fd.vpp.jvpp.JVpp; -import io.fd.vpp.jvpp.JVppRegistry; -import io.fd.vpp.jvpp.JVppRegistryImpl; -import io.fd.vpp.jvpp.VppCallbackException; -import io.fd.vpp.jvpp.core.JVppCoreImpl; -import io.fd.vpp.jvpp.core.callback.SwInterfaceSetFlagsCallback; -import io.fd.vpp.jvpp.core.callback.SwInterfaceSetFlagsNotificationCallback; -import io.fd.vpp.jvpp.core.callback.WantInterfaceEventsCallback; -import io.fd.vpp.jvpp.core.dto.SwInterfaceSetFlagsNotification; -import io.fd.vpp.jvpp.core.dto.SwInterfaceSetFlagsReply; -import io.fd.vpp.jvpp.core.dto.WantInterfaceEventsReply; - -public class CallbackNotificationApiTest { - - private static void testCallbackApi() throws Exception { - System.out.println("Testing Java callback API for notifications"); - try (final JVppRegistry registry = new JVppRegistryImpl("CallbackNotificationTest"); - final JVpp jvpp = new JVppCoreImpl()) { - registry.register(jvpp, new TestCallback()); - System.out.println("Successfully connected to VPP"); - - getEnableInterfaceNotificationsReq().send(jvpp); - System.out.println("Interface notifications started"); - // TODO test ifc dump which also triggers interface flags send - - System.out.println("Changing interface configuration"); - getChangeInterfaceState().send(jvpp); - - // Notifications are received - Thread.sleep(500); - - getDisableInterfaceNotificationsReq().send(jvpp); - System.out.println("Interface events stopped"); - - Thread.sleep(2000); - System.out.println("Disconnecting..."); - } - Thread.sleep(1000); - } - - public static void main(String[] args) throws Exception { - testCallbackApi(); - } - - private static class TestCallback implements SwInterfaceSetFlagsNotificationCallback, - WantInterfaceEventsCallback, SwInterfaceSetFlagsCallback { - - @Override - public void onSwInterfaceSetFlagsNotification( - final SwInterfaceSetFlagsNotification msg) { - printNotification(msg); - } - - @Override - public void onWantInterfaceEventsReply(final WantInterfaceEventsReply wantInterfaceEventsReply) { - System.out.println("Interface notification stream updated"); - } - - @Override - public void onSwInterfaceSetFlagsReply(final SwInterfaceSetFlagsReply swInterfaceSetFlagsReply) { - System.out.println("Interface flags set successfully"); - } - - @Override - public void onError(VppCallbackException ex) { - System.out.printf("Received onError exception in getNodeIndexCallback: call=%s, reply=%d, context=%d%n", - ex.getMethodName(), ex.getErrorCode(), ex.getCtxId()); - - } - } -} diff --git a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/ControlPingTest.java b/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/ControlPingTest.java deleted file mode 100644 index e97f4e3a..00000000 --- a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/ControlPingTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.core.test; - -import io.fd.vpp.jvpp.JVpp; -import io.fd.vpp.jvpp.JVppRegistry; -import io.fd.vpp.jvpp.JVppRegistryImpl; -import io.fd.vpp.jvpp.VppCallbackException; -import io.fd.vpp.jvpp.callback.ControlPingCallback; -import io.fd.vpp.jvpp.core.JVppCoreImpl; -import io.fd.vpp.jvpp.dto.ControlPing; -import io.fd.vpp.jvpp.dto.ControlPingReply; - -public class ControlPingTest { - - private static void testControlPing() throws Exception { - System.out.println("Testing ControlPing using Java callback API"); - try (JVppRegistry registry = new JVppRegistryImpl("ControlPingTest"); - JVpp jvpp = new JVppCoreImpl()) { - - registry.register(jvpp, new ControlPingCallback() { - @Override - public void onControlPingReply(final ControlPingReply reply) { - System.out.printf("Received ControlPingReply: %s%n", reply); - } - - @Override - public void onError(VppCallbackException ex) { - System.out.printf("Received onError exception: call=%s, reply=%d, context=%d ", ex.getMethodName(), - ex.getErrorCode(), ex.getCtxId()); - } - - }); - System.out.println("Successfully connected to VPP"); - Thread.sleep(1000); - - System.out.println("Sending control ping using JVppRegistry"); - registry.controlPing(jvpp.getClass()); - - Thread.sleep(2000); - - System.out.println("Sending control ping using JVpp plugin"); - jvpp.send(new ControlPing()); - - Thread.sleep(2000); - System.out.println("Disconnecting..."); - } - Thread.sleep(1000); - } - - public static void main(String[] args) throws Exception { - testControlPing(); - } -} diff --git a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CreateSubInterfaceTest.java b/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CreateSubInterfaceTest.java deleted file mode 100644 index a96258f4..00000000 --- a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/CreateSubInterfaceTest.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.core.test; - -import static java.util.Objects.requireNonNull; - -import io.fd.vpp.jvpp.JVppRegistry; -import io.fd.vpp.jvpp.JVppRegistryImpl; -import io.fd.vpp.jvpp.core.JVppCoreImpl; -import io.fd.vpp.jvpp.core.dto.CreateSubif; -import io.fd.vpp.jvpp.core.dto.CreateSubifReply; -import io.fd.vpp.jvpp.core.dto.SwInterfaceDetailsReplyDump; -import io.fd.vpp.jvpp.core.dto.SwInterfaceDump; -import io.fd.vpp.jvpp.core.future.FutureJVppCoreFacade; - -/** - *

Tests sub-interface creation.
Equivalent to:
- * - *

{@code
- * vppctl create sub GigabitEthernet0/9/0 1 dot1q 100 inner-dot1q any
- * }
- * 
- * - * To verify invoke:
- *
{@code
- * vpp_api_test json
- * vat# sw_interface_dump
- * }
- */
-public class CreateSubInterfaceTest {
-
-    private static SwInterfaceDump createSwInterfaceDumpRequest(final String ifaceName) {
-        SwInterfaceDump request = new SwInterfaceDump();
-        request.nameFilter = ifaceName.getBytes();
-        request.nameFilterValid = 1;
-        return request;
-    }
-
-    private static void requireSingleIface(final SwInterfaceDetailsReplyDump response, final String ifaceName) {
-        if (response.swInterfaceDetails.size() != 1) {
-            throw new IllegalStateException(
-                String.format("Expected one interface matching filter %s but was %d", ifaceName,
-                    response.swInterfaceDetails.size()));
-        }
-    }
-
-    private static CreateSubif createSubifRequest(final int swIfIndex, final int subId) {
-        CreateSubif request = new CreateSubif();
-        request.swIfIndex = swIfIndex; // super interface id
-        request.subId = subId;
-        request.noTags = 0;
-        request.oneTag = 0;
-        request.twoTags = 1;
-        request.dot1Ad = 0;
-        request.exactMatch = 1;
-        request.defaultSub = 0;
-        request.outerVlanIdAny = 0;
-        request.innerVlanIdAny = 1;
-        request.outerVlanId = 100;
-        request.innerVlanId = 0;
-        return request;
-    }
-
-    private static void print(CreateSubifReply reply) {
-        System.out.printf("CreateSubifReply: %s%n", reply);
-    }
-
-    private static void testCreateSubInterface() throws Exception {
-        System.out.println("Testing sub-interface creation using Java callback API");
-        try (final JVppRegistry registry = new JVppRegistryImpl("CreateSubInterface");
-             final FutureJVppCoreFacade jvppFacade = new FutureJVppCoreFacade(registry, new JVppCoreImpl())) {
-            System.out.println("Successfully connected to VPP");
-            Thread.sleep(1000);
-
-            final String ifaceName = "GigabitEthernet0/8/0";
-
-            final SwInterfaceDetailsReplyDump swInterfaceDetails =
-                jvppFacade.swInterfaceDump(createSwInterfaceDumpRequest(ifaceName)).toCompletableFuture().get();
-
-            requireNonNull(swInterfaceDetails, "swInterfaceDump returned null");
-            requireNonNull(swInterfaceDetails.swInterfaceDetails, "swInterfaceDetails is null");
-            requireSingleIface(swInterfaceDetails, ifaceName);
-
-            final int swIfIndex = swInterfaceDetails.swInterfaceDetails.get(0).swIfIndex;
-            final int subId = 1;
-
-            final CreateSubifReply createSubifReply =
-                jvppFacade.createSubif(createSubifRequest(swIfIndex, subId)).toCompletableFuture().get();
-            print(createSubifReply);
-
-            final String subIfaceName = "GigabitEthernet0/8/0." + subId;
-            final SwInterfaceDetailsReplyDump subIface =
-                jvppFacade.swInterfaceDump(createSwInterfaceDumpRequest(subIfaceName)).toCompletableFuture().get();
-            requireNonNull(swInterfaceDetails, "swInterfaceDump returned null");
-            requireNonNull(subIface.swInterfaceDetails, "swInterfaceDump returned null");
-            requireSingleIface(swInterfaceDetails, ifaceName);
-
-            System.out.println("Disconnecting...");
-        }
-        Thread.sleep(1000);
-    }
-
-    public static void main(String[] args) throws Exception {
-        testCreateSubInterface();
-    }
-}
diff --git a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/FutureApiNotificationTest.java b/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/FutureApiNotificationTest.java
deleted file mode 100644
index 9efeae19..00000000
--- a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/FutureApiNotificationTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.
- */
-
-package io.fd.vpp.jvpp.core.test;
-
-import static io.fd.vpp.jvpp.core.test.NotificationUtils.getChangeInterfaceState;
-import static io.fd.vpp.jvpp.core.test.NotificationUtils.getDisableInterfaceNotificationsReq;
-import static io.fd.vpp.jvpp.core.test.NotificationUtils.getEnableInterfaceNotificationsReq;
-
-import io.fd.vpp.jvpp.JVppRegistry;
-import io.fd.vpp.jvpp.JVppRegistryImpl;
-import io.fd.vpp.jvpp.core.JVppCoreImpl;
-import io.fd.vpp.jvpp.core.future.FutureJVppCoreFacade;
-
-public class FutureApiNotificationTest {
-
-    private static void testFutureApi() throws Exception {
-        System.out.println("Testing Java future API for notifications");
-        try (final JVppRegistry registry = new JVppRegistryImpl("FutureApiNotificationTest");
-             final FutureJVppCoreFacade jvppFacade = new FutureJVppCoreFacade(registry, new JVppCoreImpl());
-             final AutoCloseable notificationListenerReg =
-                 jvppFacade.getNotificationRegistry()
-                     .registerSwInterfaceSetFlagsNotificationCallback(NotificationUtils::printNotification)) {
-            System.out.println("Successfully connected to VPP");
-            jvppFacade.wantInterfaceEvents(getEnableInterfaceNotificationsReq()).toCompletableFuture().get();
-            System.out.println("Interface events started");
-
-            System.out.println("Changing interface configuration");
-            jvppFacade.swInterfaceSetFlags(getChangeInterfaceState()).toCompletableFuture().get();
-
-            Thread.sleep(1000);
-
-            jvppFacade.wantInterfaceEvents(getDisableInterfaceNotificationsReq()).toCompletableFuture().get();
-            System.out.println("Interface events stopped");
-            System.out.println("Disconnecting...");
-        }
-    }
-
-    public static void main(String[] args) throws Exception {
-        testFutureApi();
-    }
-}
diff --git a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/FutureApiTest.java b/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/FutureApiTest.java
deleted file mode 100644
index f478bab4..00000000
--- a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/FutureApiTest.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * 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.
- */
-
-package io.fd.vpp.jvpp.core.test;
-
-import io.fd.vpp.jvpp.JVppRegistry;
-import io.fd.vpp.jvpp.JVppRegistryImpl;
-import io.fd.vpp.jvpp.core.JVppCoreImpl;
-import io.fd.vpp.jvpp.core.dto.BridgeDomainDetailsReplyDump;
-import io.fd.vpp.jvpp.core.dto.BridgeDomainDump;
-import io.fd.vpp.jvpp.core.dto.GetNodeIndex;
-import io.fd.vpp.jvpp.core.dto.GetNodeIndexReply;
-import io.fd.vpp.jvpp.core.dto.ShowVersion;
-import io.fd.vpp.jvpp.core.dto.ShowVersionReply;
-import io.fd.vpp.jvpp.core.dto.SwInterfaceDetails;
-import io.fd.vpp.jvpp.core.dto.SwInterfaceDetailsReplyDump;
-import io.fd.vpp.jvpp.core.dto.SwInterfaceDump;
-import io.fd.vpp.jvpp.core.future.FutureJVppCoreFacade;
-import java.util.Objects;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.Future;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-public class FutureApiTest {
-
-    private static final Logger LOG = Logger.getLogger(FutureApiTest.class.getName());
-
-    private static void testShowVersion(final FutureJVppCoreFacade jvpp) throws Exception {
-        LOG.info("Sending ShowVersion request...");
-        final Future replyFuture = jvpp.showVersion(new ShowVersion()).toCompletableFuture();
-        final ShowVersionReply reply = replyFuture.get();
-        LOG.info(
-            String.format(
-                "Received ShowVersionReply: context=%d, program=%s, version=%s, buildDate=%s, buildDirectory=%s%n",
-                reply.context, new String(reply.program), new String(reply.version), new String(reply.buildDate),
-                new String(reply.buildDirectory)));
-    }
-
-    private static void testEmptyBridgeDomainDump(final FutureJVppCoreFacade jvpp) throws Exception {
-        LOG.info("Sending ShowVersion request...");
-        final BridgeDomainDump request = new BridgeDomainDump();
-        request.bdId = -1; // dump call
-
-        final CompletableFuture
-            replyFuture = jvpp.bridgeDomainDump(request).toCompletableFuture();
-        final BridgeDomainDetailsReplyDump reply = replyFuture.get();
-
-        if (reply == null || reply.bridgeDomainDetails == null) {
-            LOG.severe("Received null response for empty dump: " + reply);
-        } else {
-            LOG.info(
-                String.format(
-                    "Received empty bridge-domain dump reply with list of bridge-domains: %s, %s",
-                    reply.bridgeDomainDetails, reply.bridgeDomainSwIfDetails));
-        }
-    }
-
-    private static void testGetNodeIndex(final FutureJVppCoreFacade jvpp) {
-        LOG.info("Sending GetNodeIndex request...");
-        final GetNodeIndex request = new GetNodeIndex();
-        request.nodeName = "non-existing-node".getBytes();
-        final Future replyFuture = jvpp.getNodeIndex(request).toCompletableFuture();
-        try {
-            final GetNodeIndexReply reply = replyFuture.get();
-            LOG.info(
-                String.format(
-                    "Received GetNodeIndexReply: context=%d, nodeIndex=%d%n", reply.context, reply.nodeIndex));
-        } catch (Exception e) {
-            LOG.log(Level.SEVERE, "GetNodeIndex request failed", e);
-        }
-    }
-
-    private static void testSwInterfaceDump(final FutureJVppCoreFacade jvpp) throws Exception {
-        LOG.info("Sending SwInterfaceDump request...");
-        final SwInterfaceDump request = new SwInterfaceDump();
-        request.nameFilterValid = 0;
-        request.nameFilter = "".getBytes();
-
-        final Future replyFuture = jvpp.swInterfaceDump(request).toCompletableFuture();
-        final SwInterfaceDetailsReplyDump reply = replyFuture.get();
-        for (SwInterfaceDetails details : reply.swInterfaceDetails) {
-            Objects.requireNonNull(details, "reply.swInterfaceDetails contains null element!");
-            LOG.info(
-                String.format("Received SwInterfaceDetails: interfaceName=%s, l2AddressLength=%d, adminUpDown=%d, "
-                        + "linkUpDown=%d, linkSpeed=%d, linkMtu=%d%n",
-                    new String(details.interfaceName), details.l2AddressLength, details.adminUpDown,
-                    details.linkUpDown, details.linkSpeed, (int) details.linkMtu));
-        }
-    }
-
-    private static void testFutureApi() throws Exception {
-        LOG.info("Testing Java future API");
-        try (final JVppRegistry registry = new JVppRegistryImpl("FutureApiTest");
-             final FutureJVppCoreFacade jvppFacade = new FutureJVppCoreFacade(registry, new JVppCoreImpl())) {
-            LOG.info("Successfully connected to VPP");
-
-            testEmptyBridgeDomainDump(jvppFacade);
-            testShowVersion(jvppFacade);
-            testGetNodeIndex(jvppFacade);
-            testSwInterfaceDump(jvppFacade);
-
-            LOG.info("Disconnecting...");
-        }
-    }
-
-    public static void main(String[] args) throws Exception {
-        testFutureApi();
-    }
-}
diff --git a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/L2AclTest.java b/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/L2AclTest.java
deleted file mode 100644
index 6b3fa993..00000000
--- a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/L2AclTest.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * 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.
- */
-
-package io.fd.vpp.jvpp.core.test;
-
-import io.fd.vpp.jvpp.JVppRegistry;
-import io.fd.vpp.jvpp.JVppRegistryImpl;
-import io.fd.vpp.jvpp.core.JVppCoreImpl;
-import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
-import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSessionReply;
-import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
-import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTableReply;
-import io.fd.vpp.jvpp.core.dto.ClassifySessionDetailsReplyDump;
-import io.fd.vpp.jvpp.core.dto.ClassifySessionDump;
-import io.fd.vpp.jvpp.core.dto.ClassifyTableByInterface;
-import io.fd.vpp.jvpp.core.dto.ClassifyTableByInterfaceReply;
-import io.fd.vpp.jvpp.core.dto.ClassifyTableIds;
-import io.fd.vpp.jvpp.core.dto.ClassifyTableIdsReply;
-import io.fd.vpp.jvpp.core.dto.ClassifyTableInfo;
-import io.fd.vpp.jvpp.core.dto.ClassifyTableInfoReply;
-import io.fd.vpp.jvpp.core.dto.InputAclSetInterface;
-import io.fd.vpp.jvpp.core.dto.InputAclSetInterfaceReply;
-import io.fd.vpp.jvpp.core.future.FutureJVppCoreFacade;
-import javax.xml.bind.DatatypeConverter;
-
-/**
- * 

Tests L2 ACL creation and read.
Equivalent to the following vppctl commands:
- * - *

{@code
- * vppctl classify table mask l2 src
- * vppctl classify session acl-hit-next deny opaque-index 0 table-index 0 match l2 src 01:02:03:04:05:06
- * vppctl set int input acl intfc local0 l2-table 0
- * vppctl sh class table verbose
- * }
- * 
- */ -public class L2AclTest { - - private static final int LOCAL0_IFACE_ID = 0; - - private static ClassifyAddDelTable createClassifyTable() { - ClassifyAddDelTable request = new ClassifyAddDelTable(); - request.isAdd = 1; - request.tableIndex = ~0; // default - request.nbuckets = 2; - request.memorySize = 2 << 20; - request.nextTableIndex = ~0; // default - request.missNextIndex = ~0; // default - request.skipNVectors = 0; - request.matchNVectors = 1; - request.mask = - new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, 0x00, 0x00, 0x00, 0x00}; - return request; - } - - private static ClassifyTableInfo createClassifyTableInfoRequest(final int tableId) { - ClassifyTableInfo request = new ClassifyTableInfo(); - request.tableId = tableId; - return request; - } - - private static ClassifyAddDelSession createClassifySession(final int tableIndex) { - ClassifyAddDelSession request = new ClassifyAddDelSession(); - request.isAdd = 1; - request.tableIndex = tableIndex; - request.hitNextIndex = 0; // deny - request.opaqueIndex = 0; - request.advance = 0; // default - // match 01:02:03:04:05:06 mac address - request.match = - new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, - (byte) 0x05, (byte) 0x06, 0x00, 0x00, 0x00, 0x00}; - return request; - } - - private static ClassifySessionDump createClassifySessionDumpRequest(final int newTableIndex) { - ClassifySessionDump request = new ClassifySessionDump(); - request.tableId = newTableIndex; - return request; - } - - private static InputAclSetInterface aclSetInterface() { - InputAclSetInterface request = new InputAclSetInterface(); - request.isAdd = 1; - request.swIfIndex = LOCAL0_IFACE_ID; - request.ip4TableIndex = ~0; // skip - request.ip6TableIndex = ~0; // skip - request.l2TableIndex = 0; - return request; - } - - private static ClassifyTableByInterface createClassifyTableByInterfaceRequest() { - ClassifyTableByInterface request = new ClassifyTableByInterface(); - request.swIfIndex = LOCAL0_IFACE_ID; - return request; - } - - private static void print(ClassifyAddDelTableReply reply) { - System.out.printf("ClassifyAddDelTableReply: %s%n", reply); - } - - private static void print(ClassifyTableIdsReply reply) { - System.out.printf("ClassifyTableIdsReply: %s%n", reply); - } - - private static void print(final ClassifyTableInfoReply reply) { - System.out.println(reply); - if (reply != null) { - System.out.println("Mask hex: " + DatatypeConverter.printHexBinary(reply.mask)); - } - } - - private static void print(ClassifyAddDelSessionReply reply) { - System.out.printf("ClassifyAddDelSessionReply: context=%s%n", reply); - } - - private static void print(final ClassifySessionDetailsReplyDump reply) { - System.out.println(reply); - reply.classifySessionDetails.forEach(detail -> { - System.out.println(detail); - System.out.println("Match hex: " + DatatypeConverter.printHexBinary(detail.match)); - }); - } - - private static void print(final InputAclSetInterfaceReply reply) { - System.out.printf("InputAclSetInterfaceReply: context=%s%n", reply); - } - - private static void print(final ClassifyTableByInterfaceReply reply) { - System.out.printf("ClassifyAddDelTableReply: %s%n", reply); - } - - private static void testL2Acl() throws Exception { - System.out.println("Testing L2 ACLs using Java callback API"); - try (final JVppRegistry registry = new JVppRegistryImpl("L2AclTest"); - final FutureJVppCoreFacade jvppFacade = new FutureJVppCoreFacade(registry, new JVppCoreImpl())) { - - System.out.println("Successfully connected to VPP"); - Thread.sleep(1000); - - final ClassifyAddDelTableReply classifyAddDelTableReply = - jvppFacade.classifyAddDelTable(createClassifyTable()).toCompletableFuture().get(); - print(classifyAddDelTableReply); - - final ClassifyTableIdsReply classifyTableIdsReply = - jvppFacade.classifyTableIds(new ClassifyTableIds()).toCompletableFuture().get(); - print(classifyTableIdsReply); - - final ClassifyTableInfoReply classifyTableInfoReply = - jvppFacade.classifyTableInfo(createClassifyTableInfoRequest(classifyAddDelTableReply.newTableIndex)) - .toCompletableFuture().get(); - print(classifyTableInfoReply); - - final ClassifyAddDelSessionReply classifyAddDelSessionReply = - jvppFacade.classifyAddDelSession(createClassifySession(classifyAddDelTableReply.newTableIndex)) - .toCompletableFuture().get(); - print(classifyAddDelSessionReply); - - final ClassifySessionDetailsReplyDump classifySessionDetailsReplyDump = - jvppFacade.classifySessionDump(createClassifySessionDumpRequest(classifyAddDelTableReply.newTableIndex)) - .toCompletableFuture().get(); - print(classifySessionDetailsReplyDump); - - final InputAclSetInterfaceReply inputAclSetInterfaceReply = - jvppFacade.inputAclSetInterface(aclSetInterface()).toCompletableFuture().get(); - print(inputAclSetInterfaceReply); - - final ClassifyTableByInterfaceReply classifyTableByInterfaceReply = - jvppFacade.classifyTableByInterface(createClassifyTableByInterfaceRequest()).toCompletableFuture() - .get(); - print(classifyTableByInterfaceReply); - - System.out.println("Disconnecting..."); - } - Thread.sleep(1000); - } - - public static void main(String[] args) throws Exception { - testL2Acl(); - } -} diff --git a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/LispAdjacencyTest.java b/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/LispAdjacencyTest.java deleted file mode 100644 index d7f5039b..00000000 --- a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/LispAdjacencyTest.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.core.test; - -import io.fd.vpp.jvpp.JVppRegistry; -import io.fd.vpp.jvpp.JVppRegistryImpl; -import io.fd.vpp.jvpp.core.JVppCoreImpl; -import io.fd.vpp.jvpp.core.dto.LispAddDelAdjacency; -import io.fd.vpp.jvpp.core.dto.LispAddDelLocalEid; -import io.fd.vpp.jvpp.core.dto.LispAddDelLocatorSet; -import io.fd.vpp.jvpp.core.dto.LispAddDelRemoteMapping; -import io.fd.vpp.jvpp.core.dto.LispAdjacenciesGet; -import io.fd.vpp.jvpp.core.dto.LispAdjacenciesGetReply; -import io.fd.vpp.jvpp.core.dto.LispEnableDisable; -import io.fd.vpp.jvpp.core.future.FutureJVppCoreFacade; -import java.nio.charset.StandardCharsets; -import java.util.concurrent.ExecutionException; -import java.util.logging.Logger; - -/** - * Tests lisp adjacency creation and read (custom vpe.api type support showcase). - */ -public class LispAdjacencyTest { - - private static final Logger LOG = Logger.getLogger(LispAdjacencyTest.class.getName()); - - private static void enableLisp(final FutureJVppCoreFacade jvpp) throws ExecutionException, InterruptedException { - final LispEnableDisable request = new LispEnableDisable(); - request.isEn = 1; - jvpp.lispEnableDisable(request).toCompletableFuture().get(); - LOG.info("Lisp enabled successfully"); - } - - private static void addLocatorSet(final FutureJVppCoreFacade jvpp) throws ExecutionException, InterruptedException { - final LispAddDelLocatorSet request = new LispAddDelLocatorSet(); - request.isAdd = 1; - request.locatorSetName = "ls1".getBytes(StandardCharsets.UTF_8); - jvpp.lispAddDelLocatorSet(request).toCompletableFuture().get(); - LOG.info("Locator set created successfully:" + request.toString()); - } - - private static void addLocalEid(final FutureJVppCoreFacade jvpp) throws ExecutionException, InterruptedException { - final LispAddDelLocalEid request = new LispAddDelLocalEid(); - request.isAdd = 1; - request.locatorSetName = "ls1".getBytes(StandardCharsets.UTF_8); - request.eid = new byte[] {1, 2, 1, 10}; - request.eidType = 0; // ip4 - request.vni = 0; - request.prefixLen = 32; - jvpp.lispAddDelLocalEid(request).toCompletableFuture().get(); - LOG.info("Local EID created successfully:" + request.toString()); - } - - private static void addRemoteMapping(final FutureJVppCoreFacade jvpp) - throws ExecutionException, InterruptedException { - final LispAddDelRemoteMapping request = new LispAddDelRemoteMapping(); - request.isAdd = 1; - request.vni = 0; - request.eid = new byte[] {1, 2, 1, 20}; - request.eidLen = 32; - request.rlocNum = 1; - request.rlocs = new byte[] {1, 1, 1, 1, 2, 1, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - jvpp.lispAddDelRemoteMapping(request).toCompletableFuture().get(); - LOG.info("Remote mapping created successfully:" + request.toString()); - } - - private static void addAdjacency(final FutureJVppCoreFacade jvpp) throws ExecutionException, InterruptedException { - final LispAddDelAdjacency request = new LispAddDelAdjacency(); - request.isAdd = 1; - request.leid = new byte[] {1, 2, 1, 10}; - request.leidLen = 32; - request.reid = new byte[] {1, 2, 1, 20}; - request.reidLen = 32; - request.eidType = 0; // ip4 - request.vni = 0; - jvpp.lispAddDelAdjacency(request).toCompletableFuture().get(); - LOG.info("Lisp adjacency created successfully:" + request.toString()); - } - - private static void showAdjacencies(final FutureJVppCoreFacade jvpp) - throws ExecutionException, InterruptedException { - final LispAdjacenciesGetReply reply = - jvpp.lispAdjacenciesGet(new LispAdjacenciesGet()).toCompletableFuture().get(); - LOG.info("Lisp adjacency received successfully:" + reply.toString()); - } - - private static void testAdjacency(final FutureJVppCoreFacade jvpp) throws Exception { - enableLisp(jvpp); - addLocatorSet(jvpp); - addLocalEid(jvpp); - addRemoteMapping(jvpp); - addAdjacency(jvpp); - showAdjacencies(jvpp); - } - - private static void testFutureApi() throws Exception { - LOG.info("Create lisp adjacency test"); - try (final JVppRegistry registry = new JVppRegistryImpl("LispAdjacencyTest"); - final FutureJVppCoreFacade jvppFacade = new FutureJVppCoreFacade(registry, new JVppCoreImpl())) { - LOG.info("Successfully connected to VPP"); - - testAdjacency(jvppFacade); - LOG.info("Disconnecting..."); - } - } - - public static void main(String[] args) throws Exception { - testFutureApi(); - } -} diff --git a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/NotificationUtils.java b/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/NotificationUtils.java deleted file mode 100644 index f82946c3..00000000 --- a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/NotificationUtils.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.core.test; - -import java.io.PrintStream; -import io.fd.vpp.jvpp.core.dto.SwInterfaceSetFlags; -import io.fd.vpp.jvpp.core.dto.SwInterfaceSetFlagsNotification; -import io.fd.vpp.jvpp.core.dto.WantInterfaceEvents; - -final class NotificationUtils { - - private NotificationUtils() {} - - static PrintStream printNotification(final SwInterfaceSetFlagsNotification msg) { - return System.out.printf("Received interface notification: ifc: %s%n", msg); - } - - static SwInterfaceSetFlags getChangeInterfaceState() { - final SwInterfaceSetFlags swInterfaceSetFlags = new SwInterfaceSetFlags(); - swInterfaceSetFlags.swIfIndex = 0; - swInterfaceSetFlags.adminUpDown = 1; - swInterfaceSetFlags.deleted = 0; - return swInterfaceSetFlags; - } - - static WantInterfaceEvents getEnableInterfaceNotificationsReq() { - WantInterfaceEvents wantInterfaceEvents = new WantInterfaceEvents(); - wantInterfaceEvents.pid = 1; - wantInterfaceEvents.enableDisable = 1; - return wantInterfaceEvents; - } - - static WantInterfaceEvents getDisableInterfaceNotificationsReq() { - WantInterfaceEvents wantInterfaceEvents = new WantInterfaceEvents(); - wantInterfaceEvents.pid = 1; - wantInterfaceEvents.enableDisable = 0; - return wantInterfaceEvents; - } -} diff --git a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/Readme.txt b/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/Readme.txt deleted file mode 100644 index 1344dc9e..00000000 --- a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/Readme.txt +++ /dev/null @@ -1,17 +0,0 @@ -This package contains basic tests for jvpp. To run the tests: - -- Make sure VPP is running -- From VPP's build-root/ folder execute: - - sudo java -cp build-vpp-native/vpp-api/java/jvpp-registry-17.01.jar:build-vpp-native/vpp-api/java/jvpp-core-17.01.jar io.fd.vpp.jvpp.core.test.[test name] - -Available tests: -CallbackApiTest - Similar to ControlPingTest, invokes more complex calls (e.g. interface dump) using low level JVpp APIs -CallbackJVppFacadeNotificationTest - Tests interface notifications using Callback based JVpp facade -CallbackJVppFacadeTest - Execution of more complex calls using Callback based JVpp facade -CallbackNotificationApiTest - Tests interface notifications using low level JVpp APIs -ControlPingTest - Simple test executing a single control ping using low level JVpp APIs -CreateSubInterfaceTest - Tests sub-interface creation -FutureApiNotificationTest - Tests interface notifications using Future based JVpp facade -FutureApiTest - Execution of more complex calls using Future based JVpp facade -L2AclTest - Tests L2 ACL creation -LispAdjacencyTest - Tests lisp adjacency creation and read (custom vpe.api type support showcase) diff --git a/vpp-api/java/jvpp-core/jvpp_core.c b/vpp-api/java/jvpp-core/jvpp_core.c deleted file mode 100644 index ef4cb8e3..00000000 --- a/vpp-api/java/jvpp-core/jvpp_core.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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. - */ - -#include - -#include -#define vl_typedefs /* define message structures */ -#include -#undef vl_typedefs - -#define vl_endianfun -#include -#undef vl_endianfun - -#define vl_print(handle, ...) -#define vl_printfun -#include -#undef vl_printfun - -#include -#include -#include -#include - -#include - -// TODO: generate jvpp_plugin_name.c files (or at least reuse plugin's main structure) -typedef struct { - /* Base message index for the jvpp-core plugin */ - u16 msg_id_base; - - /* Pointer to shared memory queue */ - unix_shared_memory_queue_t * vl_input_queue; - - /* VPP api client index */ - u32 my_client_index; - - /* Callback object and class references enabling asynchronous Java calls */ - jobject callbackObject; - jclass callbackClass; - -} core_main_t; - -core_main_t core_main __attribute__((aligned (64))); - -#include "io_fd_vpp_jvpp_core_JVppCoreImpl.h" -#include "jvpp_core_gen.h" - -JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_core_JVppCoreImpl_init0 -(JNIEnv * env, jclass clazz, jobject callback, jlong queue_address, jint my_client_index) { - core_main_t * plugin_main = &core_main; - plugin_main->my_client_index = my_client_index; - plugin_main->vl_input_queue = (unix_shared_memory_queue_t *)queue_address; - - plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback); - plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback)); - - #define _(N,n) \ - vl_msg_api_set_handlers(VL_API_##N, #n, \ - vl_api_##n##_t_handler, \ - vl_noop_handler, \ - vl_noop_handler, \ - vl_noop_handler, \ - sizeof(vl_api_##n##_t), 1); - foreach_api_reply_handler; - #undef _ -} - -JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_core_JVppCoreImpl_close0 -(JNIEnv *env, jclass clazz) { - core_main_t * plugin_main = &core_main; - - // cleanup: - (*env)->DeleteGlobalRef(env, plugin_main->callbackClass); - (*env)->DeleteGlobalRef(env, plugin_main->callbackObject); - - plugin_main->callbackClass = NULL; - plugin_main->callbackObject = NULL; -} - -jint JNI_OnLoad(JavaVM *vm, void *reserved) { - JNIEnv* env; - - if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { - return JNI_EVERSION; - } - - if (cache_class_references(env) != 0) { - clib_warning ("Failed to cache class references\n"); - return JNI_ERR; - } - - return JNI_VERSION_1_8; -} - -void JNI_OnUnload(JavaVM *vm, void *reserved) { - JNIEnv* env; - if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { - return; - } - delete_class_references(env); -} - - - diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVpp.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVpp.java deleted file mode 100644 index 55f25a7b..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVpp.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp; - -import io.fd.vpp.jvpp.callback.JVppCallback; -import io.fd.vpp.jvpp.dto.ControlPing; -import io.fd.vpp.jvpp.dto.JVppRequest; - -/** - * Base interface for plugin's Java API. - */ -public interface JVpp extends AutoCloseable { - - /** - * Sends request to vpp. - * - * @param request request to be sent - * @return unique identifer of message in message queue - * @throws VppInvocationException when message could not be sent - */ - int send(final JVppRequest request) throws VppInvocationException; - - /** - * Initializes plugin's Java API. - * - * @param registry plugin registry - * @param callback called by vpe.api message handlers - * @param queueAddress address of vpp shared memory queue - * @param clientIndex vpp client identifier - */ - void init(final JVppRegistry registry, final JVppCallback callback, final long queueAddress, - final int clientIndex); - - /** - * Sends control_ping message. - * - * @param controlPing request DTO - * @return unique identifer of message in message queue - * @throws VppInvocationException when message could not be sent - */ - int controlPing(final ControlPing controlPing) throws VppInvocationException; -} diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVppRegistry.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVppRegistry.java deleted file mode 100644 index 6535db02..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVppRegistry.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp; - -import io.fd.vpp.jvpp.callback.JVppCallback; - -/** - * Manages VPP connection and stores plugin callbacks. - */ -public interface JVppRegistry extends AutoCloseable { - - /** - * Vpp connection managed by the registry. - * - * @return representation of vpp connection - */ - VppConnection getConnection(); - - /** - * Registers callback and initializes Java API for given plugin. - * - * @param jvpp plugin name - * @param callback callback provided by the plugin - * @throws NullPointerException if name or callback is null - * @throws IllegalArgumentException if plugin was already registered - */ - void register(final JVpp jvpp, final JVppCallback callback); - - /** - * Unregisters callback for the given plugin. - * - * @param name plugin name - * @throws NullPointerException if name is null - * @throws IllegalArgumentException if plugin was not registered - */ - void unregister(final String name); - - /** - * Returns callback registered for the plugin. - * - * @param name plugin name - * @return callback provided by the plugin - * @throws NullPointerException if name is null - * @throws IllegalArgumentException if plugin was not registered - */ - JVppCallback get(final String name); - - /** - * Sends control ping. Reply handler calls callback registered for give plugin. - * - * Control ping is used for initial RX thread to Java thread attachment - * that takes place in the plugin's JNI lib - * and to wrap dump message replies in one list. - * - * VPP plugins don't have to provide special control ping, therefore - * it is necessary to providing control ping support in JVppRegistry. - - * @param clazz identifies plugin that should receive ping callback - * @return unique identifier of message in message queue - */ - int controlPing(final Class clazz) throws VppInvocationException; -} diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVppRegistryImpl.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVppRegistryImpl.java deleted file mode 100644 index 98ef1c15..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/JVppRegistryImpl.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp; - -import static java.util.Objects.requireNonNull; - -import io.fd.vpp.jvpp.callback.ControlPingCallback; -import io.fd.vpp.jvpp.callback.JVppCallback; -import io.fd.vpp.jvpp.dto.ControlPingReply; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Default implementation of JVppRegistry. - */ -public final class JVppRegistryImpl implements JVppRegistry, ControlPingCallback { - - private static final Logger LOG = Logger.getLogger(JVppRegistryImpl.class.getName()); - - private final VppJNIConnection connection; - // Unguarded concurrent map, no race conditions expected on top of that - private final Map pluginRegistry; - // Guarded by self - private final Map pingCalls; - - public JVppRegistryImpl(final String clientName) throws IOException { - connection = new VppJNIConnection(clientName); - connection.connect(); - pluginRegistry = new ConcurrentHashMap<>(); - pingCalls = new HashMap<>(); - } - - @Override - public VppConnection getConnection() { - return connection; - } - - @Override - public void register(final JVpp jvpp, final JVppCallback callback) { - requireNonNull(jvpp, "jvpp should not be null"); - requireNonNull(callback, "Callback should not be null"); - final String name = jvpp.getClass().getName(); - if (pluginRegistry.containsKey(name)) { - throw new IllegalArgumentException( - String.format("Callback for plugin %s was already registered", name)); - } - jvpp.init(this, callback, connection.getConnectionInfo().queueAddress, - connection.getConnectionInfo().clientIndex); - pluginRegistry.put(name, callback); - } - - @Override - public void unregister(final String name) { - requireNonNull(name, "Plugin name should not be null"); - final JVppCallback previous = pluginRegistry.remove(name); - assertPluginWasRegistered(name, previous); - } - - @Override - public JVppCallback get(final String name) { - requireNonNull(name, "Plugin name should not be null"); - JVppCallback value = pluginRegistry.get(name); - assertPluginWasRegistered(name, value); - return value; - } - - private native int controlPing0() throws VppInvocationException; - - @Override - public int controlPing(final Class clazz) throws VppInvocationException { - connection.checkActive(); - final String name = clazz.getName(); - - final ControlPingCallback callback = (ControlPingCallback) pluginRegistry.get(clazz.getName()); - assertPluginWasRegistered(name, callback); - - synchronized (pingCalls) { - int context = controlPing0(); - if (context < 0) { - throw new VppInvocationException("controlPing", context); - } - - pingCalls.put(context, callback); - return context; - } - } - - @Override - public void onControlPingReply(final ControlPingReply reply) { - final ControlPingCallback callback; - synchronized (pingCalls) { - callback = pingCalls.remove(reply.context); - if (callback == null) { - LOG.log(Level.WARNING, "No callback was registered for reply context=" + reply.context + " Contexts waiting=" - + pingCalls.keySet()); - return; - } - } - // pass the reply to the callback registered by the ping caller - callback.onControlPingReply(reply); - } - - @Override - public void onError(final VppCallbackException ex) { - final int ctxId = ex.getCtxId(); - final ControlPingCallback callback; - - synchronized (pingCalls) { - callback = pingCalls.get(ctxId); - } - if (callback == null) { - LOG.log(Level.WARNING, "No callback was registered for reply id={0} ", ctxId); - return; - } - // pass the error to the callback registered by the ping caller - callback.onError(ex); - } - - private static void assertPluginWasRegistered(final String name, final JVppCallback value) { - if (value == null) { - throw new IllegalArgumentException(String.format("Callback for plugin %s is not registered", name)); - } - } - - @Override - public void close() throws Exception { - connection.close(); - } -} diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/NativeLibraryLoader.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/NativeLibraryLoader.java deleted file mode 100644 index ce6d1bfc..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/NativeLibraryLoader.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.nio.file.attribute.PosixFilePermission; -import java.nio.file.attribute.PosixFilePermissions; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Utility class for loading JNI libraries. - */ -public final class NativeLibraryLoader { - - private static final Logger LOG = Logger.getLogger(NativeLibraryLoader.class.getName()); - - private NativeLibraryLoader() { - throw new UnsupportedOperationException("This utility class cannot be instantiated."); - } - - /** - * Loads JNI library using class loader of the given class. - * - * @param libName name of the library to be loaded - */ - public static void loadLibrary(final String libName, final Class clazz) throws IOException { - java.util.Objects.requireNonNull(libName, "libName should not be null"); - java.util.Objects.requireNonNull(clazz, "clazz should not be null"); - try (final InputStream is = clazz.getResourceAsStream('/' + libName)) { - if (is == null) { - throw new IOException("Failed to open library resource " + libName); - } - loadStream(libName, is); - } - } - - private static void loadStream(final String libName, final InputStream is) throws IOException { - final Set perms = PosixFilePermissions.fromString("rwxr-x---"); - final Path p = Files.createTempFile(libName, null, PosixFilePermissions.asFileAttribute(perms)); - try { - Files.copy(is, p, StandardCopyOption.REPLACE_EXISTING); - Runtime.getRuntime().load(p.toString()); - } catch (Exception e) { - throw new IOException("Failed to load library " + p, e); - } finally { - try { - Files.deleteIfExists(p); - } catch (IOException e) { - LOG.log(Level.WARNING, String.format("Failed to delete temporary file %s.", p), e); - } - } - } -} diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppBaseCallException.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppBaseCallException.java deleted file mode 100644 index d71e3055..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppBaseCallException.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp; - -/** - * Base exception representing failed operation of JVpp request call - */ -public abstract class VppBaseCallException extends Exception { - private final String methodName; - private final int errorCode; - - /** - * Constructs an VppCallbackException with the specified api method name and error code. - * - * @param methodName name of a method, which invocation or execution failed - * @param errorCode negative error code value associated with this failure - * @throws NullPointerException if apiMethodName is null - */ - public VppBaseCallException(final String methodName, final int errorCode) { - super(String.format("vppApi.%s failed with error code: %d", methodName, errorCode)); - this.methodName = java.util.Objects.requireNonNull(methodName, "apiMethodName is null!"); - this.errorCode = errorCode; - if(errorCode >= 0) { - throw new IllegalArgumentException("Error code must be < 0. Was " + errorCode + - " for " + methodName ); - } - } - - /** - * Returns name of a method, which invocation failed. - * - * @return method name - */ - public String getMethodName() { - return methodName; - } - - /** - * Returns the error code associated with this failure. - * - * @return a negative integer error code - */ - public int getErrorCode() { - return errorCode; - } -} diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppCallbackException.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppCallbackException.java deleted file mode 100644 index ccfcbd3c..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppCallbackException.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp; - -/** - * Callback Exception representing failed operation of JVpp request call - */ -public class VppCallbackException extends VppBaseCallException { - private final int ctxId; - - /** - * Constructs an VppCallbackException with the specified api method name and error code. - * - * @param methodName name of a method, which invocation failed. - * @param ctxId api request context identifier - * @param errorCode negative error code value associated with this failure - * @throws NullPointerException if apiMethodName is null - */ - public VppCallbackException(final String methodName, final int ctxId, final int errorCode ){ - super(methodName, errorCode); - this.ctxId = ctxId; - } - - /** - * Returns api request context identifier. - * - * @return value of context identifier - */ - public int getCtxId() { - return ctxId; - } - -} diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppConnection.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppConnection.java deleted file mode 100644 index e6fd3bdb..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppConnection.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp; - -import java.io.IOException; - -/** - * Representation of a management connection to VPP. - */ -public interface VppConnection extends AutoCloseable { - - /** - * Opens VppConnection for communication with VPP. - * - * @throws IOException if connection is not established - */ - void connect() throws IOException; - - /** - * Checks if this instance connection is active. - * - * @throws IllegalStateException if this instance was disconnected. - */ - void checkActive(); - - /** - * Closes Vpp connection. - */ - @Override - void close(); -} diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppInvocationException.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppInvocationException.java deleted file mode 100644 index a7ccb197..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppInvocationException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp; - -/** - * Exception thrown when Vpp jAPI method invocation failed. - */ -public class VppInvocationException extends VppBaseCallException { - /** - * Constructs an VppApiInvocationFailedException with the specified api method name and error code. - * - * @param methodName name of a method, which invocation failed. - * @param errorCode negative error code value associated with this failure - * @throws NullPointerException if apiMethodName is null - */ - public VppInvocationException(final String methodName, final int errorCode) { - super(methodName, errorCode); - } -} diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppJNIConnection.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppJNIConnection.java deleted file mode 100644 index 7178bcf7..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/VppJNIConnection.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp; - -import static io.fd.vpp.jvpp.NativeLibraryLoader.loadLibrary; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * JNI based representation of a management connection to VPP. - */ -public final class VppJNIConnection implements VppConnection { - private static final Logger LOG = Logger.getLogger(VppJNIConnection.class.getName()); - - static { - final String libName = "libjvpp_registry.so.0.0.0"; - try { - loadLibrary(libName, VppJNIConnection.class); - } catch (IOException e) { - LOG.log(Level.SEVERE, String.format("Can't find vpp jni library: %s", libName), e); - throw new ExceptionInInitializerError(e); - } - } - - private ConnectionInfo connectionInfo; - - private final String clientName; - private volatile boolean disconnected = false; - - /** - * Create VPPJNIConnection instance for client connecting to VPP. - * - * @param clientName client name instance to be used for communication. Single connection per clientName is - * allowed. - */ - public VppJNIConnection(final String clientName) { - this.clientName = Objects.requireNonNull(clientName, "Null clientName"); - } - - /** - * Guarded by VppJNIConnection.class - */ - private static final Map connections = new HashMap<>(); - - /** - * Initiate VPP connection for current instance - * - * Multiple instances are allowed since this class is not a singleton (VPP allows multiple management connections). - * - * However only a single connection per clientName is allowed. - * - * @throws IOException in case the connection could not be established - */ - - @Override - public void connect() throws IOException { - _connect(); - } - - private void _connect() throws IOException { - synchronized (VppJNIConnection.class) { - if (connections.containsKey(clientName)) { - throw new IOException("Client " + clientName + " already connected"); - } - - connectionInfo = clientConnect(clientName); - if (connectionInfo.status != 0) { - throw new IOException("Connection returned error " + connectionInfo.status); - } - connections.put(clientName, this); - } - } - - @Override - public final void checkActive() { - if (disconnected) { - throw new IllegalStateException("Disconnected client " + clientName); - } - } - - @Override - public final synchronized void close() { - if (!disconnected) { - disconnected = true; - try { - clientDisconnect(); - } finally { - synchronized (VppJNIConnection.class) { - connections.remove(clientName); - } - } - } - } - - public ConnectionInfo getConnectionInfo() { - return connectionInfo; - } - - /** - * VPP connection information used by plugins to reuse the connection. - */ - public static final class ConnectionInfo { - public final long queueAddress; - public final int clientIndex; - public final int status; // FIXME throw exception instead - - public ConnectionInfo(long queueAddress, int clientIndex, int status) { - this.queueAddress = queueAddress; - this.clientIndex = clientIndex; - this.status = status; - } - } - - private static native ConnectionInfo clientConnect(String clientName); - - private static native void clientDisconnect(); - -} diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/ControlPingCallback.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/ControlPingCallback.java deleted file mode 100644 index efddfdbb..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/ControlPingCallback.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.callback; - -import io.fd.vpp.jvpp.dto.ControlPingReply; - -/** - * Represents callback for control_ping message. - */ -public interface ControlPingCallback extends JVppCallback { - - void onControlPingReply(ControlPingReply reply); - -} - diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/JVppCallback.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/JVppCallback.java deleted file mode 100644 index ae02063b..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/JVppCallback.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.callback; -import io.fd.vpp.jvpp.VppCallbackException; - -/** - * Base JVppCallback interface - */ -public interface JVppCallback { - /** - * onError callback handler used to report failing operation - * @param ex VppCallbackException object containing details about failing operation - */ - void onError(VppCallbackException ex); -} diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/JVppNotificationCallback.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/JVppNotificationCallback.java deleted file mode 100644 index 8ab0cb21..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/callback/JVppNotificationCallback.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.callback; - -/** -* Notification callback -*/ -public interface JVppNotificationCallback { - -} diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/ControlPing.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/ControlPing.java deleted file mode 100644 index 984e1674..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/ControlPing.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.dto; - -import io.fd.vpp.jvpp.JVpp; -import io.fd.vpp.jvpp.VppInvocationException; - -/** - * Represents request DTO for control_ping message. - */ -public final class ControlPing implements JVppRequest { - - @Override - public int send(final JVpp jvpp) throws VppInvocationException { - return jvpp.controlPing(this); - } - -} - - diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/ControlPingReply.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/ControlPingReply.java deleted file mode 100644 index 61e4d0e4..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/ControlPingReply.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.dto; - -import java.util.Objects; - -/** - * Represents reply DTO for control_ping message. - */ -public final class ControlPingReply implements JVppReply { - - public int context; - public int clientIndex; - public int vpePid; - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - final ControlPingReply that = (ControlPingReply) o; - return context == that.context && - clientIndex == that.clientIndex && - vpePid == that.vpePid; - } - - @Override - public int hashCode() { - return Objects.hash(context, clientIndex, vpePid); - } - - @Override - public String toString() { - return "ControlPingReply{" + - "context=" + context + - ", clientIndex=" + clientIndex + - ", vpePid=" + vpePid + - '}'; - } -} - diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppDump.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppDump.java deleted file mode 100644 index 60b98984..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppDump.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.dto; - -/** -* Base interface for all dump requests -*/ -public interface JVppDump extends JVppRequest { - -} diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppNotification.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppNotification.java deleted file mode 100644 index 5554f501..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppNotification.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.dto; - -/** -* Base interface for all notification DTOs -*/ -public interface JVppNotification { -} diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppReply.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppReply.java deleted file mode 100644 index 73f512d4..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppReply.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.dto; - -/** -* Base interface for all reply DTOs -*/ -public interface JVppReply { - -} diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppReplyDump.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppReplyDump.java deleted file mode 100644 index 15111395..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppReplyDump.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.dto; - -/** -* Base interface for all dump replies -*/ -public interface JVppReplyDump> - extends JVppReply { - -} diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppRequest.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppRequest.java deleted file mode 100644 index 9b301da2..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/dto/JVppRequest.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.dto; - -import io.fd.vpp.jvpp.JVpp; -import io.fd.vpp.jvpp.VppInvocationException; - -/** -* Base interface for all request DTOs -*/ -public interface JVppRequest { - - /** - * Invoke current operation asynchronously on VPP - * - * @return context id of this request. Can be used to track incoming response - */ - int send(JVpp jvpp) throws VppInvocationException; - -} diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/future/AbstractFutureJVppInvoker.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/future/AbstractFutureJVppInvoker.java deleted file mode 100644 index e7df528a..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/future/AbstractFutureJVppInvoker.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.future; - - -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import io.fd.vpp.jvpp.JVpp; -import io.fd.vpp.jvpp.JVppRegistry; -import io.fd.vpp.jvpp.VppInvocationException; -import io.fd.vpp.jvpp.dto.JVppDump; -import io.fd.vpp.jvpp.dto.JVppReply; -import io.fd.vpp.jvpp.dto.JVppReplyDump; -import io.fd.vpp.jvpp.dto.JVppRequest; - -/** - * Future facade on top of JVpp - */ -public abstract class AbstractFutureJVppInvoker implements FutureJVppInvoker { - - private final JVpp jvpp; - private final JVppRegistry registry; - - /** - * Guarded by self - */ - private final Map>> requests; - - protected AbstractFutureJVppInvoker(final JVpp jvpp, final JVppRegistry registry, - final Map>> requestMap) { - this.jvpp = Objects.requireNonNull(jvpp, "jvpp should not be null"); - this.registry = Objects.requireNonNull(registry, "registry should not be null"); - // Request map represents the shared state between this facade and it's callback - // where facade puts futures in and callback completes + removes them - this.requests = Objects.requireNonNull(requestMap, "Null requestMap"); - } - - protected final Map>> getRequests() { - synchronized (requests) { - return requests; - } - } - - // TODO use Optional in Future, java8 - - @Override - @SuppressWarnings("unchecked") - public > CompletionStage send(REQ req) { - synchronized(requests) { - try { - final CompletableFuture replyCompletableFuture; - final int contextId = jvpp.send(req); - - if(req instanceof JVppDump) { - throw new IllegalArgumentException("Send with empty reply dump has to be used in case of dump calls"); - } - replyCompletableFuture = new CompletableFuture<>(); - requests.put(contextId, replyCompletableFuture); - - // TODO in case of timeouts/missing replies, requests from the map are not removed - // consider adding cancel method, that would remove requests from the map and cancel - // associated replyCompletableFuture - - return replyCompletableFuture; - } catch (VppInvocationException ex) { - final CompletableFuture replyCompletableFuture = new CompletableFuture<>(); - replyCompletableFuture.completeExceptionally(ex); - return replyCompletableFuture; - } - } - } - - @Override - @SuppressWarnings("unchecked") - public , DUMP extends JVppReplyDump> CompletionStage send( - REQ req, DUMP emptyReplyDump) { - synchronized(requests) { - try { - final CompletableDumpFuture replyCompletableFuture; - final int contextId = jvpp.send(req); - - if(!(req instanceof JVppDump)) { - throw new IllegalArgumentException("Send without empty reply dump has to be used in case of regular calls"); - } - replyCompletableFuture = new CompletableDumpFuture<>(contextId, emptyReplyDump); - - requests.put(contextId, replyCompletableFuture); - requests.put(registry.controlPing(jvpp.getClass()), replyCompletableFuture); - - // TODO in case of timeouts/missing replies, requests from the map are not removed - // consider adding cancel method, that would remove requests from the map and cancel - // associated replyCompletableFuture - - return replyCompletableFuture; - } catch (VppInvocationException ex) { - final CompletableFuture replyCompletableFuture = new CompletableFuture<>(); - replyCompletableFuture.completeExceptionally(ex); - return replyCompletableFuture; - } - } - } - - public static final class CompletableDumpFuture> extends CompletableFuture { - private final T replyDump; - private final int contextId; - - public CompletableDumpFuture(final int contextId, final T emptyDump) { - this.contextId = contextId; - this.replyDump = emptyDump; - } - - public int getContextId() { - return contextId; - } - - public T getReplyDump() { - return replyDump; - } - } - - @Override - public void close() throws Exception { - jvpp.close(); - } -} diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/future/FutureJVppInvoker.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/future/FutureJVppInvoker.java deleted file mode 100644 index 7a48e418..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/future/FutureJVppInvoker.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.future; - - -import io.fd.vpp.jvpp.dto.JVppReply; -import io.fd.vpp.jvpp.dto.JVppReplyDump; -import io.fd.vpp.jvpp.dto.JVppRequest; - -import java.util.concurrent.CompletionStage; -import io.fd.vpp.jvpp.notification.NotificationRegistryProvider; - -/** -* Future facade on top of JVpp -*/ -public interface FutureJVppInvoker extends NotificationRegistryProvider, AutoCloseable { - - /** - * Invoke asynchronous operation on VPP - * - * @return CompletionStage with future result of an async VPP call - * @throws io.fd.vpp.jvpp.VppInvocationException when send request failed with details - */ - > CompletionStage send(REQ req); - - - /** - * Invoke asynchronous dump operation on VPP - * - * @return CompletionStage with aggregated future result of an async VPP dump call - * @throws io.fd.vpp.jvpp.VppInvocationException when send request failed with details - */ - , DUMP extends JVppReplyDump> CompletionStage send( - REQ req, DUMP emptyReplyDump); -} diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/notification/NotificationRegistry.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/notification/NotificationRegistry.java deleted file mode 100644 index 3c72ff79..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/notification/NotificationRegistry.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.notification; - -/** - * Base registry for notification callbacks. - */ -public interface NotificationRegistry extends AutoCloseable { - - void close(); -} diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/notification/NotificationRegistryProvider.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/notification/NotificationRegistryProvider.java deleted file mode 100644 index 4a6e06b7..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/notification/NotificationRegistryProvider.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.notification; - -/** - * Provides notification registry - */ -public interface NotificationRegistryProvider { - - /** - * Get current notification registry instance - */ - NotificationRegistry getNotificationRegistry(); -} diff --git a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/test/ConnectionTest.java b/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/test/ConnectionTest.java deleted file mode 100644 index 27b4d29f..00000000 --- a/vpp-api/java/jvpp-registry/io/fd/vpp/jvpp/test/ConnectionTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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. - */ - -package io.fd.vpp.jvpp.test; - -import io.fd.vpp.jvpp.JVppRegistry; -import io.fd.vpp.jvpp.JVppRegistryImpl; - -/** - * Run using: - * sudo java -cp build-vpp-native/vpp-api/java/jvpp-registry-16.09.jar io.fd.vpp.jvpp.test.ConnectionTest - */ -public class ConnectionTest { - - private static void testConnect() throws Exception { - System.out.println("Testing JNI connection with JVppRegistry"); - final JVppRegistry registry = new JVppRegistryImpl("ConnectionTest"); - try { - System.out.println("Successfully connected to vpp"); - Thread.sleep(5000); - System.out.println("Disconnecting..."); - Thread.sleep(1000); - } finally { - registry.close(); - } - } - - public static void main(String[] args) throws Exception { - testConnect(); - } -} diff --git a/vpp-api/java/jvpp-registry/jvpp_registry.c b/vpp-api/java/jvpp-registry/jvpp_registry.c deleted file mode 100644 index cbd5e0ab..00000000 --- a/vpp-api/java/jvpp-registry/jvpp_registry.c +++ /dev/null @@ -1,352 +0,0 @@ -/* - * 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. - */ -#define _GNU_SOURCE /* for strcasestr(3) */ -#include - -#define vl_api_version(n,v) static u32 vpe_api_version = (v); -#include -#undef vl_api_version - - -#include -#include -#include "io_fd_vpp_jvpp_VppJNIConnection.h" -#include "io_fd_vpp_jvpp_JVppRegistryImpl.h" - -#include -#define vl_typedefs /* define message structures */ -#include -#undef vl_typedefs - -#define vl_endianfun -#include -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) -#define vl_printfun -#include -#undef vl_printfun - -vlib_main_t vlib_global_main; -vlib_main_t **vlib_mains; - -/* - * The Java runtime isn't compile w/ -fstack-protector, - * so we have to supply missing external references for the - * regular vpp libraries. - */ -void __stack_chk_guard(void) __attribute__((weak)); -void __stack_chk_guard(void) { -} - -typedef struct { - /* UThread attachment */ - volatile u32 control_ping_result_ready; - volatile i32 control_ping_retval; - - /* Control poing callback */ - jobject registryObject; - jclass registryClass; - jclass controlPingReplyClass; - jclass callbackExceptionClass; - - /* Thread cleanup */ - pthread_key_t cleanup_rx_thread_key; - - /* Connected indication */ - volatile u8 is_connected; -} jvpp_registry_main_t; - -jvpp_registry_main_t jvpp_registry_main __attribute__((aligned (64))); - -void vl_client_add_api_signatures(vl_api_memclnt_create_t *mp) { - /* - * Send the main API signature in slot 0. This bit of code must - * match the checks in ../vpe/api/api.c: vl_msg_api_version_check(). - */ - mp->api_versions[0] = clib_host_to_net_u32(vpe_api_version); -} - -/* cleanup handler for RX thread */ -static_always_inline void cleanup_rx_thread(void *arg) { - jvpp_main_t * jm = &jvpp_main; - jvpp_registry_main_t * rm = &jvpp_registry_main; - - vppjni_lock(jm, 99); - - int getEnvStat = (*jm->jvm)->GetEnv(jm->jvm, (void **) &(jm->jenv), - JNI_VERSION_1_8); - if (getEnvStat == JNI_EVERSION) { - clib_warning("Unsupported JNI version\n"); - rm->control_ping_retval = VNET_API_ERROR_UNSUPPORTED_JNI_VERSION; - goto out; - } else if (getEnvStat != JNI_EDETACHED) { - (*jm->jvm)->DetachCurrentThread(jm->jvm); - } - out: vppjni_unlock(jm); -} - -static void vl_api_control_ping_reply_t_handler( - vl_api_control_ping_reply_t * mp) { - jvpp_main_t * jm = &jvpp_main; - jvpp_registry_main_t * rm = &jvpp_registry_main; - char was_thread_connected = 0; - - // attach to java thread if not attached - int getEnvStat = (*jm->jvm)->GetEnv(jm->jvm, (void **) &(jm->jenv), - JNI_VERSION_1_8); - if (getEnvStat == JNI_EDETACHED) { - if ((*jm->jvm)->AttachCurrentThread(jm->jvm, (void **) &(jm->jenv), - NULL) != 0) { - clib_warning("Failed to attach thread\n"); - rm->control_ping_retval = - VNET_API_ERROR_FAILED_TO_ATTACH_TO_JAVA_THREAD; - goto out; - } - - // workaround as we can't use pthread_cleanup_push - pthread_key_create(&rm->cleanup_rx_thread_key, cleanup_rx_thread); - // destructor is only called if the value of key is non null - pthread_setspecific(rm->cleanup_rx_thread_key, (void *) 1); - was_thread_connected = 1; - } else if (getEnvStat == JNI_EVERSION) { - clib_warning("Unsupported JNI version\n"); - rm->control_ping_retval = VNET_API_ERROR_UNSUPPORTED_JNI_VERSION; - goto out; - } - - if (was_thread_connected == 0) { - JNIEnv *env = jm->jenv; - if (mp->retval < 0) { - call_on_error("controlPing", mp->context, mp->retval, - rm->registryClass, rm->registryObject, - rm->callbackExceptionClass); - } else { - jmethodID constructor = (*env)->GetMethodID(env, - rm->controlPingReplyClass, "", "()V"); - jmethodID callbackMethod = (*env)->GetMethodID(env, - rm->registryClass, "onControlPingReply", - "(Lio/fd/vpp/jvpp/dto/ControlPingReply;)V"); - - jobject dto = (*env)->NewObject(env, rm->controlPingReplyClass, - constructor); - - jfieldID contextFieldId = (*env)->GetFieldID(env, - rm->controlPingReplyClass, "context", "I"); - (*env)->SetIntField(env, dto, contextFieldId, - clib_net_to_host_u32(mp->context)); - - jfieldID clientIndexFieldId = (*env)->GetFieldID(env, - rm->controlPingReplyClass, "clientIndex", "I"); - (*env)->SetIntField(env, dto, clientIndexFieldId, - clib_net_to_host_u32(mp->client_index)); - - jfieldID vpePidFieldId = (*env)->GetFieldID(env, - rm->controlPingReplyClass, "vpePid", "I"); - (*env)->SetIntField(env, dto, vpePidFieldId, - clib_net_to_host_u32(mp->vpe_pid)); - - (*env)->CallVoidMethod(env, rm->registryObject, callbackMethod, - dto); - (*env)->DeleteLocalRef(env, dto); - } - } - - out: rm->control_ping_result_ready = 1; -} - -static int send_initial_control_ping() { - f64 timeout; - clib_time_t clib_time; - vl_api_control_ping_t * mp; - jvpp_main_t * jm = &jvpp_main; - jvpp_registry_main_t * rm = &jvpp_registry_main; - - clib_time_init(&clib_time); - - rm->control_ping_result_ready = 0; - mp = vl_msg_api_alloc(sizeof(*mp)); - memset(mp, 0, sizeof(*mp)); - mp->_vl_msg_id = ntohs(VL_API_CONTROL_PING); - mp->client_index = jm->my_client_index; - - // send message: - vl_msg_api_send_shmem(jm->vl_input_queue, (u8 *) &mp); - - // wait for results: Current time + 10 seconds is the timeout - timeout = clib_time_now(&clib_time) + 10.0; - int rv = VNET_API_ERROR_RESPONSE_NOT_READY; - while (clib_time_now(&clib_time) < timeout) { - if (rm->control_ping_result_ready == 1) { - rv = rm->control_ping_retval; - break; - } - } - - if (rv != 0) { - clib_warning("common: first control ping failed: %d", rv); - } - - return rv; -} - -static int connect_to_vpe(char *name) { - jvpp_main_t * jm = &jvpp_main; - api_main_t * am = &api_main; - - if (vl_client_connect_to_vlib("/vpe-api", name, 32) < 0) - return -1; - - jm->my_client_index = am->my_client_index; - - jm->vl_input_queue = am->shmem_hdr->vl_input_queue; - - vl_msg_api_set_handlers(VL_API_CONTROL_PING_REPLY, "control_ping_reply", - vl_api_control_ping_reply_t_handler, vl_noop_handler, - vl_api_control_ping_reply_t_endian, - vl_api_control_ping_reply_t_print, - sizeof(vl_api_control_ping_reply_t), 1); - - return send_initial_control_ping(); -} - -JNIEXPORT jobject JNICALL Java_io_fd_vpp_jvpp_VppJNIConnection_clientConnect( - JNIEnv *env, jclass obj, jstring clientName) { - int rv; - const char *client_name; - void vl_msg_reply_handler_hookup(void); - jvpp_main_t * jm = &jvpp_main; - jvpp_registry_main_t * rm = &jvpp_registry_main; - - jclass connectionInfoClass = (*env)->FindClass(env, - "io/fd/vpp/jvpp/VppJNIConnection$ConnectionInfo"); - jmethodID connectionInfoConstructor = (*env)->GetMethodID(env, - connectionInfoClass, "", "(JII)V"); - - /* - * Bail out now if we're not running as root - */ - if (geteuid() != 0) { - return (*env)->NewObject(env, connectionInfoClass, - connectionInfoConstructor, 0, 0, - VNET_API_ERROR_NOT_RUNNING_AS_ROOT); - } - - if (rm->is_connected) { - return (*env)->NewObject(env, connectionInfoClass, - connectionInfoConstructor, 0, 0, - VNET_API_ERROR_ALREADY_CONNECTED); - } - - client_name = (*env)->GetStringUTFChars(env, clientName, 0); - if (!client_name) { - return (*env)->NewObject(env, connectionInfoClass, - connectionInfoConstructor, 0, 0, VNET_API_ERROR_INVALID_VALUE); - } - - rv = connect_to_vpe((char *) client_name); - - if (rv < 0) - clib_warning("connection failed, rv %d", rv); - - (*env)->ReleaseStringUTFChars(env, clientName, client_name); - - return (*env)->NewObject(env, connectionInfoClass, - connectionInfoConstructor, (jlong) jm->vl_input_queue, - (jint) jm->my_client_index, (jint) rv); -} - -JNIEXPORT jint JNICALL Java_io_fd_vpp_jvpp_JVppRegistryImpl_controlPing0( - JNIEnv *env, jobject regstryObject) { - jvpp_main_t * jm = &jvpp_main; - vl_api_control_ping_t * mp; - u32 my_context_id = vppjni_get_context_id(&jvpp_main); - jvpp_registry_main_t * rm = &jvpp_registry_main; - - if (rm->registryObject == 0) { - rm->registryObject = (*env)->NewGlobalRef(env, regstryObject); - } - if (rm->registryClass == 0) { - rm->registryClass = (jclass) (*env)->NewGlobalRef(env, - (*env)->GetObjectClass(env, regstryObject)); - } - - mp = vl_msg_api_alloc(sizeof(*mp)); - memset(mp, 0, sizeof(*mp)); - mp->_vl_msg_id = ntohs(VL_API_CONTROL_PING); - mp->client_index = jm->my_client_index; - mp->context = clib_host_to_net_u32(my_context_id); - - // send message: - vl_msg_api_send_shmem(jm->vl_input_queue, (u8 *) &mp); - return my_context_id; -} - -JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_VppJNIConnection_clientDisconnect( - JNIEnv *env, jclass clazz) { - jvpp_registry_main_t * rm = &jvpp_registry_main; - rm->is_connected = 0; // TODO make thread safe - vl_client_disconnect_from_vlib(); - - // cleanup: - if (rm->registryObject) { - (*env)->DeleteGlobalRef(env, rm->registryObject); - rm->registryObject = 0; - } - if (rm->registryClass) { - (*env)->DeleteGlobalRef(env, rm->registryClass); - rm->registryClass = 0; - } -} - -jint JNI_OnLoad(JavaVM *vm, void *reserved) { - jvpp_main_t * jm = &jvpp_main; - jvpp_registry_main_t * rm = &jvpp_registry_main; - JNIEnv* env; - - if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { - return JNI_EVERSION; - } - - rm->controlPingReplyClass = (jclass) (*env)->NewGlobalRef(env, - (*env)->FindClass(env, "io/fd/vpp/jvpp/dto/ControlPingReply")); - if ((*env)->ExceptionCheck(env)) { - (*env)->ExceptionDescribe(env); - clib_warning("Failed to cache class references\n"); - return JNI_ERR; - } - - rm->callbackExceptionClass = (jclass) (*env)->NewGlobalRef(env, - (*env)->FindClass(env, "io/fd/vpp/jvpp/VppCallbackException")); - if ((*env)->ExceptionCheck(env)) { - (*env)->ExceptionDescribe(env); - return JNI_ERR; - } - - jm->jvm = vm; - return JNI_VERSION_1_8; -} - -void JNI_OnUnload(JavaVM *vm, void *reserved) { - jvpp_main_t * jm = &jvpp_main; - JNIEnv* env; - if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { - return; - } - - jm->jenv = NULL; - jm->jvm = NULL; -} diff --git a/vpp-api/java/jvpp/gen/jvpp_gen.py b/vpp-api/java/jvpp/gen/jvpp_gen.py deleted file mode 100755 index 5f8df2a9..00000000 --- a/vpp-api/java/jvpp/gen/jvpp_gen.py +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/env python -# -# 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 -# l -# 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. -# - -import argparse -import importlib -import sys -import os -import json - -from jvppgen import types_gen -from jvppgen import callback_gen -from jvppgen import notification_gen -from jvppgen import dto_gen -from jvppgen import jvpp_callback_facade_gen -from jvppgen import jvpp_future_facade_gen -from jvppgen import jvpp_impl_gen -from jvppgen import jvpp_c_gen -from jvppgen import util - -blacklist = [ "memclnt.api", "flowperpkt.api" ] - -# Invocation: -# ~/Projects/vpp/vpp-api/jvpp/gen$ mkdir -p java/io/fd/vpp/jvpp && cd java/io/fd/vpp/jvpp -# ~/Projects/vpp/vpp-api/jvpp/gen/java/io/fd/vpp/jvpp$ ../../../../jvpp_gen.py -idefs_api_vpp_papi.py -# -# Compilation: -# ~/Projects/vpp/vpp-api/jvpp/gen/java/io/fd/vpp/jvpp$ javac *.java dto/*.java callback/*.java -# -# where -# defs_api_vpp_papi.py - vpe.api in python format (generated by vppapigen) - -parser = argparse.ArgumentParser(description='VPP Java API generator') -parser.add_argument('-i', action="store", dest="inputfiles", nargs='+') -parser.add_argument('--plugin_name', action="store", dest="plugin_name") -args = parser.parse_args() - -sys.path.append(".") - -print "Generating Java API for %s" % args.inputfiles -print "inputfiles %s" % args.inputfiles -plugin_name = args.plugin_name -print "plugin_name %s" % plugin_name - -cfg = {} - -for inputfile in args.inputfiles: - if any(substring in inputfile for substring in blacklist): - print "WARNING: Imput file %s blacklisted" % inputfile - continue - _cfg = json.load(open(inputfile, 'r')) - if 'types' in cfg: - cfg['types'].extend(_cfg['types']) - else: - cfg['types'] = _cfg['types'] - if 'messages' in cfg: - cfg['messages'].extend(_cfg['messages']) - else: - cfg['messages'] = _cfg['messages'] - - -def is_request_field(field_name): - return field_name not in {'_vl_msg_id', 'client_index', 'context'} - - -def is_response_field(field_name): - return field_name not in {'_vl_msg_id'} - - -def get_args(t, filter): - arg_list = [] - for i in t: - if is_crc(i): - continue - if not filter(i[1]): - continue - arg_list.append(i[1]) - return arg_list - - -def get_types(t, filter): - types_list = [] - lengths_list = [] - crc = None - for i in t: - if is_crc(i): - crc = ('crc', i['crc'][2:]) - continue - if not filter(i[1]): - continue - if len(i) is 3: # array type - types_list.append(i[0] + '[]') - lengths_list.append((i[2], False)) - elif len(i) is 4: # variable length array type - types_list.append(i[0] + '[]') - lengths_list.append((i[3], True)) - else: # primitive type - types_list.append(i[0]) - lengths_list.append((0, False)) - return types_list, lengths_list, crc - - -def is_crc(arg): - """ Check whether the argument inside message definition is just crc """ - return 'crc' in arg - - -def get_definitions(defs): - # Pass 1 - func_list = [] - func_name = {} - for a in defs: - java_name = util.underscore_to_camelcase(a[0]) - - # For replies include all the arguments except message_id - if util.is_reply(java_name): - types, lengths, crc = get_types(a[1:], is_response_field) - func_name[a[0]] = dict( - [('name', a[0]), ('java_name', java_name), - ('args', get_args(a[1:], is_response_field)), ('full_args', get_args(a[1:], lambda x: True)), - ('types', types), ('lengths', lengths), crc]) - # For requests skip message_id, client_id and context - else: - types, lengths, crc = get_types(a[1:], is_request_field) - func_name[a[0]] = dict( - [('name', a[0]), ('java_name', java_name), - ('args', get_args(a[1:], is_request_field)), ('full_args', get_args(a[1:], lambda x: True)), - ('types', types), ('lengths', lengths), crc]) - - # Indexed by name - func_list.append(func_name[a[0]]) - return func_list, func_name - - -base_package = 'io.fd.vpp.jvpp' -plugin_package = base_package + '.' + plugin_name -types_package = 'types' -dto_package = 'dto' -callback_package = 'callback' -notification_package = 'notification' -future_package = 'future' -# TODO find better package name -callback_facade_package = 'callfacade' - -types_list, types_name = get_definitions(cfg['types']) - -types_gen.generate_types(types_list, plugin_package, types_package, args.inputfiles) - -func_list, func_name = get_definitions(cfg['messages']) - -dto_gen.generate_dtos(func_list, base_package, plugin_package, plugin_name.title(), dto_package, args.inputfiles) -jvpp_impl_gen.generate_jvpp(func_list, base_package, plugin_package, plugin_name, dto_package, args.inputfiles) -callback_gen.generate_callbacks(func_list, base_package, plugin_package, plugin_name.title(), callback_package, dto_package, args.inputfiles) -notification_gen.generate_notification_registry(func_list, base_package, plugin_package, plugin_name.title(), notification_package, callback_package, dto_package, args.inputfiles) -jvpp_c_gen.generate_jvpp(func_list, plugin_name, args.inputfiles) -jvpp_future_facade_gen.generate_jvpp(func_list, base_package, plugin_package, plugin_name.title(), dto_package, callback_package, notification_package, future_package, args.inputfiles) -jvpp_callback_facade_gen.generate_jvpp(func_list, base_package, plugin_package, plugin_name.title(), dto_package, callback_package, notification_package, callback_facade_package, args.inputfiles) - -print "Java API for %s generated successfully" % args.inputfiles diff --git a/vpp-api/java/jvpp/gen/jvppgen/__init__.py b/vpp-api/java/jvpp/gen/jvppgen/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/vpp-api/java/jvpp/gen/jvppgen/callback_gen.py b/vpp-api/java/jvpp/gen/jvppgen/callback_gen.py deleted file mode 100644 index 68f70126..00000000 --- a/vpp-api/java/jvpp/gen/jvppgen/callback_gen.py +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env python -# -# 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. - -import os -import util -from string import Template - -from util import remove_suffix - -callback_suffix = "Callback" - -callback_template = Template(""" -package $plugin_package.$callback_package; - -/** - *

Represents callback for plugin's api file message. - *
It was generated by callback_gen.py based on $inputfile preparsed data: - *

-$docs
- * 
- */ -public interface $cls_name extends $base_package.$callback_package.$callback_type { - - $callback_method - -} -""") - -global_callback_template = Template(""" -package $plugin_package.$callback_package; - -/** - *

Global aggregated callback interface. - *
It was generated by callback_gen.py based on $inputfile - *
(python representation of api file generated by vppapigen). - */ -public interface JVpp${plugin_name}GlobalCallback extends $base_package.$callback_package.ControlPingCallback, $callbacks { -} -""") - - -def generate_callbacks(func_list, base_package, plugin_package, plugin_name, callback_package, dto_package, inputfile): - """ Generates callback interfaces """ - print "Generating Callback interfaces" - - if not os.path.exists(callback_package): - raise Exception("%s folder is missing" % callback_package) - - callbacks = [] - for func in func_list: - - camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name']) - - if util.is_ignored(func['name']) or util.is_control_ping(camel_case_name_with_suffix): - continue - if not util.is_reply(camel_case_name_with_suffix) and not util.is_notification(func['name']): - continue - - if util.is_reply(camel_case_name_with_suffix): - camel_case_name = util.remove_reply_suffix(camel_case_name_with_suffix) - callback_type = "JVppCallback" - else: - camel_case_name_with_suffix = util.add_notification_suffix(camel_case_name_with_suffix) - camel_case_name = camel_case_name_with_suffix - callback_type = "JVppNotificationCallback" - - callbacks.append("{0}.{1}.{2}".format(plugin_package, callback_package, camel_case_name + callback_suffix)) - callback_path = os.path.join(callback_package, camel_case_name + callback_suffix + ".java") - callback_file = open(callback_path, 'w') - - reply_type = "%s.%s.%s" % (plugin_package, dto_package, camel_case_name_with_suffix) - method = "void on{0}({1} reply);".format(camel_case_name_with_suffix, reply_type) - callback_file.write( - callback_template.substitute(inputfile=inputfile, - docs=util.api_message_to_javadoc(func), - cls_name=camel_case_name + callback_suffix, - callback_method=method, - base_package=base_package, - plugin_package=plugin_package, - callback_package=callback_package, - callback_type=callback_type)) - callback_file.flush() - callback_file.close() - - callback_file = open(os.path.join(callback_package, "JVpp%sGlobalCallback.java" % plugin_name), 'w') - callback_file.write(global_callback_template.substitute(inputfile=inputfile, - callbacks=", ".join(callbacks), - base_package=base_package, - plugin_package=plugin_package, - plugin_name=plugin_name, - callback_package=callback_package)) - callback_file.flush() - callback_file.close() diff --git a/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py b/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py deleted file mode 100644 index a043c945..00000000 --- a/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py +++ /dev/null @@ -1,308 +0,0 @@ -#!/usr/bin/env python -# -# 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. - -import os -from string import Template - -import util - -dto_template = Template(""" -package $plugin_package.$dto_package; - -/** - *

This class represents $description. - *
It was generated by dto_gen.py based on $inputfile preparsed data: - *

-$docs
- * 
- */ -public final class $cls_name implements $base_package.$dto_package.$base_type { - -$fields -$methods -} -""") - -field_template = Template(""" public $type $name;\n""") - -send_template = Template(""" @Override - public int send(final $base_package.JVpp jvpp) throws io.fd.vpp.jvpp.VppInvocationException { - return (($plugin_package.JVpp${plugin_name})jvpp).$method_name($args); - }""") - - -def generate_dtos(func_list, base_package, plugin_package, plugin_name, dto_package, inputfile): - """ Generates dto objects in a dedicated package """ - print "Generating DTOs" - - if not os.path.exists(dto_package): - raise Exception("%s folder is missing" % dto_package) - - for func in func_list: - camel_case_dto_name = util.underscore_to_camelcase_upper(func['name']) - camel_case_method_name = util.underscore_to_camelcase(func['name']) - dto_path = os.path.join(dto_package, camel_case_dto_name + ".java") - - if util.is_ignored(func['name']) or util.is_control_ping(camel_case_dto_name): - continue - - fields = generate_dto_fields(camel_case_dto_name, func) - methods = generate_dto_base_methods(camel_case_dto_name, func) - base_type = "" - - # Generate request/reply or dump/dumpReply even if structure can be used as notification - if not util.is_just_notification(func["name"]): - if util.is_reply(camel_case_dto_name): - description = "reply DTO" - request_dto_name = get_request_name(camel_case_dto_name, func['name']) - if util.is_details(camel_case_dto_name): - # FIXME assumption that dump calls end with "Dump" suffix. Not enforced in vpe.api - base_type += "JVppReply<%s.%s.%s>" % (plugin_package, dto_package, request_dto_name + "Dump") - generate_dump_reply_dto(request_dto_name, base_package, plugin_package, dto_package, - camel_case_dto_name, camel_case_method_name, func) - else: - base_type += "JVppReply<%s.%s.%s>" % (plugin_package, dto_package, request_dto_name) - else: - args = "" if fields is "" else "this" - methods += send_template.substitute(method_name=camel_case_method_name, - base_package=base_package, - plugin_package=plugin_package, - plugin_name=plugin_name, - args=args) - if util.is_dump(camel_case_dto_name): - base_type += "JVppDump" - description = "dump request DTO" - else: - base_type += "JVppRequest" - description = "request DTO" - - write_dto_file(base_package, plugin_package, base_type, camel_case_dto_name, description, dto_package, - dto_path, fields, func, inputfile, methods) - - # for structures that are also used as notifications, generate dedicated notification DTO - if util.is_notification(func["name"]): - base_type = "JVppNotification" - description = "notification DTO" - camel_case_dto_name = util.add_notification_suffix(camel_case_dto_name) - dto_path = os.path.join(dto_package, camel_case_dto_name + ".java") - methods = generate_dto_base_methods(camel_case_dto_name, func) - write_dto_file(base_package, plugin_package, base_type, camel_case_dto_name, description, dto_package, - dto_path, fields, func, inputfile, methods) - - flush_dump_reply_dtos(inputfile) - - -def generate_dto_base_methods(camel_case_dto_name, func): - methods = generate_dto_hash(func) - methods += generate_dto_equals(camel_case_dto_name, func) - methods += generate_dto_tostring(camel_case_dto_name, func) - return methods - - -def generate_dto_fields(camel_case_dto_name, func): - fields = "" - for t in zip(func['types'], func['args']): - # for retval don't generate dto field in Reply - field_name = util.underscore_to_camelcase(t[1]) - if util.is_reply(camel_case_dto_name) and util.is_retval_field(field_name): - continue - fields += field_template.substitute(type=util.jni_2_java_type_mapping[t[0]], - name=field_name) - return fields - - -tostring_field_template = Template(""" \"$field_name=\" + $field_name + ", " +\n""") -tostring_array_field_template = Template(""" \"$field_name=\" + java.util.Arrays.toString($field_name) + ", " +\n""") -tostring_template = Template(""" @Override - public String toString() { - return "$cls_name{" + -$fields_tostring "}"; - }\n\n""") - - -def generate_dto_tostring(camel_case_dto_name, func): - tostring_fields = "" - for t in zip(func['types'], func['args']): - - field_name = util.underscore_to_camelcase(t[1]) - # for retval don't generate dto field in Reply - if util.is_retval_field(field_name): - continue - - # handle array types - if util.is_array(util.jni_2_java_type_mapping[t[0]]): - tostring_fields += tostring_array_field_template.substitute(field_name=field_name) - else: - tostring_fields += tostring_field_template.substitute(field_name=field_name) - - return tostring_template.substitute(cls_name=camel_case_dto_name, - fields_tostring=tostring_fields[:-8]) - -equals_other_template = Template(""" - final $cls_name other = ($cls_name) o; -\n""") -equals_field_template = Template(""" if (!java.util.Objects.equals(this.$field_name, other.$field_name)) { - return false; - }\n""") -equals_array_field_template = Template(""" if (!java.util.Arrays.equals(this.$field_name, other.$field_name)) { - return false; - }\n""") -equals_template = Template(""" @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } -$comparisons - return true; - }\n\n""") - - -def generate_dto_equals(camel_case_dto_name, func): - equals_fields = "" - for t in zip(func['types'], func['args']): - field_name = util.underscore_to_camelcase(t[1]) - # for retval don't generate dto field in Reply - if util.is_retval_field(field_name): - continue - - # handle array types - if util.is_array(util.jni_2_java_type_mapping[t[0]]): - equals_fields += equals_array_field_template.substitute(field_name=field_name) - else: - equals_fields += equals_field_template.substitute(field_name=field_name) - - if equals_fields != "": - equals_fields = equals_other_template.substitute(cls_name=camel_case_dto_name) + equals_fields - - return equals_template.substitute(comparisons=equals_fields) - - -hash_template = Template(""" @Override - public int hashCode() { - return java.util.Objects.hash($fields); - }\n\n""") -hash_single_array_type_template = Template(""" @Override - public int hashCode() { - return java.util.Arrays.hashCode($fields); - }\n\n""") - - -def generate_dto_hash(func): - hash_fields = "" - - # Special handling for hashCode in case just a single array field is present. Cannot use Objects.equals since the - # array is mistaken for a varargs parameter. Instead use Arrays.hashCode in such case. - if len(func['args']) == 1: - single_type = func['types'][0] - single_type_name = func['args'][0] - if util.is_array(util.jni_2_java_type_mapping[single_type]): - return hash_single_array_type_template.substitute(fields=util.underscore_to_camelcase(single_type_name)) - - for t in zip(func['types'], func['args']): - field_name = util.underscore_to_camelcase(t[1]) - # for retval don't generate dto field in Reply - if util.is_retval_field(field_name): - continue - - hash_fields += field_name + ", " - - return hash_template.substitute(fields=hash_fields[:-2]) - - -def write_dto_file(base_package, plugin_package, base_type, camel_case_dto_name, description, dto_package, dto_path, - fields, func, inputfile, methods): - dto_file = open(dto_path, 'w') - dto_file.write(dto_template.substitute(inputfile=inputfile, - description=description, - docs=util.api_message_to_javadoc(func), - cls_name=camel_case_dto_name, - fields=fields, - methods=methods, - base_package=base_package, - plugin_package=plugin_package, - base_type=base_type, - dto_package=dto_package)) - dto_file.flush() - dto_file.close() - - -dump_dto_suffix = "ReplyDump" -dump_reply_artificial_dtos = {} - - -# Returns request name or special one from unconventional_naming_rep_req map -def get_request_name(camel_case_dto_name, func_name): - return util.underscore_to_camelcase_upper( - util.unconventional_naming_rep_req[func_name]) if func_name in util.unconventional_naming_rep_req \ - else util.remove_reply_suffix(camel_case_dto_name) - - -def flush_dump_reply_dtos(inputfile): - for dump_reply_artificial_dto in dump_reply_artificial_dtos.values(): - dto_path = os.path.join(dump_reply_artificial_dto['dto_package'], - dump_reply_artificial_dto['cls_name'] + ".java") - dto_file = open(dto_path, 'w') - dto_file.write(dto_template.substitute(inputfile=inputfile, - description="dump reply wrapper", - docs=dump_reply_artificial_dto['docs'], - cls_name=dump_reply_artificial_dto['cls_name'], - fields=dump_reply_artificial_dto['fields'], - methods=dump_reply_artificial_dto['methods'], - plugin_package=dump_reply_artificial_dto['plugin_package'], - base_package=dump_reply_artificial_dto['base_package'], - base_type=dump_reply_artificial_dto['base_type'], - dto_package=dump_reply_artificial_dto['dto_package'])) - dto_file.flush() - dto_file.close() - - -def generate_dump_reply_dto(request_dto_name, base_package, plugin_package, dto_package, camel_case_dto_name, - camel_case_method_name, func): - base_type = "JVppReplyDump<%s.%s.%s, %s.%s.%s>" % ( - plugin_package, dto_package, util.remove_reply_suffix(camel_case_dto_name) + "Dump", - plugin_package, dto_package, camel_case_dto_name) - fields = " public java.util.List<%s> %s = new java.util.ArrayList<>();" % (camel_case_dto_name, camel_case_method_name) - cls_name = camel_case_dto_name + dump_dto_suffix - # using artificial type for fields, just to bypass the is_array check in base methods generators - # the type is not really used - artificial_type = 'u8' - - # In case of already existing artificial reply dump DTO, just update it - # Used for sub-dump dtos - if request_dto_name in dump_reply_artificial_dtos.keys(): - dump_reply_artificial_dtos[request_dto_name]['fields'] += '\n' + fields - dump_reply_artificial_dtos[request_dto_name]['field_names'].append(func['name']) - dump_reply_artificial_dtos[request_dto_name]['field_types'].append(artificial_type) - methods = '\n' + generate_dto_base_methods(dump_reply_artificial_dtos[request_dto_name]['cls_name'], - {'args': dump_reply_artificial_dtos[request_dto_name]['field_names'], - 'types': dump_reply_artificial_dtos[request_dto_name]['field_types']}) - dump_reply_artificial_dtos[request_dto_name]['methods'] = methods - else: - methods = '\n' + generate_dto_base_methods(cls_name, {'args': [func['name']], - 'types': [artificial_type]}) - dump_reply_artificial_dtos[request_dto_name] = ({'docs': util.api_message_to_javadoc(func), - 'cls_name': cls_name, - 'fields': fields, - 'field_names': [func['name']], - 'field_types': [artificial_type], - # strip too many newlines at the end of base method block - 'methods': methods, - 'plugin_package': plugin_package, - 'base_package': base_package, - 'base_type': base_type, - 'dto_package': dto_package}) diff --git a/vpp-api/java/jvpp/gen/jvppgen/jni_gen.py b/vpp-api/java/jvpp/gen/jvppgen/jni_gen.py deleted file mode 100644 index 328cc8d3..00000000 --- a/vpp-api/java/jvpp/gen/jvppgen/jni_gen.py +++ /dev/null @@ -1,295 +0,0 @@ -#!/usr/bin/env python -# -# 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. - -from string import Template - -import util - -variable_length_array_value_template = Template("""mp->${length_var_name}""") -variable_length_array_template = Template("""clib_net_to_host_${length_field_type}(${value})""") - -dto_field_id_template = Template(""" - jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${field_name}", "${jni_signature}");""") - -default_dto_field_setter_template = Template(""" - (*env)->Set${jni_setter}(env, ${object_name}, ${field_reference_name}FieldId, mp->${c_name}); -""") - -variable_length_array_value_template = Template("""mp->${length_var_name}""") -variable_length_array_template = Template("""clib_net_to_host_${length_field_type}(${value})""") - -u16_dto_field_setter_template = Template(""" - (*env)->Set${jni_setter}(env, ${object_name}, ${field_reference_name}FieldId, clib_net_to_host_u16(mp->${c_name})); -""") - -u32_dto_field_setter_template = Template(""" - (*env)->Set${jni_setter}(env, ${object_name}, ${field_reference_name}FieldId, clib_net_to_host_u32(mp->${c_name})); -""") - -u64_dto_field_setter_template = Template(""" - (*env)->Set${jni_setter}(env, ${object_name}, ${field_reference_name}FieldId, clib_net_to_host_u64(mp->${c_name})); -""") - -u8_array_dto_field_setter_template = Template(""" - jbyteArray ${field_reference_name} = (*env)->NewByteArray(env, ${field_length}); - (*env)->SetByteArrayRegion(env, ${field_reference_name}, 0, ${field_length}, (const jbyte*)mp->${c_name}); - (*env)->SetObjectField(env, ${object_name}, ${field_reference_name}FieldId, ${field_reference_name}); - (*env)->DeleteLocalRef(env, ${field_reference_name}); -""") - -u16_array_dto_field_setter_template = Template(""" - { - jshortArray ${field_reference_name} = (*env)->NewShortArray(env, ${field_length}); - jshort * ${field_reference_name}ArrayElements = (*env)->GetShortArrayElements(env, ${field_reference_name}, NULL); - unsigned int _i; - for (_i = 0; _i < ${field_length}; _i++) { - ${field_reference_name}ArrayElements[_i] = clib_net_to_host_u16(mp->${c_name}[_i]); - } - - (*env)->ReleaseShortArrayElements(env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0); - (*env)->SetObjectField(env, ${object_name}, ${field_reference_name}FieldId, ${field_reference_name}); - (*env)->DeleteLocalRef(env, ${field_reference_name}); - } -""") - -u32_array_dto_field_setter_template = Template(""" - { - jintArray ${field_reference_name} = (*env)->NewIntArray(env, ${field_length}); - jint * ${field_reference_name}ArrayElements = (*env)->GetIntArrayElements(env, ${field_reference_name}, NULL); - unsigned int _i; - for (_i = 0; _i < ${field_length}; _i++) { - ${field_reference_name}ArrayElements[_i] = clib_net_to_host_u32(mp->${c_name}[_i]); - } - - (*env)->ReleaseIntArrayElements(env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0); - (*env)->SetObjectField(env, ${object_name}, ${field_reference_name}FieldId, ${field_reference_name}); - (*env)->DeleteLocalRef(env, ${field_reference_name}); - } -""") - -# For each u64 array we get its elements. Then we convert values to host byte order. -# All changes to jlong* buffer are written to jlongArray (isCopy is set to NULL) -u64_array_dto_field_setter_template = Template(""" - { - jlongArray ${field_reference_name} = (*env)->NewLongArray(env, ${field_length}); - jlong * ${field_reference_name}ArrayElements = (*env)->GetLongArrayElements(env, ${field_reference_name}, NULL); - unsigned int _i; - for (_i = 0; _i < ${field_length}; _i++) { - ${field_reference_name}ArrayElements[_i] = clib_net_to_host_u64(mp->${c_name}[_i]); - } - - (*env)->ReleaseLongArrayElements(env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0); - (*env)->SetObjectField(env, ${object_name}, ${field_reference_name}FieldId, ${field_reference_name}); - (*env)->DeleteLocalRef(env, ${field_reference_name}); - } -""") - -dto_field_setter_templates = {'u8': default_dto_field_setter_template, - 'u16': u16_dto_field_setter_template, - 'u32': u32_dto_field_setter_template, - 'i32': u32_dto_field_setter_template, - 'u64': u64_dto_field_setter_template, - 'f64': default_dto_field_setter_template, # fixme - 'u8[]': u8_array_dto_field_setter_template, - 'u16[]': u16_array_dto_field_setter_template, - 'u32[]': u32_array_dto_field_setter_template, - 'u64[]': u64_array_dto_field_setter_template - } - - -def jni_reply_handler_for_type(handler_name, ref_name, field_type, c_name, field_reference_name, - field_name, field_length, is_variable_len_array, length_field_type, - object_name="dto"): - """ - Generates jni code that initializes a field of java object (dto or custom type). - To be used in reply message handlers. - :param field_type: type of the field to be initialized (as defined in vpe.api) - :param c_name: name of the message struct member that stores initialization value - :param field_reference_name: name of the field reference in generated code - :param field_name: name of the field (camelcase) - :param field_length: integer or name of variable that stores field length - :param object_name: name of the object to be initialized - """ - - # todo move validation to vppapigen - if field_type.endswith('[]') and field_length == '0': - raise Exception('Variable array \'%s\' defined in \'%s\' ' - 'should have defined length (e.g. \'%s[%s_length]\'' - % (c_name, handler_name, c_name, c_name)) - - if is_variable_len_array: - length_var_name = field_length - field_length = variable_length_array_value_template.substitute(length_var_name=length_var_name) - if length_field_type != 'u8': # we need net to host conversion: - field_length = variable_length_array_template.substitute( - length_field_type=length_field_type, value=field_length) - - # for retval don't generate setters - if util.is_retval_field(c_name): - return "" - - jni_signature = util.jni_2_signature_mapping[field_type] - jni_setter = util.jni_field_accessors[field_type] - - result = dto_field_id_template.substitute( - field_reference_name=field_reference_name, - field_name=field_name, - class_ref_name=ref_name, - jni_signature=jni_signature) - - dto_setter_template = dto_field_setter_templates[field_type] - - result += dto_setter_template.substitute( - jni_signature=jni_signature, - object_name=object_name, - field_reference_name=field_reference_name, - c_name=c_name, - jni_setter=jni_setter, - field_length=field_length) - return result - - -request_field_identifier_template = Template(""" - jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${object_name}Class, "${field_name}", "${jni_signature}"); - ${jni_type} ${field_reference_name} = (*env)->Get${jni_getter}(env, ${object_name}, ${field_reference_name}FieldId); - """) - -array_length_enforcement_template = Template(""" - size_t max_size = ${field_length}; - if (cnt > max_size) cnt = max_size;""") - -u8_struct_setter_template = Template(""" - mp->${c_name} = ${field_reference_name};""") - -u16_struct_setter_template = Template(""" - mp->${c_name} = clib_host_to_net_u16(${field_reference_name});""") - -u32_struct_setter_template = Template(""" - mp->${c_name} = clib_host_to_net_u32(${field_reference_name});""") - -i32_struct_setter_template = Template(""" - mp->${c_name} = clib_host_to_net_i32(${field_reference_name});!""") - -u64_struct_setter_template = Template(""" - mp->${c_name} = clib_host_to_net_u64(${field_reference_name});""") - -array_length_enforcement_template = Template(""" - size_t max_size = ${field_length}; - if (cnt > max_size) cnt = max_size;""") - -u8_array_struct_setter_template = Template(""" - if (${field_reference_name}) { - jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name}); - ${field_length_check} - (*env)->GetByteArrayRegion(env, ${field_reference_name}, 0, cnt, (jbyte *)mp->${c_name}); - } -""") - -u16_array_struct_setter_template = Template(""" - if (${field_reference_name}) { - jshort * ${field_reference_name}ArrayElements = (*env)->GetShortArrayElements(env, ${field_reference_name}, NULL); - size_t _i; - jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name}); - ${field_length_check} - for (_i = 0; _i < cnt; _i++) { - mp->${c_name}[_i] = clib_host_to_net_u16(${field_reference_name}ArrayElements[_i]); - } - (*env)->ReleaseShortArrayElements (env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0); - } - """) - -u32_array_struct_setter_template = Template(""" - if (${field_reference_name}) { - jint * ${field_reference_name}ArrayElements = (*env)->GetIntArrayElements(env, ${field_reference_name}, NULL); - size_t _i; - jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name}); - ${field_length_check} - for (_i = 0; _i < cnt; _i++) { - mp->${c_name}[_i] = clib_host_to_net_u32(${field_reference_name}ArrayElements[_i]); - } - (*env)->ReleaseIntArrayElements (env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0); - } - """) - -u64_array_struct_setter_template = Template(""" - if (${field_reference_name}) { - jlong * ${field_reference_name}ArrayElements = (*env)->GetLongArrayElements(env, ${field_reference_name}, NULL); - size_t _i; - jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name}); - ${field_length_check} - for (_i = 0; _i < cnt; _i++) { - mp->${c_name}[_i] = clib_host_to_net_u64(${field_reference_name}ArrayElements[_i]); - } - (*env)->ReleaseLongArrayElements (env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0); - } - """) - -struct_setter_templates = {'u8': u8_struct_setter_template, - 'u16': u16_struct_setter_template, - 'u32': u32_struct_setter_template, - 'i32': u32_struct_setter_template, - 'u64': u64_struct_setter_template, - 'u8[]': u8_array_struct_setter_template, - 'u16[]': u16_array_struct_setter_template, - 'u32[]': u32_array_struct_setter_template, - 'u64[]': u64_array_struct_setter_template - } - - -def jni_request_binding_for_type(field_type, c_name, field_reference_name, field_name, field_length, - is_variable_len_array, object_name="request"): - """ - Generates jni code that initializes C structure that corresponds to a field of java object - (dto or custom type). To be used in request message handlers. - :param field_type: type of the field to be initialized (as defined in vpe.api) - :param c_name: name of the message struct member to be initialized - :param field_reference_name: name of the field reference in generated code - :param field_name: name of the field (camelcase) - :param field_length: integer or name of variable that stores field length - :param object_name: name of the object to be initialized - """ - # field identifiers - jni_type = util.vpp_2_jni_type_mapping[field_type] - jni_signature = util.jni_2_signature_mapping[field_type] - jni_getter = util.jni_field_accessors[field_type] - - # field identifier - msg_initialization = request_field_identifier_template.substitute( - jni_type=jni_type, - field_reference_name=field_reference_name, - field_name=field_name, - jni_signature=jni_signature, - jni_getter=jni_getter, - object_name=object_name) - - # field setter - field_length_check = "" - - # check if we are processing variable length array: - if is_variable_len_array: - field_length = util.underscore_to_camelcase(field_length) - - # enforce max length if array has fixed length or uses variable length syntax - if str(field_length) != "0": - field_length_check = array_length_enforcement_template.substitute(field_length=field_length) - - struct_setter_template = struct_setter_templates[field_type] - - msg_initialization += struct_setter_template.substitute( - c_name=c_name, - field_reference_name=field_reference_name, - field_length_check=field_length_check) - - return msg_initialization diff --git a/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py b/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py deleted file mode 100644 index 5fc84c7b..00000000 --- a/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py +++ /dev/null @@ -1,343 +0,0 @@ -#!/usr/bin/env python -# -# 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 -# l -# 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. -# - -import os, util -from string import Template - -import jni_gen - - -def is_manually_generated(f_name, plugin_name): - return f_name in {'control_ping_reply'} - - -class_reference_template = Template("""jclass ${ref_name}Class; -""") - -find_class_invocation_template = Template(""" - ${ref_name}Class = (jclass)(*env)->NewGlobalRef(env, (*env)->FindClass(env, "io/fd/vpp/jvpp/${plugin_name}/dto/${class_name}")); - if ((*env)->ExceptionCheck(env)) { - (*env)->ExceptionDescribe(env); - return JNI_ERR; - }""") - -find_class_template = Template(""" - ${ref_name}Class = (jclass)(*env)->NewGlobalRef(env, (*env)->FindClass(env, "${class_name}")); - if ((*env)->ExceptionCheck(env)) { - (*env)->ExceptionDescribe(env); - return JNI_ERR; - }""") - -delete_class_invocation_template = Template(""" - if (${ref_name}Class) { - (*env)->DeleteGlobalRef(env, ${ref_name}Class); - }""") - -class_cache_template = Template(""" -$class_references -static int cache_class_references(JNIEnv* env) { - $find_class_invocations - return 0; -} - -static void delete_class_references(JNIEnv* env) { - $delete_class_invocations -}""") - - -def generate_class_cache(func_list, plugin_name): - class_references = [] - find_class_invocations = [] - delete_class_invocations = [] - for f in func_list: - c_name = f['name'] - class_name = util.underscore_to_camelcase_upper(c_name) - ref_name = util.underscore_to_camelcase(c_name) - - if util.is_ignored(c_name) or util.is_control_ping(class_name): - continue - - if util.is_reply(class_name): - class_references.append(class_reference_template.substitute( - ref_name=ref_name)) - find_class_invocations.append(find_class_invocation_template.substitute( - plugin_name=plugin_name, - ref_name=ref_name, - class_name=class_name)) - delete_class_invocations.append(delete_class_invocation_template.substitute(ref_name=ref_name)) - elif util.is_notification(c_name): - class_references.append(class_reference_template.substitute( - ref_name=util.add_notification_suffix(ref_name))) - find_class_invocations.append(find_class_invocation_template.substitute( - plugin_name=plugin_name, - ref_name=util.add_notification_suffix(ref_name), - class_name=util.add_notification_suffix(class_name))) - delete_class_invocations.append(delete_class_invocation_template.substitute( - ref_name=util.add_notification_suffix(ref_name))) - - # add exception class to class cache - ref_name = 'callbackException' - class_name = 'io/fd/vpp/jvpp/VppCallbackException' - class_references.append(class_reference_template.substitute( - ref_name=ref_name)) - find_class_invocations.append(find_class_template.substitute( - ref_name=ref_name, - class_name=class_name)) - delete_class_invocations.append(delete_class_invocation_template.substitute(ref_name=ref_name)) - - return class_cache_template.substitute( - class_references="".join(class_references), find_class_invocations="".join(find_class_invocations), - delete_class_invocations="".join(delete_class_invocations)) - - -# TODO: cache method and field identifiers to achieve better performance -# https://jira.fd.io/browse/HONEYCOMB-42 -request_class_template = Template(""" - jclass requestClass = (*env)->FindClass(env, "io/fd/vpp/jvpp/${plugin_name}/dto/${java_name_upper}");""") - -request_field_identifier_template = Template(""" - jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${object_name}Class, "${field_name}", "${jni_signature}"); - ${jni_type} ${field_reference_name} = (*env)->Get${jni_getter}(env, ${object_name}, ${field_reference_name}FieldId); - """) - - -jni_impl_template = Template(""" -/** - * JNI binding for sending ${c_name} message. - * Generated based on $inputfile preparsed data: -$api_data - */ -JNIEXPORT jint JNICALL Java_io_fd_vpp_jvpp_${plugin_name}_JVpp${java_plugin_name}Impl_${field_name}0 -(JNIEnv * env, jclass clazz$args) { - ${plugin_name}_main_t *plugin_main = &${plugin_name}_main; - vl_api_${c_name}_t * mp; - u32 my_context_id = vppjni_get_context_id (&jvpp_main); - $request_class - - // create message: - mp = vl_msg_api_alloc(sizeof(*mp)); - memset (mp, 0, sizeof (*mp)); - mp->_vl_msg_id = ntohs (VL_API_${c_name_uppercase} + plugin_main->msg_id_base); - mp->client_index = plugin_main->my_client_index; - mp->context = clib_host_to_net_u32 (my_context_id); - - $msg_initialization - - // send message: - vl_msg_api_send_shmem (plugin_main->vl_input_queue, (u8 *)&mp); - if ((*env)->ExceptionCheck(env)) { - return JNI_ERR; - } - return my_context_id; -}""") - -def generate_jni_impl(func_list, plugin_name, inputfile): - jni_impl = [] - for f in func_list: - f_name = f['name'] - camel_case_function_name = util.underscore_to_camelcase(f_name) - if is_manually_generated(f_name, plugin_name) or util.is_reply(camel_case_function_name) \ - or util.is_ignored(f_name) or util.is_just_notification(f_name): - continue - - arguments = '' - request_class = '' - msg_initialization = '' - f_name_uppercase = f_name.upper() - - if f['args']: - arguments = ', jobject request' - camel_case_function_name_upper = util.underscore_to_camelcase_upper(f_name) - - request_class = request_class_template.substitute( - java_name_upper=camel_case_function_name_upper, - plugin_name=plugin_name) - - for t in zip(f['types'], f['args'], f['lengths']): - field_name = util.underscore_to_camelcase(t[1]) - msg_initialization += jni_gen.jni_request_binding_for_type(field_type=t[0], c_name=t[1], - field_reference_name=field_name, - field_name=field_name, - field_length=t[2][0], - is_variable_len_array=t[2][1]) - - jni_impl.append(jni_impl_template.substitute( - inputfile=inputfile, - api_data=util.api_message_to_javadoc(f), - field_reference_name=camel_case_function_name, - field_name=camel_case_function_name, - c_name_uppercase=f_name_uppercase, - c_name=f_name, - plugin_name=plugin_name, - java_plugin_name=plugin_name.title(), - request_class=request_class, - msg_initialization=msg_initialization, - args=arguments)) - - return "\n".join(jni_impl) - -# code fragment for checking result of the operation before sending request reply -callback_err_handler_template = Template(""" - // for negative result don't send callback message but send error callback - if (mp->retval<0) { - call_on_error("${handler_name}", mp->context, mp->retval, plugin_main->callbackClass, plugin_main->callbackObject, callbackExceptionClass); - return; - } - if (mp->retval == VNET_API_ERROR_IN_PROGRESS) { - clib_warning("Result in progress"); - return; - } -""") - -msg_handler_template = Template(""" -/** - * Handler for ${handler_name} message. - * Generated based on $inputfile preparsed data: -$api_data - */ -static void vl_api_${handler_name}_t_handler (vl_api_${handler_name}_t * mp) -{ - ${plugin_name}_main_t *plugin_main = &${plugin_name}_main; - JNIEnv *env = jvpp_main.jenv; - - $err_handler - - jmethodID constructor = (*env)->GetMethodID(env, ${class_ref_name}Class, "", "()V"); - jmethodID callbackMethod = (*env)->GetMethodID(env, plugin_main->callbackClass, "on${dto_name}", "(Lio/fd/vpp/jvpp/${plugin_name}/dto/${dto_name};)V"); - - jobject dto = (*env)->NewObject(env, ${class_ref_name}Class, constructor); - $dto_setters - - (*env)->CallVoidMethod(env, plugin_main->callbackObject, callbackMethod, dto); - // free DTO as per http://stackoverflow.com/questions/1340938/memory-leak-when-calling-java-code-from-c-using-jni - (*env)->DeleteLocalRef(env, dto); -}""") - - -def generate_msg_handlers(func_list, plugin_name, inputfile): - handlers = [] - for f in func_list: - handler_name = f['name'] - dto_name = util.underscore_to_camelcase_upper(handler_name) - ref_name = util.underscore_to_camelcase(handler_name) - - if is_manually_generated(handler_name, plugin_name) or util.is_ignored(handler_name): - continue - - if not util.is_reply(dto_name) and not util.is_notification(handler_name): - continue - - if util.is_notification(handler_name): - dto_name = util.add_notification_suffix(dto_name) - ref_name = util.add_notification_suffix(ref_name) - - dto_setters = '' - err_handler = '' - # dto setters - for t in zip(f['types'], f['args'], f['lengths']): - c_name = t[1] - java_name = util.underscore_to_camelcase(c_name) - field_length = t[2][0] - is_variable_len_array = t[2][1] - length_field_type = None - if is_variable_len_array: - length_field_type = f['types'][f['args'].index(field_length)] - dto_setters += jni_gen.jni_reply_handler_for_type(handler_name=handler_name, ref_name=ref_name, - field_type=t[0], c_name=t[1], - field_reference_name=java_name, - field_name=java_name, field_length=field_length, - is_variable_len_array=is_variable_len_array, - length_field_type=length_field_type) - - # for retval don't generate setters and generate retval check - if util.is_retval_field(c_name): - err_handler = callback_err_handler_template.substitute( - handler_name=handler_name - ) - continue - - handlers.append(msg_handler_template.substitute( - inputfile=inputfile, - api_data=util.api_message_to_javadoc(f), - handler_name=handler_name, - plugin_name=plugin_name, - dto_name=dto_name, - class_ref_name=ref_name, - dto_setters=dto_setters, - err_handler=err_handler)) - - return "\n".join(handlers) - - -handler_registration_template = Template("""_(${upercase_name}, ${name}) \\ -""") - - -def generate_handler_registration(func_list): - handler_registration = ["#define foreach_api_reply_handler \\\n"] - for f in func_list: - name = f['name'] - camelcase_name = util.underscore_to_camelcase(f['name']) - - if (not util.is_reply(camelcase_name) and not util.is_notification(name)) or util.is_ignored(name) \ - or util.is_control_ping(camelcase_name): - continue - - handler_registration.append(handler_registration_template.substitute( - name=name, - upercase_name=name.upper())) - - return "".join(handler_registration) - - -jvpp_c_template = Template("""/** - * This file contains JNI bindings for jvpp Java API. - * It was generated by jvpp_c_gen.py based on $inputfile - * (python representation of api file generated by vppapigen). - */ - -// JAVA class reference cache -$class_cache - -// JNI bindings -$jni_implementations - -// Message handlers -$msg_handlers - -// Registration of message handlers in vlib -$handler_registration -""") - -def generate_jvpp(func_list, plugin_name, inputfile): - """ Generates jvpp C file """ - print "Generating jvpp C" - - class_cache = generate_class_cache(func_list, plugin_name) - jni_impl = generate_jni_impl(func_list, plugin_name, inputfile) - msg_handlers = generate_msg_handlers(func_list, plugin_name, inputfile) - handler_registration = generate_handler_registration(func_list) - - jvpp_c_file = open("jvpp_%s_gen.h" % plugin_name, 'w') - jvpp_c_file.write(jvpp_c_template.substitute( - inputfile=inputfile, - class_cache=class_cache, - jni_implementations=jni_impl, - msg_handlers=msg_handlers, - handler_registration=handler_registration)) - jvpp_c_file.flush() - jvpp_c_file.close() - diff --git a/vpp-api/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py b/vpp-api/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py deleted file mode 100644 index ac096a71..00000000 --- a/vpp-api/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py +++ /dev/null @@ -1,324 +0,0 @@ -#!/usr/bin/env python -# -# 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. - -import os, util -from string import Template - -import callback_gen -import dto_gen - -jvpp_ifc_template = Template(""" -package $plugin_package.$callback_facade_package; - -/** - *

Callback Java API representation of $plugin_package plugin. - *
It was generated by jvpp_callback_facade_gen.py based on $inputfile - *
(python representation of api file generated by vppapigen). - */ -public interface CallbackJVpp${plugin_name} extends $base_package.$notification_package.NotificationRegistryProvider, java.lang.AutoCloseable { - - // TODO add send - -$methods -} -""") - -jvpp_impl_template = Template(""" -package $plugin_package.$callback_facade_package; - -/** - *

Default implementation of Callback${plugin_name}JVpp interface. - *
It was generated by jvpp_callback_facade_gen.py based on $inputfile - *
(python representation of api file generated by vppapigen). - */ -public final class CallbackJVpp${plugin_name}Facade implements CallbackJVpp${plugin_name} { - - private final $plugin_package.JVpp${plugin_name} jvpp; - private final java.util.Map callbacks; - private final $plugin_package.$notification_package.${plugin_name}NotificationRegistryImpl notificationRegistry = new $plugin_package.$notification_package.${plugin_name}NotificationRegistryImpl(); - /** - *

Create CallbackJVpp${plugin_name}Facade object for provided JVpp instance. - * Constructor internally creates CallbackJVppFacadeCallback class for processing callbacks - * and then connects to provided JVpp instance - * - * @param jvpp provided $base_package.JVpp instance - * - * @throws java.io.IOException in case instance cannot connect to JVPP - */ - public CallbackJVpp${plugin_name}Facade(final $base_package.JVppRegistry registry, final $plugin_package.JVpp${plugin_name} jvpp) throws java.io.IOException { - this.jvpp = java.util.Objects.requireNonNull(jvpp,"jvpp is null"); - this.callbacks = new java.util.HashMap<>(); - java.util.Objects.requireNonNull(registry, "JVppRegistry should not be null"); - registry.register(jvpp, new CallbackJVpp${plugin_name}FacadeCallback(this.callbacks, notificationRegistry)); - } - - @Override - public $plugin_package.$notification_package.${plugin_name}NotificationRegistry getNotificationRegistry() { - return notificationRegistry; - } - - @Override - public void close() throws Exception { - jvpp.close(); - } - - // TODO add send() - -$methods -} -""") - -method_template = Template( - """ void $name($plugin_package.$dto_package.$request request, $plugin_package.$callback_package.$callback callback) throws $base_package.VppInvocationException;""") - -method_impl_template = Template(""" public final void $name($plugin_package.$dto_package.$request request, $plugin_package.$callback_package.$callback callback) throws $base_package.VppInvocationException { - synchronized (callbacks) { - callbacks.put(jvpp.$name(request), callback); - } - } -""") - -no_arg_method_template = Template(""" void $name($plugin_package.$callback_package.$callback callback) throws $base_package.VppInvocationException;""") -no_arg_method_impl_template = Template(""" public final void $name($plugin_package.$callback_package.$callback callback) throws $base_package.VppInvocationException { - synchronized (callbacks) { - callbacks.put(jvpp.$name(), callback); - } - } -""") - - -def generate_jvpp(func_list, base_package, plugin_package, plugin_name, dto_package, callback_package, notification_package, callback_facade_package, inputfile): - """ Generates callback facade """ - print "Generating JVpp callback facade" - - if os.path.exists(callback_facade_package): - util.remove_folder(callback_facade_package) - - os.mkdir(callback_facade_package) - - methods = [] - methods_impl = [] - for func in func_list: - - if util.is_notification(func['name']) or util.is_ignored(func['name']): - continue - - camel_case_name = util.underscore_to_camelcase(func['name']) - camel_case_name_upper = util.underscore_to_camelcase_upper(func['name']) - if util.is_reply(camel_case_name) or util.is_control_ping(camel_case_name): - continue - - # Strip suffix for dump calls - callback_type = get_request_name(camel_case_name_upper, func['name']) + callback_gen.callback_suffix - - if len(func['args']) == 0: - methods.append(no_arg_method_template.substitute(name=camel_case_name, - base_package=base_package, - plugin_package=plugin_package, - dto_package=dto_package, - callback_package=callback_package, - callback=callback_type)) - methods_impl.append(no_arg_method_impl_template.substitute(name=camel_case_name, - base_package=base_package, - plugin_package=plugin_package, - dto_package=dto_package, - callback_package=callback_package, - callback=callback_type)) - else: - methods.append(method_template.substitute(name=camel_case_name, - request=camel_case_name_upper, - base_package=base_package, - plugin_package=plugin_package, - dto_package=dto_package, - callback_package=callback_package, - callback=callback_type)) - methods_impl.append(method_impl_template.substitute(name=camel_case_name, - request=camel_case_name_upper, - base_package=base_package, - plugin_package=plugin_package, - dto_package=dto_package, - callback_package=callback_package, - callback=callback_type)) - - join = os.path.join(callback_facade_package, "CallbackJVpp%s.java" % plugin_name) - jvpp_file = open(join, 'w') - jvpp_file.write( - jvpp_ifc_template.substitute(inputfile=inputfile, - methods="\n".join(methods), - base_package=base_package, - plugin_package=plugin_package, - plugin_name=plugin_name, - dto_package=dto_package, - notification_package=notification_package, - callback_facade_package=callback_facade_package)) - jvpp_file.flush() - jvpp_file.close() - - jvpp_file = open(os.path.join(callback_facade_package, "CallbackJVpp%sFacade.java" % plugin_name), 'w') - jvpp_file.write(jvpp_impl_template.substitute(inputfile=inputfile, - methods="\n".join(methods_impl), - base_package=base_package, - plugin_package=plugin_package, - plugin_name=plugin_name, - dto_package=dto_package, - notification_package=notification_package, - callback_package=callback_package, - callback_facade_package=callback_facade_package)) - jvpp_file.flush() - jvpp_file.close() - - generate_callback(func_list, base_package, plugin_package, plugin_name, dto_package, callback_package, notification_package, callback_facade_package, inputfile) - - -jvpp_facade_callback_template = Template(""" -package $plugin_package.$callback_facade_package; - -/** - *

Implementation of JVppGlobalCallback interface for Java Callback API. - *
It was generated by jvpp_callback_facade_gen.py based on $inputfile - *
(python representation of api file generated by vppapigen). - */ -public final class CallbackJVpp${plugin_name}FacadeCallback implements $plugin_package.$callback_package.JVpp${plugin_name}GlobalCallback { - - private final java.util.Map requests; - private final $plugin_package.$notification_package.Global${plugin_name}NotificationCallback notificationCallback; - private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(CallbackJVpp${plugin_name}FacadeCallback.class.getName()); - - public CallbackJVpp${plugin_name}FacadeCallback(final java.util.Map requestMap, - final $plugin_package.$notification_package.Global${plugin_name}NotificationCallback notificationCallback) { - this.requests = requestMap; - this.notificationCallback = notificationCallback; - } - - @Override - public void onError($base_package.VppCallbackException reply) { - - $base_package.$callback_package.JVppCallback failedCall; - synchronized(requests) { - failedCall = requests.remove(reply.getCtxId()); - } - - if(failedCall != null) { - try { - failedCall.onError(reply); - } catch(RuntimeException ex) { - ex.addSuppressed(reply); - LOG.log(java.util.logging.Level.WARNING, String.format("Callback: %s failed while handling exception: %s", failedCall, reply), ex); - } - } - } - - @Override - @SuppressWarnings("unchecked") - public void onControlPingReply($base_package.$dto_package.ControlPingReply reply) { - - $base_package.$callback_package.ControlPingCallback callback; - synchronized(requests) { - callback = ($base_package.$callback_package.ControlPingCallback) requests.remove(reply.context); - } - - if(callback != null) { - callback.onControlPingReply(reply); - } - } - -$methods -} -""") - -jvpp_facade_callback_method_template = Template(""" - @Override - @SuppressWarnings("unchecked") - public void on$callback_dto($plugin_package.$dto_package.$callback_dto reply) { - - $plugin_package.$callback_package.$callback callback; - synchronized(requests) { - callback = ($plugin_package.$callback_package.$callback) requests.remove(reply.context); - } - - if(callback != null) { - callback.on$callback_dto(reply); - } - } -""") - -jvpp_facade_callback_notification_method_template = Template(""" - @Override - @SuppressWarnings("unchecked") - public void on$callback_dto($plugin_package.$dto_package.$callback_dto notification) { - notificationCallback.on$callback_dto(notification); - } -""") - - -def generate_callback(func_list, base_package, plugin_package, plugin_name, dto_package, callback_package, notification_package, callback_facade_package, inputfile): - callbacks = [] - for func in func_list: - - camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name']) - - if util.is_ignored(func['name']) or util.is_control_ping(camel_case_name_with_suffix): - continue - - if util.is_reply(camel_case_name_with_suffix): - callbacks.append(jvpp_facade_callback_method_template.substitute(plugin_package=plugin_package, - dto_package=dto_package, - callback_package=callback_package, - callback=util.remove_reply_suffix(camel_case_name_with_suffix) + callback_gen.callback_suffix, - callback_dto=camel_case_name_with_suffix)) - - if util.is_notification(func["name"]): - with_notification_suffix = util.add_notification_suffix(camel_case_name_with_suffix) - callbacks.append(jvpp_facade_callback_notification_method_template.substitute(plugin_package=plugin_package, - dto_package=dto_package, - callback_package=callback_package, - callback=with_notification_suffix + callback_gen.callback_suffix, - callback_dto=with_notification_suffix)) - - jvpp_file = open(os.path.join(callback_facade_package, "CallbackJVpp%sFacadeCallback.java" % plugin_name), 'w') - jvpp_file.write(jvpp_facade_callback_template.substitute(inputfile=inputfile, - base_package=base_package, - plugin_package=plugin_package, - plugin_name=plugin_name, - dto_package=dto_package, - notification_package=notification_package, - callback_package=callback_package, - methods="".join(callbacks), - callback_facade_package=callback_facade_package)) - jvpp_file.flush() - jvpp_file.close() - - -# Returns request name or special one from unconventional_naming_rep_req map -def get_request_name(camel_case_dto_name, func_name): - if func_name in reverse_dict(util.unconventional_naming_rep_req): - request_name = util.underscore_to_camelcase_upper(reverse_dict(util.unconventional_naming_rep_req)[func_name]) - else: - request_name = camel_case_dto_name - return remove_suffix(request_name) - - -def reverse_dict(map): - return dict((v, k) for k, v in map.iteritems()) - - -def remove_suffix(name): - if util.is_reply(name): - return util.remove_reply_suffix(name) - else: - if util.is_dump(name): - return util.remove_suffix(name, util.dump_suffix) - else: - return name diff --git a/vpp-api/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py b/vpp-api/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py deleted file mode 100644 index ebb840f7..00000000 --- a/vpp-api/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py +++ /dev/null @@ -1,331 +0,0 @@ -#!/usr/bin/env python -# -# 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. - -import os -from string import Template - -import dto_gen -import util - -jvpp_facade_callback_template = Template(""" -package $plugin_package.$future_package; - -/** - *

Async facade callback setting values to future objects - *
It was generated by jvpp_future_facade_gen.py based on $inputfile - *
(python representation of api file generated by vppapigen). - */ -public final class FutureJVpp${plugin_name}FacadeCallback implements $plugin_package.$callback_package.JVpp${plugin_name}GlobalCallback { - - private final java.util.Map>> requests; - private final $plugin_package.$notification_package.Global${plugin_name}NotificationCallback notificationCallback; - - public FutureJVpp${plugin_name}FacadeCallback( - final java.util.Map>> requestMap, - final $plugin_package.$notification_package.Global${plugin_name}NotificationCallback notificationCallback) { - this.requests = requestMap; - this.notificationCallback = notificationCallback; - } - - @Override - @SuppressWarnings("unchecked") - public void onError($base_package.VppCallbackException reply) { - final java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply> completableFuture; - - synchronized(requests) { - completableFuture = (java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply>) requests.get(reply.getCtxId()); - } - - if(completableFuture != null) { - completableFuture.completeExceptionally(reply); - - synchronized(requests) { - requests.remove(reply.getCtxId()); - } - } - } - - @Override - @SuppressWarnings("unchecked") - public void onControlPingReply($base_package.$dto_package.ControlPingReply reply) { - final java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply> completableFuture; - - synchronized(requests) { - completableFuture = (java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply>) requests.get(reply.context); - } - - if(completableFuture != null) { - // Finish dump call - if (completableFuture instanceof $base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture) { - completableFuture.complete((($base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture) completableFuture).getReplyDump()); - // Remove future mapped to dump call context id - synchronized(requests) { - requests.remove((($base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture) completableFuture).getContextId()); - } - } else { - completableFuture.complete(reply); - } - - synchronized(requests) { - requests.remove(reply.context); - } - } - } - -$methods -} -""") - -jvpp_facade_callback_method_template = Template(""" - @Override - @SuppressWarnings("unchecked") - public void on$callback_dto($plugin_package.$dto_package.$callback_dto reply) { - final java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply> completableFuture; - - synchronized(requests) { - completableFuture = (java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply>) requests.get(reply.context); - } - - if(completableFuture != null) { - completableFuture.complete(reply); - - synchronized(requests) { - requests.remove(reply.context); - } - } - } -""") - -jvpp_facade_callback_notification_method_template = Template(""" - @Override - public void on$callback_dto($plugin_package.$dto_package.$callback_dto notification) { - notificationCallback.on$callback_dto(notification); - } -""") - -jvpp_facade_details_callback_method_template = Template(""" - @Override - @SuppressWarnings("unchecked") - public void on$callback_dto($plugin_package.$dto_package.$callback_dto reply) { - final $base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture<$plugin_package.$dto_package.$callback_dto_reply_dump> completableFuture; - - synchronized(requests) { - completableFuture = ($base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture<$plugin_package.$dto_package.$callback_dto_reply_dump>) requests.get(reply.context); - } - - if(completableFuture != null) { - completableFuture.getReplyDump().$callback_dto_field.add(reply); - } - } -""") - - -def generate_jvpp(func_list, base_package, plugin_package, plugin_name, dto_package, callback_package, notification_package, future_facade_package, inputfile): - """ Generates JVpp interface and JNI implementation """ - print "Generating JVpp future facade" - - if not os.path.exists(future_facade_package): - raise Exception("%s folder is missing" % future_facade_package) - - methods = [] - methods_impl = [] - callbacks = [] - for func in func_list: - camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name']) - - if util.is_ignored(func['name']) or util.is_control_ping(camel_case_name_with_suffix): - continue - - if not util.is_reply(camel_case_name_with_suffix) and not util.is_notification(func['name']): - continue - - camel_case_method_name = util.underscore_to_camelcase(func['name']) - - if not util.is_notification(func["name"]): - camel_case_request_method_name = util.remove_reply_suffix(util.underscore_to_camelcase(func['name'])) - if util.is_details(camel_case_name_with_suffix): - camel_case_reply_name = get_standard_dump_reply_name(util.underscore_to_camelcase_upper(func['name']), - func['name']) - callbacks.append(jvpp_facade_details_callback_method_template.substitute(base_package=base_package, - plugin_package=plugin_package, - dto_package=dto_package, - callback_dto=camel_case_name_with_suffix, - callback_dto_field=camel_case_method_name, - callback_dto_reply_dump=camel_case_reply_name + dto_gen.dump_dto_suffix, - future_package=future_facade_package)) - - methods.append(future_jvpp_method_template.substitute(plugin_package=plugin_package, - dto_package=dto_package, - method_name=camel_case_request_method_name + - util.underscore_to_camelcase_upper(util.dump_suffix), - reply_name=camel_case_reply_name + dto_gen.dump_dto_suffix, - request_name=util.remove_reply_suffix(camel_case_reply_name) + - util.underscore_to_camelcase_upper(util.dump_suffix))) - methods_impl.append(future_jvpp_dump_method_impl_template.substitute(plugin_package=plugin_package, - dto_package=dto_package, - method_name=camel_case_request_method_name + - util.underscore_to_camelcase_upper(util.dump_suffix), - reply_name=camel_case_reply_name + dto_gen.dump_dto_suffix, - request_name=util.remove_reply_suffix(camel_case_reply_name) + - util.underscore_to_camelcase_upper(util.dump_suffix))) - else: - request_name = util.underscore_to_camelcase_upper(util.unconventional_naming_rep_req[func['name']]) \ - if func['name'] in util.unconventional_naming_rep_req else util.remove_reply_suffix(camel_case_name_with_suffix) - - methods.append(future_jvpp_method_template.substitute(plugin_package=plugin_package, - dto_package=dto_package, - method_name=camel_case_request_method_name, - reply_name=camel_case_name_with_suffix, - request_name=request_name)) - methods_impl.append(future_jvpp_method_impl_template.substitute(plugin_package=plugin_package, - dto_package=dto_package, - method_name=camel_case_request_method_name, - reply_name=camel_case_name_with_suffix, - request_name=request_name)) - - callbacks.append(jvpp_facade_callback_method_template.substitute(base_package=base_package, - plugin_package=plugin_package, - dto_package=dto_package, - callback_dto=camel_case_name_with_suffix)) - - if util.is_notification(func["name"]): - callbacks.append(jvpp_facade_callback_notification_method_template.substitute(plugin_package=plugin_package, - dto_package=dto_package, - callback_dto=util.add_notification_suffix(camel_case_name_with_suffix))) - - jvpp_file = open(os.path.join(future_facade_package, "FutureJVpp%sFacadeCallback.java" % plugin_name), 'w') - jvpp_file.write(jvpp_facade_callback_template.substitute(inputfile=inputfile, - base_package=base_package, - plugin_package=plugin_package, - plugin_name=plugin_name, - dto_package=dto_package, - notification_package=notification_package, - callback_package=callback_package, - methods="".join(callbacks), - future_package=future_facade_package)) - jvpp_file.flush() - jvpp_file.close() - - jvpp_file = open(os.path.join(future_facade_package, "FutureJVpp%s.java" % plugin_name), 'w') - jvpp_file.write(future_jvpp_template.substitute(inputfile=inputfile, - base_package=base_package, - plugin_package=plugin_package, - plugin_name=plugin_name, - notification_package=notification_package, - methods="".join(methods), - future_package=future_facade_package)) - jvpp_file.flush() - jvpp_file.close() - - jvpp_file = open(os.path.join(future_facade_package, "FutureJVpp%sFacade.java" % plugin_name), 'w') - jvpp_file.write(future_jvpp_facade_template.substitute(inputfile=inputfile, - base_package=base_package, - plugin_package=plugin_package, - plugin_name=plugin_name, - dto_package=dto_package, - notification_package=notification_package, - methods="".join(methods_impl), - future_package=future_facade_package)) - jvpp_file.flush() - jvpp_file.close() - - -future_jvpp_template = Template(''' -package $plugin_package.$future_package; - -/** - *

Async facade extension adding specific methods for each request invocation - *
It was generated by jvpp_future_facade_gen.py based on $inputfile - *
(python representation of api file generated by vppapigen). - */ -public interface FutureJVpp${plugin_name} extends $base_package.$future_package.FutureJVppInvoker { -$methods - - @Override - public $plugin_package.$notification_package.${plugin_name}NotificationRegistry getNotificationRegistry(); - -} -''') - -future_jvpp_method_template = Template(''' - java.util.concurrent.CompletionStage<$plugin_package.$dto_package.$reply_name> $method_name($plugin_package.$dto_package.$request_name request); -''') - - -future_jvpp_facade_template = Template(''' -package $plugin_package.$future_package; - -/** - *

Implementation of FutureJVpp based on AbstractFutureJVppInvoker - *
It was generated by jvpp_future_facade_gen.py based on $inputfile - *
(python representation of api file generated by vppapigen). - */ -public class FutureJVpp${plugin_name}Facade extends $base_package.$future_package.AbstractFutureJVppInvoker implements FutureJVpp${plugin_name} { - - private final $plugin_package.$notification_package.${plugin_name}NotificationRegistryImpl notificationRegistry = new $plugin_package.$notification_package.${plugin_name}NotificationRegistryImpl(); - - /** - *

Create FutureJVpp${plugin_name}Facade object for provided JVpp instance. - * Constructor internally creates FutureJVppFacadeCallback class for processing callbacks - * and then connects to provided JVpp instance - * - * @param jvpp provided $base_package.JVpp instance - * - * @throws java.io.IOException in case instance cannot connect to JVPP - */ - public FutureJVpp${plugin_name}Facade(final $base_package.JVppRegistry registry, final $base_package.JVpp jvpp) throws java.io.IOException { - super(jvpp, registry, new java.util.HashMap<>()); - java.util.Objects.requireNonNull(registry, "JVppRegistry should not be null"); - registry.register(jvpp, new FutureJVpp${plugin_name}FacadeCallback(getRequests(), notificationRegistry)); - } - - @Override - public $plugin_package.$notification_package.${plugin_name}NotificationRegistry getNotificationRegistry() { - return notificationRegistry; - } - -$methods -} -''') - -future_jvpp_method_impl_template = Template(''' - @Override - public java.util.concurrent.CompletionStage<$plugin_package.$dto_package.$reply_name> $method_name($plugin_package.$dto_package.$request_name request) { - return send(request); - } -''') - -future_jvpp_dump_method_impl_template = Template(''' - @Override - public java.util.concurrent.CompletionStage<$plugin_package.$dto_package.$reply_name> $method_name($plugin_package.$dto_package.$request_name request) { - return send(request, new $plugin_package.$dto_package.$reply_name()); - } -''') - - -# Returns request name or special one from unconventional_naming_rep_req map -def get_standard_dump_reply_name(camel_case_dto_name, func_name): - # FIXME this is a hotfix for sub-details callbacks - # FIXME also for L2FibTableEntry - # It's all because unclear mapping between - # request -> reply, - # dump -> reply, details, - # notification_start -> reply, notifications - - # vpe.api needs to be "standardized" so we can parse the information and create maps before generating java code - suffix = func_name.split("_")[-1] - return util.underscore_to_camelcase_upper( - util.unconventional_naming_rep_req[func_name]) + util.underscore_to_camelcase_upper(suffix) if func_name in util.unconventional_naming_rep_req \ - else camel_case_dto_name diff --git a/vpp-api/java/jvpp/gen/jvppgen/jvpp_impl_gen.py b/vpp-api/java/jvpp/gen/jvppgen/jvpp_impl_gen.py deleted file mode 100644 index 4146c141..00000000 --- a/vpp-api/java/jvpp/gen/jvppgen/jvpp_impl_gen.py +++ /dev/null @@ -1,219 +0,0 @@ -#!/usr/bin/env python -# -# 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. - -import os, util -from string import Template - -jvpp_ifc_template = Template(""" -package $plugin_package; - -/** - *

Java representation of plugin's api file. - *
It was generated by jvpp_impl_gen.py based on $inputfile - *
(python representation of api file generated by vppapigen). - */ -public interface JVpp${plugin_name} extends $base_package.JVpp { - - /** - * Generic dispatch method for sending requests to VPP - * - * @throws io.fd.vpp.jvpp.VppInvocationException if send request had failed - */ - int send($base_package.$dto_package.JVppRequest request) throws io.fd.vpp.jvpp.VppInvocationException; - -$methods -} -""") - -jvpp_impl_template = Template(""" -package $plugin_package; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.nio.file.attribute.PosixFilePermission; -import java.nio.file.attribute.PosixFilePermissions; -import java.util.Set; -import java.util.logging.Logger; -import $base_package.callback.JVppCallback; -import $base_package.VppConnection; -import $base_package.JVppRegistry; - -/** - *

Default implementation of JVpp interface. - *
It was generated by jvpp_impl_gen.py based on $inputfile - *
(python representation of api file generated by vppapigen). - */ -public final class JVpp${plugin_name}Impl implements $plugin_package.JVpp${plugin_name} { - - private final static Logger LOG = Logger.getLogger(JVpp${plugin_name}Impl.class.getName()); - private static final String LIBNAME = "libjvpp_${plugin_name_underscore}.so.0.0.0"; - - // FIXME using NativeLibraryLoader makes load fail could not find (WantInterfaceEventsReply). - static { - try { - loadLibrary(); - } catch (Exception e) { - LOG.severe("Can't find jvpp jni library: " + LIBNAME); - throw new ExceptionInInitializerError(e); - } - } - - private static void loadStream(final InputStream is) throws IOException { - final Set perms = PosixFilePermissions.fromString("rwxr-x---"); - final Path p = Files.createTempFile(LIBNAME, null, PosixFilePermissions.asFileAttribute(perms)); - try { - Files.copy(is, p, StandardCopyOption.REPLACE_EXISTING); - - try { - Runtime.getRuntime().load(p.toString()); - } catch (UnsatisfiedLinkError e) { - throw new IOException("Failed to load library " + p, e); - } - } finally { - try { - Files.deleteIfExists(p); - } catch (IOException e) { - } - } - } - - private static void loadLibrary() throws IOException { - try (final InputStream is = JVpp${plugin_name}Impl.class.getResourceAsStream('/' + LIBNAME)) { - if (is == null) { - throw new IOException("Failed to open library resource " + LIBNAME); - } - loadStream(is); - } - } - - private VppConnection connection; - private JVppRegistry registry; - - private static native void init0(final JVppCallback callback, final long queueAddress, final int clientIndex); - @Override - public void init(final JVppRegistry registry, final JVppCallback callback, final long queueAddress, final int clientIndex) { - this.registry = java.util.Objects.requireNonNull(registry, "registry should not be null"); - this.connection = java.util.Objects.requireNonNull(registry.getConnection(), "connection should not be null"); - connection.checkActive(); - init0(callback, queueAddress, clientIndex); - } - - private static native void close0(); - @Override - public void close() { - close0(); - } - - @Override - public int send($base_package.$dto_package.JVppRequest request) throws io.fd.vpp.jvpp.VppInvocationException { - return request.send(this); - } - - @Override - public final int controlPing(final io.fd.vpp.jvpp.dto.ControlPing controlPing) throws io.fd.vpp.jvpp.VppInvocationException { - return registry.controlPing(JVpp${plugin_name}Impl.class); - } - -$methods -} -""") - -method_template = Template(""" int $name($plugin_package.$dto_package.$request request) throws io.fd.vpp.jvpp.VppInvocationException;""") -method_native_template = Template( - """ private static native int ${name}0($plugin_package.$dto_package.$request request);""") -method_impl_template = Template(""" public final int $name($plugin_package.$dto_package.$request request) throws io.fd.vpp.jvpp.VppInvocationException { - java.util.Objects.requireNonNull(request,"Null request object"); - connection.checkActive(); - int result=${name}0(request); - if(result<0){ - throw new io.fd.vpp.jvpp.VppInvocationException("${name}",result); - } - return result; - } -""") - -no_arg_method_template = Template(""" int $name() throws io.fd.vpp.jvpp.VppInvocationException;""") -no_arg_method_native_template = Template(""" private static native int ${name}0() throws io.fd.vpp.jvpp.VppInvocationException;""") -no_arg_method_impl_template = Template(""" public final int $name() throws io.fd.vpp.jvpp.VppInvocationException { - connection.checkActive(); - int result=${name}0(); - if(result<0){ - throw new io.fd.vpp.jvpp.VppInvocationException("${name}",result); - } - return result; - } -""") - - -def generate_jvpp(func_list, base_package, plugin_package, plugin_name_underscore, dto_package, inputfile): - """ Generates JVpp interface and JNI implementation """ - print "Generating JVpp" - plugin_name = util.underscore_to_camelcase_upper(plugin_name_underscore) - - methods = [] - methods_impl = [] - for func in func_list: - - # Skip structures that are used only as notifications - if util.is_just_notification(func['name']) or util.is_ignored(func['name']): - continue - - camel_case_name = util.underscore_to_camelcase(func['name']) - camel_case_name_upper = util.underscore_to_camelcase_upper(func['name']) - if util.is_reply(camel_case_name): - continue - - if len(func['args']) == 0: - methods.append(no_arg_method_template.substitute(name=camel_case_name)) - methods_impl.append(no_arg_method_native_template.substitute(name=camel_case_name)) - methods_impl.append(no_arg_method_impl_template.substitute(name=camel_case_name)) - else: - methods.append(method_template.substitute(name=camel_case_name, - request=camel_case_name_upper, - plugin_package=plugin_package, - dto_package=dto_package)) - methods_impl.append(method_native_template.substitute(name=camel_case_name, - request=camel_case_name_upper, - plugin_package=plugin_package, - dto_package=dto_package)) - methods_impl.append(method_impl_template.substitute(name=camel_case_name, - request=camel_case_name_upper, - plugin_package=plugin_package, - dto_package=dto_package)) - - jvpp_file = open("JVpp%s.java" % plugin_name, 'w') - jvpp_file.write( - jvpp_ifc_template.substitute(inputfile=inputfile, - methods="\n".join(methods), - base_package=base_package, - plugin_package=plugin_package, - plugin_name=plugin_name, - dto_package=dto_package)) - jvpp_file.flush() - jvpp_file.close() - - jvpp_file = open("JVpp%sImpl.java" % plugin_name, 'w') - jvpp_file.write(jvpp_impl_template.substitute(inputfile=inputfile, - methods="\n".join(methods_impl), - base_package=base_package, - plugin_package=plugin_package, - plugin_name=plugin_name, - plugin_name_underscore=plugin_name_underscore, - dto_package=dto_package)) - jvpp_file.flush() - jvpp_file.close() diff --git a/vpp-api/java/jvpp/gen/jvppgen/notification_gen.py b/vpp-api/java/jvpp/gen/jvppgen/notification_gen.py deleted file mode 100644 index eb380fc8..00000000 --- a/vpp-api/java/jvpp/gen/jvppgen/notification_gen.py +++ /dev/null @@ -1,199 +0,0 @@ -#!/usr/bin/env python -# -# 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. - -import os - -import callback_gen -import util -from string import Template - -notification_registry_template = Template(""" -package $plugin_package.$notification_package; - -/** - *

Registry for notification callbacks defined in ${plugin_name}. - *
It was generated by notification_gen.py based on $inputfile - *
(python representation of api file generated by vppapigen). - */ -public interface ${plugin_name}NotificationRegistry extends $base_package.$notification_package.NotificationRegistry { - - $register_callback_methods - - @Override - void close(); -} -""") - -global_notification_callback_template = Template(""" -package $plugin_package.$notification_package; - -/** - *

Aggregated callback interface for notifications only. - *
It was generated by notification_gen.py based on $inputfile - *
(python representation of api file generated by vppapigen). - */ -public interface Global${plugin_name}NotificationCallback$callbacks { - -} -""") - -notification_registry_impl_template = Template(""" -package $plugin_package.$notification_package; - -/** - *

Notification registry delegating notification processing to registered callbacks. - *
It was generated by notification_gen.py based on $inputfile - *
(python representation of api file generated by vppapigen). - */ -public final class ${plugin_name}NotificationRegistryImpl implements ${plugin_name}NotificationRegistry, Global${plugin_name}NotificationCallback { - - // TODO add a special NotificationCallback interface and only allow those to be registered - private final java.util.concurrent.ConcurrentMap, $base_package.$callback_package.JVppNotificationCallback> registeredCallbacks = - new java.util.concurrent.ConcurrentHashMap<>(); - - $register_callback_methods - $handler_methods - - @Override - public void close() { - registeredCallbacks.clear(); - } -} -""") - -register_callback_impl_template = Template(""" - public java.lang.AutoCloseable register$callback(final $plugin_package.$callback_package.$callback callback){ - if(null != registeredCallbacks.putIfAbsent($plugin_package.$dto_package.$notification.class, callback)){ - throw new IllegalArgumentException("Callback for " + $plugin_package.$dto_package.$notification.class + - "notification already registered"); - } - return () -> registeredCallbacks.remove($plugin_package.$dto_package.$notification.class); - } -""") - -handler_impl_template = Template(""" - @Override - public void on$notification( - final $plugin_package.$dto_package.$notification notification) { - final $base_package.$callback_package.JVppNotificationCallback jVppNotificationCallback = registeredCallbacks.get($plugin_package.$dto_package.$notification.class); - if (null != jVppNotificationCallback) { - (($plugin_package.$callback_package.$callback) registeredCallbacks - .get($plugin_package.$dto_package.$notification.class)) - .on$notification(notification); - } - } -""") - -notification_provider_template = Template(""" -package $plugin_package.$notification_package; - - /** - * Provides ${plugin_name}NotificationRegistry. - *
The file was generated by notification_gen.py based on $inputfile - *
(python representation of api file generated by vppapigen). - */ -public interface ${plugin_name}NotificationRegistryProvider extends $base_package.$notification_package.NotificationRegistryProvider { - - @Override - public ${plugin_name}NotificationRegistry getNotificationRegistry(); -} -""") - - -def generate_notification_registry(func_list, base_package, plugin_package, plugin_name, notification_package, callback_package, dto_package, inputfile): - """ Generates notification registry interface and implementation """ - print "Generating Notification interfaces and implementation" - - if not os.path.exists(notification_package): - raise Exception("%s folder is missing" % notification_package) - - callbacks = [] - register_callback_methods = [] - register_callback_methods_impl = [] - handler_methods = [] - for func in func_list: - - if not util.is_notification(func['name']): - continue - - camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name']) - notification_dto = util.add_notification_suffix(camel_case_name_with_suffix) - callback_ifc = notification_dto + callback_gen.callback_suffix - fully_qualified_callback_ifc = "{0}.{1}.{2}".format(plugin_package, callback_package, callback_ifc) - callbacks.append(fully_qualified_callback_ifc) - - # TODO create NotificationListenerRegistration and return that instead of AutoCloseable to better indicate - # that the registration should be closed - register_callback_methods.append("java.lang.AutoCloseable register{0}({1} callback);" - .format(callback_ifc, fully_qualified_callback_ifc)) - register_callback_methods_impl.append(register_callback_impl_template.substitute(plugin_package=plugin_package, - callback_package=callback_package, - dto_package=dto_package, - notification=notification_dto, - callback=callback_ifc)) - handler_methods.append(handler_impl_template.substitute(base_package=base_package, - plugin_package=plugin_package, - callback_package=callback_package, - dto_package=dto_package, - notification=notification_dto, - callback=callback_ifc)) - - - callback_file = open(os.path.join(notification_package, "%sNotificationRegistry.java" % plugin_name), 'w') - callback_file.write(notification_registry_template.substitute(inputfile=inputfile, - register_callback_methods="\n ".join(register_callback_methods), - base_package=base_package, - plugin_package=plugin_package, - plugin_name=plugin_name, - notification_package=notification_package)) - callback_file.flush() - callback_file.close() - - callback_file = open(os.path.join(notification_package, "Global%sNotificationCallback.java" % plugin_name), 'w') - - global_notification_callback_callbacks = "" - if (callbacks): - global_notification_callback_callbacks = " extends " + ", ".join(callbacks) - - callback_file.write(global_notification_callback_template.substitute(inputfile=inputfile, - callbacks=global_notification_callback_callbacks, - plugin_package=plugin_package, - plugin_name=plugin_name, - notification_package=notification_package)) - callback_file.flush() - callback_file.close() - - callback_file = open(os.path.join(notification_package, "%sNotificationRegistryImpl.java" % plugin_name), 'w') - callback_file.write(notification_registry_impl_template.substitute(inputfile=inputfile, - callback_package=callback_package, - dto_package=dto_package, - register_callback_methods="".join(register_callback_methods_impl), - handler_methods="".join(handler_methods), - base_package=base_package, - plugin_package=plugin_package, - plugin_name=plugin_name, - notification_package=notification_package)) - callback_file.flush() - callback_file.close() - - callback_file = open(os.path.join(notification_package, "%sNotificationRegistryProvider.java" % plugin_name), 'w') - callback_file.write(notification_provider_template.substitute(inputfile=inputfile, - base_package=base_package, - plugin_package=plugin_package, - plugin_name=plugin_name, - notification_package=notification_package)) - callback_file.flush() - callback_file.close() - diff --git a/vpp-api/java/jvpp/gen/jvppgen/types_gen.py b/vpp-api/java/jvpp/gen/jvppgen/types_gen.py deleted file mode 100644 index d12fb3d7..00000000 --- a/vpp-api/java/jvpp/gen/jvppgen/types_gen.py +++ /dev/null @@ -1,227 +0,0 @@ -#!/usr/bin/env python -# -# 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. - -import os -from string import Template - -import util -import jni_gen -import dto_gen - -type_template = Template(""" -package $plugin_package.$type_package; - -/** - *

This class represents $c_type_name type definition. - *
It was generated by types_gen.py based on $inputfile preparsed data: - *

-$docs
- * 
- */ -public final class $java_type_name { -$fields -$methods -} -""") - -field_template = Template(""" public $type $name;\n""") - - -def generate_type_fields(type_definition): - """ - Generates fields for class representing typeonly definition - :param type_definition: python representation of typeonly definition - :return: string representing class fields - """ - fields = "" - for t in zip(type_definition['types'], type_definition['args']): - field_name = util.underscore_to_camelcase(t[1]) - fields += field_template.substitute(type=util.jni_2_java_type_mapping[t[0]], - name=field_name) - return fields - -object_struct_setter_template = Template(""" - { - jclass ${field_reference_name}Class = (*env)->FindClass(env, "${class_FQN}"); - memset (&(mp->${c_name}), 0, sizeof (mp->${c_name})); - ${struct_initialization} - } -""") - -object_array_struct_setter_template = Template(""" - { - jclass ${field_reference_name}ArrayElementClass = (*env)->FindClass(env, "${class_FQN}"); - if (${field_reference_name}) { - size_t _i; - jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name}); - ${field_length_check} - for (_i = 0; _i < cnt; _i++) { - jobject ${field_reference_name}ArrayElement = (*env)->GetObjectArrayElement(env, ${field_reference_name}, _i); - memset (&(mp->${c_name}[_i]), 0, sizeof (mp->${c_name}[_i])); - ${struct_initialization} - } - } - } -""") - -object_dto_field_setter_template = Template(""" - { - jclass ${field_reference_name}Class = (*env)->FindClass(env, "${class_FQN}"); - jmethodID ${field_reference_name}Constructor = (*env)->GetMethodID(env, ${field_reference_name}Class, "", "()V"); - jobject ${field_reference_name} = (*env)->NewObject(env, ${field_reference_name}Class, ${field_reference_name}Constructor); - ${type_initialization} - (*env)->SetObjectField(env, dto, ${field_reference_name}FieldId, ${field_reference_name}); - } -""") - -object_array_dto_field_setter_template = Template(""" - { - jclass ${field_reference_name}Class = (*env)->FindClass(env, "${class_FQN}"); - jobjectArray ${field_reference_name} = (*env)->NewObjectArray(env, ${field_length}, ${field_reference_name}Class, 0); - unsigned int _i; - for (_i = 0; _i < ${field_length}; _i++) { - jmethodID ${field_reference_name}Constructor = (*env)->GetMethodID(env, ${field_reference_name}Class, "", "()V"); - jobject ${field_reference_name}ArrayElement = (*env)->NewObject(env, ${field_reference_name}Class, ${field_reference_name}Constructor); - ${type_initialization} - (*env)->SetObjectArrayElement(env, ${field_reference_name}, _i, ${field_reference_name}ArrayElement); - } - (*env)->SetObjectField(env, dto, ${field_reference_name}FieldId, ${field_reference_name}); - } -""") - - -def generate_struct_initialization(type_def, c_name_prefix, object_name, indent): - struct_initialization = "" - # field identifiers - for t in zip(type_def['types'], type_def['args'], type_def['lengths']): - field_reference_name = "${c_name}" + util.underscore_to_camelcase_upper(t[1]) - field_name = util.underscore_to_camelcase(t[1]) - struct_initialization += jni_gen.jni_request_binding_for_type(field_type=t[0], c_name=c_name_prefix + t[1], - field_reference_name=field_reference_name, - field_name=field_name, - field_length=t[2][0], - is_variable_len_array=t[2][1], - object_name=object_name) - return indent + struct_initialization.replace('\n', '\n' + indent) - - -def generate_type_setter(handler_name, type_def, c_name_prefix, object_name, indent): - type_initialization = "" - for t in zip(type_def['types'], type_def['args'], type_def['lengths']): - field_length = t[2][0] - is_variable_len_array = t[2][1] - length_field_type = None - if is_variable_len_array: - length_field_type = type_def['types'][type_def['args'].index(field_length)] - type_initialization += jni_gen.jni_reply_handler_for_type(handler_name=handler_name, - ref_name="${field_reference_name}", - field_type=t[0], c_name=c_name_prefix + t[1], - field_reference_name="${c_name}" + util.underscore_to_camelcase_upper(t[1]), - field_name=util.underscore_to_camelcase(t[1]), - field_length=field_length, - is_variable_len_array=is_variable_len_array, - length_field_type=length_field_type, - object_name=object_name) - return indent + type_initialization.replace('\n', '\n' + indent) - - -def generate_types(types_list, plugin_package, types_package, inputfile): - """ - Generates Java representation of custom types defined in api file. - """ - - # - if not types_list: - print "Skipping custom types generation (%s does not define custom types)." % inputfile - return - - print "Generating custom types" - - if not os.path.exists(types_package): - raise Exception("%s folder is missing" % types_package) - - for type in types_list: - c_type_name = type['name'] - java_type_name = util.underscore_to_camelcase_upper(type['name']) - dto_path = os.path.join(types_package, java_type_name + ".java") - - fields = generate_type_fields(type) - - dto_file = open(dto_path, 'w') - dto_file.write(type_template.substitute(plugin_package=plugin_package, - type_package=types_package, - c_type_name=c_type_name, - inputfile=inputfile, - docs=util.api_message_to_javadoc(type), - java_type_name=java_type_name, - fields=fields, - methods=dto_gen.generate_dto_base_methods(java_type_name, type) - )) - - # update type mappings: - # todo fix vpe.api to use type_name instead of vl_api_type_name_t - type_name = "vl_api_" + c_type_name + "_t" - java_fqn = "%s.%s.%s" % (plugin_package, types_package, java_type_name) - util.vpp_2_jni_type_mapping[type_name] = "jobject" - util.vpp_2_jni_type_mapping[type_name + "[]"] = "jobjectArray" - util.jni_2_java_type_mapping[type_name] = java_fqn - util.jni_2_java_type_mapping[type_name + "[]"] = java_fqn + "[]" - jni_name = java_fqn.replace('.', "/") - jni_signature = "L" + jni_name + ";" - util.jni_2_signature_mapping[type_name] = "L" + jni_name + ";" - util.jni_2_signature_mapping[type_name + "[]"] = "[" + jni_signature - util.jni_field_accessors[type_name] = "ObjectField" - util.jni_field_accessors[type_name + "[]"] = "ObjectField" - - jni_gen.struct_setter_templates[type_name] = Template( - object_struct_setter_template.substitute( - c_name="${c_name}", - field_reference_name="${field_reference_name}", - class_FQN=jni_name, - struct_initialization=generate_struct_initialization(type, "${c_name}.", - "${field_reference_name}", ' ' * 4)) - ) - - jni_gen.struct_setter_templates[type_name+ "[]"] = Template( - object_array_struct_setter_template.substitute( - c_name="${c_name}", - field_reference_name="${field_reference_name}", - field_length_check="${field_length_check}", - class_FQN=jni_name, - struct_initialization=generate_struct_initialization(type, "${c_name}[_i].", - "${field_reference_name}ArrayElement", ' ' * 8)) - ) - - jni_gen.dto_field_setter_templates[type_name] = Template( - object_dto_field_setter_template.substitute( - field_reference_name="${field_reference_name}", - field_length="${field_length}", - class_FQN=jni_name, - type_initialization=generate_type_setter(c_type_name, type, "${c_name}.", - "${field_reference_name}", ' ' * 4)) - ) - - jni_gen.dto_field_setter_templates[type_name + "[]"] = Template( - object_array_dto_field_setter_template.substitute( - field_reference_name="${field_reference_name}", - field_length="${field_length}", - class_FQN=jni_name, - type_initialization=generate_type_setter(c_type_name, type, "${c_name}[_i].", - "${field_reference_name}ArrayElement", ' ' * 8)) - ) - - dto_file.flush() - dto_file.close() - diff --git a/vpp-api/java/jvpp/gen/jvppgen/util.py b/vpp-api/java/jvpp/gen/jvppgen/util.py deleted file mode 100644 index fc971c17..00000000 --- a/vpp-api/java/jvpp/gen/jvppgen/util.py +++ /dev/null @@ -1,220 +0,0 @@ -#!/usr/bin/env python -# -# 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. - -import os, pprint -from os import removedirs - - -def underscore_to_camelcase(name): - name = name.title().replace("_", "") - return name[0].lower() + name[1:] - - -def underscore_to_camelcase_upper(name): - name = name.title().replace("_", "") - return name[0].upper() + name[1:] - - -def remove_folder(folder): - """ Remove folder with all its files """ - for root, dirs, files in os.walk(folder, topdown=False): - for name in files: - os.remove(os.path.join(root, name)) - removedirs(folder) - - -reply_suffixes = ("reply", "details", "l2fibtableentry") - - -def is_reply(name): - return name.lower().endswith(reply_suffixes) - - -def is_details(name): - return name.lower().endswith(reply_suffixes[1]) or name.lower().endswith(reply_suffixes[2]) - - -def is_retval_field(name): - return name == 'retval' - -dump_suffix = "dump" - - -def is_dump(name): - return name.lower().endswith(dump_suffix) - - -def get_reply_suffix(name): - for reply_suffix in reply_suffixes: - if name.lower().endswith(reply_suffix): - if reply_suffix == reply_suffixes[2]: - # FIXME workaround for l2_fib_table_entry - return 'entry' - else: - return reply_suffix - -# Mapping according to: -# http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html -# -# Unsigned types are converted to signed java types that have the same size. -# It is the API user responsibility to interpret them correctly. -jni_2_java_type_mapping = {'u8': 'byte', - 'u8[]': 'byte[]', - 'i8': 'byte', - 'i8[]': 'byte[]', - 'u16': 'short', - 'u16[]': 'short[]', - 'i16': 'short', - 'i16[]': 'short[]', - 'u32': 'int', - 'u32[]': 'int[]', - 'i32': 'int', - 'i32[]': 'int[]', - 'u64': 'long', - 'u64[]': 'long[]', - 'i64': 'long', - 'i64[]': 'long[]', - 'f64': 'double', - 'f64[]': 'double[]' - } - -vpp_2_jni_type_mapping = {'u8': 'jbyte', - 'u8[]': 'jbyteArray', - 'i8': 'jbyte', - 'u8[]': 'jbyteArray', - 'u16': 'jshort', - 'u16[]': 'jshortArray', - 'i16': 'jshort', - 'i16[]': 'jshortArray', - 'u32': 'jint', - 'u32[]': 'jintArray', - 'i32': 'jint', - 'i32[]': 'jintArray', - 'u64': 'jlong', - 'u64[]': 'jlongArray', - 'i64': 'jlong', - 'i64[]': 'jlongArray', - 'f64': 'jdouble', - 'f64[]': 'jdoubleArray' - } - -# https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/types.html#type_signatures -jni_2_signature_mapping = {'u8': 'B', - 'u8[]': '[B', - 'i8': 'B', - 'i8[]': '[B', - 'u16': 'S', - 'u16[]': '[S', - 'i16': 'S', - 'i16[]': '[S', - 'u32': 'I', - 'u32[]': '[I', - 'i32': 'I', - 'i32[]': '[I', - 'u64': 'J', - 'u64[]': '[J', - 'i64': 'J', - 'i64[]': '[J', - 'f64': 'D', - 'f64[]': '[D' - } - -# https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#Get_type_Field_routines -jni_field_accessors = {'u8': 'ByteField', - 'u8[]': 'ObjectField', - 'i8': 'ByteField', - 'i8[]': 'ObjectField', - 'u16': 'ShortField', - 'u16[]': 'ObjectField', - 'i16': 'ShortField', - 'i16[]': 'ObjectField', - 'u32': 'IntField', - 'u32[]': 'ObjectField', - 'i32': 'IntField', - 'i32[]': 'ObjectField', - 'u64': 'LongField', - 'u64[]': 'ObjectField', - 'i64': 'LongField', - 'i64[]': 'ObjectField', - 'f64': 'DoubleField', - 'f64[]': 'ObjectField' - } - - -# vpe.api calls that do not follow naming conventions and have to be handled exceptionally when finding reply -> request mapping -# FIXME in vpe.api -unconventional_naming_rep_req = { - 'cli_reply': 'cli_request', - 'vnet_summary_stats_reply': 'vnet_get_summary_stats', - # This below is actually a sub-details callback. We cannot derive the mapping of dump request - # belonging to this sub-details from naming conventions. We need special mapping - 'bridge_domain_sw_if_details': 'bridge_domain', - # This is standard dump call + details reply. However it's not called details but entry - 'l2_fib_table_entry': 'l2_fib_table' - } - -# -# FIXME no convention in the naming of events (notifications) in vpe.api -notifications_message_suffixes = ("event", "counters") -notification_messages_reused = ["sw_interface_set_flags"] - -# messages that must be ignored. These messages are INSUFFICIENTLY marked as disabled in vpe.api -# FIXME -ignored_messages = ["is_address_reachable"] - - -def is_notification(name): - """ Returns true if the structure is a notification regardless of its no other use """ - return is_just_notification(name) or name.lower() in notification_messages_reused - - -def is_just_notification(name): - """ Returns true if the structure is just a notification and has no other use """ - return name.lower().endswith(notifications_message_suffixes) - - -def is_ignored(param): - return param.lower() in ignored_messages - - -def remove_reply_suffix(camel_case_name_with_suffix): - return remove_suffix(camel_case_name_with_suffix, get_reply_suffix(camel_case_name_with_suffix)) - - -def remove_suffix(camel_case_name_with_suffix, suffix): - suffix_length = len(suffix) - return camel_case_name_with_suffix[:-suffix_length] if suffix_length != 0 else camel_case_name_with_suffix - - -def is_control_ping(camel_case_name_with_suffix): - return camel_case_name_with_suffix.lower().startswith("controlping"); - - -def api_message_to_javadoc(api_message): - """ Converts vpe.api message description to javadoc """ - str = pprint.pformat(api_message, indent=4, width=120, depth=None) - return " * " + str.replace("\n", "\n * ") - - -notification_dto_suffix = "Notification" - - -def add_notification_suffix(camel_case_dto_name): - camel_case_dto_name += notification_dto_suffix - return camel_case_dto_name - - -def is_array(java_type_as_string): - return java_type_as_string.endswith("[]") diff --git a/vpp-api/java/m4/ax_check_java_home.m4 b/vpp-api/java/m4/ax_check_java_home.m4 deleted file mode 100644 index cfe8f589..00000000 --- a/vpp-api/java/m4/ax_check_java_home.m4 +++ /dev/null @@ -1,80 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_check_java_home.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_CHECK_JAVA_HOME -# -# DESCRIPTION -# -# Check for Sun Java (JDK / JRE) installation, where the 'java' VM is in. -# If found, set environment variable JAVA_HOME = Java installation home, -# else left JAVA_HOME untouch, which in most case means JAVA_HOME is -# empty. -# -# LICENSE -# -# Copyright (c) 2008 Gleen Salmon -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation; either version 2 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program. If not, see . -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 6 - -AU_ALIAS([AC_CHECK_JAVA_HOME], [AX_CHECK_JAVA_HOME]) - -AC_DEFUN([AX_CHECK_JAVA_HOME], -[AC_MSG_CHECKING([for JAVA_HOME]) -# We used a fake loop so that we can use "break" to exit when the result -# is found. -while true -do - # If the user defined JAVA_HOME, don't touch it. - test "${JAVA_HOME+set}" = set && break - - # On Mac OS X 10.5 and following, run /usr/libexec/java_home to get - # the value of JAVA_HOME to use. - # (http://developer.apple.com/library/mac/#qa/qa2001/qa1170.html). - JAVA_HOME=`/usr/libexec/java_home 2>/dev/null` - test x"$JAVA_HOME" != x && break - - # See if we can find the java executable, and compute from there. - TRY_JAVA_HOME=`ls -dr /usr/java/* 2> /dev/null | head -n 1` - if test x$TRY_JAVA_HOME != x; then - PATH=$PATH:$TRY_JAVA_HOME/bin - fi - AC_PATH_PROG([JAVA_PATH_NAME], [java]) - if test "x$JAVA_PATH_NAME" != x; then - JAVA_HOME=`echo $JAVA_PATH_NAME | sed "s/\(.*\)[[/]]bin[[/]]java.*/\1/"` - break - fi - - AC_MSG_NOTICE([Could not compute JAVA_HOME]) - break -done -AC_MSG_RESULT([$JAVA_HOME]) -]) diff --git a/vpp-api/java/m4/ax_check_java_plugin.m4 b/vpp-api/java/m4/ax_check_java_plugin.m4 deleted file mode 100644 index 920753e5..00000000 --- a/vpp-api/java/m4/ax_check_java_plugin.m4 +++ /dev/null @@ -1,101 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_check_java_plugin.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_CHECK_JAVA_PLUGIN() -# -# DESCRIPTION -# -# This macro sets to empty on failure and to a compatible -# version of plugin.jar otherwise. Directories searched are /usr/java/* -# and /usr/local/java/*, which are assumed to be j{dk,re} installations. -# Apply the shell variable as you see fit. If sun changes things so -# /lib/plugin.jar is not the magic file it will stop working. -# -# This macro assumes that unzip, zipinfo or pkzipc is available (and can -# list the contents of the jar archive). The first two are assumed to work -# similarly enough to the infozip versisonms. The pkzipc version is -# assumed to work if I undertstand the documentation on pkware's site but -# YMMV. I do not have access to pwkware's version to test it. -# -# LICENSE -# -# Copyright (c) 2008 Duncan Simpson -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation; either version 2 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program. If not, see . -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 7 - -AU_ALIAS([DPS_CHECK_PLUGIN], [AX_CHECK_JAVA_PLUGIN]) -AC_DEFUN([AX_CHECK_JAVA_PLUGIN], -[AC_REQUIRE([AC_PROG_AWK]) -AC_REQUIRE([AC_PROG_FGREP]) -AC_CHECK_PROG(ZIPINFO,[zipinfo unzip pkzipc]) -AC_MSG_CHECKING([for the java plugin]) -case "x$ZIPINFO" in -[*/zipinfo)] - zipinf="zipinfo -1" ;; -[*/unzip)] - zipinf="unzip -l";; -[*/pkzipc)] - ziping="unzipc -view";; -[x*)] - AC_MSG_RESULT([skiped, none of zipinfo, unzip and pkzipc found]) - AC_SUBST($1,[]) - zipinf="";; -esac -if test "x$zipinf" != "x"; then -jplugin="" -for jhome in `ls -dr /usr/java/* /usr/local/java/* 2> /dev/null`; do -for jfile in lib/plugin.jar jre/lib/plugin.jar; do -if test "x$jplugin" = "x" && test -f "$jhome/$jfile"; then -eval "$zipinf $jhome/$jfile | $AWK '{ print \$NF; }' | $FGREP netscape/javascript/JSObject" >/dev/null 2>/dev/null -if test $? -eq 0; then -dnl Some version of gcj (and javac) refuse to work with some files -dnl that pass this test. To stop this problem make sure that the compiler -dnl still works with this jar file in the classpath -cat << \EOF > Test.java -/* [#]line __oline__ "configure" */ -public class Test { -} -EOF -if eval "$JAVAC -classpath $jhome/$jfile Test.java 2>/dev/null >/dev/null" && test -f Test.class; then -jplugin="$jhome/$jfile" -fi -rm -f Test.java Test.class -fi; fi; done; done -if test "x$jplugin" != "x"; then -AC_SUBST($1,$jplugin) -AC_MSG_RESULT($jplugin) -else -AC_MSG_RESULT([java plugin not found]) -AC_SUBST($1,[]) -fi -fi -]) diff --git a/vpp-api/java/m4/ax_java_check_class.m4 b/vpp-api/java/m4/ax_java_check_class.m4 deleted file mode 100644 index 917638ae..00000000 --- a/vpp-api/java/m4/ax_java_check_class.m4 +++ /dev/null @@ -1,85 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_java_check_class.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_JAVA_CHECK_CLASS(,,) -# -# DESCRIPTION -# -# Test if a Java class is available. Based on AX_PROG_JAVAC_WORKS. This -# version uses a cache variable which is both compiler, options and -# classpath dependent (so if you switch from javac to gcj it correctly -# notices and redoes the test). -# -# The macro tries to compile a minimal program importing . Some -# newer compilers moan about the failure to use this but fail or produce a -# class file anyway. All moaing is sunk to /dev/null since I only wanted -# to know if the class could be imported. This is a recommended followup -# to AX_CHECK_JAVA_PLUGIN with classpath appropriately adjusted. -# -# LICENSE -# -# Copyright (c) 2008 Duncan Simpson -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation; either version 2 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program. If not, see . -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 9 - -AU_ALIAS([DPS_JAVA_CHECK_CLASS], [AX_JAVA_CHECK_CLASS]) -AC_DEFUN([AX_JAVA_CHECK_CLASS],[ -m4_define([cache_val],[m4_translit(ax_cv_have_java_class_$1, " ." ,"__")]) -if test "x$CLASSPATH" != "x"; then -xtra=" with classpath ${CLASSPATH}" -xopts=`echo ${CLASSPATH} | ${SED} 's/^ *://'` -xopts="-classpath $xopts" -else xtra=""; xopts=""; fi -cache_var="cache_val"AS_TR_SH([_Jc_${JAVAC}_Cp_${CLASSPATH}]) -AC_CACHE_CHECK([if the $1 class is available$xtra], [$cache_var], [ -JAVA_TEST=Test.java -CLASS_TEST=Test.class -cat << \EOF > $JAVA_TEST -/* [#]xline __oline__ "configure" */ -import $1; -public class Test { -} -EOF -if AC_TRY_COMMAND($JAVAC $JAVACFLAGS $xopts $JAVA_TEST) >/dev/null 2>&1; then - eval "${cache_var}=yes" -else - eval "${cache_var}=no" - echo "configure: failed program was:" >&AS_MESSAGE_LOG_FD - cat $JAVA_TEST >&AS_MESSAGE_LOG_FD -fi -rm -f $JAVA_TEST $CLASS_TEST -]) -if eval 'test "x$'${cache_var}'" = "xyes"'; then -$2 -true; else -$3 -false; fi]) diff --git a/vpp-api/java/m4/ax_java_options.m4 b/vpp-api/java/m4/ax_java_options.m4 deleted file mode 100644 index 36c10d92..00000000 --- a/vpp-api/java/m4/ax_java_options.m4 +++ /dev/null @@ -1,48 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_java_options.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_JAVA_OPTIONS -# -# DESCRIPTION -# -# AX_JAVA_OPTIONS adds configure command line options used for Java m4 -# macros. This Macro is optional. -# -# Note: This is part of the set of autoconf M4 macros for Java programs. -# It is VERY IMPORTANT that you download the whole set, some macros depend -# on other. Unfortunately, the autoconf archive does not support the -# concept of set of macros, so I had to break it for submission. The -# general documentation, as well as the sample configure.in, is included -# in the AX_PROG_JAVA macro. -# -# LICENSE -# -# Copyright (c) 2008 Devin Weaver -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 6 - -AU_ALIAS([AC_JAVA_OPTIONS], [AX_JAVA_OPTIONS]) -AC_DEFUN([AX_JAVA_OPTIONS],[ -AC_ARG_WITH(java-prefix, - [ --with-java-prefix=PFX prefix where Java runtime is installed (optional)]) -AC_ARG_WITH(javac-flags, - [ --with-javac-flags=FLAGS flags to pass to the Java compiler (optional)]) -AC_ARG_WITH(java-flags, - [ --with-java-flags=FLAGS flags to pass to the Java VM (optional)]) -JAVAPREFIX=$with_java_prefix -JAVACFLAGS=$with_javac_flags -JAVAFLAGS=$with_java_flags -AC_SUBST(JAVAPREFIX)dnl -AC_SUBST(JAVACFLAGS)dnl -AC_SUBST(JAVAFLAGS)dnl -AC_SUBST(JAVA)dnl -AC_SUBST(JAVAC)dnl -]) diff --git a/vpp-api/java/m4/ax_libgcj_jar.m4 b/vpp-api/java/m4/ax_libgcj_jar.m4 deleted file mode 100644 index 5e942857..00000000 --- a/vpp-api/java/m4/ax_libgcj_jar.m4 +++ /dev/null @@ -1,83 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_libgcj_jar.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_LIBGCJ_JAR -# -# DESCRIPTION -# -# Locate libgcj.jar so you can place it before everything else when using -# gcj. -# -# LICENSE -# -# Copyright (c) 2008 Duncan Simpson -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation; either version 2 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program. If not, see . -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 9 - -AU_ALIAS([DPS_LIBGCJ_JAR], [AX_LIBGCJ_JAR]) -AC_DEFUN([AX_LIBGCJ_JAR], -[ -AC_REQUIRE([AC_EXEEXT]) -AC_REQUIRE([AX_PROG_JAVAC]) -AC_REQUIRE([AC_PROG_FGREP]) -AC_PROG_SED -if test "x$SED" = "x"; then -AC_MSG_WARN([sed not avaiable, so libgcj.jar test skipped]) -else -AC_MSG_CHECKING([if $JAVAC is gcj]); -jc=`eval "[echo x$JAVAC | $SED 's/^x.*\\/\\([^/]*\\)\$/x\\1/;s/^ *\\([^ ]*\\) .*$/\\1/;s/"$EXEEXT"$//']"` -if test "x$jc" != "xxgcj"; then -AC_MSG_RESULT(no) -else -AC_MSG_RESULT(yes) -AC_MSG_CHECKING([libgcj.jar location]) -save_cp="$CLASSPATH"; -unset CLASSPATH; -AC_MSG_CHECKING([gcj default classpath]) -cat << \EOF > Test.java -/* [#]line __oline__ "configure" */ -public class Test { -} -EOF -lgcj=`eval "[$JAVAC -v -C Test.java 2>&1 | $FGREP \\(system\\) | $SED 's/^ *\\([^ ]*\\) .*$/\\1/;s/\\.jar\\//.jar/']"`; -if test -f Test.class && test "x$lgcj" != "x"; then -AC_MSG_RESULT($lgcj) -$1="$lgcj:" -else -AC_MSG_RESULT(failed) -$1="" -fi -if test "x$save_cp" != "x"; then CLASSPATH="$save_cp"; fi -rm -f Test.java Test.class -fi -fi -]) diff --git a/vpp-api/java/m4/ax_prog_jar.m4 b/vpp-api/java/m4/ax_prog_jar.m4 deleted file mode 100644 index 3c60fcaf..00000000 --- a/vpp-api/java/m4/ax_prog_jar.m4 +++ /dev/null @@ -1,49 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_prog_jar.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_PROG_JAR -# -# DESCRIPTION -# -# AX_PROG_JAR tests for an existing jar program. It uses the environment -# variable JAR then tests in sequence various common jar programs. -# -# If you want to force a specific compiler: -# -# - at the configure.in level, set JAR=yourcompiler before calling -# AX_PROG_JAR -# -# - at the configure level, setenv JAR -# -# You can use the JAR variable in your Makefile.in, with @JAR@. -# -# Note: This macro depends on the autoconf M4 macros for Java programs. It -# is VERY IMPORTANT that you download that whole set, some macros depend -# on other. Unfortunately, the autoconf archive does not support the -# concept of set of macros, so I had to break it for submission. -# -# The general documentation of those macros, as well as the sample -# configure.in, is included in the AX_PROG_JAVA macro. -# -# LICENSE -# -# Copyright (c) 2008 Egon Willighagen -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 7 - -AU_ALIAS([AC_PROG_JAR], [AX_PROG_JAR]) -AC_DEFUN([AX_PROG_JAR],[ -AS_IF([test "x$JAVAPREFIX" = x], - [test "x$JAR" = x && AC_CHECK_PROGS([JAR], [jar])], - [test "x$JAR" = x && AC_CHECK_PROGS([JAR], [jar], [], [$JAVAPREFIX/bin])]) -test "x$JAR" = x && AC_MSG_ERROR([no acceptable jar program found in \$PATH]) -AC_PROVIDE([$0])dnl -]) diff --git a/vpp-api/java/m4/ax_prog_java.m4 b/vpp-api/java/m4/ax_prog_java.m4 deleted file mode 100644 index 03961db5..00000000 --- a/vpp-api/java/m4/ax_prog_java.m4 +++ /dev/null @@ -1,115 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_prog_java.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_PROG_JAVA -# -# DESCRIPTION -# -# Here is a summary of the main macros: -# -# AX_PROG_JAVAC: finds a Java compiler. -# -# AX_PROG_JAVA: finds a Java virtual machine. -# -# AX_CHECK_CLASS: finds if we have the given class (beware of CLASSPATH!). -# -# AX_CHECK_RQRD_CLASS: finds if we have the given class and stops -# otherwise. -# -# AX_TRY_COMPILE_JAVA: attempt to compile user given source. -# -# AX_TRY_RUN_JAVA: attempt to compile and run user given source. -# -# AX_JAVA_OPTIONS: adds Java configure options. -# -# AX_PROG_JAVA tests an existing Java virtual machine. It uses the -# environment variable JAVA then tests in sequence various common Java -# virtual machines. For political reasons, it starts with the free ones. -# You *must* call [AX_PROG_JAVAC] before. -# -# If you want to force a specific VM: -# -# - at the configure.in level, set JAVA=yourvm before calling AX_PROG_JAVA -# -# (but after AC_INIT) -# -# - at the configure level, setenv JAVA -# -# You can use the JAVA variable in your Makefile.in, with @JAVA@. -# -# *Warning*: its success or failure can depend on a proper setting of the -# CLASSPATH env. variable. -# -# TODO: allow to exclude virtual machines (rationale: most Java programs -# cannot run with some VM like kaffe). -# -# Note: This is part of the set of autoconf M4 macros for Java programs. -# It is VERY IMPORTANT that you download the whole set, some macros depend -# on other. Unfortunately, the autoconf archive does not support the -# concept of set of macros, so I had to break it for submission. -# -# A Web page, with a link to the latest CVS snapshot is at -# . -# -# This is a sample configure.in Process this file with autoconf to produce -# a configure script. -# -# AC_INIT(UnTag.java) -# -# dnl Checks for programs. -# AC_CHECK_CLASSPATH -# AX_PROG_JAVAC -# AX_PROG_JAVA -# -# dnl Checks for classes -# AX_CHECK_RQRD_CLASS(org.xml.sax.Parser) -# AX_CHECK_RQRD_CLASS(com.jclark.xml.sax.Driver) -# -# AC_OUTPUT(Makefile) -# -# LICENSE -# -# Copyright (c) 2008 Stephane Bortzmeyer -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation; either version 2 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program. If not, see . -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 9 - -AU_ALIAS([AC_PROG_JAVA], [AX_PROG_JAVA]) -AC_DEFUN([AX_PROG_JAVA],[ -m4_define([m4_ax_prog_java_list], [kaffe java])dnl -AS_IF([test "x$JAVAPREFIX" = x], - [test x$JAVA = x && AC_CHECK_PROGS([JAVA], [m4_ax_prog_java_list])], - [test x$JAVA = x && AC_CHECK_PROGS([JAVA], [m4_ax_prog_java_list], [], [$JAVAPREFIX/bin])]) -test x$JAVA = x && AC_MSG_ERROR([no acceptable Java virtual machine found in \$PATH]) -m4_undefine([m4_ax_prog_java_list])dnl -AX_PROG_JAVA_WORKS -AC_PROVIDE([$0])dnl -]) diff --git a/vpp-api/java/m4/ax_prog_java_cc.m4 b/vpp-api/java/m4/ax_prog_java_cc.m4 deleted file mode 100644 index 3df064ff..00000000 --- a/vpp-api/java/m4/ax_prog_java_cc.m4 +++ /dev/null @@ -1,104 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_prog_java_cc.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_PROG_JAVA_CC -# -# DESCRIPTION -# -# Finds the appropriate java compiler on your path. By preference the java -# compiler is gcj, then jikes then javac. -# -# The macro can take one argument specifying a space separated list of -# java compiler names. -# -# For example: -# -# AX_PROG_JAVA_CC(javac, gcj) -# -# The macro also sets the compiler options variable: JAVA_CC_OPTS to -# something sensible: -# -# - for GCJ it sets it to: @GCJ_OPTS@ -# (if GCJ_OPTS is not yet defined then it is set to "-C") -# -# - no other compiler has applicable options yet -# -# Here's an example configure.in: -# -# AC_INIT(Makefile.in) -# AX_PROG_JAVA_CC() -# AC_OUTPUT(Makefile) -# dnl End. -# -# And here's the start of the Makefile.in: -# -# PROJECT_ROOT := @srcdir@ -# # Tool definitions. -# JAVAC := @JAVA_CC@ -# JAVAC_OPTS := @JAVA_CC_OPTS@ -# JAR_TOOL := @jar_tool@ -# -# LICENSE -# -# Copyright (c) 2008 Nic Ferrier -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation; either version 2 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program. If not, see . -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 4 - -# AX_PROG_JAVA_CC([COMPILER ...]) -# -------------------------- -# COMPILER ... is a space separated list of java compilers to search for. -# This just gives the user an opportunity to specify an alternative -# search list for the java compiler. -AU_ALIAS([AC_PROG_JAVA_CC], [AX_PROG_JAVA_CC]) -AC_DEFUN([AX_PROG_JAVA_CC], -[AC_ARG_VAR([JAVA_CC], [java compiler command])dnl -AC_ARG_VAR([JAVA_CC_FLAGS], [java compiler flags])dnl -m4_ifval([$1], - [AC_CHECK_TOOLS(JAVA_CC, [$1])], -[AC_CHECK_TOOL(JAVA_CC, gcj) -if test -z "$JAVA_CC"; then - AC_CHECK_TOOL(JAVA_CC, javac) -fi -if test -z "$JAVA_CC"; then - AC_CHECK_TOOL(JAVA_CC, jikes) -fi -]) - -if test "$JAVA_CC" = "gcj"; then - if test "$GCJ_OPTS" = ""; then - AC_SUBST(GCJ_OPTS,-C) - fi - AC_SUBST(JAVA_CC_OPTS, @GCJ_OPTS@, - [Define the compilation options for GCJ]) -fi -test -z "$JAVA_CC" && AC_MSG_ERROR([no acceptable java compiler found in \$PATH]) -])# AX_PROG_JAVA_CC diff --git a/vpp-api/java/m4/ax_prog_java_works.m4 b/vpp-api/java/m4/ax_prog_java_works.m4 deleted file mode 100644 index 54e132af..00000000 --- a/vpp-api/java/m4/ax_prog_java_works.m4 +++ /dev/null @@ -1,134 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_prog_java_works.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_PROG_JAVA_WORKS -# -# DESCRIPTION -# -# Internal use ONLY. -# -# Note: This is part of the set of autoconf M4 macros for Java programs. -# It is VERY IMPORTANT that you download the whole set, some macros depend -# on other. Unfortunately, the autoconf archive does not support the -# concept of set of macros, so I had to break it for submission. The -# general documentation, as well as the sample configure.in, is included -# in the AX_PROG_JAVA macro. -# -# LICENSE -# -# Copyright (c) 2008 Stephane Bortzmeyer -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation; either version 2 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program. If not, see . -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 9 - -AU_ALIAS([AC_PROG_JAVA_WORKS], [AX_PROG_JAVA_WORKS]) -AC_DEFUN([AX_PROG_JAVA_WORKS], [ -AC_PATH_PROG(UUDECODE, uudecode, [no]) -if test x$UUDECODE != xno; then -AC_CACHE_CHECK([if uudecode can decode base 64 file], ac_cv_prog_uudecode_base64, [ -dnl /** -dnl * Test.java: used to test if java compiler works. -dnl */ -dnl public class Test -dnl { -dnl -dnl public static void -dnl main( String[] argv ) -dnl { -dnl System.exit (0); -dnl } -dnl -dnl } -cat << \EOF > Test.uue -begin-base64 644 Test.class -yv66vgADAC0AFQcAAgEABFRlc3QHAAQBABBqYXZhL2xhbmcvT2JqZWN0AQAE -bWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARDb2RlAQAPTGluZU51 -bWJlclRhYmxlDAAKAAsBAARleGl0AQAEKEkpVgoADQAJBwAOAQAQamF2YS9s -YW5nL1N5c3RlbQEABjxpbml0PgEAAygpVgwADwAQCgADABEBAApTb3VyY2VG -aWxlAQAJVGVzdC5qYXZhACEAAQADAAAAAAACAAkABQAGAAEABwAAACEAAQAB -AAAABQO4AAyxAAAAAQAIAAAACgACAAAACgAEAAsAAQAPABAAAQAHAAAAIQAB -AAEAAAAFKrcAErEAAAABAAgAAAAKAAIAAAAEAAQABAABABMAAAACABQ= -==== -EOF -if $UUDECODE Test.uue; then - ac_cv_prog_uudecode_base64=yes -else - echo "configure: __oline__: uudecode had trouble decoding base 64 file 'Test.uue'" >&AS_MESSAGE_LOG_FD - echo "configure: failed file was:" >&AS_MESSAGE_LOG_FD - cat Test.uue >&AS_MESSAGE_LOG_FD - ac_cv_prog_uudecode_base64=no -fi -rm -f Test.uue]) -fi -if test x$ac_cv_prog_uudecode_base64 != xyes; then - rm -f Test.class - AC_MSG_WARN([I have to compile Test.class from scratch]) - if test x$ac_cv_prog_javac_works = xno; then - AC_MSG_ERROR([Cannot compile java source. $JAVAC does not work properly]) - fi - if test x$ac_cv_prog_javac_works = x; then - AX_PROG_JAVAC - fi -fi -AC_CACHE_CHECK(if $JAVA works, ac_cv_prog_java_works, [ -JAVA_TEST=Test.java -CLASS_TEST=Test.class -TEST=Test -changequote(, )dnl -cat << \EOF > $JAVA_TEST -/* [#]line __oline__ "configure" */ -public class Test { -public static void main (String args[]) { - System.exit (0); -} } -EOF -changequote([, ])dnl -if test x$ac_cv_prog_uudecode_base64 != xyes; then - if AC_TRY_COMMAND($JAVAC $JAVACFLAGS $JAVA_TEST) && test -s $CLASS_TEST; then - : - else - echo "configure: failed program was:" >&AS_MESSAGE_LOG_FD - cat $JAVA_TEST >&AS_MESSAGE_LOG_FD - AC_MSG_ERROR(The Java compiler $JAVAC failed (see config.log, check the CLASSPATH?)) - fi -fi -if AC_TRY_COMMAND($JAVA -classpath . $JAVAFLAGS $TEST) >/dev/null 2>&1; then - ac_cv_prog_java_works=yes -else - echo "configure: failed program was:" >&AS_MESSAGE_LOG_FD - cat $JAVA_TEST >&AS_MESSAGE_LOG_FD - AC_MSG_ERROR(The Java VM $JAVA failed (see config.log, check the CLASSPATH?)) -fi -rm -fr $JAVA_TEST $CLASS_TEST Test.uue -]) -AC_PROVIDE([$0])dnl -] -) diff --git a/vpp-api/java/m4/ax_prog_javac.m4 b/vpp-api/java/m4/ax_prog_javac.m4 deleted file mode 100644 index d061243c..00000000 --- a/vpp-api/java/m4/ax_prog_javac.m4 +++ /dev/null @@ -1,79 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_prog_javac.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_PROG_JAVAC -# -# DESCRIPTION -# -# AX_PROG_JAVAC tests an existing Java compiler. It uses the environment -# variable JAVAC then tests in sequence various common Java compilers. For -# political reasons, it starts with the free ones. -# -# If you want to force a specific compiler: -# -# - at the configure.in level, set JAVAC=yourcompiler before calling -# AX_PROG_JAVAC -# -# - at the configure level, setenv JAVAC -# -# You can use the JAVAC variable in your Makefile.in, with @JAVAC@. -# -# *Warning*: its success or failure can depend on a proper setting of the -# CLASSPATH env. variable. -# -# TODO: allow to exclude compilers (rationale: most Java programs cannot -# compile with some compilers like guavac). -# -# Note: This is part of the set of autoconf M4 macros for Java programs. -# It is VERY IMPORTANT that you download the whole set, some macros depend -# on other. Unfortunately, the autoconf archive does not support the -# concept of set of macros, so I had to break it for submission. The -# general documentation, as well as the sample configure.in, is included -# in the AX_PROG_JAVA macro. -# -# LICENSE -# -# Copyright (c) 2008 Stephane Bortzmeyer -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation; either version 2 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program. If not, see . -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 7 - -AU_ALIAS([AC_PROG_JAVAC], [AX_PROG_JAVAC]) -AC_DEFUN([AX_PROG_JAVAC],[ -m4_define([m4_ax_prog_javac_list],["gcj -C" guavac jikes javac])dnl -AS_IF([test "x$JAVAPREFIX" = x], - [test "x$JAVAC" = x && AC_CHECK_PROGS([JAVAC], [m4_ax_prog_javac_list])], - [test "x$JAVAC" = x && AC_CHECK_PROGS([JAVAC], [m4_ax_prog_javac_list], [], [$JAVAPREFIX/bin])]) -m4_undefine([m4_ax_prog_javac_list])dnl -test "x$JAVAC" = x && AC_MSG_ERROR([no acceptable Java compiler found in \$PATH]) -AX_PROG_JAVAC_WORKS -AC_PROVIDE([$0])dnl -]) diff --git a/vpp-api/java/m4/ax_prog_javac_works.m4 b/vpp-api/java/m4/ax_prog_javac_works.m4 deleted file mode 100644 index 7dfa1e37..00000000 --- a/vpp-api/java/m4/ax_prog_javac_works.m4 +++ /dev/null @@ -1,72 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_prog_javac_works.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_PROG_JAVAC_WORKS -# -# DESCRIPTION -# -# Internal use ONLY. -# -# Note: This is part of the set of autoconf M4 macros for Java programs. -# It is VERY IMPORTANT that you download the whole set, some macros depend -# on other. Unfortunately, the autoconf archive does not support the -# concept of set of macros, so I had to break it for submission. The -# general documentation, as well as the sample configure.in, is included -# in the AX_PROG_JAVA macro. -# -# LICENSE -# -# Copyright (c) 2008 Stephane Bortzmeyer -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation; either version 2 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program. If not, see . -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 6 - -AU_ALIAS([AC_PROG_JAVAC_WORKS], [AX_PROG_JAVAC_WORKS]) -AC_DEFUN([AX_PROG_JAVAC_WORKS],[ -AC_CACHE_CHECK([if $JAVAC works], ac_cv_prog_javac_works, [ -JAVA_TEST=Test.java -CLASS_TEST=Test.class -cat << \EOF > $JAVA_TEST -/* [#]line __oline__ "configure" */ -public class Test { -} -EOF -if AC_TRY_COMMAND($JAVAC $JAVACFLAGS $JAVA_TEST) >/dev/null 2>&1; then - ac_cv_prog_javac_works=yes -else - AC_MSG_ERROR([The Java compiler $JAVAC failed (see config.log, check the CLASSPATH?)]) - echo "configure: failed program was:" >&AS_MESSAGE_LOG_FD - cat $JAVA_TEST >&AS_MESSAGE_LOG_FD -fi -rm -f $JAVA_TEST $CLASS_TEST -]) -AC_PROVIDE([$0])dnl -]) diff --git a/vpp-api/java/m4/ax_prog_javadoc.m4 b/vpp-api/java/m4/ax_prog_javadoc.m4 deleted file mode 100644 index bcb6045a..00000000 --- a/vpp-api/java/m4/ax_prog_javadoc.m4 +++ /dev/null @@ -1,50 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_prog_javadoc.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_PROG_JAVADOC -# -# DESCRIPTION -# -# AX_PROG_JAVADOC tests for an existing javadoc generator. It uses the -# environment variable JAVADOC then tests in sequence various common -# javadoc generator. -# -# If you want to force a specific compiler: -# -# - at the configure.in level, set JAVADOC=yourgenerator before calling -# AX_PROG_JAVADOC -# -# - at the configure level, setenv JAVADOC -# -# You can use the JAVADOC variable in your Makefile.in, with @JAVADOC@. -# -# Note: This macro depends on the autoconf M4 macros for Java programs. It -# is VERY IMPORTANT that you download that whole set, some macros depend -# on other. Unfortunately, the autoconf archive does not support the -# concept of set of macros, so I had to break it for submission. -# -# The general documentation of those macros, as well as the sample -# configure.in, is included in the AX_PROG_JAVA macro. -# -# LICENSE -# -# Copyright (c) 2008 Egon Willighagen -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 8 - -AU_ALIAS([AC_PROG_JAVADOC], [AX_PROG_JAVADOC]) -AC_DEFUN([AX_PROG_JAVADOC],[ -AS_IF([test "x$JAVAPREFIX" = x], - [test "x$JAVADOC" = x && AC_CHECK_PROGS([JAVADOC], [javadoc])], - [test "x$JAVADOC" = x && AC_CHECK_PROGS([JAVADOC], [javadoc], [], [$JAVAPREFIX/bin])]) -test "x$JAVADOC" = x && AC_MSG_ERROR([no acceptable javadoc generator found in \$PATH]) -AC_PROVIDE([$0])dnl -]) diff --git a/vpp-api/java/m4/ax_prog_javah.m4 b/vpp-api/java/m4/ax_prog_javah.m4 deleted file mode 100644 index cefc616d..00000000 --- a/vpp-api/java/m4/ax_prog_javah.m4 +++ /dev/null @@ -1,64 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_prog_javah.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_PROG_JAVAH -# -# DESCRIPTION -# -# AX_PROG_JAVAH tests the availability of the javah header generator and -# looks for the jni.h header file. If available, JAVAH is set to the full -# path of javah and CPPFLAGS is updated accordingly. -# -# LICENSE -# -# Copyright (c) 2008 Luc Maisonobe -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 8 - -AU_ALIAS([AC_PROG_JAVAH], [AX_PROG_JAVAH]) -AC_DEFUN([AX_PROG_JAVAH],[ -AC_REQUIRE([AC_CANONICAL_BUILD])dnl -AC_REQUIRE([AC_PROG_CPP])dnl -AC_PATH_PROG(JAVAH,javah) -AS_IF([test -n "$ac_cv_path_JAVAH"], - [ - AC_TRY_CPP([#include ],,[ - ac_save_CPPFLAGS="$CPPFLAGS" - _ACJAVAH_FOLLOW_SYMLINKS("$ac_cv_path_JAVAH") - ax_prog_javah_bin_dir=`AS_DIRNAME([$_ACJAVAH_FOLLOWED])` - ac_dir="`AS_DIRNAME([$ax_prog_javah_bin_dir])`/include" - AS_CASE([$build_os], - [cygwin*], - [ac_machdep=win32], - [ac_machdep=`AS_ECHO($build_os) | sed 's,[[-0-9]].*,,'`]) - CPPFLAGS="$ac_save_CPPFLAGS -I$ac_dir -I$ac_dir/$ac_machdep" - AC_TRY_CPP([#include ], - ac_save_CPPFLAGS="$CPPFLAGS", - AC_MSG_WARN([unable to include ])) - CPPFLAGS="$ac_save_CPPFLAGS"]) - ]) -]) - -AC_DEFUN([_ACJAVAH_FOLLOW_SYMLINKS],[ -# find the include directory relative to the javac executable -_cur="$1" -while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do - AC_MSG_CHECKING([symlink for $_cur]) - _slink=`ls -ld "$_cur" | sed 's/.* -> //'` - case "$_slink" in - /*) _cur="$_slink";; - # 'X' avoids triggering unwanted echo options. - *) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";; - esac - AC_MSG_RESULT([$_cur]) -done -_ACJAVAH_FOLLOWED="$_cur" -]) diff --git a/vpp-api/java/m4/ax_try_compile_java.m4 b/vpp-api/java/m4/ax_try_compile_java.m4 deleted file mode 100644 index a8ed6b2a..00000000 --- a/vpp-api/java/m4/ax_try_compile_java.m4 +++ /dev/null @@ -1,55 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_try_compile_java.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_TRY_COMPILE_JAVA -# -# DESCRIPTION -# -# AX_TRY_COMPILE_JAVA attempt to compile user given source. -# -# *Warning*: its success or failure can depend on a proper setting of the -# CLASSPATH env. variable. -# -# Note: This is part of the set of autoconf M4 macros for Java programs. -# It is VERY IMPORTANT that you download the whole set, some macros depend -# on other. Unfortunately, the autoconf archive does not support the -# concept of set of macros, so I had to break it for submission. The -# general documentation, as well as the sample configure.in, is included -# in the AX_PROG_JAVA macro. -# -# LICENSE -# -# Copyright (c) 2008 Devin Weaver -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 8 - -AU_ALIAS([AC_TRY_COMPILE_JAVA], [AX_TRY_COMPILE_JAVA]) -AC_DEFUN([AX_TRY_COMPILE_JAVA],[ -AC_REQUIRE([AX_PROG_JAVAC])dnl -cat << \EOF > Test.java -/* [#]line __oline__ "configure" */ -ifelse([$1], , , [import $1;]) -public class Test { -[$2] -} -EOF -if AC_TRY_COMMAND($JAVAC $JAVACFLAGS Test.java) && test -s Test.class -then -dnl Don't remove the temporary files here, so they can be examined. - ifelse([$3], , :, [$3]) -else - echo "configure: failed program was:" >&AS_MESSAGE_LOG_FD - cat Test.java >&AS_MESSAGE_LOG_FD -ifelse([$4], , , [ rm -fr Test.java Test.class - $4 -])dnl -fi -rm -fr Test.java Test.class]) diff --git a/vpp-api/java/m4/ax_try_run_java.m4 b/vpp-api/java/m4/ax_try_run_java.m4 deleted file mode 100644 index c680f03f..00000000 --- a/vpp-api/java/m4/ax_try_run_java.m4 +++ /dev/null @@ -1,56 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_try_run_java.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_TRY_RUN_JAVA -# -# DESCRIPTION -# -# AX_TRY_RUN_JAVA attempt to compile and run user given source. -# -# *Warning*: its success or failure can depend on a proper setting of the -# CLASSPATH env. variable. -# -# Note: This is part of the set of autoconf M4 macros for Java programs. -# It is VERY IMPORTANT that you download the whole set, some macros depend -# on other. Unfortunately, the autoconf archive does not support the -# concept of set of macros, so I had to break it for submission. The -# general documentation, as well as the sample configure.in, is included -# in the AX_PROG_JAVA macro. -# -# LICENSE -# -# Copyright (c) 2008 Devin Weaver -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 2 - -AU_ALIAS([AC_TRY_RUN_JAVA], [AX_TRY_RUN_JAVA]) -AC_DEFUN([AX_TRY_RUN_JAVA],[ -AC_REQUIRE([AX_PROG_JAVAC])dnl -AC_REQUIRE([AX_PROG_JAVA])dnl -cat << \EOF > Test.java -/* [#]line __oline__ "configure" */ -ifelse([$1], , , [include $1;]) -public class Test { -[$2] -} -EOF -if AC_TRY_COMMAND($JAVAC $JAVACFLAGS Test.java) && test -s Test.class && ($JAVA $JAVAFLAGS Test; exit) 2>/dev/null -then -dnl Don't remove the temporary files here, so they can be examined. - ifelse([$3], , :, [$3]) -else - echo "configure: failed program was:" >&AS_MESSAGE_LOG_FD - cat Test.java >&AS_MESSAGE_LOG_FD -ifelse([$4], , , [ rm -fr Test.java Test.class - $4 -])dnl -fi -rm -fr Test.java Test.class]) diff --git a/vpp-api/lua/README.md b/vpp-api/lua/README.md deleted file mode 100644 index 4ecdb34d..00000000 --- a/vpp-api/lua/README.md +++ /dev/null @@ -1,50 +0,0 @@ -This is the experimental version of Lua API, aimed for the luajit use. - -Please take a look and send the feedback to ayourtch@gmail.com. - -To run the examples here: - -1) install luajit - "sudo apt-get install luajit" on ubuntu - -2) "make build-vpp-api" in the top VPP directory - -3) "make run" in a separate terminal window - This ensures you have an instance of VPP running - -4) sudo luajit examples/example-cli.lua - -This will result in something like this: - -Version: -00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ -00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ - -{ [1] = { ["luaapi_message_name"] = show_version_reply,["program"] = vpe,["version"] = ,["build_date"] = Fri Nov 25 10:58:48 UTC 2016,["retval"] = 0,["build_directory"] = /home/ubuntu/vpp,["_vl_msg_id"] = 170,["context"] = 0,} ,} ---- -{ [1] = { ["luaapi_message_name"] = cli_inband_reply,["_vl_msg_id"] = 94,["length"] = 66,["reply"] = vpp v built by ubuntu on vpp-toys at Fri Nov 25 10:58:48 UTC 2016 -,["retval"] = 0,["context"] = 0,} ,} ---- - -5) You can also run the performance test bench: - -$ sudo luajit bench.lua -10001 iterations, average speed 5624LL per second -10001 iterations, average speed 6650LL per second -10001 iterations, average speed 6053LL per second -10001 iterations, average speed 7056LL per second -10001 iterations, average speed 6388LL per second -10001 iterations, average speed 5849LL per second -10001 iterations, average speed 6321LL per second -10001 iterations, average speed 6368LL per second -10001 iterations, average speed 5958LL per second -10001 iterations, average speed 6482LL per second -Average tps across the tests: 6274LL - -Note: the above is run in an lxd container running inside 2-core -xhyve VM on a Macbook Pro, so I would not take the performance numbers for granted :) - -The "examples" directory contains a few naive examples, as well as a couple of more -advanced ones - a tab-completing CLI for VPP that can call both the APIs and CLI, -and also a small test utility which I use for automating some small tests using -VPP. - diff --git a/vpp-api/lua/bench.lua b/vpp-api/lua/bench.lua deleted file mode 100644 index 8e5a0b4b..00000000 --- a/vpp-api/lua/bench.lua +++ /dev/null @@ -1,70 +0,0 @@ ---[[ -/* - * 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. - */ -]] - -local vpp = require "vpp-lapi" - -local ffi = require "ffi" - -ffi.cdef([[ - struct timespec { - long tv_sec; /* seconds */ - long tv_nsec; /* nanoseconds */ - }; - - int clock_gettime(int clk_id, struct timespec *tp); -]]) - - -local time_cache = ffi.new("struct timespec[1]") -local time_cache_1 = time_cache[0] -function get_ns() - ffi.C.clock_gettime(0, time_cache) - return time_cache_1.tv_nsec + 1000000000 * time_cache_1.tv_sec -end - -function do_bench() - local cycle_start = get_ns() - local n_iterations = 10000 - local count = 1 - for i = 1,n_iterations do - -- print(i) - vpp:api_call("show_version") - count = count + 1 - -- print(i, "done") - end - cycle_end = get_ns() - local tps = n_iterations*1000000000LL/(cycle_end - cycle_start) - print (tostring(count) .. " iterations, average speed " .. tostring(tps) .. " per second") - return tps -end - -root_dir = "/home/ubuntu/vpp" -pneum_path = root_dir .. "/build-root/install-vpp_lite_debug-native/vpp-api/lib64/libpneum.so" -vpp:init({ pneum_path = pneum_path }) -vpp:json_api(root_dir .. "/build-root/install-vpp_lite_debug-native/vpp/vpp-api/vpe.api.json") - -vpp:connect("lua-bench") -local n_tests = 10 -local tps_acc = 0LL -for i=1,n_tests do - tps_acc = tps_acc + do_bench() -end -print("Average tps across the tests: " .. tostring(tps_acc/n_tests)) - -vpp:disconnect() - - diff --git a/vpp-api/lua/examples/cli/README.md b/vpp-api/lua/examples/cli/README.md deleted file mode 100644 index 3a5f8ee9..00000000 --- a/vpp-api/lua/examples/cli/README.md +++ /dev/null @@ -1,5 +0,0 @@ -This is a small experiment to have a wrapper CLI which can call both API functions as well as debug CLI. - -To facilitate tab completion and help, the API call names are broken up with spaces replacing the underscores. - - diff --git a/vpp-api/lua/examples/cli/lua-cli.lua b/vpp-api/lua/examples/cli/lua-cli.lua deleted file mode 100644 index b3a24d7d..00000000 --- a/vpp-api/lua/examples/cli/lua-cli.lua +++ /dev/null @@ -1,747 +0,0 @@ ---[[ -/* - * 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. - */ -]] - --- Experimental prototype CLI using API to VPP, with tab completion --- --- Written by Andrew Yourtchenko (ayourtch@cisco.com) 2010,2016 --- - -vpp = require "vpp-lapi" - - -local dotdotdot = "..." - --- First the "readline" routine - -readln = { -split = function(str, pat) - local t = {} -- NOTE: use {n = 0} in Lua-5.0 - local fpat = "(.-)" .. pat - local last_end = 1 - if str then - local s, e, cap = str:find(fpat, 1) - while s do - if s ~= 1 or cap ~= "" then - table.insert(t,cap) - end - last_end = e+1 - s, e, cap = str:find(fpat, last_end) - end - if last_end <= #str then - cap = str:sub(last_end) - table.insert(t, cap) - end - end - return t -end, - -reader = function() - local rl = {} - - rl.init = function() - os.execute("stty -icanon min 1 -echo") - rl.rawmode = true - end - - rl.done = function() - os.execute("stty icanon echo") - rl.rawmode = false - end - - rl.prompt = ">" - rl.history = { "" } - rl.history_index = 1 - rl.history_length = 1 - - rl.hide_cmd = function() - local bs = string.char(8) .. " " .. string.char(8) - for i = 1, #rl.command do - io.stdout:write(bs) - end - end - - rl.show_cmd = function() - if rl.command then - io.stdout:write(rl.command) - end - end - - rl.store_history = function(cmd) - if cmd == "" then - return - end - rl.history[rl.history_length] = cmd - rl.history_length = rl.history_length + 1 - rl.history_index = rl.history_length - rl.history[rl.history_length] = "" - end - - rl.readln = function() - local done = false - local need_prompt = true - rl.command = "" - - if not rl.rawmode then - rl.init() - end - - while not done do - if need_prompt then - io.stdout:write(rl.prompt) - io.stdout:write(rl.command) - need_prompt = false - end - - local ch = io.stdin:read(1) - if ch:byte(1) == 27 then - -- CONTROL - local ch2 = io.stdin:read(1) - -- arrows - if ch2:byte(1) == 91 then - local ch3 = io.stdin:read(1) - local b = ch3:byte(1) - if b == 65 then - ch = "UP" - elseif b == 66 then - ch = "DOWN" - elseif b == 67 then - ch = "RIGHT" - elseif b == 68 then - ch = "LEFT" - end - -- print("Byte: " .. ch3:byte(1)) - -- if ch3:byte(1) - end - end - - if ch == "?" then - io.stdout:write(ch) - io.stdout:write("\n") - if rl.help then - rl.help(rl) - end - need_prompt = true - elseif ch == "\t" then - if rl.tab_complete then - rl.tab_complete(rl) - end - io.stdout:write("\n") - need_prompt = true - elseif ch == "\n" then - io.stdout:write(ch) - done = true - elseif ch == "\004" then - io.stdout:write("\n") - rl.command = nil - done = true - elseif ch == string.char(127) then - if rl.command ~= "" then - io.stdout:write(string.char(8) .. " " .. string.char(8)) - rl.command = string.sub(rl.command, 1, -2) - end - elseif #ch > 1 then - -- control char - if ch == "UP" then - rl.hide_cmd() - if rl.history_index == #rl.history then - rl.history[rl.history_index] = rl.command - end - if rl.history_index > 1 then - rl.history_index = rl.history_index - 1 - rl.command = rl.history[rl.history_index] - end - rl.show_cmd() - elseif ch == "DOWN" then - rl.hide_cmd() - if rl.history_index < rl.history_length then - rl.history_index = rl.history_index + 1 - rl.command = rl.history[rl.history_index] - end - rl.show_cmd() - end - else - io.stdout:write(ch) - rl.command = rl.command .. ch - end - end - if rl.command then - rl.store_history(rl.command) - end - return rl.command - end - return rl -end - -} - ---[[ - -r = reader() - -local done = false - -while not done do - local cmd = r.readln() - print("Command: " .. tostring(cmd)) - if not cmd or cmd == "quit" then - done = true - end -end - -r.done() - -]] - ---------- MDS show tech parser - -local print_section = nil -local list_sections = false - -local curr_section = "---" -local curr_parser = nil - --- by default operate in batch mode -local batch_mode = true - -local db = {} -local device = {} -device.output = {} -local seen_section = {} - -function start_collection(name) - device = {} - seen_section = {} -end - -function print_error(errmsg) - print("@#$:" .. errmsg) -end - -function keys(tbl) - local t = {} - for k, v in pairs(tbl) do - table.insert(t, k) - end - return t -end - -function tset (parent, ...) - - -- print ('set', ...) - - local len = select ('#', ...) - local key, value = select (len-1, ...) - local cutpoint, cutkey - - for i=1,len-2 do - - local key = select (i, ...) - local child = parent[key] - - if value == nil then - if child == nil then return - elseif next (child, next (child)) then cutpoint = nil cutkey = nil - elseif cutpoint == nil then cutpoint = parent cutkey = key end - - elseif child == nil then child = {} parent[key] = child end - - parent = child - end - - if value == nil and cutpoint then cutpoint[cutkey] = nil - else parent[key] = value return value end - end - - -function tget (parent, ...) - local len = select ('#', ...) - for i=1,len do - parent = parent[select (i, ...)] - if parent == nil then break end - end - return parent - end - - -local pager_lines = 23 -local pager_printed = 0 -local pager_skipping = false -local pager_filter_pipe = nil - -function pager_reset() - pager_printed = 0 - pager_skipping = false - if pager_filter_pipe then - pager_filter_pipe:close() - pager_filter_pipe = nil - end -end - - -function print_more() - io.stdout:write(" --More-- ") -end - -function print_nomore() - local bs = string.char(8) - local bs10 = bs .. bs .. bs .. bs .. bs .. bs .. bs .. bs .. bs .. bs - io.stdout:write(bs10 .. " " .. bs10) -end - -function print_line(txt) - if pager_filter_pipe then - pager_filter_pipe:write(txt .. "\n") - return - end - if pager_printed >= pager_lines then - print_more() - local ch = io.stdin:read(1) - if ch == " " then - pager_printed = 0 - elseif ch == "\n" then - pager_printed = pager_printed - 1 - elseif ch == "q" then - pager_printed = 0 - pager_skipping = true - end - print_nomore() - end - if not pager_skipping then - print(txt) - pager_printed = pager_printed + 1 - else - -- skip printing - end -end - -function paged_write(text) - local t = readln.split(text, "[\n]") - if string.sub(text, -1) == "\n" then - table.insert(t, "") - end - for i, v in ipairs(t) do - if i < #t then - print_line(v) - else - if pager_filter_pipe then - pager_filter_pipe:write(v) - else - io.stdout:write(v) - end - end - end -end - - - - - -function get_choices(tbl, key) - local res = {} - for k, v in pairs(tbl) do - if string.sub(k, 1, #key) == key then - table.insert(res, k) - elseif 0 < #key and dotdotdot == k then - table.insert(res, k) - end - end - return res -end - -function get_exact_choice(choices, val) - local exact_idx = nil - local substr_idx = nil - local substr_seen = false - - if #choices == 1 then - if choices[1] == dotdotdot then - return 1 - elseif string.sub(choices[1], 1, #val) == val then - return 1 - else - return nil - end - else - for i, v in ipairs(choices) do - if v == val then - exact_idx = i - substr_seen = true - elseif choices[i] ~= dotdotdot and string.sub(choices[i], 1, #val) == val then - if substr_seen then - substr_idx = nil - else - substr_idx = i - substr_seen = true - end - elseif choices[i] == dotdotdot then - if substr_seen then - substr_idx = nil - else - substr_idx = i - substr_seen = true - end - end - end - end - return exact_idx or substr_idx -end - -function device_cli_help(rl) - local key = readln.split(rl.command, "[ ]+") - local tree = rl.tree - local keylen = #key - local fullcmd = "" - local error = false - local terse = true - - if ((#rl.command >= 1) and (string.sub(rl.command, -1) == " ")) or (#rl.command == 0) then - table.insert(key, "") - terse = false - end - - for i, v in ipairs(key) do - local choices = get_choices(tree, v) - local idx = get_exact_choice(choices, v) - if idx then - local choice = choices[idx] - tree = tree[choice] - fullcmd = fullcmd .. choice .. " " - else - if i < #key then - error = true - end - end - - if i == #key and not error then - for j, w in ipairs(choices) do - if terse then - paged_write(w .. "\t") - else - paged_write(" " .. w .. "\n") - end - end - paged_write("\n") - if terse then - paged_write(" \n") - end - end - end - pager_reset() -end - -function device_cli_tab_complete(rl) - local key = readln.split(rl.command, "[ ]+") - local tree = rl.tree - local keylen = #key - local fullcmd = "" - local error = false - - for i, v in ipairs(key) do - local choices = get_choices(tree, v) - local idx = get_exact_choice(choices, v) - if idx and choices[idx] ~= dotdotdot then - local choice = choices[idx] - tree = tree[choice] - -- print("level " .. i .. " '" .. choice .. "'") - fullcmd = fullcmd .. choice .. " " - else - -- print("level " .. i .. " : " .. table.concat(choices, " ") .. " ") - error = true - end - end - if not error then - rl.command = fullcmd - else - -- print("\n\nerror\n") - end - pager_reset() -end - -function device_cli_exec(rl) - - local cmd_nopipe = rl.command - local cmd_pipe = nil - - local pipe1, pipe2 = string.find(rl.command, "[|]") - if pipe1 then - cmd_nopipe = string.sub(rl.command, 1, pipe1-1) - cmd_pipe = string.sub(rl.command, pipe2+1, -1) - end - - local key = readln.split(cmd_nopipe .. " ", "[ ]+") - local tree = rl.tree - local keylen = #key - local fullcmd = "" - local error = false - local func = nil - - if cmd_pipe then - pager_filter_pipe = io.popen(cmd_pipe, "w") - end - - - rl.choices = {} - - for i, v in ipairs(key) do - local choices = get_choices(tree, v) - local idx = get_exact_choice(choices, v) - if idx then - local choice = choices[idx] - if i == #key then - func = tree[choice] - else - if choice == dotdotdot then - -- keep the tree the same, update the choice value to match the input string - choices[idx] = v - choice = v - else - tree = tree[choice] - end - end - -- print("level " .. i .. " '" .. choice .. "'") - table.insert(rl.choices, choice) - else - -- print("level " .. i .. " : " .. table.concat(choices, " ") .. " ") - error = true - return nil - end - end - return func -end - -function populate_tree(commands) - local tree = {} - - for k, v in pairs(commands) do - local key = readln.split(k .. " ", "[ ]+") - local xtree = tree - for i, kk in ipairs(key) do - if i == 1 and kk == "sh" then - kk = "show" - end - if i == #key then - if type(v) == "function" then - xtree[kk] = v - else - xtree[kk] = function(rl) paged_write(table.concat(v, "\n") .. "\n") end - end - else - if not xtree[kk] then - xtree[kk] = {} - end - xtree = xtree[kk] - end - end - end - return tree -end - -function trim (s) - return (string.gsub(s, "^%s*(.-)%s*$", "%1")) -end - - -function init_vpp(vpp) - local root_dir = "/home/ubuntu/vpp" - local pneum_path = root_dir .. "/build-root/install-vpp_lite_debug-native/vpp-api/lib64/libpneum.so" - - vpp:init({ pneum_path = pneum_path }) - - vpp:init({ pneum_path = pneum_path }) - vpp:json_api(root_dir .. "/build-root/install-vpp_lite_debug-native/vpp/vpp-api/vpe.api.json") - - - - vpp:connect("lua_cli") -end - -function run_cli(vpp, cli) - local reply = vpp:api_call("cli_inband", { cmd = cli }) - if reply and #reply == 1 then - local rep = reply[1] - if 0 == rep.retval then - return rep.reply - else - return "XXXXXLUACLI: API RETVAL ERROR : " .. tostring(rep.retval) - end - else - return "XXXXXLUACLI ERROR, RAW REPLY: " .. vpp.dump(reply) - end -end - - -function toprintablestring(s) - if type(s) == "string" then - return "\n"..vpp.hex_dump(s) - else - return tostring(s) - end -end - -function interactive_cli(r) - while not done do - pager_reset() - local cmd = r.readln() - if not cmd then - done = true - elseif cmd == "quit" or cmd == "exit" then - done = true - else - local func = device_cli_exec(r) - if func then - func(r) - else - if trim(cmd) == "" then - else - for i = 1, #r.prompt do - paged_write(" ") - end - paged_write("^\n% Invalid input detected at '^' marker.\n\n") - end - end - end - end -end - -device = {} -device.output = {} - -init_vpp(vpp) -cmds_str = run_cli(vpp, "?") -vpp_cmds = readln.split(cmds_str, "\n") -vpp_clis = {} - -for linenum, line in ipairs(vpp_cmds) do - local m,h = string.match(line, "^ (.-) (.*)$") - if m and #m > 0 then - table.insert(vpp_clis, m) - device.output["vpp debug cli " .. m] = function(rl) - -- print("ARBITRARY CLI" .. vpp.dump(rl.choices)) - print("LUACLI command: " .. table.concat(rl.choices, " ")) - local sub = {} - -- - for i=4, #rl.choices -1 do - table.insert(sub, rl.choices[i]) - end - local cli = table.concat(sub, " ") - print("Running CLI: " .. tostring(cli)) - paged_write(run_cli(vpp, cli)) - end - device.output["vpp debug cli " .. m .. " " .. dotdotdot] = function(rl) - print("ARGH") - end - - local ret = run_cli(vpp, "help " .. m) - device.output["help vpp debug cli " .. m] = { ret } - end -end - -for linenum, line in ipairs(vpp_clis) do - -- print(line, ret) -end - -for msgnum, msgname in pairs(vpp.msg_number_to_name) do - local cli, numspaces = string.gsub(msgname, "_", " ") - device.output["call " .. cli .. " " .. dotdotdot] = function(rl) - print("ARGH") - end - device.output["call " .. cli] = function(rl) - print("LUACLI command: " .. table.concat(rl.choices, " ")) - print("Running API: " .. msgname) -- vpp.dump(rl.choices)) - local out = {} - local args = {} - local ntaken = 0 - local argname = "" - for i=(1+1+numspaces+1), #rl.choices-1 do - -- print(i, rl.choices[i]) - if ntaken > 0 then - ntaken = ntaken -1 - else - local fieldname = rl.choices[i] - local field = vpp.msg_name_to_fields[msgname][fieldname] - if field then - local s = rl.choices[i+1] - s=s:gsub("\\x(%x%x)",function (x) return string.char(tonumber(x,16)) end) - args[fieldname] = s - ntaken = 1 - end - end - end - -- print("ARGS: ", vpp.dump(args)) - local ret = vpp:api_call(msgname, args) - for i, reply in ipairs(ret) do - table.insert(out, "=================== Entry #" .. tostring(i)) - for k, v in pairs(reply) do - table.insert(out, " " .. tostring(k) .. " : " .. toprintablestring(v)) - end - end - -- paged_write(vpp.dump(ret) .. "\n\n") - paged_write(table.concat(out, "\n").."\n\n") - end - device.output["call " .. cli .. " help"] = function(rl) - local out = {} - for k, v in pairs(vpp.msg_name_to_fields[msgname]) do - table.insert(out, tostring(k) .. " : " .. v["ctype"] .. " ; " .. tostring(vpp.dump(v)) ) - end - -- paged_write(vpp.dump(vpp.msg_name_to_fields[msgname]) .. "\n\n") - paged_write(table.concat(out, "\n").."\n\n") - end --- vpp.msg_name_to_number = {} -end - - - -local r = readln.reader() -local done = false - -r.prompt = "VPP(luaCLI)#" - -r.help = device_cli_help -r.tab_complete = device_cli_tab_complete -print("===== CLI view, use ^D to end =====") - -r.tree = populate_tree(device.output) --- readln.pretty("xxxx", r.tree) - - -for idx, an_arg in ipairs(arg) do - local fname = an_arg - if fname == "-i" then - pager_lines = 23 - interactive_cli(r) - else - pager_lines = 100000000 - for line in io.lines(fname) do - r.command = line - local func = device_cli_exec(r) - if func then - func(r) - end - end - end -end - -if #arg == 0 then - print("You should specify '-i' as an argument for the interactive session,") - print("but with no other sources of commands, we start interactive session now anyway") - interactive_cli(r) -end - -vpp:disconnect() -r.done() - - diff --git a/vpp-api/lua/examples/example-acl-plugin.lua b/vpp-api/lua/examples/example-acl-plugin.lua deleted file mode 100644 index ca01f18d..00000000 --- a/vpp-api/lua/examples/example-acl-plugin.lua +++ /dev/null @@ -1,110 +0,0 @@ ---[[ -/* - * 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. - */ -]] - - -vpp = require "vpp-lapi" - -root_dir = "/home/ubuntu/vpp" -pneum_path = root_dir .. "/build-root/install-vpp_debug-native/vpp-api/lib64/libpneum.so" - -vpp:init({ pneum_path = pneum_path }) - -vpp:consume_api(root_dir .. "/build-root/install-vpp_debug-native/vlib-api/vlibmemory/memclnt.api") -vpp:consume_api(root_dir .. "/build-root/install-vpp_debug-native/vpp/vpp-api/vpe.api") -vpp:connect("aytest") -vpp:consume_api(root_dir .. "/plugins/acl-plugin/acl/acl.api", "acl") - --- api calls -reply = vpp:api_call("show_version") -print("Version: ", reply[1].version) -print(vpp.hex_dump(reply[1].version)) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_del", { context = 42, acl_index = 230 }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_del", { context = 42, acl_index = 8 }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_del", { context = 42, acl_index = 15 }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_add", { context = 42, count = 2, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 } } }) -print(vpp.dump(reply)) -print("---") -interface_acl_in = reply[1].acl_index - -reply = vpp:api_call("acl_add", { context = 42, count = 3, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 }, { is_permit = 1, is_ipv6 = 0 } } }) -print(vpp.dump(reply)) -print("---") -interface_acl_out = reply[1].acl_index - - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 1, acl_index = interface_acl_in }) -print(vpp.dump(reply)) -print("---") -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 1, acl_index = interface_acl_in }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 0, acl_index = interface_acl_out }) -print(vpp.dump(reply)) -print("---") -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 0, acl_index = interface_acl_out }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_add", { context = 42, count = 0 }) -print(vpp.dump(reply)) -print("---") - -acl_index_to_delete = reply[1].acl_index -print("Deleting " .. tostring(acl_index_to_delete)) -reply = vpp:api_call("acl_del", { context = 42, acl_index = acl_index_to_delete }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 0}) -for ri, rv in ipairs(reply) do - print("Reply message #" .. tostring(ri)) - print(vpp.dump(rv)) - for ai, av in ipairs(rv.r) do - print("ACL rule #" .. tostring(ai) .. " : " .. vpp.dump(av)) - end - -end -print("---") - -reply = vpp:api_call("acl_del", { context = 42, acl_index = interface_acl_out }) -print(vpp.dump(reply)) -print("---") -reply = vpp:api_call("acl_del", { context = 42, acl_index = interface_acl_in }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 0}) -print(vpp.dump(reply)) -print("---") - - -vpp:disconnect() - - diff --git a/vpp-api/lua/examples/example-classifier.lua b/vpp-api/lua/examples/example-classifier.lua deleted file mode 100644 index ec9c3d3e..00000000 --- a/vpp-api/lua/examples/example-classifier.lua +++ /dev/null @@ -1,51 +0,0 @@ ---[[ -/* - * 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. - */ -]] - - -local vpp = require "vpp-lapi" -local bit = require("bit") - -root_dir = "/home/ubuntu/vpp" -pneum_path = root_dir .. "/build-root/install-vpp_lite_debug-native/vpp-api/lib64/libpneum.so" - - -vpp:init({ pneum_path = pneum_path }) - -vpp:json_api(root_dir .. "/build-root/install-vpp_lite_debug-native/vpp/vpp-api/vpe.api.json") - -vpp:connect("aytest") - --- api calls - -print("Calling API to add a new classifier table") -reply = vpp:api_call("classify_add_del_table", { - context = 43, - memory_size = bit.lshift(2, 20), - client_index = 42, - is_add = 1, - nbuckets = 32, - skip_n_vectors = 0, - match_n_vectors = 1, - mask = "\255\255\255\255\255\255\255\255" .. "\255\255\255\255\255\255\255\255" -}) -print(vpp.dump(reply)) -print("---") - - -vpp:disconnect() - - diff --git a/vpp-api/lua/examples/example-cli.lua b/vpp-api/lua/examples/example-cli.lua deleted file mode 100644 index 8b84989f..00000000 --- a/vpp-api/lua/examples/example-cli.lua +++ /dev/null @@ -1,44 +0,0 @@ ---[[ -/* - * 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. - */ -]] - -vpp = require "vpp-lapi" - -root_dir = "/home/ubuntu/vpp" -pneum_path = root_dir .. "/build-root/install-vpp_lite_debug-native/vpp-api/lib64/libpneum.so" - -vpp:init({ pneum_path = pneum_path }) - -vpp:json_api(root_dir .. "/build-root/install-vpp_lite_debug-native/vpp/vpp-api/vpe.api.json") - -vpp:connect("aytest") - --- api calls -reply = vpp:api_call("show_version") -print("Version: ", reply[1].version) -print(vpp.hex_dump(reply[1].version)) -print(vpp.dump(reply)) -print("---") - - -reply = vpp:api_call("cli_inband", { cmd = "show vers" }) -print(vpp.dump(reply)) -print("---") - - -vpp:disconnect() - - diff --git a/vpp-api/lua/examples/lute/README.md b/vpp-api/lua/examples/lute/README.md deleted file mode 100644 index 8d37250a..00000000 --- a/vpp-api/lua/examples/lute/README.md +++ /dev/null @@ -1,66 +0,0 @@ -LUTE: Lua Unit Test Environment - -This is a small helper utility to automate some simple tests -that one might need to do. - -Think of it as a hybrid of a screen and expect who -also took some habits from HTML inline code. - -It is quite probably useless for building anything serious, -but practice shows it is quite efficient at allowing -convenient temporary quick tests, and for something -that was written over a course of a couple of evenings it -is quite a nice little helper tool. - -It allows do launch and drive multiple shell sessions, -and by virtue of having been written in Lua, it of course -also allows to add the business logic using the Lua code. - -If you launch the lute without parameters, it gives you -the interactive shell to execute the commands in. - -If you launch it with an argument, it will attempt to -read and execute the commands from the file. - -Commands: - -shell FOO - - spawn a shell in a new PTY under the label FOO. - -run FOO bar - - Send "bar" keystrokes followed by "ENTER" to the session FOO - - Special case: "break" word on its own gets translated into ^C being sent. - -cd FOO - - "change domain" into session FOO. All subsequent inputs will go, - line-buffered, into the session FOO. To jump back up, use ^D (Control-D), - or within the file, use ^D^D^D (caret D caret D caret D on its own line) - -expect FOO blablabla - - Pause further interpretation of the batch mode until you see "blablabla" - in the output of session FOO, or until timeout happens. - -sleep N - - Sleep an integer N seconds, if you are in batch mode. - -echo blabla - - Echo the remainder of the line to standard output. - -For Lua code, there is a pre-existing pseudo-session called "lua", -which accepts "run lua" command which does what you would expect -(evaluate the rest of the string in Lua context - being the same -as lute itself). Also you can do "cd lua" and get into a -multiline-enabled interpreter shell. - -This way for the VPP case you can automate some of the things in your routine -that you would have to have done manually, and test drive API as well -as use the realistic native OS components to create the environment around it. - - diff --git a/vpp-api/lua/examples/lute/lute.lua b/vpp-api/lua/examples/lute/lute.lua deleted file mode 100644 index 89b9924b..00000000 --- a/vpp-api/lua/examples/lute/lute.lua +++ /dev/null @@ -1,777 +0,0 @@ ---[[ -version = 1 -/* - * 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. - */ -]] - --- LUTE: Lua Unit Test Environment --- AKA what happens when screen tries to marry with lua and expect, --- but escapes mid-ceremony. --- --- comments: @ayourtch - -ffi = require("ffi") - -vpp = {} -function vpp.dump(o) - if type(o) == 'table' then - local s = '{ ' - for k,v in pairs(o) do - if type(k) ~= 'number' then k = '"'..k..'"' end - s = s .. '['..k..'] = ' .. vpp.dump(v) .. ',' - end - return s .. '} ' - else - return tostring(o) - end -end - - -ffi.cdef([[ - -int posix_openpt(int flags); -int grantpt(int fd); -int unlockpt(int fd); -char *ptsname(int fd); - -typedef long pid_t; -typedef long ssize_t; -typedef long size_t; -typedef int nfds_t; -typedef long time_t; -typedef long suseconds_t; - -pid_t fork(void); -pid_t setsid(void); - -int close(int fd); -int open(char *pathname, int flags); - -int dup2(int oldfd, int newfd); - -ssize_t read(int fd, void *buf, size_t count); -ssize_t write(int fd, const void *buf, size_t count); - -struct pollfd { - int fd; /* file descriptor */ - short events; /* requested events */ - short revents; /* returned events */ - }; - -int poll(struct pollfd *fds, nfds_t nfds, int timeout); - -struct timeval { - time_t tv_sec; /* seconds */ - suseconds_t tv_usec; /* microseconds */ - }; - -int gettimeofday(struct timeval *tv, struct timezone *tz); - -int inet_pton(int af, const char *src, void *dst); - -]]) - -ffi.cdef([[ -void *memset(void *s, int c, size_t n); -void *memcpy(void *dest, void *src, size_t n); -void *memmove(void *dest, const void *src, size_t n); -void *memmem(const void *haystack, size_t haystacklen, - const void *needle, size_t needlelen); -]]) - - - -local O_RDWR = 2 - - -function os_time() - local tv = ffi.new("struct timeval[1]") - local ret = ffi.C.gettimeofday(tv, nil) - return tonumber(tv[0].tv_sec) + (tonumber(tv[0].tv_usec)/1000000.0) -end - -function sleep(n) - local when_wakeup = os_time() + n - while os_time() <= when_wakeup do - ffi.C.poll(nil, 0, 10) - end -end - - -function c_str(text_in) - local text = text_in - local c_str = ffi.new("char[?]", #text+1) - ffi.copy(c_str, text) - return c_str -end - -function ip46(addr_text) - local out = ffi.new("char [200]") - local AF_INET6 = 10 - local AF_INET = 2 - local is_ip6 = ffi.C.inet_pton(AF_INET6, c_str(addr_text), out) - if is_ip6 == 1 then - return ffi.string(out, 16), true - end - local is_ip4 = ffi.C.inet_pton(AF_INET, c_str(addr_text), out) - if is_ip4 then - return (string.rep("4", 12).. ffi.string(out, 4)), false - end -end - -function pty_master_open() - local fd = ffi.C.posix_openpt(O_RDWR) - ffi.C.grantpt(fd) - ffi.C.unlockpt(fd) - local p = ffi.C.ptsname(fd) - print("PTS:" .. ffi.string(p)) - return fd, ffi.string(p) -end - -function pty_run(cmd) - local master_fd, pts_name = pty_master_open() - local child_pid = ffi.C.fork() - if (child_pid == -1) then - print("Error fork()ing") - return -1 - end - - if child_pid ~= 0 then - -- print("Parent") - return master_fd, child_pid - end - - -- print("Child") - if (ffi.C.setsid() == -1) then - print("Child error setsid") - os.exit(-1) - end - - ffi.C.close(master_fd) - - local slave_fd = ffi.C.open(c_str(pts_name), O_RDWR) - if slave_fd == -1 then - print("Child can not open slave fd") - os.exit(-2) - end - - ffi.C.dup2(slave_fd, 0) - ffi.C.dup2(slave_fd, 1) - ffi.C.dup2(slave_fd, 2) - os.execute(cmd) -end - -function readch() - local buf = ffi.new("char[1]") - local nread= ffi.C.read(0, buf, 1) - -- print("\nREADCH : " .. string.char(buf[0])) - return string.char(buf[0]) -end - -function stdout_write(str) - ffi.C.write(1, c_str(str), #str) -end - - -readln = { -split = function(str, pat) - local t = {} -- NOTE: use {n = 0} in Lua-5.0 - local fpat = "(.-)" .. pat - local last_end = 1 - if str then - local s, e, cap = str:find(fpat, 1) - while s do - if s ~= 1 or cap ~= "" then - table.insert(t,cap) - end - last_end = e+1 - s, e, cap = str:find(fpat, last_end) - end - if last_end <= #str then - cap = str:sub(last_end) - table.insert(t, cap) - end - end - return t -end, - -reader = function() - local rl = {} - - rl.init = function() - os.execute("stty -icanon min 1 -echo") - rl.rawmode = true - end - - rl.done = function() - os.execute("stty icanon echo") - rl.rawmode = false - end - - rl.prompt = ">" - rl.history = { "" } - rl.history_index = 1 - rl.history_length = 1 - - rl.hide_cmd = function() - local bs = string.char(8) .. " " .. string.char(8) - for i = 1, #rl.command do - stdout_write(bs) - end - end - - rl.show_cmd = function() - if rl.command then - stdout_write(rl.command) - end - end - - rl.store_history = function(cmd) - if cmd == "" then - return - end - rl.history[rl.history_length] = cmd - rl.history_length = rl.history_length + 1 - rl.history_index = rl.history_length - rl.history[rl.history_length] = "" - end - - rl.readln = function(stdin_select_fn, batch_cmd, batch_when, batch_expect) - local done = false - local need_prompt = true - rl.command = "" - - if not rl.rawmode then - rl.init() - end - - while not done do - local indent_value = #rl.prompt + #rl.command - if need_prompt then - stdout_write(rl.prompt) - stdout_write(rl.command) - need_prompt = false - end - if type(stdin_select_fn) == "function" then - while not stdin_select_fn(indent_value, batch_cmd, batch_when, batch_expect) do - stdout_write(rl.prompt) - stdout_write(rl.command) - indent_value = #rl.prompt + #rl.command - end - if batch_cmd and ((os_time() > batch_when) or (batch_expect and expect_success(batch_expect, buf, 0))) then - stdout_write("\n" .. rl.prompt .. batch_cmd .. "\n") - if batch_expect then - expect_done(batch_expect) - end - return batch_cmd, batch_expect - end - end - local ch = readch() - if ch:byte(1) == 27 then - -- CONTROL - local ch2 = readch() - -- arrows - if ch2:byte(1) == 91 then - local ch3 = readch() - local b = ch3:byte(1) - if b == 65 then - ch = "UP" - elseif b == 66 then - ch = "DOWN" - elseif b == 67 then - ch = "RIGHT" - elseif b == 68 then - ch = "LEFT" - end - -- print("Byte: " .. ch3:byte(1)) - -- if ch3:byte(1) - end - end - - if ch == "?" then - stdout_write(ch) - stdout_write("\n") - if rl.help then - rl.help(rl) - end - need_prompt = true - elseif ch == "\t" then - if rl.tab_complete then - rl.tab_complete(rl) - end - stdout_write("\n") - need_prompt = true - elseif ch == "\n" then - stdout_write(ch) - done = true - elseif ch == "\004" then - stdout_write("\n") - rl.command = nil - done = true - elseif ch == string.char(127) then - if rl.command ~= "" then - stdout_write(string.char(8) .. " " .. string.char(8)) - rl.command = string.sub(rl.command, 1, -2) - end - elseif #ch > 1 then - -- control char - if ch == "UP" then - rl.hide_cmd() - if rl.history_index == #rl.history then - rl.history[rl.history_index] = rl.command - end - if rl.history_index > 1 then - rl.history_index = rl.history_index - 1 - rl.command = rl.history[rl.history_index] - end - rl.show_cmd() - elseif ch == "DOWN" then - rl.hide_cmd() - if rl.history_index < rl.history_length then - rl.history_index = rl.history_index + 1 - rl.command = rl.history[rl.history_index] - end - rl.show_cmd() - end - else - stdout_write(ch) - rl.command = rl.command .. ch - end - end - if rl.command then - rl.store_history(rl.command) - end - return rl.command - end - return rl -end - -} - -local select_fds = {} -local sessions = {} - -local line_erased = false - -function erase_line(indent) - if not line_erased then - line_erased = true - stdout_write(string.rep(string.char(8), indent)..string.rep(" ", indent)..string.rep(string.char(8), indent)) - end -end - -function do_select_stdin(indent, batch_cmd, batch_when, batch_expect) - while true do - local nfds = 1+#select_fds - local pfds = ffi.new("struct pollfd[?]", nfds) - pfds[0].fd = 0; - pfds[0].events = 1; - pfds[0].revents = 0; - for i = 1,#select_fds do - pfds[i].fd = select_fds[i].fd - pfds[i].events = 1 - pfds[i].revents = 0 - end - if batch_cmd and ((os_time() > batch_when) or (batch_expect and expect_success(batch_expect, buf, 0))) then - return true - end - while ffi.C.poll(pfds, nfds, 10) == 0 do - if batch_cmd and ((os_time() > batch_when) or (batch_expect and expect_success(batch_expect, buf, 0))) then - return true - end - if line_erased then - line_erased = false - return false - end - end - if pfds[0].revents == 1 then - return true - end - for i = 1,#select_fds do - if(pfds[i].revents > 0) then - if pfds[i].fd ~= select_fds[i].fd then - print("File descriptors unequal", pfds[i].fd, select_fds[i].fd) - end - select_fds[i].cb(select_fds[i], pfds[i].revents, indent) - end - end - end -end - -local buf = ffi.new("char [32768]") - -function session_stdout_write(prefix, data) - data = prefix .. data:gsub("\n", "\n"..prefix):gsub("\n"..prefix.."$", "\n") - - stdout_write(data) -end - -function expect_success(sok, buf, nread) - local expect_buf_sz = ffi.sizeof(sok.expect_buf) - 128 - local expect_buf_avail = expect_buf_sz - sok.expect_buf_idx - -- print("EXPECT_SUCCESS: nread ".. tostring(nread).. " expect_buf_idx: " .. tostring(sok.expect_buf_idx) .. " expect_buf_avail: " .. tostring(expect_buf_avail) ) - if expect_buf_avail < 0 then - print "EXPECT BUFFER OVERRUN ALREADY" - os.exit(1) - end - if expect_buf_avail < nread then - if (nread >= ffi.sizeof(sok.expect_buf)) then - print("Read too large of a chunk to fit into expect buffer") - return nil - end - local delta = nread - expect_buf_avail - - ffi.C.memmove(sok.expect_buf, sok.expect_buf + delta, expect_buf_sz - delta) - sok.expect_buf_idx = sok.expect_buf_idx - delta - expect_buf_avail = nread - end - if sok.expect_buf_idx + nread > expect_buf_sz then - print("ERROR, I have just overrun the buffer !") - os.exit(1) - end - ffi.C.memcpy(sok.expect_buf + sok.expect_buf_idx, buf, nread) - sok.expect_buf_idx = sok.expect_buf_idx + nread - if sok.expect_str == nil then - return true - end - local match_p = ffi.C.memmem(sok.expect_buf, sok.expect_buf_idx, sok.expect_str, sok.expect_str_len) - if match_p ~= nil then - return true - end - return false -end - -function expect_done(sok) - local expect_buf_sz = ffi.sizeof(sok.expect_buf) - 128 - if not sok.expect_str then - return false - end - local match_p = ffi.C.memmem(sok.expect_buf, sok.expect_buf_idx, sok.expect_str, sok.expect_str_len) - if match_p ~= nil then - if sok.expect_cb then - sok.expect_cb(sok) - end - local match_idx = ffi.cast("char *", match_p) - ffi.cast("char *", sok.expect_buf) - ffi.C.memmove(sok.expect_buf, ffi.cast("char *", match_p) + sok.expect_str_len, expect_buf_sz - match_idx - sok.expect_str_len) - sok.expect_buf_idx = match_idx + sok.expect_str_len - sok.expect_success = true - - sok.expect_str = nil - sok.expect_str_len = 0 - return true - end -end - -function slave_events(sok, revents, indent) - local fd = sok.fd - local nread = ffi.C.read(fd, buf, ffi.sizeof(buf)-128) - local idx = nread - 1 - while idx >= 0 and buf[idx] ~= 10 do - idx = idx - 1 - end - if idx >= 0 then - erase_line(indent) - session_stdout_write(sok.prefix, sok.buf .. ffi.string(buf, idx+1)) - sok.buf = "" - end - sok.buf = sok.buf .. ffi.string(buf+idx+1, nread-idx-1) - -- print("\nRead: " .. tostring(nread)) - -- stdout_write(ffi.string(buf, nread)) - if expect_success(sok, buf, nread) then - return true - end - return false -end - - -function start_session(name) - local mfd, cpid = pty_run("/bin/bash") - local sok = { ["fd"] = mfd, ["cb"] = slave_events, ["buf"] = "", ["prefix"] = name .. ":", ["expect_buf"] = ffi.new("char [165536]"), ["expect_buf_idx"] = 0, ["expect_str"] = nil } - table.insert(select_fds, sok) - sessions[name] = sok -end - -function command_transform(exe) - if exe == "break" then - exe = string.char(3) - end - return exe -end - -function session_write(a_session, a_str) - if has_session(a_session) then - return tonumber(ffi.C.write(sessions[a_session].fd, c_str(a_str), #a_str)) - else - return 0 - end -end - -function session_exec(a_session, a_cmd) - local exe = command_transform(a_cmd) .. "\n" - session_write(a_session, exe) -end - -function session_cmd(ui, a_session, a_cmd) - if not has_session(a_session) then - stdout_write("ERR: No such session '" .. tostring(a_session) .. "'\n") - return nil - end - if a_session == "lua" then - local func, msg = loadstring(ui.lua_acc .. a_cmd) - -- stdout_write("LOADSTR: " .. vpp.dump({ ret, msg }) .. "\n") - if not func and string.match(msg, "") then - if a_session ~= ui.in_session then - stdout_write("ERR LOADSTR: " .. tostring(msg) .. "\n") - return nil - end - ui.lua_acc = ui.lua_acc .. a_cmd .. "\n" - return true - end - ui.lua_acc = "" - local ret, msg = pcall(func) - if ret then - return true - else - stdout_write("ERR: " .. msg .. "\n") - return nil - end - else - session_exec(a_session, a_cmd) - if ui.session_cmd_delay then - return { "delay", ui.session_cmd_delay } - end - return true - end -end - -function has_session(a_session) - if a_session == "lua" then - return true - end - return (sessions[a_session] ~= nil) -end - -function command_match(list, input, output) - for i, v in ipairs(list) do - local m = {} - m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9] = string.match(input, v[1]) - -- print("MATCH: ", vpp.dump(m)) - if m[1] then - output["result"] = m - output["result_index"] = i - return m - end - end - return nil -end - -function cmd_spawn_shell(ui, a_arg) - start_session(a_arg[1]) - return true -end - -function cmd_run_cmd(ui, a_arg) - local a_sess = a_arg[1] - local a_cmd = a_arg[2] - return session_cmd(ui, a_sess, a_cmd) -end - -function cmd_cd(ui, a_arg) - local a_sess = a_arg[1] - if has_session(a_sess) then - ui.in_session = a_sess - return true - else - stdout_write("ERR: Unknown session '".. tostring(a_sess) .. "'\n") - return nil - end -end - -function cmd_sleep(ui, a_arg) - return { "delay", tonumber(a_arg[1]) } -end - -function cmd_expect(ui, a_arg) - local a_sess = a_arg[1] - local a_expect = a_arg[2] - local sok = sessions[a_sess] - if not sok then - stdout_write("ERR: unknown session '" .. tostring(a_sess) .. "'\n") - return nil - end - sok.expect_str = c_str(a_expect) - sok.expect_str_len = #a_expect - return { "expect", a_sess } -end - -function cmd_info(ui, a_arg) - local a_sess = a_arg[1] - local sok = sessions[a_sess] - if not sok then - stdout_write("ERR: unknown session '" .. tostring(a_sess) .. "'\n") - return nil - end - print("Info for session " .. tostring(a_sess) .. "\n") - print("Expect buffer index: " .. tostring(sok.expect_buf_idx)) - print("Expect buffer: '" .. tostring(ffi.string(sok.expect_buf, sok.expect_buf_idx)) .. "'\n") - if sok.expect_str then - print("Expect string: '" .. tostring(ffi.string(sok.expect_str, sok.expect_str_len)) .. "'\n") - else - print("Expect string not set\n") - end -end - -function cmd_echo(ui, a_arg) - local a_data = a_arg[1] - print("ECHO: " .. tostring(a_data)) -end - -main_command_table = { - { "^shell ([a-zA-Z0-9_]+)$", cmd_spawn_shell }, - { "^run ([a-zA-Z0-9_]+) (.+)$", cmd_run_cmd }, - { "^cd ([a-zA-Z0-9_]+)$", cmd_cd }, - { "^sleep ([0-9]+)$", cmd_sleep }, - { "^expect ([a-zA-Z0-9_]+) (.-)$", cmd_expect }, - { "^info ([a-zA-Z0-9_]+)$", cmd_info }, - { "^echo (.-)$", cmd_echo } -} - - - -function ui_set_prompt(ui) - if ui.in_session then - if ui.in_session == "lua" then - if #ui.lua_acc > 0 then - ui.r.prompt = ui.in_session .. ">>" - else - ui.r.prompt = ui.in_session .. ">" - end - else - ui.r.prompt = ui.in_session .. "> " - end - else - ui.r.prompt = "> " - end - return ui.r.prompt -end - -function ui_run_command(ui, cmd) - -- stdout_write("Command: " .. tostring(cmd) .. "\n") - local ret = false - if ui.in_session then - if cmd then - if cmd == "^D^D^D" then - ui.in_session = nil - ret = true - else - ret = session_cmd(ui, ui.in_session, cmd) - end - else - ui.in_session = nil - ret = true - end - else - if cmd then - local out = {} - if cmd == "" then - ret = true - end - if command_match(main_command_table, cmd, out) then - local i = out.result_index - local m = out.result - if main_command_table[i][2] then - ret = main_command_table[i][2](ui, m) - end - end - end - if not cmd or cmd == "quit" then - return "quit" - end - end - return ret -end - -local ui = {} -ui.in_session = nil -ui.r = readln.reader() -ui.lua_acc = "" -ui.session_cmd_delay = 0.3 - -local lines = "" - -local done = false --- a helper function which always returns nil -local no_next_line = function() return nil end - --- a function which returns the next batch line -local next_line = no_next_line - -local batchfile = arg[1] - -if batchfile then - local f = io.lines(batchfile) - next_line = function() - local line = f() - if line then - return line - else - next_line = no_next_line - session_stdout_write(batchfile .. ":", "End of batch\n") - return nil - end - end -end - - -local batch_when = 0 -local batch_expect = nil -while not done do - local prompt = ui_set_prompt(ui) - local batch_cmd = next_line() - local cmd, expect_sok = ui.r.readln(do_select_stdin, batch_cmd, batch_when, batch_expect) - if expect_sok and not expect_success(expect_sok, buf, 0) then - if not cmd_ret and next_line ~= no_next_line then - print("ERR: expect timeout\n") - next_line = no_next_line - end - else - local cmd_ret = ui_run_command(ui, cmd) - if not cmd_ret and next_line ~= no_next_line then - print("ERR: Error during batch execution\n") - next_line = no_next_line - end - - if cmd_ret == "quit" then - done = true - end - batch_expect = nil - batch_when = 0 - if type(cmd_ret) == "table" then - if cmd_ret[1] == "delay" then - batch_when = os_time() + tonumber(cmd_ret[2]) - end - if cmd_ret[1] == "expect" then - batch_expect = sessions[cmd_ret[2]] - batch_when = os_time() + 15 - end - end - end -end -ui.r.done() - -os.exit(1) - - - diff --git a/vpp-api/lua/examples/lute/script-inout-acl-noacl.lute b/vpp-api/lua/examples/lute/script-inout-acl-noacl.lute deleted file mode 100644 index a24d04bf..00000000 --- a/vpp-api/lua/examples/lute/script-inout-acl-noacl.lute +++ /dev/null @@ -1,329 +0,0 @@ -shell vppbuild -run vppbuild stty -echo -run vppbuild sudo -u ubuntu -i bash -c "(cd vpp && make plugins && echo ALLGOOD)" -expect vppbuild ALLGOOD - -shell s0 -shell s1 -shell s2 - - -cd s1 -unshare -n /bin/bash -/sbin/ifconfig -a -^D^D^D - -cd s2 -unshare -n /bin/bash -/sbin/ifconfig -a -^D^D^D - - -cd lua - -function session_get_bash_pid(s) - if not has_session(s) then - return nil - end - local fname = "/tmp/lute-"..s.."-pid.txt" - - session_exec(s, "echo $$ >" .. fname) - -- it's a dirty hack but it's quick - sleep(0.5) - local pid = io.lines(fname)() - print("Got pid for " .. s .. " : " .. tostring(pid)) - return(tonumber(pid)) -end - -function session_connect_with(s0, s1) - -- local pid0 = tostring(session_get_bash_pid(s0)) - local pid1 = tostring(session_get_bash_pid(s1)) - local eth_options = { "rx", "tx", "sg", "tso", "ufo", "gso", "gro", "lro", "rxvlan", "txvlan", "rxhash" } - local this_end = s0 .. "_" .. s1 - local other_end = s1 .. "_" .. s0 - session_exec(s0, "ip link add name " .. this_end .. " type veth peer name " .. other_end) - session_exec(s0, "ip link set dev " .. this_end .. " up promisc on") - for i, option in ipairs(eth_options) do - session_exec(s0, "/sbin/ethtool --offload " .. this_end .. " " .. option .. " off") - session_exec(s0, "/sbin/ethtool --offload " .. other_end .. " " .. option .. " off") - end - session_exec(s0, "ip link set dev " .. other_end .. " up promisc on netns /proc/" .. pid1 .. "/ns/net") - sleep(0.5) -end - -^D^D^D -run lua session_connect_with("s0", "s1") -run lua session_connect_with("s0", "s2") - -cd s1 -ip -6 addr add dev s1_s0 2001:db8:1::1/64 -ip -4 addr add dev s1_s0 192.0.2.1/24 -ip link set dev s1_s0 up promisc on -^D^D^D - -cd s2 -ip -6 addr add dev s2_s0 2001:db8:1::2/64 -ip -6 addr add dev s2_s0 2001:db8:1::3/64 -ip -6 addr add dev s2_s0 2001:db8:1::4/64 -ip -4 addr add dev s2_s0 192.0.2.2/24 -ip -4 addr add dev s2_s0:1 192.0.2.3/24 -ip -4 addr add dev s2_s0:2 192.0.2.4/24 -ip link set dev s2_s0 up promisc on -^D^D^D - -run s1 ip addr -run s2 ip addr -shell VPP -cd VPP -cd /home/ubuntu/vpp -make debug -r -^D^D^D -expect VPP DBGvpp# - -cd lua --- Initialization of the Lua environment for talking to VPP -vpp = require("vpp-lapi") -root_dir = "/home/ubuntu/vpp" -pneum_path = root_dir .. "/build-root/install-vpp_debug-native/vpp-api/lib64/libpneum.so" -vpp:init({ pneum_path = pneum_path }) -vpp:consume_api(root_dir .. "/build-root/install-vpp_debug-native/vlib-api/vlibmemory/memclnt.api") -vpp:consume_api(root_dir .. "/build-root/install-vpp_debug-native/vpp/vpp-api/vpe.api") -vpp:connect("aytest") -vpp:consume_api(root_dir .. "/plugins/acl-plugin/acl/acl.api", "acl") - -^D^D^D - -cd lua - -reply = vpp:api_call("af_packet_create", { host_if_name = "s0_s1", hw_addr = "AAAAAA" }) -vpp_if_to_s1 = reply[1].sw_if_index - -reply = vpp:api_call("af_packet_create", { host_if_name = "s0_s2", hw_addr = "AAAAAA" }) -vpp_if_to_s2 = reply[1].sw_if_index - -ifaces = { vpp_if_to_s1, vpp_if_to_s2 } - -reply = vpp:api_call("sw_interface_set_flags", { sw_if_index = vpp_if_to_s1, admin_up_down = 1, link_up_down = 1 }) -print(vpp.dump(reply)) -reply = vpp:api_call("sw_interface_set_flags", { sw_if_index = vpp_if_to_s2, admin_up_down = 1, link_up_down = 1 }) -print(vpp.dump(reply)) - -bd_id = 42 - -reply = vpp:api_call("bridge_domain_add_del", { bd_id = bd_id, flood = 1, uu_flood = 1, forward = 1, learn = 1, arp_term = 0, is_add = 1 }) -print(vpp.dump(reply)) - -for i, v in ipairs(ifaces) do - reply = vpp:api_call("sw_interface_set_l2_bridge", { rx_sw_if_index = v, bd_id = bd_id, shg = 0, bvi = 0, enable = 1 } ) - print(vpp.dump(reply)) -end - -^D^D^D - -run s1 ping -c 3 192.0.2.2 -expect s1 packet loss -run s1 ping -c 3 192.0.2.3 -expect s1 packet loss -run s1 ping -c 3 192.0.2.4 -expect s1 packet loss -run s1 ping6 -c 3 2001:db8:1::2 -expect s1 packet loss -run s1 ping6 -c 3 2001:db8:1::3 -expect s1 packet loss -run s1 ping6 -c 3 2001:db8:1::4 -expect s1 packet loss - - -cd lua ---- ACL testing - ---[[ temporary comment out - -reply = vpp:api_call("acl_del", { context = 42, acl_index = 230 }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_del", { context = 42, acl_index = 8 }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_del", { context = 42, acl_index = 15 }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_add_replace", { context = 42, count = 2, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 } } }) -print(vpp.dump(reply)) -print("---") -interface_acl_in = reply[1].acl_index - -reply = vpp:api_call("acl_add_replace", { context = 42, count = 3, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 }, { is_permit = 1, is_ipv6 = 0 } } }) -print(vpp.dump(reply)) -print("---") -interface_acl_out = reply[1].acl_index - - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 1, acl_index = interface_acl_in }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 1, acl_index = interface_acl_in }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 0, acl_index = interface_acl_out }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 0, acl_index = interface_acl_out }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_add_replace", { context = 42, count = 0 }) -print(vpp.dump(reply)) -print("---") - -acl_index_to_delete = reply[1].acl_index -print("Deleting " .. tostring(acl_index_to_delete)) -reply = vpp:api_call("acl_del", { context = 42, acl_index = acl_index_to_delete }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 0}) -for ri, rv in ipairs(reply) do - print("Reply message #" .. tostring(ri)) - print(vpp.dump(rv)) - for ai, av in ipairs(rv.r) do - print("ACL rule #" .. tostring(ai) .. " : " .. vpp.dump(av)) - end - -end -print("---") - -reply = vpp:api_call("acl_del", { context = 42, acl_index = interface_acl_out }) -print(vpp.dump(reply)) -print("---") -reply = vpp:api_call("acl_del", { context = 42, acl_index = interface_acl_in }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 0}) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 4294967295 }) -print(vpp.dump(reply)) -print("---") - - -]] -- end of comment out - ----- Should be nothing ^^ -r = { - { is_permit = 1, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8:1::2"), dst_ip_prefix_len = 128 }, - { is_permit = 0, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8:1::3"), dst_ip_prefix_len = 128 }, - { is_permit = 1, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8::"), dst_ip_prefix_len = 32 }, - { is_permit = 1, is_ipv6 = 0, dst_ip_addr = ip46("192.0.2.2"), dst_ip_prefix_len = 32}, - { is_permit = 0, is_ipv6 = 0, dst_ip_addr = ip46("192.0.2.3"), dst_ip_prefix_len = 32 }, -} - -reply = vpp:api_call("acl_add_replace", { context = 42, count = 5, r = r }) -print(vpp.dump(reply)) -print("---") -interface_acl_in = reply[1].acl_index - -reply = vpp:api_call("acl_add_replace", { context = 42, count = 3, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 }, { is_permit = 1, is_ipv6 = 0 } } }) -print(vpp.dump(reply)) -print("---") -interface_acl_out = reply[1].acl_in - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s1, is_add = 1, is_input = 1, acl_index = interface_acl_in }) -print(vpp.dump(reply)) -print("---") - ---reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s2, is_add = 1, is_input = 0, acl_index = interface_acl_out }) --- print(vpp.dump(reply)) ---print("---") - -^D^D^D - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping6 -c 3 2001:db8:1::2 -expect s1 packet loss -run VPP show trace -expect VPP match: inacl 0 rule 0 - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping6 -c 3 2001:db8:1::3 -expect s1 packet loss -run VPP show trace -expect VPP match: inacl 0 rule 1 - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping6 -c 3 2001:db8:1::4 -expect s1 packet loss -run VPP show trace -expect VPP match: inacl 0 rule 2 - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping -c 3 192.0.2.2 -expect s1 packet loss -run VPP show trace -expect VPP match: inacl 0 rule 3 - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping -c 3 192.0.2.3 -expect s1 packet loss -run VPP show trace -expect VPP match: inacl 0 rule 4 - - -cd lua - ---- TEST OUTBOUND ACL - -r1 = { - { is_permit = 1, is_ipv6 = 1, src_ip_addr = ip46("2001:db8:1::1"), src_ip_prefix_len = 128, dst_ip_addr = ip46("2001:db8:1::2"), dst_ip_prefix_len = 128 }, - { is_permit = 0, is_ipv6 = 1, src_ip_addr = ip46("2001:db8:1::1"), src_ip_prefix_len = 128, dst_ip_addr = ip46("2001:db8:1::4"), dst_ip_prefix_len = 128 } -} - -reply = vpp:api_call("acl_add_replace", { context = 42, count = 3, r = r1 }) -print(vpp.dump(reply)) -print("---") -interface_acl_out = reply[1].acl_index - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s2, is_add = 1, is_input = 0, acl_index = interface_acl_out }) -print(vpp.dump(reply)) -print("---") - - -^D^D^D - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping6 -c 3 2001:db8:1::2 -expect s1 packet loss -run VPP show trace -expect VPP match: outacl 2 rule 0 - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping6 -c 3 2001:db8:1::3 -expect s1 packet loss -run VPP show trace -expect VPP match: inacl 0 rule 1 - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping6 -c 3 2001:db8:1::4 -expect s1 packet loss -run VPP show trace -expect VPP match: outacl 2 rule 1 - -run lua print("ALL GOOD!") - diff --git a/vpp-api/lua/examples/lute/script-inout-acl-old.lute b/vpp-api/lua/examples/lute/script-inout-acl-old.lute deleted file mode 100644 index 9edebf02..00000000 --- a/vpp-api/lua/examples/lute/script-inout-acl-old.lute +++ /dev/null @@ -1,329 +0,0 @@ -shell vppbuild -run vppbuild stty -echo -run vppbuild sudo -u ubuntu -i bash -c "(cd vpp && make plugins && echo ALLGOOD)" -expect vppbuild ALLGOOD - -shell s0 -shell s1 -shell s2 - - -cd s1 -unshare -n /bin/bash -/sbin/ifconfig -a -^D^D^D - -cd s2 -unshare -n /bin/bash -/sbin/ifconfig -a -^D^D^D - - -cd lua - -function session_get_bash_pid(s) - if not has_session(s) then - return nil - end - local fname = "/tmp/lute-"..s.."-pid.txt" - - session_exec(s, "echo $$ >" .. fname) - -- it's a dirty hack but it's quick - sleep(0.5) - local pid = io.lines(fname)() - print("Got pid for " .. s .. " : " .. tostring(pid)) - return(tonumber(pid)) -end - -function session_connect_with(s0, s1) - -- local pid0 = tostring(session_get_bash_pid(s0)) - local pid1 = tostring(session_get_bash_pid(s1)) - local eth_options = { "rx", "tx", "sg", "tso", "ufo", "gso", "gro", "lro", "rxvlan", "txvlan", "rxhash" } - local this_end = s0 .. "_" .. s1 - local other_end = s1 .. "_" .. s0 - session_exec(s0, "ip link add name " .. this_end .. " type veth peer name " .. other_end) - session_exec(s0, "ip link set dev " .. this_end .. " up promisc on") - for i, option in ipairs(eth_options) do - session_exec(s0, "/sbin/ethtool --offload " .. this_end .. " " .. option .. " off") - session_exec(s0, "/sbin/ethtool --offload " .. other_end .. " " .. option .. " off") - end - session_exec(s0, "ip link set dev " .. other_end .. " up promisc on netns /proc/" .. pid1 .. "/ns/net") - sleep(0.5) -end - -^D^D^D -run lua session_connect_with("s0", "s1") -run lua session_connect_with("s0", "s2") - -cd s1 -ip -6 addr add dev s1_s0 2001:db8:1::1/64 -ip -4 addr add dev s1_s0 192.0.2.1/24 -ip link set dev s1_s0 up promisc on -^D^D^D - -cd s2 -ip -6 addr add dev s2_s0 2001:db8:1::2/64 -ip -6 addr add dev s2_s0 2001:db8:1::3/64 -ip -6 addr add dev s2_s0 2001:db8:1::4/64 -ip -4 addr add dev s2_s0 192.0.2.2/24 -ip -4 addr add dev s2_s0:1 192.0.2.3/24 -ip -4 addr add dev s2_s0:2 192.0.2.4/24 -ip link set dev s2_s0 up promisc on -^D^D^D - -run s1 ip addr -run s2 ip addr -shell VPP -cd VPP -cd /home/ubuntu/vpp -make debug -r -^D^D^D -expect VPP DBGvpp# - -cd lua --- Initialization of the Lua environment for talking to VPP -vpp = require("vpp-lapi") -root_dir = "/home/ubuntu/vpp" -pneum_path = root_dir .. "/build-root/install-vpp_debug-native/vpp-api/lib64/libpneum.so" -vpp:init({ pneum_path = pneum_path }) -vpp:consume_api(root_dir .. "/build-root/install-vpp_debug-native/vlib-api/vlibmemory/memclnt.api") -vpp:consume_api(root_dir .. "/build-root/install-vpp_debug-native/vpp/vpp-api/vpe.api") -vpp:connect("aytest") -vpp:consume_api(root_dir .. "/plugins/acl-plugin/acl/acl.api", "acl") - -^D^D^D - -cd lua - -reply = vpp:api_call("af_packet_create", { host_if_name = "s0_s1", hw_addr = "AAAAAA" }) -vpp_if_to_s1 = reply[1].sw_if_index - -reply = vpp:api_call("af_packet_create", { host_if_name = "s0_s2", hw_addr = "AAAAAA" }) -vpp_if_to_s2 = reply[1].sw_if_index - -ifaces = { vpp_if_to_s1, vpp_if_to_s2 } - -reply = vpp:api_call("sw_interface_set_flags", { sw_if_index = vpp_if_to_s1, admin_up_down = 1, link_up_down = 1 }) -print(vpp.dump(reply)) -reply = vpp:api_call("sw_interface_set_flags", { sw_if_index = vpp_if_to_s2, admin_up_down = 1, link_up_down = 1 }) -print(vpp.dump(reply)) - -bd_id = 42 - -reply = vpp:api_call("bridge_domain_add_del", { bd_id = bd_id, flood = 1, uu_flood = 1, forward = 1, learn = 1, arp_term = 0, is_add = 1 }) -print(vpp.dump(reply)) - -for i, v in ipairs(ifaces) do - reply = vpp:api_call("sw_interface_set_l2_bridge", { rx_sw_if_index = v, bd_id = bd_id, shg = 0, bvi = 0, enable = 1 } ) - print(vpp.dump(reply)) -end - -^D^D^D - -run s1 ping -c 3 192.0.2.2 -expect s1 packet loss -run s1 ping -c 3 192.0.2.3 -expect s1 packet loss -run s1 ping -c 3 192.0.2.4 -expect s1 packet loss -run s1 ping6 -c 3 2001:db8:1::2 -expect s1 packet loss -run s1 ping6 -c 3 2001:db8:1::3 -expect s1 packet loss -run s1 ping6 -c 3 2001:db8:1::4 -expect s1 packet loss - - -cd lua ---- ACL testing - ---[[ temporary comment out - -reply = vpp:api_call("acl_del", { context = 42, acl_index = 230 }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_del", { context = 42, acl_index = 8 }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_del", { context = 42, acl_index = 15 }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_add", { context = 42, count = 2, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 } } }) -print(vpp.dump(reply)) -print("---") -interface_acl_in = reply[1].acl_index - -reply = vpp:api_call("acl_add", { context = 42, count = 3, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 }, { is_permit = 1, is_ipv6 = 0 } } }) -print(vpp.dump(reply)) -print("---") -interface_acl_out = reply[1].acl_index - - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 1, acl_index = interface_acl_in }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 1, acl_index = interface_acl_in }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 0, acl_index = interface_acl_out }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 0, acl_index = interface_acl_out }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_add", { context = 42, count = 0 }) -print(vpp.dump(reply)) -print("---") - -acl_index_to_delete = reply[1].acl_index -print("Deleting " .. tostring(acl_index_to_delete)) -reply = vpp:api_call("acl_del", { context = 42, acl_index = acl_index_to_delete }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 0}) -for ri, rv in ipairs(reply) do - print("Reply message #" .. tostring(ri)) - print(vpp.dump(rv)) - for ai, av in ipairs(rv.r) do - print("ACL rule #" .. tostring(ai) .. " : " .. vpp.dump(av)) - end - -end -print("---") - -reply = vpp:api_call("acl_del", { context = 42, acl_index = interface_acl_out }) -print(vpp.dump(reply)) -print("---") -reply = vpp:api_call("acl_del", { context = 42, acl_index = interface_acl_in }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 0}) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 4294967295 }) -print(vpp.dump(reply)) -print("---") - - -]] -- end of comment out - ----- Should be nothing ^^ -r = { - { is_permit = 1, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8:1::2"), dst_ip_prefix_len = 128 }, - { is_permit = 0, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8:1::3"), dst_ip_prefix_len = 128 }, - { is_permit = 1, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8::"), dst_ip_prefix_len = 32 }, - { is_permit = 1, is_ipv6 = 0, dst_ip_addr = ip46("192.0.2.2"), dst_ip_prefix_len = 32}, - { is_permit = 0, is_ipv6 = 0, dst_ip_addr = ip46("192.0.2.3"), dst_ip_prefix_len = 32 }, -} - -reply = vpp:api_call("acl_add", { context = 42, count = 5, r = r }) -print(vpp.dump(reply)) -print("---") -interface_acl_in = reply[1].acl_index - -reply = vpp:api_call("acl_add", { context = 42, count = 3, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 }, { is_permit = 1, is_ipv6 = 0 } } }) -print(vpp.dump(reply)) -print("---") -interface_acl_out = reply[1].acl_in - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s1, is_add = 1, is_input = 1, acl_index = interface_acl_in }) -print(vpp.dump(reply)) -print("---") - ---reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s2, is_add = 1, is_input = 0, acl_index = interface_acl_out }) --- print(vpp.dump(reply)) ---print("---") - -^D^D^D - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping6 -c 3 2001:db8:1::2 -expect s1 packet loss -run VPP show trace -expect VPP match: inacl 0 rule 0 - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping6 -c 3 2001:db8:1::3 -expect s1 packet loss -run VPP show trace -expect VPP match: inacl 0 rule 1 - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping6 -c 3 2001:db8:1::4 -expect s1 packet loss -run VPP show trace -expect VPP match: inacl 0 rule 2 - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping -c 3 192.0.2.2 -expect s1 packet loss -run VPP show trace -expect VPP match: inacl 0 rule 3 - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping -c 3 192.0.2.3 -expect s1 packet loss -run VPP show trace -expect VPP match: inacl 0 rule 4 - - -cd lua - ---- TEST OUTBOUND ACL - -r1 = { - { is_permit = 1, is_ipv6 = 1, src_ip_addr = ip46("2001:db8:1::1"), src_ip_prefix_len = 128, dst_ip_addr = ip46("2001:db8:1::2"), dst_ip_prefix_len = 128 }, - { is_permit = 0, is_ipv6 = 1, src_ip_addr = ip46("2001:db8:1::1"), src_ip_prefix_len = 128, dst_ip_addr = ip46("2001:db8:1::4"), dst_ip_prefix_len = 128 } -} - -reply = vpp:api_call("acl_add", { context = 42, count = 3, r = r1 }) -print(vpp.dump(reply)) -print("---") -interface_acl_out = reply[1].acl_index - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s2, is_add = 1, is_input = 0, acl_index = interface_acl_out }) -print(vpp.dump(reply)) -print("---") - - -^D^D^D - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping6 -c 3 2001:db8:1::2 -expect s1 packet loss -run VPP show trace -expect VPP match: outacl 2 rule 0 - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping6 -c 3 2001:db8:1::3 -expect s1 packet loss -run VPP show trace -expect VPP match: inacl 0 rule 1 - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping6 -c 3 2001:db8:1::4 -expect s1 packet loss -run VPP show trace -expect VPP match: outacl 2 rule 1 - -run lua print("ALL GOOD!") - diff --git a/vpp-api/lua/examples/lute/script-inout-acl.lute b/vpp-api/lua/examples/lute/script-inout-acl.lute deleted file mode 100644 index d7e7423c..00000000 --- a/vpp-api/lua/examples/lute/script-inout-acl.lute +++ /dev/null @@ -1,329 +0,0 @@ -shell vppbuild -run vppbuild stty -echo -run vppbuild sudo -u ubuntu -i bash -c "(cd vpp && make plugins && echo ALLGOOD)" -expect vppbuild ALLGOOD - -shell s0 -shell s1 -shell s2 - - -cd s1 -unshare -n /bin/bash -/sbin/ifconfig -a -^D^D^D - -cd s2 -unshare -n /bin/bash -/sbin/ifconfig -a -^D^D^D - - -cd lua - -function session_get_bash_pid(s) - if not has_session(s) then - return nil - end - local fname = "/tmp/lute-"..s.."-pid.txt" - - session_exec(s, "echo $$ >" .. fname) - -- it's a dirty hack but it's quick - sleep(0.5) - local pid = io.lines(fname)() - print("Got pid for " .. s .. " : " .. tostring(pid)) - return(tonumber(pid)) -end - -function session_connect_with(s0, s1) - -- local pid0 = tostring(session_get_bash_pid(s0)) - local pid1 = tostring(session_get_bash_pid(s1)) - local eth_options = { "rx", "tx", "sg", "tso", "ufo", "gso", "gro", "lro", "rxvlan", "txvlan", "rxhash" } - local this_end = s0 .. "_" .. s1 - local other_end = s1 .. "_" .. s0 - session_exec(s0, "ip link add name " .. this_end .. " type veth peer name " .. other_end) - session_exec(s0, "ip link set dev " .. this_end .. " up promisc on") - for i, option in ipairs(eth_options) do - session_exec(s0, "/sbin/ethtool --offload " .. this_end .. " " .. option .. " off") - session_exec(s0, "/sbin/ethtool --offload " .. other_end .. " " .. option .. " off") - end - session_exec(s0, "ip link set dev " .. other_end .. " up promisc on netns /proc/" .. pid1 .. "/ns/net") - sleep(0.5) -end - -^D^D^D -run lua session_connect_with("s0", "s1") -run lua session_connect_with("s0", "s2") - -cd s1 -ip -6 addr add dev s1_s0 2001:db8:1::1/64 -ip -4 addr add dev s1_s0 192.0.2.1/24 -ip link set dev s1_s0 up promisc on -^D^D^D - -cd s2 -ip -6 addr add dev s2_s0 2001:db8:1::2/64 -ip -6 addr add dev s2_s0 2001:db8:1::3/64 -ip -6 addr add dev s2_s0 2001:db8:1::4/64 -ip -4 addr add dev s2_s0 192.0.2.2/24 -ip -4 addr add dev s2_s0:1 192.0.2.3/24 -ip -4 addr add dev s2_s0:2 192.0.2.4/24 -ip link set dev s2_s0 up promisc on -^D^D^D - -run s1 ip addr -run s2 ip addr -shell VPP -cd VPP -cd /home/ubuntu/vpp -make debug -r -^D^D^D -expect VPP DBGvpp# - -cd lua --- Initialization of the Lua environment for talking to VPP -vpp = require("vpp-lapi") -root_dir = "/home/ubuntu/vpp" -pneum_path = root_dir .. "/build-root/install-vpp_debug-native/vpp-api/lib64/libpneum.so" -vpp:init({ pneum_path = pneum_path }) -vpp:consume_api(root_dir .. "/build-root/install-vpp_debug-native/vlib-api/vlibmemory/memclnt.api") -vpp:consume_api(root_dir .. "/build-root/install-vpp_debug-native/vpp/vpp-api/vpe.api") -vpp:connect("aytest") -vpp:consume_api(root_dir .. "/plugins/acl-plugin/acl/acl.api", "acl") - -^D^D^D - -cd lua - -reply = vpp:api_call("af_packet_create", { host_if_name = "s0_s1", hw_addr = "AAAAAA" }) -vpp_if_to_s1 = reply[1].sw_if_index - -reply = vpp:api_call("af_packet_create", { host_if_name = "s0_s2", hw_addr = "AAAAAA" }) -vpp_if_to_s2 = reply[1].sw_if_index - -ifaces = { vpp_if_to_s1, vpp_if_to_s2 } - -reply = vpp:api_call("sw_interface_set_flags", { sw_if_index = vpp_if_to_s1, admin_up_down = 1, link_up_down = 1 }) -print(vpp.dump(reply)) -reply = vpp:api_call("sw_interface_set_flags", { sw_if_index = vpp_if_to_s2, admin_up_down = 1, link_up_down = 1 }) -print(vpp.dump(reply)) - -bd_id = 42 - -reply = vpp:api_call("bridge_domain_add_del", { bd_id = bd_id, flood = 1, uu_flood = 1, forward = 1, learn = 1, arp_term = 0, is_add = 1 }) -print(vpp.dump(reply)) - -for i, v in ipairs(ifaces) do - reply = vpp:api_call("sw_interface_set_l2_bridge", { rx_sw_if_index = v, bd_id = bd_id, shg = 0, bvi = 0, enable = 1 } ) - print(vpp.dump(reply)) -end - -^D^D^D - -run s1 ping -c 3 192.0.2.2 -expect s1 packet loss -run s1 ping -c 3 192.0.2.3 -expect s1 packet loss -run s1 ping -c 3 192.0.2.4 -expect s1 packet loss -run s1 ping6 -c 3 2001:db8:1::2 -expect s1 packet loss -run s1 ping6 -c 3 2001:db8:1::3 -expect s1 packet loss -run s1 ping6 -c 3 2001:db8:1::4 -expect s1 packet loss - - -cd lua ---- ACL testing - ---[[ temporary comment out - -reply = vpp:api_call("acl_del", { context = 42, acl_index = 230 }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_del", { context = 42, acl_index = 8 }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_del", { context = 42, acl_index = 15 }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_add_replace", { context = 42, acl_index = -1, count = 2, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 } } }) -print(vpp.dump(reply)) -print("---") -interface_acl_in = reply[1].acl_index - -reply = vpp:api_call("acl_add_replace", { context = 42, acl_index = -1, count = 3, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 }, { is_permit = 1, is_ipv6 = 0 } } }) -print(vpp.dump(reply)) -print("---") -interface_acl_out = reply[1].acl_index - - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 1, acl_index = interface_acl_in }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 1, acl_index = interface_acl_in }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 0, acl_index = interface_acl_out }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 0, acl_index = interface_acl_out }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_add_replace", { context = 42, acl_index = -1, count = 0 }) -print(vpp.dump(reply)) -print("---") - -acl_index_to_delete = reply[1].acl_index -print("Deleting " .. tostring(acl_index_to_delete)) -reply = vpp:api_call("acl_del", { context = 42, acl_index = acl_index_to_delete }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 0}) -for ri, rv in ipairs(reply) do - print("Reply message #" .. tostring(ri)) - print(vpp.dump(rv)) - for ai, av in ipairs(rv.r) do - print("ACL rule #" .. tostring(ai) .. " : " .. vpp.dump(av)) - end - -end -print("---") - -reply = vpp:api_call("acl_del", { context = 42, acl_index = interface_acl_out }) -print(vpp.dump(reply)) -print("---") -reply = vpp:api_call("acl_del", { context = 42, acl_index = interface_acl_in }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 0}) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 4294967295 }) -print(vpp.dump(reply)) -print("---") - - -]] -- end of comment out - ----- Should be nothing ^^ -r = { - { is_permit = 1, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8:1::2"), dst_ip_prefix_len = 128 }, - { is_permit = 0, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8:1::3"), dst_ip_prefix_len = 128 }, - { is_permit = 1, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8::"), dst_ip_prefix_len = 32 }, - { is_permit = 1, is_ipv6 = 0, dst_ip_addr = ip46("192.0.2.2"), dst_ip_prefix_len = 32}, - { is_permit = 0, is_ipv6 = 0, dst_ip_addr = ip46("192.0.2.3"), dst_ip_prefix_len = 32 }, -} - -reply = vpp:api_call("acl_add_replace", { context = 42, acl_index = -1, count = 5, r = r }) -print(vpp.dump(reply)) -print("---") -interface_acl_in = reply[1].acl_index - -reply = vpp:api_call("acl_add_replace", { context = 42, acl_index = -1, count = 3, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 }, { is_permit = 1, is_ipv6 = 0 } } }) -print(vpp.dump(reply)) -print("---") -interface_acl_out = reply[1].acl_in - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s1, is_add = 1, is_input = 1, acl_index = interface_acl_in }) -print(vpp.dump(reply)) -print("---") - ---reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s2, is_add = 1, is_input = 0, acl_index = interface_acl_out }) --- print(vpp.dump(reply)) ---print("---") - -^D^D^D - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping6 -c 3 2001:db8:1::2 -expect s1 packet loss -run VPP show trace -expect VPP match: inacl 0 rule 0 - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping6 -c 3 2001:db8:1::3 -expect s1 packet loss -run VPP show trace -expect VPP match: inacl 0 rule 1 - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping6 -c 3 2001:db8:1::4 -expect s1 packet loss -run VPP show trace -expect VPP match: inacl 0 rule 2 - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping -c 3 192.0.2.2 -expect s1 packet loss -run VPP show trace -expect VPP match: inacl 0 rule 3 - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping -c 3 192.0.2.3 -expect s1 packet loss -run VPP show trace -expect VPP match: inacl 0 rule 4 - - -cd lua - ---- TEST OUTBOUND ACL - -r1 = { - { is_permit = 1, is_ipv6 = 1, src_ip_addr = ip46("2001:db8:1::1"), src_ip_prefix_len = 128, dst_ip_addr = ip46("2001:db8:1::2"), dst_ip_prefix_len = 128 }, - { is_permit = 0, is_ipv6 = 1, src_ip_addr = ip46("2001:db8:1::1"), src_ip_prefix_len = 128, dst_ip_addr = ip46("2001:db8:1::4"), dst_ip_prefix_len = 128 } -} - -reply = vpp:api_call("acl_add_replace", { context = 42, acl_index = -1, count = 3, r = r1 }) -print(vpp.dump(reply)) -print("---") -interface_acl_out = reply[1].acl_index - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s2, is_add = 1, is_input = 0, acl_index = interface_acl_out }) -print(vpp.dump(reply)) -print("---") - - -^D^D^D - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping6 -c 3 2001:db8:1::2 -expect s1 packet loss -run VPP show trace -expect VPP match: outacl 2 rule 0 - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping6 -c 3 2001:db8:1::3 -expect s1 packet loss -run VPP show trace -expect VPP match: inacl 0 rule 1 - -run VPP clear trace -run VPP trace add af-packet-input 100 -run s1 ping6 -c 3 2001:db8:1::4 -expect s1 packet loss -run VPP show trace -expect VPP match: outacl 2 rule 1 - -run lua print("ALL GOOD!") - diff --git a/vpp-api/lua/examples/lute/script.lute b/vpp-api/lua/examples/lute/script.lute deleted file mode 100644 index c3dd90f2..00000000 --- a/vpp-api/lua/examples/lute/script.lute +++ /dev/null @@ -1,7 +0,0 @@ -shell s1 -expect s1 $ -run s1 echo testing123 -expect s1 $ -run s1 echo done -quit - diff --git a/vpp-api/lua/examples/lute/sessions-acl.lute b/vpp-api/lua/examples/lute/sessions-acl.lute deleted file mode 100644 index ac237ef9..00000000 --- a/vpp-api/lua/examples/lute/sessions-acl.lute +++ /dev/null @@ -1,308 +0,0 @@ -run lua -- collectgarbage("stop") - -shell vppbuild -run vppbuild stty -echo -run vppbuild sudo -u ubuntu -i bash -c "(cd vpp && make plugins && echo ALLGOOD)" -expect vppbuild ALLGOOD - -shell s0 -shell s1 -shell s2 - - -cd s1 -unshare -n /bin/bash -/sbin/ifconfig -a -^D^D^D - -cd s2 -unshare -n /bin/bash -/sbin/ifconfig -a -^D^D^D - - -cd lua - -function session_get_bash_pid(s) - if not has_session(s) then - return nil - end - local fname = "/tmp/lute-"..s.."-pid.txt" - - session_exec(s, "echo $$ >" .. fname) - -- it's a dirty hack but it's quick - sleep(0.5) - local pid = io.lines(fname)() - print("Got pid for " .. s .. " : " .. tostring(pid)) - return(tonumber(pid)) -end - -function session_connect_with(s0, s1) - -- local pid0 = tostring(session_get_bash_pid(s0)) - local pid1 = tostring(session_get_bash_pid(s1)) - local eth_options = { "rx", "tx", "sg", "tso", "ufo", "gso", "gro", "lro", "rxvlan", "txvlan", "rxhash" } - local this_end = s0 .. "_" .. s1 - local other_end = s1 .. "_" .. s0 - session_exec(s0, "ip link add name " .. this_end .. " type veth peer name " .. other_end) - session_exec(s0, "ip link set dev " .. this_end .. " up promisc on") - for i, option in ipairs(eth_options) do - session_exec(s0, "/sbin/ethtool --offload " .. this_end .. " " .. option .. " off") - session_exec(s0, "/sbin/ethtool --offload " .. other_end .. " " .. option .. " off") - end - session_exec(s0, "ip link set dev " .. other_end .. " up promisc on netns /proc/" .. pid1 .. "/ns/net") - sleep(0.5) -end - -^D^D^D -run lua session_connect_with("s0", "s1") -run lua session_connect_with("s0", "s2") - -cd s1 -ip -6 addr add dev s1_s0 2001:db8:1::1/64 -ip -4 addr add dev s1_s0 192.0.2.1/24 -ip link set dev s1_s0 up promisc on -^D^D^D - -cd s2 -ip -6 addr add dev s2_s0 2001:db8:1::2/64 -ip -6 addr add dev s2_s0 2001:db8:1::3/64 -ip -6 addr add dev s2_s0 2001:db8:1::4/64 -ip -4 addr add dev s2_s0 192.0.2.2/24 -ip -4 addr add dev s2_s0:1 192.0.2.3/24 -ip -4 addr add dev s2_s0:2 192.0.2.4/24 -ip link set dev s2_s0 up promisc on -^D^D^D - -run s1 ip addr -run s2 ip addr -shell VPP -cd VPP -cd /home/ubuntu/vpp -make debug -r -^D^D^D -expect VPP DBGvpp# - -cd lua --- Initialization of the Lua environment for talking to VPP -vpp = require("vpp-lapi") -root_dir = "/home/ubuntu/vpp" -pneum_path = root_dir .. "/build-root/install-vpp_debug-native/vpp-api/lib64/libpneum.so" -vpp:init({ pneum_path = pneum_path }) -vpp:consume_api(root_dir .. "/build-root/install-vpp_debug-native/vlib-api/vlibmemory/memclnt.api") -vpp:consume_api(root_dir .. "/build-root/install-vpp_debug-native/vpp/vpp-api/vpe.api") -vpp:connect("aytest") -vpp:consume_api(root_dir .. "/plugins/acl-plugin/acl/acl.api", "acl") - -^D^D^D - -cd lua - -reply = vpp:api_call("af_packet_create", { host_if_name = "s0_s1", hw_addr = "AAAAAA" }) -vpp_if_to_s1 = reply[1].sw_if_index - -reply = vpp:api_call("af_packet_create", { host_if_name = "s0_s2", hw_addr = "AAAAAA" }) -vpp_if_to_s2 = reply[1].sw_if_index - -ifaces = { vpp_if_to_s1, vpp_if_to_s2 } - -reply = vpp:api_call("sw_interface_set_flags", { sw_if_index = vpp_if_to_s1, admin_up_down = 1, link_up_down = 1 }) -print(vpp.dump(reply)) -reply = vpp:api_call("sw_interface_set_flags", { sw_if_index = vpp_if_to_s2, admin_up_down = 1, link_up_down = 1 }) -print(vpp.dump(reply)) - -bd_id = 42 - -reply = vpp:api_call("bridge_domain_add_del", { bd_id = bd_id, flood = 1, uu_flood = 1, forward = 1, learn = 1, arp_term = 0, is_add = 1 }) -print(vpp.dump(reply)) - -for i, v in ipairs(ifaces) do - reply = vpp:api_call("sw_interface_set_l2_bridge", { rx_sw_if_index = v, bd_id = bd_id, shg = 0, bvi = 0, enable = 1 } ) - print(vpp.dump(reply)) -end - -^D^D^D - -run s1 ping -c 3 192.0.2.2 -expect s1 packet loss -run s1 ping -c 3 192.0.2.3 -expect s1 packet loss -run s1 ping -c 3 192.0.2.4 -expect s1 packet loss -run s1 ping6 -c 3 2001:db8:1::2 -expect s1 packet loss -run s1 ping6 -c 3 2001:db8:1::3 -expect s1 packet loss -run s1 ping6 -c 3 2001:db8:1::4 -expect s1 packet loss - - -cd lua ---- ACL testing - ---[[ temporary comment out - -reply = vpp:api_call("acl_del", { context = 42, acl_index = 230 }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_del", { context = 42, acl_index = 8 }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_del", { context = 42, acl_index = 15 }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_add", { context = 42, count = 2, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 } } }) -print(vpp.dump(reply)) -print("---") -interface_acl_in = reply[1].acl_index - -reply = vpp:api_call("acl_add", { context = 42, count = 3, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 }, { is_permit = 1, is_ipv6 = 0 } } }) -print(vpp.dump(reply)) -print("---") -interface_acl_out = reply[1].acl_index - - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 1, acl_index = interface_acl_in }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 1, acl_index = interface_acl_in }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 0, acl_index = interface_acl_out }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = 0, is_add = 1, is_input = 0, acl_index = interface_acl_out }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_add", { context = 42, count = 0 }) -print(vpp.dump(reply)) -print("---") - -acl_index_to_delete = reply[1].acl_index -print("Deleting " .. tostring(acl_index_to_delete)) -reply = vpp:api_call("acl_del", { context = 42, acl_index = acl_index_to_delete }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 0}) -for ri, rv in ipairs(reply) do - print("Reply message #" .. tostring(ri)) - print(vpp.dump(rv)) - for ai, av in ipairs(rv.r) do - print("ACL rule #" .. tostring(ai) .. " : " .. vpp.dump(av)) - end - -end -print("---") - -reply = vpp:api_call("acl_del", { context = 42, acl_index = interface_acl_out }) -print(vpp.dump(reply)) -print("---") -reply = vpp:api_call("acl_del", { context = 42, acl_index = interface_acl_in }) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 0}) -print(vpp.dump(reply)) -print("---") - -reply = vpp:api_call("acl_dump", { context = 42, sw_if_index = 4294967295 }) -print(vpp.dump(reply)) -print("---") - - -]] -- end of comment out - ----- Should be nothing ^^ -r = { - { is_permit = 1, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8:1::2"), dst_ip_prefix_len = 128 }, - { is_permit = 0, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8:1::3"), dst_ip_prefix_len = 128 }, - { is_permit = 1, is_ipv6 = 1, dst_ip_addr = ip46("2001:db8::"), dst_ip_prefix_len = 32 }, - { is_permit = 1, is_ipv6 = 0, dst_ip_addr = ip46("192.0.2.2"), dst_ip_prefix_len = 32}, - { is_permit = 0, is_ipv6 = 0, dst_ip_addr = ip46("192.0.2.3"), dst_ip_prefix_len = 32 }, -} - -reply = vpp:api_call("acl_add", { context = 42, count = 5, r = r }) -print(vpp.dump(reply)) -print("---") -interface_acl_in = reply[1].acl_index - -reply = vpp:api_call("acl_add", { context = 42, count = 3, r = { { is_permit = 1, is_ipv6 = 1 }, { is_permit = 0, is_ipv6 = 1 }, { is_permit = 1, is_ipv6 = 0 } } }) -print(vpp.dump(reply)) -print("---") -interface_acl_out = reply[1].acl_in - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s1, is_add = 1, is_input = 1, acl_index = interface_acl_in }) -print(vpp.dump(reply)) -print("---") - ---- TEST OUTBOUND ACL - -r1 = { - { is_permit = 1, is_ipv6 = 1, src_ip_addr = ip46("2001:db8:1::1"), src_ip_prefix_len = 128, dst_ip_addr = ip46("2001:db8:1::2"), dst_ip_prefix_len = 128 }, - { is_permit = 0, is_ipv6 = 1, src_ip_addr = ip46("2001:db8:1::1"), src_ip_prefix_len = 128, dst_ip_addr = ip46("2001:db8:1::4"), dst_ip_prefix_len = 128 }, - { is_permit = 2, is_ipv6 = 0 } -} - -reply = vpp:api_call("acl_add", { context = 42, count = 3, r = r1 }) -print(vpp.dump(reply)) -print("---") -interface_acl_out = reply[1].acl_index - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s2, is_add = 1, is_input = 0, acl_index = interface_acl_out }) -print(vpp.dump(reply)) -print("---") - -r2 = { - { is_permit = 1, is_ipv6 = 1 }, - { is_permit = 0, is_ipv6 = 0 } -} - -reply = vpp:api_call("acl_add", { context = 42, count = 2, r = r2 }) -print(vpp.dump(reply)) -print("---") -second_interface_acl_in = reply[1].acl_index - -reply = vpp:api_call("acl_interface_add_del", { context = 42, sw_if_index = vpp_if_to_s2, is_add = 1, is_input = 1, acl_index = second_interface_acl_in }) -print(vpp.dump(reply)) -print("---") - -^D^D^D - -run VPP show classify tables -run VPP clear trace -run VPP trace add af-packet-input 100 -run s2 nc -v -l -p 22 -run s1 nc 192.0.2.2 22 -run s1 echo -sleep 1 -run s1 break -sleep 1 -run VPP show trace -expect VPP match: outacl 2 rule 2 -run VPP show classify tables - - -run VPP show classify tables -run VPP clear trace -run VPP trace add af-packet-input 100 -run s2 nc -v -l -p 22 -run s1 nc 192.0.2.2 22 -run s1 echo -sleep 1 -run s1 break -sleep 1 -run VPP show trace -expect VPP match: outacl 2 rule 2 -run VPP show classify tables - - -run lua print("ALL GOOD!") - diff --git a/vpp-api/lua/vpp-lapi.lua b/vpp-api/lua/vpp-lapi.lua deleted file mode 100644 index ebfd032b..00000000 --- a/vpp-api/lua/vpp-lapi.lua +++ /dev/null @@ -1,989 +0,0 @@ ---[[ -/* - * 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. - */ -]] - --- json decode/encode from https://gist.github.com/tylerneylon/59f4bcf316be525b30ab --- licensed by the author tylerneylon into public domain. Thanks! - -local json = {} - --- Internal functions. - -local function kind_of(obj) - if type(obj) ~= 'table' then return type(obj) end - local i = 1 - for _ in pairs(obj) do - if obj[i] ~= nil then i = i + 1 else return 'table' end - end - if i == 1 then return 'table' else return 'array' end -end - -local function escape_str(s) - local in_char = {'\\', '"', '/', '\b', '\f', '\n', '\r', '\t'} - local out_char = {'\\', '"', '/', 'b', 'f', 'n', 'r', 't'} - for i, c in ipairs(in_char) do - s = s:gsub(c, '\\' .. out_char[i]) - end - return s -end - --- Returns pos, did_find; there are two cases: --- 1. Delimiter found: pos = pos after leading space + delim; did_find = true. --- 2. Delimiter not found: pos = pos after leading space; did_find = false. --- This throws an error if err_if_missing is true and the delim is not found. -local function skip_delim(str, pos, delim, err_if_missing) - pos = pos + #str:match('^%s*', pos) - if str:sub(pos, pos) ~= delim then - if err_if_missing then - error('Expected ' .. delim .. ' near position ' .. pos) - end - return pos, false - end - return pos + 1, true -end - --- Expects the given pos to be the first character after the opening quote. --- Returns val, pos; the returned pos is after the closing quote character. -local function parse_str_val(str, pos, val) - val = val or '' - local early_end_error = 'End of input found while parsing string.' - if pos > #str then error(early_end_error) end - local c = str:sub(pos, pos) - if c == '"' then return val, pos + 1 end - if c ~= '\\' then return parse_str_val(str, pos + 1, val .. c) end - -- We must have a \ character. - local esc_map = {b = '\b', f = '\f', n = '\n', r = '\r', t = '\t'} - local nextc = str:sub(pos + 1, pos + 1) - if not nextc then error(early_end_error) end - return parse_str_val(str, pos + 2, val .. (esc_map[nextc] or nextc)) -end - --- Returns val, pos; the returned pos is after the number's final character. -local function parse_num_val(str, pos) - local num_str = str:match('^-?%d+%.?%d*[eE]?[+-]?%d*', pos) - local val = tonumber(num_str) - if not val then error('Error parsing number at position ' .. pos .. '.') end - return val, pos + #num_str -end - - --- Public values and functions. - -function json.stringify(obj, as_key) - local s = {} -- We'll build the string as an array of strings to be concatenated. - local kind = kind_of(obj) -- This is 'array' if it's an array or type(obj) otherwise. - if kind == 'array' then - if as_key then error('Can\'t encode array as key.') end - s[#s + 1] = '[' - for i, val in ipairs(obj) do - if i > 1 then s[#s + 1] = ', ' end - s[#s + 1] = json.stringify(val) - end - s[#s + 1] = ']' - elseif kind == 'table' then - if as_key then error('Can\'t encode table as key.') end - s[#s + 1] = '{' - for k, v in pairs(obj) do - if #s > 1 then s[#s + 1] = ', ' end - s[#s + 1] = json.stringify(k, true) - s[#s + 1] = ':' - s[#s + 1] = json.stringify(v) - end - s[#s + 1] = '}' - elseif kind == 'string' then - return '"' .. escape_str(obj) .. '"' - elseif kind == 'number' then - if as_key then return '"' .. tostring(obj) .. '"' end - return tostring(obj) - elseif kind == 'boolean' then - return tostring(obj) - elseif kind == 'nil' then - return 'null' - else - error('Unjsonifiable type: ' .. kind .. '.') - end - return table.concat(s) -end - -json.null = {} -- This is a one-off table to represent the null value. - -function json.parse(str, pos, end_delim) - pos = pos or 1 - if pos > #str then error('Reached unexpected end of input.') end - local pos = pos + #str:match('^%s*', pos) -- Skip whitespace. - local first = str:sub(pos, pos) - if first == '{' then -- Parse an object. - local obj, key, delim_found = {}, true, true - pos = pos + 1 - while true do - key, pos = json.parse(str, pos, '}') - if key == nil then return obj, pos end - if not delim_found then error('Comma missing between object items.') end - pos = skip_delim(str, pos, ':', true) -- true -> error if missing. - obj[key], pos = json.parse(str, pos) - pos, delim_found = skip_delim(str, pos, ',') - end - elseif first == '[' then -- Parse an array. - local arr, val, delim_found = {}, true, true - pos = pos + 1 - while true do - val, pos = json.parse(str, pos, ']') - if val == nil then return arr, pos end - if not delim_found then error('Comma missing between array items.') end - arr[#arr + 1] = val - pos, delim_found = skip_delim(str, pos, ',') - end - elseif first == '"' then -- Parse a string. - return parse_str_val(str, pos + 1) - elseif first == '-' or first:match('%d') then -- Parse a number. - return parse_num_val(str, pos) - elseif first == end_delim then -- End of an object or array. - return nil, pos + 1 - else -- Parse true, false, or null. - local literals = {['true'] = true, ['false'] = false, ['null'] = json.null} - for lit_str, lit_val in pairs(literals) do - local lit_end = pos + #lit_str - 1 - if str:sub(pos, lit_end) == lit_str then return lit_val, lit_end + 1 end - end - local pos_info_str = 'position ' .. pos .. ': ' .. str:sub(pos, pos + 10) - error('Invalid json syntax starting at ' .. pos_info_str) - end -end - - -local vpp = {} - -local ffi = require("ffi") - ---[[ - -The basic type definitions. A bit of weird gymnastic with -unionization of the hton* and ntoh* functions results -is to make handling of signed and unsigned types a bit cleaner, -essentially building typecasting into a C union. - -The vl_api_opaque_message_t is a synthetic type assumed to have -enough storage to hold the entire API message regardless of the type. -During the operation it is casted to the specific message struct types. - -]] - - -ffi.cdef([[ - -typedef uint8_t u8; -typedef int8_t i8; -typedef uint16_t u16; -typedef int16_t i16; -typedef uint32_t u32; -typedef int32_t i32; -typedef uint64_t u64; -typedef int64_t i64; -typedef double f64; -typedef float f32; - -#pragma pack(1) -typedef union { - u16 u16; - i16 i16; -} lua_ui16t; - -#pragma pack(1) -typedef union { - u32 u32; - i32 i32; -} lua_ui32t; - -u16 ntohs(uint16_t hostshort); -u16 htons(uint16_t hostshort); -u32 htonl(uint32_t along); -u32 ntohl(uint32_t along); -void *memset(void *s, int c, size_t n); -void *memcpy(void *dest, void *src, size_t n); - -#pragma pack(1) -typedef struct _vl_api_opaque_message { - u16 _vl_msg_id; - u8 data[65536]; -} vl_api_opaque_message_t; -]]) - - --- CRC-based version stuff - -local crc32c_table = ffi.new('const uint32_t[256]', - { 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, - 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, - 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, - 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, - 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, - 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, - 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, - 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, - 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, - 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, - 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, - 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, - 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, - 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, - 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, - 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, - 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, - 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, - 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, - 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, - 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, - 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, - 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, - 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, - 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, - 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, - 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, - 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, - 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, - 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, - 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, - 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, - 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, - 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, - 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, - 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, - 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, - 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, - 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, - 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, - 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, - 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, - 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, - 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, - 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, - 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, - 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, - 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, - 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, - 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, - 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, - 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, - 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, - 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, - 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, - 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, - 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, - 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, - 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, - 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, - 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, - 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, - 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, - 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351 } -); - -local function CRC8(crc, d) - return bit.bxor(bit.rshift(crc, 8), crc32c_table[bit.band(0xff, bit.bxor(crc, d))]) -end - -local function CRC16(crc, d) - crc = CRC8(crc, bit.band(d, 0xFF)) - d = bit.rshift(d, 8) - crc = CRC8(crc, bit.band(d, 0xFF)) - return crc -end - -local function string_crc(str, crc) - for i=1,#str do - -- print("S", i, string.byte(str, i), string.char(string.byte(str, i))) - crc = CRC8(crc, string.byte(str, i)) - end - return crc -end - -local tokens = { - { ["match"] =' ', ["act"] = { } }, - { ["match"] ='\n', ["act"] = { } }, - { ["match"] ="manual_endian", ["act"] = { "NODE_MANUAL_ENDIAN", "MANUAL_ENDIAN", 276 } }, - { ["match"] ="define", ["act"] = { "NODE_DEFINE", "DEFINE", 267 } }, - { ["match"] ="dont_trace", ["act"] = { "NODE_DONT_TRACE", "DONT_TRACE", 279 } }, - { ["match"] ="f64", ["act"] = { "NODE_F64", "PRIMTYPE", string_crc } }, - { ["match"] ="i16", ["act"] = { "NODE_I16", "PRIMTYPE", string_crc } }, - { ["match"] ="i32", ["act"] = { "NODE_I32", "PRIMTYPE", string_crc } }, - { ["match"] ="i64", ["act"] = { "NODE_I64", "PRIMTYPE", string_crc } }, - { ["match"] ="i8", ["act"] = { "NODE_I8", "PRIMTYPE", string_crc } }, - { ["match"] ="manual_print", ["act"] = { "NODE_MANUAL_PRINT", "MANUAL_PRINT", 275 } }, - { ["match"] ="noversion", ["act"] = { "NODE_NOVERSION", "NOVERSION", 274 } }, - { ["match"] ="packed", ["act"] = { "NODE_PACKED", "TPACKED", 266 } }, - { ["match"] ="typeonly", ["act"] = { "NODE_TYPEONLY", "TYPEONLY", 278 } }, - { ["match"] ="u16", ["act"] = { "NODE_U16", "PRIMTYPE", string_crc } }, - { ["match"] ="u32", ["act"] = { "NODE_U32", "PRIMTYPE", string_crc } }, - { ["match"] ="u64", ["act"] = { "NODE_U64", "PRIMTYPE", string_crc } }, - { ["match"] ="u8", ["act"] = { "NODE_U8", "PRIMTYPE", string_crc } }, - { ["match"] ="union", ["act"] = { "NODE_UNION", "UNION", 271 } }, - { ["match"] ="uword", ["act"] = { "NODE_UWORD", "PRIMTYPE", string_crc } }, - { ["match"] ="%(", ["act"] = { "NODE_LPAR", "LPAR", 259 } }, - { ["match"] ="%)", ["act"] = { "NODE_RPAR", "RPAR", 258 } }, - { ["match"] =";", ["act"] = { "NODE_SEMI", "SEMI", 260 } }, - { ["match"] ="%[", ["act"] = { "NODE_LBRACK", "LBRACK", 261 } }, - { ["match"] ="%]", ["act"] = { "NODE_RBRACK", "RBRACK", 262 } }, - { ["match"] ="%{", ["act"] = { "NODE_LCURLY", "LCURLY", 268 } }, - { ["match"] ="%}", ["act"] = { "NODE_RCURLY", "RCURLY", 269 } }, - { ["match"] ='%b""', ["act"] = { "NODE_STRING", "STRING", string_crc } }, - { ["match"] ='%b@@', ["act"] = { "NODE_HELPER", "HELPER_STRING", string_crc } }, - -- TODO: \ must be consumed - { ["match"] ='[_a-zA-Z][_a-zA-Z0-9]*', - ["act"] = { "NODE_NAME", "NAME", string_crc } }, - { ["match"] ='[0-9]+', ["act"] = { "NODE_NUMBER", "NUMBER", string_crc } }, - { ["match"] ='#[^\n]+', ["act"] = { "NODE_PRAGMA", "PRAGMA", nil } }, -} - - -function vpp.crc_version_string(data) - local input_crc = 0 - -- Get rid of comments - data = data:gsub("/%*.-%*/", "") - data = data:gsub("//[^\n]+", "") - -- print(data) - idx = 1 - while (true) do - local matched = nil - for k, v in ipairs(tokens) do - if not matched then - local x, y, cap = string.find(data, v["match"], idx) - if x == idx then - matched = { ["node"] = v["act"], ["x"] = x, ["y"] = y, ["cap"] = cap, ["chars"] = string.sub(data, x, y) } - -- print(k, v, x, y, cap, matched.chars, matched.node[0] ) - end - end - end - if matched then - idx = idx + (matched.y - matched.x + 1) - if matched.node[1] then - local act = matched.node[3] - if type(act) == "function" then - input_crc = act(matched.chars, input_crc) - elseif type(act) == "number" then - input_crc = CRC16(input_crc, act) - end - -- print(vpp.dump(matched)) - end - else - -- print("NOT MATCHED!") - local crc = CRC16(input_crc, 0xFFFFFFFF) - return string.sub(string.format("%x", crc), -8) - end - end -end - - -function vpp.dump(o) - if type(o) == 'table' then - local s = '{ ' - for k,v in pairs(o) do - if type(k) ~= 'number' then k = '"'..k..'"' end - s = s .. '['..k..'] = ' .. vpp.dump(v) .. ',' - end - return s .. '} ' - else - return tostring(o) - end -end - -function vpp.hex_dump(buf) - local ret = {} - for i=1,math.ceil(#buf/16) * 16 do - if (i-1) % 16 == 0 then table.insert(ret, string.format('%08X ', i-1)) end - table.insert(ret, ( i > #buf and ' ' or string.format('%02X ', buf:byte(i)) )) - if i % 8 == 0 then table.insert(ret, ' ') end - if i % 16 == 0 then table.insert(ret, buf:sub(i-16+1, i):gsub('%c','.')..'\n' ) end - end - return table.concat(ret) -end - - -function vpp.c_str(text_in) - local text = text_in -- \000 will be helpfully added by ffi.copy - local c_str = ffi.new("char[?]", #text+1) - ffi.copy(c_str, text) - return c_str -end - - -function vpp.init(vpp, args) - local pneum_api = args.pneum_api or [[ - int cough_pneum_attach(char *pneum_path, char *cough_path); - int pneum_connect(char *name, char *chroot_prefix, void *cb); - int pneum_disconnect(void); - int pneum_read(char **data, int *l); - int pneum_write(char *data, int len); - void pneum_free(char *data); - uint32_t pneum_get_msg_index(unsigned char * name); -]] - - vpp.pneum_path = args.pneum_path - ffi.cdef(pneum_api) - local init_res = 0 - vpp.pneum = ffi.load(vpp.pneum_path) - if (init_res < 0) then - return nil - end - - vpp.next_msg_num = 1 - vpp.msg_name_to_number = {} - vpp.msg_name_to_fields = {} - vpp.msg_number_to_name = {} - vpp.msg_number_to_type = {} - vpp.msg_number_to_pointer_type = {} - vpp.msg_name_to_crc = {} - vpp.c_type_to_fields = {} - vpp.events = {} - vpp.plugin_version = {} - vpp.is_connected = false - - - vpp.t_lua2c = {} - vpp.t_c2lua = {} - vpp.t_lua2c["u8"] = function(c_type, src, dst_c_ptr) - if type(src) == "string" then - -- ffi.copy adds a zero byte at the end. Grrr. - -- ffi.copy(dst_c_ptr, src) - ffi.C.memcpy(dst_c_ptr, vpp.c_str(src), #src) - return(#src) - elseif type(src) == "table" then - for i,v in ipairs(src) do - ffi.cast("u8 *", dst_c_ptr)[i-1] = v - end - return(#src) - else - return 1, src -- ffi.cast("u8", src) - end - end - vpp.t_c2lua["u8"] = function(c_type, src_ptr, src_len) - if src_len then - return ffi.string(src_ptr, src_len) - else - return (tonumber(src_ptr)) - end - end - - vpp.t_lua2c["u16"] = function(c_type, src, dst_c_ptr) - if type(src) == "table" then - for i,v in ipairs(src) do - ffi.cast("u16 *", dst_c_ptr)[i-1] = ffi.C.htons(v) - end - return(2 * #src) - else - return 2, (ffi.C.htons(src)) - end - end - vpp.t_c2lua["u16"] = function(c_type, src_ptr, src_len) - if src_len then - local out = {} - for i = 0,src_len-1 do - out[i+1] = tonumber(ffi.C.ntohs(src_ptr[i])) - end - return out - else - return (tonumber(ffi.C.ntohs(src_ptr))) - end - end - - vpp.t_lua2c["u32"] = function(c_type, src, dst_c_ptr) - if type(src) == "table" then - for i,v in ipairs(src) do - ffi.cast("u32 *", dst_c_ptr)[i-1] = ffi.C.htonl(v) - end - return(4 * #src) - else - return 4, (ffi.C.htonl(src)) - end - end - vpp.t_c2lua["u32"] = function(c_type, src_ptr, src_len) - if src_len then - local out = {} - for i = 0,src_len-1 do - out[i+1] = tonumber(ffi.C.ntohl(src_ptr[i])) - end - return out - else - return (tonumber(ffi.C.ntohl(src_ptr))) - end - end - vpp.t_lua2c["i32"] = function(c_type, src, dst_c_ptr) - if type(src) == "table" then - for i,v in ipairs(src) do - ffi.cast("i32 *", dst_c_ptr)[i-1] = ffi.C.htonl(v) - end - return(4 * #src) - else - return 4, (ffi.C.htonl(src)) - end - end - vpp.t_c2lua["i32"] = function(c_type, src_ptr, src_len) - local ntohl = function(src) - local u32val = ffi.cast("u32", src) - local ntohlval = (ffi.C.ntohl(u32val)) - local out = tonumber(ffi.cast("i32", ntohlval + 0LL)) - return out - end - if src_len then - local out = {} - for i = 0,src_len-1 do - out[i+1] = tonumber(ntohl(src_ptr[i])) - end - else - return (tonumber(ntohl(src_ptr))) - end - end - - vpp.t_lua2c["u64"] = function(c_type, src, dst_c_ptr) - if type(src) == "table" then - for i,v in ipairs(src) do - ffi.cast("u64 *", dst_c_ptr)[i-1] = v --- FIXME ENDIAN - end - return(8 * #src) - else - return 8, ffi.cast("u64", src) --- FIXME ENDIAN - end - end - vpp.t_c2lua["u64"] = function(c_type, src_ptr, src_len) - if src_len then - local out = {} - for i = 0,src_len-1 do - out[i+1] = tonumber(src_ptr[i]) -- FIXME ENDIAN - end - return out - else - return (tonumber(src_ptr)) --FIXME ENDIAN - end - end - - - - - vpp.t_lua2c["__MSG__"] = function(c_type, src, dst_c_ptr) - local dst = ffi.cast(c_type .. " *", dst_c_ptr) - local additional_len = 0 - local fields_info = vpp.c_type_to_fields[c_type] - -- print("__MSG__ type: " .. tostring(c_type)) - ffi.C.memset(dst_c_ptr, 0, ffi.sizeof(dst[0])) - -- print(vpp.dump(fields_info)) - -- print(vpp.dump(src)) - for k,v in pairs(src) do - local field = fields_info[k] - if not field then - print("ERROR: field " .. tostring(k) .. " in message " .. tostring(c_type) .. " is unknown") - end - local lua2c = vpp.t_lua2c[field.c_type] - -- print("__MSG__ field " .. tostring(k) .. " : " .. vpp.dump(field)) - -- if the field is not an array type, try to coerce the argument to a number - if not field.array and type(v) == "string" then - v = tonumber(v) - end - if not lua2c then - print("__MSG__ " .. tostring(c_type) .. " t_lua2c: can not store field " .. field.name .. - " type " .. field.c_type .. " dst " .. tostring(dst[k])) - return 0 - end - local len = 0 - local val = nil - if field.array and (type(v) == "table") then - -- print("NTFY: field " .. tostring(k) .. " in message " .. tostring(c_type) .. " is an array") - for field_i, field_v in ipairs(v) do - -- print("NTFY: setting member#" .. tostring(field_i) .. " to value " .. vpp.dump(field_v)) - local field_len, field_val = lua2c(field.c_type, field_v, dst[k][field_i-1]) - len = len + field_len - end - else - len, val = lua2c(field.c_type, v, dst[k]) - end - if not field.array then - dst[k] = val - else - if 0 == field.array then - additional_len = additional_len + len - -- print("Adding " .. tostring(len) .. " bytes due to field " .. tostring(field.name)) - -- If there is a variable storing the length - -- and the input table does not set it, do magic - if field.array_size and not src[field.array_size] then - local size_field = fields_info[field.array_size] - if size_field then - dst[field.array_size] = vpp.t_c2lua[size_field.c_type](size_field.c_type, len) - end - end - end - end - -- print("Full message:\n" .. vpp.hex_dump(ffi.string(ffi.cast('void *', req_store_cache), 64))) - end - return (ffi.sizeof(dst[0])+additional_len) - end - - vpp.t_c2lua["__MSG__"] = function(c_type, src_ptr, src_len) - local out = {} - local reply_typed_ptr = ffi.cast(c_type .. " *", src_ptr) - local field_desc = vpp.c_type_to_fields[c_type] - if src_len then - for i = 0,src_len-1 do - out[i+1] = vpp.t_c2lua[c_type](c_type, src_ptr[i]) - end - return out - end - - for k, v in pairs(field_desc) do - local v_c2lua = vpp.t_c2lua[v.c_type] - if v_c2lua then - local len = v.array - -- print(dump(v)) - if len then - local len_field_name = k .. "_length" - local len_field = field_desc[len_field_name] - if (len_field) then - local real_len = vpp.t_c2lua[len_field.c_type](len_field.c_type, reply_typed_ptr[len_field_name]) - out[k] = v_c2lua(v.c_type, reply_typed_ptr[k], real_len) - elseif len == 0 then - -- check if len = 0, then must be a field which contains the size - len_field = field_desc[v.array_size] - local real_len = vpp.t_c2lua[len_field.c_type](len_field.c_type, reply_typed_ptr[v.array_size]) - -- print("REAL length: " .. vpp.dump(v) .. " : " .. tostring(real_len)) - out[k] = v_c2lua(v.c_type, reply_typed_ptr[k], real_len) - else - -- alas, just stuff the entire array - out[k] = v_c2lua(v.c_type, reply_typed_ptr[k], len) - end - else - out[k] = v_c2lua(v.c_type, reply_typed_ptr[k]) - end - else - out[k] = "" - end - -- print(k, out[k]) - end - return out - end - - return vpp -end - -function vpp.resolve_message_number(msgname) - local name = msgname .. "_" .. vpp.msg_name_to_crc[msgname] - local idx = vpp.pneum.pneum_get_msg_index(vpp.c_str(name)) - if vpp.debug_dump then - print("Index for " .. tostring(name) .. " is " .. tostring(idx)) - end - vpp.msg_name_to_number[msgname] = idx - vpp.msg_number_to_name[idx] = msgname - vpp.msg_number_to_type[idx] = "vl_api_" .. msgname .. "_t" - vpp.msg_number_to_pointer_type[idx] = vpp.msg_number_to_type[idx] .. " *" - ffi.cdef("\n\n enum { vl_msg_" .. msgname .. " = " .. idx .. " };\n\n") -end - -function vpp.connect(vpp, client_name) - local name = "lua_client" - if client_name then - name = client_name - end - local ret = vpp.pneum.pneum_connect(vpp.c_str(client_name), nil, nil) - if tonumber(ret) == 0 then - vpp.is_connected = true - end - for k, v in pairs(vpp.msg_name_to_number) do - vpp.resolve_message_number(k) - end - end - -function vpp.disconnect(vpp) - vpp.pneum.pneum_disconnect() - end - -function vpp.json_api(vpp, path, plugin_name) - -- print("Consuming the VPP api from "..path) - local ffii = {} - local f = io.open(path, "r") - if not f then - print("Could not open " .. path) - return nil - end - local data = f:read("*all") - local json = json.parse(data) - if not (json.types or json.messages) then - print("Can not parse " .. path) - return nil - end - - local all_types = {} - - for i, v in ipairs(json.types) do - table.insert(all_types, { typeonly = 1, desc = v }) - end - for i, v in ipairs(json.messages) do - table.insert(all_types, { typeonly = 0, desc = v }) - end - for i, v in ipairs(all_types) do - local typeonly = v.typeonly - local name = v.desc[1] - local c_type = "vl_api_" .. name .. "_t" - - local fields = {} - -- vpp.msg_name_to_fields[name] = fields - -- print("CTYPE " .. c_type) - vpp.c_type_to_fields[c_type] = fields - vpp.t_lua2c[c_type] = vpp.t_lua2c["__MSG__"] - vpp.t_c2lua[c_type] = vpp.t_c2lua["__MSG__"] - - local cdef = { "\n\n#pragma pack(1)\ntypedef struct _vl_api_", name, " {\n" } - for ii, vv in ipairs(v.desc) do - if type(vv) == "table" then - if vv.crc then - vpp.msg_name_to_crc[name] = string.sub(vv.crc, 3) -- strip the leading 0x - else - local fieldtype = vv[1] - local fieldname = vv[2] - local fieldcount = vv[3] - local fieldcountvar = vv[4] - local fieldrec = { name = fieldname, c_type = fieldtype, array = fieldcount, array_size = fieldcountvar } - if fieldcount then - table.insert(cdef, " " .. fieldtype .. " " .. fieldname .. "[" .. fieldcount .. "];\n") - if fieldtype == "u8" then - -- any array of bytes is treated as a string - elseif vpp.t_lua2c[fieldtype] then - -- print("Array of " .. fieldtype .. " is ok!") - else - print("Unknown array type: ", name, " : " , fieldname, " : ", fieldtype, ":", fieldcount, ":", fieldcountvar) - end - else - table.insert(cdef, " " .. fieldtype .. " " .. fieldname .. ";\n") - end - fields[fieldname] = fieldrec - end - end - end - - table.insert(cdef, "} vl_api_" .. name .. "_t;") - table.insert(ffii, table.concat(cdef)) - - if typeonly == 0 then - -- we will want to resolve this later - if vpp.debug_dump then - print("Remember to resolve " .. name) - end - vpp.msg_name_to_number[name] = -1 - if vpp.is_connected then - vpp.resolve_message_number(name) - end - end - - end - local cdef_full = table.concat(ffii) - ffi.cdef(cdef_full) -end - -function vpp.consume_api(vpp, path, plugin_name) - -- print("Consuming the VPP api from "..path) - local ffii = {} - local f = io.open(path, "r") - if not f then - print("Could not open " .. path) - return nil - end - local data = f:read("*all") - -- Remove all C comments - data = data:gsub("/%*.-%*/", "") - if vpp.is_connected and not plugin_name then - print(path .. ": must specify plugin name!") - return - end - if plugin_name then - vpp.plugin_version[plugin_name] = vpp.crc_version_string(data) - local full_plugin_name = plugin_name .. "_" .. vpp.plugin_version[plugin_name] - local reply = vpp:api_call("get_first_msg_id", { name = full_plugin_name } ) - vpp.next_msg_num = tonumber(reply[1].first_msg_id) - print("Plugin " .. full_plugin_name .. " first message is " .. tostring(vpp.next_msg_num)) - end - -- print ("data len: ", #data) - data = data:gsub("\n(.-)(%S+)%s*{([^}]*)}", function (preamble, name, members) - local _, typeonly = preamble:gsub("typeonly", "") - local maybe_msg_id_field = { [0] = "u16 _vl_msg_id;", "" } - local onedef = "\n\n#pragma pack(1)\ntypedef struct _vl_api_"..name.. " {\n" .. - -- " u16 _vl_msg_id;" .. - maybe_msg_id_field[typeonly] .. - members:gsub("%[[a-zA-Z_]+]", "[0]") .. - "} vl_api_" .. name .. "_t;" - - local c_type = "vl_api_" .. name .. "_t" - - local fields = {} - -- vpp.msg_name_to_fields[name] = fields - -- print("CTYPE " .. c_type) - vpp.c_type_to_fields[c_type] = fields - vpp.t_lua2c[c_type] = vpp.t_lua2c["__MSG__"] - vpp.t_c2lua[c_type] = vpp.t_c2lua["__MSG__"] - local mirec = { name = "_vl_msg_id", c_type = "u16", array = nil, array_size = nil } - if typeonly == 0 then - fields[mirec.name] = mirec - end - - -- populate the field reflection table for the message - -- sets the various type information as well as the accessors for lua<->C conversion - members:gsub("(%S+)%s+(%S+);", function (fieldtype, fieldname) - local fieldcount = nil - local fieldcountvar = nil - -- data = data:gsub("%[[a-zA-Z_]+]", "[0]") - fieldname = fieldname:gsub("(%b[])", function(cnt) - fieldcount = tonumber(cnt:sub(2, -2)); - if not fieldcount then - fieldcount = 0 - fieldcountvar = cnt:sub(2, -2) - end - return "" - end) - local fieldrec = { name = fieldname, c_type = fieldtype, array = fieldcount, array_size = fieldcountvar } - if fieldcount then - if fieldtype == "u8" then - -- any array of bytes is treated as a string - elseif vpp.t_lua2c[fieldtype] then - -- print("Array of " .. fieldtype .. " is ok!") - else - print("Unknown array type: ", name, " : " , fieldname, " : ", fieldtype, ":", fieldcount, ":", fieldcountvar) - end - end - fields[fieldname] = fieldrec - end) - - -- print(dump(fields)) - - if typeonly == 0 then - local this_message_number = vpp.next_msg_num - vpp.next_msg_num = vpp.next_msg_num + 1 - vpp.msg_name_to_number[name] = this_message_number - vpp.msg_number_to_name[this_message_number] = name - vpp.msg_number_to_type[this_message_number] = "vl_api_" .. name .. "_t" - vpp.msg_number_to_pointer_type[this_message_number] = vpp.msg_number_to_type[this_message_number] .. " *" - onedef = onedef .. "\n\n enum { vl_msg_" .. name .. " = " .. this_message_number .. " };\n\n" - end - table.insert(ffii, onedef); - return ""; - end) - local cdef = table.concat(ffii) - -- print(cdef) - ffi.cdef(cdef) - end - - -function vpp.lua2c(vpp, c_type, src, dst_c_ptr) - -- returns the number of bytes written to memory pointed by dst - local lua2c = vpp.t_lua2c[c_type] - if lua2c then - return(lua2c(c_type, src, dst_c_ptr)) - else - print("vpp.lua2c: do not know how to store type " .. tostring(c_type)) - local x = "a" .. nil - return 0 - end -end - -function vpp.c2lua(vpp, c_type, src_ptr, src_len) - -- returns the lua data structure - local c2lua = vpp.t_c2lua[c_type] - if c2lua then - return(c2lua(c_type, src_ptr, src_len)) - else - print("vpp.c2lua: do not know how to load type " .. c_type) - return nil - end -end - -local req_store_cache = ffi.new("vl_api_opaque_message_t[1]") - -function vpp.api_write(vpp, api_name, req_table) - local msg_num = vpp.msg_name_to_number[api_name] - if not msg_num then - print ("API call "..api_name.." is not known") - return nil - end - - if not req_table then - req_table = {} - end - req_table._vl_msg_id = msg_num - - local packed_len = vpp:lua2c(vpp.msg_number_to_type[msg_num], req_table, req_store_cache) - if vpp.debug_dump then - print("Write Message length: " .. tostring(packed_len) .. "\n" .. vpp.hex_dump(ffi.string(ffi.cast('void *', req_store_cache), packed_len))) - end - - res = vpp.pneum.pneum_write(ffi.cast('void *', req_store_cache), packed_len) - return res - end - -local rep_store_cache = ffi.new("vl_api_opaque_message_t *[1]") -local rep_len_cache = ffi.new("int[1]") - -function vpp.api_read(vpp) - local rep_type = "vl_api_opaque_message_t" - local rep = rep_store_cache - local replen = rep_len_cache - res = vpp.pneum.pneum_read(ffi.cast("void *", rep), replen) - if vpp.debug_dump then - print("Read Message length: " .. tostring(replen[0]) .. "\n" .. vpp.hex_dump(ffi.string(ffi.cast('void *', rep[0]), replen[0]))) - end - - local reply_msg_num = ffi.C.ntohs(rep[0]._vl_msg_id) - local reply_msg_name = vpp.msg_number_to_name[reply_msg_num] - - local reply_typed_ptr = ffi.cast(vpp.msg_number_to_pointer_type[reply_msg_num], rep[0]) - local out = vpp:c2lua(vpp.msg_number_to_type[reply_msg_num], rep[0], nil, replen[0]) - if type(out) == "table" then - out["luaapi_message_name"] = reply_msg_name - end - - vpp.pneum.pneum_free(ffi.cast('void *',rep[0])) - - return reply_msg_name, out - end - -function vpp.api_call(vpp, api_name, req_table, options_in) - local msg_num = vpp.msg_name_to_number[api_name] - local end_message_name = api_name .."_reply" - local replies = {} - local cstruct = "" - local options = options_in or {} - if msg_num then - if vpp.debug_dump then - print("Message #" .. tostring(msg_num) .. " for name " .. tostring(api_name)) - end - vpp:api_write(api_name, req_table) - if not vpp.msg_name_to_number[end_message_name] or options.force_ping then - end_message_name = "control_ping_reply" - vpp:api_write("control_ping") - end - repeat - reply_message_name, reply = vpp:api_read() - if reply and not reply.context then - -- there may be async events inbetween - table.insert(vpp.events, reply) - else - if reply_message_name ~= "control_ping_reply" then - -- do not insert the control ping encapsulation - table.insert(replies, reply) - end - end - -- print(reply) - until reply_message_name == end_message_name - else - print(api_name .. " is an unknown API call") - return nil - end - return replies - end - -return vpp -- cgit 1.2.3-korg From d995c757f05f78aa759b0a65c0a7e38088e690a9 Mon Sep 17 00:00:00 2001 From: Padraig Connolly Date: Tue, 29 Nov 2016 17:17:20 +0000 Subject: vppctl: bash completion for vppctl commands Added bash completion that will include all commands from build time *Script takes list of commands generated by doxygen-siphon-list *Configured doxygen-siphon makefile to generate just cli commands *List of cli commands put in /usr/share/vpp *Stopped siphon using doxygen bootstrap, uses main bootstrap instead *Added rpm/deb check for installation of packages, separate from bootstrap *NOTE: Once you have installed the vpp .deb/.rpm package you will have to restart bash Change-Id: Ie503e80d5177481f6e7dbe59378f2e0d76f29152 Signed-off-by: Padraig Connolly --- Makefile | 46 ++++++++++++++++++++++++++++++++++++------- build-data/platforms.mk | 8 ++++++++ build-root/Makefile | 3 ++- build-root/rpm/vpp.spec | 6 ++++++ doxygen/Makefile | 25 ++++++++--------------- src/scripts/vppctl_completion | 30 ++++++++++++++++++++++++++++ 6 files changed, 93 insertions(+), 25 deletions(-) create mode 100755 src/scripts/vppctl_completion (limited to 'doxygen/Makefile') diff --git a/Makefile b/Makefile index 6af33b08..7c3dded2 100644 --- a/Makefile +++ b/Makefile @@ -32,8 +32,8 @@ endif DEB_DEPENDS = curl build-essential autoconf automake bison libssl-dev ccache DEB_DEPENDS += debhelper dkms git libtool libganglia1-dev libapr1-dev dh-systemd -DEB_DEPENDS += libconfuse-dev git-review exuberant-ctags cscope pkg-config -DEB_DEPENDS += python-dev python-virtualenv python-pip lcov chrpath autoconf +DEB_DEPENDS += libconfuse-dev git-review exuberant-ctags cscope pkg-config doxygen graphviz +DEB_DEPENDS += python-dev python-virtualenv python-pip python-pyparsing python-jinja2 lcov chrpath autoconf ifeq ($(OS_VERSION_ID),14.04) DEB_DEPENDS += openjdk-8-jdk-headless else @@ -41,9 +41,9 @@ else endif RPM_DEPENDS_GROUPS = 'Development Tools' -RPM_DEPENDS = redhat-lsb glibc-static java-1.8.0-openjdk-devel yum-utils +RPM_DEPENDS = redhat-lsb glibc-static java-1.8.0-openjdk-devel yum-utils doxygen graphviz RPM_DEPENDS += openssl-devel https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm apr-devel -RPM_DEPENDS += python-devel python-virtualenv lcov chrpath +RPM_DEPENDS += python-devel python-virtualenv pyparsing python-jinja2 lcov chrpath EPEL_DEPENDS = libconfuse-devel ganglia-devel ifneq ($(wildcard $(STARTUP_DIR)/startup.conf),) @@ -183,6 +183,35 @@ distversion: $(BR)/scripts/.version $(BR)/scripts/verdist ${BR} ${prefix}-$(shell $(BR)/scripts/version rpm-version) ${verstring} mv $(verstring).tar.gz $(BR)/rpm +deb-depends-check: +ifeq ($(OS_ID),ubuntu) + @MISSING=$$(apt-get install -y -qq -s $(DEB_DEPENDS) | grep "^Inst ") ; \ + if [ -n "$$MISSING" ] ; then \ + echo "\nPlease install missing packages: \n$$MISSING\n" ; \ + echo "by executing \"make install-dep\"\n" ; \ + exit 1 ; \ + fi; \ + exit 0 +endif + +rpm-depends-check: +ifeq ($(OS_ID),centos) + @RPM_DEPENDS_ARRAY=($(RPM_DEPENDS)) ; \ + for i in "$${!RPM_DEPENDS_ARRAY[@]}"; do \ + if ! yum list installed "$${RPM_DEPENDS_ARRAY[$$i]}" >/dev/null 2>&1; then \ + if ! [[ "$${RPM_DEPENDS_ARRAY[$$i]}" == *"://"* ]] ; then \ + MISSING="$$MISSING $${RPM_DEPENDS_ARRAY[$$i]}" ; \ + fi; \ + fi; \ + done; \ + if [ -n "$$MISSING" ] ; then \ + echo "\nPlease install missing packages: \n$$MISSING\n" ; \ + echo "by executing \"make install-dep\"\n" ; \ + exit 1 ; \ + fi; \ + exit 0 +endif + build: $(BR)/.bootstrap.ok $(call make,$(PLATFORM)_debug,vpp-install) @@ -286,10 +315,10 @@ build-vat: run-vat: @sudo $(BR)/install-$(PLATFORM)_debug-native/vpp/bin/vpp_api_test -pkg-deb: +pkg-deb: deb-depends-check doxygen-siphon-list $(call make,$(PLATFORM),install-deb) -pkg-rpm: dist +pkg-rpm: dist rpm-depends-check doxygen-siphon-list $(call make,$(PLATFORM),install-rpm) ctags: ctags.files @@ -321,7 +350,7 @@ endef .PHONY: bootstrap-doxygen doxygen wipe-doxygen -bootstrap-doxygen: +bootstrap-doxygen: deb-depends-check rpm-depends-check $(call make-doxy) doxygen: @@ -330,6 +359,9 @@ doxygen: wipe-doxygen: $(call make-doxy) +doxygen-siphon-list: + $(call make-doxy) + define banner @echo "========================================================================" @echo " $(1)" diff --git a/build-data/platforms.mk b/build-data/platforms.mk index e192155b..111a45dc 100644 --- a/build-data/platforms.mk +++ b/build-data/platforms.mk @@ -73,6 +73,14 @@ install-deb: $(patsubst %,%-find-source,$(ROOT_PACKAGES)) \ : and sysctl config ; \ echo ../../src/vpp/conf/80-vpp.conf /etc/sysctl.d \ + >> deb/debian/vpp.install ; \ + \ + : bash completion for vppctl ; \ + echo ../../src/scripts/vppctl_completion /etc/bash_completion.d \ + >> deb/debian/vpp.install ; \ + \ + : move dictionary of vppctl commands ; \ + echo ../docs/siphon_docs/clicmd.itemlist /usr/share/vpp \ >> deb/debian/vpp.install ; \ \ : dev package needs a couple of additions ; \ diff --git a/build-root/Makefile b/build-root/Makefile index 6e26e90e..9fe03d66 100644 --- a/build-root/Makefile +++ b/build-root/Makefile @@ -1141,7 +1141,8 @@ package_wipe_script = \ @message=$(if $(is_build_tool),"Wiping build $(PACKAGE)","Wiping build/install $(PACKAGE)") ; \ $(call build_msg_fn,$$message) ; \ $(BUILD_ENV) ; \ - rm -rf $(if $(is_build_tool),$(PACKAGE_BUILD_DIR),$(PACKAGE_INSTALL_DIR) $(PACKAGE_BUILD_DIR)) + rm -rf $(if $(is_build_tool),$(PACKAGE_BUILD_DIR),$(PACKAGE_INSTALL_DIR) $(PACKAGE_BUILD_DIR)); \ + rm -f $(MU_BUILD_ROOT_DIR)/docs/siphon_docs/clicmd.itemlist .PHONY: %-wipe %-wipe: diff --git a/build-root/rpm/vpp.spec b/build-root/rpm/vpp.spec index c3c0d927..07ea2c34 100644 --- a/build-root/rpm/vpp.spec +++ b/build-root/rpm/vpp.spec @@ -129,6 +129,8 @@ install -p -m 644 %{_mu_build_dir}/../src/vpp/conf/80-vpp.conf %{buildroot}/etc/ # libraries # mkdir -p -m755 %{buildroot}%{_libdir} +mkdir -p -m755 %{buildroot}/usr/share/vpp +mkdir -p -m755 %{buildroot}/etc/bash_completion.d for file in $(find %{_mu_build_dir}/%{_vpp_install_dir}/*/lib* -type f -name '*.so.*.*.*' -print ) do install -p -m 755 $file %{buildroot}%{_libdir} @@ -145,6 +147,8 @@ for file in $(find %{_mu_build_dir}/%{_vpp_install_dir}/vpp/share/vpp/api -type do install -p -m 644 $file %{buildroot}/usr/share/vpp/api done +install -p -m 644 %{_mu_build_dir}/../src/scripts/vppctl_completion %{buildroot}/etc/bash_completion.d +install -p -m 644 %{_mu_build_dir}/docs/siphon_docs/clicmd.itemlist %{buildroot}/usr/share/vpp # Lua bindings mkdir -p -m755 %{buildroot}/usr/share/doc/vpp/examples/lua/examples/cli @@ -273,6 +277,8 @@ fi %exclude %{_libdir}/vpp_api_test_plugins %{_libdir}/* /usr/share/vpp/api/* +/etc/bash_completion.d/vppctl_completion +/usr/share/vpp/clicmd.itemlist %files api-lua %defattr(644,root,root) diff --git a/doxygen/Makefile b/doxygen/Makefile index face5b44..18086626 100644 --- a/doxygen/Makefile +++ b/doxygen/Makefile @@ -33,8 +33,6 @@ endif OS_ID ?= $(shell grep '^ID=' /etc/os-release | cut -f2- -d= | sed -e 's/\"//g') # Package dependencies -DOC_DEB_DEPENDS = doxygen graphviz python-pyparsing python-jinja2 -DOC_RPM_DEPENDS = doxygen graphviz pyparsing python-jinja2 DOC_MAC_BIN_DEPENDS = doxygen dot git DOC_MAC_PY_DEPENDS = pyparsing jinja2 @@ -129,22 +127,11 @@ SIPHON_DOCS = $(addprefix $(SIPHON_OUTPUT)/,$(addsuffix .md,$(SIPHONS))) SIPHON_ITEMLIST = $(addprefix $(SIPHON_OUTPUT)/,$(addsuffix .itemlist,$(filter clicmd,$(SIPHONS)))) $(BR)/.doxygen-bootstrap.ok: Makefile - @echo "Checking whether dependencies for Doxygen are installed..." ifeq ($(OS_ID),ubuntu) - @set -e; inst=; \ - for i in $(DOC_DEB_DEPENDS); do \ - dpkg-query --show $$i >/dev/null 2>&1 || inst="$$inst $$i"; \ - done; \ - if [ "$$inst" ]; then \ - sudo apt-get update; \ - sudo apt-get $(CONFIRM) $(FORCE) install $$inst; \ - fi @if [ ! -s /usr/lib/graphviz/config6a ]; then \ - echo "Rebuidlding system Graphviz configuration."; \ + echo "Rebuilding system Graphviz configuration."; \ sudo dot -c; \ fi -else ifneq ("$(wildcard /etc/redhat-release)","") - @sudo yum install $(CONFIRM) $(DOC_RPM_DEPENDS) else ifeq ($(OS_ID),darwin) @set -e; \ for bin in $(DOC_MAC_BIN_DEPENDS); do \ @@ -187,8 +174,7 @@ $(BR)/.doxygen-siphon.dep: Makefile \ # Generate .siphon files that contain fragments of source file that # relate to the siphons we support. .NOTPARALLEL: $(SIPHON_FILES) -$(SIPHON_FILES): $(BR)/.doxygen-bootstrap.ok \ - $(DOXY_DIR)/siphon-generate \ +$(SIPHON_FILES):$(DOXY_DIR)/siphon-generate \ $(addprefix,$(WSROOT),$(DOXY_INPUT)) \ $(wildcard $(DOXY_DIR)/siphon/*.py) @echo "Validating source tree..." @@ -246,7 +232,12 @@ $(eval $(call siphon-process,itemlist,itemlist)) # This target can be used just to generate the siphoned things .PHONY: doxygen-siphon -doxygen-siphon: $(SIPHON_DOCS) $(SIPHON_ITEMLIST) +doxygen-siphon: $(SIPHON_DOCS) + +# This target is used generate list of cli commands for use with +# the bash completion element for vppctl +.PHONY: doxygen-siphon-list +doxygen-siphon-list: $(SIPHON_ITEMLIST) # Generate the doxygen docs .PHONY: doxygen diff --git a/src/scripts/vppctl_completion b/src/scripts/vppctl_completion new file mode 100755 index 00000000..7e60249f --- /dev/null +++ b/src/scripts/vppctl_completion @@ -0,0 +1,30 @@ +#Copyright 2016 Intel Corporation +# +#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. + +_vppctl() +{ + local cur prev num opts + COMPREPLY=( $(compgen -f ${cur}) ) + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[@]:1}" + num="$((${#COMP_WORDS[@]}-1))" + + VPP_CMD_LIST="$(cat /usr/share/vpp/clicmd.itemlist)" + + opts="$(awk -v prev="^$prev" -v num=$num '{if($0 ~ prev) print $num}' <<< "${VPP_CMD_LIST}")" + + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + +} +complete -F _vppctl vppctl -- cgit 1.2.3-korg From 6bbf83a01b813b3d50b27ab9001d25cae5c4592a Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Tue, 10 Jan 2017 10:39:21 +0100 Subject: Revert "vppctl: bash completion for vppctl commands" This patch is causing build failures This reverts commit d995c757f05f78aa759b0a65c0a7e38088e690a9. Change-Id: I0c8d5a4208135d77aaa3a6a470d26140f7b74733 Signed-off-by: Damjan Marion --- Makefile | 46 +++++++------------------------------------ build-data/platforms.mk | 8 -------- build-root/Makefile | 3 +-- build-root/rpm/vpp.spec | 6 ------ doxygen/Makefile | 25 +++++++++++++++-------- src/scripts/vppctl_completion | 30 ---------------------------- 6 files changed, 25 insertions(+), 93 deletions(-) delete mode 100755 src/scripts/vppctl_completion (limited to 'doxygen/Makefile') diff --git a/Makefile b/Makefile index 7c3dded2..6af33b08 100644 --- a/Makefile +++ b/Makefile @@ -32,8 +32,8 @@ endif DEB_DEPENDS = curl build-essential autoconf automake bison libssl-dev ccache DEB_DEPENDS += debhelper dkms git libtool libganglia1-dev libapr1-dev dh-systemd -DEB_DEPENDS += libconfuse-dev git-review exuberant-ctags cscope pkg-config doxygen graphviz -DEB_DEPENDS += python-dev python-virtualenv python-pip python-pyparsing python-jinja2 lcov chrpath autoconf +DEB_DEPENDS += libconfuse-dev git-review exuberant-ctags cscope pkg-config +DEB_DEPENDS += python-dev python-virtualenv python-pip lcov chrpath autoconf ifeq ($(OS_VERSION_ID),14.04) DEB_DEPENDS += openjdk-8-jdk-headless else @@ -41,9 +41,9 @@ else endif RPM_DEPENDS_GROUPS = 'Development Tools' -RPM_DEPENDS = redhat-lsb glibc-static java-1.8.0-openjdk-devel yum-utils doxygen graphviz +RPM_DEPENDS = redhat-lsb glibc-static java-1.8.0-openjdk-devel yum-utils RPM_DEPENDS += openssl-devel https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm apr-devel -RPM_DEPENDS += python-devel python-virtualenv pyparsing python-jinja2 lcov chrpath +RPM_DEPENDS += python-devel python-virtualenv lcov chrpath EPEL_DEPENDS = libconfuse-devel ganglia-devel ifneq ($(wildcard $(STARTUP_DIR)/startup.conf),) @@ -183,35 +183,6 @@ distversion: $(BR)/scripts/.version $(BR)/scripts/verdist ${BR} ${prefix}-$(shell $(BR)/scripts/version rpm-version) ${verstring} mv $(verstring).tar.gz $(BR)/rpm -deb-depends-check: -ifeq ($(OS_ID),ubuntu) - @MISSING=$$(apt-get install -y -qq -s $(DEB_DEPENDS) | grep "^Inst ") ; \ - if [ -n "$$MISSING" ] ; then \ - echo "\nPlease install missing packages: \n$$MISSING\n" ; \ - echo "by executing \"make install-dep\"\n" ; \ - exit 1 ; \ - fi; \ - exit 0 -endif - -rpm-depends-check: -ifeq ($(OS_ID),centos) - @RPM_DEPENDS_ARRAY=($(RPM_DEPENDS)) ; \ - for i in "$${!RPM_DEPENDS_ARRAY[@]}"; do \ - if ! yum list installed "$${RPM_DEPENDS_ARRAY[$$i]}" >/dev/null 2>&1; then \ - if ! [[ "$${RPM_DEPENDS_ARRAY[$$i]}" == *"://"* ]] ; then \ - MISSING="$$MISSING $${RPM_DEPENDS_ARRAY[$$i]}" ; \ - fi; \ - fi; \ - done; \ - if [ -n "$$MISSING" ] ; then \ - echo "\nPlease install missing packages: \n$$MISSING\n" ; \ - echo "by executing \"make install-dep\"\n" ; \ - exit 1 ; \ - fi; \ - exit 0 -endif - build: $(BR)/.bootstrap.ok $(call make,$(PLATFORM)_debug,vpp-install) @@ -315,10 +286,10 @@ build-vat: run-vat: @sudo $(BR)/install-$(PLATFORM)_debug-native/vpp/bin/vpp_api_test -pkg-deb: deb-depends-check doxygen-siphon-list +pkg-deb: $(call make,$(PLATFORM),install-deb) -pkg-rpm: dist rpm-depends-check doxygen-siphon-list +pkg-rpm: dist $(call make,$(PLATFORM),install-rpm) ctags: ctags.files @@ -350,7 +321,7 @@ endef .PHONY: bootstrap-doxygen doxygen wipe-doxygen -bootstrap-doxygen: deb-depends-check rpm-depends-check +bootstrap-doxygen: $(call make-doxy) doxygen: @@ -359,9 +330,6 @@ doxygen: wipe-doxygen: $(call make-doxy) -doxygen-siphon-list: - $(call make-doxy) - define banner @echo "========================================================================" @echo " $(1)" diff --git a/build-data/platforms.mk b/build-data/platforms.mk index 111a45dc..e192155b 100644 --- a/build-data/platforms.mk +++ b/build-data/platforms.mk @@ -73,14 +73,6 @@ install-deb: $(patsubst %,%-find-source,$(ROOT_PACKAGES)) \ : and sysctl config ; \ echo ../../src/vpp/conf/80-vpp.conf /etc/sysctl.d \ - >> deb/debian/vpp.install ; \ - \ - : bash completion for vppctl ; \ - echo ../../src/scripts/vppctl_completion /etc/bash_completion.d \ - >> deb/debian/vpp.install ; \ - \ - : move dictionary of vppctl commands ; \ - echo ../docs/siphon_docs/clicmd.itemlist /usr/share/vpp \ >> deb/debian/vpp.install ; \ \ : dev package needs a couple of additions ; \ diff --git a/build-root/Makefile b/build-root/Makefile index 9fe03d66..6e26e90e 100644 --- a/build-root/Makefile +++ b/build-root/Makefile @@ -1141,8 +1141,7 @@ package_wipe_script = \ @message=$(if $(is_build_tool),"Wiping build $(PACKAGE)","Wiping build/install $(PACKAGE)") ; \ $(call build_msg_fn,$$message) ; \ $(BUILD_ENV) ; \ - rm -rf $(if $(is_build_tool),$(PACKAGE_BUILD_DIR),$(PACKAGE_INSTALL_DIR) $(PACKAGE_BUILD_DIR)); \ - rm -f $(MU_BUILD_ROOT_DIR)/docs/siphon_docs/clicmd.itemlist + rm -rf $(if $(is_build_tool),$(PACKAGE_BUILD_DIR),$(PACKAGE_INSTALL_DIR) $(PACKAGE_BUILD_DIR)) .PHONY: %-wipe %-wipe: diff --git a/build-root/rpm/vpp.spec b/build-root/rpm/vpp.spec index 07ea2c34..c3c0d927 100644 --- a/build-root/rpm/vpp.spec +++ b/build-root/rpm/vpp.spec @@ -129,8 +129,6 @@ install -p -m 644 %{_mu_build_dir}/../src/vpp/conf/80-vpp.conf %{buildroot}/etc/ # libraries # mkdir -p -m755 %{buildroot}%{_libdir} -mkdir -p -m755 %{buildroot}/usr/share/vpp -mkdir -p -m755 %{buildroot}/etc/bash_completion.d for file in $(find %{_mu_build_dir}/%{_vpp_install_dir}/*/lib* -type f -name '*.so.*.*.*' -print ) do install -p -m 755 $file %{buildroot}%{_libdir} @@ -147,8 +145,6 @@ for file in $(find %{_mu_build_dir}/%{_vpp_install_dir}/vpp/share/vpp/api -type do install -p -m 644 $file %{buildroot}/usr/share/vpp/api done -install -p -m 644 %{_mu_build_dir}/../src/scripts/vppctl_completion %{buildroot}/etc/bash_completion.d -install -p -m 644 %{_mu_build_dir}/docs/siphon_docs/clicmd.itemlist %{buildroot}/usr/share/vpp # Lua bindings mkdir -p -m755 %{buildroot}/usr/share/doc/vpp/examples/lua/examples/cli @@ -277,8 +273,6 @@ fi %exclude %{_libdir}/vpp_api_test_plugins %{_libdir}/* /usr/share/vpp/api/* -/etc/bash_completion.d/vppctl_completion -/usr/share/vpp/clicmd.itemlist %files api-lua %defattr(644,root,root) diff --git a/doxygen/Makefile b/doxygen/Makefile index 18086626..face5b44 100644 --- a/doxygen/Makefile +++ b/doxygen/Makefile @@ -33,6 +33,8 @@ endif OS_ID ?= $(shell grep '^ID=' /etc/os-release | cut -f2- -d= | sed -e 's/\"//g') # Package dependencies +DOC_DEB_DEPENDS = doxygen graphviz python-pyparsing python-jinja2 +DOC_RPM_DEPENDS = doxygen graphviz pyparsing python-jinja2 DOC_MAC_BIN_DEPENDS = doxygen dot git DOC_MAC_PY_DEPENDS = pyparsing jinja2 @@ -127,11 +129,22 @@ SIPHON_DOCS = $(addprefix $(SIPHON_OUTPUT)/,$(addsuffix .md,$(SIPHONS))) SIPHON_ITEMLIST = $(addprefix $(SIPHON_OUTPUT)/,$(addsuffix .itemlist,$(filter clicmd,$(SIPHONS)))) $(BR)/.doxygen-bootstrap.ok: Makefile + @echo "Checking whether dependencies for Doxygen are installed..." ifeq ($(OS_ID),ubuntu) + @set -e; inst=; \ + for i in $(DOC_DEB_DEPENDS); do \ + dpkg-query --show $$i >/dev/null 2>&1 || inst="$$inst $$i"; \ + done; \ + if [ "$$inst" ]; then \ + sudo apt-get update; \ + sudo apt-get $(CONFIRM) $(FORCE) install $$inst; \ + fi @if [ ! -s /usr/lib/graphviz/config6a ]; then \ - echo "Rebuilding system Graphviz configuration."; \ + echo "Rebuidlding system Graphviz configuration."; \ sudo dot -c; \ fi +else ifneq ("$(wildcard /etc/redhat-release)","") + @sudo yum install $(CONFIRM) $(DOC_RPM_DEPENDS) else ifeq ($(OS_ID),darwin) @set -e; \ for bin in $(DOC_MAC_BIN_DEPENDS); do \ @@ -174,7 +187,8 @@ $(BR)/.doxygen-siphon.dep: Makefile \ # Generate .siphon files that contain fragments of source file that # relate to the siphons we support. .NOTPARALLEL: $(SIPHON_FILES) -$(SIPHON_FILES):$(DOXY_DIR)/siphon-generate \ +$(SIPHON_FILES): $(BR)/.doxygen-bootstrap.ok \ + $(DOXY_DIR)/siphon-generate \ $(addprefix,$(WSROOT),$(DOXY_INPUT)) \ $(wildcard $(DOXY_DIR)/siphon/*.py) @echo "Validating source tree..." @@ -232,12 +246,7 @@ $(eval $(call siphon-process,itemlist,itemlist)) # This target can be used just to generate the siphoned things .PHONY: doxygen-siphon -doxygen-siphon: $(SIPHON_DOCS) - -# This target is used generate list of cli commands for use with -# the bash completion element for vppctl -.PHONY: doxygen-siphon-list -doxygen-siphon-list: $(SIPHON_ITEMLIST) +doxygen-siphon: $(SIPHON_DOCS) $(SIPHON_ITEMLIST) # Generate the doxygen docs .PHONY: doxygen diff --git a/src/scripts/vppctl_completion b/src/scripts/vppctl_completion deleted file mode 100755 index 7e60249f..00000000 --- a/src/scripts/vppctl_completion +++ /dev/null @@ -1,30 +0,0 @@ -#Copyright 2016 Intel Corporation -# -#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. - -_vppctl() -{ - local cur prev num opts - COMPREPLY=( $(compgen -f ${cur}) ) - cur="${COMP_WORDS[COMP_CWORD]}" - prev="${COMP_WORDS[@]:1}" - num="$((${#COMP_WORDS[@]}-1))" - - VPP_CMD_LIST="$(cat /usr/share/vpp/clicmd.itemlist)" - - opts="$(awk -v prev="^$prev" -v num=$num '{if($0 ~ prev) print $num}' <<< "${VPP_CMD_LIST}")" - - COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) - -} -complete -F _vppctl vppctl -- cgit 1.2.3-korg From 1c5ee872b14c5e9412b8c0e4f169b85d11238d14 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Tue, 10 Jan 2017 17:07:38 +0100 Subject: Remove vcgn plugin Change-Id: I79f18ec386dedd91a8dcea2ca5726208b7b3c67c Signed-off-by: Damjan Marion --- doxygen/Makefile | 3 +- plugins/Makefile.am | 34 - plugins/configure.ac | 60 - plugins/vcgn-plugin/Makefile.am | 97 - plugins/vcgn-plugin/configure.ac | 9 - plugins/vcgn-plugin/vcgn/README | 100 - plugins/vcgn-plugin/vcgn/cgn_bitmap.h | 133 - plugins/vcgn-plugin/vcgn/cgse_defs.h | 88 - plugins/vcgn-plugin/vcgn/cnat_bulk_port.c | 964 ----- plugins/vcgn-plugin/vcgn/cnat_bulk_port.h | 157 - plugins/vcgn-plugin/vcgn/cnat_bulk_port_defs.h | 57 - plugins/vcgn-plugin/vcgn/cnat_cli.h | 206 -- plugins/vcgn-plugin/vcgn/cnat_cli_handler.c | 961 ----- plugins/vcgn-plugin/vcgn/cnat_common_api.h | 22 - plugins/vcgn-plugin/vcgn/cnat_config.c | 77 - plugins/vcgn-plugin/vcgn/cnat_config.h | 582 --- plugins/vcgn-plugin/vcgn/cnat_config_api.h | 46 - plugins/vcgn-plugin/vcgn/cnat_db.h | 701 ---- plugins/vcgn-plugin/vcgn/cnat_db_scanner.c | 493 --- plugins/vcgn-plugin/vcgn/cnat_db_v2.c | 3806 -------------------- plugins/vcgn-plugin/vcgn/cnat_debug_msg_handler.c | 1780 --------- plugins/vcgn-plugin/vcgn/cnat_global.c | 79 - plugins/vcgn-plugin/vcgn/cnat_global.h | 87 - plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp.h | 60 - .../vcgn/cnat_ipv4_icmp_error_inside_input.c | 476 --- .../vcgn/cnat_ipv4_icmp_error_outside_input.c | 452 --- .../vcgn/cnat_ipv4_icmp_query_inside_input.c | 404 --- .../cnat_ipv4_icmp_query_inside_input_exception.c | 235 -- .../vcgn/cnat_ipv4_icmp_query_outside_input.c | 381 -- .../vcgn-plugin/vcgn/cnat_ipv4_tcp_inside_input.c | 424 --- .../vcgn/cnat_ipv4_tcp_inside_input_exceptions.c | 314 -- .../vcgn-plugin/vcgn/cnat_ipv4_tcp_outside_input.c | 382 -- plugins/vcgn-plugin/vcgn/cnat_ipv4_udp.h | 41 - .../vcgn-plugin/vcgn/cnat_ipv4_udp_inside_input.c | 508 --- .../vcgn/cnat_ipv4_udp_inside_input_exceptions.c | 283 -- .../vcgn-plugin/vcgn/cnat_ipv4_udp_outside_input.c | 605 ---- plugins/vcgn-plugin/vcgn/cnat_log_api.h | 114 - plugins/vcgn-plugin/vcgn/cnat_log_common.h | 79 - plugins/vcgn-plugin/vcgn/cnat_logging.c | 3500 ------------------ plugins/vcgn-plugin/vcgn/cnat_logging.h | 1091 ------ plugins/vcgn-plugin/vcgn/cnat_pcp_server.h | 398 -- plugins/vcgn-plugin/vcgn/cnat_ports.c | 1113 ------ plugins/vcgn-plugin/vcgn/cnat_ports.h | 208 -- plugins/vcgn-plugin/vcgn/cnat_show.c | 810 ----- plugins/vcgn-plugin/vcgn/cnat_show_api.h | 40 - plugins/vcgn-plugin/vcgn/cnat_show_response.h | 580 --- plugins/vcgn-plugin/vcgn/cnat_syslog.c | 1787 --------- plugins/vcgn-plugin/vcgn/cnat_syslog.h | 190 - plugins/vcgn-plugin/vcgn/cnat_util.c | 2256 ------------ plugins/vcgn-plugin/vcgn/cnat_v4_ftp_alg.h | 133 - plugins/vcgn-plugin/vcgn/cnat_v4_functions.c | 364 -- plugins/vcgn-plugin/vcgn/cnat_v4_functions.h | 342 -- plugins/vcgn-plugin/vcgn/cnat_v4_pptp_alg.h | 150 - .../vcgn-plugin/vcgn/cnat_v4_tcp_in2out_stages.c | 679 ---- plugins/vcgn-plugin/vcgn/cnat_va_db.c | 286 -- plugins/vcgn-plugin/vcgn/cnat_va_db.h | 121 - plugins/vcgn-plugin/vcgn/dslite_db.h | 170 - plugins/vcgn-plugin/vcgn/dslite_defs.h | 336 -- plugins/vcgn-plugin/vcgn/index_list.c | 336 -- plugins/vcgn-plugin/vcgn/index_list.h | 118 - plugins/vcgn-plugin/vcgn/nat64_db.h | 480 --- plugins/vcgn-plugin/vcgn/nat64_defs.h | 576 --- plugins/vcgn-plugin/vcgn/nat64_tcp_sm.h | 91 - plugins/vcgn-plugin/vcgn/platform_common.h | 136 - .../vcgn-plugin/vcgn/platform_common_override.h | 304 -- plugins/vcgn-plugin/vcgn/spp_ctx.h | 76 - plugins/vcgn-plugin/vcgn/spp_platform_trace_log.c | 989 ----- plugins/vcgn-plugin/vcgn/spp_platform_trace_log.h | 358 -- plugins/vcgn-plugin/vcgn/spp_timers.h | 139 - plugins/vcgn-plugin/vcgn/tcp_header_definitions.h | 1582 -------- plugins/vcgn-plugin/vcgn/vcgn_classify.c | 1508 -------- plugins/vcgn-plugin/vcgn/vcgn_db.h | 117 - src/vnet/buffer.h | 66 - 73 files changed, 1 insertion(+), 36729 deletions(-) delete mode 100644 plugins/Makefile.am delete mode 100644 plugins/configure.ac delete mode 100644 plugins/vcgn-plugin/Makefile.am delete mode 100644 plugins/vcgn-plugin/configure.ac delete mode 100644 plugins/vcgn-plugin/vcgn/README delete mode 100644 plugins/vcgn-plugin/vcgn/cgn_bitmap.h delete mode 100644 plugins/vcgn-plugin/vcgn/cgse_defs.h delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_bulk_port.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_bulk_port.h delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_bulk_port_defs.h delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_cli.h delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_cli_handler.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_common_api.h delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_config.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_config.h delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_config_api.h delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_db.h delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_db_scanner.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_db_v2.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_debug_msg_handler.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_global.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_global.h delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp.h delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_error_inside_input.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_error_outside_input.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_inside_input.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_inside_input_exception.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_outside_input.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_inside_input.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_inside_input_exceptions.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_outside_input.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_ipv4_udp.h delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_inside_input.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_inside_input_exceptions.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_outside_input.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_log_api.h delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_log_common.h delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_logging.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_logging.h delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_pcp_server.h delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_ports.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_ports.h delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_show.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_show_api.h delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_show_response.h delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_syslog.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_syslog.h delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_util.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_v4_ftp_alg.h delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_v4_functions.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_v4_functions.h delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_v4_pptp_alg.h delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_v4_tcp_in2out_stages.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_va_db.c delete mode 100644 plugins/vcgn-plugin/vcgn/cnat_va_db.h delete mode 100644 plugins/vcgn-plugin/vcgn/dslite_db.h delete mode 100644 plugins/vcgn-plugin/vcgn/dslite_defs.h delete mode 100644 plugins/vcgn-plugin/vcgn/index_list.c delete mode 100644 plugins/vcgn-plugin/vcgn/index_list.h delete mode 100644 plugins/vcgn-plugin/vcgn/nat64_db.h delete mode 100644 plugins/vcgn-plugin/vcgn/nat64_defs.h delete mode 100644 plugins/vcgn-plugin/vcgn/nat64_tcp_sm.h delete mode 100644 plugins/vcgn-plugin/vcgn/platform_common.h delete mode 100644 plugins/vcgn-plugin/vcgn/platform_common_override.h delete mode 100644 plugins/vcgn-plugin/vcgn/spp_ctx.h delete mode 100644 plugins/vcgn-plugin/vcgn/spp_platform_trace_log.c delete mode 100644 plugins/vcgn-plugin/vcgn/spp_platform_trace_log.h delete mode 100644 plugins/vcgn-plugin/vcgn/spp_timers.h delete mode 100644 plugins/vcgn-plugin/vcgn/tcp_header_definitions.h delete mode 100644 plugins/vcgn-plugin/vcgn/vcgn_classify.c delete mode 100644 plugins/vcgn-plugin/vcgn/vcgn_db.h (limited to 'doxygen/Makefile') diff --git a/doxygen/Makefile b/doxygen/Makefile index face5b44..640acc26 100644 --- a/doxygen/Makefile +++ b/doxygen/Makefile @@ -59,8 +59,7 @@ DOXY_INPUT ?= \ $(wildcard $(WS_ROOT)/*.md) \ $(wildcard $(DOXY_DIR)/*.md) \ $(DOXY_SRC_DIRECTORIES) \ - $(DOXY_SRC)/plugins \ - plugins + $(DOXY_SRC)/plugins # Strip leading workspace path from input names DOXY_INPUT := $(subst $(WS_ROOT)/,,$(DOXY_INPUT)) diff --git a/plugins/Makefile.am b/plugins/Makefile.am deleted file mode 100644 index 20676fc8..00000000 --- a/plugins/Makefile.am +++ /dev/null @@ -1,34 +0,0 @@ -# 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. - -AUTOMAKE_OPTIONS = foreign subdir-objects - -# To add a new plugin subdirectory: -# -# add a stanza here: -# if ENABLE_new_PLUGIN -# SUBDIRS += new-plugin -# endif -# -# Also: add PLUGIN(new) to configure.ac - -SUBDIRS = - -if ENABLE_sample_PLUGIN -SUBDIRS += sample-plugin -endif - -if ENABLE_vcgn_PLUGIN -SUBDIRS += vcgn-plugin -endif - diff --git a/plugins/configure.ac b/plugins/configure.ac deleted file mode 100644 index b6ba4152..00000000 --- a/plugins/configure.ac +++ /dev/null @@ -1,60 +0,0 @@ -AC_INIT(core_plugins, 1.0) -LT_INIT -AM_INIT_AUTOMAKE -AM_SILENT_RULES([yes]) - -AC_PROG_CC - -AC_ARG_ENABLE(tests, - AC_HELP_STRING([--enable-tests], [Build unit tests]), - [enable_tests=1], - [enable_tests=0]) - -AC_ARG_WITH(dpdk, - AC_HELP_STRING([--with-dpdk],[Use DPDK]), - [with_dpdk=1], - [with_dpdk=0]) - -AM_CONDITIONAL(ENABLE_TESTS, test "$enable_tests" = "1") - -AM_CONDITIONAL(WITH_DPDK, test "$with_dpdk" = "1") -AC_SUBST(DPDK,["-DDPDK=${with_dpdk}"]) - -AC_DEFUN([PLUGIN_ENABLED], -[ - AC_ARG_ENABLE($1_plugin, - AC_HELP_STRING([--disable-$1-plugin], [Do not build $1 plugin]), - [enable_the_plugin=0], - [enable_the_plugin=1]) -if test "x$enable_the_plugin" = x1; then - AC_CONFIG_SUBDIRS($1-plugin) -fi -AM_CONDITIONAL(ENABLE_$1_PLUGIN, test "$enable_the_plugin" = "1") -]) - -AC_DEFUN([PLUGIN_DISABLED], -[ - AC_ARG_ENABLE($1_plugin, - AC_HELP_STRING([--enable-$1-plugin], [Build $1 plugin]), - [enable_the_plugin=1], - [enable_the_plugin=0]) -if test "x$enable_the_plugin" = x1; then - AC_CONFIG_SUBDIRS($1-plugin) -fi -AM_CONDITIONAL(ENABLE_$1_PLUGIN, test "$enable_the_plugin" = "1") -]) - -# To add a new plugin subdirectory: -# -# add PLUGIN(new) below, and -# add the following to Makefile.am: -# -# if ENABLE_new_PLUGIN -# SUBDIRS += new-plugin -# endif - -# Disabled plugins, require --enable-XXX-plugin -PLUGIN_DISABLED(vcgn) -PLUGIN_DISABLED(sample) - -AC_OUTPUT([Makefile]) diff --git a/plugins/vcgn-plugin/Makefile.am b/plugins/vcgn-plugin/Makefile.am deleted file mode 100644 index 927f35b6..00000000 --- a/plugins/vcgn-plugin/Makefile.am +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright (c) 2015 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -AUTOMAKE_OPTIONS = foreign subdir-objects - -AM_CFLAGS = -Wall -AM_LDFLAGS = -module -shared -avoid-version - -######################################## -# Virtual Carrier Grade NAT -######################################## - -libvcgn_plugin_la_SOURCES = \ - vcgn/cnat_bulk_port.c \ - vcgn/cnat_config.c \ - vcgn/cnat_db_scanner.c \ - vcgn/cnat_db_v2.c \ - vcgn/cnat_debug_msg_handler.c \ - vcgn/cnat_cli_handler.c \ - vcgn/cnat_global.c \ - vcgn/cnat_ipv4_udp_inside_input.c \ - vcgn/cnat_ipv4_udp_inside_input_exceptions.c \ - vcgn/cnat_ipv4_udp_outside_input.c \ - vcgn/cnat_ipv4_tcp_inside_input.c \ - vcgn/cnat_ipv4_tcp_inside_input_exceptions.c \ - vcgn/cnat_ipv4_tcp_outside_input.c \ - vcgn/cnat_ipv4_icmp_query_inside_input.c \ - vcgn/cnat_ipv4_icmp_query_inside_input_exception.c \ - vcgn/cnat_ipv4_icmp_query_outside_input.c \ - vcgn/cnat_ipv4_icmp_error_inside_input.c \ - vcgn/cnat_ipv4_icmp_error_outside_input.c \ - vcgn/cnat_logging.c \ - vcgn/cnat_ports.c \ - vcgn/cnat_util.c \ - vcgn/cnat_show.c \ - vcgn/cnat_syslog.c \ - vcgn/cnat_v4_functions.c \ - vcgn/index_list.c \ - vcgn/spp_platform_trace_log.c \ - vcgn/vcgn_classify.c - -nobase_include_HEADERS = \ - vcgn/cgn_bitmap.h \ - vcgn/cgse_defs.h \ - vcgn/cnat_bulk_port_defs.h \ - vcgn/cnat_bulk_port.h \ - vcgn/cnat_cli.h \ - vcgn/cnat_common_api.h \ - vcgn/cnat_config_api.h \ - vcgn/cnat_config.h \ - vcgn/cnat_db.h \ - vcgn/cnat_global.h \ - vcgn/cnat_ipv4_icmp.h \ - vcgn/cnat_ipv4_udp.h \ - vcgn/cnat_log_api.h \ - vcgn/cnat_log_common.h \ - vcgn/cnat_logging.h \ - vcgn/cnat_pcp_server.h \ - vcgn/cnat_ports.h \ - vcgn/cnat_show_api.h \ - vcgn/cnat_show_response.h \ - vcgn/cnat_syslog.h \ - vcgn/cnat_v4_ftp_alg.h \ - vcgn/cnat_v4_functions.h \ - vcgn/cnat_v4_pptp_alg.h \ - vcgn/cnat_va_db.h \ - vcgn/dslite_db.h \ - vcgn/dslite_defs.h \ - vcgn/index_list.h \ - vcgn/nat64_db.h \ - vcgn/nat64_defs.h \ - vcgn/nat64_tcp_sm.h \ - vcgn/platform_common.h \ - vcgn/platform_common_override.h \ - vcgn/spp_ctx.h \ - vcgn/spp_platform_trace_log.h \ - vcgn/spp_timers.h \ - vcgn/tcp_header_definitions.h \ - vcgn/vcgn_db.h - -vpppluginsdir = ${libdir}/vpp_plugins - -vppplugins_LTLIBRARIES = libvcgn_plugin.la - -# Remove *.la files -install-data-hook: - @(cd $(vpppluginsdir) && $(RM) $(vppplugins_LTLIBRARIES)) diff --git a/plugins/vcgn-plugin/configure.ac b/plugins/vcgn-plugin/configure.ac deleted file mode 100644 index f9c365af..00000000 --- a/plugins/vcgn-plugin/configure.ac +++ /dev/null @@ -1,9 +0,0 @@ -AC_INIT(vcgn_plugin, 1.0) -LT_INIT -AM_INIT_AUTOMAKE -AM_SILENT_RULES([yes]) -AC_PREFIX_DEFAULT([/usr]) - -AC_PROG_CC - -AC_OUTPUT([Makefile]) diff --git a/plugins/vcgn-plugin/vcgn/README b/plugins/vcgn-plugin/vcgn/README deleted file mode 100644 index 9b903967..00000000 --- a/plugins/vcgn-plugin/vcgn/README +++ /dev/null @@ -1,100 +0,0 @@ - ================================= - CARRIER GRADE NAT - NAT44 README - ================================= - -What is implemented: -==================== -* NAT44 UDP, TCP, ICMP protocols -* Show and config commands for various parameters for the same -* NF9 logging is implemented but is not tested - -What is not implemented: -========================= -* TCP MSS -* TCP refresh direction -* Static port forwarding -* Syslog support -* Destination based logging or session logging -* None of the ALGs -* Performance optimization -* Binary APIs, suitable for configuring the feature from netconf/restconf/yang -* Support for VLANs - -Setup -===== - - +--------------+ -+------------+ GEb/0/0 | | -| Tester +-------------->+ vCGN/vPE-f | -| +<--------------+ VM in UCS | -+------------+ GE13/0/0 | | - +--------------+ - -Configure Interfaces and add routes in vPE-f -============================================= -set int ip address GigabitEthernetb/0/0 10.4.5.2/24 -set int state GigabitEthernetb/0/0 up -set int ip address GigabitEthernet13/0/0 20.4.5.2/24 -set int state GigabitEthernet13/0/0 up -ip route add 4.4.4.0/24 via GigabitEthernet13/0/0 -ip route add 1.2.3.0/24 via GigabitEthernetb/0/0 show ip fib - -Configure vCGN NAT44 for UDP/TCP/ICMP -======================================= -set vcgn inside GigabitEthernetb/0/0 outside GigabitEthernet13/0/0 -set vcgn port limit 65535 set vcgn dynamic port start 5641 -set vcgn map 10.1.1.0 - 10.1.1.31 set vcgn tcp timeout active 65535 init 65535 -set vcgn udp timeout active 65535 init 65535 set vcgn icmp timeout 65535 - -Set ARP entries for CGN to Tester -================================== -set ip arp GigabitEthernet13/0/0 4.4.4.4 11:22:33:44:55:00 -set ip arp GigabitEthernetb/0/0 1.2.3.0 11:22:33:44:55:10 -set ip arp GigabitEthernetb/0/0 1.2.3.1 11:22:33:44:55:12 -set ip arp GigabitEthernetb/0/0 1.2.3.2 11:22:33:44:55:13 -set ip arp GigabitEthernetb/0/0 1.2.3.3 11:22:33:44:55:14 -set ip arp GigabitEthernetb/0/0 1.2.3.4 11:22:33:4e:55:11 -set ip arp GigabitEthernetb/0/0 1.2.3.5 11:22:33:44:55:15 -set ip arp GigabitEthernetb/0/0 1.2.3.6 11:22:33:44:55:16 -set ip arp GigabitEthernetb/0/0 1.2.3.7 11:22:33:44:55:17 -set ip arp GigabitEthernetb/0/0 1.2.3.8 11:22:33:44:55:18 -set ip arp GigabitEthernetb/0/0 1.2.3.9 11:22:33:44:55:19 -set ip arp GigabitEthernetb/0/0 1.2.3.10 11:22:33:44:55:1a -set ip arp GigabitEthernetb/0/0 1.2.3.11 11:22:33:44:55:1b -set ip arp GigabitEthernetb/0/0 1.2.3.12 11:22:33:44:55:1c -set ip arp GigabitEthernetb/0/0 1.2.3.13 11:22:33:44:55:1d -set ip arp GigabitEthernetb/0/0 1.2.3.14 11:22:33:44:55:1e -set ip arp GigabitEthernetb/0/0 1.2.3.15 11:22:33:44:55:1f -set ip arp GigabitEthernetb/0/0 1.2.3.16 11:22:33:44:50:01 -set ip arp GigabitEthernetb/0/0 1.2.3.17 11:22:33:44:51:01 -set ip arp GigabitEthernetb/0/0 1.2.3.18 11:22:33:44:52:01 -set ip arp GigabitEthernetb/0/0 1.2.3.19 11:22:33:44:53:01 -set ip arp GigabitEthernetb/0/0 1.2.3.20 11:22:33:44:54:02 -set ip arp GigabitEthernetb/0/0 1.2.3.21 11:22:33:44:55:01 -set ip arp GigabitEthernetb/0/0 1.2.3.22 11:22:33:44:56:02 -set ip arp GigabitEthernetb/0/0 1.2.3.23 11:22:33:44:57:00 -set ip arp GigabitEthernetb/0/0 1.2.3.24 11:22:33:44:58:02 -set ip arp GigabitEthernetb/0/0 1.2.3.25 11:22:33:44:59:03 -set ip arp GigabitEthernetb/0/0 1.2.3.26 11:22:33:44:5a:01 -set ip arp GigabitEthernetb/0/0 1.2.3.27 11:22:33:44:5b:02 -set ip arp GigabitEthernetb/0/0 1.2.3.28 11:22:33:44:5c:03 -set ip arp GigabitEthernetb/0/0 1.2.3.29 11:22:33:44:5d:04 -set ip arp GigabitEthernetb/0/0 1.2.3.30 11:22:33:44:5e:05 -set ip arp GigabitEthernetb/0/0 1.2.3.31 11:22:33:44:5f:06 - - -Show commands -============= -show vcgn config -show vcgn statistics -show node counters -show interface - -Show commands to show translations -================================== -show vcgn inside-translation protocol tcp inside-addr 1.2.3.4 start-port 5641 end-port 5645 -show vcgn outside-translation protocol tcp outside-addr 10.1.1.31 start-port 7000 end-port 8000 -show vcgn inside-translation protocol icmp inside-addr 1.2.3.4 start-port 7000 end-port 8000 -show vcgn outside-translation protocol icmp outside-addr 10.1.1.31 start-port 7000 end-port 8000 - - diff --git a/plugins/vcgn-plugin/vcgn/cgn_bitmap.h b/plugins/vcgn-plugin/vcgn/cgn_bitmap.h deleted file mode 100644 index 6c46b75a..00000000 --- a/plugins/vcgn-plugin/vcgn/cgn_bitmap.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * Modifications to this file - * Copyright (c) 2006-2009 by cisco Systems, Inc. - * All rights reserved. - */ - -/* - Copyright (c) 2001, 2002, 2003, 2005 Eliot Dresselhaus - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef __CGN_BITMAP_H__ -#define __CGN_BITMAP_H__ - -/* Bitmaps built as vectors of machine words. */ - -#include -#include -#include -#include -#include - -#define clib_bitmap_dup(v) vec_dup(v) -#define clib_bitmap_free(v) vec_free(v) -#define clib_bitmap_bytes(v) vec_bytes(v) -#define clib_bitmap_zero(v) vec_zero(v) - -/* Allocate bitmap with given number of bits. */ -#define clib_bitmap_alloc(v,n_bits) \ - v = vec_new (uword, ((n_bits) + BITS (uword) - 1) / BITS (uword)) - -/* Sets given bit. Returns old value. */ -static inline uword -cgn_clib_bitmap_set_no_check (uword * a, uword i) -{ - uword i0 = i / BITS (a[0]); - uword bit = (uword) 1 << (i % BITS (a[0])); - uword ai; - -/* ASSERT (i0 < vec_len (a)); */ - ai = a[i0]; - a[i0] = ai | bit; - - return (ai & bit) != 0; -} - -/* Clears given bit. Returns old value. */ -static inline -uword cgn_clib_bitmap_clear_no_check (uword * a, uword i) -{ - uword i0 = i / BITS (a[0]); - uword bit = (uword) 1 << (i % BITS (a[0])); - uword ai; - -/* ASSERT (i0 < vec_len (a)); */ - ai = a[i0]; - a[i0] = ai & ~bit; - - return (ai & bit) != 0; -} - -/* Gets num_bits from ai start at start. assume that all bits are - * in the same uword. - */ -static inline uword cgn_clib_bitmap_get_bits (uword *ai, u16 start, - unsigned char num_bits) -{ - uword i0 = start / BITS (ai[0]); - uword i1 = start % BITS (ai[0]); - uword result = ai[i0] >> i1; - if(num_bits >= BITS(ai[0])) return result; - /* Else, we have to trim the bits */ - result = result & (((uword)1 << num_bits) - 1); - return result; -} - -/* Check if all of the bits from start to numb_bits are avaiable */ -static inline uword cgn_clib_bitmap_check_if_all (uword *ai, u16 start, - i16 num_bits) -{ - /* Now check if any bits are zero.. if yes, return false */ - uword bitmask; - if(num_bits >= BITS(ai[0])) { - /* assume that its going to be multiples of BUTS(ai[0]) */ - uword i0 = start / BITS (ai[0]); - bitmask = ~0; /* set all bits to 1 */ - do { - if(ai[i0] ^ bitmask) return 0; - num_bits = num_bits - BITS (ai[0]); - i0++; - } while (num_bits > 0); - return 1; - } - else { - uword result = cgn_clib_bitmap_get_bits (ai, start, num_bits); - bitmask = ((uword)1 << num_bits) -1; /* set only num_bits */ - return (!(result ^ bitmask)); - } -} - -#endif diff --git a/plugins/vcgn-plugin/vcgn/cgse_defs.h b/plugins/vcgn-plugin/vcgn/cgse_defs.h deleted file mode 100644 index 08255875..00000000 --- a/plugins/vcgn-plugin/vcgn/cgse_defs.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - *------------------------------------------------------------------ - * cgse_defs.h - CGSE specific definiitions - * - * Copyright (c) 2007-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef __CGSE_DEFS_H__ -#define __CGSE_DEFS_H__ - -#include "spp_platform_common.h" -#include - - -#define CGSE_SVI_TYPE_CNAT 1 -#define CGSE_SVI_TYPE_XLAT 2 -#define CGSE_SVI_TYPE_NAT64_STATEFUL 3 -#define CGSE_SVI_TYPE_V6RD 4 -#define CGSE_SVI_TYPE_INFRA 5 -#define CGSE_SVI_TYPE_DS_LITE 7 -#define CGSE_SVI_TYPE_MAPE 9 - -#define CGSE_SET_TX_PKT_TYPE(type) PLATFORM_SET_CTX_RU_TX_PKT_TYPE(ctx, type) - -#define CGSE_INVALID_UIDX 0xffff /*invalid svi app uidb index */ -#define CGSE_INVALID_VRFID 0xffffffff /*invalid vrf id */ - -#define CGSE_VRF_MASK 0x3fff -#define CGSE_MAX_VRFMAP_ENTRIES (CGSE_VRF_MASK + 1) - -#define CGSE_VRFMAP_ENTRY_INVALID 0xffff - - -#define CGSE_INVALID_CGSE_ID (0) - -#define CGSE_TABLE_ENTRY_DELETED 0 -#define CGSE_TABLE_ENTRY_ACTIVE 1 -#define CGSE_TABLE_ENTRY_DORMANT 2 -#define CGSE_TABLE_ENTRY_INVALID_UIDB 3 - - -#define CGSE_CONFIG_HANDLER_DEBUG_PRINTF1(level, a) \ - if (cgse_config_debug_level > level) printf(a); - -#define CGSE_CONFIG_HANDLER_DEBUG_PRINTF2(level, a, b) \ - if (cgse_config_debug_level > level) printf(a, b); - -#define CGSE_CONFIG_HANDLER_DEBUG_PRINTF3(level, a, b, c) \ - if (cgse_config_debug_level > level) printf(a, b, c); - -#define CGSE_CONFIG_HANDLER_DEBUG_PRINTF4(level, a, b, c, d) \ - if (cgse_config_debug_level > level) printf(a, b, c, d); - -#define CGSE_CONFIG_HANDLER_DEBUG_PRINTF5(level, a, b, c, d, e) \ - if (cgse_config_debug_level > level) printf(a, b, c, d, e); - -#define CGSE_CONFIG_HANDLER_DEBUG_PRINTF6(level, a, b, c, d, e, f) \ - if (cgse_config_debug_level > level) printf(a, b, c, d, e, f); - -#define CGSE_CONFIG_HANDLER_DEBUG_PRINTF7(level, a, b, c, d, e, f, g) \ - if (cgse_config_debug_level > level) printf(a, b, c, d, e, f, g); - -#define CGSE_CONFIG_HANDLER_DEBUG_PRINTF8(level, a, b, c, d, e, f, g, h) \ - if (cgse_config_debug_level > level) printf(a, b, c, d, e, f, g, h); - -#define CGSE_CONFIG_HANDLER_DEBUG_PRINTF9(level, a, b, c, d, e, f, g, h, i) \ - if (cgse_config_debug_level > level) printf(a, b, c, d, e, f, g, h, i); - -extern u16 *cgse_uidb_index_cgse_id_mapping_ptr; - -#define CGSE_ADD_UIDB_INDEX_CGSE_ID_MAPPING(uidb_index, cgse_id) \ - *(cgse_uidb_index_cgse_id_mapping_ptr + uidb_index) = cgse_id; - -extern u8 my_instance_number; - -#endif diff --git a/plugins/vcgn-plugin/vcgn/cnat_bulk_port.c b/plugins/vcgn-plugin/vcgn/cnat_bulk_port.c deleted file mode 100644 index d8894eb8..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_bulk_port.c +++ /dev/null @@ -1,964 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_bulk_ports.c - wrappers for bulk port allocation - * - * Copyright (c) 2011-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cnat_db.h" -#include "cnat_config.h" -#include "cnat_global.h" -#include "cnat_logging.h" -#include "spp_timers.h" -#include "platform_common.h" -#include "cgn_bitmap.h" -#include "spp_platform_trace_log.h" -#include "cnat_ports.h" - -#ifndef NO_BULK_LOGGING - -#define PORT_TO_CACHE(y, z) ((y)/(z)) -/* The last bit (MSB) is used to indicate whether the cache entry is full */ -#define CACHE_TO_PORT(x, z) (((x)& 0x7FFF) * (z)) -#define IS_CACHE_ENTRY_FULL(x) ((x) & 0x8000) -#define MARK_CACHE_ENTRY_AS_FULL(x) ((x) = ((x) | 0x8000)) -#define UNMARK_CACHE_ENTRY_AS_FULL(x) ((x) = ((x) & 0x7FFF)) -#define CACHE_ENTRY_WITHOUT_FULL_STAT(x) ((x) & 0x7FFF) - - -#define NUM_BULK_CHECK 128 /* max number of previous chache to check. - * somewhat orbirtrary.. assume 64 as bulk size.. can handle up - * to 128*64 ports allocated by a single subscriber */ - -/* #define DEBUG_BULK_PORT 1 */ -/* #define DEBUG_BULK_PORT_DETAIL 1 */ -#define HAVE_BULK_PORT_STATS 1 - -#ifdef HAVE_BULK_PORT_STATS -static uword bulk_cache_hit_count; -static uword bulk_port_use_count; -static uword bulk_port_alloc_count; -static uword mapped_port_alloc_count; -#endif /* HAVE_BULK_PORT_STATS */ - -static u32 bulk_port_rand_across; - -void show_bulk_port_allocation(u16 in_vrfid, u32 inside_ip) -{ - cnat_db_key_bucket_t u_ki; - cnat_user_db_entry_t *udb; - int i; - u32 head; - cnat_main_db_entry_t *db = NULL; - i16 printed_so_far = 0; /* entries printed so far */ - u16 prev_bulks[NUM_BULK_CHECK]; - cnat_vrfmap_t *my_vrfmap = 0; - cnat_vrfmap_t *vrfmap = 0; - bulk_alloc_size_t bulk_size; - - u_ki.k.k.vrf = in_vrfid; - u_ki.k.k.ipv4 = inside_ip; - u_ki.k.k.port = 0; - - PLATFORM_DEBUG_PRINT("Searching for user %x in invrf %d\n", - inside_ip, in_vrfid); - udb = cnat_user_db_lookup_entry(&u_ki); - if(!udb) { - PLATFORM_DEBUG_PRINT("No such user\n"); return; - } - - pool_foreach (vrfmap, cnat_map_by_vrf, ({ - if(vrfmap->i_vrf == in_vrfid) { - my_vrfmap = vrfmap; - break; - }})); - - if(!my_vrfmap) { - PLATFORM_DEBUG_PRINT("Vrf map not found\n"); - return; - } - bulk_size = BULKSIZE_FROM_VRFMAP(my_vrfmap); - - if(bulk_size == BULK_ALLOC_SIZE_NONE) { - PLATFORM_DEBUG_PRINT("Bulk allocation not enabled\n"); - return; - } - - PLATFORM_DEBUG_PRINT("\nBulk cache for subscriber 0x%x: ", inside_ip); - for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) { - PLATFORM_DEBUG_PRINT("%d , ", - CACHE_TO_PORT(udb->bulk_port_range_cache[i], bulk_size)); - } - PLATFORM_DEBUG_PRINT("\nNon cached bulk allocation for subscriber 0x%x:\n", - inside_ip); - ASSERT(udb); - memset(prev_bulks, 0,sizeof(prev_bulks)); - - head = udb->translation_list_head_index; - if(PREDICT_FALSE(head == EMPTY)) { - return; - } - db = cnat_main_db + head; - while (1) { - /* skip static ports - static ports may not belong to bulk pool*/ - if(db->out2in_key.k.port < cnat_static_port_range) goto next_entry; - - u16 bm_index = PORT_TO_CACHE(db->out2in_key.k.port, bulk_size); - - /*Check if we have already tested this bulk */ - for(i=0; i < printed_so_far; i++) { - if(prev_bulks[i] == bm_index) goto next_entry; - } - - /*Check if this base port is already part of cache */ - for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) { - if(CACHE_ENTRY_WITHOUT_FULL_STAT(udb->bulk_port_range_cache[i]) - == bm_index) { - goto next_entry; - } - } - /* this is not in chache already */ - PLATFORM_DEBUG_PRINT("%d ", CACHE_TO_PORT(bm_index, bulk_size)); - if(printed_so_far < NUM_BULK_CHECK) { - prev_bulks[printed_so_far] = bm_index; - printed_so_far++; - } - -next_entry: - db = cnat_main_db + db->user_ports.next; - /* - * its a circular list, so if we have reached the head again - * all the entries for that user have been read - */ - if (db == (cnat_main_db + head)) { - break; - } - } /* while loop for db entries */ - - PLATFORM_DEBUG_PRINT("\n"); - return; -} - -void show_bulk_port_stats() -{ - - cnat_vrfmap_t *my_vrfmap = 0; - PLATFORM_DEBUG_PRINT("Bulk size settings of each inside vrf ...\n"); - pool_foreach (my_vrfmap, cnat_map_by_vrf, ({ - PLATFORM_DEBUG_PRINT("vrf id %d, bulk size %d\n", my_vrfmap->i_vrf, - BULKSIZE_FROM_VRFMAP(my_vrfmap)); - })); - -#ifdef HAVE_BULK_PORT_STATS - PLATFORM_DEBUG_PRINT("\nBulk port allocation, use and cache hit statistics\n"); - PLATFORM_DEBUG_PRINT("Number of times bulk ports allocated %lld\n", - bulk_port_alloc_count); - PLATFORM_DEBUG_PRINT("Number of times pre-allocated ports used %lld\n", - bulk_port_use_count); - PLATFORM_DEBUG_PRINT( - "Number of times pre-allocated bulk port found from cache %lld\n", - bulk_cache_hit_count); - PLATFORM_DEBUG_PRINT( - "Number of times mapped port (static) allocations made %lld\n", - mapped_port_alloc_count); -#else - PLATFORM_DEBUG_PRINT("\nNat44 bulk port statistics not turned on\n"); -#endif /* HAVE_BULK_PORT_STATS */ -} - -void clear_bulk_port_stats() -{ -#ifdef HAVE_BULK_PORT_STATS - bulk_port_alloc_count = 0; - bulk_port_use_count = 0; - bulk_cache_hit_count = 0; - mapped_port_alloc_count = 0; -#endif /* HAVE_BULK_PORT_STATS */ - return; -} - -void cnat_update_bulk_range_cache(cnat_user_db_entry_t *udb, u16 o_port, - bulk_alloc_size_t bulk_size) -{ - i16 i; - if(!udb) { -#ifdef DEBUG_BULK_PORT - PLATFORM_DEBUG_PRINT("%s, null udb!\n", __func__); -#endif - return; - } - if(BULK_ALLOC_SIZE_NONE == bulk_size) { /* no bulk logging */ - return; - } - - /* Take care of caching */ - if(o_port & 0x1) { - o_port--; - } - if(PREDICT_FALSE(o_port <= 0)) { -#ifdef DEBUG_BULK_PORT - PLATFORM_DEBUG_PRINT("%s invalid port: %d\n", __func__, o_port); -#endif - return; - } - - /* First preference is for the cache entry's that are not used yet */ - for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) { - if(PREDICT_FALSE( - udb->bulk_port_range_cache[i] == (i16)BULK_RANGE_INVALID)) { - udb->bulk_port_range_cache[i] = PORT_TO_CACHE(o_port, bulk_size); - return; - } - } - - /* Now check if any cache entry is full and if it can be replaced */ - for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) { - if(PREDICT_FALSE(IS_CACHE_ENTRY_FULL(udb->bulk_port_range_cache[i]))) { - udb->bulk_port_range_cache[i] = PORT_TO_CACHE(o_port, bulk_size); - return; - } - } - - return; -} - - -void cnat_port_free_v2_bulk ( - cnat_portmap_v2_t *pm, - int index, - port_pair_t ptype, - u16 base_port, - cnat_user_db_entry_t *udb, - u16 static_port_range, - bulk_alloc_size_t bulk_size, - int *nfv9_log_req) -{ - cnat_portmap_v2_t *my_pm; - i16 bm_index; - i16 i; - int unmark_full_status = 0; - - *nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED; - - /* First free up the port */ - cnat_port_free_v2(pm, index, ptype, base_port, static_port_range); - if(BULK_ALLOC_SIZE_NONE == bulk_size) /* no bulk logging */ - return; - if(PREDICT_FALSE(!udb)) { -#ifdef DEBUG_BULK_PORT - PLATFORM_DEBUG_PRINT("%s udb is null\n", __func__); -#endif - } - - if(PREDICT_FALSE(base_port < static_port_range)) { - return; - } - /* Now check if cache needs to be removed */ - my_pm = pm + index; - base_port = base_port/bulk_size; - base_port = base_port * bulk_size; /*Align it to multiples of bulk_size */ - if(PREDICT_TRUE(!cgn_clib_bitmap_check_if_all( - my_pm->bm, base_port, bulk_size))) { - *nfv9_log_req = CACHE_ALLOC_NO_LOG_REQUIRED; - unmark_full_status = 1; - /* One or more ports are still in use */ - } else { - *nfv9_log_req = base_port; /* logging required now. indicate base port*/ - } - bm_index = PORT_TO_CACHE(base_port, bulk_size); - /* Now check if this is in the cache */ - for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) { - if(PREDICT_FALSE( - CACHE_ENTRY_WITHOUT_FULL_STAT(udb->bulk_port_range_cache[i])) - == bm_index) { - if(unmark_full_status) { - /* Unmark full stat.. if it was marked so..*/ - UNMARK_CACHE_ENTRY_AS_FULL(udb->bulk_port_range_cache[i]); - } else { - udb->bulk_port_range_cache[i] = (i16)BULK_RANGE_INVALID; -#ifdef DEBUG_BULK_PORT - PLATFORM_DEBUG_PRINT( - "Clearing cache for client 0x%x, bulk port %d\n", - my_pm->ipv4_address, base_port); -#endif - } - break; - } - } - return; -} - - -/* Get suitable port from range */ -static i16 get_suiting_port_pos_from_range(cnat_portmap_v2_t *my_pm, - u16 bulk_start, i16 bulk_size, port_pair_t pair_type) -{ - i16 num_pos = 0, num_bits, iterations; - uword bulk_ports; - i16 inc = 0; - i16 num_uwords = bulk_size/BITS(my_pm->bm[0]); - - if(PREDICT_FALSE(!num_uwords)) { - iterations = 0; - num_bits = bulk_size; - bulk_size = 0; - } else { - bulk_port_rand_across = randq1(bulk_port_rand_across); - iterations = bulk_port_rand_across % num_uwords; - num_bits = BITS(my_pm->bm[0]); - } - - do { - bulk_ports = cgn_clib_bitmap_get_bits(my_pm->bm, - (bulk_start + iterations * BITS(my_pm->bm[0])), num_bits); -#ifdef DEBUG_BULK_PORT_DETAIL - PLATFORM_DEBUG_PRINT("%s %d, bulk start %d, num_bits %d, ports %lld \n", - __func__, __LINE__, bulk_start, num_bits, bulk_ports); -#endif /* DEBUG_BULK_PORT_DETAIL */ - if(PREDICT_FALSE(!bulk_ports)) goto next_uword; - if(PREDICT_TRUE((pair_type == PORT_SINGLE) - || (pair_type == PORT_PAIR))) { - num_pos =0; - inc = 1; - } else if(pair_type == PORT_S_ODD) { - num_pos = 1; - inc = 2; - } else if(pair_type == PORT_S_EVEN) { - num_pos =0; - inc = 2; - } - - for(; num_pos < num_bits; num_pos = num_pos + inc) { - if(!((bulk_ports >> num_pos) & 1)) - continue; /* In use */ - /* Check if the available port meets our - * criteria such as add, even, pair etc */ - else if(PREDICT_FALSE( - (pair_type == PORT_PAIR) && ((num_pos & 0x1) || - (!((bulk_ports >> (num_pos + 1)) & 1))))) - continue; - else break; /* Found one that meets the criteria */ - } - if(num_pos < num_bits) - return (num_pos + iterations * BITS(my_pm->bm[0])); -next_uword: - num_bits = BITS(my_pm->bm[0]); - bulk_size -= BITS(my_pm->bm[0]); - iterations++; - if(iterations >= num_uwords) iterations = 0; - } while (bulk_size > 0); - - return -2; /* nothing found */ -} - -static cnat_errno_t try_bulk_port_from_non_cache( - cnat_user_db_entry_t *udb, - cnat_portmap_v2_t *my_pm, - port_pair_t pair_type, - bulk_alloc_size_t bulk_size, - u16 *port_available, - u16 static_port_range - ) -{ - /**** - 1. user should have existing translations.. otherwise, we wouldn't get here. - 2. For each, get the outside port. get the base port. - check if it is already in cache - 3. if not, we stand chance. - 4. Check for availability from this non cached pool. - 5. if found, repalce this with one of the cache that is invalid or full?? - 6. if we are replacing the cache.. it has to be governed by user - preference on prefer oldest pool or prefer newest pool - ********/ - u32 head; - cnat_main_db_entry_t *db = NULL; - u16 bulk_start; /* start point in 64 bitmap array to search for port */ - i16 port_pos; /* indicates the position of available port in bulk */ - i16 i; /* just a counter */ - i16 attempts_so_far = 0; /* (futile-;) attemps so far..*/ - u16 prev_bulks[NUM_BULK_CHECK]; - ASSERT(udb); - memset(prev_bulks, 0,sizeof(prev_bulks)); - - head = udb->translation_list_head_index; - if(PREDICT_FALSE(head == EMPTY)) return CNAT_NO_PRE_ALLOCATED_BULK_PORTS; - - db = cnat_main_db + head; - while (1) { //what should be the limit?? - - /* skip static ports - static ports may not belong to bulk pool*/ - if(db->out2in_key.k.port < static_port_range) goto next_entry; - - u16 bm_index = PORT_TO_CACHE(db->out2in_key.k.port, bulk_size); - - /*Check if we have already tested this bulk */ - for(i=0; i < attempts_so_far; i++) { - if(prev_bulks[i] == bm_index) { - goto next_entry; - } - } - - /*Check if this base port is already part of cache */ - for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) { - if(CACHE_ENTRY_WITHOUT_FULL_STAT(udb->bulk_port_range_cache[i]) - == bm_index) - goto next_entry; - } - - /* this is not in chache already */ - bulk_start = CACHE_TO_PORT(bm_index, bulk_size); - port_pos = get_suiting_port_pos_from_range(my_pm, - bulk_start, bulk_size, pair_type); - - if(port_pos < 0) { /* no port available in this range */ - /* Mark this bulk so that we don't have to try this again */ - if(attempts_so_far < NUM_BULK_CHECK) { - prev_bulks[attempts_so_far] = bm_index; - attempts_so_far++; - } - goto next_entry; - } - - /* Got one...Get the port number */ - *port_available = bulk_start + port_pos; - - /* Check to see if we shoud replace one of the cache */ - for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) { - if(PREDICT_FALSE((udb->bulk_port_range_cache[i] - == (i16)BULK_RANGE_INVALID) || ( - IS_CACHE_ENTRY_FULL(udb->bulk_port_range_cache[i])))) { - udb->bulk_port_range_cache[i] = bm_index; - return CNAT_SUCCESS; - } - } - /* Check to replace an existing (in use) entry */ - /* TODO: enforce policy */ - /* order of looping should depend on policy */ - - return CNAT_SUCCESS; - -next_entry: - db = cnat_main_db + db->user_ports.next; - /* - * its a circular list, so if we have reached the head again - * all the entries for that user have been read - */ - if (db == (cnat_main_db + head)) { - break; - } - } /* while loop for db entries */ - /* no ports available from pre allocated bulk pool */ - return CNAT_NO_PORT_FROM_BULK; -} - -cnat_errno_t -cnat_dynamic_port_alloc_v2_bulk ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - port_pair_t pair_type, - u32 *index, - u32 *o_ipv4_address, - u16 *o_port, - u16 static_port_range, - cnat_user_db_entry_t *udb, - bulk_alloc_size_t bulk_size, - int *nfv9_log_req, - u16 ip_n_to_1, - u32 *rseed_ip - ) -{ - - cnat_errno_t rv; - u16 port_available = 0; - i16 i; - cnat_portmap_v2_t *my_pm; - - if((BULK_ALLOC_SIZE_NONE != bulk_size) /* bulk logging enabled */ - && (udb)) { /* This user does have translations already */ - u16 bulk_start; - i16 port_pos; - - my_pm = pm + *index; - /* We have a case to check if bulk allocated ports can be used */ - /* TODO: order of looping to be based on policy - * like prefer older or prefer newer ?? - * For now, start with most recent cache entry - * so that we stand a better chance of - * finding a port - */ - for(i= 0; i < BULK_RANGE_CACHE_SIZE; i++) { - if(PREDICT_TRUE((udb->bulk_port_range_cache[i] == - (i16)BULK_RANGE_INVALID) || - IS_CACHE_ENTRY_FULL(udb->bulk_port_range_cache[i]))) { - continue; /* This range is not initialized yet or it is full */ - } - bulk_start = CACHE_TO_PORT(udb->bulk_port_range_cache[i], - bulk_size); - port_pos = get_suiting_port_pos_from_range(my_pm, - bulk_start, bulk_size, pair_type); - if(PREDICT_FALSE(port_pos < 0)) { - /* Mark this cache entry as full so that we do not - * waste time on this entry again */ - MARK_CACHE_ENTRY_AS_FULL(udb->bulk_port_range_cache[i]); -#ifdef DEBUG_BULK_PORT - PLATFORM_DEBUG_PRINT("Marked bulk cache entry %d as full for %x \n", - i, my_pm->ipv4_address); -#endif /* #ifdef DEBUG_BULK_PORT */ - continue; - } - /* Get the port number */ - port_available = bulk_start+ port_pos; -#ifdef DEBUG_BULK_PORT - PLATFORM_DEBUG_PRINT( - "Found port from cache : IP 0x%x, port %d %d iterations\n", - my_pm->ipv4_address, port_available, i) -#endif -#ifdef HAVE_BULK_PORT_STATS - bulk_cache_hit_count++; -#endif /* HAVE_BULK_PORT_STATS */ - break; - } /* end of for loop for cache check */ - /* If we have not found a port yet, check if we can have - * pre allocated bulk port from non-cache */ - if(PREDICT_FALSE(i == BULK_RANGE_CACHE_SIZE)) { - if( try_bulk_port_from_non_cache(udb, my_pm, pair_type, - bulk_size, &port_available, - static_port_range) != CNAT_SUCCESS ) { - goto ALLCOATE_NEW_BULK; - } -#ifdef DEBUG_BULK_PORT - PLATFORM_DEBUG_PRINT("Found port from non-cache : IP 0x%x, port %d\n", - my_pm->ipv4_address, port_available); -#endif - } - /* Assign the port, mark it as in use */ - cgn_clib_bitmap_clear_no_check(my_pm->bm, port_available); - (my_pm->inuse)++; - if(PREDICT_FALSE(pair_type == PORT_PAIR)) {/* Mark the next one too */ - cgn_clib_bitmap_clear_no_check(my_pm->bm, port_available + 1); - (my_pm->inuse)++; - } - *o_ipv4_address = my_pm->ipv4_address; - *o_port = port_available; - *nfv9_log_req = CACHE_ALLOC_NO_LOG_REQUIRED; -#ifdef HAVE_BULK_PORT_STATS - bulk_port_use_count++; -#endif /* HAVE_BULK_PORT_STATS */ - return (CNAT_SUCCESS); - } -ALLCOATE_NEW_BULK: -#ifdef DEBUG_BULK_PORT - if(BULK_ALLOC_SIZE_NONE != bulk_size) { - PLATFORM_DEBUG_PRINT( - "No port available from bulk cache, bulk size %d\n", bulk_size); - } -#endif - /* For whatever reason, we have not got a port yet */ - rv = cnat_dynamic_port_alloc_v2(pm, atype, pair_type, index, - o_ipv4_address, o_port, static_port_range, bulk_size, nfv9_log_req, - ip_n_to_1, rseed_ip); - if (PREDICT_FALSE(rv != CNAT_SUCCESS)) { - return rv; - } - /* Take care of caching */ - if(PREDICT_FALSE(udb != NULL)) { - /* Predict false because, we usually allocate for new users */ - cnat_update_bulk_range_cache(udb, *o_port, bulk_size); - } -#ifdef HAVE_BULK_PORT_STATS - bulk_port_alloc_count++; -#endif /* HAVE_BULK_PORT_STATS */ - return (CNAT_SUCCESS); -} - - -cnat_errno_t -cnat_static_port_alloc_v2_bulk ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - port_pair_t pair_type, - u32 i_ipv4_address, - u16 i_port, - u32 *index, - u32 *o_ipv4_address, - u16 *o_port, - u16 static_port_range, - cnat_user_db_entry_t *udb, - bulk_alloc_size_t bulk_size, - int *nfv9_log_req, - u16 ip_n_to_1 - ) -{ - - /*** - * Requirements - - * 1. If the port allocated is below dyn start, it should be individual - * port (not bulk) - * 2. If NOT, it should be bulk allocated - * 3. Try and keep the inside port same as outside port in both the - * cases (best effort) - - * Algorithm - * 1. Check if it is below stat port start or user is new or bulk is - * disabled. If yes, call existing function - * 2. If not, see if we can pick from bulk and yet try to keep the port - * same - difficult thing - check if the port is free - then check if the - * entire bulk is free - if not check if bulk is owned by the user already. - * If all of these fail, call existing function to allocate a new bulk - * 3. Update cache, etc return log requirements - *****/ - - cnat_errno_t rv; - i16 i; - u32 head; - cnat_portmap_v2_t *my_pm; - uword bit_test_result, start_bit; - cnat_main_db_entry_t *db = NULL; - - if((BULK_ALLOC_SIZE_NONE != bulk_size) /* bulk logging enabled */ - && (udb) && /* This user does have translations already */ - i_port >= static_port_range ) { /* It is outside stat port range*/ - - my_pm = pm + *index; - /* We have a case to check if bulk allocated ports can be used */ - - /* First check if the required port is available. */ - if(PREDICT_FALSE(clib_bitmap_get_no_check(my_pm->bm, i_port) == 0)) { - goto ALLOCATE_NEW_BULK_STATIC; - } - - /* Port is free.. check if the bulk is also free */ - start_bit= ((i_port/bulk_size) * bulk_size); - bit_test_result = cgn_clib_bitmap_check_if_all(my_pm->bm, - start_bit, bulk_size); - if(PREDICT_TRUE(bit_test_result)) { /* bulk is available, grab it */ - goto ALLOCATE_NEW_BULK_STATIC; - } - - /* else, bulk is taken by someone. check if it is me */ - /* Check if we own the bulk by any chance */ - for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) { - if(udb->bulk_port_range_cache[i] == start_bit) break; - } - if(i == BULK_RANGE_CACHE_SIZE) { /* no luck with cache */ - head = udb->translation_list_head_index; - if(PREDICT_FALSE(head == EMPTY)) - goto ALLOCATE_NEW_BULK_STATIC; - db = cnat_main_db + head; - i = 0; - while(1) { - if((db->out2in_key.k.port/bulk_size) * bulk_size == start_bit) { - i = 1; /* Just to indicate it is found */ - break; - } - db = cnat_main_db + db->user_ports.next; - /* - * its a circular list, so if we have reached the head again - * all the entries for that user have been read - */ - if (db == (cnat_main_db + head)) break; - } /* while loop for db entries */ - if(!i) { - goto ALLOCATE_NEW_BULK_STATIC; - } - } - /* Assign the port, mark it as in use */ - cgn_clib_bitmap_clear_no_check(my_pm->bm, i_port); - (my_pm->inuse)++; - *o_ipv4_address = my_pm->ipv4_address; - *o_port = i_port; - *nfv9_log_req = CACHE_ALLOC_NO_LOG_REQUIRED; -#ifdef HAVE_BULK_PORT_STATS - bulk_port_use_count++; -#endif /* HAVE_BULK_PORT_STATS */ - -#ifdef DEBUG_BULK_PORT - PLATFORM_DEBUG_PRINT("%s, %d, found stat port from bulk: %x, %d\n", - __func__, - __LINE__, *o_ipv4_address, *o_port); -#endif /* DEBUG_BULK_PORT */ - return (CNAT_SUCCESS); - } - -ALLOCATE_NEW_BULK_STATIC: -#ifdef DEBUG_BULK_PORT - PLATFORM_DEBUG_PRINT("%s No port available from bulk cache, bulk size %d\n", - __func__,bulk_size); -#endif - /* For whatever reason, we have not got a port yet */ - rv = cnat_static_port_alloc_v2(pm, atype, pair_type, i_ipv4_address, - i_port, index, o_ipv4_address, o_port, static_port_range, - bulk_size, nfv9_log_req,ip_n_to_1); - if (PREDICT_FALSE(rv != CNAT_SUCCESS)) { - return rv; - } - /* Take care of caching only if it was a bulk alloc */ - if(PREDICT_FALSE(udb && (BULK_ALLOC_NOT_ATTEMPTED != *nfv9_log_req))) { - cnat_update_bulk_range_cache(udb, *o_port, bulk_size); - } -#ifdef HAVE_BULK_PORT_STATS - bulk_port_alloc_count++; -#endif /* HAVE_BULK_PORT_STATS */ - return (CNAT_SUCCESS); - -} - -cnat_errno_t -cnat_mapped_static_port_alloc_v2_bulk ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - u32 *index, - u32 ipv4_address, - u16 port, - cnat_user_db_entry_t *udb, - bulk_alloc_size_t bulk_size, - int *nfv9_log_req, - u16 ip_n_to_1 - ) -{ - /* Requirements : - * 1. Check if bulk allocation is required. - * 2. Call cnat_mapped_static_port_alloc_v2 to allocate - * 3. Decide if alloc has to be cached - * 4. Update nfv9_log_req - */ - cnat_errno_t rv; - rv = cnat_mapped_static_port_alloc_v2 (pm, - atype, index, ipv4_address, port, nfv9_log_req, bulk_size, ip_n_to_1); - if (PREDICT_FALSE(rv != CNAT_SUCCESS)) { - return rv; - } - /* Take care of caching only if it was a bulk alloc */ - if(PREDICT_FALSE(udb && (BULK_ALLOC_NOT_ATTEMPTED != *nfv9_log_req))) { - int i; - port = port*bulk_size; - port = port/bulk_size; /* align it to bulk size boundary */ - for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) { - if(CACHE_ENTRY_WITHOUT_FULL_STAT(udb->bulk_port_range_cache[i]) - == PORT_TO_CACHE(port, bulk_size)) - break; - } - if( i == BULK_RANGE_CACHE_SIZE) { /* else, it is alredy in cache */ - cnat_update_bulk_range_cache(udb, port, bulk_size); - } - } -#ifdef HAVE_BULK_PORT_STATS - mapped_port_alloc_count++; -#endif /* HAVE_BULK_PORT_STATS */ - return (CNAT_SUCCESS); -} - - -cnat_errno_t -cnat_dynamic_port_alloc_rtsp_bulk ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - port_pair_t pair_type, - u16 i_port, - u32 *index, - u32 *o_ipv4_address, - u16 *o_port, - u16 static_port_range, - cnat_user_db_entry_t *udb, - bulk_alloc_size_t bulk_size, - int *nfv9_log_req, - u32 *rseed_ip) -{ - - /*** - * Algorithm - * 1. Compute the range of ports required based on the number of digits - * in the port request made by the client. - * 2. Check if bulk logging is enabled. If not, use the existing method. - * 3. Check if there are 2 adjacent ports available that meet the above - * criteria in any of the bulk allocations made already. - * 4. If yes, mark them in use and return. - * 5. If not allocate a new bulk and pick 2 ports in it - ***/ - - i16 i; - cnat_portmap_v2_t *my_pm = 0; - u32 start_port1, end_port1, start_port2, end_port2; - int range_loop; - u16 bulk_start; - i16 port_pos; - u16 port_available = 0; - - ASSERT(index); - ASSERT(o_ipv4_address); - ASSERT(o_port); - - /* - * Check if the port is 4 digit or 5 digit. I am assuming we are - * not getting 3 (or 2 or 1) digit ports, which we cannot anyway - * allocate same sized outside ports - as outside ports start from 1024 - * - * Static Port has its own reserved range. Ensure that the range is - * such that atleast few 4 digit ports are available for RTSP. If - * not it does not make sense to do special allocation for RTSP. - */ - if (PREDICT_TRUE(static_port_range < MIN_STATIC_PORT_RANGE_FOR_RTSP)) { - /* - * 4 digit port or less - */ - if (i_port <= 9999) { - start_port1 = static_port_range; - end_port1 = 9999; - - start_port2 = 10000; - end_port2 = PORTS_PER_ADDR - 1; - } else { /* 5 digit port */ - start_port1 = 10000; - end_port1 = PORTS_PER_ADDR - 1; - - start_port2 = static_port_range; - end_port2 = 9999; - } - } else { /* Static port range is too big */ - start_port1 = static_port_range; - end_port1 = PORTS_PER_ADDR - 1; - - /* - * PORTS_PER_ADDR is just a placeholder for - * INVALID_PORT, valid ports are b/w 1 and PORTS_PER_ADDR - */ - start_port2 = PORTS_PER_ADDR; - end_port2 = PORTS_PER_ADDR; - } - - - if(PREDICT_TRUE(udb != NULL)) { - my_pm = pm + *index; - } - - /* Now check if this user already owns a bulk range that is - * within start range 1 - */ - - u32 start_range = start_port1; - u32 end_range = end_port1; - for(range_loop = 0; range_loop < 2; range_loop++) { - if((BULK_ALLOC_SIZE_NONE == bulk_size) || (!udb)) { - goto ALLOCATE_NEW_RTSP_PORTS; - } - for(i= 0; i < BULK_RANGE_CACHE_SIZE; i++) { - if(PREDICT_TRUE((udb->bulk_port_range_cache[i] == - (i16)BULK_RANGE_INVALID) || - IS_CACHE_ENTRY_FULL(udb->bulk_port_range_cache[i]))) { - continue; /* This range is not initialized yet or it is full */ - } - - bulk_start = CACHE_TO_PORT(udb->bulk_port_range_cache[i], - bulk_size); - if(bulk_start < start_port1 || bulk_start >= end_port1) { - continue; /* Not in the range */ - } - - port_pos = get_suiting_port_pos_from_range(my_pm, - bulk_start, bulk_size, pair_type); - if(PREDICT_FALSE(port_pos < 0)) { - /* Not Marking this cache entry as full as it failed - * for pair type. It might have individual entries - */ - continue; - } - /* Get the port number */ - port_available = bulk_start+ port_pos; -#ifdef DEBUG_BULK_PORT - PLATFORM_DEBUG_PRINT( - "Found port from cache : IP 0x%x, port %d %d iterations\n", - my_pm->ipv4_address, port_available, i) -#endif -#ifdef HAVE_BULK_PORT_STATS - bulk_cache_hit_count += 2; -#endif /* HAVE_BULK_PORT_STATS */ - break; - } /* end of for loop for cache check */ - - if(PREDICT_FALSE(i == BULK_RANGE_CACHE_SIZE)) { - /* we have not found a port yet, but to do not want to try - * non-cache bulks.. because, it is a very low probability and - * do not want to tweak that code for this special case - * The impact of non checking the non-cache is, we give this - * user few extra ports .. which is OK - */ - goto ALLOCATE_NEW_RTSP_PORTS; - } -#ifdef DEBUG_BULK_PORT - PLATFORM_DEBUG_PRINT("RTSP: Found port from non-cache : IP 0x%x, port %d\n", - my_pm->ipv4_address, port_available); -#endif - - /* Assign the port, mark it as in use */ - cgn_clib_bitmap_clear_no_check(my_pm->bm, port_available); - (my_pm->inuse)++; - cgn_clib_bitmap_clear_no_check(my_pm->bm, port_available + 1); - (my_pm->inuse)++; - - *o_ipv4_address = my_pm->ipv4_address; - *o_port = port_available; - *nfv9_log_req = CACHE_ALLOC_NO_LOG_REQUIRED; -#ifdef HAVE_BULK_PORT_STATS - bulk_port_use_count += 2; -#endif /* HAVE_BULK_PORT_STATS */ - return (CNAT_SUCCESS); - -ALLOCATE_NEW_RTSP_PORTS: - /* No luck. Let's try allocating new bulk.. */ - if(PREDICT_TRUE(CNAT_SUCCESS == cnat_dynamic_port_alloc_rtsp - (pm, atype, pair_type, - start_range, end_range,index, o_ipv4_address, - o_port, bulk_size, nfv9_log_req,rseed_ip))) { - if(PREDICT_FALSE(udb && - (BULK_ALLOC_NOT_ATTEMPTED != *nfv9_log_req))) { - cnat_update_bulk_range_cache(udb, *o_port, bulk_size); - } -#ifdef HAVE_BULK_PORT_STATS - bulk_port_alloc_count++; -#endif /* HAVE_BULK_PORT_STATS */ - return CNAT_SUCCESS; - } - - /* Could not allocate in range 1.. so move to range 2. */ - start_range = start_port2; - end_range = end_port2; - - } - - return (CNAT_NOT_FOUND_DIRECT); /* if we are here, we could not get any ports */ - -} - -#else /* Dummy definitions */ -void show_bulk_port_stats() -{ - PLATFORM_DEBUG_PRINT("\nBulk logging feature not included\n"); -} - - void clear_bulk_port_stats() -{ - PLATFORM_DEBUG_PRINT("\nBulk logging feature not included\n"); -} -#endif /* NO_BULK_LOGGING */ diff --git a/plugins/vcgn-plugin/vcgn/cnat_bulk_port.h b/plugins/vcgn-plugin/vcgn/cnat_bulk_port.h deleted file mode 100644 index 3e48b9a7..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_bulk_port.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_bulk_port_defs.h bulk port alloc definitions - * - * Copyright (c) 2011-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef __CNAT_BULK_PORT_H__ -#define __CNAT_BULK_PORT_H__ - -#ifndef NO_BULK_LOGGING -#include "cnat_bulk_port_defs.h" - -cnat_errno_t -cnat_dynamic_port_alloc_v2_bulk ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - port_pair_t pair_type, - u32 *index, - u32 *o_ipv4_address, - u16 *o_port, - u16 static_port_range, - cnat_user_db_entry_t *udb, - bulk_alloc_size_t bulk_size, - int *nfv9_log_req, - u16 ip_n_to_1, - u32 *rseed_ip); - -void cnat_update_bulk_range_cache(cnat_user_db_entry_t *udb, u16 o_port, - bulk_alloc_size_t bulk_size); - -void cnat_port_free_v2_bulk ( - cnat_portmap_v2_t *pm, - int index, - port_pair_t ptype, - u16 base_port, - cnat_user_db_entry_t *udb, - u16 static_port_range, - bulk_alloc_size_t bulk_size, - int *nfv9_log_req); - -cnat_errno_t cnat_static_port_alloc_v2_bulk ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - port_pair_t pair_type, - u32 i_ipv4_address, - u16 i_port, - u32 *index, - u32 *o_ipv4_address, - u16 *o_port, - u16 static_port_range, - cnat_user_db_entry_t *udb, - bulk_alloc_size_t bulk_size, - int *nfv9_log_req, - u16 ip_n_to_1 - ); - -cnat_errno_t cnat_dynamic_port_alloc_rtsp_bulk ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - port_pair_t pair_type, - u16 i_port, - u32 *index, - u32 *o_ipv4_address, - u16 *o_port, - u16 static_port_range, - cnat_user_db_entry_t *udb, - bulk_alloc_size_t bulk_size, - int *nfv9_log_req, - u32 *rseed_ip); - -cnat_errno_t -cnat_mapped_static_port_alloc_v2_bulk ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - u32 *index, - u32 ipv4_address, - u16 port, - cnat_user_db_entry_t *udb, - bulk_alloc_size_t bulk_size, - int *nfv9_log_req, - u16 ip_n_to_1 - ); - -#else /* NO_BULK_LOGGING */ -/* use older code */ -inline cnat_errno_t -cnat_dynamic_port_alloc_v2_bulk ( - cnat_vrfmap_t *vrf_map, - port_alloc_t atype, - port_pair_t pair_type, - u32 *index, - u32 *o_ipv4_address, - u16 *o_port, - u16 static_port_range, - u16 ip_n_to_1, - u32 *rseed_ip - ) -{ - return cnat_dynamic_port_alloc_v2(vrf_map->portmap_list, atype, - pair_type, index, o_ipv4_address, o_port, static_port_range, - ip_n_to_1, rseed_ip); -} - -inline void cnat_port_free_v2_bulk ( - cnat_portmap_v2_t *pm, - int index, - port_pair_t ptype, - u16 base_port, - cnat_user_db_entry_t *udb, - u16 static_port_range); -{ - return cnat_port_free_v2(pm, index, ptype, base_port, - static_port_range); -} - -inline cnat_errno_t cnat_static_port_alloc_v2_bulk ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - port_pair_t pair_type, - u32 i_ipv4_address, - u16 i_port, - u32 *index, - u32 *o_ipv4_address, - u16 *o_port, - u16 static_port_range) -{ - return cnat_static_port_alloc_v2 (pm, atype, pair_type, - i_ipv4_address, i_port, index, o_ipv4_address, o_port); -} - -inline cnat_errno_t -cnat_mapped_static_port_alloc_v2_bulk ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - u32 *index, - u32 ipv4_address, - u16 port) -{ - return cnat_mapped_static_port_alloc_v2(pm, atype, index - ipv4_address, port); -} - -#endif /* NO_BULK_LOGGING */ -#endif /* __CNAT_BULK_PORT_H__ */ diff --git a/plugins/vcgn-plugin/vcgn/cnat_bulk_port_defs.h b/plugins/vcgn-plugin/vcgn/cnat_bulk_port_defs.h deleted file mode 100644 index edb47b0a..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_bulk_port_defs.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_bulk_port_defs.h bulk port alloc definitions - * - * Copyright (c) 2011 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef __CNAT_BULK_PORT_DEFS_H__ -#define __CNAT_BULK_PORT_DEFS_H__ - - -#ifndef NO_BULK_LOGGING - -typedef enum { - BULK_ALLOC_SIZE_NONE = 1, - BULK_ALLOC_SIZE_16 = 16, - BULK_ALLOC_SIZE_32 = 32, - BULK_ALLOC_SIZE_64 = 64, - BULK_ALLOC_SIZE_128 = 128, - BULK_ALLOC_SIZE_256 = 256, - BULK_ALLOC_SIZE_512 = 512, - BULK_ALLOC_SIZE_1024 = 1024, - BULK_ALLOC_SIZE_2048 = 2048, - BULK_ALLOC_SIZE_4096 = 4096 -} bulk_alloc_size_t; - -/* #define DEBUG_BULK_PORT 1 TODO: remove this later */ - -#define CACHE_ALLOC_NO_LOG_REQUIRED -1 -#define BULK_ALLOC_NOT_ATTEMPTED -2 - -#define BULK_RANGE_INVALID 0xFFFF -#define BULK_RANGE_CACHE_SIZE 4 - -#define BULKSIZE_FROM_VRFMAP(vrfmap) ((vrfmap)->bulk_size) - -#define INIT_BULK_CACHE(udb) \ - { \ - int i; \ - for(i =0; i < BULK_RANGE_CACHE_SIZE; i++) \ - (udb)->bulk_port_range_cache[i] = (i16)BULK_RANGE_INVALID; \ - } - -#endif /* NO_BULK_LOGGING */ -#endif /* __CNAT_BULK_PORT_DEFS_H__ */ diff --git a/plugins/vcgn-plugin/vcgn/cnat_cli.h b/plugins/vcgn-plugin/vcgn/cnat_cli.h deleted file mode 100644 index e9d190a5..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_cli.h +++ /dev/null @@ -1,206 +0,0 @@ -/* *------------------------------------------------------------------ - * cnat_cli.h - CLI definitions - * - * Copyright (c) 2007-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef __CNAT_CLI_H__ -#define __CNAT_CLI_H__ - -#include "cnat_config_api.h" -#include "cnat_show_api.h" - -/* from iox cli error */ -typedef enum { - CNAT_SUCCESS = 0, - CNAT_NO_CONFIG, - CNAT_NO_VRF_RUN, - CNAT_NO_POOL_ANY, - CNAT_NO_PORT_ANY, -#ifndef NO_BULK_LOGGING - CNAT_NO_PORT_FROM_BULK, - CNAT_NO_PRE_ALLOCATED_BULK_PORTS, -#endif /* NO_BULK_LOGGING */ - CNAT_BAD_INUSE_ANY, - CNAT_NOT_FOUND_ANY, - CNAT_INV_PORT_DIRECT, - CNAT_DEL_PORT_DIRECT, - CNAT_BAD_INUSE_DIRECT, - CNAT_NOT_FOUND_DIRECT, - CNAT_OUT_LIMIT, - CNAT_MAIN_DB_LIMIT, - CNAT_USER_DB_LIMIT, - CNAT_NOT_STATIC_PORT, - CNAT_BAD_STATIC_PORT_REQ, - CNAT_NOT_THIS_CORE, - CNAT_ERR_PARSER, - CNAT_ERR_INVALID_MSG_ID, - CNAT_ERR_INVALID_MSG_SIZE, - CNAT_ERR_INVALID_PAYLOAD_SIZE, - CNAT_ERR_BAD_TCP_UDP_PORT, - CNAT_ERR_BULK_SINGLE_FAILURE, - CNAT_ERR_XLAT_ID_INVALID, - CNAT_ERR_XLAT_V6_PREFIX_INVALID, - CNAT_ERR_XLAT_V4_PREFIX_INVALID, - CNAT_ERR_XLAT_TCP_MSS_INVALID, - CNAT_ERR_6RD_ID_INVALID, - CNAT_ERR_6RD_V4_TUNNEL_SRC_INVALID, - CNAT_ERR_6RD_V6_PREFIX_INVALID, - CNAT_ERR_6RD_V6_BR_UNICAST_INVALID, - CNAT_ERR_6RD_V4_PREFIX_MASK_LEN_INVALID, - CNAT_ERR_6RD_V4_SUFFIX_MASK_LEN_INVALID, - CNAT_ERR_6RD_V4_COMBO_MASK_LEN_INVALID, - CNAT_ERR_6RD_TUNNEL_MTU_INVALID, - CNAT_ERR_6RD_TUNNEL_TTL_INVALID, - CNAT_ERR_6RD_TUNNEL_TOS_INVALID, - CNAT_ERR_NAT64_NO_VRF_RUN, - CNAT_ERR_NAT64_ID_INVALID, - CNAT_ERR_NAT64_V6_PREFIX_INVALID, - CNAT_ERR_NAT64_V4_PREFIX_INVALID, - CNAT_ERR_NAT64_TCP_MSS_INVALID, -#ifdef CGSE_DS_LITE - CNAT_ERR_DS_LITE_ID_INVALID, -#endif /* CGSE_DS_LITE */ - CNAT_ERR_NO_SESSION_DB, - CNAT_ERR_MAPE_ID_INVALID, - CNAT_ERR_MAX -} cnat_errno_t; - -#define CNAT_TRUE 1 -#define CNAT_FALSE 0 - - -#define CNAT_DEBUG_NONE (0) -#define CNAT_DEBUG_GLOBAL_ERR (1 << 0) -#define CNAT_DEBUG_DROP_TCP (1 << 0) -#define CNAT_DEBUG_DROP_UDP (1 << 1) -#define CNAT_DEBUG_DROP_ICMP (1 << 2) -#define CNAT_DEBUG_ERR_TCP (1 << 3) -#define CNAT_DEBUG_ERR_UDP (1 << 4) -#define CNAT_DEBUG_ERR_ICMP (1 << 5) -#define CNAT_DEBUG_ERR_ALG (1 << 6) -#define CNAT_DEBUG_GLOBAL_ALL (1 << 7) -#define CNAT_DEBUG_FTP_ALG (1 << 8) - - - -#define CNAT_DEBUG_ALL 0x1FF /*all of above*/ -#define CNAT_DEBUG_ERR_ALL 0x38 - -#define CNAT_DB_CLEAR_SPECIFIC (0) -#define CNAT_DB_CLEAR_ALL (1 << 0) -#define CNAT_DB_CLEAR_VRF (1 << 1) -#define CNAT_DB_CLEAR_ADDR (1 << 2) -#define CNAT_DB_CLEAR_PROTO (1 << 3) -#define CNAT_DB_CLEAR_PORT (1 << 4) - - -#define MAX_UIDX 0x3fff /*the max svi app uidb index */ -/* address mask per core */ -#define ADDR_MASK_PER_CORE PLATFORM_ADDR_MASK_PER_CORE -#define ADDR_MASK_PER_CORE_PER_PARTITION \ - PLATFORM_ADDR_MASK_PER_CORE_PER_PARTITION - -#define MAX_CORES PLATFORM_MAX_CORES -#define MAX_CORES_PER_PARTITION PLATFORM_MAX_CORES_PER_PARTITION - -/* - * Maximum pool size that is supported by platform - */ -#define CNAT_MAX_ADDR_POOL_SIZE PLATFORM_CNAT_MAX_ADDR_POOL_SIZE -#define CNAT_MAX_ADDR_POOL_SIZE_PER_CORE \ - (CNAT_MAX_ADDR_POOL_SIZE / MAX_CORES_PER_PARTITION) - -#define BOUNDARY_VALUE 256 - -#define BOUNDARY_VALUE_MASK 0xff - -#define NUM_ADDR_IN_RANGE(range, value, instance) \ - ((range / value) + ((instance % MAX_CORES_PER_PARTITION) < (range%value) ? 1 : 0)) - -typedef enum { - CNAT_DEBUG_FLAGS_DUMP = 0, - CNAT_DEBUG_FLAG_UDP_INSIDE_CHECKSUM_DISABLE, - CNAT_DEBUG_FLAG_UDP_OUTSIDE_CHECKSUM_DISABLE, - CNAT_DEBUG_FLAG_UDP_OUTSIDE_PKT_DUMP_ENABLE, - CNAT_DEBUG_FLAG_UDP_INSIDE_PKT_DUMP_ENABLE, - CNAT_DEBUG_FLAG_ICMP_PKT_DUMP_ENABLE, - CNAT_DEBUG_FLAG_FRAG_PKT_DUMP_ENABLE, - CNAT_DEBUG_FLAG_CONFIG_DEBUG_ENABLE, - CNAT_DEBUG_FLAG_GLOBAL_DEBUG_ALL_ENABLE, - CNAT_DEBUG_FLAG_SUMMARY_STATS_DEBUG_ENABLE, - CNAT_DEBUG_FLAG_SHOW_DEBUG_ENABLE, - CNAT_DEBUG_FLAG_XLAT_CONFIG_DEBUG_ENABLE, - CNAT_DEBUG_FLAG_XLAT_DATA_PATH_DEBUG_ENABLE, - CNAT_DEBUG_FLAG_TCP_LOGGING_ENABLE, - CNAT_DEBUG_FLAG_NFV9_LOGGING_DUMP_ENABLE, - CNAT_DEBUG_FLAG_SYSLOG_LOGGING_DUMP_ENABLE, - CNAT_DEBUG_SET_STATIC_PORT_RANGE, - CNAT_DEBUG_FLAG_V6RD_DATA_PATH_DEBUG_ENABLE, - CNAT_DEBUG_FLAG_V6RD_CONFIG_DEBUG_ENABLE, - CNAT_DEBUG_FLAG_V6RD_DEFRAG_DEBUG_ENABLE, - CNAT_DEBUG_FLAG_NAT64_CONFIG_DEBUG_ENABLE, - CNAT_DEBUG_FLAG_NAT64_DATA_PATH_DEBUG_ENABLE, - CNAT_DEBUG_FLAG_DSLITE_DP_ENABLE, - CNAT_DEBUG_FLAG_DSLITE_CONFIG_DEBUG_ENABLE, - CNAT_DEBUG_FLAG_CONFIG_PPTP_ENABLE = 24, - CNAT_DEBUG_FLAG_CONFIG_PCP_ENABLE = 25, - CNAT_DEBUG_FLAG_MAPE_CONFIG_DEBUG_ENABLE, - CNAT_DEBUG_FLAG_MAPE_DATA_PATH_DEBUG_ENABLE, - CNAT_DEBUG_FLAG_MAX, -} cnat_debug_variable_value; - -/* - * Don't use too small values for PATH MTU - */ -#define MIN_NFV9_PATH_MTU 100 - -extern u32 global_debug_flag; -extern u16 debug_i_vrf; -extern u32 debug_i_flag; -extern u32 debug_i_addr_start; -extern u32 debug_i_addr_end; -extern u16 debug_o_vrf; -extern u32 debug_o_flag; -extern u32 debug_o_addr_start; -extern u32 debug_o_addr_end; -extern u32 tcp_logging_enable_flag; -extern u32 nfv9_logging_debug_flag; - -extern u32 udp_inside_checksum_disable; -extern u32 udp_outside_checksum_disable; -extern u32 udp_inside_packet_dump_enable; -extern u32 udp_outside_packet_dump_enable; - -extern u32 icmp_debug_flag; -extern u32 frag_debug_flag; - -extern u32 summary_stats_debug_flag; - -extern u32 config_debug_level; -extern u32 show_debug_level; - - -/* CLI API prototypes called from vcgn_classify.c */ -extern void cnat_nat44_add_vrf_map_t_handler(spp_api_cnat_v4_add_vrf_map_t *mp, - vlib_main_t *vm); -extern void cnat_nat44_handle_show_stats(vlib_main_t *vm); -extern void cnat_nat44_handle_show_config(vlib_main_t *vm); -extern void cnat_nat44_set_protocol_timeout_value(u16 active, - u16 init, u8 *proto, u8 reset, vlib_main_t *vm); -extern void cnat_v4_show_inside_entry_req_t_handler -(spp_api_cnat_v4_show_inside_entry_req_t *mp, vlib_main_t *vm); - -#endif /* __CNAT_CLI_H__ */ diff --git a/plugins/vcgn-plugin/vcgn/cnat_cli_handler.c b/plugins/vcgn-plugin/vcgn/cnat_cli_handler.c deleted file mode 100644 index a4010349..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_cli_handler.c +++ /dev/null @@ -1,961 +0,0 @@ -/* *------------------------------------------------------------------ - * cnat_cli_handler.c - CLI handler definitions - * - * Copyright (c) 2007-2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cnat_db.h" -#include "cnat_config.h" -#include "cnat_global.h" -#include "cnat_cli.h" -#include "cnat_logging.h" -#include "cnat_syslog.h" -#include "cnat_config_api.h" -#include "cnat_show_api.h" -#include "cnat_show_response.h" - -#include - -#if DPDK -#include -#endif - -u32 show_debug_level = 0; - -u32 -cnat_get_vrfmap_nfv9_logging_index (u32 i_vrf_id) -{ - cnat_nfv9_logging_info_t *my_nfv9_logging_info = 0; - u32 logging_index = EMPTY; - - /* - * Start with global logging index if available - */ - if (cnat_nfv9_global_info.cnat_nfv9_init_done) { - logging_index = cnat_nfv9_global_info.cnat_nfv9_global_collector_index; - - pool_foreach (my_nfv9_logging_info, cnat_nfv9_logging_info_pool, ({ - if (my_nfv9_logging_info->i_vrf_id == i_vrf_id) { - logging_index = my_nfv9_logging_info - - cnat_nfv9_logging_info_pool; - break; - } - })); - } - return (logging_index); -} - -u32 -cnat_get_vrfmap_syslog_logging_index (u32 i_vrf_id) -{ - cnat_syslog_logging_info_t *my_syslog_info = NULL; - u32 logging_index = EMPTY; - - /* - * Start with global logging index if available - */ - if(PREDICT_TRUE(cnat_syslog_global_info.cnat_syslog_init_done)) { - - pool_foreach (my_syslog_info, cnat_syslog_logging_info_pool, ({ - if (my_syslog_info->i_vrf_id == i_vrf_id) { - logging_index = my_syslog_info - - cnat_syslog_logging_info_pool; - break; - } - })); - } - return (logging_index); -} - -void -cnat_set_vrf_params_with_default(cnat_vrfmap_t *my_vrfmap, u32 i_vrf, u32 i_vrf_id) -{ - - my_vrfmap->status = S_WAO; - - my_vrfmap->i_vrf = i_vrf; - my_vrfmap->i_vrf_id = i_vrf_id; - - my_vrfmap->o_vrf = INVALID_UIDX; - my_vrfmap->o_vrf_id = INVALID_VRFID; - -#ifndef NO_BULK_LOGGING - BULKSIZE_FROM_VRFMAP(my_vrfmap) = BULK_ALLOC_SIZE_NONE; -#endif /* #ifndef NO_BULK_LOGGING */ - my_vrfmap->tcp_mss = V4_TCP_MSS_NOT_CONFIGURED_VALUE; - my_vrfmap->frag_tout = CNAT_IPV4_FRAG_TIMEOUT_DEF; - my_vrfmap->port_limit = V4_DEF_VRF_MAX_PORTS; - my_vrfmap->nfv9_logging_index = - cnat_get_vrfmap_nfv9_logging_index(i_vrf_id); - my_vrfmap->syslog_logging_index = - cnat_get_vrfmap_syslog_logging_index(i_vrf_id); - - /* Copy logging policy from nfv9 info. */ - if(my_vrfmap->nfv9_logging_index != EMPTY) { - cnat_nfv9_logging_info_t *nfv9_logging_info = - cnat_nfv9_logging_info_pool + my_vrfmap->nfv9_logging_index; - my_vrfmap->nf_logging_policy = nfv9_logging_info->logging_policy; - } - if(my_vrfmap->syslog_logging_index != EMPTY) { - cnat_syslog_logging_info_t *syslog_logging_info = - cnat_syslog_logging_info_pool + my_vrfmap->syslog_logging_index; - my_vrfmap->syslog_logging_policy = syslog_logging_info->logging_policy; - } - #if 0 - printf("Initializing params in cnat_set_vrf_params_with_default\n" - "my_vrfmap->status = %u\n" - "my_vrfmap->tcp_mss = %u\n" - "my_vrfmap->i_vrf = %u\n" - "my_vrfmap->i_vrf_id = %u\n" - "my_vrfmap->o_vrf = %u\n" - "my_vrfmap->o_vrf_id = %u\n" - "my_vrfmap->bulk_size = %u\n" - "my_vrfmap->nfv9_logging_index = %u\n" - "my_vrfmap->syslog_logging_index = %u\n" - "my_vrfmap->frag_tout = %u\n" - "my_vrfmap->port_limit = %u\n" - "my_vrfmap->nf_logging_policy = %u\n" - "my_vrfmap->syslog_logging_policy = %u\n", - my_vrfmap->status, - my_vrfmap->tcp_mss, - my_vrfmap->i_vrf, - my_vrfmap->i_vrf_id, - my_vrfmap->o_vrf, - my_vrfmap->o_vrf_id, - my_vrfmap->bulk_size, - my_vrfmap->nfv9_logging_index, - my_vrfmap->syslog_logging_index, - my_vrfmap->frag_tout, - my_vrfmap->port_limit, - my_vrfmap->nf_logging_policy, - my_vrfmap->syslog_logging_policy); - #endif /* if 0 */ -} - -/* config command handlers */ -void cnat_nat44_add_vrf_map_t_handler(spp_api_cnat_v4_add_vrf_map_t *mp, - vlib_main_t *vm) -{ - void cnat_table_entry_fill_map(u32 start_addr, u32 end_addr, - cnat_portmap_v2_t **port_map_holder); - u32 start_addr, end_addr; - u32 pm_len __attribute__((unused)); - cnat_vrfmap_t *my_vrfmap = 0; - cnat_portmap_v2_t *pm = 0; - u16 i_vrf, o_vrf; - u32 ivrf_id, ovrf_id; - u16 my_vrfmap_index; - u8 i = 0; - - start_addr = mp->start_addr[0]; - end_addr = mp->end_addr[0]; - i_vrf = mp->i_vrf; - o_vrf = mp->o_vrf; - ovrf_id = mp->o_vrf_id; - ivrf_id = mp->i_vrf_id; - -#if DEBUG_NOT_COMMENTED - vlib_cli_output(vm, "%s: saddr[0x%x], eaddr[0x%x], i_vrf[0x%x], o_vrf[0x%x], " - "ovrf_id[0x%x], ivrf_id[0x%x]\n", __func__, start_addr, end_addr, - i_vrf, o_vrf, ovrf_id, ivrf_id); -#endif - if (start_addr > end_addr) { - vlib_cli_output(vm, "Add VRF Map failed start addr 0x%x > end addr 0x%x\n", - start_addr, end_addr); - return; - } - if ((end_addr - start_addr) > CNAT_MAX_ADDR_POOL_SIZE) { - vlib_cli_output(vm, "Add VRF Map failed start addr 0x%x - end addr " - "0x%x range > 65536\n", start_addr, end_addr); - return; - } - my_vrfmap_index = vrf_map_array[i_vrf]; - - if (my_vrfmap_index != VRF_MAP_ENTRY_EMPTY) { - - my_vrfmap = cnat_map_by_vrf + my_vrfmap_index; - - my_vrfmap->o_vrf = o_vrf; - my_vrfmap->i_vrf_id = ivrf_id; - my_vrfmap->o_vrf_id = ovrf_id; - } else { - /* - * first time add - */ - pool_get(cnat_map_by_vrf, my_vrfmap); - memset(my_vrfmap, 0, sizeof(*my_vrfmap)); - /* waiting for outside vrf */ - cnat_set_vrf_params_with_default(my_vrfmap, i_vrf, ivrf_id); - my_vrfmap->i_vrf = i_vrf; - my_vrfmap->o_vrf = o_vrf; - my_vrfmap->i_vrf_id = ivrf_id; - my_vrfmap->o_vrf_id = ovrf_id; -#ifndef NO_BULK_LOGGING - BULKSIZE_FROM_VRFMAP(my_vrfmap) = BULK_ALLOC_SIZE_NONE; -#endif /* #ifndef NO_BULK_LOGGING */ - - my_vrfmap->tcp_mss = V4_TCP_MSS_NOT_CONFIGURED_VALUE; - my_vrfmap->status = S_WA; - my_vrfmap->frag_tout = 0; /* currently setting it to 0 */ - my_vrfmap->port_limit = V4_DEF_VRF_MAX_PORTS; - vrf_map_array[i_vrf] = (my_vrfmap - cnat_map_by_vrf); - } - pm = my_vrfmap->portmap_list; - pm_len = vec_len(pm); - for(i=0; i < 1 ; i++) { - start_addr = mp->start_addr[i]; - end_addr = mp->end_addr[i]; - if((start_addr == 0) || (end_addr == 0)) - break; - - cnat_table_entry_fill_map(start_addr, end_addr, - &(my_vrfmap->portmap_list)); - } - my_vrfmap->status = S_RUN; - vlib_cli_output(vm, "Address Pool Config Successful !!\n"); - return; -} - -void cnat_nat44_set_protocol_timeout_value(u16 active, - u16 init, u8 *proto, u8 reset, vlib_main_t *vm) -{ - if (!strncmp((char *) proto, "tcp", 3)) { - tcp_initial_setup_timeout = (reset) ? V4_DEF_TCP_IS_TO : init; - tcp_active_timeout = (reset) ? V4_DEF_TCP_AS_TO : active; - - } else if (!strncmp((char *) proto, "udp", 3)) { - udp_init_session_timeout = (reset) ? V4_DEF_UDP_IS_TO : init; - udp_act_session_timeout = (reset) ? V4_DEF_UDP_AS_TO : active; - - } else if (!strncmp((char *) proto, "icmp", 4)) { - icmp_session_timeout = (reset) ? V4_DEF_ICMP_S_TO : active; - - } else { - vlib_cli_output(vm, "Error !! Unsupported protocol %s\n", proto); - } - return; -} - - - - -/* Show command handlers */ -void cnat_nat44_handle_show_stats(vlib_main_t *vm) -{ - pool_header_t *h; - u32 used, free; - cnat_vrfmap_t *my_vrfmap =0; - cnat_portmap_v2_t *pm =0, *my_pm = 0; - u32 i, pm_len; - struct in_addr ip; - void cnat_nfv9_show_collector - (vlib_main_t *vm, cnat_nfv9_logging_info_t *my_nfv9_logging_info); - - /* active translations */ - h = pool_header(cnat_main_db); - free = vec_len(h->free_indices); - used = vec_len(cnat_main_db) - free; - - vlib_cli_output(vm, "vCGN NAT44 Statistics :\n"); - vlib_cli_output(vm, "\tActive Translations : %u\n", - NAT44_COMMON_STATS.active_translations); - vlib_cli_output(vm, "\tTotal free translation entries : %u\n", free); - vlib_cli_output(vm, "\tTotal used translation entries : %u\n", used); - vlib_cli_output(vm, "\ti2o drops due to port limit exceeded : %lu\n", - in2out_drops_port_limit_exceeded); - vlib_cli_output(vm, "\ti2o drops due to system limit reached : %lu\n", - in2out_drops_system_limit_reached); - vlib_cli_output(vm, "\ti2o drops due to resource depletion : %lu\n", - in2out_drops_resource_depletion); - vlib_cli_output(vm, "\to2i drops due to no translations : %lu\n", - NAT44_COMMON_STATS.no_translation_entry_drops); - - vlib_cli_output(vm, "\tPool address usage:\n"); - vlib_cli_output(vm, "\t-------------------------------------------------\n"); - vlib_cli_output(vm, "\tExternal Address \tPorts Used\n"); - vlib_cli_output(vm, "\t-------------------------------------------------\n"); - - used = 0; - pool_foreach (my_vrfmap, cnat_map_by_vrf, ({ - pm = my_vrfmap->portmap_list; - pm_len = vec_len(pm); - for (i = 0; i < pm_len; i++) { - my_pm = pm + i; - if (my_pm->inuse) { - used++; - /* maximum of 200 addresses to be returned */ - if (used <= 200) { - ip.s_addr = ntohl(my_pm->ipv4_address); - vlib_cli_output(vm, "\t%s \t\t%u\n", inet_ntoa(ip), my_pm->inuse); - } - } - } - })); - return; -} - -void cnat_nat44_handle_show_config(vlib_main_t *vm) -{ - cnat_vrfmap_t * my_vrfmap; - cnat_portmap_v2_t *pm = 0; - cnat_portmap_v2_t *my_pm = 0; - u32 pm_len; - struct in_addr ip_addr; - u8 status_str[20]; - cnat_nfv9_logging_info_t *my_nfv9_logging_info, - *global_nfv9_logging_info = 0; - - vnet_hw_interface_t * hw; - vnet_main_t * vnm = vnet_get_main(); - - void cnat_nfv9_show_collector - (vlib_main_t *vm, cnat_nfv9_logging_info_t *my_nfv9_logging_info); - - vlib_cli_output(vm, "vCGN NAT44 Config:\n"); - vlib_cli_output(vm, "\tPort Limit : %u\n", cnat_main_db_max_ports_per_user); - vlib_cli_output(vm, "\ttotal address pool : %u\n", total_address_pool_allocated); - vlib_cli_output(vm, "\tdynamic port start range : %u\n", cnat_static_port_range); - - pool_foreach(my_vrfmap, cnat_map_by_vrf, ({ - hw = vnet_get_hw_interface (vnm, my_vrfmap->i_vrf); - vlib_cli_output(vm, "\tInside Interface : %v\n", hw->name); - hw = vnet_get_hw_interface (vnm, my_vrfmap->o_vrf); - vlib_cli_output(vm, "\tOutside Interface : %v\n", hw->name); - - memset(status_str, 0x00, sizeof(status_str)); - switch(my_vrfmap->status) { - case S_WAO: clib_memcpy(status_str, "S_WAO", 5); break; - case S_WA: clib_memcpy(status_str, "S_WA", 4); break; - case S_WO: clib_memcpy(status_str, "S_WO", 4); break; - case S_RUN: clib_memcpy(status_str, "ONLINE", 6); break; - case S_DEL: clib_memcpy(status_str, "S_DEL", 5); break; - default: clib_memcpy(status_str, "Invalid state", 13); - - } - vlib_cli_output(vm, - "\tAddress pool map table status : %s\n", status_str); - - pm = my_vrfmap->portmap_list; - pm_len = vec_len(pm); - my_pm = pm; - ip_addr.s_addr = clib_net_to_host_u32(my_pm->ipv4_address); - vlib_cli_output(vm, - "\tStart Address : %s\n", inet_ntoa(ip_addr)); - my_pm = pm + (pm_len - 1); - ip_addr.s_addr = clib_net_to_host_u32(my_pm->ipv4_address); - vlib_cli_output(vm, - "\tEnd Address : %s\n", inet_ntoa(ip_addr)); - - })); - vlib_cli_output(vm, - "\ttcp init timeout : %u sec\n", tcp_initial_setup_timeout); - vlib_cli_output(vm, - "\ttcp active timeout : %u sec\n", tcp_active_timeout); - vlib_cli_output(vm, - "\tudp init timeout : %u sec\n", udp_init_session_timeout); - vlib_cli_output(vm, - "\tudp active timeout : %u sec\n", udp_act_session_timeout); - vlib_cli_output(vm, - "\ticmp session timeout: %u sec\n", icmp_session_timeout); - -#if 0 - if (cnat_nfv9_global_info.cnat_nfv9_global_collector_index != EMPTY) { - vlib_cli_output(vm,"\nGloabal NFV9 Collector :"); - global_nfv9_logging_info = cnat_nfv9_logging_info_pool + - cnat_nfv9_global_info.cnat_nfv9_global_collector_index; - cnat_nfv9_show_collector(vm, global_nfv9_logging_info); - } -#endif - - vlib_cli_output(vm, "\nNFV9 Collector :"); - if (cnat_nfv9_logging_info_pool !=NULL) { - pool_foreach (my_nfv9_logging_info, cnat_nfv9_logging_info_pool, ({ - if (my_nfv9_logging_info != global_nfv9_logging_info) { - cnat_nfv9_show_collector(vm, my_nfv9_logging_info); - vlib_cli_output(vm, "\n"); - } - })); - } else { - vlib_cli_output(vm, "\n"); - } - - return; -} - -/* - * Check if the request flag matches the entry flags and - * if so return "1" - * - * entry_flag_ptr is an output parameter - it returns the flags - * corresponding to the translation entry - */ -static u8 cnat_v4_show_verify_display_entry ( - u16 request_flag, - cnat_main_db_entry_t *db, - u16 *entry_flag_ptr) -{ - u8 display_entry = 0; - - /* - * This should never happen - */ - if (!entry_flag_ptr) { - return (display_entry); - } - - *entry_flag_ptr = 0; - - if ((db->flags & CNAT_DB_FLAG_STATIC_PORT) - &&(db->flags & CNAT_DB_FLAG_ALG_ENTRY)) { - *entry_flag_ptr |= CNAT_TRANSLATION_ENTRY_STATIC; - *entry_flag_ptr |= CNAT_TRANSLATION_ENTRY_ALG; - } else if (db->flags & CNAT_DB_FLAG_STATIC_PORT) { - *entry_flag_ptr |= CNAT_TRANSLATION_ENTRY_STATIC; - } else if ((db->flags & CNAT_DB_FLAG_ALG_ENTRY) || - (db->flags & CNAT_DB_FLAG_PPTP_GRE_ENTRY)) { - *entry_flag_ptr |= CNAT_TRANSLATION_ENTRY_ALG; - } else if (db->flags & CNAT_DB_FLAG_PCPI) { - *entry_flag_ptr |= CNAT_TRANSLATION_ENTRY_PCPI_DYNAMIC; - } else if (db->flags & CNAT_DB_FLAG_PCPE) { - *entry_flag_ptr |= CNAT_TRANSLATION_ENTRY_PCPE_DYNAMIC; - } else { - *entry_flag_ptr |= CNAT_TRANSLATION_ENTRY_DYNAMIC; - } - - if (request_flag == CNAT_TRANSLATION_ENTRY_ALL) { - display_entry = 1; - } else { - /* - * Check if the request_flag is STATIC or ALG - * and the entry is STATIC or ALG as well - */ - if ((request_flag & CNAT_TRANSLATION_ENTRY_STATIC) && - (*entry_flag_ptr & CNAT_TRANSLATION_ENTRY_STATIC)) { - display_entry = 1; - } - - if ((request_flag & CNAT_TRANSLATION_ENTRY_ALG) && - (*entry_flag_ptr & CNAT_TRANSLATION_ENTRY_ALG)) { - display_entry = 1; - } - - if ((request_flag & CNAT_TRANSLATION_ENTRY_PCPI_DYNAMIC) && - (*entry_flag_ptr & CNAT_TRANSLATION_ENTRY_PCPI_DYNAMIC)) { - display_entry = 1; - } - - if ((request_flag & CNAT_TRANSLATION_ENTRY_PCPE_DYNAMIC) && - (*entry_flag_ptr & CNAT_TRANSLATION_ENTRY_PCPE_DYNAMIC)) { - display_entry = 1; - } - - /* - * For dynamic entry case, check if flags field is 0 - */ - if ((request_flag & CNAT_TRANSLATION_ENTRY_DYNAMIC) && - (*entry_flag_ptr & CNAT_TRANSLATION_ENTRY_DYNAMIC)) { - display_entry = 1; - } - } - - if (PREDICT_FALSE(show_debug_level > 2)) { - PLATFORM_DEBUG_PRINT("Entry (0x%x, %d) -> (0x%x, %d) request_flag 0x%x, entry_flag 0x%x, display_entry %d\n", db->in2out_key.k.ipv4, db->in2out_key.k.port, db->out2in_key.k.ipv4, db->out2in_key.k.port, request_flag, *entry_flag_ptr, display_entry); - } - - return (display_entry); -} -void cnat_v4_show_inside_entry_req_t_handler -(spp_api_cnat_v4_show_inside_entry_req_t *mp, vlib_main_t * vm) -{ - cnat_user_db_entry_t *udb = NULL; - cnat_main_db_entry_t *db = NULL; - cnat_db_key_bucket_t u_ki, ki; - u64 a, b, c; - u32 index; - u16 start_port, end_port, port; - u16 request_flag = 0; - u16 entry_flag = 0; - u8 num_entries = 0; - u8 proto, all; - u8 done = 0; - cnat_v4_show_translation_entry *entry_list; - cnat_v4_show_translation_entry entry[PLATFORM_MAX_TRANSLATION_ENTRIES]; - u8 display_entry; - u8 flag_str[11]; - vnet_hw_interface_t * hw; - vnet_main_t * vnm = vnet_get_main(); - - ki.k.k.ipv4 = mp->ipv4_addr; - ki.k.k.vrf = mp->vrf_id; - start_port = mp->start_port; - end_port = mp->end_port; -#if DEBUG - vlib_cli_output(vm, "## proto %d, inside-addr 0x%x, start_port %u, " - "end_port %u, vrf 0x%x, flag 0x%x\n", - mp->protocol, - mp->ipv4_addr, - mp->start_port, - mp->end_port, - mp->vrf_id, - mp->flags); -#endif - - proto = mp->protocol; - ki.k.k.vrf |= ((u16)proto << CNAT_PRO_SHIFT); - - all = mp->all_entries; /* for no port range case */ - request_flag = mp->flags; /* for all, alg, static entries case */ - entry_list = entry; - - /* - * check if the address is belonging to this core - */ - - - /* - * first we check if the user exists in the udb, if he is not then - * it does not make sense to check the main db for translations - */ - u_ki.k.k.vrf = ki.k.k.vrf & CNAT_VRF_MASK; - u_ki.k.k.ipv4 = ki.k.k.ipv4; - u_ki.k.k.port = 0; - - if (PREDICT_FALSE(show_debug_level > 0)) { - vlib_cli_output(vm, "\nI_TRANS_CORE %d: IPv4 0x%x, VRF 0x%x, " - "start_port %d, end_port %d", - my_instance_number, ki.k.k.ipv4, - ki.k.k.vrf, start_port, end_port); - } - - udb = cnat_user_db_lookup_entry(&u_ki); - if (!udb) { - if (PREDICT_FALSE(show_debug_level > 0)) { - vlib_cli_output(vm, "\nReturning %d entries", - num_entries); - } - return; - } - - if (all) { - #if 0 - if (PREDICT_FALSE(show_debug_level > 0)) { - PLATFORM_DEBUG_PRINT("\nI_TRANS: Printing ALL\n"); - } - - /* - * get the head of list of translation entries for that user - * from the user db - */ - head = udb->translation_list_head_index; - db = cnat_main_db + head; - - while (num_entries < PLATFORM_MAX_TRANSLATION_ENTRIES) { - - if (((db->in2out_key.k.vrf & CNAT_PRO_MASK) >> CNAT_PRO_SHIFT) - != proto) { - goto next_entry; - } - - display_entry = - spp_api_cnat_v4_show_verify_display_entry(request_flag, db, - &entry_flag); - - if (display_entry) { - entry_list->ipv4_addr = - spp_host_to_net_byte_order_32(db->out2in_key.k.ipv4); - entry_list->cnat_port = - spp_host_to_net_byte_order_16(db->out2in_key.k.port); - entry_list->src_port = - spp_host_to_net_byte_order_16(db->in2out_key.k.port); - - entry_list->protocol = proto; - - /* incase of gre - in2out is not accounted */ - if(proto != CNAT_PPTP) { - - entry_list->in2out_packets = - spp_host_to_net_byte_order_32(db->in2out_pkts); - } else { - entry_list->in2out_packets = 0; - } - entry_list->out2in_packets = - spp_host_to_net_byte_order_32(db->out2in_pkts); - - entry_list->flags = - spp_host_to_net_byte_order_16(entry_flag); - - num_entries++; - entry_list = entry_list + 1; - } -next_entry: - db = cnat_main_db + db->user_ports.next; - /* - * its a circular list, so if we have reached the head again - * all the entries for that user have been read - */ - if (db == (cnat_main_db + head)) { - break; - } - } - resp->num_entries = num_entries; - #endif /* if 0 */ - } else { - if (PREDICT_FALSE(show_debug_level > 0)) { - vlib_cli_output(vm, "\nI_TRANS: Printing range %d .. %d\n", - start_port, end_port); - } - /* - * port range is specified so for each port calculate the hash and - * check if the entry is present in main db - */ - port = start_port; - done = 0; - while ((!done) && (num_entries < PLATFORM_MAX_TRANSLATION_ENTRIES)) { - - ki.k.k.port = port; - if (port >= end_port) { - done = 1; - } else { - port++; - } - CNAT_V4_GET_HASH(ki.k.key64, - ki.bucket, - CNAT_MAIN_HASH_MASK); - index = cnat_in2out_hash[ki.bucket].next; - if (PREDICT_TRUE(index == EMPTY)) { - continue; - } - - do { - db = cnat_main_db + index; - if (db->in2out_key.key64 == ki.k.key64) { - break; - } - index = db->in2out_hash.next; - } while (index != EMPTY); - - if (index == EMPTY) { - continue; - } else { - - display_entry = - cnat_v4_show_verify_display_entry(request_flag, db, - &entry_flag); - if (display_entry) { - - entry_list->ipv4_addr = - clib_host_to_net_u32(db->out2in_key.k.ipv4); - entry_list->cnat_port = - clib_host_to_net_u16(db->out2in_key.k.port); - entry_list->src_port = - clib_host_to_net_u16(db->in2out_key.k.port); - - entry_list->protocol = proto; - entry_list->nsessions = db->nsessions; - entry_list->flags = ((db->flags & CNAT_DB_FLAG_TCP_ACTIVE) || - (db->flags & CNAT_DB_FLAG_UDP_ACTIVE)) ? 1:0; - /* incase of gre - in2out is not accounted */ - if(proto != CNAT_PPTP) { - entry_list->in2out_packets = - clib_host_to_net_u32(db->in2out_pkts); - } else { - entry_list->in2out_packets = 0; - } - - entry_list->out2in_packets = - clib_host_to_net_u32(db->out2in_pkts); - - if (PREDICT_FALSE(show_debug_level > 3)) { - vlib_cli_output(vm, "\n1. Entry: Addr 0x%x, port %d, num_entries %d", - clib_net_to_host_u32(entry_list->ipv4_addr), - clib_net_to_host_u16(entry_list->cnat_port), - num_entries); - } - - entry_list = entry_list + 1; - num_entries++; - } - } /* if (index == EMPTY) */ - } /* while() */ - } - - if (PREDICT_FALSE(show_debug_level > 0)) { - if (num_entries) { - vlib_cli_output(vm, "\nReturning %d entries\n", - num_entries); - } - } - - entry_list = entry; - u8 i = 0; - struct in_addr ip; - u8 proto_str[10]; - u8 transl_str[10]; - memset(proto_str, 0x00, 10); - memset(transl_str, 0x00, 10); - - if (proto == 1) strncpy((char *)proto_str, "udp", 3); - else if (proto == 2) strncpy((char *)proto_str, "tcp", 3); - else if (proto == 3) strncpy((char *)proto_str, "icmp", 4); - else strncpy((char *)proto_str, "unknown", 7); - - if (request_flag == 0x04) strncpy((char *)transl_str, "Dynamic", 7); - else strncpy((char *)transl_str, "Unknown", 7); /* currently we are not supporting static/alg entries */ - - ip.s_addr = clib_net_to_host_u32(u_ki.k.k.ipv4); - hw = vnet_get_hw_interface (vnm, u_ki.k.k.vrf); - - vlib_cli_output (vm, "Inside-translation details\n"); - vlib_cli_output (vm, "--------------------------\n"); - - vlib_cli_output (vm, "Inside interface : %s\n", hw->name); - vlib_cli_output (vm, "Inside address : %s\n", inet_ntoa(ip)); - vlib_cli_output (vm, "Start port : %u\n", start_port); - vlib_cli_output (vm, "End port : %u\n", end_port); - - vlib_cli_output (vm, "--------------------------------------------------------------------------------------" - "-----------------------\n"); - vlib_cli_output (vm, "Outside Protocol Inside Outside Translation" - " I2O O2I Flag Num\n"); - vlib_cli_output (vm, "Address Src Port Src Port Type " - " Pkts Pkts Sessions\n"); - vlib_cli_output (vm, "--------------------------------------------------------------------------------------" - "-----------------------\n"); - - while ((num_entries) && (entry_list) && (i < 50)) { - - ip.s_addr = entry_list->ipv4_addr; - memset(flag_str,0x00,11); - if((proto == 1) || (proto == 2)) { - if(entry_list->flags == 1) { - strncpy((char *)flag_str,"Active",6); - } - else { - strncpy((char *) flag_str,"Non Active",10); - } - } else { - strncpy((char *) flag_str, "NA", 2); - } - vlib_cli_output(vm, "%s %10s %11u %12u %13s %10u %10u %14s %6u\n", - inet_ntoa(ip), proto_str, - clib_net_to_host_u16(entry_list->src_port), - clib_net_to_host_u16(entry_list->cnat_port), - transl_str, - clib_net_to_host_u32(entry_list->in2out_packets), - clib_net_to_host_u32(entry_list->out2in_packets), - flag_str, - entry_list->nsessions); - entry_list++; - num_entries--; i++; - } - - return; -} - -void cnat_v4_show_outside_entry_req_t_handler -(spp_api_cnat_v4_show_outside_entry_req_t *mp, vlib_main_t *vm) -{ - cnat_main_db_entry_t *db = NULL; - cnat_db_key_bucket_t ko; - u64 a, b, c; - u32 index; - u16 start_port, end_port, port; - u16 request_flag = 0; - u16 entry_flag = 0; - u8 num_entries = 0; - u8 proto; - cnat_v4_show_translation_entry *entry_list; - cnat_v4_show_translation_entry entry[PLATFORM_MAX_TRANSLATION_ENTRIES]; - u8 done = 0; - u8 display_entry; - u8 flag_str[11]; - vnet_hw_interface_t * hw; - vnet_main_t * vnm = vnet_get_main(); - - ko.k.k.ipv4 = mp->ipv4_addr; - ko.k.k.vrf = mp->vrf_id; - start_port = mp->start_port; - end_port = mp->end_port; - - proto = mp->protocol; - request_flag = mp->flags; - - ko.k.k.vrf |= ((u16)proto << CNAT_PRO_SHIFT); - - entry_list = entry; - - if (PREDICT_FALSE(show_debug_level > 0)) { - vlib_cli_output(vm, "\nO_TRANS_CORE %d: IPv4 0x%x, VRF 0x%x, " - "start_port %d, end_port %d", my_instance_number, - ko.k.k.ipv4, ko.k.k.vrf, start_port, end_port); - } - - /* - * for each ip and port combination we need to scan the main db - * and check if the entry is present in main db - */ - port = start_port; - done = 0; - while ((!done) && (num_entries < PLATFORM_MAX_TRANSLATION_ENTRIES)) { - ko.k.k.port = port; - - /* - * If we have reached the end_port, we are DONE - */ - if (port >= end_port) { - done = 1; - } else { - port++; - } - - CNAT_V4_GET_HASH(ko.k.key64, - ko.bucket, - CNAT_MAIN_HASH_MASK); - - index = cnat_out2in_hash[ko.bucket].next; - if (PREDICT_TRUE(index == EMPTY)) { - continue; - } - - do { - db = cnat_main_db + index; - if (db->out2in_key.key64 == ko.k.key64) { - break; - } - index = db->out2in_hash.next; - } while (index != EMPTY); - - if (index == EMPTY) { - continue; - } else { - display_entry = - cnat_v4_show_verify_display_entry(request_flag, db, - &entry_flag); - - if (display_entry) { - entry_list->ipv4_addr = - clib_host_to_net_u32(db->in2out_key.k.ipv4); - entry_list->cnat_port = - clib_host_to_net_u16(db->out2in_key.k.port); - entry_list->src_port = - clib_host_to_net_u16(db->in2out_key.k.port); - entry_list->protocol = proto; - entry_list->nsessions = db->nsessions; - entry_list->flags = ((db->flags & CNAT_DB_FLAG_TCP_ACTIVE) || - (db->flags & CNAT_DB_FLAG_UDP_ACTIVE)) ? 1:0; - /* incase of gre - in2out is not accounted */ - if(proto != CNAT_PPTP) { - entry_list->in2out_packets = - clib_host_to_net_u32(db->in2out_pkts); - } else { - entry_list->in2out_packets = 0 ; - } - entry_list->out2in_packets = - clib_host_to_net_u32(db->out2in_pkts); - #if 0 - entry_list->flags = - clib_host_to_net_u16(entry_flag); - #endif - entry_list = entry_list + 1; - num_entries++; - } - } - } - - if (num_entries == 0) { - /* No point proceeding further */ - return; - } - - if (PREDICT_FALSE(show_debug_level > 0)) { - if (num_entries) { - vlib_cli_output(vm, "\nO_TRANS: Core %d returning %d entries", - num_entries); - } - } - - entry_list = entry; - u8 i = 0; - struct in_addr ip; - u8 proto_str[10]; - u8 transl_str[10]; - memset(proto_str, 0x00, 10); - memset(transl_str, 0x00, 10); - - if (proto == 1) strncpy((char *) proto_str, "udp", 3); - else if (proto == 2) strncpy((char *) proto_str, "tcp", 3); - else if (proto == 3) strncpy((char *) proto_str, "icmp", 4); - else strncpy((char *) proto_str, "unknown", 7); - - if (request_flag == 0x04) strncpy((char *) transl_str, "Dynamic", 7); - else strncpy((char *)transl_str, "Unknown", 7); /* currently we are not supporting static/alg entries */ - - ip.s_addr = clib_net_to_host_u32(ko.k.k.ipv4); - hw = vnet_get_hw_interface (vnm, (ko.k.k.vrf & CNAT_VRF_MASK)); - - vlib_cli_output (vm, "Outside-translation details\n"); - vlib_cli_output (vm, "--------------------------\n"); - - vlib_cli_output (vm, "Outside interface : %s\n", hw->name); - vlib_cli_output (vm, "Outside address : %s\n", inet_ntoa(ip)); - vlib_cli_output (vm, "Start port : %u\n", start_port); - vlib_cli_output (vm, "End port : %u\n", end_port); - - vlib_cli_output (vm, "--------------------------------------------------------------------------------------" - "-----------------------\n"); - vlib_cli_output (vm, "Inside Protocol Outside Inside Translation" - " I2O O2I Flag Num\n"); - vlib_cli_output (vm, "Address Dst Port Dst Port Type " - " Pkts Pkts Sessions\n"); - vlib_cli_output (vm, "--------------------------------------------------------------------------------------" - "-----------------------\n"); - - while ((num_entries) && (entry_list) && (i < 50)) { - ip.s_addr = entry_list->ipv4_addr; - memset(flag_str,0x00,11); - if((proto == 1) || (proto == 2)) { - if(entry_list->flags == 1) { - strncpy((char *) flag_str,"Active",6); - } - else { - strncpy((char *) flag_str,"Non Active",10); - } - } else { - strncpy((char *) flag_str, "NA", 2); - } - vlib_cli_output(vm, "%s %10s %11u %12u %13s %10u %10u %14s %6u\n", - inet_ntoa(ip), proto_str, - clib_net_to_host_u16(entry_list->cnat_port), - clib_net_to_host_u16(entry_list->src_port), - transl_str, - clib_net_to_host_u32(entry_list->in2out_packets), - clib_net_to_host_u32(entry_list->out2in_packets), - flag_str, - entry_list->nsessions); - entry_list++; - num_entries--; i++; - - } - return; -} diff --git a/plugins/vcgn-plugin/vcgn/cnat_common_api.h b/plugins/vcgn-plugin/vcgn/cnat_common_api.h deleted file mode 100644 index a4eb7443..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_common_api.h +++ /dev/null @@ -1,22 +0,0 @@ -/*--------------------------------------------------------------------------- - * Copyright (c) 2009-2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *--------------------------------------------------------------------------- - */ -#ifndef __CNAT_COMMON_API_H__ -#define __CNAT_COMMON_API_H__ - -/* All common API prototypes */ -void cnat_scanner_db_process_turn_on(vlib_main_t *vm); - -#endif diff --git a/plugins/vcgn-plugin/vcgn/cnat_config.c b/plugins/vcgn-plugin/vcgn/cnat_config.c deleted file mode 100644 index 87183dfa..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_config.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_config.c - configuration definitions - * - * Copyright (c) 2007-2012 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ -#include "cnat_config.h" -#include "cnat_cli.h" -#include "cnat_v4_pptp_alg.h" -#include "platform_common.h" - -/* session timeout */ - -u16 tcp_initial_setup_timeout = V4_DEF_TCP_IS_TO; /* sec */ -u16 tcp_active_timeout = V4_DEF_TCP_AS_TO; /* sec */ -u16 udp_init_session_timeout = V4_DEF_UDP_IS_TO; /* 30 sec */ -u16 udp_act_session_timeout = V4_DEF_UDP_AS_TO; /* 2 min */ -u16 icmp_session_timeout = V4_DEF_ICMP_S_TO; /* 60 sec */ - -cnat_pptp_config_t pptp_cfg = - { - .enable = PPTP_DISABLED, - .timeout = PPTP_GRE_TIMEOUT - } ; - -/* This flag is used as indication of timeout related config - * changes and hence db needs to be updated - */ -u8 timeout_dirty_flag = 0; - -/* mapping refresh direction, - * 1 inbound and outbound refresh - */ -u8 mapping_refresh_both_direction = V4_DEF_ENABLE; - -u16 cnat_main_db_max_ports_per_user = V4_DEF_MAX_PORTS; - -u32 cnat_main_db_icmp_rate_limit = DEF_RATE_LIMIT; -u32 cnat_main_db_icmp_rate_limit_core = DEF_RATE_LIMIT_CORE; -u32 crc_zero_udp_rate_limit_core = RATE_LIMIT_UDP_CORE; -u16 cnat_static_port_range = CNAT_DEF_STATIC_PORT_RANGE; - - -/* - * ftp alg enable - */ -u8 ftp_alg_enabled = V4_DEF_DISABLE; -u16 rtsp_alg_port_num = 0; - -/* - * load balancing debug mode - */ -u8 lb_debug_enable = V4_DEF_DISABLE; - - -/* good or evil mode - * 0 endpoint-independnet filter, good mode - * 1 address depedent filter, evil mode - */ -u8 address_dependent_filtering = V4_DEF_DISABLE; - -u16 per_user_icmp_msg_limit = ICMP_MSG_RATE_LIMIT; - -u16 config_delete_timeout = V4_CONFIG_DELETE_TO; - diff --git a/plugins/vcgn-plugin/vcgn/cnat_config.h b/plugins/vcgn-plugin/vcgn/cnat_config.h deleted file mode 100644 index f1042737..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_config.h +++ /dev/null @@ -1,582 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_config.h - configuration database definitions - * - * Copyright (c) 2007-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef __CNAT_CONFIG_H__ -#define __CNAT_CONFIG_H__ - -#include -#include - -#include "cnat_bulk_port_defs.h" - -/* default policy value */ -#define V4_DEF_ICMP_S_TO 60 /*icmp session timeout */ -#define V4_DEF_UDP_IS_TO 30 /*udp init session timeout */ -#define V4_DEF_UDP_AS_TO 120 /*udp active session timeout */ -#define V4_DEF_TCP_IS_TO 120 /*tcp init session timeout */ -#define V4_DEF_TCP_AS_TO 1800 /*tcp active session timeout, 30 min */ -#define V4_DEF_TCP_MSS 1460 /*tcp mss */ -#define V4_DEF_MAX_PORTS 100 /*max port limit per user */ -#define DEF_RATE_LIMIT PLATFORM_MAX_CORES /* No of packets/sec icmp generated */ -#define DEF_RATE_LIMIT_CORE 1 /* No of packets/sec icmp generated (per core) */ -#define RATE_LIMIT_UDP_CORE 1000 /* Max allowed udp crc zero packets/sec/core */ - -#define NAT44_RESERVED_INST_ID 1 -#define DSLITE_START_ID (NAT44_RESERVED_INST_ID + 1) -#define V4_DEF_VRF_MAX_PORTS 0 /*max port limit per vrf user; - 0 means use the global port limit for user*/ -/*Hardcoded . TBD - can be made configurable */ - -#define V4_DEF_ENABLE 1 /* feature enable */ -#define V4_DEF_DISABLE 0 /* feature disable */ - -#define CNAT_DEF_STATIC_PORT_RANGE 1024 /* Default range for static ports */ -/* - * If TCP MSS is not configured, store the maximum possible value - */ -#define V4_TCP_MSS_NOT_CONFIGURED_VALUE 0xffff - -/* default timeout for fragments in seconds set to 2 - * in case its not configured - */ -#define CNAT_IPV4_FRAG_TIMEOUT_DEF 2 -/* other */ -/* max db entries to be scaned */ -#define MAX_DB_ENTRY_PER_SCAN PLATFORM_MAX_DB_ENTRY_PER_SCAN -/* max db entries selected per scan */ -#define MAX_DB_ENTRY_SELECTED_PER_SCAN PLATFORM_MAX_DB_ENTRY_SELECTED_PER_SCAN - -#define ICMP_MSG_RATE_LIMIT 3 /* rate limit for icmp message */ -#define V4_CONFIG_DELETE_TO 600 /* timeout for entry to be deleted */ - -/* session timeout */ - -extern u16 tcp_initial_setup_timeout; -extern u16 tcp_active_timeout; -extern u16 udp_init_session_timeout; -extern u16 udp_act_session_timeout; -extern u16 icmp_session_timeout; - -extern u8 timeout_dirty_flag; - -/* mapping refresh direction, - * 0 outbound only refresh, - * 1 inbound and outbound refresh - */ -extern u8 mapping_refresh_both_direction; - - -extern u16 cnat_main_db_max_ports_per_user; -extern u32 cnat_main_db_icmp_rate_limit; -extern u32 cnat_main_db_icmp_rate_limit_core; -extern u32 crc_zero_udp_rate_limit_core; - -extern u16 cnat_static_port_range; - -typedef enum { - LOG_FORMAT_UNDEFINED =0, - LOG_FORMAT_COMPACT, - LOG_FORMAT_NF9, - LOG_FORMAT_MAX, /* keep this as last */ -} log_format_t; - -typedef enum { - CNAT_CONFIG_DEL_OP = 0, - CNAT_CONFIG_ADD_OP, -} cnat_op_flag_t; - -extern u8 ftp_alg_enabled; -extern u16 rtsp_alg_port_num; - -/* - * load balancing debug mode - */ -extern u8 lb_debug_enable; - -/* good or evil mode - * 0 endpoint-independnet filter, good mode - * 1 address depedent filter, evil mode - */ -extern u8 address_dependent_filtering; - -extern u16 per_user_icmp_msg_limit; - -/* vrfmap or portmap holding time - * after delete - */ -extern u16 config_delete_timeout; - -/* - * Bit map for various configuration in the POLICY KNOB case - */ -#define BIDIR_REFRESH_ENABLE 0x01 -#define BIDIR_REFRESH_DISABLE 0x02 -#define FTP_ALG_ENABLE 0x04 -#define FTP_ALG_DISABLE 0x08 -#define DEFAULT_NFV9_LOGGING_SERVER_ENABLE 0x10 -#define DEFAULT_NFV9_LOGGING_SERVER_DISABLE 0x20 - - -/* - * This structure contains a single VRF map configuration - * from a bulk message. This structure is in conformanace - * with the following structures defined in cnat_config_api.h - * - spp_api_cnat_v4_bulk_vrf_map_t - * - * Any change in the above structures should be propagated here - */ -typedef struct _spp_api_cnat_v4_single_vrf_map_req { - u32 i_vrf_id; - u32 o_vrf_id; - - u16 i_vrf; - u16 o_vrf; - - u32 start_addr; - u32 end_addr; - - u16 vrf_policy_enable; -#define TCP_MSS_ENABLE 0x0001 -#define TCP_MSS_DISABLE 0x0002 -#define NFV9_LOGGING_ENABLE 0x0004 -#define NFV9_LOGGING_DISABLE 0x0008 -#define VRF_MAP_DELETE 0x0010 -#define VRF_MAP_ADD 0x0020 -#define BULK_ALLOC_CHANGE 0x0040 - - u16 tcp_mss_value; - u32 vrf_nfv9_logging_ipv4_address; - u16 vrf_nfv9_logging_udp_port; - u16 vrf_nfv9_refresh_rate; - u16 vrf_nfv9_timeout_rate; - u16 vrf_nfv9_path_mtu; -#ifndef NO_BULK_LOGGING - bulk_alloc_size_t bulk_size; -#endif /* NO_BULK_LOGGING */ -} spp_api_cnat_v4_single_vrf_map_req; - -typedef struct _spp_api_cnat_v4_single_vrf_map_rc { - u8 vrf_map_rc; - u8 tcp_mss_rc; - u8 nfv9_logging_rc; - u8 pad; -} spp_api_cnat_v4_single_vrf_map_rc; - -/* - * Bulk Response for the VRF map request - */ -typedef struct _spp_api_cnat_v4_bulk_vrf_map_resp { - u16 _spp_msg_id; - u8 bulk_rc; - u8 pad; - - u32 num_vrfmap_entries; - - spp_api_cnat_v4_single_vrf_map_rc vrf_map_rc; - -} spp_api_cnat_v4_bulk_vrf_map_resp; - -/* - * Bulk Response for the Policy Knob request - */ -typedef struct _spp_api_cnat_v4_bulk_policy_knob_resp { - u16 _spp_msg_id; - u8 bulk_rc; /* Global rc code */ - u8 pad; - - u8 port_limit_rc; - u8 icmp_timeout_rc; - u8 udp_init_timeout_rc; - u8 udp_act_timeout_rc; - - u8 tcp_init_timeout_rc; - u8 tcp_act_timeout_rc; - u8 nfv9_logging_rc; - u8 pad2; -} spp_api_cnat_v4_bulk_policy_knob_resp; - - -/* PPTP ALG defs and structures */ - -/* dont change the order.. - maintened at offset mapped to msg ids */ - -typedef struct pptp_ctrl_msg_ctrs_t { - u64 dummy; - u64 sccr; - u64 sccrp; - u64 stccrq; - u64 stccrp; - u64 erq; - u64 erp; - u64 ocrq; - u64 ocrp; - u64 icrq; - u64 icrp; - u64 iccn; - u64 cclr; - u64 cdn; - u64 wen; - u64 sli; -}pptp_ctrl_msg_ctrs_t; - -#define PPTP_INCR(ctr) pptp_cfg.counters.pptp_##ctr++ -#define PPTP_DECR(ctr) pptp_cfg.counters.pptp_##ctr-- - -typedef struct pptp_counters_t { - - u64 pptp_ctrl_msg_drops; - u64 pptp_active_tunnels; - u64 pptp_active_channels; - u64 pptp_in2out_gre_drops; - u64 pptp_out2in_gre_drops; - u64 pptp_in2out_gre_fwds; - u64 pptp_out2in_gre_fwds; - pptp_ctrl_msg_ctrs_t ctrl_ctrs; - -} pptp_counters_t; - -#define CNAT_PPTP_ENABLE 1 -#define CNAT_PPTP_DEF_TIMEOUT 60 /* secs */ - -typedef struct cnat_pptp_config_t { - u8 enable; - u16 timeout; - pptp_counters_t counters; - -} cnat_pptp_config_t; - - -#define CNAT_PPTP_ENABLE_FLAG 0x01 -#define CNAT_PPTP_TIMEOUT_FLAG 0x02 - -/* pptp config msg resp */ -typedef struct _spp_api_cnat_v4_config_pptp_alg_resp { - u16 _spp_msg_id; - u8 bulk_rc; - u8 pad; - -} spp_api_cnat_v4_config_pptp_alg_resp_t; - -typedef struct { - u16 msg_id; - u8 rc; - u8 pad[5]; - - /* better to have a group structures rather than individual - variables, any change in counters is will automatically - reflect here */ - pptp_counters_t counters; -} pptp_show_counters_resp_t ; - - -extern cnat_pptp_config_t pptp_cfg; - - -/* ========= 6RD declarations =============================== */ - -#define V6RD_ENTRY_DELETE 0x00 -#define IPV4_TUNNEL_SRC_CONFIG 0x04 -#define TUNNEL_MTU_CONFIG 0x08 -#define IPV4_PREFIXMASK_LEN_CONFIG 0x10 -#define IPV4_SUFFIXMASK_LEN_CONFIG 0x20 -#define TTL_CONFIG 0x40 -#define TOS_CONFIG 0x80 -#define V6RD_IPV6_PREFIX_CONFIG 0x100 -#define V6RD_RESET_DF_BIT_CONFIG 0x200 -#define V6RD_UNICAST_ADDR_CONFIG 0x400 -#define V6RD_REASSEMB_CONFIG 0x800 - -#define TTL_ENABLE 0x1 -#define TOS_ENABLE 0x2 -#define RESET_DF_BIT 0x4 -#define REASSEMBLY_ENABLE 0x8 - -/* ========= 6RD declarations =============================== */ - -/* - * Single Request for XLAT config - */ -typedef struct _spp_api_cnat_v4_single_xlat_config_req { - - /* - * Indicates the xlat instance id - How big will this value be - * Can we restrict it between 0..255, that way the APP code - * can use an array to store the xlat instances. - */ - u32 xlat_id; - -#define XLAT_ENTRY_DELETE 0x0000 -#define IPV6_SVI_IF_NUM_CONFIG 0x0001 -#define IPV4_SVI_IF_NUM_CONFIG 0x0002 -#define IPV4_TO_IPV6_TCP_MSS_CONFIG 0x0004 -#define IPV6_TO_IPV4_TCP_MSS_CONFIG 0x0008 -#define IPV6_PREFIX_CONFIG 0x0010 -#define IPV6_UBIT_ON_CONFIG 0x0020 -#define IPV6_NON_TRANSLATABLE_PREFIX_MAP_CONFIG 0x0040 -#define IPV4_TOS_SETTING_CONFIG 0x0080 -#define IPV6_TOS_SETTING_CONFIG 0x0100 -#define IPV4_DFBIT_CLEAR_CONFIG 0x0200 -#define ICMPV6_PTB_MTU_SET_CONFIG 0x0400 -#define IPV6_NON_TRANSLATABLE_PREFIX_MAP_ALG_CONFIG 0x0800 -#define CPE_V4_PREFIX_CONFIG 0x1000 /* for map-t */ -#define CPE_V6_PREFIX_CONFIG 0x2000 /* for map-t */ -#define EXTERNAL_V6_PREFIX_CONFIG 0x4000 /* for map-t */ -#define PORT_SHARING_RATIO_CONFIG 0x8000 /* for map-t */ -#define CONSECUTIVE_PORTS_CONFIG 0x10000 /* for map-t */ - - u32 xlat_config_fields_enable; - - /* - * If numbers of the IPv6 and IPv4 SVI interfaces - */ - u32 ipv6_svi_if_num; - u32 ipv4_svi_if_num; - - /* - * TCP MSS values for the 2 XLAT directions - */ - u16 v4_to_v6_tcp_mss; - u16 v6_to_v4_tcp_mss; - - /* - * XLAT IPv6 prefix - */ - u32 v6_prefix[4]; - - /* - * XLAT IPv6 prefix mask - */ - u8 v6_prefix_mask_len; - - /* - * Set to non-zero if UBITs are reserved - */ -#define UBITS_ON 0x01 -#define IPV4_DF_BIT_CLEAR 0x02 -#define ICMPV6_MTU_SET 0x04 -#define IPV4_TOS_SET_ENABLED 0x08 -#define IPV6_TC_SET_ENABLED 0x10 - - u8 feature_enable_bits; - - u8 v4_prefix_mask_len; - -#define IPV6_NON_TRANSLATABLE_PREFIX_MAP_ALG_HASH 0x1 -#define IPV6_NON_TRANSLATABLE_PREFIX_MAP_ALG_TTL 0x2 -#define IPV6_NON_TRANSLATABLE_PREFIX_MAP_ALG_RANDOM 0x3 - u8 non_translatable_v6_prefix_v4_map_prefix_alg; - - u8 ipv6_tos_value; - - u8 ipv4_tos_value; - - u8 pad2; - - u8 pad3; - - u32 v4_prefix; - - /* - * MAP-T/MAP-E specific parameters - */ - u8 xlat_type; - - u32 cpe_domain_v6_prefix[4]; - u8 cpe_domain_v6_prefix_len; - - u32 cpe_domain_v4_prefix; - u8 cpe_domain_v4_prefix_len; - - u32 external_domain_v6_prefix[4]; - u8 external_domain_v6_prefix_len; - - u8 port_sharing_ratio_bits; - u8 consecutive_ports_bits; - -} spp_api_cnat_v4_single_xlat_config_req; - -/* - * Single Response for the xlat config request - */ -typedef struct _spp_api_cnat_v4_single_xlat_config_resp { - u8 v4_if_num_rc; - u8 v6_if_num_rc; - u8 v4_to_v6_tcp_mss_rc; - u8 v6_to_v4_tcp_mss_rc; - - u8 v6_prefix_rc; - u8 ubit_on_rc; - u8 v4_prefix_rc; - u8 xlat_id_rc; - - u8 non_translatable_v6_prefix_v4_map_alg_rc; - u8 ipv4_dfbit_clear_rc; - u8 icmpv6_ptb_mtu_set_rc; - u8 ipv4_tos_set_rc; - - u8 ipv6_tos_set_rc; - u8 pad1; - u8 pad2; - u8 pad3; -} spp_api_cnat_v4_single_xlat_config_resp; - -/* - * Bulk Response for the xlat config request - */ -typedef struct _spp_api_cnat_v4_bulk_xlat_config_resp { - u16 _spp_msg_id; - u16 pad; - - u32 bulk_rc; - - u32 num_xlat_entries; - - spp_api_cnat_v4_single_xlat_config_resp xlat_config_resp; - -} spp_api_cnat_v4_bulk_xlat_config_resp; - -typedef struct _spp_api_v6rd_v4_single_v6rd_config_resp { - u8 v6rd_id_rc; - u8 v4_if_num_rc; - u8 v6_if_num_rc; - u8 tunnel_source_rc; - u8 tunnel_mtu_rc; - u8 ipv4masklen_prefix_rc; - u8 ipv4masklen_suffix_rc; - u8 ttl_rc; - u8 tos_rc; - u8 anycast_rc; - u8 v6_prefix_rc; - u8 v6_br_unicast_rc; - u8 reassembly_rc; - u8 pad1; - u8 pad2; - u8 pad3; -} spp_api_v6rd_v4_single_v6rd_config_resp_t; - -typedef struct _spp_api_v6rd_v4_bulk_v6rd_config_resp { - u16 _spp_msg_id; - u16 pad; - u32 bulk_rc; - u32 num_v6rd_entries; - spp_api_v6rd_v4_single_v6rd_config_resp_t v6rd_config_resp[0]; -} spp_api_v6rd_v4_bulk_v6rd_config_resp_t; - -/* - * Single Request for MAPE config - */ -typedef struct _spp_api_mape_single_config_req { - - /* - * Indicates the mape instance id - How big will this value be - * Can we restrict it between 0..255, that way the APP code - * can use an array to store the xlat instances. - */ - u32 mape_id; - -#define MAPE_ENTRY_DELETE 0x0000 -#define MAPE_IPV4_SVI_IF_NUM_CONFIG 0x0001 -#define MAPE_IPV6_SVI_IF_NUM_CONFIG 0x0002 -#define MAPE_IPV4_TO_IPV6_TCP_MSS_CONFIG 0x0004 -#define MAPE_IPV6_TO_IPV4_TCP_MSS_CONFIG 0x0008 -#define MAPE_CPE_V4_PREFIX_CONFIG 0x0010 -#define MAPE_CPE_V6_PREFIX_CONFIG 0x0020 -#define MAPE_PORT_SHARING_RATIO_CONFIG 0x0040 -#define MAPE_CONSECUTIVE_PORTS_CONFIG 0x0080 -#define MAPE_PATH_MTU 0x0100 -#define MAPE_TUNNEL_ENDPOINT_V6_CONFIG 0x0200 - - u32 mape_config_fields_enable; - - /* - * If numbers of the IPv6 and IPv4 SVI interfaces - */ - u32 ipv6_svi_if_num; - u32 ipv4_svi_if_num; - - /* - * TCP MSS values for the 2 XLAT directions - */ - u16 v4_to_v6_tcp_mss; - u16 v6_to_v4_tcp_mss; - - /* - * Path v6 MTU. - */ - u32 path_mtu; - - /* - * CPE IPv6 prefix and mask len. - */ - u32 cpe_domain_v6_prefix[4]; - u8 cpe_domain_v6_prefix_len; - - /* - * CPE IPv4 prefix and mask len. - */ - u32 cpe_domain_v4_prefix; - u8 cpe_domain_v4_prefix_len; - - /* - * BR IPv6 tunnel end point V6 prefix and mask len. - */ - u32 aftr_tunnel_endpoint_address_v6[4]; - u8 aftr_tunnel_endpoint_address_v6_len; - - /* - * BR IPv6 tunnel end point V6 prefix and mask len. - */ - u8 port_sharing_ratio_bits; - u8 consecutive_ports_bits; - -} spp_api_mape_single_config_req; - - -/* - * Single Response for the mape config response - */ -typedef struct _spp_api_mape_single_config_resp { - u8 v4_if_num_rc; - u8 v6_if_num_rc; - u8 v4_to_v6_tcp_mss_rc; - u8 v6_to_v4_tcp_mss_rc; - u8 mape_id_rc; - u8 path_mtu_rc; - u8 cpe_v6_prefix_rc; - u8 cpe_v4_prefix_rc; - u8 tunnel_endpoint_prefix_rc; - u8 port_sharing_ratio_rc; - u8 port_contiguous_rc; - u8 pad1; -} spp_api_mape_single_config_resp; - -/* - * Bulk Response for the mape config request - */ -typedef struct _spp_api_mape_bulk_config_resp { - u16 _spp_msg_id; - u16 pad; - u32 bulk_rc; - u32 num_mape_entries; - spp_api_mape_single_config_resp mape_config_resp; -} spp_api_mape_bulk_config_resp; - - -#endif /* __CNAT_CONFIG_H__ */ diff --git a/plugins/vcgn-plugin/vcgn/cnat_config_api.h b/plugins/vcgn-plugin/vcgn/cnat_config_api.h deleted file mode 100644 index 0789d6a9..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_config_api.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __CNAT_CONFIG_API_H__ -#define __CNAT_CONFIG_API_H__ - -typedef struct _spp_api_cnat_v4_add_vrf_map { - u16 _spp_msg_id; - u8 rc; - u8 pad; - u32 i_vrf_id; - u32 o_vrf_id; - u16 i_vrf; - u16 o_vrf; - u32 start_addr[8]; - u32 end_addr[8]; -} spp_api_cnat_v4_add_vrf_map_t; - -typedef struct _spp_api_cnat_v4_config_nfv9_logging { - u16 _spp_msg_id; - u8 rc; - u8 enable; - u32 ipv4_address; - u32 i_vrf_id; - u16 i_vrf; - u16 port; - u16 refresh_rate; - u16 timeout_rate; - u16 path_mtu; - u8 nfv9_global_collector; - u8 session_logging; -} spp_api_cnat_v4_config_nfv9_logging_t; - - -#endif diff --git a/plugins/vcgn-plugin/vcgn/cnat_db.h b/plugins/vcgn-plugin/vcgn/cnat_db.h deleted file mode 100644 index 3596e238..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_db.h +++ /dev/null @@ -1,701 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_db.h - translation database definitions - * - * Copyright (c) 2007-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef __CNAT_DB_H__ -#define __CNAT_DB_H__ - -#include "cnat_cli.h" -#include "cnat_ports.h" -#include "index_list.h" - -#define VRF_NAME_LEN_STORED 12 -#define MAX_VRFID 400 -typedef struct _cnat_svi_params_entry { - u16 svi_type; - u16 pad; - - u32 vrf_id; - u16 if_num; - - u32 ipv6_addr[4]; - u32 ipv4_addr; - - u8 direction; - u32 tbl_id; /* vrf */ - u32 vrf_override_id; /* tbl_id for override vrf */ - u8 vrf_override_flag; - u8 partition_id; -} cnat_svi_params_entry; - -typedef struct _cnat_ingress_vrfid_name_entry { - u32 vrf_id; - u16 ref_count; /*no# of serviceApps under a single vrf*/ - u8 vrf_name[VRF_NAME_LEN_STORED]; - u16 pad1; -} cnat_ingress_vrfid_name_entry; -#define HASH_ENHANCE 4 - -#define CNAT_DB_SIZE (PLATFORM_MAX_NAT_ENTRIES / PLATFORM_CNAT_INSTS) -#define CNAT_MAIN_HASH_SIZE (HASH_ENHANCE * PLATFORM_CNAT_MAIN_PRELIM_HASH_SIZE) -#define CNAT_MAIN_HASH_MASK (CNAT_MAIN_HASH_SIZE-1) - -#define CNAT_USER_DB_SIZE (PLATFORM_MAX_USER_ENTRIES / PLATFORM_CNAT_INSTS) -#define CNAT_USER_HASH_SIZE (HASH_ENHANCE * PLATFORM_CNAT_USER_PRELIM_HASH_SIZE) -#define CNAT_USER_HASH_MASK (CNAT_USER_HASH_SIZE-1) - -#define CNAT_SESSION_DB_SIZE (PLATFORM_MAX_NAT_ENTRIES / PLATFORM_CNAT_INSTS) -#define CNAT_SESSION_HASH_SIZE (HASH_ENHANCE * PLATFORM_CNAT_MAIN_PRELIM_HASH_SIZE) -#define CNAT_SESSION_HASH_MASK (CNAT_SESSION_HASH_SIZE-1) - - -#define CNAT_MAX_SESSIONS_PER_BIB 0xFFFF - -#define NUM_BITS_IN_UWORD (8*sizeof(uword)) - -/* No. of per ip/port config will be limited to 1024 */ -#define CNAT_TIMEOUT_HASH_SIZE 1024 -#define CNAT_TIMEOUT_HASH_MASK (CNAT_TIMEOUT_HASH_SIZE - 1) -#define CNAT_TIMEOUT_FULL_MASK 0xFFFFFFFFFFFFFFFF -#define CNAT_TIMEOUT_IPPROT_MASK PLATFORM_CNAT_TIMEOUT_IPPROT_MASK -#define CNAT_TIMEOUT_PORTPROT_MASK PLATFORM_CNAT_TIMEOUT_PORTPROT_MASK - -#define TRUE 1 -#define FALSE 0 - -/* - * The key structure. All fields are in NETWORK byte order! - */ -typedef struct { - u32 ipv4; - u16 port; - u16 vrf; //bit0-12:vrf, bit13:unused, bit14-15:protocol -} cnat_db_key_t; - -/* bit14-15:protocol in cnat_db_key_t */ -#define CNAT_INVALID_PROTO 0x0000 -#define CNAT_PPTP 0x0000 -#define CNAT_UDP 0x4000 -#define CNAT_TCP 0x8000 -#define CNAT_ICMP 0xc000 -#define CNAT_VRF_MASK 0x3fff -#define CNAT_PRO_MASK 0xc000 -#define CNAT_PRO_SHIFT 14 - -/* - * Maximum number of VRF entries supported - */ -#define CNAT_MAX_VRFMAP_ENTRIES (CNAT_VRF_MASK + 1) -/* - * for hashing purposes, fetch the key in one instr. - */ -typedef union { - cnat_db_key_t k; - u64 key64; -} cnat_key_t; - -typedef struct { - cnat_key_t k; - u32 bucket; -} cnat_db_key_bucket_t; - -typedef struct { - u32 ipv6[4]; - cnat_key_t ipv4_key; -} dslite_key_t; - -typedef struct { -/* - cnat_db_key_bucket_t ck; - u32 ipv6[4]; -*/ - dslite_key_t dk; - u32 bucket; -} dslite_db_key_bucket_t; - - -/* Per port/ip timeout related strucutres */ -extern index_slist_t *cnat_timeout_hash; - -typedef struct { - cnat_key_t timeout_key; - u16 timeout_value; -} cnat_timeout_t; - -typedef struct { - cnat_timeout_t t_key; - index_slist_t t_hash; -} cnat_timeout_db_entry_t; - -extern cnat_timeout_db_entry_t *cnat_timeout_db; - -/* - * Main translation database entries. Currently 0x5A = 90 bytes in length. - * Given 20,000,000 entries, it saves nearly 1gb of SDRAM to pack the entries - * and pay the extra prefetch. So, that's what we do. - */ - -typedef struct { - /* 0x00 */ - index_slist_t out2in_hash; /* hash-and-chain, x2 */ - index_slist_t in2out_hash; - - /* 0x08 */ - u16 flags; /* Always need flags... */ -#define CNAT_DB_FLAG_PORT_PAIR (1<<0) -#define CNAT_DB_FLAG_TCP_ACTIVE (1<<1) -#define CNAT_DB_FLAG_ENTRY_FREE (1<<2) -#define CNAT_DB_FLAG_UDP_ACTIVE (1<<3) -#define CNAT_DB_FLAG_STATIC_PORT (1<<4) -/* This alg entry is set for FTP data connection */ -#define CNAT_DB_FLAG_ALG_ENTRY (1<<5) - -/* Will be set for TCP connection with destination port - 1723 - * note - here CNAT_DB_FLAG_TCP_ACTIVE is also set */ -#define CNAT_DB_FLAG_PPTP_TUNNEL_INIT (1<<6) -#define CNAT_DB_FLAG_PPTP_TUNNEL_ACTIVE (1<<7) - -/* for PPTP GRE packtes */ -#define CNAT_DB_FLAG_PPTP_GRE_ENTRY (1<<8) - -/* for PCP support */ -#define CNAT_DB_FLAG_PCPI (1<<9) -#define CNAT_DB_FLAG_PCPE (1<<10) -#define CNAT_PCP_FLAG (CNAT_DB_FLAG_PCPI | CNAT_DB_FLAG_PCPE) - -#define CNAT_TAC_SEQ_MISMATCH (1<<11) -/* This alg entry is set for ftp control connection */ -#define CNAT_DB_FLAG_ALG_CTRL_FLOW (1<<12) - -/* This is for marking the state where connection is closing */ -#define CNAT_DB_FLAG_TCP_CLOSING (1<<13) - -#define CNAT_DB_DSLITE_FLAG (1<<14) -#define CNAT_DB_NAT64_FLAG (1<<15) - - /* 0x0A */ - u16 vrfmap_index; /* index of vrfmap */ - - /* 0x0C */ - u32 user_index; /* index of user that owns this entry */ - - /* 0x10 */ - cnat_key_t out2in_key; /* network-to-user, outside-to-inside key */ - - /* 0x18 */ - cnat_key_t in2out_key; /* user-to-network, inside-to-outside key */ - - /* 0x20 */ - index_dlist_t user_ports; /* per-user translation list */ - - /* 0x28 */ - u32 out2in_pkts; /* pkt counters */ - - /* 0x2C */ - u32 in2out_pkts; - - /* 0x30 */ - u32 entry_expires; /* timestamp used to expire translations */ - - /* 0x34 */ - union { /* used by FTP ALG, pkt len delta due to FTP PORT cmd */ - u16 delta; - i8 alg_dlt[2]; /* two delta values, 0 for previous, 1 for current */ - u16 il; /* Used to indicate if interleaved mode is used - in case of RTSP ALG */ - } alg; - - /* 0x36 */ - u16 timeout; - - /* 0x38 */ - union { - struct seq_pcp_t { - u32 tcp_seq_num; /* last tcp (FTP) seq # that has pkt len change due to PORT */ - u32 pcp_lifetime; /* peer and map life time value sent in reply*/ - } seq_pcp; - - /* This is for TCP seq check */ - struct tcp_seq_chk_t { - u32 seq_no; - u32 ack_no; - } tcp_seq_chk; - - /* used for pptp alg entries - 1. only tunnel : prev and next = 0xFFFFFFFF - 2. first gre entry : prev = tunnel db, next = next gre db - 3. last gre entry : prev = previous gre/tunnel db, next= 0xFFFFFFFF; - - *while adding gre entry- updated at the begining of head - *while deleting gre entry - hash look up will be done and prev and next are adjusted - * while deleting need not traverse throufgh the list, as done in index_dlist_remelem - - */ - index_dlist_t pptp_list; - - } proto_data; - - /* 0x40 */ - u32 dst_ipv4; /* pointer to ipv4 dst list, used in evil mode */ - - /* 0x44 */ - u16 dst_port; - - /* 0x46 */ - u16 dslite_nat44_inst_id; - - /* 0x48 */ - u32 session_head_index; - - /* 0x4C */ - u16 nsessions; - - /* 0x4E */ - u8 unused; - - /* 0x4F */ - u8 scale; - - /* 0x50 */ - u32 diff_window; - - /* Sizeof cnat_main_db_entry_t = 0x54 */ -} cnat_main_db_entry_t; - -/* Caution ... - * 1. The size of this structure should be same as that of - * nat64_bib_user_entry_t - * 2. Do not alter the position of first four fields - */ -typedef struct { - /* 0x00 */ - index_slist_t user_hash; /* hash 'n chain bucket chain */ - - /* 0x04 */ - u16 ntranslations; /* translations hold by this user */ - - /* 0x06 */ - u8 icmp_msg_count; /* use to rate limit imcp send to this user */ - - /* 0x07 */ - u8 flags; /* To identfiy whether it is NAT64 or NAT44 etc */ -#define CNAT_USER_DB_NAT44_FLAG 0 -#define CNAT_USER_DB_NAT64_FLAG 1 -#define CNAT_USER_DB_DSLITE_FLAG 2 -#define CNAT_USER_DB_PORT_LIMIT_EXCEEDED 0X80 - - /* 0x08 */ - u32 translation_list_head_index; - - /* 0x0C */ - u32 portmap_index; /* index of bound port-map */ - - /* 0x10 */ - cnat_key_t key; /* For dslite this should store IPv6 address */ - u32 ipv6[4]; // B4 ipv6 address - /* 0x18 */ -#if 0 - u32 temp1; - u32 temp2; - u32 temp3; -#endif - /* 0x28 same as nat64_user_db */ -#ifndef NO_BULK_LOGGING - /* Now adding 8 more bytes for bulk allocation.. This makes it - * 0x30 (48). Added the same to nat64_bib_user_entry_t make the - * the sizes equal. For nat64 stful, we may support bulk allocation - * later. - */ - /* Indicates the currently used bulk port range */ - i16 bulk_port_range_cache[BULK_RANGE_CACHE_SIZE]; -#endif /* #ifndef NO_BULK_LOGGING */ -} cnat_user_db_entry_t; - -/* - * cnat_session_entry_t - * This structure represents the cnat session table. It maintains the - * information about the destination of a given translation (main db) - * There would be entry here only if packets are send to more than 1 destn - * from the same source. - */ -typedef struct { - - /* 0x00 */ - index_slist_t cnat_session_hash; - - /* 0x04 */ - u32 main_db_index; /* would point to v4 src transport address */ - - /* 0x08 */ - cnat_key_t v4_dest_key; - - /* 0x10 */ - u16 flags; /* Same as cnat_main_db_t */ - - /* 0x12 */ - u16 timeout; - - /* 0x14 */ - u32 entry_expires; - /* 0x18 */ - index_dlist_t main_list; - /* 0x20 = 32 B */ - - union { /* alg same as cnat_main_db_t */ - u16 delta; - i8 alg_dlt[2]; - u16 il; - } alg; - - /* 0x22 */ - u16 tcp_flags; - - /* 0x24 */ - u32 tcp_seq_num; - - /* 0x28 */ - u32 ack_no; - - /* 0x2C */ - u32 window; - - /* 0x30 */ - u8 scale; - - /* 0x31 */ - u8 pad; - - /* 0x32 */ -} cnat_session_entry_t; - - - -/* - * out2in and in2out hash bucket arrays are simply arrays of index_slist_t's - */ - -typedef enum { - CNAT_DB_CREATE_DEFAULT=0, /* honor cnat_main_db_max_ports_per_user */ - CNAT_DB_CREATE_OVERRIDE, /* just do it. */ -} cnat_db_create_policy_t; - -typedef struct { - cnat_key_t in2out_key; - cnat_key_t out2in_key; - u32 dst_ipv4; /* evil for mode only */ - u16 cnat_instance; - cnat_portmap_t *portmap; - u16 *portmap_inuse; - cnat_main_db_entry_t *db; - cnat_db_create_policy_t policy; - port_pair_t pair_of_ports; -} cnat_db_create_args_t; - -extern cnat_main_db_entry_t *cnat_main_db; -extern cnat_user_db_entry_t *cnat_user_db; -extern cnat_session_entry_t *cnat_session_db; - -#define S_WAO 0 -#define S_WA 1 /* waiting for address pool */ -#define S_WO 2 /* waiting for outside vrf */ -#define S_RUN 3 /* got everything */ -#define S_DEL 4 /* just delete */ - -#define INVALID_UIDX 0xffff /*invalid svi app uidb index */ -#define INVALID_VRFID 0xffffffff /*invalid vrf id */ - -typedef struct { - u16 status; - u16 tcp_mss; //tcp max segment size for this inside vrf */ - u32 delete_time; - u16 i_vrf; //inside SVI uidx - u16 o_vrf; //outside SVI uidx - u32 i_vrf_id; //inside vrf id - u32 o_vrf_id; //outside vrf id - cnat_portmap_v2_t *portmap_list; - u32 nfv9_logging_index; - u32 syslog_logging_index; - u16 ip_n_to_1; -#ifndef NO_BULK_LOGGING - bulk_alloc_size_t bulk_size; -#endif /* #ifndef NO_BULK_LOGGING */ - u32 pcp_server_addr; - u32 pcp_server_port; - - u8 nf_logging_policy; - u8 syslog_logging_policy; - u8 frag_tout; - u32 rseed_ip; - u16 port_limit; - u8 tcp_seq_check_enable; - u8 pad; - u32 tcp_seq_user_window; - u8 filter_policy; - u8 ignore_port; -} cnat_vrfmap_t; - -/* - * When creating cnat_vrfmap entry, ensure that any already - * configured logging info is taken into account - */ -#define CNAT_SET_VRFMAP_NFV9_LOGGING_INDEX(logging_index, i_vrf) \ -do { \ - cnat_nfv9_logging_info_t *my_nfv9_logging_info = 0; \ - pool_foreach (my_nfv9_logging_info, cnat_nfv9_logging_info, ({ \ - if (my_nfv9_logging_info->i_vrf == i_vrf) { \ - logging_index = my_nfv9_logging_info - cnat_nfv9_logging_info; \ - break; \ - } \ - })); \ -while (0) - - -typedef struct { - /* - * spp_ctx_alloc() call failed - */ - u64 nfv9_logging_context_creation_fail_count; - - /* - * Cannot send the existing logging pkt, so cannot create - * any additional packets for logging purposes - */ - u64 nfv9_logging_context_creation_deferred_count; - - /* - * Cannot send the existing logging pkt due to cnat_rewrite_output - * superframe being full. - */ - u64 nfv9_downstream_constipation_count; - - /* - * buffer for spp_ctx_alloc() call failed - */ - u64 nfv9_logging_context_buffer_allocation_fail_count; - -} cnat_global_counters_t; - - -extern cnat_global_counters_t cnat_global_counters; - -extern u16 *cnat_portmap_indices_by_vrf; -extern cnat_vrfmap_t *cnat_portmap_by_vrf; -extern cnat_portmap_t **cnat_portmaps; -extern u16 **cnat_portmaps_inuse; - -extern cnat_vrfmap_t *cnat_map_by_vrf; - -/* - * Special define to indicate that the VRF map index entry is empty - */ -#define VRF_MAP_ENTRY_EMPTY 0xffff -extern u16 vrf_map_array[CNAT_MAX_VRFMAP_ENTRIES]; - -extern cnat_svi_params_entry svi_params_array[CNAT_MAX_VRFMAP_ENTRIES]; -extern cnat_ingress_vrfid_name_entry vrfid_name_map[MAX_VRFID]; - -extern index_slist_t *cnat_out2in_hash; -extern index_slist_t *cnat_in2out_hash; -extern index_slist_t *cnat_user_hash; -extern index_slist_t *cnat_session_hash; - -typedef enum { - CNAT_DB_IN2OUT = 0, - CNAT_DB_OUT2IN, -} cnat_db_which_t; - -typedef enum { - CNAT_NO_ICMP_MSG =0, - CNAT_ICMP_MSG, -} cnat_icmp_msg_t; - -typedef struct { - cnat_errno_t error; - cnat_icmp_msg_t gen_icmp_msg; - u32 svi_addr; -} cnat_gen_icmp_info; - -typedef cnat_vrfmap_t nat64_vrfmap_t; -typedef cnat_portmap_v2_t nat64_portmap_v2_t; - -#define CNAT_V4_GET_HASH(key64, hash, mask) \ - a = key64; \ - b = c = 0x9e3779b97f4a7c13LL; \ - /* Jenkins hash, arbitrarily use c as the "answer" */ \ - hash_mix64(a, b, c); \ - hash = c & mask; - -#define CNAT_V4_GET_SESSION_HASH(main_index, in_addr, port, vrf, hash, mask) \ - a = main_index ^ in_addr ^ port ^ vrf; \ - b = c = 0x9e3779b9; \ - /* Jenkins hash, arbitrarily use c as the "answer" */ \ - hash_mix32(a, b, c); \ - hash = c & mask; - -#define CNAT_V4_GET_FRAG_HASH(key64, key32, hash, mask) \ - a = key64; \ - b = key32; \ - c = 0x9e3779b97f4a7c13LL; \ - hash_mix64(a, b, c); \ - hash = c % mask; - -#define CNAT_DB_UPDATE_IN2OUT_TIMER \ - db->entry_expires = cnat_current_time; \ - db->in2out_pkts++; - -#define CNAT_DB_TIMEOUT_RST(db) \ - if(PREDICT_TRUE(db->entry_expires != 0 )) \ - db->entry_expires = cnat_current_time; - -#define DEBUG_I2O_DROP(debug_flag) \ -if (debug_i_flag & debug_flag) { \ - cnat_db_debug_i2o_drop(&ki); \ -} - - -cnat_main_db_entry_t *cnat_main_db_create (cnat_db_create_args_t *a); -void cnat_main_db_entry_delete(cnat_main_db_entry_t *ep); - -void cnat_delete_main_db_entry(cnat_main_db_entry_t *ep); -void cnat_delete_main_db_entry_v2(cnat_main_db_entry_t *ep); - - -cnat_main_db_entry_t* -cnat_get_main_db_entry(cnat_db_key_bucket_t *ki, - port_pair_t port_type, - cnat_errno_t *error, - cnat_user_db_entry_t ** user_db_entry); - -cnat_main_db_entry_t* -cnat_get_main_db_entry_v2(cnat_db_key_bucket_t *ki, - port_pair_t port_pair_type, - port_type_t port_type, - cnat_gen_icmp_info *info, - cnat_key_t *dest_info); - -cnat_main_db_entry_t* -cnat_create_static_main_db_entry_v2(cnat_db_key_bucket_t *ki, - cnat_db_key_bucket_t *ko, - cnat_vrfmap_t *my_vrfmap, - cnat_gen_icmp_info *info); - -cnat_main_db_entry_t* -cnat_create_main_db_entry_and_hash(cnat_db_key_bucket_t *ki, - cnat_db_key_bucket_t *ko, - cnat_user_db_entry_t *udb); - -cnat_user_db_entry_t* -cnat_user_db_create_entry(cnat_db_key_bucket_t *uki, - u32 portmap_index); - -cnat_user_db_entry_t* -cnat_user_db_lookup_entry(cnat_db_key_bucket_t *uki); - -cnat_main_db_entry_t* -cnat_main_db_lookup_entry(cnat_db_key_bucket_t *ki); - -cnat_main_db_entry_t* -cnat_main_db_lookup_entry_out2in (cnat_db_key_bucket_t *ko); - -void cnat_main_db_entry_dump (cnat_main_db_entry_t *db); -void cnat_db_in2out_hash_delete (cnat_main_db_entry_t *ep, cnat_user_db_entry_t *up); -void cnat_db_out2in_hash_delete (cnat_main_db_entry_t *ep); -void cnat_user_db_delete (cnat_user_db_entry_t *up); -void cnat_db_debug_i2o_drop(cnat_db_key_bucket_t *ki); - -/* - * Function to dump the Hash Table that maps if_num to uidb_index - */ -extern void cnat_if_num_hash_table_dump(void); - -#define MAIN_DB_TYPE 0 -#define SESSION_DB_TYPE 1 -u16 query_and_update_db_timeout(void *db, u8 db_type); - -u16 cnat_timeout_db_create (cnat_timeout_t t_entry); -void cnat_timeout_db_delete(cnat_key_t t_key); - -cnat_session_entry_t * -cnat_create_session_db_entry(cnat_key_t *ko, - cnat_main_db_entry_t *bdb, u8 log); - -void cnat_dest_update_main2session(cnat_main_db_entry_t *mdb, - cnat_session_entry_t *sdb); - -cnat_session_entry_t *cnat_handle_1to2_session( - cnat_main_db_entry_t *mdb, - cnat_key_t *dest_info); - -void cnat_add_dest_n_log( - cnat_main_db_entry_t *mdb, - cnat_key_t *dest_info); - -cnat_session_entry_t * - cnat_session_db_lookup_entry(cnat_key_t *ko,u32 main_db_index); - -cnat_session_entry_t * - cnat_session_db_edm_lookup_entry(cnat_key_t *ko, - u32 session_head_index, - u32 main_db_index); - - -typedef struct{ - u32 sessions; - u32 active_translations; - u32 num_dynamic_translations; - u32 num_static_translations; - u64 in2out_drops_port_limit_exceeded; - u64 in2out_drops_system_limit_reached; - u64 in2out_drops_resource_depletion; - u64 no_translation_entry_drops; - u32 num_subscribers; - u32 dummy; - u64 drops_sessiondb_limit_exceeded; -} nat44_dslite_common_stats_t; - -typedef struct { - u32 translation_delete_count; - u32 translation_create_count; - u32 out2in_forwarding_count; -} nat44_dslite_global_stats_t; - -typedef struct { - u64 v4_to_v6_tcp_seq_mismatch_drop_count; - u64 v4_to_v6_tcp_seq_mismatch_count; - u64 v4_to_v6_out2in_session_create_count; - u64 v4_to_v6_end_point_filter_drop_count; -} nat44_counters_stats_t; - -#define NAT44_STATS 0 -#define DSLITE_STATS 1 -extern nat44_dslite_common_stats_t nat44_dslite_common_stats[255]; /* 0 is for nat44 */ -extern nat44_dslite_global_stats_t nat44_dslite_global_stats[2]; /* 0 for nat44 and 1 for dslite */ -extern nat44_counters_stats_t nat44_counters_stats[CNAT_MAX_VRFMAP_ENTRIES];/*For displaying show cgn inside-vrf counters */ - -#define NAT44_COMMON_STATS nat44_dslite_common_stats[NAT44_RESERVED_INST_ID] -#define NAT44_GLOBAL_STATS nat44_dslite_global_stats[NAT44_STATS] -#define DSLITE_GLOBAL_STATS nat44_dslite_global_stats[DSLITE_STATS] -#define SESSION_LOG_ENABLE 1 -#define ALG_ENABLED_DB(db) \ - ((db->flags & CNAT_PCP_FLAG) || \ - (db->flags & CNAT_DB_FLAG_ALG_CTRL_FLOW) || \ - (db->flags & (CNAT_DB_FLAG_PPTP_TUNNEL_INIT | \ - CNAT_DB_FLAG_PPTP_TUNNEL_ACTIVE))) - - -#endif /* __CNAT_DB_H__ */ diff --git a/plugins/vcgn-plugin/vcgn/cnat_db_scanner.c b/plugins/vcgn-plugin/vcgn/cnat_db_scanner.c deleted file mode 100644 index 6e536d84..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_db_scanner.c +++ /dev/null @@ -1,493 +0,0 @@ -/* - *--------------------------------------------------------------------------- - * cnat_db_scanner.c - cnat_db_scanner dispatch function and initialization - * - * Copyright (c) 2009-2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *--------------------------------------------------------------------------- - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include "cnat_db.h" -#include "cnat_logging.h" -#include "cnat_global.h" -#include "cnat_ipv4_udp.h" -#include "cnat_common_api.h" - -u32 translation_create_count, translation_delete_count; -u32 translation_create_rate, translation_delete_rate; - -u32 in2out_forwarding_count, out2in_forwarding_count; -u32 in2out_forwarding_rate, out2in_forwarding_rate; - -u32 nat44_active_translations; -u32 num_entries; -uword check_these_pool_indices[2*MAX_DB_ENTRY_SELECTED_PER_SCAN]; - -#define CNAT_DB_SCANNER_TURN_ON 5 /* just an arbitary number for easier debugging */ - -//extern u32 pcp_throttle_count; - -typedef struct { - u32 cached_next_index; - /* $$$$ add data here */ - - /* convenience variables */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; -} cnat_db_scanner_main_t; - -cnat_db_scanner_main_t cnat_db_scanner_main; - - -static inline void check_session_for_expiry( - cnat_session_entry_t * sdb, u8 timeout_dirty - /*,dslite_table_entry_t *dslite_entry_ptr*/) -{ - void cnat_delete_session_db_entry (cnat_session_entry_t *ep, u8 log); - /* Tasks - - * 1. Check for expiry for this entry - * 2. Delete if expired - */ - u32 timeout = 0; - - switch(sdb->v4_dest_key.k.vrf & CNAT_PRO_MASK) { - case CNAT_TCP: - if (sdb->flags & CNAT_DB_FLAG_TCP_ACTIVE) { - timeout = sdb->timeout; - if(PREDICT_FALSE(timeout_dirty)) { - timeout = query_and_update_db_timeout( - (void *)sdb, SESSION_DB_TYPE); - } - if(PREDICT_TRUE(timeout == 0)) { - timeout = tcp_active_timeout; - //dslite_entry_ptr->timeout_info.tcp_active_timeout; - } - } else { - timeout = tcp_initial_setup_timeout; - //dslite_entry_ptr->timeout_info.tcp_initial_setup_timeout; - } - break; - case CNAT_UDP: - if (sdb->flags & CNAT_DB_FLAG_UDP_ACTIVE) { - timeout = sdb->timeout; - if(PREDICT_FALSE(timeout_dirty)) { - timeout = query_and_update_db_timeout( - (void *)sdb, SESSION_DB_TYPE); - } - - if(PREDICT_TRUE(timeout == 0)) { - timeout = udp_act_session_timeout; - //dslite_entry_ptr->timeout_info.udp_act_session_timeout; - } - } else { - timeout = udp_init_session_timeout; - //dslite_entry_ptr->timeout_info.udp_init_session_timeout; - } - break; - case CNAT_ICMP: - timeout = icmp_session_timeout; - //dslite_entry_ptr->timeout_info.icmp_session_timeout; - break; - case CNAT_PPTP: - timeout = pptp_cfg.timeout; - break; - default: - return; - } - /* Changes required for clearing sessions */ - if (PREDICT_FALSE((sdb->entry_expires == 0) || - (sdb->entry_expires + timeout < cnat_current_time))) { - cnat_delete_session_db_entry(sdb, TRUE); - } -} - -static u8 handle_db_scan_for_sessions( - cnat_main_db_entry_t *db, int *dirty_index, uword db_index - /* ,dslite_table_entry_t *dslite_entry_ptr */) -{ - /* Tasks - - * 1. Traverse through the sessions and check for timeouts - * 2. Delete sessions that have exipred - * 3. Check if the db has only one session remaining.. if so, - * the details of the session has to be moved to main db - * and session db entry needs to be freed - * 4. If db does not have any sessions left, the db itself - * needs to be deleted. - */ - u32 nsessions, session_index_head, session_index; - cnat_session_entry_t *sdb; - u8 timeout_dirty = FALSE; - - if(PREDICT_FALSE(*dirty_index == db_index)) { - *dirty_index = -1; - } - if(PREDICT_FALSE(timeout_dirty_flag == 1)) { - timeout_dirty_flag = 0; - *dirty_index = db_index; - timeout_dirty = TRUE; - } - - session_index_head = session_index = db->session_head_index; - nsessions = db->nsessions; - - do { - sdb = cnat_session_db + session_index; - if(PREDICT_FALSE(!sdb)) { - //TO DO: Debug msg? - return FALSE; - } - session_index = sdb->main_list.next; - check_session_for_expiry(sdb, timeout_dirty /*,dslite_entry_ptr*/); - nsessions--; /* To ensure that we do not get in to an infinite loop */ - } while(session_index != session_index_head - && db->session_head_index != EMPTY && - nsessions); - - /* Note.. the code below assumes that while deleting the - * sessions, we do not delete the main db entry if it does - * not have any sessions anymore - */ - if(PREDICT_FALSE((!db->nsessions) && - (!(db->flags & CNAT_DB_FLAG_STATIC_PORT)))) { - cnat_delete_main_db_entry_v2(db); - return TRUE; /* to indicate that main db was deleted */ - } - return FALSE; -} - -static void cnat_db_scanner(void) -{ - cnat_main_db_entry_t * db; - u32 timeout; - cnat_vrfmap_t *my_vrfmap __attribute__((unused)) = 0; - static int dirty_index = -1; - u16 instance __attribute__((unused)); - //dslite_table_entry_t *dslite_entry_ptr; - u32 i; - uword db_index; - //pcp_throttle_count = 0; - - for (i = 0; i < num_entries; i++) { - db_index = check_these_pool_indices[i]; - db = cnat_main_db + db_index; - timeout=0; - my_vrfmap = 0; - -#if 0 - if(PREDICT_FALSE(db->flags & CNAT_PCP_FLAG)) { - - if(db->proto_data.seq_pcp.pcp_lifetime < cnat_current_time) { - /* mark as implicit */ - db->flags &= ~CNAT_PCP_FLAG; - } - continue; - } - -#endif - if(PREDICT_FALSE(db->nsessions > 1)) { - if(PREDICT_FALSE( - handle_db_scan_for_sessions(db, &dirty_index, db_index /*,dslite_entry_ptr */))) { - continue; - } else if(PREDICT_TRUE(db->nsessions > 1)) { - continue; - } - /* if there is exactly one dest left.. let it fall through - * and check if that needs to be deleted as well - */ - } - -#if 0 - if (PREDICT_FALSE(db->flags & CNAT_DB_FLAG_STATIC_PORT)) { - if (PREDICT_FALSE(db->flags & CNAT_DB_DSLITE_FLAG)) { - if(PREDICT_FALSE( - ((dslite_entry_ptr->nf_logging_policy != SESSION_LOG_ENABLE) && - (dslite_entry_ptr->syslog_logging_policy != SESSION_LOG_ENABLE)) - || (db->nsessions !=1))) { - continue; - } - } else { - my_vrfmap = cnat_map_by_vrf + db->vrfmap_index; - if(PREDICT_FALSE( - ((my_vrfmap->nf_logging_policy != SESSION_LOG_ENABLE) && - (my_vrfmap->syslog_logging_policy != SESSION_LOG_ENABLE)) || - (db->nsessions !=1))) { - continue; - } - } - } -#endif - - switch(db->in2out_key.k.vrf & CNAT_PRO_MASK) { - case CNAT_TCP: - if (db->flags & CNAT_DB_FLAG_TCP_ACTIVE) { - timeout = db->timeout; - if(PREDICT_FALSE(dirty_index == db_index)) { - dirty_index = -1; - } - if(PREDICT_FALSE(timeout_dirty_flag == 1)) { - timeout_dirty_flag = 0; - dirty_index = db_index; - } - if(PREDICT_FALSE(dirty_index != -1)) { - timeout = query_and_update_db_timeout( - (void *)db, MAIN_DB_TYPE); - } - if(PREDICT_TRUE(timeout == 0)) { - timeout = tcp_active_timeout; - } - } else { - timeout = tcp_initial_setup_timeout; - } - break; - case CNAT_UDP: - if (db->flags & CNAT_DB_FLAG_UDP_ACTIVE) { - timeout = db->timeout; - if(PREDICT_FALSE(dirty_index == db_index)) { - dirty_index = -1; - } - if(PREDICT_FALSE(timeout_dirty_flag == 1)) { - timeout_dirty_flag = 0; - dirty_index = db_index; - } - if(PREDICT_FALSE(dirty_index != -1)) { - timeout = query_and_update_db_timeout( - (void *)db, MAIN_DB_TYPE); - } - if(PREDICT_TRUE(timeout == 0)) { - timeout = udp_act_session_timeout; - } - } else { - timeout = udp_init_session_timeout; - } - break; - case CNAT_ICMP: - timeout = icmp_session_timeout; - break; - case CNAT_PPTP: - timeout = pptp_cfg.timeout; - break; - default: - continue; - } - - - /* Ref: CSCtu97536 */ - if (PREDICT_FALSE((db->entry_expires == 0) || - (db->entry_expires + timeout < cnat_current_time))) { -#if 0 - if (PREDICT_FALSE(db->flags & CNAT_DB_FLAG_STATIC_PORT)) { - if (PREDICT_FALSE(db->flags & CNAT_DB_DSLITE_FLAG)) { - instance = db->dslite_nat44_inst_id; - } else { - instance = NAT44_RESERVED_INST_ID; - cnat_session_log_nat44_mapping_delete(db, 0, my_vrfmap); - } - - /* Reset the session details */ - db->nsessions = 0; - db->dst_ipv4 = 0; - db->dst_port = 0; - db->flags &= ~(CNAT_DB_FLAG_TCP_ACTIVE | CNAT_DB_FLAG_UDP_ACTIVE - | CNAT_DB_FLAG_ALG_ENTRY); - db->timeout = 0; - db->entry_expires = 0; - db->alg.delta = 0; - db->proto_data.seq_pcp.tcp_seq_num = 0; - continue; - } -#endif - //printf("DELETING DB ENTRY FOR 0x%x\n", db->in2out_key.k.ipv4); - cnat_delete_main_db_entry_v2(db); - } - //free(check_these_pool_indices[i]); - } -} - -static void walk_the_db (void) -{ - pool_header_t *h = pool_header(cnat_main_db); - u32 db_uword_len; - static u32 base_index = 0, free_bitmap_index = 0; - int bits_scanned = 0, i; - uword inuse_bitmap; - - num_entries=0; - - /* Across all db entries... */ - db_uword_len = vec_len(cnat_main_db) / NUM_BITS_IN_UWORD; - if (PREDICT_FALSE(vec_len(cnat_main_db) % NUM_BITS_IN_UWORD)) { - /* - * It should not come here as in cnat_db_init_v2() - * it is made multiple of NUM_BITS_IN_UWORD - */ - ASSERT(0); - return ; - } - - if (PREDICT_FALSE(! db_uword_len)) - return ; - - while (bits_scanned < MAX_DB_ENTRY_PER_SCAN) { - - if (PREDICT_FALSE(free_bitmap_index < vec_len(h->free_bitmap))) { - - /* free_bitmap exists and it is not all 0 */ - - inuse_bitmap = ~(h->free_bitmap[free_bitmap_index]); - i = 0; - while (inuse_bitmap) { - - /* Check to see if the index is in use */ - if (PREDICT_FALSE((inuse_bitmap >> i) & 1)) { - check_these_pool_indices[num_entries] = base_index + i; - inuse_bitmap &= ~((uword) 1 << i); - num_entries++; - } - i++; - } // while (inuse_bitmap) - } else { - - /* - * 64-bit entry is 0, means all 64 entries are allocated. - * So, simply add all 64 entries here. - * No need to form inuse_bitmap, check and reset bits - */ - for (i=0; ifree_bitmap)) - - /* Update free_bitmap_index and base_index for next run */ - if (PREDICT_FALSE(free_bitmap_index == db_uword_len - 1)) { - /* wrap-around for next run */ - free_bitmap_index = 0; - base_index = 0; - } else { - free_bitmap_index ++; - base_index += NUM_BITS_IN_UWORD; - } - - /* increment # of bits scanned */ - bits_scanned += NUM_BITS_IN_UWORD; - - /* Found enough entries to check ? */ - if (PREDICT_FALSE(num_entries >= MAX_DB_ENTRY_SELECTED_PER_SCAN)) - { - /* This check is introduced to keep fixed MAX scan entry value */ - /* This is very much required when we do scanning for NAT64 */ - /* please check comments in cnat_db_scanner() & - * handler_nat64_db_scanner() */ - if (num_entries >= MAX_COMBINED_DB_ENTRIES_PER_SCAN) { - num_entries = MAX_COMBINED_DB_ENTRIES_PER_SCAN; - } - break; - } - - } // while (bits_scanned < MAX_DB_ENTRY_PER_SCAN) - - if (PREDICT_FALSE(num_entries > 0)) { - //printf("%s: num_entries [%d]\n", __func__, num_entries); - cnat_db_scanner(); - } - return ; -} - -static uword cnat_db_scanner_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - f64 timeout = 0.01; /* timeout value in sec (10 ms) */ - static u8 timeout_count = 0; - - uword event_type; - uword * event_data = 0; - /* Wait until vCGN is configured */ - while (1) { - /* Assigning a huge timeout value, vCGN may or - * may not get configured within this timeout */ - vlib_process_wait_for_event_or_clock (vm, 1e9); - event_type = vlib_process_get_events (vm, &event_data); - - /* check whether the process is waken up by correct guy, - * otherwise continue waiting for the vCGN config */ - if (event_type == CNAT_DB_SCANNER_TURN_ON) { - break; - } - } - - while(1) { - vlib_process_suspend(vm, timeout); - - /* Above suspend API should serve the purpose, no need to invoke wait API */ - /* vlib_process_wait_for_event_or_clock (vm, timeout); */ - - /* Lets make use of this timeout for netflow packet sent */ - if (timeout_count < 100) { /* 100*10 ms = 1 sec */ - timeout_count++; - } else { - if (nfv9_configured) { - handle_pending_nfv9_pkts(); - } - timeout_count = 0; - } - /* Do we need this ? */ - //event_type = vlib_process_get_events (vm, &event_data); - cnat_current_time = (u32)vlib_time_now (vm); - if (cnat_db_init_done) { - walk_the_db(); - } - } - - return 0; -} - - -VLIB_REGISTER_NODE (cnat_db_scanner_node) = { - .function = cnat_db_scanner_fn, - .type = VLIB_NODE_TYPE_PROCESS, - .name = "cnat-db-scanner", - .process_log2_n_stack_bytes = 18, -}; - -clib_error_t *cnat_db_scanner_init (vlib_main_t *vm) -{ - cnat_db_scanner_main_t *mp = &cnat_db_scanner_main; - - mp->vlib_main = vm; - mp->vnet_main = vnet_get_main(); - - return 0; -} - -void cnat_scanner_db_process_turn_on(vlib_main_t *vm) -{ - vlib_process_signal_event (vm, cnat_db_scanner_node.index, - CNAT_DB_SCANNER_TURN_ON, 0); - return; -} - -VLIB_INIT_FUNCTION (cnat_db_scanner_init); - diff --git a/plugins/vcgn-plugin/vcgn/cnat_db_v2.c b/plugins/vcgn-plugin/vcgn/cnat_db_v2.c deleted file mode 100644 index 46af9f31..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_db_v2.c +++ /dev/null @@ -1,3806 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_db_v2.c - translation database definitions - * - * Copyright (c) 2007-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cnat_db.h" -#include "cnat_config.h" -#include "cnat_global.h" -#include "cnat_v4_functions.h" -#include "cnat_log_api.h" -#include "cnat_cli.h" -#include "spp_platform_trace_log.h" -#include "cnat_bulk_port.h" -#include "nat64_db.h" -#include "dslite_db.h" -#include "cnat_config_api.h" - -#define HASH_TABLE_SIZE 8192 // hash table size -#define THROTTLE_TIME 180 // throttle time value for out of port msg/user - -u8 cnat_db_init_done = 0; - -typedef struct { - /* Locks for multi thread support */ - CLIB_CACHE_LINE_ALIGN_MARK(cacheline0); - pthread_spinlock_t *main_db_lockp; - pthread_spinlock_t *user_db_lockp; - pthread_spinlock_t *session_db_lockp; - - u32 cached_next_index; - /* $$$$ add data here */ - - /* convenience variables */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; -} cnat_db_v2_main_t; - -cnat_db_v2_main_t cnat_db_v2_main; - -#if 1 -/* TOBE_PORTED : Remove the following once fixed */ -#undef PREDICT_TRUE -#undef PREDICT_FALSE -#define PREDICT_TRUE(x) (x) -#define PREDICT_FALSE(x) (x) -#endif - -#define foreach_cnat_db_v2_error \ -_(DROP, "error-drop packets") - -typedef enum { -#define _(sym,str) CNAT_DB_V2_##sym, - foreach_cnat_db_v2_error -#undef _ - CNAT_DB_V2_N_ERROR, -} cnat_db_v2_error_t; - -static char * cnat_db_v2_error_strings[] __attribute__((unused)) = { -#define _(sym,string) string, - foreach_cnat_db_v2_error -#undef _ -}; - - -void cnat_table_entry_fill_map(u32 start_addr, u32 end_addr, - cnat_portmap_v2_t **port_map_holder) -{ - u32 this_start_addr, this_end_addr, this_addr, new; - u32 loop_count; - u32 pm_len, i; - cnat_portmap_v2_t *my_pm =0; - cnat_portmap_v2_t *pm = 0; - - my_instance_number = 0; - - this_start_addr = start_addr; - this_end_addr = end_addr; - - /* - * How many new addresses are getting added ?? - */ - /* commenting this. Right now end - start will be for this vCGN instance */ - //new = ((this_end_addr - this_start_addr) / MAX_CORES_PER_PARTITION) + 1; - new = (this_end_addr - this_start_addr) + 1; - - pm = *port_map_holder; - pm_len = vec_len(pm); -#if DEBUG_NOT_COMMENTED - printf("this_start_addr = 0x%08X, this_end_addr = 0x%08X, Num Addr = %d\n", - this_start_addr, this_end_addr, new); - printf("pm_len = %d\n", pm_len); -#endif - /* Check whether the address pool add requested already exists */ - my_pm = pm; - for(i = 0; i< pm_len; i++) { - if(my_pm->ipv4_address == this_start_addr) { - printf("address pool with addr 0x%08X exists\n", this_start_addr); - return; - } - my_pm++; - } - - /* - * For now give a warning message only.... - */ -#if 0 - if ((total_address_pool_allocated + new) > - CNAT_MAX_ADDR_POOL_SIZE_PER_CORE) { - printf("address pool size (%d) would cross permissible limit (%u) \n", - (total_address_pool_allocated + new), - CNAT_MAX_ADDR_POOL_SIZE_PER_CORE); - } -#endif - - total_address_pool_allocated += new; - vec_add2(pm, my_pm, new); - -#if DEBUG_NOT_COMMENTED - printf("total_address_pool_allocated changed from %d to %d (added %d)", - (total_address_pool_allocated - new), - total_address_pool_allocated, new); - printf("vec add is ok\n"); -#endif - - memset(my_pm, 0, new*sizeof(*my_pm)); - this_addr = this_start_addr; - loop_count = 0; /* Sanity counter */ - - while (this_addr <= this_end_addr) { -#if DEBUG_NOT_COMMENTED - printf("loop %d: this addr = 0x%08X\n", loop_count+1, this_addr); -#endif - my_pm->ipv4_address = this_addr; - /* - * Set all bits to "1" indicating all ports are free - */ - memset(my_pm->bm, 0xff, - (((BITS_PER_INST + BITS(uword)-1)/BITS(uword))*(sizeof(uword)))); - //this_addr += MAX_CORES_PER_PARTITION; - this_addr += 1; - my_pm++; - loop_count++; - } - /* - * We should have loop_count same as the new value - */ - if (loop_count != new) { - printf("Mismatch in loop_count (%d) != new (%d)\n", - loop_count, new); - } - - *port_map_holder = pm; - -#if DEBUG_NOT_COMMENTED - printf("revised pm len %d\n", vec_len(*port_map_holder)); -#endif - - return; -} - - -void cnat_delete_session_db_entry (cnat_session_entry_t *ep, u8 log); -void handle_cnat_port_exceeded_logging( - cnat_user_db_entry_t *udb, - cnat_key_t * key, - cnat_vrfmap_t *vrfmap); - -cnat_global_counters_t cnat_global_counters; -u32 last_log_timestamp = 0; -u32 last_user_dyn_port_exc_timestamp = 0; -u32 last_user_stat_port_exc_timestamp = 0; - -index_slist_t *cnat_out2in_hash; -index_slist_t *cnat_in2out_hash; -index_slist_t *cnat_user_hash; -index_slist_t *cnat_timeout_hash; -index_slist_t *cnat_session_hash; - -cnat_main_db_entry_t *cnat_main_db; -cnat_user_db_entry_t *cnat_user_db; -cnat_session_entry_t *cnat_session_db; -cnat_timeout_db_entry_t *cnat_timeout_db; - -cgse_nat_db_entry_t *cgse_nat_db; -cgse_nat_user_db_entry_t *cgse_user_db; -cgse_nat_session_db_entry_t *cgse_session_db; - -nat44_dslite_common_stats_t nat44_dslite_common_stats[255]; /* 0 is for nat44 */ -nat44_dslite_global_stats_t nat44_dslite_global_stats[2]; /* 0 for nat44 and 1 for dslite */ -nat44_counters_stats_t nat44_counters_stats[CNAT_MAX_VRFMAP_ENTRIES]; -/*For displaying show cgn inside-vrf counters */ - -/* - * This is the pool of vrf map structures used by latest main-db functions - */ -cnat_vrfmap_t *cnat_map_by_vrf; - -/* - * Have a mapping table of vrf_id-->vrf_map_index - * This helps in easily getting the vrf_map structure during - * main-db create paths - */ -u16 vrf_map_array[CNAT_MAX_VRFMAP_ENTRIES]; -cnat_svi_params_entry svi_params_array[CNAT_MAX_VRFMAP_ENTRIES]; -cnat_ingress_vrfid_name_entry vrfid_name_map[MAX_VRFID] = {{0}}; -u64 in2out_drops_port_limit_exceeded; -u64 in2out_drops_system_limit_reached; -u64 in2out_drops_resource_depletion; -u64 no_translation_entry_drops; -u32 no_sessions; - -#define CNAT_SET_ICMP_MSG_INFO \ -if (PREDICT_TRUE((my_vrfmap->i_vrf < CNAT_MAX_VRFMAP_ENTRIES) && \ - (svi_params_array[my_vrfmap->i_vrf].ipv4_addr))) { \ - info->gen_icmp_msg = icmp_msg_gen_allowed(); \ - info->svi_addr = svi_params_array[my_vrfmap->i_vrf].ipv4_addr; \ -} - -#define CNAT_DEBUG_INSIDE_ERR(err) \ -if (((protocol == CNAT_UDP) && \ - (debug_i_flag & CNAT_DEBUG_ERR_UDP)) || \ - ((protocol == CNAT_TCP) && \ - (debug_i_flag & CNAT_DEBUG_ERR_TCP)) || \ - ((protocol == CNAT_ICMP) && \ - (debug_i_flag & CNAT_DEBUG_ERR_ICMP))) { \ - cnat_db_debug_error(&u_ki, err); \ -} - -#define DSLITE_DEBUG_INSIDE_ERR(err) \ -if (((protocol == CNAT_UDP) && \ - (debug_i_flag & CNAT_DEBUG_ERR_UDP)) || \ - ((protocol == CNAT_TCP) && \ - (debug_i_flag & CNAT_DEBUG_ERR_TCP)) || \ - ((protocol == CNAT_ICMP) && \ - (debug_i_flag & CNAT_DEBUG_ERR_ICMP))) { \ - dslite_db_debug_error(&u_ki, err); \ -} - -#define PORT_LIMIT_LOW_THRESHOLD_FOR_SYSLOG 7 -/* If the max_limit is less than 10, no meaningful throttling can be - * done.. so, log only once per user and never clear the flag - * once the user exceeds limit - */ -#define CHECK_CLEAR_PORT_LIMIT_EXCEED_FLAG(udb, max_limit) \ - if(PREDICT_FALSE(udb->flags & CNAT_USER_DB_PORT_LIMIT_EXCEEDED)) { \ - if(udb->ntranslations < \ - ((max_limit/10)*PORT_LIMIT_LOW_THRESHOLD_FOR_SYSLOG) && \ - max_limit >= 10) { \ - udb->flags = udb->flags & (~CNAT_USER_DB_PORT_LIMIT_EXCEEDED); \ - } \ - } - -#ifdef TOBE_PORTED -/* Commented to remove unused variable warning */ -static char *debug_db_error[] = { - "no error", /* CNAT_SUCCESS */ - "no config", /*CNAT_NO_CONFIG*/ - "not in run state", /*CNAT_NO_VRF_RUN*/ - "no pool for any", /*CNAT_NO_POOL_ANY*/ - "no port for any", /*CNAT_NO_PORT_ANY*/ - "bad in use for any", /*CNAT_BAD_INUSE_ANY*/ - "not found for any", /*CNAT_NOT_FOUND_ANY*/ - "invalid index for direct", /*CNAT_INV_PORT_DIRECT*/ - "deleted addr for direct", /*CNAT_DEL_PORT_DIRECT*/ - "bad in use for direct",/*CNAT_BAD_INUSE_DIRECT*/ - "not found for direct",/*CNAT_NOT_FOUND_DIRECT*/ - "out of port limit", /*CNAT_OUT_LIMIT*/ - "main db limit", /*CNAT_MAIN_DB_LIMIT*/ - "user db limit", /*CNAT_USER_DB_LIMIT*/ - "not static port", /*CNAT_NOT_STATIC_PORT*/ - "bad static port request", /*CNAT_BAD_STATIC_PORT_REQ*/ - "not this core", /*CNAT_NOT_THIS_CORE*/ - "parser error", /*CNAT_ERR_PARSER*/ - "invalid msg id", /*CNAT_ERR_INVALID_MSG_ID*/ - "invalid msg size", /*CNAT_ERR_INVALID_MSG_SIZE*/ - "invalid payload size", /*CNAT_ERR_INVALID_PAYLOAD_SIZE*/ - "bad tcp udp port", /*CNAT_ERR_BAD_TCP_UDP_PORT*/ - "bulk single failure", /*CNAT_ERR_BULK_SINGLE_FAILURE*/ - "xlat id invalid", /*CNAT_ERR_XLAT_ID_INVALID*/ - "xlat v6 prefix invalid", /*CNAT_ERR_XLAT_V6_PREFIX_INVALID*/ - "xlat v4 prefix invalid", /*CNAT_ERR_XLAT_V4_PREFIX_INVALID*/ - "xlat tcp mss invalid", /*CNAT_ERR_XLAT_TCP_MSS_INVALID*/ - "6rd id invalid", /*CNAT_ERR_6RD_ID_INVALID*/ - "6rd v4 tunnel src invalid", /*CNAT_ERR_6RD_V4_TUNNEL_SRC_INVALID*/ - "6rd v6 prefix invalid", /*CNAT_ERR_6RD_V6_PREFIX_INVALID*/ - "6rd v6 BR unicast invalid", /*CNAT_ERR_6RD_V6_BR_UNICAST_INVALID*/ - "6rd v4 prefix masklen invalid", /*CNAT_ERR_6RD_V4_PREFIX_MASK_LEN_INVALID*/ - "6rd v4 suffix masklen invalid", /*CNAT_ERR_6RD_V4_SUFFIX_MASK_LEN_INVALID*/ - "6rd v4 combo masklen invalid", /*CNAT_ERR_6RD_V4_COMBO_MASK_LEN_INVALID*/ - "6rd tunnel mtu invalid", /*CNAT_ERR_6RD_TUNNEL_MTU_INVALID*/ - "6rd tunnel ttl invalid", /*CNAT_ERR_6RD_TUNNEL_TTL_INVALID*/ - "6rd tunnel tos invalid", /*CNAT_ERR_6RD_TUNNEL_TOS_INVALID*/ -}; -#endif - -f64 port_log_timestamps[HASH_TABLE_SIZE]; /* 32 KB array per core */ - -void port_exceeded_msg_log (u32 src_addr, u16 i_vrf) -{ - u32 hash_value; - f64 current_timestamp; - vlib_main_t *vlib_main; - - vlib_main = vlib_get_main(); - current_timestamp = vlib_time_now((vlib_main_t *) vlib_main); - - hash_value = ((src_addr >> 16) ^ ((src_addr & 0xffff) ^ i_vrf)) % (1024*8); - - if (PREDICT_FALSE((current_timestamp - port_log_timestamps[hash_value]) > THROTTLE_TIME)) { - u32 arg[2] = {i_vrf, src_addr}; - /* update timestamp */ - port_log_timestamps[hash_value] = current_timestamp; - spp_printf(CNAT_USER_OUT_OF_PORTS, 2, arg); - } - - return ; -} - -static void log_port_alloc_error(cnat_errno_t error, cnat_key_t *k) -{ - u32 error_code; - u32 arr[] = {k->k.vrf, k->k.ipv4, k->k.port}; - switch (error) - { - case CNAT_NO_POOL_ANY: - error_code = CNAT_NO_POOL_FOR_ANY_ERROR; - break; - case CNAT_NO_PORT_ANY: - error_code = CNAT_NO_PORT_FOR_ANY_ERROR; - break; - case CNAT_ERR_PARSER: - error_code = CNAT_WRONG_PORT_ALLOC_TYPE; - break; - case CNAT_BAD_INUSE_ANY: - error_code = CNAT_BAD_INUSE_ANY_ERROR; - break; - case CNAT_BAD_INUSE_DIRECT: - error_code = CNAT_BAD_INUSE_DIRECT_ERROR; - break; - case CNAT_NOT_FOUND_ANY: - error_code = CNAT_NOT_FOUND_ANY_ERROR; - break; - case CNAT_NOT_FOUND_DIRECT: - error_code = CNAT_NOT_FOUND_DIRECT_ERROR; - break; - case CNAT_INV_PORT_DIRECT: - error_code = CNAT_INV_PORT_FOR_DIRECT_ERROR; - break; - default: - error_code = CNAT_NEW_PORT_ALLOC_ERROR; /* If this code is seen in the log, - it means, new error codes are to be added here */ - break; - } - spp_printf(error_code, 3, arr); -} - -void cnat_db_debug_error(cnat_db_key_bucket_t *u_ki, - cnat_errno_t error) -{ - if (PREDICT_FALSE((u_ki->k.k.vrf == debug_i_vrf) && - ((u_ki->k.k.ipv4 >= debug_i_addr_start) && - (u_ki->k.k.ipv4 <= debug_i_addr_end)))) { -#ifdef DEBUG_PRINTF_ENABLED - PLATFORM_DEBUG_PRINT("failed to allocate port due to %s " - "for i-vrf 0x%x addr 0x%x port 0x%x\n", - debug_db_error[error], u_ki->k.k.vrf, - u_ki->k.k.ipv4, u_ki->k.k.port); -#endif - { - u32 arg[] = {u_ki->k.k.vrf, u_ki->k.k.ipv4, u_ki->k.k.port}; - spp_printf(error, 3, arg); - } - } -} - -void dslite_db_debug_error(dslite_db_key_bucket_t *u_ki, - cnat_errno_t error) -{ - if (PREDICT_FALSE((u_ki->dk.ipv4_key.k.vrf == debug_i_vrf) && - ((u_ki->dk.ipv4_key.k.ipv4 >= debug_i_addr_start) && - (u_ki->dk.ipv4_key.k.ipv4 <= debug_i_addr_end)))) { -#ifdef DEBUG_PRINTF_ENABLED - PLATFORM_DEBUG_PRINT("failed to allocate port due to %s " - "for i-vrf 0x%x addr 0x%x port 0x%x\n", - debug_db_error[error], u_ki->dk.ipv4_key.k.vrf, - u_ki->dk.ipv4_key.k.ipv4, u_ki->dk.ipv4_key.k.port); -#endif - { - u32 arg[] = {u_ki->dk.ipv4_key.k.vrf, u_ki->dk.ipv4_key.k.ipv4, u_ki->dk.ipv4_key.k.port}; - spp_printf(error, 3, arg); - } - } -} - -void cnat_db_debug_i2o_drop(cnat_db_key_bucket_t *ki) -{ - if (PREDICT_FALSE(((ki->k.k.vrf & CNAT_VRF_MASK) == debug_i_vrf) && - ((ki->k.k.ipv4 >= debug_i_addr_start) && - (ki->k.k.ipv4 <= debug_i_addr_end)))) { -#ifdef DEBUG_PRINTF_ENABLED - PLATFORM_DEBUG_PRINT("pakcet[i-vrf 0x%x addr 0x%x port 0x%x] dropped\n", - ki->k.k.vrf, ki->k.k.ipv4, ki->k.k.port); -#endif - { - u32 arg[] = {ki->k.k.vrf, ki->k.k.ipv4, ki->k.k.port}; - spp_printf(CNAT_PACKET_DROP_ERROR, 3, arg); - } - } -} - -void cnat_db_in2out_hash_delete (cnat_main_db_entry_t *ep, cnat_user_db_entry_t *up) -{ - u64 a, b, c; - u32 index, bucket; - cnat_main_db_entry_t *this, *prev; - -#ifdef DSLITE_DEF - if (PREDICT_FALSE(ep->flags & CNAT_DB_DSLITE_FLAG)) { - dslite_key_t dk = { - {up->ipv6[0], up->ipv6[1], up->ipv6[2], up->ipv6[3]} , - {ep->in2out_key.k.ipv4, ep->in2out_key.k.port, ep->in2out_key.k.vrf} - }; - DSLITE_V6_GET_HASH((&dk), - bucket, - CNAT_MAIN_HASH_MASK); - DSLITE_PRINTF(1, "Delete1 DSL main hash bucket ..%u\n", bucket); - } else { - CNAT_V4_GET_HASH(ep->in2out_key.key64, - bucket, CNAT_MAIN_HASH_MASK) - DSLITE_PRINTF(1, "Delete1 NAT44 main hash bucket ..%u\n", bucket); - } -#else - CNAT_V4_GET_HASH(ep->in2out_key.key64, - bucket, CNAT_MAIN_HASH_MASK) -#endif - - index = cnat_in2out_hash[bucket].next; - - ASSERT(index != EMPTY); - - prev = 0; - do { - this = cnat_main_db + index; - if (PREDICT_TRUE(this == ep)) { - if (prev == 0) { - cnat_in2out_hash[bucket].next = ep->in2out_hash.next; - return; - } else { - prev->in2out_hash.next = ep->in2out_hash.next; - return; - } - } - prev = this; - index = this->in2out_hash.next; - } while (index != EMPTY); - - ASSERT(0); -} - -void cnat_db_out2in_hash_delete (cnat_main_db_entry_t *ep) -{ - u64 a, b, c; - u32 index, bucket; - cnat_main_db_entry_t *this, *prev; - - CNAT_V4_GET_HASH(ep->out2in_key.key64, - bucket, CNAT_MAIN_HASH_MASK) - - index = cnat_out2in_hash[bucket].next; - - ASSERT(index != EMPTY); - - prev = 0; - do { - this = cnat_main_db + index; - if (PREDICT_TRUE(this == ep)) { - if (prev == 0) { - cnat_out2in_hash[bucket].next = ep->out2in_hash.next; - return; - } else { - prev->out2in_hash.next = ep->out2in_hash.next; - return; - } - } - prev = this; - index = this->out2in_hash.next; - } while (index != EMPTY); - - ASSERT(0); -} - -cnat_main_db_entry_t* -cnat_main_db_lookup_entry(cnat_db_key_bucket_t *ki) -{ - u64 a, b, c; - u32 index; - cnat_main_db_entry_t *db; - - CNAT_V4_GET_HASH(ki->k.key64, - ki->bucket, - CNAT_MAIN_HASH_MASK); - - index = cnat_in2out_hash[ki->bucket].next; - if (PREDICT_TRUE(index == EMPTY)) { - return (NULL); - } - - do { - db = cnat_main_db + index; - if (PREDICT_TRUE(db->in2out_key.key64 == ki->k.key64)) { - return db; - } - index = db->in2out_hash.next; - } while (index != EMPTY); - - return (NULL); -} - -void cnat_user_db_delete (cnat_user_db_entry_t *up) -{ - u64 a, b, c; - u32 index, bucket; - cnat_user_db_entry_t *this, *prev; - - if (PREDICT_FALSE(up->flags & CNAT_USER_DB_NAT64_FLAG) != 0) { - /* Preventive check - Not a NAT44 entry */ - return; - } - - pthread_spin_lock(cnat_db_v2_main.user_db_lockp); -#if 1 - if(PREDICT_FALSE(up->flags & CNAT_USER_DB_DSLITE_FLAG)) { - dslite_key_t dk = { - {up->ipv6[0], up->ipv6[1], up->ipv6[2], up->ipv6[3]} , - {{up->key.k.ipv4, up->key.k.port, up->key.k.vrf}} - }; - - DSLITE_V6_GET_HASH((&dk), - bucket, - CNAT_USER_HASH_MASK); - DSLITE_PRINTF(1, "Delete1 DSL user hash bucket ..%u\n", bucket); - } else { - CNAT_V4_GET_HASH(up->key.key64, - bucket, CNAT_USER_HASH_MASK) - DSLITE_PRINTF(1, "Delete1 NAT44 user hash bucket ..%u\n", bucket); - } -#else - CNAT_V4_GET_HASH(up->key.key64, - bucket, CNAT_USER_HASH_MASK) - DSLITE_PRINTF(1, "Delete2 NAT44 user hash bucket ..%u\n", bucket); -#endif - - index = cnat_user_hash[bucket].next; - - ASSERT(index != EMPTY); - - prev = 0; - do { - this = cnat_user_db + index; - if (PREDICT_TRUE(this == up)) { - if (prev == 0) { - cnat_user_hash[bucket].next = up->user_hash.next; - goto found; - } else { - prev->user_hash.next = up->user_hash.next; - goto found; - } - } - prev = this; - index = this->user_hash.next; - } while (index != EMPTY); - - ASSERT(0); - - found: - pool_put(cnat_user_db, up); - pthread_spin_unlock(cnat_db_v2_main.user_db_lockp); -} - -cnat_user_db_entry_t* -cnat_user_db_lookup_entry(cnat_db_key_bucket_t *uki) -{ - u64 a, b, c; - u32 index; - cnat_user_db_entry_t *udb=NULL; - - CNAT_V4_GET_HASH(uki->k.key64, - uki->bucket, - CNAT_USER_HASH_MASK) - - /* now: index in user vector */ - index = cnat_user_hash[uki->bucket].next; - if (PREDICT_TRUE(index != EMPTY)) { - do { - udb = cnat_user_db + index; - if (PREDICT_FALSE(udb->key.key64 == uki->k.key64)) { - return udb; - } - index = udb->user_hash.next; - } while (index != EMPTY); - } - return (NULL); -} - -cnat_user_db_entry_t* -cnat_user_db_create_entry(cnat_db_key_bucket_t *uki, - u32 portmap_index) -{ - cnat_user_db_entry_t *udb = NULL; - - pthread_spin_lock(cnat_db_v2_main.user_db_lockp); - pool_get(cnat_user_db, udb); - memset(udb, 0, sizeof(*udb)); - - udb->ntranslations = 1; - udb->portmap_index = portmap_index; - udb->key.key64 = uki->k.key64; - /* Add this user to the head of the bucket chain */ - udb->user_hash.next = - cnat_user_hash[uki->bucket].next; - cnat_user_hash[uki->bucket].next = udb - cnat_user_db; - -#ifndef NO_BULK_LOGGING - INIT_BULK_CACHE(udb) -#endif /* NO_BULK_LOGGING */ - pthread_spin_unlock(cnat_db_v2_main.user_db_lockp); - return udb; -} - -cnat_main_db_entry_t* -cnat_create_main_db_entry_and_hash(cnat_db_key_bucket_t *ki, - cnat_db_key_bucket_t *ko, - cnat_user_db_entry_t *udb) -{ - u64 a, b, c; - u32 db_index; - cnat_main_db_entry_t *db = NULL; - - pool_get(cnat_main_db, db); - memset(db, 0, sizeof(*db)); - - db_index = db - cnat_main_db; - db->in2out_key.k.ipv4 = ki->k.k.ipv4; - db->in2out_key.k.port = ki->k.k.port; - db->in2out_key.k.vrf = ki->k.k.vrf; - db->out2in_key.k.ipv4 = ko->k.k.ipv4; - db->out2in_key.k.port = ko->k.k.port; - db->out2in_key.k.vrf = ko->k.k.vrf; - - db->user_ports.next = db_index; - db->user_ports.prev = db_index; - db->user_index = udb - cnat_user_db; - //db->portmap_index = udb->portmap_index; - db->flags &= ~(CNAT_DB_DSLITE_FLAG); // Mark that it is not dslite - if (PREDICT_FALSE(udb->ntranslations == 1)) { - /* - * first port for this src vrf/src ip addr - */ - udb->translation_list_head_index = db_index; - } else { - index_dlist_addtail(udb->translation_list_head_index, - (u8 *)cnat_main_db, sizeof(cnat_main_db[0]), - STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports), - db_index); - } - - /* - * setup o2i hash key - */ - CNAT_V4_GET_HASH(ko->k.key64, - ko->bucket, - CNAT_MAIN_HASH_MASK) - db->out2in_hash.next = cnat_out2in_hash[ko->bucket].next; - cnat_out2in_hash[ko->bucket].next = db_index; - /* - * setup i2o hash key, bucket is already calculate - */ - db->in2out_hash.next = cnat_in2out_hash[ki->bucket].next; - cnat_in2out_hash[ki->bucket].next = db_index; - -#if DEBUG > 1 - printf("\nMy_Instance_Number %d: Bucket %d, Db_Index %d", - my_instance_number, ki->bucket, db_index); - printf("\nInside (VRF 0x%x, IP 0x%x, PORT 0x%x)", - db->in2out_key.k.vrf, db->in2out_key.k.ipv4, db->in2out_key.k.port); - printf("\nOutside (VRF 0x%x, IP 0x%x, PORT 0x%x)", - db->out2in_key.k.vrf, db->out2in_key.k.ipv4, db->out2in_key.k.port); - printf("\nUser Index %d, IP 0x%x", - db->user_index, udb->key.k.ipv4); -#endif - - NAT44_COMMON_STATS.active_translations++; - - return db; -} - -static inline void pptp_clear_all_channels( - cnat_main_db_entry_t *db) -{ - u32 db_index, current_db_index; - cnat_main_db_entry_t *temp_db; - - /* clear all channels */ - - db_index = db->proto_data.pptp_list.next; - current_db_index = db - cnat_main_db; - - while( db_index != EMPTY) { - temp_db = cnat_main_db + db_index; - db_index = temp_db->proto_data.pptp_list.next; - temp_db->entry_expires = 0; - if(PREDICT_FALSE(temp_db->proto_data.pptp_list.prev - == current_db_index)) { // Decouple child GREs from parent - temp_db->proto_data.pptp_list.prev = EMPTY; - } - } - - db->proto_data.pptp_list.next = EMPTY; -} - -void pptp_remove_channel_from_tunnel(cnat_main_db_entry_t *db) { - - cnat_main_db_entry_t *prev_db, *next_db; - - prev_db = cnat_main_db + db->proto_data.pptp_list.prev; - next_db = cnat_main_db + db->proto_data.pptp_list.next; - - /* remove entry from the tunnel list */ - if(PREDICT_TRUE(db->proto_data.pptp_list.prev != EMPTY)) { - prev_db->proto_data.pptp_list.next = - db->proto_data.pptp_list.next ; - } - - if(db->proto_data.pptp_list.next != EMPTY) { - next_db->proto_data.pptp_list.prev - = db->proto_data.pptp_list.prev; - } - -} - -void cnat_delete_main_db_entry_v2 (cnat_main_db_entry_t *ep) -{ - u32 main_db_index; - u32 vrfmap_len, udb_len; - cnat_user_db_entry_t *up =0; - cnat_portmap_v2_t *pm =0; - cnat_portmap_v2_t *my_pm =0; - cnat_vrfmap_t *my_vrfmap =0; - u16 static_port_range; -#ifndef NO_BULK_LOGGING - bulk_alloc_size_t bulk_size; - int nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED; -#endif - pool_header_t *h = pool_header(cnat_user_db); - u16 instance = 0; - u32 my_index; - - - if (PREDICT_FALSE(ep->flags & CNAT_DB_NAT64_FLAG) != 0) { - /* Preventive check - Not a NAT44 entry */ - return; - } - - pthread_spin_lock(cnat_db_v2_main.main_db_lockp); - if(PREDICT_FALSE(ep->flags & - CNAT_DB_FLAG_PPTP_TUNNEL_ACTIVE)) { - pptp_clear_all_channels(ep); - PPTP_DECR(active_tunnels); - } - - if(PREDICT_FALSE(ep->flags & - CNAT_DB_FLAG_PPTP_GRE_ENTRY)) { - pptp_remove_channel_from_tunnel(ep); - PPTP_DECR(active_channels); - } - - /* This function gets called from various locations.. - * many times from config handler.. so we - * to ensure that multiple sessions if any are - * released - */ - - if(PREDICT_FALSE(ep->nsessions > 1)) { - cnat_session_entry_t *sdb; - while(ep->nsessions > 1 && - ep->session_head_index != EMPTY) { - sdb = cnat_session_db + ep->session_head_index; - cnat_delete_session_db_entry(sdb, TRUE); - } - } - - /* Find the set of portmaps for the outside vrf */ - vrfmap_len = vec_len(cnat_map_by_vrf); - udb_len = vec_len(cnat_user_db); - - /* In case of invalid user just return, deleting only main db - * is not a good idea, since some valid user db entry might be pointing - * to that main db and hence leave the dbs in a inconsistent state - */ - if (PREDICT_FALSE((ep->user_index >= udb_len) || - (clib_bitmap_get(h->free_bitmap, ep->user_index)))) { -#ifdef DEBUG_PRINTF_ENABLED - printf("invalid/unused user index in db %d\n", ep->user_index); -#endif - spp_printf(CNAT_INV_UNUSED_USR_INDEX, 1, (u32 *) &(ep->user_index)); - cnat_main_db_entry_dump(ep); - goto unlock; - } - - up = cnat_user_db + ep->user_index; - -/* Point to the right portmap list */ -if (PREDICT_FALSE(ep->flags & CNAT_DB_DSLITE_FLAG)) { - instance = ep->dslite_nat44_inst_id; - pm = dslite_table_db_ptr[instance].portmap_list; - if(PREDICT_FALSE((pm == NULL))) { - DSLITE_PRINTF(3, "NULL portmap list for dslite_id %u, state %u\n", - instance, dslite_table_db_ptr[instance].state); - cnat_main_db_entry_dump(ep); - goto delete_entry; - } - static_port_range = - STAT_PORT_RANGE_FROM_INST_PTR(&(dslite_table_db_ptr[instance])); - /* - * Netflow logging API for delete event - */ - bulk_size = - BULKSIZE_FROM_VRFMAP(&(dslite_table_db_ptr[instance])); -} else { - if (PREDICT_FALSE(ep->vrfmap_index >= vrfmap_len)) { -#ifdef DEBUG_PRINTF_ENABLED - printf("invalid vrfmap index in db\n"); -#endif - spp_printf(CNAT_INVALID_VRFMAP_INDEX, 0, NULL); - cnat_main_db_entry_dump(ep); - goto delete_entry; - } - instance = NAT44_RESERVED_INST_ID; - my_vrfmap = cnat_map_by_vrf + ep->vrfmap_index; - pm = my_vrfmap->portmap_list; - static_port_range = cnat_static_port_range; - bulk_size = BULKSIZE_FROM_VRFMAP(my_vrfmap); -} - - if (PREDICT_FALSE(ep->flags & CNAT_DB_FLAG_PORT_PAIR)) { - /* Give back the port(s) */ - cnat_port_free_v2_bulk(pm, up->portmap_index, - PORT_PAIR, ep->out2in_key.k.port, up, static_port_range -#ifndef NO_BULK_LOGGING - , bulk_size, &nfv9_log_req -#endif - ); - } else { - /* Give back the port(s) */ - cnat_port_free_v2_bulk (pm, up->portmap_index, - PORT_SINGLE, ep->out2in_key.k.port, up, static_port_range -#ifndef NO_BULK_LOGGING - , bulk_size, &nfv9_log_req -#endif - ); - } - - if (PREDICT_TRUE(!(ep->flags & CNAT_DB_DSLITE_FLAG))) { - if(PREDICT_FALSE(nfv9_log_req != CACHE_ALLOC_NO_LOG_REQUIRED)) { - if(PREDICT_FALSE(my_vrfmap->nf_logging_policy == SESSION_LOG_ENABLE)) { - if(ep->nsessions != 0) { - cnat_nfv9_nat44_log_session_delete(ep, NULL, my_vrfmap); - } - } else { - cnat_nfv9_log_mapping_delete(ep, my_vrfmap -#ifndef NO_BULK_LOGGING - , nfv9_log_req -#endif - ); - } - if(PREDICT_TRUE((my_vrfmap->syslog_logging_policy != SESSION_LOG_ENABLE) || - (ep->nsessions != 0))) { - cnat_syslog_nat44_mapping_delete(ep, my_vrfmap, NULL -#ifndef NO_BULK_LOGGING - , nfv9_log_req -#endif - ); - } - } - } else { - if(PREDICT_FALSE(nfv9_log_req != CACHE_ALLOC_NO_LOG_REQUIRED)) { - if(PREDICT_FALSE( dslite_table_db_ptr[instance].nf_logging_policy == - SESSION_LOG_ENABLE)) { - cnat_nfv9_ds_lite_log_session_delete(ep, - (dslite_table_db_ptr + instance),NULL); - } else { - cnat_nfv9_ds_lite_mapping_delete(ep, - (dslite_table_db_ptr + instance) -#ifndef NO_BULK_LOGGING - , nfv9_log_req -#endif - ); - } -#ifdef TOBE_PORTED - cnat_syslog_ds_lite_mapping_delete(ep, - (dslite_table_db_ptr + instance), NULL -#ifndef NO_BULK_LOGGING - , nfv9_log_req -#endif - ); -#endif /* TOBE_PORTED */ - } - } - -delete_entry: - - main_db_index = ep - cnat_main_db; - - pthread_spin_lock(cnat_db_v2_main.user_db_lockp); - up->ntranslations--; - pthread_spin_unlock(cnat_db_v2_main.user_db_lockp); - - /* - * when user reaches max allowed port limit - * we generate icmp msg and inc the counter - * when counter reach the icmp msg rate limit - * we stop icmp msg gen - * when a user port is freed - * that means we need to clear the msg gen counter - * so that next time - * reach max port limit, we can generate new icmp msg again - */ - up->icmp_msg_count = 0; - - up->translation_list_head_index = index_dlist_remelem ( - up->translation_list_head_index, (u8 *)cnat_main_db, - sizeof (cnat_main_db[0]), - STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports), - main_db_index); - - cnat_db_in2out_hash_delete(ep, up); - - if (PREDICT_FALSE(up->ntranslations == 0)) { - ASSERT(up->translation_list_head_index == EMPTY); - nat44_dslite_common_stats[instance].num_subscribers--; - my_index = up->portmap_index; - my_pm = pm + my_index; - if(PREDICT_TRUE(my_pm->private_ip_users_count)) { - my_pm->private_ip_users_count--; -#ifdef DEBUG_PRINTF_IP_N_TO_1_ENABLED - PLATFORM_DEBUG_PRINT("\n cnat_delete_main_db_entry_v2 " - "private_ip_users_count = %d", - my_pm->private_ip_users_count); -#endif - - } - cnat_user_db_delete(up); - - } - - /* Remove from main DB hashes */ - //cnat_db_in2out_hash_delete(ep); - cnat_db_out2in_hash_delete(ep); - - pool_put(cnat_main_db, ep); - - if(PREDICT_FALSE(ep->flags & CNAT_DB_FLAG_STATIC_PORT)) { - nat44_dslite_common_stats[instance].num_static_translations--; - } else { - nat44_dslite_common_stats[instance].num_dynamic_translations--; - } - nat44_dslite_common_stats[instance].active_translations--; - nat44_dslite_global_stats[!!(instance - 1)].translation_delete_count ++; -unlock: - pthread_spin_unlock(cnat_db_v2_main.main_db_lockp); -} - -cnat_main_db_entry_t* -cnat_main_db_lookup_entry_out2in (cnat_db_key_bucket_t *ko) -{ - u64 a, b, c; - u32 index; - cnat_main_db_entry_t *db; - - CNAT_V4_GET_HASH(ko->k.key64, - ko->bucket, - CNAT_MAIN_HASH_MASK); - - index = cnat_out2in_hash[ko->bucket].next; - if (PREDICT_TRUE(index == EMPTY)) { - return (NULL); - } - - do { - db = cnat_main_db + index; - if (PREDICT_TRUE(db->out2in_key.key64 == ko->k.key64)) { - return db; - } - index = db->out2in_hash.next; - } while (index != EMPTY); - - return (NULL); -} - -/* Creates 2 sessions. - * Moves the default dest info from mdb to first session - * Fills the dest_info details in to second session and - * returns the pointer to second session - */ -cnat_session_entry_t *cnat_handle_1to2_session( - cnat_main_db_entry_t *mdb, - cnat_key_t *dest_info) -{ - cnat_key_t old_dest_info; - pool_header_t *h; - u32 free_session = 0; - u16 instance; - cnat_session_entry_t *session_db1 = NULL, *session_db2 = NULL; - - h = pool_header(cnat_session_db); - free_session = vec_len(h->free_indices) - 1; - - if (PREDICT_FALSE(free_session < 2)) { - if (mdb->flags & CNAT_DB_DSLITE_FLAG) { - instance = mdb->dslite_nat44_inst_id; - } else { - instance = NAT44_RESERVED_INST_ID; - } - - /* we need 2 sessions here, return NULL */ - nat44_dslite_common_stats[instance].drops_sessiondb_limit_exceeded++; - return NULL; - } - - old_dest_info.k.ipv4 = mdb->dst_ipv4; - old_dest_info.k.port = mdb->dst_port; - old_dest_info.k.vrf = mdb->in2out_key.k.vrf; - - /* create 2 new sessions */ - session_db1 = cnat_create_session_db_entry(&old_dest_info, - mdb, FALSE); - - if(PREDICT_FALSE(session_db1 == NULL)) { - return NULL; - } - - /* update pkt info to session 2 */ - session_db2 = cnat_create_session_db_entry(dest_info, - mdb, TRUE); - - if(PREDICT_FALSE(session_db2 == NULL)) { - cnat_delete_session_db_entry(session_db1, FALSE); - return NULL; - } - /* update main db info to session 1 */ - cnat_dest_update_main2session(mdb, session_db1); - - return session_db2; -} - -/* The below function shold be called only - * when a NAT44 STATIC entry received traffic - * for the first time. This is to ensure - * the destination is noted and logged - */ -void cnat_add_dest_n_log( - cnat_main_db_entry_t *mdb, - cnat_key_t *dest_info) -{ - - if(PREDICT_FALSE(mdb->nsessions != 0)) { - return; /* Should not have been called */ - } - - mdb->dst_ipv4 = dest_info->k.ipv4; - mdb->dst_port = dest_info->k.port; - mdb->nsessions = 1; - mdb->entry_expires = cnat_current_time; - u16 instance; - - if (mdb->flags & CNAT_DB_DSLITE_FLAG) { - instance = mdb->dslite_nat44_inst_id; - cnat_session_log_ds_lite_mapping_create(mdb, - (dslite_table_db_ptr + instance),NULL); - } else { - instance = NAT44_RESERVED_INST_ID; - cnat_vrfmap_t *my_vrfmap = cnat_map_by_vrf + mdb->vrfmap_index; - cnat_session_log_nat44_mapping_create(mdb, 0, my_vrfmap); - } -} - -/* - * this function is called by exception node - * when lookup is fialed in i2o node - * - * if reash per user port limit, - * set user_db_entry pointer, and error == CNAT_OUT_LIMIT - */ -static cnat_main_db_entry_t* -_cnat_get_main_db_entry_v2(cnat_db_key_bucket_t *ki, - port_pair_t port_pair_type, - port_type_t port_type, - cnat_gen_icmp_info *info, - cnat_key_t *dest_info) -{ - u16 protocol; - cnat_errno_t rv; - cnat_db_key_bucket_t u_ki, ko; - u32 my_index, free_main, free_user; - u32 current_timestamp; - u16 my_vrfmap_index; - u16 my_vrfmap_entry_found = 0; - cnat_vrfmap_t *my_vrfmap =0; - cnat_portmap_v2_t *pm =0; - cnat_user_db_entry_t *udb = 0; - cnat_main_db_entry_t *db = 0; - pool_header_t *h; - u16 port_limit; - cnat_portmap_v2_t *my_pm = 0; - -#ifndef NO_BULK_LOGGING - int nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED; -#endif - - - /* - * need to try lookup again because - * second pkt may come here before the entry is created - * by receiving first pkt due to high line rate. - */ - info->gen_icmp_msg = CNAT_NO_ICMP_MSG; - info->error = CNAT_SUCCESS; - db = cnat_main_db_lookup_entry(ki); - if (PREDICT_TRUE(db)) { - /* what if the source is talking to a - * new dest now? We will have to handle this case and - * take care of - creating session db and logging - */ - if(PREDICT_FALSE((!dest_info->k.ipv4) && (!dest_info->k.port))) { - return db; /* if dest_info is null don't create session */ - } - if(PREDICT_TRUE((db->dst_ipv4 == dest_info->k.ipv4) && - (db->dst_port == dest_info->k.port))) { - return db; - } - dest_info->k.vrf = db->in2out_key.k.vrf; - /* Src is indeed talking to a different dest */ - cnat_session_entry_t *session_db2 = NULL; - if(PREDICT_TRUE(db->nsessions == 1)) { - session_db2 = cnat_handle_1to2_session(db, dest_info); - if(PREDICT_TRUE(session_db2 != NULL)) { - CNAT_DB_TIMEOUT_RST(session_db2); - return db; - } else { - info->error = CNAT_ERR_NO_SESSION_DB; - return NULL; - } - } else if(PREDICT_FALSE(db->nsessions == 0)) { - /* Should be static entry.. should never happen - */ - if(PREDICT_TRUE(dest_info->k.ipv4 != 0)) { - cnat_add_dest_n_log(db, dest_info); - } - return db; - } else { - /* The src has already created multiple sessions.. very rare - */ - session_db2 = cnat_create_session_db_entry(dest_info, - db, TRUE); - if(PREDICT_TRUE(session_db2 != NULL)) { - CNAT_DB_TIMEOUT_RST(session_db2); - return db; - } else { - info->error = CNAT_ERR_NO_SESSION_DB; - return NULL; - } - } - - } - - /* - * step 1. check if outside vrf is configured or not - * and Find the set of portmaps for the outside vrf - * insider vrf is one to one mappted to outside vrf - * key is vrf and ip only - * ki.k.k.vrf has protocol bits, mask out - */ - protocol = ki->k.k.vrf & CNAT_PRO_MASK; - u_ki.k.k.vrf = ki->k.k.vrf & CNAT_VRF_MASK; - u_ki.k.k.ipv4 = ki->k.k.ipv4; - u_ki.k.k.port = 0; - - my_vrfmap_index = vrf_map_array[u_ki.k.k.vrf]; - my_vrfmap = cnat_map_by_vrf + my_vrfmap_index; - - my_vrfmap_entry_found = ((my_vrfmap_index != VRF_MAP_ENTRY_EMPTY) && - (my_vrfmap->status == S_RUN) && - (my_vrfmap->i_vrf == u_ki.k.k.vrf)); - - if (PREDICT_FALSE(!my_vrfmap_entry_found)) { - u32 arr[] = {ki->k.k.vrf, ki->k.k.ipv4, ki->k.k.port}; - if ((my_vrfmap_index == VRF_MAP_ENTRY_EMPTY) || - (my_vrfmap->i_vrf == u_ki.k.k.vrf)) { - info->error = CNAT_NO_CONFIG; - CNAT_DEBUG_INSIDE_ERR(CNAT_NO_CONFIG) - spp_printf(CNAT_NO_CONFIG_ERROR, 3, arr); - } else { - info->error = CNAT_NO_VRF_RUN; - CNAT_DEBUG_INSIDE_ERR(CNAT_NO_VRF_RUN) - spp_printf(CNAT_NO_VRF_RUN_ERROR, 3, arr); - } - - return (NULL); - } - - pm = my_vrfmap->portmap_list; - - port_limit = my_vrfmap->port_limit; - if(PREDICT_FALSE(!port_limit)) { - port_limit = cnat_main_db_max_ports_per_user; - } - /* - * set o2i key with protocl bits - */ - ko.k.k.vrf = my_vrfmap->o_vrf | protocol; - - /* - * step 2. check if src vrf, src ip addr is alreay - * in the user db - * if yes, use PORT_ALLOC_DIRECTED - * if no, use PORT_ALLOC_ANY since it is first time - */ - udb = cnat_user_db_lookup_entry(&u_ki); - if (PREDICT_TRUE(udb)) { - /* - * not first time allocate port for this user - * check limit - */ - if (PREDICT_FALSE(udb->ntranslations >= - port_limit)) { - /* Check for the port type here. If we are getting - * a STATIC PORT, allow the config. - */ - if (PREDICT_TRUE(port_type != PORT_TYPE_STATIC)) { - info->error = CNAT_OUT_LIMIT; - CNAT_SET_ICMP_MSG_INFO - CNAT_DEBUG_INSIDE_ERR(CNAT_OUT_LIMIT) - port_exceeded_msg_log(u_ki.k.k.ipv4, u_ki.k.k.vrf); - in2out_drops_port_limit_exceeded ++; - u_ki.k.k.port = ki->k.k.port; - u_ki.k.k.vrf = ki->k.k.vrf; - handle_cnat_port_exceeded_logging(udb, &u_ki.k, my_vrfmap); - return (NULL); - } - } - CHECK_CLEAR_PORT_LIMIT_EXCEED_FLAG(udb, - port_limit) - - /* - * check if main db has space to accomodate new entry - */ - h = pool_header(cnat_main_db); - - free_main = vec_len(h->free_indices) - 1; - if (PREDICT_FALSE(!free_main)) { - info->error = CNAT_MAIN_DB_LIMIT; - CNAT_SET_ICMP_MSG_INFO - in2out_drops_system_limit_reached ++; - CNAT_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT) - - current_timestamp = spp_trace_log_get_unix_time_in_seconds(); - if (PREDICT_FALSE((current_timestamp - last_log_timestamp) > - 1800)) { - spp_printf(CNAT_SESSION_THRESH_EXCEEDED, 0, NULL); - last_log_timestamp = current_timestamp; - } - -#ifdef UT_TEST_CODE - printf("Limit reached : OLD USER"); -#endif - return NULL; - } - - /* - * allocate port, from existing mapping - */ - my_index = udb->portmap_index; - - if (PREDICT_FALSE(port_type == PORT_TYPE_STATIC)) { - rv = cnat_static_port_alloc_v2_bulk(pm, - PORT_ALLOC_DIRECTED, - port_pair_type, - ki->k.k.ipv4, - ki->k.k.port, - &my_index, - &(ko.k.k.ipv4), - &(ko.k.k.port), - cnat_static_port_range -#ifndef NO_BULK_LOGGING - , - udb, BULKSIZE_FROM_VRFMAP(my_vrfmap), - &nfv9_log_req -#endif - , my_vrfmap->ip_n_to_1 - ); - - } else if (PREDICT_TRUE(port_type != PORT_TYPE_RTSP) ) { - - rv = cnat_dynamic_port_alloc_v2_bulk(pm, - PORT_ALLOC_DIRECTED, - port_pair_type, - &my_index, - &(ko.k.k.ipv4), - &(ko.k.k.port), - cnat_static_port_range -#ifndef NO_BULK_LOGGING - , - udb, BULKSIZE_FROM_VRFMAP(my_vrfmap), - &nfv9_log_req -#endif - , my_vrfmap->ip_n_to_1, - &(my_vrfmap->rseed_ip) - ); - - } else { - /* - * For RTSP, two translation entries are created, - * check if main db has space to accomodate two new entry - */ - free_main = free_main - 1; - if (PREDICT_FALSE(!free_main)) { - info->error = CNAT_MAIN_DB_LIMIT; - CNAT_SET_ICMP_MSG_INFO - in2out_drops_system_limit_reached ++; - CNAT_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT) - - return NULL; - } else { - rv = cnat_dynamic_port_alloc_rtsp_bulk(pm, - PORT_ALLOC_DIRECTED, - port_pair_type, - ki->k.k.port, - &my_index, - &(ko.k.k.ipv4), - &(ko.k.k.port), - cnat_static_port_range -#ifndef NO_BULK_LOGGING - , - udb, BULKSIZE_FROM_VRFMAP(my_vrfmap), - &nfv9_log_req -#endif - , &(my_vrfmap->rseed_ip) - ); - } - } - - - if (PREDICT_FALSE(rv != CNAT_SUCCESS)) { - info->error = rv; - CNAT_SET_ICMP_MSG_INFO - CNAT_DEBUG_INSIDE_ERR(rv) - in2out_drops_resource_depletion++; - log_port_alloc_error(rv, &(ki->k)); - return (NULL); - } - /* - * increment port in use for this user - */ - pthread_spin_lock(cnat_db_v2_main.user_db_lockp); - udb->ntranslations += 1; - pthread_spin_unlock(cnat_db_v2_main.user_db_lockp); - - } else { - /* - * first time allocate port for this user - */ - - /* - * Do not create entry if port limit is invalid - */ - - if (PREDICT_FALSE(!port_limit)) { - if (PREDICT_TRUE(port_type != PORT_TYPE_STATIC)) { - info->error = CNAT_OUT_LIMIT; - in2out_drops_port_limit_exceeded ++; - port_exceeded_msg_log(u_ki.k.k.ipv4, u_ki.k.k.vrf); - CNAT_SET_ICMP_MSG_INFO - CNAT_DEBUG_INSIDE_ERR(CNAT_OUT_LIMIT) - return (NULL); - } - } - - /* - * Check if main db has space for new entry - * Allowing a user db entry to be created if main db is not free - * will cause a port to be allocated to that user, which results in - * wastage of that port, hence the check is done here. - */ - h = pool_header(cnat_main_db); - free_main = vec_len(h->free_indices) - 1; - h = pool_header(cnat_user_db); - free_user = vec_len(h->free_indices) - 1; - - /* - * If either main_db or user_db does not have entries - * bail out, with appropriate error - */ - if (PREDICT_FALSE(!(free_main && free_user))) { - u32 log_error; - if(free_main) { - info->error = CNAT_USER_DB_LIMIT; - log_error = CNAT_USER_DB_LIMIT_ERROR; - } else { - info->error = CNAT_MAIN_DB_LIMIT; - log_error = CNAT_MAIN_DB_LIMIT_ERROR; - } - in2out_drops_system_limit_reached ++; - CNAT_SET_ICMP_MSG_INFO - CNAT_DEBUG_INSIDE_ERR(info->error) - spp_printf(log_error, 0, 0); - return NULL; - } - - if (PREDICT_FALSE(port_type == PORT_TYPE_STATIC)) { - rv = cnat_static_port_alloc_v2_bulk(pm, - PORT_ALLOC_ANY, - port_pair_type, - ki->k.k.ipv4, - ki->k.k.port, - &my_index, - &(ko.k.k.ipv4), - &(ko.k.k.port), - cnat_static_port_range -#ifndef NO_BULK_LOGGING - , - udb, BULKSIZE_FROM_VRFMAP(my_vrfmap), - &nfv9_log_req -#endif - , my_vrfmap->ip_n_to_1 - ); - - } else if (PREDICT_TRUE(port_type != PORT_TYPE_RTSP)) { - rv = cnat_dynamic_port_alloc_v2_bulk(pm, - PORT_ALLOC_ANY, - port_pair_type, - &my_index, - &(ko.k.k.ipv4), - &(ko.k.k.port), - cnat_static_port_range -#ifndef NO_BULK_LOGGING - , NULL, BULKSIZE_FROM_VRFMAP(my_vrfmap), - &nfv9_log_req -#endif - , my_vrfmap->ip_n_to_1, - &(my_vrfmap->rseed_ip) - ); - } else { - /* - * For RTSP, two translation entries are created, - * check if main db has space to accomodate two new entry - */ - free_main = free_main - 1; - if (PREDICT_FALSE(!free_main)) { - info->error = CNAT_MAIN_DB_LIMIT; - CNAT_SET_ICMP_MSG_INFO - in2out_drops_system_limit_reached ++; - CNAT_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT) - - return NULL; - } else { - - rv = cnat_dynamic_port_alloc_rtsp_bulk(pm, - PORT_ALLOC_ANY, - port_pair_type, - ki->k.k.port, - &my_index, - &(ko.k.k.ipv4), - &(ko.k.k.port), - cnat_static_port_range -#ifndef NO_BULK_LOGGING - , NULL, BULKSIZE_FROM_VRFMAP(my_vrfmap), - &nfv9_log_req -#endif - , &(my_vrfmap->rseed_ip) - ); - /* TODO: Add the port pair flag here */ - } - } - - - - if (PREDICT_FALSE(rv != CNAT_SUCCESS)) { - info->error = rv; - in2out_drops_resource_depletion ++; - CNAT_SET_ICMP_MSG_INFO - CNAT_DEBUG_INSIDE_ERR(rv) - log_port_alloc_error(rv, &(ki->k)); - return (NULL); - } - /* - * create entry in user db - */ - udb = cnat_user_db_create_entry(&u_ki, my_index); - NAT44_COMMON_STATS.num_subscribers++; - my_pm = pm + my_index; - if(PREDICT_TRUE(my_pm->private_ip_users_count < PORTS_PER_ADDR)) { - my_pm->private_ip_users_count++; -#ifdef DEBUG_PRINTF_IP_N_TO_1_ENABLED - PLATFORM_DEBUG_PRINT("\n cnat_get_main_db_entry_v2 " - "dynamic alloc private_ip_users_count = %d", - my_pm->private_ip_users_count); -#endif - } else { - PLATFORM_DEBUG_PRINT("\n ERROR: private_ip_users_count has " - "reached MAX PORTS_PER_ADDR"); - } -#ifndef NO_BULK_LOGGING - if(PREDICT_TRUE(udb && (BULK_ALLOC_NOT_ATTEMPTED != nfv9_log_req))) { - cnat_update_bulk_range_cache(udb, ko.k.k.port, - BULKSIZE_FROM_VRFMAP(my_vrfmap)); - } -#endif /* #ifndef NO_BULK_LOGGING */ - - } - - /* - * step 3: - * outside port is allocated for this src vrf/src ip addr - * 1)create a new entry in main db - * 2)setup cnat_out2in_hash key - * 3)setup cnat_in2out_hash key - */ - db = cnat_create_main_db_entry_and_hash(ki, &ko, udb); - - translation_create_count ++; -#ifdef DSLITE_DEF - db->dslite_nat44_inst_id = NAT44_RESERVED_INST_ID; -#endif - db->vrfmap_index = my_vrfmap - cnat_map_by_vrf; - - /* - * don't forget logging - * logging API is unconditional, - * logging configuration check is done inside the inline function - */ - - db->dst_ipv4 = dest_info->k.ipv4; - db->dst_port = dest_info->k.port; - if(PREDICT_TRUE(db->dst_ipv4 || db->dst_port)) { - db->nsessions++; - } - - if(PREDICT_FALSE(nfv9_log_req != CACHE_ALLOC_NO_LOG_REQUIRED)) { - if(PREDICT_FALSE(my_vrfmap->nf_logging_policy == SESSION_LOG_ENABLE)) { - /* do not log for static entries.. we will log when traffic flows */ - if(PREDICT_TRUE(db->dst_ipv4 || db->dst_port)) { - cnat_nfv9_nat44_log_session_create(db, 0, my_vrfmap); - } - } else { - cnat_nfv9_log_mapping_create(db, my_vrfmap -#ifndef NO_BULK_LOGGING - , nfv9_log_req -#endif - ); - } - if(PREDICT_TRUE((my_vrfmap->syslog_logging_policy != SESSION_LOG_ENABLE) || - (db->dst_ipv4 || db->dst_port))) { - cnat_syslog_nat44_mapping_create(db, my_vrfmap, 0 -#ifndef NO_BULK_LOGGING - , nfv9_log_req -#endif - ); - } - } - if (PREDICT_FALSE(port_pair_type == PORT_PAIR)) { - cnat_main_db_entry_t *db2 = 0; - cnat_db_key_bucket_t new_ki = *ki; - u64 a, b, c; - - new_ki.k.k.port += 1; - ko.k.k.port += 1; - - CNAT_V4_GET_HASH(new_ki.k.key64, new_ki.bucket, - CNAT_MAIN_HASH_MASK); - - db2 = cnat_create_main_db_entry_and_hash(&new_ki, &ko, udb); - - translation_create_count ++; -#ifdef DSLITE_DEF - db2->dslite_nat44_inst_id = NAT44_RESERVED_INST_ID; -#endif - db2->vrfmap_index = my_vrfmap - cnat_map_by_vrf; - db2->entry_expires = cnat_current_time; - db2->flags |= CNAT_DB_FLAG_ALG_ENTRY; - pthread_spin_lock(cnat_db_v2_main.user_db_lockp); - udb->ntranslations += 1; - pthread_spin_unlock(cnat_db_v2_main.user_db_lockp); - db2->dst_ipv4 = dest_info->k.ipv4; - db2->dst_port = dest_info->k.port; - db2->nsessions = 0; /* For ALG db, set sessions to 0 - CSCuf78420 */ - - if(PREDICT_FALSE(nfv9_log_req != CACHE_ALLOC_NO_LOG_REQUIRED)) { - if(PREDICT_FALSE(my_vrfmap->nf_logging_policy == SESSION_LOG_ENABLE)) { - /* do not log for static entries.. we will log when traffic flows */ - if(PREDICT_TRUE(db2->dst_ipv4 || db2->dst_port)) { - cnat_nfv9_nat44_log_session_create(db2, 0, my_vrfmap); - } - } else { - cnat_nfv9_log_mapping_create(db2, my_vrfmap -#ifndef NO_BULK_LOGGING - , nfv9_log_req -#endif - ); - } - if(PREDICT_TRUE((my_vrfmap->syslog_logging_policy != SESSION_LOG_ENABLE) || - (db2->dst_ipv4 || db2->dst_port))) { - cnat_syslog_nat44_mapping_create(db2, my_vrfmap, 0 -#ifndef NO_BULK_LOGGING - , nfv9_log_req -#endif - ); - } - } - } - - return db; -} - -cnat_main_db_entry_t* -cnat_get_main_db_entry_v2(cnat_db_key_bucket_t *ki, - port_pair_t port_pair_type, - port_type_t port_type, - cnat_gen_icmp_info *info, - cnat_key_t *dest_info) -{ - - cnat_main_db_entry_t *db; - pthread_spin_lock(cnat_db_v2_main.main_db_lockp); - db = _cnat_get_main_db_entry_v2(ki, port_pair_type, - port_type, info, dest_info); - pthread_spin_unlock(cnat_db_v2_main.main_db_lockp); - return db; -} - -/* - * this function is called from config handler only - * to allocate a static port based db entry - * - * the actual mapped address and port are already specified - */ -cnat_main_db_entry_t* -cnat_create_static_main_db_entry_v2 (cnat_db_key_bucket_t *ki, - cnat_db_key_bucket_t *ko, - cnat_vrfmap_t *my_vrfmap, - cnat_gen_icmp_info *info) -{ - u16 protocol; - u32 head; - cnat_errno_t rv; - cnat_db_key_bucket_t u_ki; - u32 my_index, free_main, free_user; - cnat_portmap_v2_t *pm =0; - cnat_portmap_v2_t *my_pm =0; - cnat_user_db_entry_t *udb = 0; - cnat_main_db_entry_t *db = 0; - pool_header_t *h; -#ifndef NO_BULK_LOGGING - int nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED; -#endif - - /* UNUSED. Therefore not ported to be multi-thread friendly */ - ASSERT(0); - - /* - * need to try lookup again because - * second pkt may come here before the entry is created - * by receiving first pkt due to high line rate. - */ - info->gen_icmp_msg = CNAT_NO_ICMP_MSG; - info->error = CNAT_SUCCESS; - db = cnat_main_db_lookup_entry(ki); - - /* - * If we already have an entry with this inside address, port - * check delete the entry and proceed further. This should - * If yes, something is terribly wrong. Bail out - */ - if (PREDICT_FALSE(db)) { - - if (db->flags & CNAT_DB_FLAG_STATIC_PORT) { - - if ((db->out2in_key.k.ipv4 == ko->k.k.ipv4) && - (db->out2in_key.k.port == ko->k.k.port) && - (db->out2in_key.k.vrf == ko->k.k.vrf)) { - -#ifdef DEBUG_PRINTF_ENABLED - printf("Same Static Port Exists ki 0x%16llx ko 0x%16llx", - ki->k, ko->k); -#endif - /* - * We have already programmed this, return - */ - return (db); - } - - /* - * We already have a static port with different mapping - * Return an error for this case. - */ - info->error = CNAT_ERR_PARSER; - -#ifdef DEBUG_PRINTF_ENABLED - printf("Static Port Existing and Diff ki 0x%16llx ko 0x%16llx", - ki, db->out2in_key); -#endif - { - u32 arr[] = {STAT_PORT_CONFIG_IN_USE, (ki->k.k.vrf & CNAT_VRF_MASK), - ki->k.k.ipv4, ki->k.k.port, (ki->k.k.vrf & CNAT_PRO_MASK) }; - spp_printf(CNAT_CONFIG_ERROR, 5, arr); - } - return (db); - } - -#ifdef DEBUG_PRINTF_ENABLED - printf("Deleting Dynamic entry ki 0x%16llx ko 0x%16llx", - ki, db->out2in_key); -#endif - - /* - * If for some reason we have dynamic entries, just delete them - * and proceed. - */ - cnat_delete_main_db_entry_v2(db); - - db = NULL; - } - - protocol = ki->k.k.vrf & CNAT_PRO_MASK; - u_ki.k.k.vrf = ki->k.k.vrf & CNAT_VRF_MASK; - u_ki.k.k.ipv4 = ki->k.k.ipv4; - u_ki.k.k.port = 0; - - pm = my_vrfmap->portmap_list; - - /* - * check if src vrf, src ip addr is already - * in the user db - * if yes, use PORT_ALLOC_DIRECTED - * if no, use PORT_ALLOC_ANY since it is first time - */ - udb = cnat_user_db_lookup_entry(&u_ki); - if (PREDICT_TRUE(udb)) { - /* - * check if main db has space to accomodate new entry - */ - h = pool_header(cnat_main_db); - - free_main = vec_len(h->free_indices) - 1; - if (PREDICT_FALSE(!free_main)) { - info->error = CNAT_MAIN_DB_LIMIT; - CNAT_SET_ICMP_MSG_INFO - in2out_drops_system_limit_reached ++; - CNAT_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT) -#ifdef UT_TEST_CODE - printf("Limit reached : OLD USER"); -#endif - spp_printf(CNAT_MAIN_DB_LIMIT_ERROR, 0, 0); - return NULL; - } - - /* - * allocate port, from existing mapping - */ - my_index = udb->portmap_index; - my_pm = pm + my_index; - /* It is quite possible that we hit the scenario of CSCtj17774. - * Delete all the main db entries and add the ipv4 address sent by - * CGN-MA as Static port alloc any - */ - - if (PREDICT_FALSE(my_pm->ipv4_address != ko->k.k.ipv4)) { - if (PREDICT_FALSE(global_debug_flag && CNAT_DEBUG_GLOBAL_ALL)) { - printf("Delete Main db entry and check for" - " ipv4 address sanity pm add = 0x%x ip add = 0x%x\n", - my_pm->ipv4_address, ko->k.k.ipv4); - } - do { - /* udb is not NULL when we begin with for sure */ - head = udb->translation_list_head_index; - db = cnat_main_db + head; - cnat_delete_main_db_entry_v2(db); - } while (!pool_is_free(cnat_user_db, udb)); - - rv = cnat_mapped_static_port_alloc_v2_bulk (pm, - PORT_ALLOC_ANY, &my_index, ko->k.k.ipv4, ko->k.k.port, - udb, BULKSIZE_FROM_VRFMAP(my_vrfmap), &nfv9_log_req, - my_vrfmap->ip_n_to_1); - - if (PREDICT_FALSE(rv != CNAT_SUCCESS)) { - info->error = rv; - in2out_drops_resource_depletion ++; - CNAT_SET_ICMP_MSG_INFO - CNAT_DEBUG_INSIDE_ERR(rv) - return (NULL); - } - /* - * create entry in user db - */ - udb = cnat_user_db_create_entry(&u_ki, my_index); - my_pm = pm + my_index; - if(PREDICT_TRUE(my_pm->private_ip_users_count < PORTS_PER_ADDR)) { - my_pm->private_ip_users_count++; -#ifdef DEBUG_PRINTF_IP_N_TO_1_ENABLED - PLATFORM_DEBUG_PRINT("\n cnat_create_static_main_db_entry_v2 " - "static del n alloc private_ip_users_count = " - "%d",my_pm->private_ip_users_count); -#endif - } else { - PLATFORM_DEBUG_PRINT("\n ERROR: private_ip_users_count has " - "reached MAX PORTS_PER_ADDR"); - } - NAT44_COMMON_STATS.num_subscribers++; -#ifndef NO_BULK_LOGGING - cnat_update_bulk_range_cache(udb, ko->k.k.port, - BULKSIZE_FROM_VRFMAP(my_vrfmap)); -#endif /* #ifndef NO_BULK_LOGGING */ - } else { - - rv = cnat_mapped_static_port_alloc_v2_bulk (pm, - PORT_ALLOC_DIRECTED, &my_index, ko->k.k.ipv4, ko->k.k.port, - udb, BULKSIZE_FROM_VRFMAP(my_vrfmap), &nfv9_log_req, - my_vrfmap->ip_n_to_1); - - if (PREDICT_FALSE(rv != CNAT_SUCCESS)) { - info->error = rv; - CNAT_SET_ICMP_MSG_INFO - CNAT_DEBUG_INSIDE_ERR(rv) - log_port_alloc_error(rv, &(ki->k)); - return (NULL); - } - - /* - * increment port in use for this user - */ - udb->ntranslations += 1; - } - } else { - if (PREDICT_FALSE(global_debug_flag && CNAT_DEBUG_GLOBAL_ALL)) { - printf ("Static port alloc any\n"); - } - /* - * first time allocate port for this user - */ - - /* - * Check if main db has space for new entry - * Allowing a user db entry to be created if main db is not free - * will cause a port to be allocated to that user, which results in - * wastage of that port, hence the check is done here. - */ - h = pool_header(cnat_main_db); - free_main = vec_len(h->free_indices) - 1; - h = pool_header(cnat_user_db); - free_user = vec_len(h->free_indices) - 1; - - /* - * If either main_db or user_db does not have entries - * bail out, with appropriate error - */ - if (PREDICT_FALSE(!(free_main && free_user))) { - u32 log_error; - if(free_main) { - info->error = CNAT_USER_DB_LIMIT; - log_error = CNAT_USER_DB_LIMIT_ERROR; - } else { - info->error = CNAT_MAIN_DB_LIMIT; - log_error = CNAT_MAIN_DB_LIMIT_ERROR; - } - in2out_drops_system_limit_reached ++; - CNAT_SET_ICMP_MSG_INFO - CNAT_DEBUG_INSIDE_ERR(info->error) - spp_printf(log_error, 0, 0); - return NULL; - } - - rv = cnat_mapped_static_port_alloc_v2_bulk (pm, - PORT_ALLOC_ANY, &my_index, ko->k.k.ipv4, ko->k.k.port, - udb, BULKSIZE_FROM_VRFMAP(my_vrfmap), &nfv9_log_req, - my_vrfmap->ip_n_to_1); - - if (PREDICT_FALSE(rv != CNAT_SUCCESS)) { - info->error = rv; - in2out_drops_resource_depletion ++; - CNAT_SET_ICMP_MSG_INFO - CNAT_DEBUG_INSIDE_ERR(rv) - log_port_alloc_error(rv, &(ki->k)); - return (NULL); - } - /* - * create entry in user db - */ - udb = cnat_user_db_create_entry(&u_ki, my_index); - my_pm = pm + my_index; - if(PREDICT_TRUE(my_pm->private_ip_users_count < PORTS_PER_ADDR)) { - my_pm->private_ip_users_count++; -#ifdef DEBUG_PRINTF_IP_N_TO_1_ENABLED - PLATFORM_DEBUG_PRINT("\n cnat_create_static_main_db_entry_v2 " - "static alloc private_ip_users_count = %d", - my_pm->private_ip_users_count); -#endif - } else { - PLATFORM_DEBUG_PRINT("\n ERROR: private_ip_users_count has " - "reached MAX PORTS_PER_ADDR"); - } - NAT44_COMMON_STATS.num_subscribers++; -#ifndef NO_BULK_LOGGING - cnat_update_bulk_range_cache(udb, ko->k.k.port, - BULKSIZE_FROM_VRFMAP(my_vrfmap)); -#endif /* #ifndef NO_BULK_LOGGING */ - } - - /* - * step 3: - * outside port is allocated for this src vrf/src ip addr - * 1)create a new entry in main db - * 2)setup cnat_out2in_hash key - * 3)setup cnat_in2out_hash key - */ - db = cnat_create_main_db_entry_and_hash(ki, ko, udb); - - translation_create_count ++; - db->vrfmap_index = my_vrfmap - cnat_map_by_vrf; - - /* - * don't forget logging - * logging API is unconditional, - * logging configuration check is done inside the inline function - */ - - if(PREDICT_FALSE(nfv9_log_req != CACHE_ALLOC_NO_LOG_REQUIRED)) { - /* if session logging is enabled .. do not log as there is no - * traffic yet - */ - if(PREDICT_FALSE(my_vrfmap->nf_logging_policy != SESSION_LOG_ENABLE)) { - cnat_nfv9_log_mapping_create(db, my_vrfmap -#ifndef NO_BULK_LOGGING - , nfv9_log_req -#endif - ); - } - if(PREDICT_FALSE(my_vrfmap->syslog_logging_policy != SESSION_LOG_ENABLE)) { - cnat_syslog_nat44_mapping_create(db, my_vrfmap, 0 -#ifndef NO_BULK_LOGGING - , nfv9_log_req -#endif - ); - } - } - - return db; -} - - -cnat_main_db_entry_t* -dslite_main_db_lookup_entry(dslite_db_key_bucket_t *ki); - -cnat_user_db_entry_t* -dslite_user_db_lookup_entry(dslite_db_key_bucket_t *uki); - -cnat_user_db_entry_t* -dslite_user_db_create_entry(dslite_db_key_bucket_t *uki, u32 portmap_index); - -cnat_main_db_entry_t* -dslite_create_main_db_entry_and_hash(dslite_db_key_bucket_t *ki, - cnat_db_key_bucket_t *ko, - cnat_user_db_entry_t *udb); - -#ifdef TOBE_PORTED -/* - * this function is called from config handler only - * to allocate a static port based db entry - * - * the actual mapped address and port are already specified - */ -cnat_main_db_entry_t* -dslite_create_static_main_db_entry_v2 (dslite_db_key_bucket_t *ki, - cnat_db_key_bucket_t *ko, - dslite_table_entry_t *dslite_entry_ptr, - cnat_gen_icmp_info *info) -{ - u16 protocol; - u32 head; - cnat_errno_t rv; - dslite_db_key_bucket_t u_ki; - u32 my_index, free_main, free_user; - cnat_portmap_v2_t *pm =0; - cnat_portmap_v2_t *my_pm =0; - cnat_user_db_entry_t *udb = 0; - cnat_main_db_entry_t *db = 0; - pool_header_t *h; - u16 dslite_id = dslite_entry_ptr->dslite_id; -#ifndef NO_BULK_LOGGING - int nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED; -#endif - cnat_vrfmap_t *my_vrfmap =0; - u16 my_vrfmap_index; - - /* UNUSED. Therefore not ported to be multi-thread friendly */ - ASSERT(0); - /* - * need to try lookup again because - * second pkt may come here before the entry is created - * by receiving first pkt due to high line rate. - */ - info->gen_icmp_msg = CNAT_NO_ICMP_MSG; - info->error = CNAT_SUCCESS; - db = dslite_main_db_lookup_entry(ki); - - /* - * If we already have an entry with this inside address, port - * check delete the entry and proceed further. This should - * If yes, something is terribly wrong. Bail out - */ - if (PREDICT_FALSE(db)) { - - if (db->flags & CNAT_DB_FLAG_STATIC_PORT) { - - if ((db->out2in_key.k.ipv4 == ko->k.k.ipv4) && - (db->out2in_key.k.port == ko->k.k.port) && - (db->out2in_key.k.vrf == ko->k.k.vrf)) { - -#ifdef DEBUG_PRINTF_ENABLED - printf("Same Static Port Exists ki 0x%16llx ko 0x%16llx", - ki->k, ko->k); -#endif - /* - * We have already programmed this, return - */ - return (db); - } - - /* - * We already have a static port with different mapping - * Return an error for this case. - */ - info->error = CNAT_ERR_PARSER; - -#ifdef DEBUG_PRINTF_ENABLED - printf("Static Port Existing and Diff ki 0x%16llx ko 0x%16llx", - ki, db->out2in_key); -#endif - { - u32 arr[] = {STAT_PORT_CONFIG_IN_USE, (ki->dk.ipv4_key.k.vrf & CNAT_VRF_MASK), - ki->dk.ipv4_key.k.ipv4, ki->dk.ipv4_key.k.port, (ki->dk.ipv4_key.k.vrf & CNAT_PRO_MASK) }; - spp_printf(CNAT_CONFIG_ERROR, 5, arr); - } - return (db); - } - -#ifdef DEBUG_PRINTF_ENABLED - printf("Deleting Dynamic entry ki 0x%16llx ko 0x%16llx", - ki, db->out2in_key); -#endif - - /* - * If for some reason we have dynamic entries, just delete them - * and proceed. - */ - cnat_delete_main_db_entry_v2(db); - - db = NULL; - } - - - protocol = ki->dk.ipv4_key.k.vrf & CNAT_PRO_MASK; - u_ki.dk.ipv4_key.k.vrf = ki->dk.ipv4_key.k.vrf & CNAT_VRF_MASK; - u_ki.dk.ipv4_key.k.ipv4 = ki->dk.ipv4_key.k.ipv4; - u_ki.dk.ipv4_key.k.port = 0; - u_ki.dk.ipv6[0] = ki->dk.ipv6[0]; - u_ki.dk.ipv6[1] = ki->dk.ipv6[1]; - u_ki.dk.ipv6[2] = ki->dk.ipv6[2]; - u_ki.dk.ipv6[3] = ki->dk.ipv6[3]; - - my_vrfmap_index = vrf_map_array[u_ki.dk.ipv4_key.k.vrf]; - my_vrfmap = cnat_map_by_vrf + my_vrfmap_index; - - pm = dslite_entry_ptr->portmap_list; - - /* - * check if src vrf, src ip addr is already - * in the user db - * if yes, use PORT_ALLOC_DIRECTED - * if no, use PORT_ALLOC_ANY since it is first time - */ - udb = dslite_user_db_lookup_entry(&u_ki); - if (PREDICT_TRUE(udb)) { - /* - * check if main db has space to accomodate new entry - */ - h = pool_header(cnat_main_db); - - free_main = vec_len(h->free_indices) - 1; - if (PREDICT_FALSE(!free_main)) { - info->error = CNAT_MAIN_DB_LIMIT; - nat44_dslite_common_stats[dslite_id].in2out_drops_port_limit_exceeded ++; - DSLITE_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT) -#ifdef UT_TEST_CODE - printf("Limit reached : OLD USER"); -#endif - spp_printf(CNAT_MAIN_DB_LIMIT_ERROR, 0, 0); - return NULL; - } - - /* - * allocate port, from existing mapping - */ - my_index = udb->portmap_index; - my_pm = pm + my_index; - /* It is quite possible that we hit the scenario of CSCtj17774. - * Delete all the main db entries and add the ipv4 address sent by - * CGN-MA as Static port alloc any - */ - - if (PREDICT_FALSE(my_pm->ipv4_address != ko->k.k.ipv4)) { - if (PREDICT_FALSE(global_debug_flag && CNAT_DEBUG_GLOBAL_ALL)) { - printf("Delete Main db entry and check for" - " ipv4 address sanity pm add = 0x%x ip add = 0x%x\n", - my_pm->ipv4_address, ko->k.k.ipv4); - } - do { - /* udb is not NULL when we begin with for sure */ - head = udb->translation_list_head_index; - db = cnat_main_db + head; - cnat_delete_main_db_entry_v2(db); - } while (!pool_is_free(cnat_user_db, udb)); - - rv = cnat_mapped_static_port_alloc_v2_bulk (pm, - PORT_ALLOC_ANY, &my_index, ko->k.k.ipv4, ko->k.k.port, - udb, BULKSIZE_FROM_VRFMAP(dslite_entry_ptr), &nfv9_log_req, - my_vrfmap->ip_n_to_1); - - if (PREDICT_FALSE(rv != CNAT_SUCCESS)) { - info->error = rv; - nat44_dslite_common_stats[dslite_id].in2out_drops_port_limit_exceeded ++; - DSLITE_DEBUG_INSIDE_ERR(rv) - return (NULL); - } - /* - * create entry in user db - */ - udb = dslite_user_db_create_entry(&u_ki, my_index); - nat44_dslite_common_stats[dslite_id].num_subscribers++; -#ifndef NO_BULK_LOGGING - if(PREDICT_FALSE(udb && (BULK_ALLOC_NOT_ATTEMPTED != nfv9_log_req))) { - cnat_update_bulk_range_cache(udb, ko->k.k.port, - BULKSIZE_FROM_VRFMAP(dslite_entry_ptr)); - } -#endif /* #ifndef NO_BULK_LOGGING */ - } else { - - rv = cnat_mapped_static_port_alloc_v2_bulk (pm, - PORT_ALLOC_DIRECTED, &my_index, ko->k.k.ipv4, ko->k.k.port, - udb, BULKSIZE_FROM_VRFMAP(dslite_entry_ptr), &nfv9_log_req, - my_vrfmap->ip_n_to_1); - - if (PREDICT_FALSE(rv != CNAT_SUCCESS)) { - info->error = rv; - DSLITE_DEBUG_INSIDE_ERR(rv) - log_port_alloc_error(rv, &(ki->dk.ipv4_key)); - return (NULL); - } - - /* - * increment port in use for this user - */ - udb->ntranslations += 1; - } - } else { - if (PREDICT_FALSE(global_debug_flag && CNAT_DEBUG_GLOBAL_ALL)) { - printf ("Static port alloc any\n"); - } - /* - * first time allocate port for this user - */ - - /* - * Check if main db has space for new entry - * Allowing a user db entry to be created if main db is not free - * will cause a port to be allocated to that user, which results in - * wastage of that port, hence the check is done here. - */ - h = pool_header(cnat_main_db); - free_main = vec_len(h->free_indices) - 1; - h = pool_header(cnat_user_db); - free_user = vec_len(h->free_indices) - 1; - - /* - * If either main_db or user_db does not have entries - * bail out, with appropriate error - */ - if (PREDICT_FALSE(!(free_main && free_user))) { - u32 log_error; - if(free_main) { - info->error = CNAT_USER_DB_LIMIT; - log_error = CNAT_USER_DB_LIMIT_ERROR; - } else { - info->error = CNAT_MAIN_DB_LIMIT; - log_error = CNAT_MAIN_DB_LIMIT_ERROR; - } - nat44_dslite_common_stats[dslite_id].in2out_drops_port_limit_exceeded ++; - DSLITE_DEBUG_INSIDE_ERR(info->error) - spp_printf(log_error, 0, 0); - return NULL; - } - - rv = cnat_mapped_static_port_alloc_v2_bulk (pm, - PORT_ALLOC_ANY, &my_index, ko->k.k.ipv4, ko->k.k.port, - udb, BULKSIZE_FROM_VRFMAP(dslite_entry_ptr), &nfv9_log_req, - my_vrfmap->ip_n_to_1); - - if (PREDICT_FALSE(rv != CNAT_SUCCESS)) { - info->error = rv; - nat44_dslite_common_stats[dslite_id].in2out_drops_port_limit_exceeded ++; - DSLITE_DEBUG_INSIDE_ERR(rv) - log_port_alloc_error(rv, &(ki->dk.ipv4_key)); - return (NULL); - } - /* - * create entry in user db - */ - udb = dslite_user_db_create_entry(&u_ki, my_index); - nat44_dslite_common_stats[dslite_id].num_subscribers++; -#ifndef NO_BULK_LOGGING - if(PREDICT_FALSE(udb && (BULK_ALLOC_NOT_ATTEMPTED != nfv9_log_req))) { - cnat_update_bulk_range_cache(udb, ko->k.k.port, - BULKSIZE_FROM_VRFMAP(dslite_entry_ptr)); - } -#endif /* #ifndef NO_BULK_LOGGING */ - } - - /* - * step 3: - * outside port is allocated for this src vrf/src ip addr - * 1)create a new entry in main db - * 2)setup cnat_out2in_hash key - * 3)setup cnat_in2out_hash key - */ - db = dslite_create_main_db_entry_and_hash(ki, ko, udb); - db->dslite_nat44_inst_id = dslite_id; - nat44_dslite_common_stats[dslite_id].active_translations++; - dslite_translation_create_count++; - - /* - * don't forget logging - * logging API is unconditional, - * logging configuration check is done inside the inline function - */ -#if 0 /* TBD - NEED TO DECIDE ON LOGGING */ - if(PREDICT_FALSE(nfv9_log_req != CACHE_ALLOC_NO_LOG_REQUIRED)) { - /* if session logging is enabled .. do not log as there is no - * traffic yet - */ -#endif /* #if 0 - this has to be removed later */ - - return db; -} -#endif /* TOBE_PORTED */ - - -/* Per port/ip timeout related routines */ -static -u32 cnat_timeout_db_hash_lookup (cnat_key_t t_key) -{ - cnat_key_t key; - u64 a, b, c; - u32 index; - cnat_timeout_db_entry_t *db; - - key.k.ipv4 = t_key.k.ipv4; - key.k.port = t_key.k.port; - key.k.vrf = t_key.k.vrf; - - CNAT_V4_GET_HASH(key.key64, - index, CNAT_TIMEOUT_HASH_MASK) - - - index = cnat_timeout_hash[index].next; - - if (PREDICT_FALSE(index == EMPTY)) - return EMPTY; - - do { - db = cnat_timeout_db + index; - if (PREDICT_TRUE((db->t_key.timeout_key.key64 & CNAT_TIMEOUT_FULL_MASK) - == (key.key64 & CNAT_TIMEOUT_FULL_MASK))) - break; - index = db->t_hash.next; - } while (index != EMPTY); - - return index; -} - -/* Pass db_type as MAIN_DB_TYPE if you are passing - * cnat_main_db_entry_t * casted as void * for db - * else pass db_type as SESSION_DB_TYPE - */ -u16 -query_and_update_db_timeout(void *db, u8 db_type) -{ - cnat_key_t t_search_key; - u32 index; - cnat_timeout_db_entry_t *timeout_db_entry; - pool_header_t *h; - u32 free; - - cnat_main_db_entry_t *mdb = NULL; - cnat_session_entry_t *sdb = NULL; - - if(PREDICT_TRUE(db_type == MAIN_DB_TYPE)) { - mdb = (cnat_main_db_entry_t *)db; - } else if(db_type == SESSION_DB_TYPE) { - sdb = (cnat_session_entry_t *)db; - } else { - return 0; - } - - h = pool_header(cnat_timeout_db); - free = vec_len(h->free_indices) - 1; - - if(free == CNAT_TIMEOUT_HASH_SIZE) { - /* No timeout db configured */ - return 0; - } - - /* First search for ip/port pair */ - if(PREDICT_TRUE(db_type == MAIN_DB_TYPE)) { - t_search_key.k.ipv4 = mdb->dst_ipv4; - t_search_key.k.port = mdb->dst_port; - t_search_key.k.vrf = mdb->in2out_key.k.vrf; - } else { - t_search_key.k.ipv4 = sdb->v4_dest_key.k.ipv4; - t_search_key.k.port = sdb->v4_dest_key.k.port; - t_search_key.k.vrf = sdb->v4_dest_key.k.vrf; - } - - index = cnat_timeout_db_hash_lookup(t_search_key); - - if(index == EMPTY) { - /* Search for port map */ - t_search_key.k.ipv4 = 0; - - index = cnat_timeout_db_hash_lookup(t_search_key); - - if(index == EMPTY) { - /* Search for ip only map */ - if(PREDICT_TRUE(db_type == MAIN_DB_TYPE)) { - t_search_key.k.ipv4 = mdb->dst_ipv4; - } else { - t_search_key.k.ipv4 = sdb->v4_dest_key.k.ipv4; - } - t_search_key.k.port = 0; - - index = cnat_timeout_db_hash_lookup(t_search_key); - if(index != EMPTY) { -#ifdef DEBUG_PRINTF_ENABLED - printf("%s: ip only map sucess\n","query_and_update_db_timeout"); -#endif - } - } else { -#ifdef DEBUG_PRINTF_ENABLED - printf("%s: port only map sucess\n", "query_and_update_db_timeout"); -#endif - } - - } else { -#ifdef DEBUG_PRINTF_ENABLED - printf("%s: ip port map sucess\n","query_and_update_db_timeout"); -#endif - - } - - if(index == EMPTY) { - /* No match found, clear timeout */ - if(PREDICT_TRUE(db_type == MAIN_DB_TYPE)) { - mdb->timeout = 0; - } else { - sdb->timeout = 0; - } -#ifdef DEBUG_PRINTF_ENABLED - printf("%s: No match\n","query_and_update_db_timeout"); -#endif - } else { - /* Match found, update timeout */ - timeout_db_entry = cnat_timeout_db + index; - if(PREDICT_TRUE(db_type == MAIN_DB_TYPE)) { - mdb->timeout = timeout_db_entry->t_key.timeout_value; - } else { - sdb->timeout = timeout_db_entry->t_key.timeout_value; - } - return timeout_db_entry->t_key.timeout_value; - } - return 0; -} - - - -static -void cnat_timeout_db_hash_add (cnat_timeout_db_entry_t *t_entry) -{ - cnat_key_t key; - u64 a, b, c; - u32 index, bucket; - cnat_key_t t_key = t_entry->t_key.timeout_key; - - key.k.ipv4 = t_key.k.ipv4; - key.k.port = t_key.k.port; - key.k.vrf = t_key.k.vrf; - - CNAT_V4_GET_HASH(key.key64, - bucket, CNAT_TIMEOUT_HASH_MASK) - - - index = cnat_timeout_hash[bucket].next; - - /* Add this db entry to the head of the bucket chain */ - t_entry->t_hash.next = index; - cnat_timeout_hash[bucket].next = t_entry - cnat_timeout_db; -} - - - -u16 -cnat_timeout_db_create (cnat_timeout_t t_entry) -{ - cnat_timeout_db_entry_t *db; - cnat_key_t t_key = t_entry.timeout_key; - u32 db_index; - - pool_header_t *h; - u32 free; - - /* UNUSED. Therefore not ported to be multi-thread friendly */ - ASSERT(0); - - db_index = cnat_timeout_db_hash_lookup(t_key); - - if(db_index != EMPTY) { - /* Entry already exists. Check if it is replay or update */ - db = cnat_timeout_db + db_index; - db->t_key.timeout_value = t_entry.timeout_value; - return CNAT_SUCCESS; - } - - h = pool_header(cnat_timeout_db); - free = vec_len(h->free_indices) - 1; - - if(free == 0) { - return CNAT_OUT_LIMIT; - } - - - pool_get(cnat_timeout_db, db); - ASSERT(db); - - memset(db, 0, sizeof(*db)); - - db_index = db - cnat_timeout_db; - - db->t_key.timeout_key.k.ipv4 = t_key.k.ipv4; - db->t_key.timeout_key.k.port = t_key.k.port; - db->t_key.timeout_key.k.vrf = t_key.k.vrf; - db->t_key.timeout_value = t_entry.timeout_value; - - - cnat_timeout_db_hash_add(db); - return CNAT_SUCCESS; -} - -void cnat_timeout_db_delete(cnat_key_t t_key) -{ - cnat_key_t key; - u64 a, b, c; - u32 index, bucket; - cnat_timeout_db_entry_t *this, *prev; - - /* UNUSED. Therefore not ported to be multi-thread friendly */ - ASSERT(0); - - key.k.ipv4 = t_key.k.ipv4; - key.k.port = t_key.k.port; - key.k.vrf = t_key.k.vrf; - - - CNAT_V4_GET_HASH(key.key64, - bucket, CNAT_TIMEOUT_HASH_MASK) - - - index = cnat_timeout_hash[bucket].next; - - if(index == EMPTY) return; - - prev = 0; - do { - this = cnat_timeout_db + index; - if (PREDICT_TRUE( - (this->t_key.timeout_key.key64 & CNAT_TIMEOUT_FULL_MASK) == - (key.key64 & CNAT_TIMEOUT_FULL_MASK))) { - if (prev == 0) { - cnat_timeout_hash[bucket].next = this->t_hash.next; - goto found; - } else { - prev->t_hash.next = this->t_hash.next; - goto found; - } - } - - prev = this; - index = this->t_hash.next; - } while (index != EMPTY); - - if(index == EMPTY) return; - - found: - pool_put(cnat_timeout_db, this); - -} - -void cnat_session_db_hash_delete (cnat_session_entry_t *ep) -{ - u32 a, b, c; - u32 index, bucket; - cnat_session_entry_t *this, *prev; - - CNAT_V4_GET_SESSION_HASH(ep->main_db_index, ep->v4_dest_key.k.ipv4, - ep->v4_dest_key.k.port, ep->v4_dest_key.k.vrf, bucket, - CNAT_SESSION_HASH_MASK) - - - index = cnat_session_hash[bucket].next; - - ASSERT(index != EMPTY); - - prev = 0; - do { - this = cnat_session_db + index; - if (PREDICT_TRUE(this == ep)) { - if (prev == 0) { - cnat_session_hash[bucket].next = - ep->cnat_session_hash.next; - return; - } else { - prev->cnat_session_hash.next = - ep->cnat_session_hash.next; - return; - } - } - prev = this; - index = this->cnat_session_hash.next; - } while (index != EMPTY); - - ASSERT(0); - -} - -cnat_session_entry_t * -cnat_session_db_edm_lookup_entry(cnat_key_t *ko,u32 session_head_index, - u32 main_db_index) -{ - u32 index; - cnat_session_entry_t *db; - - - index = session_head_index; - if (PREDICT_TRUE(index == EMPTY)) { - return (NULL); - } - - do { - db = cnat_session_db + index; - if(PREDICT_TRUE((db->main_db_index == main_db_index) && - (db->v4_dest_key.k.vrf == ko->k.vrf) && - (db->v4_dest_key.k.ipv4 == ko->k.ipv4))) { - - return db; - } - index = db->cnat_session_hash.next; - } while (index != EMPTY); - - return (NULL); -} - - - -cnat_session_entry_t * -cnat_session_db_lookup_entry(cnat_key_t *ko,u32 main_db_index) -{ - u32 a, b, c; - u32 index, bucket; - cnat_session_entry_t *db; - - CNAT_V4_GET_SESSION_HASH(main_db_index, ko->k.ipv4, ko->k.port, - ko->k.vrf, bucket, CNAT_SESSION_HASH_MASK) - - - index = cnat_session_hash[bucket].next; - if (PREDICT_TRUE(index == EMPTY)) { - return (NULL); - } - - do { - db = cnat_session_db + index; - if(PREDICT_TRUE((db->main_db_index == main_db_index) && - (db->v4_dest_key.k.vrf == ko->k.vrf) && - (db->v4_dest_key.k.port == ko->k.port) && - (db->v4_dest_key.k.ipv4 == ko->k.ipv4))) { - - return db; - } - index = db->cnat_session_hash.next; - } while (index != EMPTY); - - return (NULL); -} - -cnat_session_entry_t * -cnat_create_session_db_entry(cnat_key_t *ko, - cnat_main_db_entry_t *bdb, u8 log) -{ - u32 a, b, c; - u32 db_index, bucket_out; - cnat_session_entry_t *db = NULL; - pool_header_t *h; - u32 free_session; - u16 instance; - - db = cnat_session_db_lookup_entry(ko, bdb - cnat_main_db); - if (PREDICT_FALSE(db != NULL)) { - /*printf("Create Session - Entry already Exists\n");*/ - return db; - } - - h = pool_header(cnat_session_db); - free_session = vec_len(h->free_indices) - 1; - - if (bdb->flags & CNAT_DB_DSLITE_FLAG) { - instance = bdb->dslite_nat44_inst_id; - } else { - instance = NAT44_RESERVED_INST_ID; - } - - if (PREDICT_FALSE(!free_session)) { - nat44_dslite_common_stats[instance].drops_sessiondb_limit_exceeded++; - return NULL; - } - - if( PREDICT_FALSE(bdb->nsessions == CNAT_MAX_SESSIONS_PER_BIB)) { - /* printf("Create Session - Max sessions per BIB reached\n"); */ - return NULL; - } - - pthread_spin_lock(cnat_db_v2_main.session_db_lockp); - pool_get(cnat_session_db, db); - memset(db, 0, sizeof(*db)); - - db_index = db - cnat_session_db; - db->v4_dest_key.k.port = ko->k.port; - db->v4_dest_key.k.ipv4 = ko->k.ipv4; - db->v4_dest_key.k.vrf = ko->k.vrf; - - db->main_list.next = db_index; - db->main_list.prev = db_index; - db->main_db_index = bdb - cnat_main_db; - - db->tcp_seq_num = 0; - db->ack_no = 0; - db->window = 0; - - if(PREDICT_FALSE(log)) { - bdb->nsessions++; - query_and_update_db_timeout(db, SESSION_DB_TYPE); - } - - if (PREDICT_FALSE(bdb->nsessions == 1)) { - /* - * first port for this src vrf/src ip addr - */ - bdb->session_head_index = db_index; - } else { - index_dlist_addtail(bdb->session_head_index, - (u8 *)cnat_session_db, sizeof(cnat_session_db[0]), - STRUCT_OFFSET_OF(cnat_session_entry_t, main_list), - db_index); - } - - /* - * setup o2i hash key - */ - CNAT_V4_GET_SESSION_HASH(db->main_db_index, ko->k.ipv4, ko->k.port, - ko->k.vrf, bucket_out, CNAT_SESSION_HASH_MASK) - - - db->cnat_session_hash.next = - cnat_session_hash[bucket_out].next; - cnat_session_hash[bucket_out].next = db_index; - - - if(PREDICT_FALSE(log)) { - if (bdb->flags & CNAT_DB_DSLITE_FLAG) { - cnat_session_log_ds_lite_mapping_create(bdb, - (dslite_table_db_ptr + instance),db); - } else { - cnat_vrfmap_t *my_vrfmap = cnat_map_by_vrf + bdb->vrfmap_index; - cnat_session_log_nat44_mapping_create(bdb, db, my_vrfmap); - } - } - - /* Need to set entry_expires here, as we need to override 0 check for - newly established sessions */ - db->entry_expires = cnat_current_time; - nat44_dslite_common_stats[instance].sessions++; - pthread_spin_unlock(cnat_db_v2_main.session_db_lockp); - return db; -} - -void -cnat_dest_update_main2session(cnat_main_db_entry_t *mdb, - cnat_session_entry_t *sdb) -{ - - sdb->flags = mdb->flags; - sdb->timeout = mdb->timeout; - sdb->entry_expires = mdb->entry_expires; - sdb->alg.delta = mdb->alg.delta; - sdb->tcp_seq_num = mdb->proto_data.seq_pcp.tcp_seq_num; - - /* Reset Main db values to 0 */ - /* Reset only session specific flags */ - mdb->flags &= ~(CNAT_DB_FLAG_TCP_ACTIVE | CNAT_DB_FLAG_UDP_ACTIVE - | CNAT_DB_FLAG_ALG_ENTRY | CNAT_DB_FLAG_ALG_CTRL_FLOW); - mdb->timeout = 0; - mdb->entry_expires = 0; - mdb->alg.delta = 0; - if(PREDICT_FALSE(!((mdb->flags & CNAT_DB_FLAG_PPTP_TUNNEL_ACTIVE) || - (mdb->flags & CNAT_DB_FLAG_PPTP_TUNNEL_INIT)))) { - mdb->proto_data.seq_pcp.tcp_seq_num = 0; - } - - mdb->dst_ipv4 = 0; - mdb->dst_port = 0; -} - - -void -cnat_dest_update_session2main(cnat_main_db_entry_t *mdb, - cnat_session_entry_t *sdb) -{ - - u16 flags = sdb->flags & (CNAT_DB_FLAG_TCP_ACTIVE | - CNAT_DB_FLAG_UDP_ACTIVE | CNAT_DB_FLAG_ALG_ENTRY | - CNAT_DB_FLAG_ALG_CTRL_FLOW); - mdb->flags |= flags; - mdb->timeout = sdb->timeout; - mdb->entry_expires = sdb->entry_expires; - mdb->alg.delta = sdb->alg.delta; - if(PREDICT_FALSE(!((mdb->flags & CNAT_DB_FLAG_PPTP_TUNNEL_ACTIVE) || - (mdb->flags & CNAT_DB_FLAG_PPTP_TUNNEL_INIT)))) { - mdb->proto_data.seq_pcp.tcp_seq_num = sdb->tcp_seq_num; - } - mdb->dst_ipv4 = sdb->v4_dest_key.k.ipv4; - mdb->dst_port = sdb->v4_dest_key.k.port; -} - -static void -_cnat_delete_session_db_entry (cnat_session_entry_t *ep, u8 log) -{ - u32 session_db_index; - u32 bdb_len; - cnat_main_db_entry_t *be =0; - cnat_session_entry_t *sdb_last = NULL; - u16 instance; - - if (PREDICT_FALSE(ep->flags & CNAT_DB_NAT64_FLAG) != 0) { - /* Preventive check - Not a NAT44 entry */ - return; - } - - pool_header_t *h = pool_header(cnat_main_db); - - /* Validate .. just in case we are trying to delete a non existing one */ - bdb_len = vec_len(cnat_main_db); - - /* In case of invalid user just return, deleting only main db - * is not a good idea, since some valid user db entry might be pointing - * to that main db and hence leave the dbs in a inconsistent state - */ - if (PREDICT_FALSE((ep->main_db_index >= bdb_len) || - (clib_bitmap_get(h->free_bitmap, ep->main_db_index)))) { -#ifdef DEBUG_PRINTF_ENABLED - printf("invalid/unused user index in db %d\n", ep->main_db_index); -#endif - spp_printf(CNAT_INV_UNUSED_USR_INDEX, 1, (u32 *) &(ep->main_db_index)); - return; - } - - be = cnat_main_db + ep->main_db_index; - - session_db_index = ep - cnat_session_db; - - be->session_head_index = index_dlist_remelem ( - be->session_head_index, (u8 *)cnat_session_db, - sizeof (cnat_session_db[0]), - STRUCT_OFFSET_OF(cnat_session_entry_t, main_list), - session_db_index); - - if (be->flags & CNAT_DB_DSLITE_FLAG) { - instance = be->dslite_nat44_inst_id; - } else { - instance = NAT44_RESERVED_INST_ID; - } - - if(PREDICT_TRUE(log)) { - if (be->flags & CNAT_DB_DSLITE_FLAG) { - cnat_session_log_ds_lite_mapping_delete(be, - (dslite_table_db_ptr + instance),ep); - } else { - cnat_vrfmap_t *my_vrfmap = cnat_map_by_vrf + be->vrfmap_index; - cnat_session_log_nat44_mapping_delete(be, ep, my_vrfmap); - } - be->nsessions--; - } - - if (PREDICT_FALSE(be->nsessions == 1 && log)) { - /* There is only 1 session left - * Copy the info back to main db and release the last - * existing session - */ - - sdb_last = cnat_session_db + be->session_head_index; - ASSERT(sdb_last != NULL); - - cnat_dest_update_session2main(be, sdb_last); - _cnat_delete_session_db_entry(sdb_last, FALSE); - } - - /* Remove from session DB hashes */ - cnat_session_db_hash_delete(ep); - nat44_dslite_common_stats[instance].sessions--; - - pool_put(cnat_session_db, ep); -} - -void cnat_delete_session_db_entry (cnat_session_entry_t *ep, u8 log) -{ - pthread_spin_lock(cnat_db_v2_main.session_db_lockp); - _cnat_delete_session_db_entry (ep, log); - pthread_spin_unlock(cnat_db_v2_main.session_db_lockp); -} - -cnat_main_db_entry_t* -dslite_main_db_lookup_entry(dslite_db_key_bucket_t *ki) -{ - u64 a, b, c; - u32 index; - cnat_main_db_entry_t *db; - cnat_user_db_entry_t *userdb; - - DSLITE_V6_GET_HASH((&(ki->dk)), - ki->bucket, - CNAT_MAIN_HASH_MASK); - - DSLITE_PRINTF(1,"MDBLU hash..%u\n", ki->bucket); - - index = cnat_in2out_hash[ki->bucket].next; - if (PREDICT_TRUE(index == EMPTY)) { - DSLITE_PRINTF(1,"MDBLU index MT..\n"); - return (NULL); - } - - do { -/* We can add a flag here to indicate if the db entry is for nat44 or - * dslite. If the db entry is for nat44 then we can simply move to the - * one. - */ - db = cnat_main_db + index; - userdb = cnat_user_db + db->user_index; - if (PREDICT_TRUE(db->in2out_key.key64 == ki->dk.ipv4_key.key64) - && userdb->ipv6[0] == ki->dk.ipv6[0] - && userdb->ipv6[1] == ki->dk.ipv6[1] - && userdb->ipv6[2] == ki->dk.ipv6[2] - && userdb->ipv6[3] == ki->dk.ipv6[3]) { - DSLITE_PRINTF(1,"MDBLU success..%u\n", index); - return db; - } - index = db->in2out_hash.next; - } while (index != EMPTY); - - DSLITE_PRINTF(1,"MDBLU Entry does not exist..\n"); - return (NULL); -} - -cnat_user_db_entry_t* -dslite_user_db_lookup_entry(dslite_db_key_bucket_t *uki) -{ - u64 a, b, c; - u32 index; - cnat_user_db_entry_t *udb=NULL; - - DSLITE_V6_GET_HASH((&(uki->dk)), - uki->bucket, - CNAT_USER_HASH_MASK) - - DSLITE_PRINTF(1,"UDBLU hash..%u\n", uki->bucket); - - /* now: index in user vector */ - index = cnat_user_hash[uki->bucket].next; - if (PREDICT_TRUE(index != EMPTY)) { - DSLITE_PRINTF(1,"UDBLU hash table entry not MT..\n"); - do { - udb = cnat_user_db + index; - if (PREDICT_FALSE(udb->key.key64 == uki->dk.ipv4_key.key64) - && udb->ipv6[0] == uki->dk.ipv6[0] - && udb->ipv6[1] == uki->dk.ipv6[1] - && udb->ipv6[2] == uki->dk.ipv6[2] - && udb->ipv6[3] == uki->dk.ipv6[3]) { - DSLITE_PRINTF(1,"UDBLU success..%u\n", index); - return udb; - } - index = udb->user_hash.next; - } while (index != EMPTY); - } - DSLITE_PRINTF(1,"UDBLU Entry doesnt exist..\n"); - return (NULL); -} - -cnat_user_db_entry_t* -dslite_user_db_create_entry(dslite_db_key_bucket_t *uki, - u32 portmap_index) -{ - cnat_user_db_entry_t *udb = NULL; - - /* UNUSED. Therefore not ported to be multi-thread friendly */ - ASSERT(0); - - pool_get(cnat_user_db, udb); - memset(udb, 0, sizeof(*udb)); - - udb->ntranslations = 1; - udb->portmap_index = portmap_index; -// udb->key.key64 = uki->k.key64; - - udb->key.key64 = uki->dk.ipv4_key.key64; - udb->ipv6[0] = uki->dk.ipv6[0]; - udb->ipv6[1] = uki->dk.ipv6[1]; - udb->ipv6[2] = uki->dk.ipv6[2]; - udb->ipv6[3] = uki->dk.ipv6[3]; - - udb->flags |= CNAT_USER_DB_DSLITE_FLAG; - /* Add this user to the head of the bucket chain */ - udb->user_hash.next = - cnat_user_hash[uki->bucket].next; - cnat_user_hash[uki->bucket].next = udb - cnat_user_db; - -#ifndef NO_BULK_LOGGING - INIT_BULK_CACHE(udb) -#endif /* NO_BULK_LOGGING */ - - return udb; -} - -#ifndef TOBE_PORTED -cnat_main_db_entry_t* -dslite_create_main_db_entry_and_hash(dslite_db_key_bucket_t *ki, - cnat_db_key_bucket_t *ko, - cnat_user_db_entry_t *udb) -{ - return 0; -} -#else -cnat_main_db_entry_t* -dslite_create_main_db_entry_and_hash(dslite_db_key_bucket_t *ki, - cnat_db_key_bucket_t *ko, - cnat_user_db_entry_t *udb) -{ - u64 a, b, c; - u32 db_index; - cnat_main_db_entry_t *db = NULL; - - /* UNUSED. Therefore not ported to be multi-thread friendly */ - ASSERT(0); - - pool_get(cnat_main_db, db); - memset(db, 0, sizeof(*db)); - - db_index = db - cnat_main_db; - db->in2out_key.k.ipv4 = ki->dk.ipv4_key.k.ipv4; - db->in2out_key.k.port = ki->dk.ipv4_key.k.port; - db->in2out_key.k.vrf = ki->dk.ipv4_key.k.vrf; - db->out2in_key.k.ipv4 = ko->k.k.ipv4; - db->out2in_key.k.port = ko->k.k.port; - db->out2in_key.k.vrf = ko->k.k.vrf; - - db->user_ports.next = db_index; - db->user_ports.prev = db_index; - db->user_index = udb - cnat_user_db; - //db->portmap_index = udb->portmap_index; - db->flags |= CNAT_DB_DSLITE_FLAG; - - if (PREDICT_FALSE(udb->ntranslations == 1)) { - /* - * first port for this src vrf/src ip addr - */ - udb->translation_list_head_index = db_index; - DSLITE_PRINTF(1,"First translation of this user..\n"); - } else { - index_dlist_addtail(udb->translation_list_head_index, - (u8 *)cnat_main_db, sizeof(cnat_main_db[0]), - STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports), - db_index); - } - - /* - * setup o2i hash key - */ - CNAT_V4_GET_HASH(ko->k.key64, - ko->bucket, - CNAT_MAIN_HASH_MASK) - db->out2in_hash.next = cnat_out2in_hash[ko->bucket].next; - cnat_out2in_hash[ko->bucket].next = db_index; - /* - * setup i2o hash key, bucket is already calculate - */ - db->in2out_hash.next = cnat_in2out_hash[ki->bucket].next; - cnat_in2out_hash[ki->bucket].next = db_index; - - DSLITE_PRINTF(1,"Create main db and hash..%u %u %u %u %x\n", - ki->bucket, ko->bucket, - db_index, db->user_index, ko->k.key64); - -#if DEBUG > 1 - printf("\nMy_Instance_Number %d: Bucket %d, Db_Index %d", - my_instance_number, ki->bucket, db_index); - printf("\nInside (VRF 0x%x, IP 0x%x, PORT 0x%x)", - db->in2out_key.k.vrf, db->in2out_key.k.ipv4, db->in2out_key.k.port); - printf("\nOutside (VRF 0x%x, IP 0x%x, PORT 0x%x)", - db->out2in_key.k.vrf, db->out2in_key.k.ipv4, db->out2in_key.k.port); - printf("\nUser Index %d, IP 0x%x", - db->user_index, udb->key.k.ipv4); -#endif - - //nat44_dslite_common_stats[DSLITE_COMMON_STATS].active_translations++; - - return db; -} - -static inline void handle_dslite_port_exceeded_logging( - cnat_user_db_entry_t *udb, - dslite_key_t * key, - dslite_table_entry_t *dslite_entry_ptr) -{ - - if(PREDICT_TRUE(udb->flags & CNAT_USER_DB_PORT_LIMIT_EXCEEDED)) { - /* Already logged ..*/ - return; - } - - /* else, set the flag and call the log API */ - udb->flags = udb->flags | CNAT_USER_DB_PORT_LIMIT_EXCEEDED; - cnat_log_ds_lite_port_limit_exceeded(key, dslite_entry_ptr); - return; -} -#endif - -void handle_cnat_port_exceeded_logging( - cnat_user_db_entry_t *udb, - cnat_key_t * key, - cnat_vrfmap_t *vrfmap) -{ - - if(PREDICT_TRUE(udb->flags & CNAT_USER_DB_PORT_LIMIT_EXCEEDED)) { - /* Already logged ..*/ - return; - } - - /* else, set the flag and call the log API */ - udb->flags = udb->flags | CNAT_USER_DB_PORT_LIMIT_EXCEEDED; - cnat_log_nat44_port_limit_exceeded(key,vrfmap); - return; -} - -#ifndef TOBE_PORTED -cnat_main_db_entry_t* -dslite_get_main_db_entry_v2(dslite_db_key_bucket_t *ki, - port_pair_t port_pair_type, - port_type_t port_type, - cnat_gen_icmp_info *info, - dslite_table_entry_t *dslite_entry_ptr, - cnat_key_t *dest_info) -{ - return 0; -} -#else -/* - * this function is called by exception node - * when lookup is fialed in i2o node - * - * if reash per user port limit, - * set user_db_entry pointer, and error == CNAT_OUT_LIMIT - */ -cnat_main_db_entry_t* -dslite_get_main_db_entry_v2(dslite_db_key_bucket_t *ki, - port_pair_t port_pair_type, - port_type_t port_type, - cnat_gen_icmp_info *info, - dslite_table_entry_t *dslite_entry_ptr, - cnat_key_t *dest_info) -{ - u16 protocol; - cnat_errno_t rv; - dslite_db_key_bucket_t u_ki; - cnat_db_key_bucket_t ko; - u32 my_index, free_main, free_user; - u32 current_timestamp; - cnat_vrfmap_t *my_vrfmap =0; - u16 my_vrfmap_index; - cnat_portmap_v2_t *pm =0; - cnat_user_db_entry_t *udb = 0; - cnat_main_db_entry_t *db = 0; - pool_header_t *h; - u16 dslite_id = dslite_entry_ptr->dslite_id; - -#ifndef NO_BULK_LOGGING - int nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED; -#endif - - /* UNUSED. Therefore not ported to be multi-thread friendly */ - ASSERT(0); - - /* - * need to try lookup again because - * second pkt may come here before the entry is created - * by receiving first pkt due to high line rate. - */ - info->gen_icmp_msg = CNAT_NO_ICMP_MSG; - info->error = CNAT_SUCCESS; - db = dslite_main_db_lookup_entry(ki); - if (PREDICT_TRUE(db)) { - /* what if the source is talking to a - * new dest now? We will have to handle this case and - * take care of - creating session db and logging - */ - if(PREDICT_FALSE((!dest_info->k.ipv4) && (!dest_info->k.port))) { - return db; /* if dest_info is null don't create session */ - } - - if(PREDICT_TRUE((db->dst_ipv4 == dest_info->k.ipv4) && - (db->dst_port == dest_info->k.port))) { - return db; - } - dest_info->k.vrf = db->in2out_key.k.vrf; - /* Src is indeed talking to a different dest */ - cnat_session_entry_t *session_db2 = NULL; - if(PREDICT_TRUE(db->nsessions == 1)) { - session_db2 = cnat_handle_1to2_session(db, dest_info); - if(PREDICT_TRUE(session_db2 != NULL)) { - CNAT_DB_TIMEOUT_RST(session_db2); - return db; - } else { - info->error = CNAT_ERR_NO_SESSION_DB; - return NULL; - } - } else if(PREDICT_FALSE(db->nsessions == 0)) { - /* Should be static entry.. should never happen - */ - if(PREDICT_TRUE(dest_info->k.ipv4 != 0)) { - cnat_add_dest_n_log(db, dest_info); - } - return db; - } else { - /* The src has already created multiple sessions.. very rare - */ - session_db2 = cnat_create_session_db_entry(dest_info, - db, TRUE); - if(PREDICT_TRUE(session_db2 != NULL)) { - CNAT_DB_TIMEOUT_RST(session_db2); - return db; - } else { - info->error = CNAT_ERR_NO_SESSION_DB; - return NULL; - } - } - - } - - /* - * step 1. check if outside vrf is configured or not - * and Find the set of portmaps for the outside vrf - * insider vrf is one to one mappted to outside vrf - * key is vrf and ip only - * ki.k.k.vrf has protocol bits, mask out - */ - protocol = ki->dk.ipv4_key.k.vrf & CNAT_PRO_MASK; - u_ki.dk.ipv4_key.k.vrf = ki->dk.ipv4_key.k.vrf & CNAT_VRF_MASK; -#ifdef DSLITE_USER_IPV4 - u_ki.dk.ipv4_key.k.ipv4 = ki->dk.ipv4_key.k.ipv4; -#else - /* - * Inside ipv4 address should be masked, if port limit - * need to be done at B4 element level. - */ - u_ki.dk.ipv4_key.k.ipv4 = 0; -#endif - u_ki.dk.ipv4_key.k.port = 0; - - u_ki.dk.ipv6[0] = ki->dk.ipv6[0]; - u_ki.dk.ipv6[1] = ki->dk.ipv6[1]; - u_ki.dk.ipv6[2] = ki->dk.ipv6[2]; - u_ki.dk.ipv6[3] = ki->dk.ipv6[3]; - - my_vrfmap_index = vrf_map_array[u_ki.dk.ipv4_key.k.vrf]; - my_vrfmap = cnat_map_by_vrf + my_vrfmap_index; -/* Checking if the inst entry is active or not is done much earlier - */ -#if 0 - my_vrfmap_index = vrf_map_array[u_ki.k.k.vrf]; - my_vrfmap = cnat_map_by_vrf + my_vrfmap_index; - my_vrfmap_entry_found = ((my_vrfmap_index != VRF_MAP_ENTRY_EMPTY) && - (my_vrfmap->status == S_RUN) && - (my_vrfmap->i_vrf == u_ki.k.k.vrf)); - - if (PREDICT_FALSE(!my_vrfmap_entry_found)) { - u32 arr[] = {ki->k.k.vrf, ki->k.k.ipv4, ki->k.k.port}; - if ((my_vrfmap_index == VRF_MAP_ENTRY_EMPTY) || - (my_vrfmap->i_vrf == u_ki.k.k.vrf)) { - info->error = CNAT_NO_CONFIG; - CNAT_DEBUG_INSIDE_ERR(CNAT_NO_CONFIG) - spp_printf(CNAT_NO_CONFIG_ERROR, 3, arr); - } else { - info->error = CNAT_NO_VRF_RUN; - CNAT_DEBUG_INSIDE_ERR(CNAT_NO_VRF_RUN) - spp_printf(CNAT_NO_VRF_RUN_ERROR, 3, arr); - } - - return (NULL); - } -#endif -/* - dslite_inst_ptr = dslite_nat44_config_table[dslite_inst_id]; -*/ - pm = dslite_entry_ptr->portmap_list; - //pm = my_vrfmap->portmap_list; - - /* - * set o2i key with protocl bits - */ - ko.k.k.vrf = dslite_entry_ptr->o_vrf | protocol; - //ko.k.k.vrf = my_vrfmap->o_vrf | protocol; - - /* - * step 2. check if src vrf, src ip addr is alreay - * in the user db - * if yes, use PORT_ALLOC_DIRECTED - * if no, use PORT_ALLOC_ANY since it is first time - */ - udb = dslite_user_db_lookup_entry(&u_ki); - if (PREDICT_TRUE(udb)) { - /* - * not first time allocate port for this user - * check limit - */ - if (PREDICT_FALSE(udb->ntranslations >= - dslite_entry_ptr->cnat_main_db_max_ports_per_user)) { - //cnat_main_db_max_ports_per_user)) - - /* Check for the port type here. If we are getting - * a STATIC PORT, allow the config. - */ - if (PREDICT_TRUE(port_type != PORT_TYPE_STATIC)) { - info->error = CNAT_OUT_LIMIT; - DSLITE_DEBUG_INSIDE_ERR(CNAT_OUT_LIMIT) - port_exceeded_msg_log(u_ki.dk.ipv4_key.k.ipv4, u_ki.dk.ipv4_key.k.vrf); - nat44_dslite_common_stats[dslite_id].in2out_drops_port_limit_exceeded ++; - u_ki.dk.ipv4_key.k.vrf = ki->dk.ipv4_key.k.vrf; - u_ki.dk.ipv4_key.k.port = ki->dk.ipv4_key.k.port; - handle_dslite_port_exceeded_logging(udb, &u_ki.dk, dslite_entry_ptr); - return (NULL); - } - } - - CHECK_CLEAR_PORT_LIMIT_EXCEED_FLAG(udb, - dslite_entry_ptr->cnat_main_db_max_ports_per_user) - - /* - * check if main db has space to accomodate new entry - */ - h = pool_header(cnat_main_db); - - free_main = vec_len(h->free_indices) - 1; - if (PREDICT_FALSE(!free_main)) { - info->error = CNAT_MAIN_DB_LIMIT; - nat44_dslite_common_stats[dslite_id].in2out_drops_system_limit_reached ++; - DSLITE_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT) - - current_timestamp = spp_trace_log_get_unix_time_in_seconds(); - if (PREDICT_FALSE((current_timestamp - last_log_timestamp) > - 1800)) { - spp_printf(CNAT_SESSION_THRESH_EXCEEDED, 0, NULL); - last_log_timestamp = current_timestamp; - } - -#ifdef UT_TEST_CODE - printf("Limit reached : OLD USER"); -#endif - return NULL; - } - - /* - * allocate port, from existing mapping - */ - my_index = udb->portmap_index; - - if (PREDICT_FALSE(port_type == PORT_TYPE_STATIC)) { - rv = cnat_static_port_alloc_v2_bulk(pm, - PORT_ALLOC_DIRECTED, - port_pair_type, - ki->dk.ipv4_key.k.ipv4, - ki->dk.ipv4_key.k.port, - &my_index, - &(ko.k.k.ipv4), - &(ko.k.k.port), - STAT_PORT_RANGE_FROM_INST_PTR(dslite_entry_ptr) -#ifndef NO_BULK_LOGGING - , udb, - BULKSIZE_FROM_VRFMAP(dslite_entry_ptr), - &nfv9_log_req -#endif - , my_vrfmap->ip_n_to_1 - ); - } else if (PREDICT_TRUE(port_type != PORT_TYPE_RTSP) ) { - - rv = cnat_dynamic_port_alloc_v2_bulk(pm, - PORT_ALLOC_DIRECTED, - port_pair_type, - &my_index, - &(ko.k.k.ipv4), - &(ko.k.k.port), - STAT_PORT_RANGE_FROM_INST_PTR(dslite_entry_ptr) -#ifndef NO_BULK_LOGGING - , udb, - BULKSIZE_FROM_VRFMAP(dslite_entry_ptr), - &nfv9_log_req -#endif - , 0, - &(dslite_entry_ptr->rseed_ip) - ); - DSLITE_PRINTF(1,"D_PORT_ALLOC %x %u\n", ko.k.k.ipv4, ko.k.k.port); - } else { - /* - * For RTSP, two translation entries are created, - * check if main db has space to accomodate two new entry - */ - free_main = free_main - 1; - - if (PREDICT_FALSE(!free_main)) { - info->error = CNAT_MAIN_DB_LIMIT; - nat44_dslite_common_stats[dslite_id].in2out_drops_system_limit_reached ++; - DSLITE_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT) - - return NULL; - } else { - - rv = cnat_dynamic_port_alloc_rtsp_bulk(pm, - PORT_ALLOC_DIRECTED, - port_pair_type, - ki->dk.ipv4_key.k.port, - &my_index, - &(ko.k.k.ipv4), - &(ko.k.k.port), - STAT_PORT_RANGE_FROM_INST_PTR(dslite_entry_ptr) -#ifndef NO_BULK_LOGGING - , udb, - BULKSIZE_FROM_VRFMAP(dslite_entry_ptr), - &nfv9_log_req -#endif - , &(dslite_entry_ptr->rseed_ip) - ); - } - } - - if (PREDICT_FALSE(rv != CNAT_SUCCESS)) { - DSLITE_PRINTF(1,"D_PORT_ALLOC port alloc error\n"); - info->error = rv; - DSLITE_DEBUG_INSIDE_ERR(rv) - nat44_dslite_common_stats[dslite_id].in2out_drops_resource_depletion ++; - log_port_alloc_error(rv, &(ki->dk.ipv4_key)); - return (NULL); - } - /* - * increment port in use for this user - */ - udb->ntranslations += 1; - } else { - /* - * first time allocate port for this user - */ - - /* - * Do not create entry if port limit is invalid - */ - if (PREDICT_FALSE(!(dslite_entry_ptr->cnat_main_db_max_ports_per_user))) { - if (PREDICT_TRUE(port_type != PORT_TYPE_STATIC)) { - info->error = CNAT_OUT_LIMIT; - nat44_dslite_common_stats[dslite_id].in2out_drops_port_limit_exceeded ++; - port_exceeded_msg_log(u_ki.dk.ipv4_key.k.ipv4, u_ki.dk.ipv4_key.k.vrf); - DSLITE_DEBUG_INSIDE_ERR(CNAT_OUT_LIMIT) - return (NULL); - } - } - - /* - * Check if main db has space for new entry - * Allowing a user db entry to be created if main db is not free - * will cause a port to be allocated to that user, which results in - * wastage of that port, hence the check is done here. - */ - h = pool_header(cnat_main_db); - free_main = vec_len(h->free_indices) - 1; - - h = pool_header(cnat_user_db); - free_user = vec_len(h->free_indices) - 1; - - /* - * If either main_db or user_db does not have entries - * bail out, with appropriate error - */ - if (PREDICT_FALSE(!(free_main && free_user))) { - u32 log_error; - if(free_main) { - info->error = CNAT_USER_DB_LIMIT; - log_error = CNAT_USER_DB_LIMIT_ERROR; - } else { - info->error = CNAT_MAIN_DB_LIMIT; - log_error = CNAT_MAIN_DB_LIMIT_ERROR; - } - nat44_dslite_common_stats[dslite_id].in2out_drops_system_limit_reached ++; - DSLITE_DEBUG_INSIDE_ERR(info->error) - spp_printf(log_error, 0, 0); - return NULL; - } - - if (PREDICT_FALSE(port_type == PORT_TYPE_STATIC)) { - rv = cnat_static_port_alloc_v2_bulk(pm, - PORT_ALLOC_ANY, - port_pair_type, - ki->dk.ipv4_key.k.ipv4, - ki->dk.ipv4_key.k.port, - &my_index, - &(ko.k.k.ipv4), - &(ko.k.k.port), - STAT_PORT_RANGE_FROM_INST_PTR(dslite_entry_ptr) -#ifndef NO_BULK_LOGGING - , NULL, - BULKSIZE_FROM_VRFMAP(dslite_entry_ptr), - &nfv9_log_req -#endif - , my_vrfmap->ip_n_to_1 - - ); - } else if (PREDICT_TRUE(port_type != PORT_TYPE_RTSP)) { - rv = cnat_dynamic_port_alloc_v2_bulk(pm, - PORT_ALLOC_ANY, - port_pair_type, - &my_index, - &(ko.k.k.ipv4), - &(ko.k.k.port), - STAT_PORT_RANGE_FROM_INST_PTR(dslite_entry_ptr) -#ifndef NO_BULK_LOGGING - , NULL, - BULKSIZE_FROM_VRFMAP(dslite_entry_ptr), - &nfv9_log_req -#endif - , 0, - &(dslite_entry_ptr->rseed_ip) - ); - DSLITE_PRINTF(1,"NU:D PORT ALLOC..%x %u\n", ko.k.k.ipv4, - ko.k.k.port); - - } else { - /* - * For RTSP, two translation entries are created, - * check if main db has space to accomodate two new entry - */ - free_main = free_main - 1; - - if (PREDICT_FALSE(!free_main)) { - info->error = CNAT_MAIN_DB_LIMIT; - nat44_dslite_common_stats[dslite_id].in2out_drops_system_limit_reached ++; - DSLITE_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT) - - return NULL; - } else { - - rv = cnat_dynamic_port_alloc_rtsp_bulk(pm, - PORT_ALLOC_DIRECTED, - port_pair_type, - ki->dk.ipv4_key.k.port, - &my_index, - &(ko.k.k.ipv4), - &(ko.k.k.port), - STAT_PORT_RANGE_FROM_INST_PTR(dslite_entry_ptr) -#ifndef NO_BULK_LOGGING - , NULL, - BULKSIZE_FROM_VRFMAP(dslite_entry_ptr), - &nfv9_log_req -#endif - , &(dslite_entry_ptr->rseed_ip) - ); - /* TODO: Add the port pair flag here */ - } - } - - - - if (PREDICT_FALSE(rv != CNAT_SUCCESS)) { - DSLITE_PRINTF(1,"NU:D_PORT_ALLOC port alloc error\n"); - info->error = rv; - nat44_dslite_common_stats[dslite_id].in2out_drops_resource_depletion ++; - DSLITE_DEBUG_INSIDE_ERR(rv) - log_port_alloc_error(rv, &(ki->dk.ipv4_key)); - return (NULL); - } - /* - * create entry in user db - */ - udb = dslite_user_db_create_entry(&u_ki, my_index); - nat44_dslite_common_stats[dslite_id].num_subscribers++; - DSLITE_PRINTF(1,"UDB crete entry done..\n"); -#ifndef NO_BULK_LOGGING - if(PREDICT_TRUE(udb && (BULK_ALLOC_NOT_ATTEMPTED != nfv9_log_req))) { - cnat_update_bulk_range_cache(udb, ko.k.k.port, - BULKSIZE_FROM_VRFMAP(dslite_entry_ptr)); - } -#endif /* #ifndef NO_BULK_LOGGING */ - } - - /* - * step 3: - * outside port is allocated for this src vrf/src ip addr - * 1)create a new entry in main db - * 2)setup cnat_out2in_hash key - * 3)setup cnat_in2out_hash key - */ - db = dslite_create_main_db_entry_and_hash(ki, &ko, udb); - DSLITE_PRINTF(1,"dslite_create_main_db_entry_and_hash done..\n"); - //db->vrfmap_index = my_vrfmap - cnat_map_by_vrf; - db->dslite_nat44_inst_id = dslite_id; - nat44_dslite_common_stats[dslite_id].active_translations++; - if (PREDICT_FALSE(port_type == PORT_TYPE_STATIC)) { - nat44_dslite_common_stats[dslite_id].num_static_translations++; - } else { - nat44_dslite_common_stats[dslite_id].num_dynamic_translations++; - } - - dslite_translation_create_count++; - - db->dst_ipv4 = dest_info->k.ipv4; - db->dst_port = dest_info->k.port; - if(PREDICT_TRUE(db->dst_ipv4 || db->dst_port)) { - /* for static fwding, let the nsessions remain zero */ - db->nsessions++; - } - - /* - * don't forget logging - * logging API is unconditional, - * logging configuration check is done inside the inline function - */ - if(PREDICT_FALSE(nfv9_log_req != CACHE_ALLOC_NO_LOG_REQUIRED)) { - if(PREDICT_FALSE( dslite_entry_ptr->nf_logging_policy == - SESSION_LOG_ENABLE)) { - if(PREDICT_TRUE(db->dst_ipv4 || db->dst_port)) { - cnat_nfv9_ds_lite_log_session_create(db, - dslite_entry_ptr,NULL); - } - } else { - cnat_nfv9_ds_lite_mapping_create(db,dslite_entry_ptr -#ifndef NO_BULK_LOGGING - ,nfv9_log_req -#endif - ); - } - if(PREDICT_TRUE((dslite_entry_ptr->syslog_logging_policy != SESSION_LOG_ENABLE) || - (db->dst_ipv4 || db->dst_port))) { - cnat_syslog_ds_lite_mapping_create(db,dslite_entry_ptr,NULL -#ifndef NO_BULK_LOGGING - ,nfv9_log_req -#endif - ); - } - } - -#if 0 - if (PREDICT_FALSE(port_pair_type == PORT_PAIR)) { - cnat_main_db_entry_t *db2 = 0; - dslite_db_key_bucket_t new_ki = *ki; - u64 a, b, c; - - new_ki.k.k.port += 1; - ko.k.k.port += 1; - - CNAT_V4_GET_HASH(new_ki.k.key64, new_ki.bucket, - CNAT_MAIN_HASH_MASK); - - db2 = cnat_create_main_db_entry_and_hash(&new_ki, &ko, udb); - - translation_create_count ++; - db2->dslite_nat44_inst_id = dslite_id; - db2->entry_expires = cnat_current_time; - db2->flags |= CNAT_DB_FLAG_ALG_ENTRY; - udb->ntranslations += 1; -#ifndef NO_BULK_LOGGING - if(PREDICT_FALSE(nfv9_log_req == BULK_ALLOC_NOT_ATTEMPTED)) - cnat_nfv9_log_mapping_create(db2, my_vrfmap, nfv9_log_req); -#else - cnat_nfv9_log_mapping_create(db2, my_vrfmap); -#endif - } -#endif - return db; -} -#endif /* TOBE_PORTED */ - -#if 0 -/* TOBE_PORTED */ -uword -cnat_db_v2_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return 0; -} -VLIB_REGISTER_NODE (cnat_db_v2_node) = { - .function = cnat_db_v2_node_fn, - .name = "vcgn-db-v2", - .vector_size = sizeof (u32), - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(cnat_db_v2_error_strings), - .error_strings = cnat_db_v2_error_strings, - - .n_next_nodes = CNAT_DB_V2_DROP, - - /* edit / add dispositions here */ - .next_nodes = { - [CNAT_DB_V2_DROP] = "error-drop", - }, -}; -#endif -void cnat_db_v2_init (void) -{ - - u32 i, n, lockinit; - cnat_timeout_db_entry_t * tdb __attribute__((unused)); - - cgse_nat_db_entry_t *comb_db __attribute__((unused)); - cgse_nat_user_db_entry_t *comb_user __attribute__((unused)); - cgse_nat_session_db_entry_t *comb_session __attribute__((unused)); - - n = CNAT_DB_SIZE*1.15; /* add 15% LB margin */ - - /* - * We also make it multiple of NUM_BITS_IN_UWORD for better - * DB scanning algorithm - */ - if (n % NUM_BITS_IN_UWORD) - n += (NUM_BITS_IN_UWORD - (n % NUM_BITS_IN_UWORD)); - - pool_alloc(cgse_nat_db,n); - for(i=0; i< n; i++) { - pool_get(cgse_nat_db, comb_db); - } - - for(i=0; i< n; i++) { - pool_put(cgse_nat_db, cgse_nat_db + i); - } - - cnat_main_db = &cgse_nat_db->nat44_main_db; - - /* For Sessions */ - if(PLATFORM_DBL_SUPPORT) { - /* create session table for NAT44 and NAT64 itself */ - printf("DBL Support exist %d\n", PLATFORM_DBL_SUPPORT); - n = CNAT_SESSION_DB_SIZE * 1.15; /* add 15% LB margin */ - } else { - /* Create session table for NAT64 only */ - printf("DBL Support Not exist\n"); - n = NAT64_MAIN_DB_SIZE * 1.15; /* add 15% LB margin */ - } - - /* - * We also make it multiple of NUM_BITS_IN_UWORD for better - * DB scanning algorithm - */ - if (n % NUM_BITS_IN_UWORD) - n += (NUM_BITS_IN_UWORD - (n % NUM_BITS_IN_UWORD)); - - pool_alloc(cgse_session_db,n); - for(i=0; i< n; i++) { - pool_get(cgse_session_db, comb_session); - } - - for(i=0; i< n; i++) { - pool_put(cgse_session_db, cgse_session_db + i); - } - - cnat_session_db = &cgse_session_db->nat44_session_db; - - vec_validate(cnat_out2in_hash, CNAT_MAIN_HASH_MASK); - memset(cnat_out2in_hash, 0xff, CNAT_MAIN_HASH_SIZE*sizeof(index_slist_t)); - - vec_validate(cnat_in2out_hash, CNAT_MAIN_HASH_MASK); - memset(cnat_in2out_hash, 0xff, CNAT_MAIN_HASH_SIZE*sizeof(index_slist_t)); - - vec_validate(cnat_session_hash, CNAT_SESSION_HASH_MASK); - memset(cnat_session_hash, 0xff, CNAT_SESSION_HASH_SIZE*sizeof(index_slist_t)); - - n = CNAT_USER_DB_SIZE * 1.15; /* use hash size as db size for LB margin */ - if (n % NUM_BITS_IN_UWORD) - n += (NUM_BITS_IN_UWORD - (n % NUM_BITS_IN_UWORD)); - - pool_alloc(cgse_user_db,n); - for(i=0; i< n; i++) { - pool_get(cgse_user_db, comb_user); - } - - for(i=0; i< n; i++) { - pool_put(cgse_user_db, cgse_user_db + i); - } - - cnat_user_db = &cgse_user_db->nat44_user_db; - - vec_validate(cnat_user_hash, CNAT_USER_HASH_MASK); - memset(cnat_user_hash, 0xff, CNAT_USER_HASH_SIZE*sizeof(index_slist_t)); - - n = CNAT_TIMEOUT_HASH_SIZE; /* use hash size as db size for LB margin */ - for(i=0; i< n; i++) { - pool_get(cnat_timeout_db, tdb); - } - - for(i=0; i< n; i++) { - pool_put(cnat_timeout_db, cnat_timeout_db + i); - } - - vec_validate(cnat_timeout_hash, CNAT_TIMEOUT_HASH_MASK); - memset(cnat_timeout_hash, 0xff, CNAT_TIMEOUT_HASH_SIZE*sizeof(index_slist_t)); - -#ifdef TOBE_PORTED - for (i=0;i -#include - -#include "cnat_cli.h" - -u32 global_debug_flag = CNAT_DEBUG_NONE; -u16 debug_i_vrf = CNAT_DEBUG_NONE; -u32 debug_i_flag = CNAT_DEBUG_NONE; -u32 debug_i_addr_start = CNAT_DEBUG_NONE; -u32 debug_i_addr_end = CNAT_DEBUG_NONE; - -u16 debug_o_vrf = CNAT_DEBUG_NONE; -u32 debug_o_flag = CNAT_DEBUG_NONE; -u32 debug_o_addr_start = CNAT_DEBUG_NONE; -u32 debug_o_addr_end = CNAT_DEBUG_NONE; - -u32 udp_inside_checksum_disable = 0; -u32 udp_outside_checksum_disable = 0; -u32 udp_inside_packet_dump_enable = 0; -u32 udp_outside_packet_dump_enable = 0; - -u32 tcp_logging_enable_flag = 0; - -u32 icmp_debug_flag = 0; -u32 frag_debug_flag = 0; - -u32 nfv9_logging_debug_flag = 0; -u32 syslog_debug_flag = 0; - -u32 summary_stats_debug_flag = 0; - -/* - * By defaut we set the config debug level to 1 - */ -u32 config_debug_level = 1; - -#ifdef TOBE_PORTED -extern void show_bulk_port_stats(); -extern void clear_bulk_port_stats(); -extern void show_bulk_port_allocation(u16 in_vrfid, u32 inside_ip); -extern void set_bulk_size_to_all_vrfs(int bulk_size); - -u32 *cnat_debug_addr_list; - -extern int global_pd_dbg_lvl; -extern int global_pi_dbg_lvl; -extern int global_l2_dbg_lvl; -extern u32 cnat_pptp_debug_flag; -extern u32 cnat_pcp_debug_flag; - -void spp_api_cnat_get_cgn_db_summary -(spp_api_cnat_generic_command_request_t *); - -void spp_api_cnat_v4_debug_dummy_t_handler -(spp_api_cnat_v4_debug_dummy_t *mp) -{ - u32 arr[] = { DEBUG_DUMMY }; - spp_printf(CNAT_DUMMY_HANDLER_HIT, 1, arr); - if(global_pd_dbg_lvl) { - PLATFORM_DEBUG_PRINT("\n invalid debug command received: message id is 0\n"); - } - mp->rc = CNAT_ERR_INVALID_MSG_ID; - -} - -void spp_api_cnat_v4_debug_dummy_max_t_handler -(spp_api_cnat_v4_debug_dummy_max_t *mp) -{ - u32 arr[] = { DEBUG_DUMMY_MAX }; - spp_printf(CNAT_DUMMY_HANDLER_HIT, 1, arr); - if(global_pd_dbg_lvl) { - PLATFORM_DEBUG_PRINT("\n invalid debug command received: message id is out of range\n"); - } - mp->rc = CNAT_ERR_INVALID_MSG_ID; - -} - - -void spp_api_cnat_v4_debug_global_t_handler -(spp_api_cnat_v4_debug_global_t *mp) -{ - if ((mp->debug_flag == CNAT_DEBUG_GLOBAL_ERR) || - (mp->debug_flag == CNAT_DEBUG_GLOBAL_ALL) || - (mp->debug_flag == CNAT_DEBUG_NONE)) { - mp->rc = CNAT_SUCCESS; - global_debug_flag = mp->debug_flag; - return; - } - - mp->rc = CNAT_ERR_PARSER; - if(global_pd_dbg_lvl) { - PLATFORM_DEBUG_PRINT("invalid global debug flag %x\n", - mp->debug_flag); - } - return; -} - -void spp_node_print_cnat_counters() -{ - if (cnat_global_counters.nfv9_downstream_constipation_count) { - PLATFORM_DEBUG_PRINT("\nNF downstream constipation count: %llu\n", - cnat_global_counters.nfv9_downstream_constipation_count); - } - - if (xlat_global_counters.v4_to_v6_frag_invalid_uidb_drop_count || - xlat_global_counters.v6_to_v4_frag_invalid_uidb_drop_count || - xlat_global_counters.v4_to_v6_icmp_invalid_uidb_drop_count || - xlat_global_counters.v6_to_v4_icmp_invalid_uidb_drop_count || - xlat_global_counters.v4_to_v6_tcp_invalid_uidb_drop_count || - xlat_global_counters.v6_to_v4_tcp_invalid_uidb_drop_count || - xlat_global_counters.v4_to_v6_udp_invalid_uidb_drop_count || - xlat_global_counters.v6_to_v4_udp_invalid_uidb_drop_count || - xlat_global_counters.v4_to_v6_udp_crc_zero_invalid_uidb_drop_count) { - - PLATFORM_DEBUG_PRINT("\nMy_instance %d: v4_to_v6 frag invalid uidb drop count %lld", - my_instance_number, - xlat_global_counters.v4_to_v6_frag_invalid_uidb_drop_count); - - PLATFORM_DEBUG_PRINT("\nMy_instance %d: v6_to_v4 frag invalid uidb drop count %lld", - my_instance_number, - xlat_global_counters.v6_to_v4_frag_invalid_uidb_drop_count); - - PLATFORM_DEBUG_PRINT("\nMy_instance %d: v4_to_v6 icmp invalid uidb drop count %lld", - my_instance_number, - xlat_global_counters.v4_to_v6_icmp_invalid_uidb_drop_count); - - PLATFORM_DEBUG_PRINT("\nMy_instance %d: v6_to_v4 icmp invalid uidb drop count %lld", - my_instance_number, - xlat_global_counters.v6_to_v4_icmp_invalid_uidb_drop_count); - - PLATFORM_DEBUG_PRINT("\nMy_instance %d: v4_to_v6 tcp invalid uidb drop count %lld", - my_instance_number, - xlat_global_counters.v4_to_v6_tcp_invalid_uidb_drop_count); - - PLATFORM_DEBUG_PRINT("\nMy_instance %d: v6_to_v4 tcp invalid uidb drop count %lld", - my_instance_number, - xlat_global_counters.v6_to_v4_tcp_invalid_uidb_drop_count); - - PLATFORM_DEBUG_PRINT("\nMy_instance %d: v4_to_v6 udp invalid uidb drop count %lld", - my_instance_number, - xlat_global_counters.v4_to_v6_udp_invalid_uidb_drop_count); - - PLATFORM_DEBUG_PRINT("\nMy_instance %d: v6_to_v4 udp invalid uidb drop count %lld", - my_instance_number, - xlat_global_counters.v6_to_v4_udp_invalid_uidb_drop_count); - - PLATFORM_DEBUG_PRINT("\nMy_instance %d: v4_to_v6 udp crc0 invld uidb drop count %lld", - my_instance_number, - xlat_global_counters.v4_to_v6_udp_crc_zero_invalid_uidb_drop_count); - - PLATFORM_DEBUG_PRINT("\n"); - } - - -} - -void spp_log_p2mp_req(spp_api_cnat_p2mp_debug_request_t *mp) -{ - u8 i = 0; - u32 num_rec = spp_net_to_host_byte_order_32(&mp->param[i++]); - u32 err_c_num_args; - - while (num_rec--) { - u8 j = 0; - u16 err_c; - u16 num_args; - u32 argv[32]; - - err_c_num_args = spp_net_to_host_byte_order_32(&mp->param[i++]); - err_c = (err_c_num_args >> 16) & 0xFFFF; - num_args = err_c_num_args & 0xFFFF; - - num_args = (num_args <= 32) ? num_args : 32; - while (j < num_args) { - argv[j++] = spp_net_to_host_byte_order_32(&mp->param[i++]); - } - - i += ((num_args - 32) > 0) ? (num_args - 32) : 0; - spp_printf(err_c, num_args, argv); - } -} - -void nat64_debug_addr_pool_add_del() -{ - cnat_portmap_v2_t *my_pm = NULL; - cnat_portmap_v2_t *pm = NULL; - u32 len, i, pm_len; - - PLATFORM_DEBUG_PRINT("\n sizeof port_map =%d\n", sizeof( cnat_portmap_v2_t)); - len = 10; - PLATFORM_DEBUG_PRINT("\n adding 10 entries in vector 1-10\n "); - vec_add2(pm, my_pm, len); - pm = my_pm; - - PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm); - for(i=0;iipv4_address = i+1; - my_pm++; - } - PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm); - - pm_len = vec_len(pm); - PLATFORM_DEBUG_PRINT("\n printing vector contents : vec_len = %d \n", pm_len); - my_pm = pm; - for(i=0;iipv4_address); - my_pm++; - } - PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm); - - PLATFORM_DEBUG_PRINT("\n adding 5 entries in vector 11-15\n "); - len = 5; - vec_add2(pm, my_pm, len); - - PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm); - for(i=0;iipv4_address = 11+i; - my_pm++; - } - - PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm); - pm_len = vec_len(pm); - PLATFORM_DEBUG_PRINT("\n printing vector contents : vec_len = %d \n", pm_len); - my_pm = pm; - for(i=0;iipv4_address); - my_pm++; - } - PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm); - - PLATFORM_DEBUG_PRINT("\n adding 6 entries in vector 16-21\n "); - len = 6; - vec_add2(pm, my_pm, len); - PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm); - for(i=0;iipv4_address = 16+i; - my_pm++; - } - - PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm); - pm_len = vec_len(pm); - PLATFORM_DEBUG_PRINT("\n printing vector contents : vec_len = %d \n", pm_len); - my_pm = pm; - for(i=0;iipv4_address); - my_pm++; - } - - PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm); - PLATFORM_DEBUG_PRINT("\nDeleting 7 entries starting from entry value=8\n"); - pm_len = vec_len(pm); - my_pm = pm; - PLATFORM_DEBUG_PRINT(" pm_len =%d\n", pm_len); - for(i=0;iipv4_address == 8){ - PLATFORM_DEBUG_PRINT("\n match found brraeaking..\n"); - break; - } - my_pm++; - } - - PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p i= %d\n", pm, my_pm, i); -// vec_delete(pm, 7, my_pm); - vec_delete(pm, 7, i); - PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm); - - PLATFORM_DEBUG_PRINT(" printing entries aftr deletion from 8-14\n"); - pm_len = vec_len(pm); - PLATFORM_DEBUG_PRINT("\n printing vector contents : vec_len = %d \n", pm_len); - my_pm = pm; - for(i=0;iipv4_address); - my_pm++; - } - - - PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm); - - PLATFORM_DEBUG_PRINT("\nadding deleted items again 8-14\n"); - len =7; - vec_add2(pm, my_pm, len); - - PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm); - for(i=0;iipv4_address = 8+i; - my_pm++; - } - - PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm); - pm_len = vec_len(pm); - PLATFORM_DEBUG_PRINT("\n printing vector contents : vec_len = %d \n", pm_len); - my_pm = pm; - for(i=0;iipv4_address); - my_pm++; - } - PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm); - PLATFORM_DEBUG_PRINT("\n"); -} - - -void uidb_mapping_dump_timeout() { - - u32 i; - - PLATFORM_DEBUG_PRINT("\nCGSE uidb mapping table \n"); - for(i = 0;i < 30;i++) { - PLATFORM_DEBUG_PRINT("%d ",*(cgse_uidb_index_cgse_id_mapping_ptr + i)); - } - -} - -void nat64_debug_dump_info(u32 debug_value) -{ - - switch(debug_value) { - - case 1 : - bib_add_v6_entry1(); - break; - - case 2 : - bib_add_v6_entry2(); - break; - - case 3 : - bib_add_v6_entry1_new(); - break; - - case 4 : - bib_add_v6_entry1_new_static(); - break; - - case 5 : - bib_add_v6_entry3(); - break; - - case 6 : - bib_add_v6_entry_new2(); - break; - - case 7 : - nat64_fill_table_entry(); - break; - - case 10 : - nat64_db_dump_main(); - break; - - case 11 : - nat64_db_dump_user(); - break; - - case 12 : - nat64_db_dump_session(); - break; - - case 13 : - nat64_dump_table(); - break; - - case 14 : - bib_del_v6_entry1_static(); - break; - - case 15 : - nat64_debug_addr_pool_add_del(); - break; - - case 16 : - nat64_db_dump_timeout(0); - break; - - case 17 : - uidb_mapping_dump_timeout(); - break; - - default : break; - } -} - - -void cnat_debug_flags_set (spp_api_cnat_p2mp_debug_request_t *mp) -{ - u32 debug_variable = spp_net_to_host_byte_order_32(&mp->param[0]); - u32 debug_value = spp_net_to_host_byte_order_32(&mp->param[1]); - - cnat_key_t t_key; - - switch (debug_variable) { - - case CNAT_DEBUG_FLAG_UDP_INSIDE_CHECKSUM_DISABLE: - udp_inside_checksum_disable = debug_value; - PLATFORM_DEBUG_PRINT("\nudp_inside_checksum_disable set to %d\n", debug_value); - break; - - case CNAT_DEBUG_FLAG_UDP_OUTSIDE_CHECKSUM_DISABLE: - udp_outside_checksum_disable = debug_value; - PLATFORM_DEBUG_PRINT("\nudp_outside_checksum_disable set to %d\n", debug_value); - break; - - case CNAT_DEBUG_FLAG_UDP_OUTSIDE_PKT_DUMP_ENABLE: - udp_outside_packet_dump_enable = debug_value; - PLATFORM_DEBUG_PRINT("\nudp_outside_packet_dump_enable set to %d\n", debug_value); - break; - - case CNAT_DEBUG_FLAG_UDP_INSIDE_PKT_DUMP_ENABLE: - udp_inside_packet_dump_enable = debug_value; - PLATFORM_DEBUG_PRINT("\nudp_inside_packet_dump_enable set to %d\n", debug_value); - break; - - case CNAT_DEBUG_FLAG_ICMP_PKT_DUMP_ENABLE: - icmp_debug_flag = debug_value; - PLATFORM_DEBUG_PRINT("\nicmp_debug_flag set to %d\n", debug_value); - break; - - case CNAT_DEBUG_FLAG_FRAG_PKT_DUMP_ENABLE: - frag_debug_flag = debug_value; - PLATFORM_DEBUG_PRINT("\nfrag_debug_flag set to %d\n", debug_value); - break; - - case CNAT_DEBUG_FLAG_XLAT_CONFIG_DEBUG_ENABLE: - xlat_config_debug_level = debug_value; - PLATFORM_DEBUG_PRINT("\nxlat_config_debug_level set to %d\n", debug_value); - break; - - case CNAT_DEBUG_FLAG_NAT64_CONFIG_DEBUG_ENABLE: - nat64_config_debug_level = debug_value; - PLATFORM_DEBUG_PRINT("\nnat64_config_debug_level set to %d\n", debug_value); - nat64_debug_dump_info(debug_value); - break; - - case CNAT_DEBUG_FLAG_NAT64_DATA_PATH_DEBUG_ENABLE: - nat64_data_path_debug_level = debug_value; - PLATFORM_DEBUG_PRINT("\nnat64_data_path_debug_level set to %d\n", debug_value); - break; - - case CNAT_DEBUG_FLAG_DSLITE_CONFIG_DEBUG_ENABLE: - ds_lite_config_debug_level = debug_value; - PLATFORM_DEBUG_PRINT("\nds_lite_config_debug_level set to %d\n", debug_value); - break; - - case CNAT_DEBUG_FLAG_XLAT_DATA_PATH_DEBUG_ENABLE: - xlat_data_path_debug_level = debug_value; - PLATFORM_DEBUG_PRINT("\nxlat_data_path_debug_level set to %d\n", debug_value); - break; - - case CNAT_DEBUG_FLAG_CONFIG_DEBUG_ENABLE: - config_debug_level = debug_value; - - PLATFORM_DEBUG_PRINT("\nconfig_debug_level set to %d\n", debug_value); - break; - - case CNAT_DEBUG_FLAG_CONFIG_PPTP_ENABLE: - cnat_pptp_debug_flag = debug_value; - - if(debug_value == 0) { - pptp_dump_counters(); - } - - PLATFORM_DEBUG_PRINT("\ncnat_pptp_debug_level set to %d\n", debug_value); - break; - - case CNAT_DEBUG_FLAG_CONFIG_PCP_ENABLE: - cnat_pcp_debug_flag = debug_value; - - if(debug_value == 0) { - pcp_dump_counters(); - } - PLATFORM_DEBUG_PRINT("\ncnat_pcp_debug_level set to %d\n", debug_value); - break; - - case CNAT_DEBUG_FLAG_GLOBAL_DEBUG_ALL_ENABLE: - global_debug_flag = debug_value; - PLATFORM_DEBUG_PRINT("\nglobal_debug_flag set to %d\n", debug_value); - break; - - case CNAT_DEBUG_FLAG_SUMMARY_STATS_DEBUG_ENABLE: - summary_stats_debug_flag = debug_value; - PLATFORM_DEBUG_PRINT("\nsummary_stats_debug_flag set to %d\n", debug_value); - break; - - case CNAT_DEBUG_FLAG_SHOW_DEBUG_ENABLE: - show_debug_level = debug_value; - PLATFORM_DEBUG_PRINT("\nshow_debug_level set to %d\n", debug_value); - break; - - case CNAT_DEBUG_FLAG_TCP_LOGGING_ENABLE: - tcp_debug_logging_enable_disable(debug_value); - break; - case CNAT_DEBUG_FLAG_V6RD_DATA_PATH_DEBUG_ENABLE: - v6rd_data_path_debug_level = debug_value; - PLATFORM_DEBUG_PRINT("\nv6rd_data_path_debug_level set to %d\n", debug_value); - break; - case CNAT_DEBUG_FLAG_V6RD_CONFIG_DEBUG_ENABLE: - v6rd_config_debug_level = debug_value; - PLATFORM_DEBUG_PRINT("\nv6rd_config_debug_level set to %d\n", debug_value); - break; - case CNAT_DEBUG_FLAG_V6RD_DEFRAG_DEBUG_ENABLE: - /* set debug atleast to 1, so that critical errors are always - * enabled - */ - v6rd_defrag_debug_level = debug_value ? debug_value : 1; - PLATFORM_DEBUG_PRINT("\nv6rd_config_debug_level set to %d\n", debug_value); - break; - - - case CNAT_DEBUG_SET_STATIC_PORT_RANGE: - PLATFORM_DEBUG_PRINT("\nChange Static Port Range from %d --> %d\n", - cnat_static_port_range, debug_value); - cnat_static_port_range = debug_value; - break; - - case CNAT_DEBUG_FLAG_DSLITE_DP_ENABLE: - PLATFORM_DEBUG_PRINT("\n Changing dslite debug flag from %d --> %d\n", - dslite_debug_level, debug_value); - dslite_debug_level = debug_value; - break; - - case CNAT_DEBUG_FLAG_NFV9_LOGGING_DUMP_ENABLE: - nfv9_logging_debug_flag = debug_value; - PLATFORM_DEBUG_PRINT("\nnfv9_logging_debug_flag set to %d\n", debug_value); - break; - - case CNAT_DEBUG_FLAG_SYSLOG_LOGGING_DUMP_ENABLE: - syslog_debug_flag = debug_value; - PLATFORM_DEBUG_PRINT("\nsyslog_debug_flag set to %d\n", debug_value); - break; - - case CNAT_DEBUG_FLAG_MAPE_CONFIG_DEBUG_ENABLE: - mape_config_debug_level = debug_value; - PLATFORM_DEBUG_PRINT("\nmape_config_debug_level set to %d\n", debug_value); - break; - - case CNAT_DEBUG_FLAG_MAPE_DATA_PATH_DEBUG_ENABLE: - mape_data_path_debug_level = debug_value; - PLATFORM_DEBUG_PRINT("\nmape_data_path_debug_level set to %d\n", debug_value); - break; - - case CNAT_DEBUG_FLAGS_DUMP: - default: - { - PLATFORM_DEBUG_PRINT("\nCurrent values of Debug Variables\n"); - PLATFORM_DEBUG_PRINT("\nTo modify an item chose its index and provide the value\n"); - PLATFORM_DEBUG_PRINT("\n%d: udp_inside_checksum_disable %d\n", - CNAT_DEBUG_FLAG_UDP_INSIDE_CHECKSUM_DISABLE, - udp_inside_checksum_disable); - PLATFORM_DEBUG_PRINT("%d: udp_outside_checksum_disable %d\n", - CNAT_DEBUG_FLAG_UDP_OUTSIDE_CHECKSUM_DISABLE, - udp_outside_checksum_disable); - PLATFORM_DEBUG_PRINT("%d: udp_inside_packet_dump_enable %d\n", - CNAT_DEBUG_FLAG_UDP_OUTSIDE_PKT_DUMP_ENABLE, - udp_inside_packet_dump_enable); - PLATFORM_DEBUG_PRINT("%d: udp_outside_packet_dump_enable %d\n", - CNAT_DEBUG_FLAG_UDP_INSIDE_PKT_DUMP_ENABLE, - udp_outside_packet_dump_enable); - PLATFORM_DEBUG_PRINT("%d: icmp_debug_flag %d\n", - CNAT_DEBUG_FLAG_ICMP_PKT_DUMP_ENABLE, - icmp_debug_flag); - PLATFORM_DEBUG_PRINT("%d: frag_debug_flag %d\n", - CNAT_DEBUG_FLAG_FRAG_PKT_DUMP_ENABLE, - frag_debug_flag); - PLATFORM_DEBUG_PRINT("%d: config_debug_level %d\n", - CNAT_DEBUG_FLAG_CONFIG_DEBUG_ENABLE, - config_debug_level); - PLATFORM_DEBUG_PRINT("%d: global_debug_flag %d\n", - CNAT_DEBUG_FLAG_GLOBAL_DEBUG_ALL_ENABLE, - global_debug_flag); - PLATFORM_DEBUG_PRINT("%d: summary_stats_debug_flag %d\n", - CNAT_DEBUG_FLAG_SUMMARY_STATS_DEBUG_ENABLE, - summary_stats_debug_flag); - PLATFORM_DEBUG_PRINT("%d: show_debug_level %d\n", - CNAT_DEBUG_FLAG_SHOW_DEBUG_ENABLE, - show_debug_level); - PLATFORM_DEBUG_PRINT("%d: xlat_config_debug_level %d\n", - CNAT_DEBUG_FLAG_XLAT_CONFIG_DEBUG_ENABLE, - xlat_config_debug_level); - PLATFORM_DEBUG_PRINT("%d: xlat_data_path_debug_level %d\n", - CNAT_DEBUG_FLAG_XLAT_DATA_PATH_DEBUG_ENABLE, - xlat_data_path_debug_level); - PLATFORM_DEBUG_PRINT("%d: tcp_logging_enable_flag %d\n", - CNAT_DEBUG_FLAG_TCP_LOGGING_ENABLE, - tcp_logging_enable_flag); - PLATFORM_DEBUG_PRINT(" tcp_logging_enable_options DISABLE %d, ENABLE %d, PKT_DUMP %d, SUMMARY_DUMP %d\n", - TCP_LOGGING_DISABLE, TCP_LOGGING_ENABLE, - TCP_LOGGING_PACKET_DUMP, TCP_LOGGING_SUMMARY_DUMP); - PLATFORM_DEBUG_PRINT("%d: nfv9_logging_debug_flag %d\n", - CNAT_DEBUG_FLAG_NFV9_LOGGING_DUMP_ENABLE, - nfv9_logging_debug_flag); - PLATFORM_DEBUG_PRINT("%d: syslog_debug_flag %d\n", - CNAT_DEBUG_FLAG_SYSLOG_LOGGING_DUMP_ENABLE, - syslog_debug_flag); - PLATFORM_DEBUG_PRINT("%d: cnat_static_port_range %d\n", - CNAT_DEBUG_SET_STATIC_PORT_RANGE, - cnat_static_port_range); - PLATFORM_DEBUG_PRINT("%d: v6rd_data_path_debug_level %d\n", - CNAT_DEBUG_FLAG_V6RD_DATA_PATH_DEBUG_ENABLE, - v6rd_data_path_debug_level); - PLATFORM_DEBUG_PRINT("%d: v6rd_config_debug_level %d\n", - CNAT_DEBUG_FLAG_V6RD_CONFIG_DEBUG_ENABLE, - v6rd_config_debug_level); - PLATFORM_DEBUG_PRINT("%d: v6rd_defrag_debug_level %d\n", - CNAT_DEBUG_FLAG_V6RD_DEFRAG_DEBUG_ENABLE, - v6rd_defrag_debug_level); - PLATFORM_DEBUG_PRINT("%d: nat64_stful_debug %d\n", - CNAT_DEBUG_FLAG_NAT64_CONFIG_DEBUG_ENABLE, - nat64_config_debug_level); - PLATFORM_DEBUG_PRINT("%d: nat64_data_path_debug_level %d\n", - CNAT_DEBUG_FLAG_NAT64_DATA_PATH_DEBUG_ENABLE, - nat64_data_path_debug_level); - PLATFORM_DEBUG_PRINT("%d: dslite_debug_level %d\n", - CNAT_DEBUG_FLAG_DSLITE_DP_ENABLE, - dslite_debug_level); - PLATFORM_DEBUG_PRINT("%d: ds_lite_config_debug_level %d\n", - CNAT_DEBUG_FLAG_DSLITE_CONFIG_DEBUG_ENABLE, - ds_lite_config_debug_level); - PLATFORM_DEBUG_PRINT("%d: mape_config_debug_level %d\n", - CNAT_DEBUG_FLAG_MAPE_CONFIG_DEBUG_ENABLE, - mape_config_debug_level); - PLATFORM_DEBUG_PRINT("%d: mape_data_path_debug_level %d\n", - CNAT_DEBUG_FLAG_MAPE_DATA_PATH_DEBUG_ENABLE, - mape_data_path_debug_level); - } - break; - } -} - -extern void dump_cnat_frag_stats(void); - -void spp_api_cnat_p2mp_debug_request_t_handler -(spp_api_cnat_p2mp_debug_request_t *mp) -{ - u16 command_type; - -/* - if (mp->core_num != my_instance_number) { - mp->rc = CNAT_NOT_THIS_CORE; - return; - } -*/ - - command_type = spp_net_to_host_byte_order_16(&mp->dump_type); - PLATFORM_DEBUG_PRINT("-->> Core%d: Received debug msg ... cmd type: %d\n", - my_instance_number, command_type); - - switch (command_type) { - - case CNAT_DEBUG_GENERIC_COMMAND_DUMP_POLICY: - PLATFORM_DEBUG_PRINT("Core%d: policy\n", my_instance_number); - cnat_db_dump_policy(); - break; - - case CNAT_DEBUG_GENERIC_COMMAND_DUMP_MAIN_DB: - PLATFORM_DEBUG_PRINT("Core%d: Main db\n", my_instance_number); - cnat_db_dump_main(); - break; - - case CNAT_DEBUG_GENERIC_COMMAND_DUMP_MAIN_DB_SUMMARY: - PLATFORM_DEBUG_PRINT("Core%d: Main db Summary\n", my_instance_number); - cnat_db_dump_main_summary(); - break; - - case CNAT_DEBUG_GENERIC_COMMAND_DUMP_USER_DB: - PLATFORM_DEBUG_PRINT("Core%d: User db\n", my_instance_number); - cnat_db_dump_user(); - break; - - case CNAT_DEBUG_GENERIC_COMMAND_DUMP_USER_DB_SUMMARY: - PLATFORM_DEBUG_PRINT("Core%d: User db Summary\n", my_instance_number); - cnat_db_dump_user_summary(); - break; - - case CNAT_DEBUG_GENERIC_COMMAND_DUMP_HASHES_DB: - PLATFORM_DEBUG_PRINT("Core%d: Hashes db\n", my_instance_number); - cnat_db_dump_hashes(); - break; - - case CNAT_DEBUG_GENERIC_COMMAND_DUMP_VRF_MAP: - PLATFORM_DEBUG_PRINT("Core%d: Vrf map \n", my_instance_number); - cnat_db_dump_portmaps(); - break; - - case CNAT_DEBUG_GENERIC_COMMAND_DUMP_SUMMARY_DB: - PLATFORM_DEBUG_PRINT("Core%d: dump summary DB \n", my_instance_number); - cnat_db_summary(); - break; - - case CNAT_DEBUG_GENERIC_COMMAND_DUMP_STATS: - PLATFORM_DEBUG_PRINT("Core%d: dump stats \n", my_instance_number); - spp_node_print_stats(1, NULL); - break; - - /* Currently does same as clear node ctr, may change */ - case CNAT_DEBUG_GENERIC_COMMAND_CLEAR_STATS: - PLATFORM_DEBUG_PRINT("Core%d: clear stats \n", my_instance_number); - spp_node_clear_stats(); - break; - - case CNAT_DEBUG_SPP_LOG: - PLATFORM_DEBUG_PRINT("Core%d: SPP LOG \n", my_instance_number); - spp_log_p2mp_req(mp); - break; - - case CNAT_DEBUG_GENERIC_COMMAND_DUMP_NODE_COUNTER: - PLATFORM_DEBUG_PRINT("Core%d: NODE Counter dump \n", my_instance_number); - spp_node_print_counters(); - break; - - case CNAT_DEBUG_GENERIC_COMMAND_CLEAR_NODE_COUNTER: - PLATFORM_DEBUG_PRINT("Core%d: clear node counter \n", my_instance_number); - spp_node_clear_stats(); - break; - - case CNAT_DEBUG_GENERIC_COMMAND_DUMP_CNAT_COUNTER: - PLATFORM_DEBUG_PRINT("Core%d: CNAT Counter dump \n", my_instance_number); - spp_node_print_cnat_counters(); - break; - - case CNAT_DEBUG_GENERIC_COMMAND_DUMP_VA: - PLATFORM_DEBUG_PRINT("Core%d: VA dump \n", my_instance_number); - { - int argc = 1; - u32 arg[2] = {spp_net_to_host_byte_order_32(&mp->param[0]), 0}; - - cnat_va_dump(argc, arg); - } - break; - - case CNAT_DEBUG_GENERIC_COMMAND_SHOW_CONFIG: - PLATFORM_DEBUG_PRINT("Core%d: Show config dump \n", my_instance_number); - { - int argc = 0; - unsigned long arg[3]; - - if (arg[argc++] = spp_net_to_host_byte_order_32(&mp->param[0])) { - if (arg[argc++] = spp_net_to_host_byte_order_32(&mp->param[1])) { - ; - } else { - argc--; - } - } - - cnat_show_cdb_command_v2(argc, arg); -/* - xlat_show_config(); - cnat_alg_show(); -*/ - v6rd_show_config(); - dslite_show_config(); - nat64_dump_table(); - mape_show_config(); - } - break; - - case CNAT_DEBUG_GENERIC_COMMAND_SHOW_NFV9: - PLATFORM_DEBUG_PRINT("Core%d: NFv9 dump \n", my_instance_number); - #if 0 /* Currently not calling this */ - cnat_nfv9_show_cmd(); - #endif - break; - - case CNAT_DEBUG_GENERIC_COMMAND_SHOW_IVRF: - PLATFORM_DEBUG_PRINT("Core%d: IVRF dump \n", my_instance_number); - { - int argc = 0; - unsigned long arg[3]; - - if (arg[argc++] = spp_net_to_host_byte_order_32(&mp->param[0])) { - if (arg[argc++] = spp_net_to_host_byte_order_32(&mp->param[1])) { - if (arg[argc++] = spp_net_to_host_byte_order_32(&mp->param[2])) { - ; - } else { - argc--; - } - } else { - argc--; - } - } - - - PLATFORM_DEBUG_PRINT("VRF: %d \n", spp_net_to_host_byte_order_32(&mp->param[0])); - PLATFORM_DEBUG_PRINT("2nd arg: %d \n", - spp_net_to_host_byte_order_32(&mp->param[1])); - - cnat_show_ivrf_command_v2(argc, arg); - } - break; - - case CNAT_DEBUG_GENERIC_COMMAND_SHOW_OVRF: - PLATFORM_DEBUG_PRINT("Core%d: OVRF dump \n", my_instance_number); - { - int argc = 0; - unsigned long arg[3]; - if (arg[argc++] = spp_net_to_host_byte_order_32(&mp->param[0])) { - if (arg[argc++] = spp_net_to_host_byte_order_32(&mp->param[1])) { - if (arg[argc++] = spp_net_to_host_byte_order_32(&mp->param[2])) { - ; - } else { - argc--; - } - } else { - argc--; - } - } - - PLATFORM_DEBUG_PRINT("VRF: %d \n", spp_net_to_host_byte_order_32(&mp->param[0])); - PLATFORM_DEBUG_PRINT("2nd arg: %d \n", - spp_net_to_host_byte_order_32(&mp->param[1])); - - cnat_show_ovrf_command_v2(argc, arg); - } - break; - - case CNAT_DEBUG_GENERIC_COMMAND_DEBUG_OPTIONS: - PLATFORM_DEBUG_PRINT("Core%d: Debug option dump \n", my_instance_number); - { - global_pd_dbg_lvl = 0; - global_pi_dbg_lvl = 0; - global_l2_dbg_lvl = 0; - - global_pd_dbg_lvl = - spp_net_to_host_byte_order_32(&mp->param[0]); - global_pi_dbg_lvl = - spp_net_to_host_byte_order_32(&mp->param[1]); - global_l2_dbg_lvl = - spp_net_to_host_byte_order_32(&mp->param[2]); - - PLATFORM_DEBUG_PRINT("global_pd_dbg_lvl: %d, global_pi_dbg_lvl: %d, global_l2_dbg_lvl: %d\n", - global_pd_dbg_lvl, global_pi_dbg_lvl, global_l2_dbg_lvl); - } - break; - - case CNAT_DEBUG_GENERIC_COMMAND_DUMP_DEBUG_LEVELS: - PLATFORM_DEBUG_PRINT("Core%d: PD Debug level: %d \n", my_instance_number, global_pd_dbg_lvl); - PLATFORM_DEBUG_PRINT("Core%d: PI Debug level: %d \n", my_instance_number, global_pi_dbg_lvl); - PLATFORM_DEBUG_PRINT("Core%d: L2 Debug level: %d \n", my_instance_number, global_l2_dbg_lvl); - break; - - case CNAT_DEBUG_GENERIC_COMMAND_DEBUG_FLAGS: - PLATFORM_DEBUG_PRINT("Core%d: Debug flags \n", my_instance_number); - cnat_debug_flags_set(mp); - break; - - case CNAT_READ_TEMP_SENSORS: - PLATFORM_INIT_TEMP_SENSORS(); - PLATFORM_READ_CPU_SENSORS(TEMPERATURE_SENSOR_TEST_MODE); - break; - - case CNAT_BLOCK_OCTEON_SENSOR_READ: - - PLATFORM_SET_TEMP_READ_BLOCK(temperature_read_blocked , mp); -#ifdef TARGET_RODDICK - temperature_read_blocked = - spp_net_to_host_byte_order_32(&mp->param[0]); -#endif - break; - - case CNAT_DEBUG_TIMEOUT_DB_SUMMARY: - cnat_db_dump_timeout(); - break; - - /* This option has to be removed later */ - case CNAT_DEBUG_SET_BULK_SIZE: - PLATFORM_DEBUG_PRINT("\nSetting bulk size to %d\n", - spp_net_to_host_byte_order_32(&mp->param[0])); - set_bulk_size_to_all_vrfs( - spp_net_to_host_byte_order_32(&mp->param[0])); - break; - - case CNAT_DEBUG_SHOW_BULK_STAT: - show_bulk_port_stats(); - break; - - case CNAT_DEBUG_CLEAR_BULK_STAT: - clear_bulk_port_stats(); - break; - - case CNAT_DEBUG_SHOW_BULK_ALLOC: - { - u16 in_vrfid = spp_net_to_host_byte_order_32(&mp->param[0]); - u32 inside_ip = spp_net_to_host_byte_order_32(&mp->param[1]); - show_bulk_port_allocation(in_vrfid, inside_ip); - } - break; - - case CNAT_DEBUG_NAT44_IN2OUT_FRAG_STATS: - dump_cnat_frag_stats(); - break; - - default: - mp->rc = CNAT_ERR_INVALID_MSG_ID; - break; - } - - mp->rc = CNAT_SUCCESS; - return; -} - - -void spp_api_cnat_v4_debug_in2out_private_addr_t_handler -(spp_api_cnat_v4_debug_in2out_private_addr_t *mp) -{ - u16 i_vrf; - u32 debug_flag; - u32 start_addr, end_addr; - - - start_addr = - spp_net_to_host_byte_order_32(&mp->start_addr); - end_addr = - spp_net_to_host_byte_order_32(&mp->end_addr); - i_vrf = - spp_net_to_host_byte_order_16(&mp->i_vrf); - debug_flag = - spp_net_to_host_byte_order_32(&mp->debug_flag); - - if ((i_vrf > MAX_UIDX) || (start_addr > end_addr) || - ((debug_flag != CNAT_DEBUG_NONE) && - ((debug_flag & CNAT_DEBUG_ALL) == CNAT_DEBUG_NONE))) { - mp->rc = CNAT_ERR_PARSER; - PLATFORM_DEBUG_PRINT("invalid debug ivrf 0x%x flag 0x%x " - "start addr 0x%x end addr 0x%x\n", - i_vrf, debug_flag, - start_addr, end_addr); - return; - } - - PLATFORM_DEBUG_PRINT("debug ivrf 0x%x flag 0x%x " - "start addr 0x%x end addr 0x%x\n", - i_vrf, debug_flag, - start_addr, end_addr); - - mp->rc = CNAT_SUCCESS; - debug_i_vrf = i_vrf; - debug_i_flag = debug_flag; - debug_i_addr_start = start_addr; - debug_i_addr_end = end_addr; - -} - -void spp_api_cnat_v4_debug_out2in_public_addr_t_handler -(spp_api_cnat_v4_debug_out2in_public_addr_t *mp) -{ - u16 o_vrf; - u32 debug_flag; - u32 start_addr, end_addr; - - start_addr = - spp_net_to_host_byte_order_32(&mp->start_addr); - end_addr = - spp_net_to_host_byte_order_32(&mp->end_addr); - o_vrf = - spp_net_to_host_byte_order_16(&mp->o_vrf); - debug_flag = - spp_net_to_host_byte_order_32(&mp->debug_flag); - - if ((o_vrf > MAX_UIDX) || (start_addr > end_addr) || - ((debug_flag != CNAT_DEBUG_NONE) && - ((debug_flag & CNAT_DEBUG_ALL) == CNAT_DEBUG_NONE))) { - mp->rc = CNAT_ERR_PARSER; - PLATFORM_DEBUG_PRINT("invalid debug ovrf 0x%x flag 0x%x " - "start addr 0x%x end addr 0x%x\n", - o_vrf, debug_flag, - start_addr, end_addr); - return; - } - - mp->rc = CNAT_SUCCESS; - debug_o_vrf = o_vrf; - debug_o_flag = debug_flag; - debug_o_addr_start = start_addr; - debug_o_addr_end = end_addr; - - PLATFORM_DEBUG_PRINT(" o2i debug currently is not supported\n"); -} - -void nat64_reset_session_expiry(nat64_bib_entry_t *db) -{ - NAT64_STFUL_DEBUG_PRINT(3, " invoking nat64_clean_bib_db_entry\n " ); - nat64_clean_bib_db_entry(db); - NAT64_STFUL_DEBUG_PRINT(3, "done with clean_bib_db_entry\n " ); -} - -void spp_api_nat64_clear_db_request_t_handler -(spp_api_nat64_clear_db_request_t *mp) -{ - u16 port, proto, flag; - u32 index; - u32 i; - nat64_bib_entry_t* db; - nat64_v6_key_t ki; - nat64_table_entry_t *my_nat64_table_db_ptr; - u16 nat64_id; - - NAT64_STFUL_FUNC_ENTER; - NAT64_STFUL_DEBUG_DUMP_MSG(mp); - - nat64_id = spp_net_to_host_byte_order_16(&mp->nat64_id); - my_nat64_table_db_ptr = nat64_table_ptr + nat64_id; - - port = spp_net_to_host_byte_order_16(&mp->port_num); - proto = mp->protocol; - - ki.vrf = nat64_id; - ki.vrf |= ((u16)proto << CNAT_PRO_SHIFT); - - for(i =0 ; i< 4 ; i++) - ki.ipv6[i] = spp_net_to_host_byte_order_32(&mp->ip_addr[i]); - - ki.port = port; - - flag = mp->flags; - - mp->rc = CNAT_SUCCESS; - - NAT64_STFUL_DEBUG_PRINT(3, "\n Nat64_id = %d, port =%d, \ - proto =%d, flags=0x%08X",\ - nat64_id, port, proto, flag); - - NAT64_STFUL_DEBUG_PRINT(3, "\n IPv6 Addr = %08X : %08X: %08X: %08X",\ - ki.ipv6[0], ki.ipv6[1], ki.ipv6[2], ki.ipv6[3]); - - if (flag == CNAT_DB_CLEAR_SPECIFIC) { - NAT64_STFUL_DEBUG_PRINT(3, "\n clear specific \n"); - - db = nat64_bib_db_lookup_entry(&ki); - if (db == NULL) { - NAT64_STFUL_DEBUG_PRINT(3, "\n clear specific - not present\n"); - mp->rc = CNAT_NOT_FOUND_ANY; - return; - } - - if( !(db->flags & CNAT_DB_NAT64_FLAG) || - (db->nat64_inst_id != nat64_id)) - return; - - - nat64_reset_session_expiry(db); - return; - } - - pool_header_t *p = pool_header(nat64_bib_db); - - for(index = 0; index < vec_len(nat64_bib_db); index++) { - - /* check is it nat44, if yes skip , do it n nat44 as well */ - - if (PREDICT_FALSE(!clib_bitmap_get(p->free_bitmap, index))) { - db = nat64_bib_db + index; - - if( !(db->flags & CNAT_DB_NAT64_FLAG) || - (db->nat64_inst_id != nat64_id)) - continue; - - if (flag == CNAT_DB_CLEAR_ALL) { - nat64_reset_session_expiry(db); - continue; - } - - if (flag & CNAT_DB_CLEAR_ADDR) { - if ((db->v6_in_key.ipv6[0] != ki.ipv6[0]) || - (db->v6_in_key.ipv6[1] != ki.ipv6[1]) || - (db->v6_in_key.ipv6[2] != ki.ipv6[2]) || - (db->v6_in_key.ipv6[3] != ki.ipv6[3])){ - NAT64_STFUL_DEBUG_PRINT(3, "\n%s:%d\n", __FUNCTION__, \ - __LINE__ ); - continue; - } - } - - if (flag & CNAT_DB_CLEAR_PROTO) { - if (((db->v6_in_key.vrf & CNAT_PRO_MASK) >> CNAT_PRO_SHIFT) - != proto) { - NAT64_STFUL_DEBUG_PRINT(3, "\n%s:%d\n", __FUNCTION__, \ - __LINE__ ); - continue; - } - } - - if (flag & CNAT_DB_CLEAR_PORT) { - if (db->v6_in_key.port != port) { - NAT64_STFUL_DEBUG_PRINT(3, "\n%s:%d\n", __FUNCTION__, \ - __LINE__ ); - continue; - } - } - - NAT64_STFUL_DEBUG_PRINT(3, "\n%s:%d\n", __FUNCTION__, \ - __LINE__ ); - /* - * Delete if the db entry matches and it is not a - */ - nat64_reset_session_expiry(db); - } - } -} - -void inline cnat_clear_session_db(cnat_main_db_entry_t *db) -{ - if(PREDICT_FALSE(db->nsessions > 1)) { - u32 session_index = db->session_head_index; - cnat_session_entry_t *sdb; - do { - sdb = cnat_session_db + session_index; - if(PREDICT_FALSE(!sdb)) { - //TO DO: Debug msg? - break; - } - sdb->entry_expires = 0; - session_index = sdb->main_list.next; - } while(session_index != db->session_head_index - && db->session_head_index != EMPTY); - } - return; -} - -#ifdef CGSE_DS_LITE -extern dslite_table_entry_t dslite_table_array[]; - -void spp_api_ds_lite_clear_db_request_t_handler -(spp_api_ds_lite_clear_db_request_t *mp) -{ - u16 port, proto, flag; - u32 index; - u32 i; - cnat_main_db_entry_t *db; - cnat_user_db_entry_t *udb; - dslite_key_t ki; - dslite_table_entry_t *my_table_db_ptr; - u16 id; - u16 i_vrf; - - - id = spp_net_to_host_byte_order_16(&mp->ds_lite_id); - id = DS_LITE_CONFIG_TO_ARRAY_ID(id); - - my_table_db_ptr = &dslite_table_array[id]; - i_vrf = my_table_db_ptr->i_vrf; - - port = spp_net_to_host_byte_order_16(&mp->port_num); - proto = mp->protocol; - - ki.ipv4_key.k.vrf = i_vrf; - ki.ipv4_key.k.vrf |= ((u16)proto << CNAT_PRO_SHIFT); - - for(i =0 ; i< 4 ; i++) - ki.ipv6[i] = spp_net_to_host_byte_order_32(&mp->ip_addr[i]); - - ki.ipv4_key.k.port = port; - - flag = mp->flags; - - mp->rc = CNAT_SUCCESS; - - DSLITE_PRINTF(3, "\n dslite id = %d, port =%d" - "proto =%d, flags=0x%08X",\ - id, port, proto, flag); - - DSLITE_PRINTF(3, "\n IPv6 Addr = %08X : %08X: %08X: %08X",\ - ki.ipv6[0], ki.ipv6[1], ki.ipv6[2], ki.ipv6[3]); - - if (flag == CNAT_DB_CLEAR_SPECIFIC) { - DSLITE_PRINTF(3, "\n Clear specific NOT supported for DS Lite \n"); - return; - } - - pool_header_t *p = pool_header(cnat_main_db); - - for(index = 0; index < vec_len(cnat_main_db); index++) { - - /* check is it dslite entry, if not skip */ - - if (PREDICT_FALSE(!clib_bitmap_get(p->free_bitmap, index))) { - db = cnat_main_db + index; - - if( !(db->flags & CNAT_DB_DSLITE_FLAG) || - ((db->in2out_key.k.vrf & CNAT_VRF_MASK) != i_vrf) || - (db->flags & CNAT_DB_FLAG_STATIC_PORT)) { - continue; - } - - if (flag == CNAT_DB_CLEAR_ALL) { - - /* - * Make the entry time as very old (0), and wait - * for a timeout to auto-expire the entry. - */ - db->entry_expires = 0; - /* Handle sessions as well.. */ - cnat_clear_session_db(db); - continue; - } - - if (flag & CNAT_DB_CLEAR_ADDR) { - udb = cnat_user_db + db->user_index; - if(PREDICT_FALSE(!udb)) { - continue; - } - if ((udb->ipv6[0] != ki.ipv6[0]) || - (udb->ipv6[1] != ki.ipv6[1]) || - (udb->ipv6[2] != ki.ipv6[2]) || - (udb->ipv6[3] != ki.ipv6[3])) { - continue; - } - } - - if (flag & CNAT_DB_CLEAR_PROTO) { - if (((db->in2out_key.k.vrf & CNAT_PRO_MASK) >> CNAT_PRO_SHIFT) - != proto) { - continue; - } - } - - if (flag & CNAT_DB_CLEAR_PORT) { - if (db->in2out_key.k.port != port) { - continue; - } - } - - /* - * Mark for expiry in the next round of DB scan - */ - db->entry_expires = 0; - /* Handle sessions as well.. */ - cnat_clear_session_db(db); - } - } -} -#endif /* #ifdef CGSE_DS_LITE */ - -void spp_api_cnat_clear_db_request_t_handler -(spp_api_cnat_clear_db_request_t *mp) -{ - u16 i_vrf, port, proto, flag; - u32 ip_addr, index; - u64 a,b,c; - cnat_main_db_entry_t * db; - cnat_db_key_bucket_t ki; - -#if defined(TARGET_LINUX_UDVR) || defined(CNAT_PG) - i_vrf = mp->inside_vrf; - ip_addr = mp->ip_addr; - port = mp->port_num; - proto = mp->protocol; -#else - i_vrf = spp_net_to_host_byte_order_16(&mp->inside_vrf); - ip_addr = spp_net_to_host_byte_order_32(&mp->ip_addr); - port = spp_net_to_host_byte_order_16(&mp->port_num); - proto = spp_net_to_host_byte_order_16(&mp->protocol); -#endif - - - - ki.k.k.vrf = i_vrf; - ki.k.k.vrf |= ((u16)proto << CNAT_PRO_SHIFT); - ki.k.k.ipv4 = ip_addr; - ki.k.k.port = port; - - flag = mp->wildcard; - - mp->rc = CNAT_SUCCESS; - - if (flag == CNAT_DB_CLEAR_SPECIFIC) { - CNAT_V4_GET_HASH(ki.k.key64, - ki.bucket, - CNAT_MAIN_HASH_MASK); - index = cnat_in2out_hash[ki.bucket].next; - if (PREDICT_TRUE(index == EMPTY)) { - mp->rc = CNAT_NOT_FOUND_ANY; - return; - } - - do { - db = cnat_main_db + index; - - /* - * Delete if the db entry matches and it is not a - * STATIC port entry - */ - if ((db->in2out_key.key64 == ki.k.key64) && - !(db->flags & CNAT_DB_FLAG_STATIC_PORT) && - !(db->flags & CNAT_DB_NAT64_FLAG) && - !(db->flags & CNAT_DB_DSLITE_FLAG)) { - - /* - * Make the entry time as very old (0), and wait - * for a timeout to auto-expire the entry. - */ - db->entry_expires = 0; - /* Handle sessions as well.. */ - cnat_clear_session_db(db); - return; - } - index = db->in2out_hash.next; - } while (index != EMPTY); - - mp->rc = CNAT_NOT_FOUND_ANY; - return; - } - - pool_header_t *p = vec_header(cnat_main_db, sizeof(pool_header_t)); - - for(index = 0; index < vec_len(cnat_main_db); index++) { - - if (PREDICT_TRUE(!clib_bitmap_get(p->free_bitmap, index))) { - db = cnat_main_db + index; - - if(PREDICT_FALSE(db->flags & CNAT_DB_NAT64_FLAG)) { - continue; - } - - if(PREDICT_FALSE(db->flags & CNAT_DB_DSLITE_FLAG)) { - continue; - } - - if (flag == CNAT_DB_CLEAR_ALL) { - if (!(db->flags & CNAT_DB_FLAG_STATIC_PORT)) { - db->entry_expires = 0; - /* Handle sessions as well.. */ - cnat_clear_session_db(db); - } - continue; - } - - if (flag & CNAT_DB_CLEAR_VRF) { - if (((db->in2out_key.k.vrf & CNAT_VRF_MASK) != i_vrf)) { - continue; - } - } - - if (flag & CNAT_DB_CLEAR_ADDR) { - if ((db->in2out_key.k.ipv4 != ip_addr)) { - continue; - } - } - - if (flag & CNAT_DB_CLEAR_PROTO) { - if (((db->in2out_key.k.vrf & CNAT_PRO_MASK) >> CNAT_PRO_SHIFT) - != proto) { - continue; - } - } - - if (flag & CNAT_DB_CLEAR_PORT) { - if (db->in2out_key.k.port != port) { - continue; - } - } - - /* - * Delete if the db entry matches and it is not a - * STATIC port entry - */ - if (!(db->flags & CNAT_DB_FLAG_STATIC_PORT)) { - db->entry_expires = 0; - /* Handle sessions as well.. */ - cnat_clear_session_db(db); - } - } - } -} - -void -spp_api_cnat_generic_command_debug (cnat_generic_command_resp *mp_resp) -{ -#ifdef SHOW_DEBUG - u32 i, j; - - i = spp_net_to_host_byte_order_32(&(mp_resp->num_bytes)); - - PLATFORM_DEBUG_PRINT("\nNum_Bytes %d\n", i); - - for (j = 0; j < i; j++) { - PLATFORM_DEBUG_PRINT("0x%02X ", mp_resp->raw_data[j]); - if ((j % 16) == 15) { - PLATFORM_DEBUG_PRINT("\n"); - } - } -#endif -} - -/* - * The following commands implements command to dump the - * user-db information - * port-map information - * for a give user source IP address - * - * The format of the output is: - * Word 0: Address of udb - * Word 1: udb->translation_list_head_index - * Word 2: - * Bytes 0..1: udb->ntranslations - * Bytes 2..2: udb->icmp_msg_coung - * Bytes 3..3: udb->unused - * Word 3: udb->portmap_index - * Word 4: udb->key.k.ipv4 - * Word 5: - * Bytes 0..1: udb->key.k.port = 0 - * Bytes 2..3: udb->key.k.vrf - * Word 6: udb->user_hash - * Word 7: Address of my_pm - * Word 8: my_pm->status - * Word 9: my_pm->inuse - * Word A: my_pm->delete_time - * Word B: my_pm->ipv4_address - */ -void spp_api_cnat_generic_command_user_db_pm -(spp_api_cnat_generic_command_request_t *mp) -{ - u32 i; - cnat_db_key_bucket_t u_ki; - u16 my_vrfmap_index; - u32 *result_array; - cnat_generic_command_resp *mp_resp; - cnat_user_db_entry_t *udb; - cnat_user_db_entry_t *mp_udb; - cnat_vrfmap_t *my_vrfmap; - cnat_portmap_v2_t *pm; - cnat_portmap_v2_t *my_pm; - - /* - * Request structure is used to send the response - */ - mp_resp = (cnat_generic_command_resp *) mp; - - u_ki.k.k.vrf = spp_net_to_host_byte_order_32(&mp->params[1]); - u_ki.k.k.ipv4 = spp_net_to_host_byte_order_32(&mp->params[2]); - u_ki.k.k.port = 0; - - udb = cnat_user_db_lookup_entry(&u_ki); - - if (!udb) { - mp_resp->num_bytes = spp_host_to_net_byte_order_32(0); - goto no_udb_found; - } - - result_array = (u32 *) (&(mp_resp->raw_data[0])); - - i = 0; - result_array[i++] = spp_host_to_net_byte_order_32((u32) udb); - - mp_udb = (cnat_user_db_entry_t *) &(result_array[i]); - - /* - * Align the entry to the next 4 byte boundary - */ - i = i + ((sizeof(cnat_user_db_entry_t)+3)/4); - - /* - * Fill in the UDB information - */ - mp_udb->translation_list_head_index = - spp_host_to_net_byte_order_32(udb->translation_list_head_index); - mp_udb->ntranslations = - spp_host_to_net_byte_order_16(udb->ntranslations); - mp_udb->icmp_msg_count = udb->icmp_msg_count; - mp_udb->flags = udb->flags; - mp_udb->portmap_index = - spp_host_to_net_byte_order_32(udb->portmap_index); - mp_udb->key.k.ipv4 = - spp_host_to_net_byte_order_32(udb->key.k.ipv4); - mp_udb->key.k.port = - spp_host_to_net_byte_order_16(udb->key.k.port); - mp_udb->key.k.vrf = - spp_host_to_net_byte_order_16(udb->key.k.vrf); - mp_udb->user_hash.next = - spp_host_to_net_byte_order_32(udb->user_hash.next); - - my_vrfmap_index = vrf_map_array[u_ki.k.k.vrf]; - my_vrfmap = cnat_map_by_vrf + my_vrfmap_index; - pm = my_vrfmap->portmap_list; - my_pm = pm + udb->portmap_index; - - /* - * Fill in the port_map information - */ - result_array[i++] = spp_host_to_net_byte_order_32((u32) my_pm); - result_array[i++] = spp_host_to_net_byte_order_32(my_pm->inuse); - result_array[i++] = spp_host_to_net_byte_order_32(my_pm->delete_time); - result_array[i++] = spp_host_to_net_byte_order_32(my_pm->ipv4_address); - - mp_resp->num_bytes = spp_host_to_net_byte_order_32(i*4); - -no_udb_found: - spp_api_cnat_generic_command_debug(mp_resp); -} - -/* - * The following commands implements command to dump the - * DB usage stats for - * main-db - * user-db - * in2out hash - * out2in hash - * - * The format of the output is: - * Word 0: Main-DB - Total - * Word 1: Main-DB - Active - * Word 2: Main-DB - Free - * Word 3: User-DB - Total - * Word 4: User-DB - Active - * Word 5: User-DB - Free - * Word 6: Hash In2Out - Size - * Word 7: Hash In2Out - Used - * Word 8: Hash In2Out - Used Percentage - * Word 9: Hash Out2In - Size - * Word A: Hash Out2In - Used - * Word B: Hash Out2In - Used Percentage - */ -void spp_api_cnat_generic_command_db_summary -(spp_api_cnat_generic_command_request_t *mp) -{ - u32 count1, count2, count3; - u32 i = 0; - u32 k = 0; - cnat_generic_command_resp *mp_resp; - u32 *result_array; - - /* - * Request structure is used to send the response - */ - mp_resp = (cnat_generic_command_resp *) mp; - result_array = (u32 *) (&(mp_resp->raw_data[0])); - - /* - * Find entries free and used in main-db - */ - count1 = vec_len(cnat_main_db); - count2 = db_free_entry(cnat_main_db); - count3 = count1 - count2; - - *(result_array + i++) = spp_host_to_net_byte_order_32(count1); - *(result_array + i++) = spp_host_to_net_byte_order_32(count3); - *(result_array + i++) = spp_host_to_net_byte_order_32(count2); - - /* - * Find entries free and used in user-db - */ - count1 = vec_len(cnat_user_db); - count2 = db_free_entry(cnat_user_db); - count3 = count1 - count2; - - *(result_array + i++) = spp_host_to_net_byte_order_32(count1); - *(result_array + i++) = spp_host_to_net_byte_order_32(count3); - *(result_array + i++) = spp_host_to_net_byte_order_32(count2); - - /* - * Find entries used in in2out and out2in hash tables - * and percentage utilization. - */ - count1 = count2 = 0; - for (k = 0; k < CNAT_MAIN_HASH_SIZE; k++) { - if(cnat_in2out_hash[k].next != ~0) count1++; - if(cnat_out2in_hash[k].next != ~0) count2++; - - } - - count3 = count1*100/CNAT_MAIN_HASH_SIZE; - - *(result_array + i++) = spp_host_to_net_byte_order_32(CNAT_MAIN_HASH_SIZE); - *(result_array + i++) = spp_host_to_net_byte_order_32(count1); - *(result_array + i++) = spp_host_to_net_byte_order_32(count3); - - count3 = count2*100/CNAT_MAIN_HASH_SIZE; - - *(result_array + i++) = spp_host_to_net_byte_order_32(CNAT_MAIN_HASH_SIZE); - *(result_array + i++) = spp_host_to_net_byte_order_32(count2); - *(result_array + i++) = spp_host_to_net_byte_order_32(count3); - - mp_resp->num_bytes = spp_host_to_net_byte_order_32(i*4); - - spp_api_cnat_generic_command_debug(mp_resp); -} - -/* - * The following commands implements generic commands such as: - * - * Command 1: - * Reads num_bytes octets from a start_locn - * generic command 0 0 0 0 0 - * - * Command 2: - * Writes upto 8 octets from a start_locn - * generic command 0 0 0 0 0 - * - * Command 3: - * Dump the db summary stats - * generic command - * - * Command 4: - * Dump the user db entry - * generic command - * - * The following structures are referenced by this command: - * typedef struct _spp_api_cnat_generic_command_request { - * u16 _spp_msg_id; - * u8 rc; - * u8 core_num; - * u32 params[8]; - * } spp_api_cnat_generic_command_request_t; - * - * typedef struct { - * u16 spp_msg_id; - * u8 rc; - * u8 core; - * u32 num_bytes; - * u8 raw_data[0]; - * } cnat_generic_command_resp; - * - */ -void spp_api_cnat_generic_command_request_t_handler -(spp_api_cnat_generic_command_request_t *mp) -{ - cnat_generic_command_resp *resp_ptr; - u32 command_type, start_locn, num_bytes; - - command_type = spp_net_to_host_byte_order_32(&mp->params[0]); - resp_ptr = (cnat_generic_command_resp *) mp; - - switch (command_type) { - case CNAT_DEBUG_GENERIC_COMMAND_READ_MEM: - start_locn = spp_net_to_host_byte_order_32(&mp->params[1]); - num_bytes = spp_net_to_host_byte_order_32(&mp->params[2]); - clib_memcpy(&(resp_ptr->raw_data[0]), (u8 *) start_locn, num_bytes); - resp_ptr->num_bytes = spp_host_to_net_byte_order_32(num_bytes); - -#ifdef SHOW_DEBUG - { - u32 i; - - for (i = 0; i < num_bytes; i++) { - PLATFORM_DEBUG_PRINT("0x%02X ", resp_ptr->raw_data[i]); - if ((i % 16) == 15) { - PLATFORM_DEBUG_PRINT("\n"); - } - } - } -#endif - break; - - case CNAT_DEBUG_GENERIC_COMMAND_WRITE_MEM: - start_locn = spp_net_to_host_byte_order_32(&mp->params[1]); - num_bytes = spp_net_to_host_byte_order_32(&mp->params[2]); - - if (num_bytes > sizeof(u64)) { - mp->rc = CNAT_ERR_INVALID_MSG_SIZE; - return; - } - - clib_memcpy((u8 *) start_locn, &(mp->params[3]), num_bytes); - resp_ptr->num_bytes = 0; - break; - - case CNAT_DEBUG_GENERIC_COMMAND_DB_SUMMARY: - spp_api_cnat_generic_command_db_summary(mp); - break; - - case CNAT_DEBUG_GENERIC_COMMAND_USER_DB_PM: - spp_api_cnat_generic_command_user_db_pm(mp); - break; - - case CNAT_DEBUG_GET_CGN_DB_SUMMARY: - spp_api_cnat_get_cgn_db_summary(mp); - break; - - default: - mp->rc = CNAT_ERR_INVALID_MSG_ID; - break; - } -} - - -static int cnat_debug_init (void *notused) -{ - spp_msg_api_set_handler(SPP_API_CNAT_V4_DEBUG_DUMMY, - spp_api_cnat_v4_debug_dummy_t_handler); - - spp_msg_api_set_handler(SPP_API_CNAT_V4_DEBUG_DUMMY_MAX, - spp_api_cnat_v4_debug_dummy_max_t_handler); - - spp_msg_api_set_handler(SPP_API_CNAT_V4_DEBUG_GLOBAL, - spp_api_cnat_v4_debug_global_t_handler); - - spp_msg_api_set_handler(SPP_API_CNAT_V4_DEBUG_IN2OUT_PRIVATE_ADDR, - spp_api_cnat_v4_debug_in2out_private_addr_t_handler); - - spp_msg_api_set_handler(SPP_API_CNAT_V4_DEBUG_OUT2IN_PUBLIC_ADDR, - spp_api_cnat_v4_debug_out2in_public_addr_t_handler); - - spp_msg_api_set_handler(SPP_API_CNAT_CLEAR_DB_REQUEST, - spp_api_cnat_clear_db_request_t_handler); - - spp_msg_api_set_handler(SPP_API_CNAT_GENERIC_COMMAND_REQUEST, - spp_api_cnat_generic_command_request_t_handler); - - spp_msg_api_set_handler(SPP_API_CNAT_P2MP_DEBUG_REQUEST, - spp_api_cnat_p2mp_debug_request_t_handler); - - spp_msg_api_set_handler(SPP_API_NAT64_CLEAR_DB_REQUEST, - spp_api_nat64_clear_db_request_t_handler); - - spp_msg_api_set_handler(SPP_API_DS_LITE_CLEAR_DB_REQUEST, - spp_api_ds_lite_clear_db_request_t_handler); - - return 0; -} - -/* -************************ -* spp_api_cnat_get_cgn_db_summary -* This is for finding out the per core CPU users and utilization -************************ -*/ - -void spp_api_cnat_get_cgn_db_summary -(spp_api_cnat_generic_command_request_t *mp) -{ - u32 total_db_entries, total_free_entries, used_entries; - u32 i = 0; - cnat_generic_command_resp *mp_resp; - u32 *result_array; - - /* - * Request structure is used to send the response - */ - mp_resp = (cnat_generic_command_resp *) mp; - result_array = (u32 *) (&(mp_resp->raw_data[0])); - - /* - * Find entries free and used in main-db - */ - total_db_entries = vec_len(cnat_main_db); - total_free_entries = db_free_entry(cnat_main_db); - used_entries = total_db_entries - total_free_entries; - - *(result_array + i++) = spp_host_to_net_byte_order_32(total_db_entries); - *(result_array + i++) = spp_host_to_net_byte_order_32(used_entries); - *(result_array + i++) = spp_host_to_net_byte_order_32(total_free_entries); - - /* - * Find entries free and used in user-db - */ - total_db_entries = vec_len(cnat_user_db); - total_free_entries = db_free_entry(cnat_user_db); - used_entries = total_db_entries - total_free_entries; - - *(result_array + i++) = spp_host_to_net_byte_order_32(total_db_entries); - *(result_array + i++) = spp_host_to_net_byte_order_32(used_entries); - *(result_array + i++) = spp_host_to_net_byte_order_32(total_free_entries); - - mp_resp->num_bytes = spp_host_to_net_byte_order_32(i*sizeof(u32)); -} - -SPP_INIT_FUNCTION(cnat_debug_init); -#endif /* TOBE_PORTED */ diff --git a/plugins/vcgn-plugin/vcgn/cnat_global.c b/plugins/vcgn-plugin/vcgn/cnat_global.c deleted file mode 100644 index 71770834..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_global.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_global.c - global variables - * - * Copyright (c) 2008-2009, 2012 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. - *------------------------------------------------------------------ - */ - -/* gloable variables */ - -#include -#include -#include -#include - -#include "dslite_defs.h" -#include "tcp_header_definitions.h" -u32 cnat_current_time; -u8 nfv9_configured = 0; -/* ctx/sf alloc error counters */ -u32 null_enq_pkt; -u32 null_deq_pkt; - -u32 null_enq_ctx; -u32 null_deq_ctx; - -u32 null_enq_wqe; -u32 null_deq_wqe; - -u32 ctx_alloc_errs; -u32 sf_alloc_errs; - -u32 rcv_pkt_errs; - -/* TOBE_PORTED : Remove following once we bring DSLite */ -u32 dslite_config_debug_level = 1; -u32 dslite_data_path_debug_level = 1; -u32 dslite_defrag_debug_level = 1; -u32 dslite_debug_level = 1; - -dslite_table_entry_t *dslite_table_db_ptr; - -/* - * ipv4_decr_ttl_n_calc_csum() - * - It decrements the TTL and calculates the incremental IPv4 checksum - */ - -/* TOBE_PORTED: Following is in cnat_util.c */ -always_inline __attribute__((unused)) -void ipv4_decr_ttl_n_calc_csum(ipv4_header *ipv4) -{ - u32 checksum; - u16 old; - u16 ttl; - - ttl = ipv4->ttl; - old = clib_net_to_host_u16(ttl); - - /* Decrement TTL */ - ipv4->ttl--; - - /* Calculate incremental checksum */ - checksum = old + (~clib_net_to_host_u16(ttl) & 0xFFFF); - checksum += clib_net_to_host_u16(ipv4->checksum); - checksum = (checksum & 0xFFFF) + (checksum >> 16); - ipv4->checksum = clib_host_to_net_u32(checksum + (checksum >> 16)); -} - diff --git a/plugins/vcgn-plugin/vcgn/cnat_global.h b/plugins/vcgn-plugin/vcgn/cnat_global.h deleted file mode 100644 index 823a4797..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_global.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_global.h - global definition and variables - * to be used by non cnat files - * - * Copyright (c) 2007-2012 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef __CNAT_GLOBAL_H__ -#define __CNAT_GLOBAL_H__ - -/* gloable variables */ - -extern u8 cnat_db_init_done; -extern u32 cnat_current_time; -extern u64 in2out_drops_port_limit_exceeded; -extern u64 in2out_drops_system_limit_reached; -extern u64 in2out_drops_resource_depletion; -extern u64 no_translation_entry_drops; -extern u8 nfv9_configured; -extern u32 translation_create_count; -extern u32 translation_create_rate; - -extern u32 translation_delete_count; -extern u32 translation_delete_rate; - -extern u32 in2out_forwarding_count; -extern u32 in2out_forwarding_rate; - -extern u32 out2in_forwarding_count; -extern u32 out2in_forwarding_rate; - -extern u32 total_address_pool_allocated; - -extern u32 nat44_active_translations; - -#if 1 //DSLITE_DEF -extern u32 dslite_translation_create_rate; -extern u32 dslite_translation_delete_rate; -extern u32 dslite_translation_create_count; -extern u32 dslite_in2out_forwarding_count; -extern u32 dslite_in2out_forwarding_count; -extern u32 dslite_out2in_forwarding_rate; -#endif -/* sf/ctx allocation error collection declarations */ -#define COLLECT_FREQ_FACTOR 100 -#define NUM_SECONDS_TO_WAIT 10 -#define COUNTER_BUFFER_SIZE 25 - -extern u32 null_enq_pkt; -extern u32 null_deq_pkt; - -extern u32 null_enq_ctx; -extern u32 null_deq_ctx; - -extern u32 null_enq_wqe; -extern u32 null_deq_wqe; - -extern u32 ctx_alloc_errs; -extern u32 sf_alloc_errs; - -extern u32 rcv_pkt_errs; - -struct counter_array_t { - u32 sf_error_counter; - u32 ctx_error_counter; - u32 timestamp; -} counter_array_t; - -#define COUNTER_BUFFER_SIZE 25 -struct counter_array_t err_cnt_arr[COUNTER_BUFFER_SIZE]; - -//#define DISABLE_ICMP_THROTTLE_FOR_DEBUG_PURPOSE - -#endif /*__CNAT_GLOBAL_H__*/ diff --git a/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp.h b/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp.h deleted file mode 100644 index 664b62ac..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - *----------------------------------------------------------------------------- - * - * Filename: cnat_ipv4_icmp.h - * - * Description: common functions for icmp node - * - * Assumptions and Constraints: - * - * Copyright (c) 2000-2009, 2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *----------------------------------------------------------------------------- - */ - -#ifndef __CNAT_IPV4_ICMP_H__ -#define __CNAT_IPV4_ICMP_H__ - -#include "tcp_header_definitions.h" -#include "cnat_db.h" -#include "cnat_v4_functions.h" -#include "cnat_global.h" -#include "cnat_config.h" - -typedef struct { - icmp_v4_t *icmp; - ipv4_header *em_ip; - u16 *em_port; - u16 *em_l4_checksum; -} icmp_em_ip_info; - -extern void swap_ip_src_icmp_id(ipv4_header *ip, - icmp_v4_t *icmp, - cnat_main_db_entry_t *db, - u16 vrf); - -extern void swap_ip_dst_icmp_id(ipv4_header *ip, - icmp_v4_t *icmp, - cnat_main_db_entry_t *db, - u16 vrf); - -extern void swap_ip_src_emip_dst(ipv4_header *ip, - icmp_em_ip_info *icmp_info, - cnat_main_db_entry_t *db, u16 vrf); - -extern void swap_ip_dst_emip_src(ipv4_header *ip, - icmp_em_ip_info *icmp_info, - cnat_main_db_entry_t *db, u16 vrf); - - -#endif /* __CNAT_IPV4_ICMP_H__ */ diff --git a/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_error_inside_input.c b/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_error_inside_input.c deleted file mode 100644 index 218d7e53..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_error_inside_input.c +++ /dev/null @@ -1,476 +0,0 @@ -/* - *--------------------------------------------------------------------------- - * cnat_ipv4_icmp_error_inside_input.c - cnat_ipv4_icmp_error_inside_input node pipeline stage functions - * - * Copyright (c) 2008-2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *--------------------------------------------------------------------------- - */ - -#include -#include -#include -#include - -#include "cnat_ipv4_icmp.h" - -#define foreach_cnat_ipv4_icmp_e_inside_input_error \ -_(CNAT_V4_ICMP_E_I2O_T_PKT, "cnat v4 icmp_e i2o packet transmit") \ -_(CNAT_V4_ICMP_E_I2O_D_PKT, "cnat v4 icmp_e i2o packet drop") \ -_(CNAT_V4_ICMP_E_I2O_TTL_DROP, "cnat v4 icmp_e i2o ttl drop") - -typedef enum { -#define _(sym,str) sym, - foreach_cnat_ipv4_icmp_e_inside_input_error -#undef _ - CNAT_IPV4_ICMP_E_INSIDE_INPUT_N_ERROR, -} cnat_ipv4_icmp_e_inside_input_t; - -static char * cnat_ipv4_icmp_e_inside_input_error_strings[] = { -#define _(sym,string) string, - foreach_cnat_ipv4_icmp_e_inside_input_error -#undef _ -}; - -typedef struct { - u32 cached_next_index; - /* $$$$ add data here */ - - /* convenience variables */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; -} cnat_ipv4_icmp_e_inside_input_main_t; - -typedef enum { - CNAT_V4_ICMP_E_I2O_T, - CNAT_V4_ICMP_E_I2O_D, - CNAT_V4_ICMP_E_I2O_NEXT, -} cnat_ipv4_icmp_e_inside_input_next_t; - -cnat_ipv4_icmp_e_inside_input_main_t cnat_ipv4_icmp_e_inside_input_main; -vlib_node_registration_t cnat_ipv4_icmp_e_inside_input_node; - -#define NSTAGES 5 - -inline void swap_ip_src_emip_dst(ipv4_header *ip, - icmp_em_ip_info *icmp_info, - cnat_main_db_entry_t *db, u16 vrf) -{ - icmp_v4_t *icmp; - ipv4_header *em_ip; - u16 *em_port; - u32 old_ip; - u16 old_port; - u16 old_ip_checksum; - - /* - * declear variable - */ - CNAT_UPDATE_L3_CHECKSUM_DECLARE - CNAT_UPDATE_ICMP_ERR_CHECKSUM_DECLARE - - /* - * fix inner layer ip & l4 checksum - */ - em_ip = icmp_info->em_ip; - em_port = icmp_info->em_port; - - CNAT_UPDATE_L3_CHECKSUM(((u16)(db->in2out_key.k.ipv4)), - ((u16)(db->in2out_key.k.ipv4 >> 16)), - (clib_net_to_host_u16(em_ip->checksum)), - ((u16)(db->out2in_key.k.ipv4)), - ((u16)(db->out2in_key.k.ipv4 >> 16))) - - old_ip = clib_net_to_host_u32(em_ip->dest_addr); - old_port = clib_net_to_host_u16(*em_port); - old_ip_checksum = clib_net_to_host_u16(em_ip->checksum); - - em_ip->dest_addr = - clib_host_to_net_u32(db->out2in_key.k.ipv4); - em_ip->checksum = - clib_host_to_net_u16(new_l3_c); - *em_port = - clib_host_to_net_u16(db->out2in_key.k.port); - - /* - * fix outter layer ip & icmp checksum - */ - icmp = icmp_info->icmp; - CNAT_UPDATE_ICMP_ERR_CHECKSUM(((u16)(old_ip & 0xFFFF)), - ((u16)(old_ip >> 16)), - (old_port), - (old_ip_checksum), - (clib_net_to_host_u16(icmp->checksum)), - ((u16)(db->out2in_key.k.ipv4 & 0xffff)), - ((u16)(db->out2in_key.k.ipv4 >> 16)), - ((u16)(db->out2in_key.k.port)), - ((u16)(new_l3_c))) - - icmp->checksum = - clib_host_to_net_u16(new_icmp_c); - - old_ip = clib_net_to_host_u32(ip->src_addr); - - ip->src_addr = - clib_host_to_net_u32(db->out2in_key.k.ipv4); - - CNAT_UPDATE_L3_CHECKSUM(((u16)(old_ip & 0xFFFF)), - ((u16)(old_ip >> 16)), - (clib_net_to_host_u16(ip->checksum)), - ((u16)(db->out2in_key.k.ipv4)), - ((u16)(db->out2in_key.k.ipv4 >> 16))) - ip->checksum = - clib_host_to_net_u16(new_l3_c); - -#if 0 - if(is_static_dest_nat_enabled(vrf) == CNAT_SUCCESS) { - /* - * fix inner layer ip & l4 checksum - */ - em_snat_ip = icmp_info->em_ip; - em_snat_port = icmp_info->em_port; - - old_ip = spp_net_to_host_byte_order_32(&(em_snat_ip->src_addr)); - old_port = spp_net_to_host_byte_order_16(em_snat_port); - old_ip_checksum = spp_net_to_host_byte_order_16(&(em_snat_ip->checksum)); - direction = 0; - if(cnat_static_dest_db_get_translation(em_snat_ip->src_addr, &postmap_ip, vrf, direction) == CNAT_SUCCESS) { - old_postmap_ip = spp_net_to_host_byte_order_32(&postmap_ip); - - CNAT_UPDATE_L3_CHECKSUM(((u16)(old_ip)), - ((u16)(old_ip >> 16)), - (spp_net_to_host_byte_order_16(&(em_snat_ip->checksum))), - ((u16)(old_postmap_ip)), - ((u16)(old_postmap_ip >> 16))) - em_snat_ip->src_addr = postmap_ip; - em_snat_ip->checksum = - spp_host_to_net_byte_order_16(new_l3_c); - - /* - * fix outter layer ip & icmp checksum - */ - icmp = icmp_info->icmp; - CNAT_UPDATE_ICMP_ERR_CHECKSUM(((u16)(old_ip & 0xFFFF)), - ((u16)(old_ip >> 16)), - (old_port), - (old_ip_checksum), - (spp_net_to_host_byte_order_16(&(icmp->checksum))), - ((u16)(old_postmap_ip & 0xffff)), - ((u16)(old_postmap_ip >> 16)), - ((u16)(old_port)), - ((u16)(new_l3_c))) - - icmp->checksum = - spp_host_to_net_byte_order_16(new_icmp_c); - - } - } - - if(is_static_dest_nat_enabled(vrf) == CNAT_SUCCESS) { - direction = 0; - if(cnat_static_dest_db_get_translation(ip->dest_addr, &postmap_ip, vrf, direction) == CNAT_SUCCESS) { - - old_ip = spp_net_to_host_byte_order_32(&(ip->dest_addr)); - old_postmap_ip = spp_net_to_host_byte_order_32(&postmap_ip); - - CNAT_UPDATE_L3_CHECKSUM(((u16)(old_ip & 0xFFFF)), - ((u16)(old_ip >> 16)), - (spp_net_to_host_byte_order_16(&(ip->checksum))), - ((u16)(old_postmap_ip & 0xFFFF)), - ((u16)(old_postmap_ip >> 16))) - ip->dest_addr = postmap_ip; - - ip->checksum = - clib_host_to_net_u16(new_l3_c); - } - } -#endif /* if 0 */ - -} - -/* - * Use the generic buffer metadata + first line of packet data prefetch - * stage function from . This is usually a Good Idea. - */ -#define stage0 generic_stage0 - - -static inline void -stage1(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - u64 a, b, c; - u32 bucket; - u8 *prefetch_target; - - vlib_buffer_t * b0 = vlib_get_buffer (vm, buffer_index); - ipv4_header *ip = vlib_buffer_get_current (b0); - u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; - icmp_v4_t *icmp = (icmp_v4_t *)((u8*)ip + ipv4_hdr_len); - ipv4_header *em_ip = (ipv4_header*)((u8*)icmp + 8); /* embedded pkt's v4 hdr */ - u8 em_ip_hdr_len = (em_ip->version_hdr_len_words & 0xf) << 2; - - u64 tmp = 0; - u32 protocol = CNAT_ICMP; - - /* Check L4 header for embedded packet */ - if (em_ip->protocol == TCP_PROT) { - tcp_hdr_type *tcp = (tcp_hdr_type*)((u8 *)em_ip + em_ip_hdr_len); - vnet_buffer(b0)->vcgn_uii.key.k.port = - clib_net_to_host_u16(tcp->dest_port); - protocol = CNAT_TCP; - - } else if (em_ip->protocol == UDP_PROT) { - udp_hdr_type_t *udp = (udp_hdr_type_t *)((u8 *)em_ip + em_ip_hdr_len); - vnet_buffer(b0)->vcgn_uii.key.k.port = - clib_net_to_host_u16(udp->dest_port); - protocol = CNAT_UDP; - - } else { - icmp_v4_t *icmp = (icmp_v4_t*)((u8 *)em_ip + em_ip_hdr_len); - vnet_buffer(b0)->vcgn_uii.key.k.port = - clib_net_to_host_u16(icmp->identifier); - - if (PREDICT_FALSE((icmp->type != ICMPV4_ECHOREPLY) && - (icmp->type != ICMPV4_ECHO))) { - /* - * Try to set invalid protocol for these cases, so that - * hash lookup does not return valid main_db. This approach - * may optimize the regular cases with valid protocols - * as it avoids one more check for regular cases in stage3 - */ - protocol = CNAT_INVALID_PROTO; - } - } - - tmp = vnet_buffer(b0)->vcgn_uii.key.k.ipv4 = - clib_net_to_host_u32(em_ip->dest_addr); - - tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.port) << 32; - - PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX], - vnet_buffer(b0)->vcgn_uii.key.k.vrf, - protocol) - tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.vrf) << 48; - - CNAT_V4_GET_HASH(tmp, bucket, CNAT_MAIN_HASH_MASK) - - prefetch_target = (u8 *)(&cnat_in2out_hash[bucket]); - vnet_buffer(b0)->vcgn_uii.bucket = bucket; - - /* Prefetch the hash bucket */ - CLIB_PREFETCH(prefetch_target, CLIB_CACHE_LINE_BYTES, LOAD); -} - -#define SPP_LOG2_CACHE_LINE_BYTES 6 -#define SPP_CACHE_LINE_BYTES (1 << SPP_LOG2_CACHE_LINE_BYTES) - -static inline void -stage2(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index); - uword prefetch_target0, prefetch_target1; - u32 bucket = vnet_buffer(b0)->vcgn_uii.bucket; - - /* read the hash bucket */ - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket - = cnat_in2out_hash[bucket].next; - - if (PREDICT_TRUE(db_index != EMPTY)) { - /* - * Prefetch database keys. We save space by not cache-line - * aligning the DB entries. We don't want to waste LSU - * bandwidth prefetching stuff we won't need. - */ - prefetch_target0 = (uword)(cnat_main_db + db_index); - CLIB_PREFETCH((void*)prefetch_target0, CLIB_CACHE_LINE_BYTES, LOAD); - /* Just beyond DB key #2 */ - prefetch_target1 = prefetch_target0 + - STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports); - /* If the targets are in different lines, do the second prefetch */ - if (PREDICT_FALSE((prefetch_target0 & ~(SPP_CACHE_LINE_BYTES-1)) != - (prefetch_target1 & ~(SPP_CACHE_LINE_BYTES-1)))) { - CLIB_PREFETCH((void *)prefetch_target1, CLIB_CACHE_LINE_BYTES, LOAD); - } - } -} - -static inline void -stage3(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - cnat_main_db_entry_t *db; - vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index); - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket; - - /* - * Note: if the search already failed (empty bucket), - * the answer is already in the pipeline context structure - */ - if (PREDICT_TRUE(db_index != EMPTY)) { - - /* - * Note: hash collisions suck. We can't easily prefetch around them. - * The first trip around the track will be fast. After that, maybe - * not so much... - */ - do { - db = cnat_main_db + db_index; - if (PREDICT_TRUE(db->in2out_key.key64 == - vnet_buffer(b0)->vcgn_uii.key.key64)) { - break; - } - db_index = db->in2out_hash.next; - } while (db_index != EMPTY); - - /* Stick the answer back into the pipeline context structure */ - vnet_buffer(b0)->vcgn_uii.bucket = db_index; - } -} - - - -static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node, - u32 bi) -{ - vlib_buffer_t *b0 = vlib_get_buffer (vm, bi); - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket; - int disposition = CNAT_V4_ICMP_E_I2O_T; - int counter = CNAT_V4_ICMP_E_I2O_T_PKT; - - ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0); - u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; - icmp_v4_t *icmp = (icmp_v4_t *)((u8*)ip + ipv4_hdr_len); - ipv4_header *em_ip = (ipv4_header*)((u8*)icmp + 8); /* embedded pkt's v4 hdr */ - u8 em_ip_hdr_len = (em_ip->version_hdr_len_words & 0xf) << 2; - vlib_node_t *n = vlib_get_node (vm, cnat_ipv4_icmp_e_inside_input_node.index); - u32 node_counter_base_index = n->error_heap_index; - vlib_error_main_t * em = &vm->error_main; - cnat_main_db_entry_t *db = NULL; - icmp_em_ip_info icmp_info; - - if (PLATFORM_HANDLE_TTL_DECREMENT) { - if (PREDICT_FALSE(ip->ttl <= 1)) { - /* - * As it is ICMP error packet with TTL <= 1, - * let's drop the packet (no need to genereate - * another ICMP error). - */ - - disposition = CNAT_V4_ICMP_E_I2O_D; - counter = CNAT_V4_ICMP_E_I2O_TTL_DROP; - - goto drop_pkt; - } - } - - if (PREDICT_TRUE(db_index != EMPTY)) { - icmp_info.em_ip = em_ip; - icmp_info.icmp = icmp; - //icmp_info.em_port = vnet_buffer(b0)->vcgn_uii.key.k.port; - - /* Note: This could have been done in stage1 itself, - * but we need to introduce one u16 * in vnet_buffer_opaque_t - * Since this flow is expected to be very rare in actual - * deployment scenario, we may afford to do these steps here - * as well. Lets confirm during core review. */ - if (em_ip->protocol == TCP_PROT) { - tcp_hdr_type *tcp = (tcp_hdr_type*)((u8 *)em_ip + em_ip_hdr_len); - icmp_info.em_port = &(tcp->dest_port); - } else if (em_ip->protocol == UDP_PROT) { - udp_hdr_type_t *udp = (udp_hdr_type_t *) - ((u8 *)em_ip + em_ip_hdr_len); - icmp_info.em_port = &(udp->dest_port); - } else { - icmp_v4_t *icmp_inner = (icmp_v4_t*)((u8 *)em_ip + em_ip_hdr_len); - icmp_info.em_port = &(icmp_inner->identifier); - } - - db = cnat_main_db + db_index; - /* - * 1. update dst addr:dst port of embedded ip pkt - * update src addr of icmp pkt - * 2. fix udp/tcp/ip checksum of embedded pkt - * fix icmp, ip check of icmp pkt - * don need to update the timer - */ - - if (PREDICT_FALSE(icmp_debug_flag)) { - printf("\nDUMPING ICMP PKT BEFORE\n"); - print_icmp_pkt(ip); - } - - if (PLATFORM_HANDLE_TTL_DECREMENT) { - /* - * Decrement TTL and update IPv4 checksum - */ - ipv4_decr_ttl_n_calc_csum(ip); - } - - swap_ip_src_emip_dst(ip, &icmp_info, - db, db->in2out_key.k.vrf); - - if (PREDICT_FALSE(icmp_debug_flag)) { - printf("\nDUMPING ICMP PKT AFTER\n"); - print_icmp_pkt(ip); - } - in2out_forwarding_count++; - - } else { - disposition = CNAT_V4_ICMP_E_I2O_D; - counter = CNAT_V4_ICMP_E_I2O_D_PKT; - } - -drop_pkt: - - em->counters[node_counter_base_index + counter] += 1; - return disposition; -} - -#include - -static uword cnat_ipv4_icmp_e_inside_input_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return dispatch_pipeline (vm, node, frame); -} - - -VLIB_REGISTER_NODE (cnat_ipv4_icmp_e_inside_input_node) = { - .function = cnat_ipv4_icmp_e_inside_input_node_fn, - .name = "vcgn-v4-icmp-e-i2o", - .vector_size = sizeof (u32), - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(cnat_ipv4_icmp_e_inside_input_error_strings), - .error_strings = cnat_ipv4_icmp_e_inside_input_error_strings, - - .n_next_nodes = CNAT_V4_ICMP_E_I2O_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [CNAT_V4_ICMP_E_I2O_T] = "ip4-input", - [CNAT_V4_ICMP_E_I2O_D] = "error-drop", - }, -}; - -clib_error_t *cnat_ipv4_icmp_e_inside_input_init (vlib_main_t *vm) -{ - cnat_ipv4_icmp_e_inside_input_main_t * mp = &cnat_ipv4_icmp_e_inside_input_main; - - mp->vlib_main = vm; - mp->vnet_main = vnet_get_main(); - - return 0; -} - -VLIB_INIT_FUNCTION (cnat_ipv4_icmp_e_inside_input_init); diff --git a/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_error_outside_input.c b/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_error_outside_input.c deleted file mode 100644 index f25f4d02..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_error_outside_input.c +++ /dev/null @@ -1,452 +0,0 @@ -/* - *--------------------------------------------------------------------------- - * cnat_ipv4_icmp_error_outside_input.c - cnat_ipv4_icmp_error_outside_input node pipeline stage functions - * - * Copyright (c) 2008-2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *--------------------------------------------------------------------------- - */ - -#include -#include -#include -#include - -#include "cnat_ipv4_icmp.h" - -#define foreach_cnat_ipv4_icmp_e_outside_input_error \ -_(CNAT_V4_ICMP_E_O2I_T_PKT, "cnat v4 icmp_e o2i packet transmit") \ -_(CNAT_V4_ICMP_E_O2I_D_PKT, "cnat v4 icmp_e o2i packet drop") \ -_(CNAT_V4_ICMP_E_O2I_TTL_DROP, "cnat v4 icmp_e o2i ttl drop") - -typedef enum { -#define _(sym,str) sym, - foreach_cnat_ipv4_icmp_e_outside_input_error -#undef _ - CNAT_IPV4_ICMP_E_OUTSIDE_INPUT_N_ERROR, -} cnat_ipv4_icmp_e_outside_input_t; - -static char * cnat_ipv4_icmp_e_outside_input_error_strings[] = { -#define _(sym,string) string, - foreach_cnat_ipv4_icmp_e_outside_input_error -#undef _ -}; - -typedef struct { - u32 cached_next_index; - /* $$$$ add data here */ - - /* convenience variables */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; -} cnat_ipv4_icmp_e_outside_input_main_t; - -typedef enum { - CNAT_V4_ICMP_E_O2I_T, - CNAT_V4_ICMP_E_O2I_D, - CNAT_V4_ICMP_E_O2I_NEXT, -} cnat_ipv4_icmp_e_outside_input_next_t; - -cnat_ipv4_icmp_e_outside_input_main_t cnat_ipv4_icmp_e_outside_input_main; -vlib_node_registration_t cnat_ipv4_icmp_e_outside_input_node; - -#define NSTAGES 5 - -inline void swap_ip_dst_emip_src(ipv4_header *ip, - icmp_em_ip_info *icmp_info, - cnat_main_db_entry_t *db, u16 vrf) -{ - icmp_v4_t *icmp; - ipv4_header *em_ip; - u16 *em_port; - u32 old_ip; - u16 old_port; - u16 old_ip_checksum; - - /* - * declear variable - */ - CNAT_UPDATE_L3_CHECKSUM_DECLARE - CNAT_UPDATE_ICMP_ERR_CHECKSUM_DECLARE - - /* - * fix inner layer ip & l4 checksum - */ - em_ip = icmp_info->em_ip; - em_port = icmp_info->em_port; - - CNAT_UPDATE_L3_CHECKSUM(((u16)(db->out2in_key.k.ipv4)), - ((u16)(db->out2in_key.k.ipv4 >> 16)), - (clib_net_to_host_u16(em_ip->checksum)), - ((u16)(db->in2out_key.k.ipv4)), - ((u16)(db->in2out_key.k.ipv4 >> 16))) - - old_ip = clib_net_to_host_u32(em_ip->src_addr); - old_port = clib_net_to_host_u16(*em_port); - old_ip_checksum = clib_net_to_host_u16(em_ip->checksum); - - em_ip->src_addr = - clib_host_to_net_u32(db->in2out_key.k.ipv4); - em_ip->checksum = - clib_host_to_net_u16(new_l3_c); - *em_port = - clib_host_to_net_u16(db->in2out_key.k.port); - - /* - * fix outter layer ip & icmp checksum - */ - icmp = icmp_info->icmp; - CNAT_UPDATE_ICMP_ERR_CHECKSUM(((u16)(old_ip & 0xFFFF)), - ((u16)(old_ip >> 16)), - (old_port), - (old_ip_checksum), - (clib_net_to_host_u16(icmp->checksum)), - ((u16)(db->in2out_key.k.ipv4 & 0xffff)), - ((u16)(db->in2out_key.k.ipv4 >> 16)), - ((u16)(db->in2out_key.k.port)), - ((u16)(new_l3_c))) - - icmp->checksum = - clib_host_to_net_u16(new_icmp_c); - - old_ip = clib_net_to_host_u32(ip->dest_addr); - - ip->dest_addr = - clib_host_to_net_u32(db->in2out_key.k.ipv4); - - CNAT_UPDATE_L3_CHECKSUM(((u16)(old_ip & 0xFFFF)), - ((u16)(old_ip >> 16)), - (clib_net_to_host_u16(ip->checksum)), - ((u16)(db->in2out_key.k.ipv4)), - ((u16)(db->in2out_key.k.ipv4 >> 16))) - ip->checksum = - clib_host_to_net_u16(new_l3_c); - -#if 0 - if(is_static_dest_nat_enabled(vrf) == CNAT_SUCCESS) { - /* - * fix inner layer ip & l4 checksum - */ - em_snat_ip = icmp_info->em_ip; - em_snat_port = icmp_info->em_port; - - old_ip = spp_net_to_host_byte_order_32(&(em_snat_ip->dest_addr)); - old_port = spp_net_to_host_byte_order_16(em_snat_port); - old_ip_checksum = spp_net_to_host_byte_order_16(&(em_snat_ip->checksum)); - direction = 1; - if(cnat_static_dest_db_get_translation(em_snat_ip->dest_addr, &postmap_ip, vrf, direction) == CNAT_SUCCESS) { - old_postmap_ip = spp_net_to_host_byte_order_32(&postmap_ip); - - CNAT_UPDATE_L3_CHECKSUM(((u16)(old_ip)), - ((u16)(old_ip >> 16)), - (spp_net_to_host_byte_order_16(&(em_snat_ip->checksum))), - ((u16)(old_postmap_ip)), - ((u16)(old_postmap_ip >> 16))) - em_snat_ip->dest_addr = postmap_ip; - em_snat_ip->checksum = - spp_host_to_net_byte_order_16(new_l3_c); - - /* - * fix outter layer ip & icmp checksum - */ - icmp = icmp_info->icmp; - CNAT_UPDATE_ICMP_ERR_CHECKSUM(((u16)(old_ip & 0xFFFF)), - ((u16)(old_ip >> 16)), - (old_port), - (old_ip_checksum), - (spp_net_to_host_byte_order_16(&(icmp->checksum))), - ((u16)(old_postmap_ip & 0xffff)), - ((u16)(old_postmap_ip >> 16)), - ((u16)(old_port)), - ((u16)(new_l3_c))) - - icmp->checksum = - spp_host_to_net_byte_order_16(new_icmp_c); - - } - } - - if(is_static_dest_nat_enabled(vrf) == CNAT_SUCCESS) { - direction = 1; - if(cnat_static_dest_db_get_translation(ip->src_addr, &postmap_ip, vrf, direction) == CNAT_SUCCESS) { - CNAT_UPDATE_L3_CHECKSUM_DECLARE - - old_ip = spp_net_to_host_byte_order_32(&(ip->src_addr)); - old_postmap_ip = spp_net_to_host_byte_order_32(&postmap_ip); - - CNAT_UPDATE_L3_CHECKSUM(((u16)(old_ip & 0xFFFF)), - ((u16)(old_ip >> 16)), - (spp_net_to_host_byte_order_16(&(ip->checksum))), - ((u16)(old_postmap_ip & 0xFFFF)), - ((u16)(old_postmap_ip >> 16))) - ip->checksum = - spp_host_to_net_byte_order_16(new_l3_c); - ip->src_addr = postmap_ip; - } - } -#endif /* if 0 */ -} - -/* - * Use the generic buffer metadata + first line of packet data prefetch - * stage function from . This is usually a Good Idea. - */ -#define stage0 generic_stage0 - - -static inline void -stage1(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - u64 a, b, c; - u32 bucket; - u8 *prefetch_target; - - vlib_buffer_t * b0 = vlib_get_buffer (vm, buffer_index); - ipv4_header *ip = vlib_buffer_get_current (b0); - u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; - icmp_v4_t *icmp = (icmp_v4_t *)((u8*)ip + ipv4_hdr_len); - ipv4_header *em_ip = (ipv4_header*)((u8*)icmp + 8); /* embedded pkt's v4 hdr */ - u8 em_ip_hdr_len = (em_ip->version_hdr_len_words & 0xf) << 2; - - u64 tmp = 0; - u32 protocol = CNAT_ICMP; - - /* Check L4 header for embedded packet */ - if (em_ip->protocol == TCP_PROT) { - tcp_hdr_type *tcp = (tcp_hdr_type*)((u8 *)em_ip + em_ip_hdr_len); - vnet_buffer(b0)->vcgn_uii.key.k.port = - clib_net_to_host_u16(tcp->src_port); - protocol = CNAT_TCP; - - } else if (em_ip->protocol == UDP_PROT) { - udp_hdr_type_t *udp = (udp_hdr_type_t *)((u8 *)em_ip + em_ip_hdr_len); - vnet_buffer(b0)->vcgn_uii.key.k.port = - clib_net_to_host_u16(udp->src_port); - protocol = CNAT_UDP; - - } else { - icmp_v4_t *icmp = (icmp_v4_t*)((u8 *)em_ip + em_ip_hdr_len); - vnet_buffer(b0)->vcgn_uii.key.k.port = - clib_net_to_host_u16(icmp->identifier); - - if (PREDICT_FALSE((icmp->type != ICMPV4_ECHOREPLY) && - (icmp->type != ICMPV4_ECHO))) { - /* - * Try to set invalid protocol for these cases, so that - * hash lookup does not return valid main_db. This approach - * may optimize the regular cases with valid protocols - * as it avoids one more check for regular cases in stage3 - */ - protocol = CNAT_INVALID_PROTO; - } - } - - tmp = vnet_buffer(b0)->vcgn_uii.key.k.ipv4 = - clib_net_to_host_u32(em_ip->src_addr); - - tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.port) << 32; - - PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX], - vnet_buffer(b0)->vcgn_uii.key.k.vrf, - protocol) - tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.vrf) << 48; - - CNAT_V4_GET_HASH(tmp, bucket, CNAT_MAIN_HASH_MASK) - - prefetch_target = (u8 *)(&cnat_out2in_hash[bucket]); - vnet_buffer(b0)->vcgn_uii.bucket = bucket; - - /* Prefetch the hash bucket */ - CLIB_PREFETCH(prefetch_target, CLIB_CACHE_LINE_BYTES, LOAD); -} - - -#define SPP_LOG2_CACHE_LINE_BYTES 6 -#define SPP_CACHE_LINE_BYTES (1 << SPP_LOG2_CACHE_LINE_BYTES) - -static inline void -stage2(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index); - uword prefetch_target0, prefetch_target1; - u32 bucket = vnet_buffer(b0)->vcgn_uii.bucket; - - /* read the hash bucket */ - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket - = cnat_out2in_hash[bucket].next; - - if (PREDICT_TRUE(db_index != EMPTY)) { - /* - * Prefetch database keys. We save space by not cache-line - * aligning the DB entries. We don't want to waste LSU - * bandwidth prefetching stuff we won't need. - */ - prefetch_target0 = (uword)(cnat_main_db + db_index); - CLIB_PREFETCH((void*)prefetch_target0, CLIB_CACHE_LINE_BYTES, LOAD); - /* Just beyond DB key #2 */ - prefetch_target1 = prefetch_target0 + - STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports); - /* If the targets are in different lines, do the second prefetch */ - if (PREDICT_FALSE((prefetch_target0 & ~(SPP_CACHE_LINE_BYTES-1)) != - (prefetch_target1 & ~(SPP_CACHE_LINE_BYTES-1)))) { - CLIB_PREFETCH((void *)prefetch_target1, CLIB_CACHE_LINE_BYTES, LOAD); - } - } -} - - -static inline void -stage3(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - cnat_main_db_entry_t *db; - vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index); - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket; - - /* - * Note: if the search already failed (empty bucket), - * the answer is already in the pipeline context structure - */ - if (PREDICT_TRUE(db_index != EMPTY)) { - - /* - * Note: hash collisions suck. We can't easily prefetch around them. - * The first trip around the track will be fast. After that, maybe - * not so much... - */ - do { - db = cnat_main_db + db_index; - if (PREDICT_TRUE(db->out2in_key.key64 == - vnet_buffer(b0)->vcgn_uii.key.key64)) { - break; - } - db_index = db->out2in_hash.next; - } while (db_index != EMPTY); - - /* Stick the answer back into the pipeline context structure */ - vnet_buffer(b0)->vcgn_uii.bucket = db_index; - } -} - -static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node, - u32 bi) -{ - vlib_buffer_t *b0 = vlib_get_buffer (vm, bi); - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket; - int disposition = CNAT_V4_ICMP_E_O2I_T; - int counter = CNAT_V4_ICMP_E_O2I_T_PKT; - - ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0); - u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; - icmp_v4_t *icmp = (icmp_v4_t *)((u8*)ip + ipv4_hdr_len); - ipv4_header *em_ip = (ipv4_header*)((u8*)icmp + 8); /* embedded pkt's v4 hdr */ - u8 em_ip_hdr_len = (em_ip->version_hdr_len_words & 0xf) << 2; - vlib_node_t *n = vlib_get_node (vm, cnat_ipv4_icmp_e_outside_input_node.index); - u32 node_counter_base_index = n->error_heap_index; - vlib_error_main_t * em = &vm->error_main; - cnat_main_db_entry_t *db = NULL; - icmp_em_ip_info icmp_info; - - - if (PREDICT_TRUE(db_index != EMPTY)) { - - icmp_info.em_ip = em_ip; - icmp_info.icmp = icmp; - - /* Note: This could have been done in stage1 itself, - * but we need to introduce one u16 * in vnet_buffer_opaque_t - * Since this flow is expected to be very rare in actual - * deployment scenario, we may afford to do these steps here - * as well. Lets confirm during core review. */ - - if (em_ip->protocol == TCP_PROT) { - tcp_hdr_type *tcp = (tcp_hdr_type*)((u8 *)em_ip + em_ip_hdr_len); - icmp_info.em_port = &(tcp->src_port); - } else if (em_ip->protocol == UDP_PROT) { - udp_hdr_type_t *udp = (udp_hdr_type_t *) - ((u8 *)em_ip + em_ip_hdr_len); - icmp_info.em_port = &(udp->src_port); - } else { - icmp_v4_t *icmp_inner = (icmp_v4_t*)((u8 *)em_ip + em_ip_hdr_len); - icmp_info.em_port = &(icmp_inner->identifier); - } - - db = cnat_main_db + db_index; - - if (PREDICT_FALSE(icmp_debug_flag)) { - printf("\nDUMPING ICMP PKT BEFORE\n"); - print_icmp_pkt(ip); - } - - if (PLATFORM_HANDLE_TTL_DECREMENT) { - /* - * Decrement TTL and update IPv4 checksum - */ - ipv4_decr_ttl_n_calc_csum(ip); - } - - swap_ip_dst_emip_src(ip, &icmp_info, - db, db->in2out_key.k.vrf); - - if (PREDICT_FALSE(icmp_debug_flag)) { - printf("\nDUMPING ICMP PKT AFTER\n"); - print_icmp_pkt(ip); - } - - } else { - disposition = CNAT_V4_ICMP_E_O2I_D; - counter = CNAT_V4_ICMP_E_O2I_D_PKT; - } - - em->counters[node_counter_base_index + counter] += 1; - return disposition; -} - -#include - -static uword cnat_ipv4_icmp_e_outside_input_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return dispatch_pipeline (vm, node, frame); -} - - -VLIB_REGISTER_NODE (cnat_ipv4_icmp_e_outside_input_node) = { - .function = cnat_ipv4_icmp_e_outside_input_node_fn, - .name = "vcgn-v4-icmp-e-o2i", - .vector_size = sizeof (u32), - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(cnat_ipv4_icmp_e_outside_input_error_strings), - .error_strings = cnat_ipv4_icmp_e_outside_input_error_strings, - - .n_next_nodes = CNAT_V4_ICMP_E_O2I_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [CNAT_V4_ICMP_E_O2I_T] = "ip4-input", - [CNAT_V4_ICMP_E_O2I_D] = "error-drop", - }, -}; - -clib_error_t *cnat_ipv4_icmp_e_outside_input_init (vlib_main_t *vm) -{ - cnat_ipv4_icmp_e_outside_input_main_t * mp = &cnat_ipv4_icmp_e_outside_input_main; - - mp->vlib_main = vm; - mp->vnet_main = vnet_get_main(); - - return 0; -} - -VLIB_INIT_FUNCTION (cnat_ipv4_icmp_e_outside_input_init); diff --git a/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_inside_input.c b/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_inside_input.c deleted file mode 100644 index 1b9f0266..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_inside_input.c +++ /dev/null @@ -1,404 +0,0 @@ -/* - *--------------------------------------------------------------------------- - * cnat_ipv4_icmp_query_inside_input.c - cnat_ipv4_icmp_query_inside_input node pipeline stage functions - * - * - * Copyright (c) 2008-2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *--------------------------------------------------------------------------- - */ -#include -#include -#include -#include - -#include "cnat_ipv4_icmp.h" - -#define foreach_cnat_ipv4_icmp_q_inside_input_error \ -_(CNAT_V4_ICMP_Q_I2O_T_PKT, "cnat v4 icmp_q i2o packet transmit") \ -_(CNAT_V4_ICMP_Q_I2O_MISS_PKT, "cnat v4 icmp_q i2o db miss") \ -_(CNAT_V4_ICMP_Q_I2O_TTL_GEN, "cnat v4 icmp_q i2o ttl generate") \ -_(CNAT_V4_ICMP_Q_I2O_TTL_DROP, "cnat v4 icmp_q i2o ttl drop") \ -_(CNAT_V4_ICMP_Q_I2O_NO_SESSION_DROP, "cnat v4 icmp_q i2o no session drop") - -typedef enum { -#define _(sym,str) sym, - foreach_cnat_ipv4_icmp_q_inside_input_error -#undef _ - CNAT_IPV4_ICMP_Q_INSIDE_INPUT_N_ERROR, -} cnat_ipv4_icmp_q_inside_input_t; - -static char * cnat_ipv4_icmp_q_inside_input_error_strings[] = { -#define _(sym,string) string, - foreach_cnat_ipv4_icmp_q_inside_input_error -#undef _ -}; - -typedef struct { - u32 cached_next_index; - /* $$$$ add data here */ - - /* convenience variables */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; -} cnat_ipv4_icmp_q_inside_input_main_t; - -typedef enum { - CNAT_V4_ICMP_Q_I2O_T, - CNAT_V4_ICMP_Q_I2O_E, - CNAT_V4_ICMP_Q_I2O_D, - CNAT_V4_ICMP_Q_I2O_NEXT, -} cnat_ipv4_icmp_q_inside_input_next_t; - -cnat_ipv4_icmp_q_inside_input_main_t cnat_ipv4_icmp_q_inside_input_main; -vlib_node_registration_t cnat_ipv4_icmp_q_inside_input_node; - -#define NSTAGES 5 - -inline void swap_ip_src_icmp_id(ipv4_header *ip, - icmp_v4_t *icmp, - cnat_main_db_entry_t *db, u16 vrf) -{ -#if 0 - u32 postmap_ip; - u8 direction; - u32 old_ip; - u32 old_postmap_ip; - - - if(is_static_dest_nat_enabled(vrf) == CNAT_SUCCESS) { - direction = 0; - if(cnat_static_dest_db_get_translation(ip->dest_addr, &postmap_ip, vrf, direction) == CNAT_SUCCESS) { - CNAT_UPDATE_L3_CHECKSUM_DECLARE - - old_ip = spp_net_to_host_byte_order_32(&(ip->dest_addr)); - old_postmap_ip = spp_net_to_host_byte_order_32(&postmap_ip); - - CNAT_UPDATE_L3_CHECKSUM(((u16)(old_ip & 0xFFFF)), - ((u16)(old_ip >> 16)), - (spp_net_to_host_byte_order_16(&(ip->checksum))), - ((u16)(old_postmap_ip & 0xFFFF)), - ((u16)(old_postmap_ip >> 16))) - ip->dest_addr = postmap_ip; - - ip->checksum = - spp_host_to_net_byte_order_16(new_l3_c); - } - } -#endif /* if 0 */ - /* - * declare variable - */ - CNAT_UPDATE_L3_L4_CHECKSUM_DECLARE - /* - * calculate checksum - */ - CNAT_UPDATE_L3_ICMP_CHECKSUM(((u16)(db->in2out_key.k.ipv4)), - ((u16)(db->in2out_key.k.ipv4 >> 16)), - (db->in2out_key.k.port), - (clib_net_to_host_u16(ip->checksum)), - (clib_net_to_host_u16(icmp->checksum)), - ((u16)(db->out2in_key.k.ipv4)), - ((u16)(db->out2in_key.k.ipv4 >> 16)), - (db->out2in_key.k.port)) - //set ip header - ip->src_addr = - clib_host_to_net_u32(db->out2in_key.k.ipv4); - ip->checksum = - clib_host_to_net_u16(new_l3_c); - - //set icmp header - icmp->identifier = - clib_host_to_net_u16(db->out2in_key.k.port); - icmp->checksum = - clib_host_to_net_u16(new_l4_c); -} - -/* - * Use the generic buffer metadata + first line of packet data prefetch - * stage function from . This is usually a Good Idea. - */ -#define stage0 generic_stage0 - -static inline void -stage1(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - u64 a, b, c; - u32 bucket; - u8 *prefetch_target; - - vlib_buffer_t * b0 = vlib_get_buffer (vm, buffer_index); - ipv4_header *ip = vlib_buffer_get_current (b0); - u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; - icmp_v4_t *icmp = (icmp_v4_t *)((u8*)ip + ipv4_hdr_len); - - u64 tmp = 0; - tmp = vnet_buffer(b0)->vcgn_uii.key.k.ipv4 = - clib_net_to_host_u32(ip->src_addr); - vnet_buffer(b0)->vcgn_uii.key.k.port = - clib_net_to_host_u16 (icmp->identifier); - - tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.port) << 32; - - PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX], - vnet_buffer(b0)->vcgn_uii.key.k.vrf, - CNAT_ICMP) - tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.vrf) << 48; - - CNAT_V4_GET_HASH(tmp, bucket, CNAT_MAIN_HASH_MASK) - - prefetch_target = (u8 *)(&cnat_in2out_hash[bucket]); - vnet_buffer(b0)->vcgn_uii.bucket = bucket; - - /* Prefetch the hash bucket */ - CLIB_PREFETCH(prefetch_target, CLIB_CACHE_LINE_BYTES, LOAD); -} - -#define SPP_LOG2_CACHE_LINE_BYTES 6 -#define SPP_CACHE_LINE_BYTES (1 << SPP_LOG2_CACHE_LINE_BYTES) - -static inline void -stage2(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index); - uword prefetch_target0, prefetch_target1; - u32 bucket = vnet_buffer(b0)->vcgn_uii.bucket; - - /* read the hash bucket */ - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket - = cnat_in2out_hash[bucket].next; - - if (PREDICT_TRUE(db_index != EMPTY)) { - /* - * Prefetch database keys. We save space by not cache-line - * aligning the DB entries. We don't want to waste LSU - * bandwidth prefetching stuff we won't need. - */ - prefetch_target0 = (uword)(cnat_main_db + db_index); - CLIB_PREFETCH((void*)prefetch_target0, CLIB_CACHE_LINE_BYTES, LOAD); - /* Just beyond DB key #2 */ - prefetch_target1 = prefetch_target0 + - STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports); - /* If the targets are in different lines, do the second prefetch */ - if (PREDICT_FALSE((prefetch_target0 & ~(SPP_CACHE_LINE_BYTES-1)) != - (prefetch_target1 & ~(SPP_CACHE_LINE_BYTES-1)))) { - CLIB_PREFETCH((void *)prefetch_target1, CLIB_CACHE_LINE_BYTES, LOAD); - } - } -} - -static inline void -stage3(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - cnat_main_db_entry_t *db; - vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index); - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket; - - /* - * Note: if the search already failed (empty bucket), - * the answer is already in the pipeline context structure - */ - if (PREDICT_TRUE(db_index != EMPTY)) { - - /* - * Note: hash collisions suck. We can't easily prefetch around them. - * The first trip around the track will be fast. After that, maybe - * not so much... - */ - do { - db = cnat_main_db + db_index; - if (PREDICT_TRUE(db->in2out_key.key64 == - vnet_buffer(b0)->vcgn_uii.key.key64)) { - break; - } - db_index = db->in2out_hash.next; - } while (db_index != EMPTY); - - /* Stick the answer back into the pipeline context structure */ - vnet_buffer(b0)->vcgn_uii.bucket = db_index; - } -} - -static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node, - u32 bi) -{ - vlib_buffer_t *b0 = vlib_get_buffer (vm, bi); - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket; - spp_ctx_t *ctx = (spp_ctx_t *) &vnet_buffer(b0)->vcgn_uii; - int disposition = CNAT_V4_ICMP_Q_I2O_T; - int counter = CNAT_V4_ICMP_Q_I2O_T_PKT; - - ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0); - u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; - icmp_v4_t *icmp = (icmp_v4_t *)((u8*)ip + ipv4_hdr_len); - vlib_node_t *n = vlib_get_node (vm, cnat_ipv4_icmp_q_inside_input_node.index); - u32 node_counter_base_index = n->error_heap_index; - vlib_error_main_t * em = &vm->error_main; - cnat_session_entry_t *session_db = NULL; - cnat_main_db_entry_t *db = NULL; - cnat_key_t dest_info; - - if (PLATFORM_HANDLE_TTL_DECREMENT) { - if (PREDICT_FALSE(ip->ttl <= 1)) { - /* Try to generate ICMP error msg, as TTL is <= 1 */ - - if (icmpv4_generate_with_throttling - (ctx, ip, ctx->ru.rx.uidb_index)) { - - /* Generated ICMP */ - disposition = CNAT_V4_ICMP_Q_I2O_T; - counter = CNAT_V4_ICMP_Q_I2O_TTL_GEN; - } else { - /* Could not generated ICMP - drop the packet */ - disposition = CNAT_V4_ICMP_Q_I2O_D; - counter = CNAT_V4_ICMP_Q_I2O_TTL_DROP; - } - goto drop_pkt; - } - } - - if (PREDICT_TRUE(db_index != EMPTY)) { - db = cnat_main_db + db_index; - dest_info.k.port = 0; - dest_info.k.ipv4 = clib_net_to_host_u32(ip->dest_addr); - - if(PREDICT_TRUE(!PLATFORM_DBL_SUPPORT)) { - - /* No DBL support, so just update the destn and proceed */ - db->dst_ipv4 = dest_info.k.ipv4; - db->dst_port = dest_info.k.port; - goto update_pkt; - } - - if(PREDICT_FALSE(db->dst_ipv4 != dest_info.k.ipv4)) { - if(PREDICT_TRUE(db->nsessions == 1)) { - /* Handle one to 2 dest scenarion */ - dest_info.k.vrf = db->in2out_key.k.vrf; - session_db = cnat_handle_1to2_session(db, &dest_info); - - if(PREDICT_FALSE(session_db == NULL)) { - disposition = CNAT_V4_ICMP_Q_I2O_D; - counter = CNAT_V4_ICMP_Q_I2O_NO_SESSION_DROP; - goto drop_pkt; - } - } else if (PREDICT_FALSE(db->nsessions == 0)) { - /* Should be a static entry - * Note this session as the first session and log - */ - cnat_add_dest_n_log(db, &dest_info); - } else { /* Many translations exist already */ - dest_info.k.vrf = db->in2out_key.k.vrf; - /* If session already exists, - * cnat_create_session_db_entry will return the existing db - * else create a new db - * If could not create, return NULL - */ - session_db = cnat_create_session_db_entry(&dest_info, - db, TRUE); - - if(PREDICT_FALSE(session_db == NULL)) { - disposition = CNAT_V4_ICMP_Q_I2O_D; - counter = CNAT_V4_ICMP_Q_I2O_NO_SESSION_DROP; - goto drop_pkt; - } - } - } - -update_pkt: - - if (PREDICT_FALSE(icmp_debug_flag)) { - printf("\nDUMPING ICMP PKT BEFORE\n"); - print_icmp_pkt(ip); - } - - if (PLATFORM_HANDLE_TTL_DECREMENT) { - /* - * Decrement TTL and update IPv4 checksum - */ - ipv4_decr_ttl_n_calc_csum(ip); - } - - /* - * 1. update src ipv4 addr and src icmp identifier - * 2. update ipv4 checksum and icmp checksum - */ - swap_ip_src_icmp_id(ip, icmp, db, db->in2out_key.k.vrf); - - if (PREDICT_FALSE(icmp_debug_flag)) { - printf("\nDUMPING ICMP PKT AFTER\n"); - print_icmp_pkt(ip); - } - - /* - * update db counter, timer - */ - - if(PREDICT_FALSE(session_db != 0)) { - CNAT_DB_TIMEOUT_RST(session_db); - } else { - CNAT_DB_TIMEOUT_RST(db); - } - db->in2out_pkts++; - in2out_forwarding_count++; - - } else { - disposition = CNAT_V4_ICMP_Q_I2O_E; - counter = CNAT_V4_ICMP_Q_I2O_MISS_PKT; - } - -drop_pkt: - - em->counters[node_counter_base_index + counter] += 1; - return disposition; -} - -#include - -static uword cnat_ipv4_icmp_q_inside_input_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return dispatch_pipeline (vm, node, frame); -} - - -VLIB_REGISTER_NODE (cnat_ipv4_icmp_q_inside_input_node) = { - .function = cnat_ipv4_icmp_q_inside_input_node_fn, - .name = "vcgn-v4-icmp-q-i2o", - .vector_size = sizeof (u32), - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(cnat_ipv4_icmp_q_inside_input_error_strings), - .error_strings = cnat_ipv4_icmp_q_inside_input_error_strings, - - .n_next_nodes = CNAT_V4_ICMP_Q_I2O_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [CNAT_V4_ICMP_Q_I2O_E] = "vcgn-v4-icmp-q-i2o-e", - [CNAT_V4_ICMP_Q_I2O_T] = "ip4-input", - [CNAT_V4_ICMP_Q_I2O_D] = "error-drop", - }, -}; - -clib_error_t *cnat_ipv4_icmp_q_inside_input_init (vlib_main_t *vm) -{ - cnat_ipv4_icmp_q_inside_input_main_t * mp = &cnat_ipv4_icmp_q_inside_input_main; - - mp->vlib_main = vm; - mp->vnet_main = vnet_get_main(); - - return 0; -} - -VLIB_INIT_FUNCTION (cnat_ipv4_icmp_q_inside_input_init); diff --git a/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_inside_input_exception.c b/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_inside_input_exception.c deleted file mode 100644 index 9b5e280e..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_inside_input_exception.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - *--------------------------------------------------------------------------- - * cnat_ipv4_icmp_query_inside_input_exception.c - cnat_ipv4_icmp_query_inside_input_exception node pipeline stage functions - * - * Copyright (c) 2008-2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *--------------------------------------------------------------------------- - */ - -#include -#include -#include -#include - -#include "cnat_ipv4_icmp.h" - -#define foreach_cnat_ipv4_icmp_q_inside_input_exc_error \ -_(CNAT_V4_ICMP_Q_I2O_E_T_PKT, "v4 icmp query i2o-e transmit") \ -_(CNAT_V4_ICMP_Q_I2O_E_G_PKT, "v4 icmp query i2o-e gen icmp msg") \ -_(CNAT_V4_ICMP_Q_I2O_E_D_PKT, "v4 icmp query i2o-e pkt drop") \ -_(CNAT_V4_ICMP_Q_I2O_E_DC_PKT, "v4 icmp query i2o-e drop (no config)") \ -_(CNAT_V4_ICMP_Q_I2O_E_DR_PKT, "v4 icmp query i2o-e drop (not in run state)") \ -_(CNAT_V4_ICMP_Q_I2O_E_DD_PKT, "v4 icmp query i2o-e drop (no direct port)") \ -_(CNAT_V4_ICMP_Q_I2O_E_DA_PKT, "v4 icmp query i2o-e drop (no any port)") \ -_(CNAT_V4_ICMP_Q_I2O_E_DO_PKT, "v4 icmp query i2o-e drop (out of port limit)") \ -_(CNAT_V4_ICMP_Q_I2O_E_DS_PKT, "v4 icmp query i2o_e drop (out of session db)") - -typedef enum { -#define _(sym,str) sym, - foreach_cnat_ipv4_icmp_q_inside_input_exc_error -#undef _ - CNAT_IPV4_ICMP_Q_INSIDE_INPUT_EXCEPTIONS_N_ERROR, -} cnat_ipv4_icmp_q_inside_input_exc_error_t; - - -static char * cnat_ipv4_icmp_q_inside_input_exc_error_strings[] = { -#define _(sym,string) string, - foreach_cnat_ipv4_icmp_q_inside_input_exc_error -#undef _ -}; - -typedef struct { - u32 cached_next_index; - /* $$$$ add data here */ - - /* convenience variables */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; -} cnat_ipv4_icmp_q_inside_input_exc_main_t; - -typedef enum { - CNAT_V4_ICMP_Q_E_I2O_T, - //CNAT_V4_ICMP_Q_E_I2O_GEN, - CNAT_V4_ICMP_Q_E_I2O_D, - CNAT_V4_ICMP_Q_E_I2O_NEXT, -} cnat_ipv4_icmp_q_inside_input_exc_next_t; - -#define CNAT_V4_ICMP_Q_E_I2O_GEN CNAT_V4_ICMP_Q_E_I2O_T - -cnat_ipv4_icmp_q_inside_input_exc_main_t cnat_ipv4_icmp_q_inside_input_exc_main; -vlib_node_registration_t cnat_ipv4_icmp_q_inside_input_exc_node; - -#define NSTAGES 2 - -/* - * Use the generic buffer metadata + first line of packet data prefetch - * stage function from . This is usually a Good Idea. - */ -#define stage0 generic_stage0 - -static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node, - u32 bi) -{ - vlib_buffer_t *b0 = vlib_get_buffer (vm, bi); - int disposition = CNAT_V4_ICMP_Q_E_I2O_T; - int counter = CNAT_V4_ICMP_Q_I2O_E_T_PKT; - - ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0); - u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; - icmp_v4_t *icmp = (icmp_v4_t *)((u8*)ip + ipv4_hdr_len); - vlib_node_t *n = vlib_get_node (vm, cnat_ipv4_icmp_q_inside_input_exc_node.index); - u32 node_counter_base_index = n->error_heap_index; - vlib_error_main_t * em = &vm->error_main; - - cnat_key_t dest_info; - cnat_gen_icmp_info info; - cnat_db_key_bucket_t ki; - cnat_main_db_entry_t *db = NULL; - - PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX], - ki.k.k.vrf, CNAT_ICMP) - - ki.k.k.ipv4 = - clib_net_to_host_u32(ip->src_addr); - ki.k.k.port = - clib_net_to_host_u16(icmp->identifier); - - dest_info.k.port = 0; - dest_info.k.ipv4 = clib_net_to_host_u32(ip->dest_addr); - PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX], - dest_info.k.vrf, CNAT_ICMP) - - db = cnat_get_main_db_entry_v2(&ki, PORT_SINGLE, PORT_TYPE_DYNAMIC, - &info, &dest_info); - if (PREDICT_TRUE(db != 0)) { - - if (PREDICT_FALSE(icmp_debug_flag)) { - printf("\nDUMPING ICMP PKT BEFORE\n"); - print_icmp_pkt(ip); - } - - if (PLATFORM_HANDLE_TTL_DECREMENT) { - /* - * Decrement TTL and update IPv4 checksum - */ - ipv4_decr_ttl_n_calc_csum(ip); - } - - /* - * step 6 do nat before fwd pkt - */ - swap_ip_src_icmp_id(ip, icmp, db, db->in2out_key.k.vrf); - - if (PREDICT_FALSE(icmp_debug_flag)) { - printf("\nDUMPING ICMP PKT AFTER\n"); - print_icmp_pkt(ip); - } - - /* - * update db for this pkt - */ - CNAT_DB_UPDATE_IN2OUT_TIMER - in2out_forwarding_count++; - - } else { - switch (info.error) { - case (CNAT_NO_VRF_RUN): - counter = CNAT_V4_ICMP_Q_I2O_E_DR_PKT; - break; - case (CNAT_OUT_LIMIT): - counter = CNAT_V4_ICMP_Q_I2O_E_DO_PKT; - break; - case (CNAT_NO_PORT_ANY): - case (CNAT_NO_POOL_ANY): - case (CNAT_BAD_INUSE_ANY): - case (CNAT_NOT_FOUND_ANY): - counter = CNAT_V4_ICMP_Q_I2O_E_DA_PKT; - break; - case (CNAT_INV_PORT_DIRECT): - case (CNAT_DEL_PORT_DIRECT): - case (CNAT_BAD_INUSE_DIRECT): - case (CNAT_NOT_FOUND_DIRECT): - counter = CNAT_V4_ICMP_Q_I2O_E_DD_PKT; - break; - case (CNAT_ERR_NO_SESSION_DB): - counter = CNAT_V4_ICMP_Q_I2O_E_DS_PKT; - break; - default: - counter = CNAT_V4_ICMP_Q_I2O_E_DC_PKT; - break; - } - /* - * send to icmp msg generate node - */ - if (info.gen_icmp_msg == CNAT_ICMP_MSG) { - #if 0 - u32 *fd = (u32*)ctx->feature_data; - fd[0] = info.svi_addr; - fd[1] = CNAT_ICMP_DEST_UNREACHABLE; - #endif - disposition = CNAT_V4_ICMP_Q_E_I2O_GEN; - counter = CNAT_V4_ICMP_Q_I2O_E_G_PKT; - } else { - disposition = CNAT_V4_ICMP_Q_E_I2O_D; - counter = CNAT_V4_ICMP_Q_I2O_E_D_PKT; - } - DEBUG_I2O_DROP(CNAT_DEBUG_DROP_ICMP) - } - - em->counters[node_counter_base_index + counter] += 1; - - return disposition; -} - -#include - -static uword cnat_ipv4_icmp_q_inside_input_exc_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return dispatch_pipeline (vm, node, frame); -} - -VLIB_REGISTER_NODE (cnat_ipv4_icmp_q_inside_input_exc_node) = { - .function = cnat_ipv4_icmp_q_inside_input_exc_node_fn, - .name = "vcgn-v4-icmp-q-i2o-e", - .vector_size = sizeof (u32), - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(cnat_ipv4_icmp_q_inside_input_exc_error_strings), - .error_strings = cnat_ipv4_icmp_q_inside_input_exc_error_strings, - - .n_next_nodes = CNAT_V4_ICMP_Q_E_I2O_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - //[CNAT_V4_ICMP_Q_E_I2O_GEN] = "icmp_msg_gen", /* Currently it will go - //to ip4-input node. We have to port icmp msg generator node */ - [CNAT_V4_ICMP_Q_E_I2O_T] = "ip4-input", - [CNAT_V4_ICMP_Q_E_I2O_D] = "error-drop", - }, -}; - - -clib_error_t *cnat_ipv4_icmp_q_inside_input_exc_init (vlib_main_t *vm) -{ - cnat_ipv4_icmp_q_inside_input_exc_main_t * mp = &cnat_ipv4_icmp_q_inside_input_exc_main; - - mp->vlib_main = vm; - mp->vnet_main = vnet_get_main(); - - return 0; -} - -VLIB_INIT_FUNCTION (cnat_ipv4_icmp_q_inside_input_exc_init); diff --git a/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_outside_input.c b/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_outside_input.c deleted file mode 100644 index 2c05e0b4..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_outside_input.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - *--------------------------------------------------------------------------- - * cnat_ipv4_icmp_query_outside_input.c - cnat_ipv4_icmp_query_outside_input node pipeline stage functions - * - * - * Copyright (c) 2008-2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *--------------------------------------------------------------------------- - */ -#include -#include -#include -#include - -#include "cnat_ipv4_icmp.h" - -#define foreach_cnat_ipv4_icmp_q_outside_input_error \ -_(CNAT_V4_ICMP_Q_O2I_T_PKT, "cnat v4 icmp_q o2i packet transmit") \ -_(CNAT_V4_ICMP_Q_O2I_MISS_PKT, "cnat v4 icmp_q o2i drop") \ -_(CNAT_V4_ICMP_Q_O2I_TTL_GEN, "cnat v4 icmp_q o2i ttl generate") \ -_(CNAT_V4_ICMP_Q_O2I_TTL_DROP, "cnat v4 icmp_q o2i ttl drop") \ -_(CNAT_V4_ICMP_Q_O2I_NO_SESSION_DROP, "cnat v4 icmp_q o2i no session drop") - -typedef enum { -#define _(sym,str) sym, - foreach_cnat_ipv4_icmp_q_outside_input_error -#undef _ - CNAT_IPV4_ICMP_Q_OUTSIDE_INPUT_N_ERROR, -} cnat_ipv4_icmp_q_outside_input_t; - -static char * cnat_ipv4_icmp_q_outside_input_error_strings[] = { -#define _(sym,string) string, - foreach_cnat_ipv4_icmp_q_outside_input_error -#undef _ -}; - -typedef struct { - u32 cached_next_index; - /* $$$$ add data here */ - - /* convenience variables */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; -} cnat_ipv4_icmp_q_outside_input_main_t; - -typedef enum { - CNAT_V4_ICMP_Q_O2I_T, - CNAT_V4_ICMP_Q_O2I_D, - CNAT_V4_ICMP_Q_O2I_NEXT, -} cnat_ipv4_icmp_q_outside_input_next_t; - -cnat_ipv4_icmp_q_outside_input_main_t cnat_ipv4_icmp_q_outside_input_main; -vlib_node_registration_t cnat_ipv4_icmp_q_outside_input_node; - -#define NSTAGES 5 - -inline void swap_ip_dst_icmp_id(ipv4_header *ip, - icmp_v4_t *icmp, - cnat_main_db_entry_t *db, u16 vrf) -{ -#if 0 - u32 postmap_ip; - u8 direction; - u32 old_ip; - u32 old_postmap_ip; - - if(is_static_dest_nat_enabled(vrf) == CNAT_SUCCESS) { - direction = 1; - if(cnat_static_dest_db_get_translation(ip->src_addr, &postmap_ip, vrf, direction) == CNAT_SUCCESS) { - CNAT_UPDATE_L3_CHECKSUM_DECLARE - - old_ip = spp_net_to_host_byte_order_32(&(ip->src_addr)); - old_postmap_ip = spp_net_to_host_byte_order_32(&postmap_ip); - - CNAT_UPDATE_L3_CHECKSUM(((u16)(old_ip & 0xFFFF)), - ((u16)(old_ip >> 16)), - (spp_net_to_host_byte_order_16(&(ip->checksum))), - ((u16)(old_postmap_ip & 0xFFFF)), - ((u16)(old_postmap_ip >> 16))) - ip->checksum = - spp_host_to_net_byte_order_16(new_l3_c); - ip->src_addr = postmap_ip; - } - } -#endif /* if 0 */ - /* - * declare variable - */ - CNAT_UPDATE_L3_L4_CHECKSUM_DECLARE - /* - * calculate checksum - */ - CNAT_UPDATE_L3_ICMP_CHECKSUM(((u16)(db->out2in_key.k.ipv4)), - ((u16)(db->out2in_key.k.ipv4 >> 16)), - (db->out2in_key.k.port), - (clib_net_to_host_u16(ip->checksum)), - (clib_net_to_host_u16(icmp->checksum)), - ((u16)(db->in2out_key.k.ipv4)), - ((u16)(db->in2out_key.k.ipv4 >> 16)), - (db->in2out_key.k.port)) - //set ip header - ip->dest_addr = - clib_host_to_net_u32(db->in2out_key.k.ipv4); - ip->checksum = - clib_host_to_net_u16(new_l3_c); - - //set icmp header - icmp->identifier = - clib_host_to_net_u16(db->in2out_key.k.port); - icmp->checksum = - clib_host_to_net_u16(new_l4_c); -} - -/* - * Use the generic buffer metadata + first line of packet data prefetch - * stage function from . This is usually a Good Idea. - */ -#define stage0 generic_stage0 - -static inline void -stage1(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - u64 a, b, c; - u32 bucket; - u8 *prefetch_target; - - vlib_buffer_t * b0 = vlib_get_buffer (vm, buffer_index); - ipv4_header *ip = vlib_buffer_get_current (b0); - u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; - icmp_v4_t *icmp = (icmp_v4_t *)((u8*)ip + ipv4_hdr_len); - - u64 tmp = 0; - tmp = vnet_buffer(b0)->vcgn_uii.key.k.ipv4 = - clib_net_to_host_u32(ip->dest_addr); - vnet_buffer(b0)->vcgn_uii.key.k.port = - clib_net_to_host_u16 (icmp->identifier); - - tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.port) << 32; - - PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX], - vnet_buffer(b0)->vcgn_uii.key.k.vrf, - CNAT_ICMP) - tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.vrf) << 48; - - CNAT_V4_GET_HASH(tmp, bucket, CNAT_MAIN_HASH_MASK) - - prefetch_target = (u8 *)(&cnat_out2in_hash[bucket]); - vnet_buffer(b0)->vcgn_uii.bucket = bucket; - - /* Prefetch the hash bucket */ - CLIB_PREFETCH(prefetch_target, CLIB_CACHE_LINE_BYTES, LOAD); -} - -#define SPP_LOG2_CACHE_LINE_BYTES 6 -#define SPP_CACHE_LINE_BYTES (1 << SPP_LOG2_CACHE_LINE_BYTES) - -static inline void -stage2(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index); - uword prefetch_target0, prefetch_target1; - u32 bucket = vnet_buffer(b0)->vcgn_uii.bucket; - - /* read the hash bucket */ - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket - = cnat_out2in_hash[bucket].next; - - if (PREDICT_TRUE(db_index != EMPTY)) { - /* - * Prefetch database keys. We save space by not cache-line - * aligning the DB entries. We don't want to waste LSU - * bandwidth prefetching stuff we won't need. - */ - prefetch_target0 = (uword)(cnat_main_db + db_index); - CLIB_PREFETCH((void*)prefetch_target0, CLIB_CACHE_LINE_BYTES, LOAD); - /* Just beyond DB key #2 */ - prefetch_target1 = prefetch_target0 + - STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports); - /* If the targets are in different lines, do the second prefetch */ - if (PREDICT_FALSE((prefetch_target0 & ~(SPP_CACHE_LINE_BYTES-1)) != - (prefetch_target1 & ~(SPP_CACHE_LINE_BYTES-1)))) { - CLIB_PREFETCH((void *)prefetch_target1, CLIB_CACHE_LINE_BYTES, LOAD); - } - } -} - -static inline void -stage3(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - cnat_main_db_entry_t *db; - vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index); - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket; - - /* - * Note: if the search already failed (empty bucket), - * the answer is already in the pipeline context structure - */ - if (PREDICT_TRUE(db_index != EMPTY)) { - - /* - * Note: hash collisions suck. We can't easily prefetch around them. - * The first trip around the track will be fast. After that, maybe - * not so much... - */ - do { - db = cnat_main_db + db_index; - if (PREDICT_TRUE(db->out2in_key.key64 == - vnet_buffer(b0)->vcgn_uii.key.key64)) { - break; - } - db_index = db->out2in_hash.next; - } while (db_index != EMPTY); - - /* Stick the answer back into the pipeline context structure */ - vnet_buffer(b0)->vcgn_uii.bucket = db_index; - } -} - - -static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node, - u32 bi) -{ - - vlib_buffer_t *b0 = vlib_get_buffer (vm, bi); - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket; - int disposition = CNAT_V4_ICMP_Q_O2I_T; - int counter = CNAT_V4_ICMP_Q_O2I_T_PKT; - - ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0); - u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; - icmp_v4_t *icmp = (icmp_v4_t *)((u8*)ip + ipv4_hdr_len); - vlib_node_t *n = vlib_get_node (vm, cnat_ipv4_icmp_q_outside_input_node.index); - u32 node_counter_base_index = n->error_heap_index; - vlib_error_main_t * em = &vm->error_main; - cnat_session_entry_t *session_db = NULL; - cnat_main_db_entry_t *db = NULL; - cnat_key_t dest_info; - cnat_vrfmap_t * vrf_map_p __attribute__((unused)) = NULL; - u32 vrf_index __attribute__((unused)) = 0; - - if (PREDICT_TRUE(db_index != EMPTY)) { - - db = cnat_main_db + db_index; - dest_info.k.port = 0; - dest_info.k.ipv4 = clib_net_to_host_u32(ip->src_addr); - - if (PREDICT_FALSE(icmp_debug_flag)) { - printf("\nDUMPING ICMP PKT BEFORE\n"); - print_icmp_pkt(ip); - } - - vrf_map_p = cnat_map_by_vrf + db->vrfmap_index; - vrf_index = (db->in2out_key.k.vrf & CNAT_VRF_MASK); - - if(PREDICT_TRUE(!PLATFORM_DBL_SUPPORT)) { - - /* No DBL support, so just update the destn and proceed */ - db->dst_ipv4 = dest_info.k.ipv4; - db->dst_port = dest_info.k.port; - goto update_pkt; - } - - if(PREDICT_FALSE(db->dst_ipv4 != dest_info.k.ipv4)) { - - if(PREDICT_TRUE(db->nsessions == 1)) { - /* Handle one to 2 dest scenarion */ - dest_info.k.vrf = db->in2out_key.k.vrf; - session_db = cnat_handle_1to2_session(db, &dest_info); - - if(PREDICT_FALSE(session_db == NULL)) { - disposition = CNAT_V4_ICMP_Q_O2I_D; - counter = CNAT_V4_ICMP_Q_O2I_NO_SESSION_DROP; - goto drop_pkt; - } - } else if (PREDICT_FALSE(db->nsessions == 0)) { - /* Should be a static entry - * Note this session as the first session and log - */ - cnat_add_dest_n_log(db, &dest_info); - } else { /* Many translations exist already */ - dest_info.k.vrf = db->in2out_key.k.vrf; - /* If session already exists, - * cnat_create_session_db_entry will return the existing db - * else create a new db - * If could not create, return NULL - */ - session_db = cnat_create_session_db_entry(&dest_info, - db, TRUE); - - if(PREDICT_FALSE(session_db == NULL)) { - disposition = CNAT_V4_ICMP_Q_O2I_D; - counter = CNAT_V4_ICMP_Q_O2I_NO_SESSION_DROP; - goto drop_pkt; - } - } - } - -update_pkt: - - if (PLATFORM_HANDLE_TTL_DECREMENT) { - /* - * Decrement TTL and update IPv4 checksum - */ - ipv4_decr_ttl_n_calc_csum(ip); - } - - /* - * 1. update dest ipv4 addr and icmp id - * 2. update ipv4 checksum and icmp checksum - */ - swap_ip_dst_icmp_id(ip, icmp, db, db->in2out_key.k.vrf); - - if (PREDICT_FALSE(icmp_debug_flag)) { - printf("\nDUMPING ICMP PKT AFTER\n"); - print_icmp_pkt(ip); - } - - db->out2in_pkts++; - - //nat44_dslite_global_stats[dslite_flag].out2in_forwarding_count++; - - } else { - disposition = CNAT_V4_ICMP_Q_O2I_D; - counter = CNAT_V4_ICMP_Q_O2I_MISS_PKT; - } - -drop_pkt: - em->counters[node_counter_base_index + counter] += 1; - return disposition; - -} - -#include - -static uword cnat_ipv4_icmp_q_outside_input_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return dispatch_pipeline (vm, node, frame); -} - - -VLIB_REGISTER_NODE (cnat_ipv4_icmp_q_outside_input_node) = { - .function = cnat_ipv4_icmp_q_outside_input_node_fn, - .name = "vcgn-v4-icmp-q-o2i", - .vector_size = sizeof (u32), - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(cnat_ipv4_icmp_q_outside_input_error_strings), - .error_strings = cnat_ipv4_icmp_q_outside_input_error_strings, - - .n_next_nodes = CNAT_V4_ICMP_Q_O2I_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [CNAT_V4_ICMP_Q_O2I_T] = "ip4-input", - [CNAT_V4_ICMP_Q_O2I_D] = "error-drop", - }, -}; - -clib_error_t *cnat_ipv4_icmp_q_outside_input_init (vlib_main_t *vm) -{ - cnat_ipv4_icmp_q_outside_input_main_t * mp = &cnat_ipv4_icmp_q_outside_input_main; - - mp->vlib_main = vm; - mp->vnet_main = vnet_get_main(); - - return 0; -} - -VLIB_INIT_FUNCTION (cnat_ipv4_icmp_q_outside_input_init); diff --git a/plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_inside_input.c b/plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_inside_input.c deleted file mode 100644 index 5bea7073..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_inside_input.c +++ /dev/null @@ -1,424 +0,0 @@ -/* - *--------------------------------------------------------------------------- - * cnat_ipv4_tcp_inside_input.c - cnat_ipv4_tcp_inside_input node pipeline - * stage functions - * - * - * Copyright (c) 2008-2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *--------------------------------------------------------------------------- - */ - -#include -#include -#include -#include - -#include "cnat_db.h" -#include "tcp_header_definitions.h" -#include "cnat_config.h" -#include "cnat_global.h" -#include "cnat_v4_functions.h" - -#define foreach_cnat_ipv4_tcp_inside_input_error \ -_(CNAT_V4_TCP_I2O_PKT_IN, "tcp i2o packets received") \ -_(CNAT_V4_TCP_I2O_PKT_T, "tcp i2o packets natted") \ -_(CNAT_V4_TCP_I2O_EXCEPTION, "packets to tcp i2o exception") \ -_(CNAT_V4_TCP_I2O_TTL_GEN, "generated TTL expiry ICMP packets") \ -_(CNAT_V4_TCP_I2O_TTL_GEN_DROP, "could not generate TTL expiry ICMP packets") \ -_(CNAT_V4_TCP_I2O_SESSION_DROP, "could not generate session") \ -_(CNAT_V4_UDP_I2O_FRAG_DROP, "non-first fragment drop") - -typedef enum { -#define _(sym,str) sym, - foreach_cnat_ipv4_tcp_inside_input_error -#undef _ - CNAT_IPV4_TCP_INSIDE_INPUT_N_ERROR, -} cnat_ipv4_tcp_inside_input_t; - -static char * cnat_ipv4_tcp_inside_input_error_strings[] = { -#define _(sym,string) string, - foreach_cnat_ipv4_tcp_inside_input_error -#undef _ -}; - -typedef struct { - u32 cached_next_index; - /* $$$$ add data here */ - - /* convenience variables */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; -} cnat_ipv4_tcp_inside_input_main_t; - -typedef enum { - CNAT_V4_TCP_I2O_E, - CNAT_V4_TCP_I2O_T, - CNAT_V4_TCP_I2O_D, - CNAT_V4_TCP_I2O_NEXT, -} cnat_ipv4_tcp_inside_input_next_t; - -#define CNAT_REWRITE_OUTPUT CNAT_V4_TCP_I2O_T -#define CNAT_V4_ICMP_GEN CNAT_V4_TCP_I2O_D - -//#define CNAT_V4_TCP_I2O_E CNAT_V4_TCP_I2O_D //remove it once exception node is created -cnat_ipv4_tcp_inside_input_main_t cnat_ipv4_tcp_inside_input_main; -vlib_node_registration_t cnat_ipv4_tcp_inside_input_node; - -#define NSTAGES 6 - -/* - * Use the generic buffer metadata + first line of packet data prefetch - * stage function from . This is usually a Good Idea. - */ -#define stage0 generic_stage0 - - -static inline void -stage1(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - u64 a, b, c; - u32 bucket; - u8 *prefetch_target; - //cnat_feature_data_t *fd = (cnat_feature_data_t *)ctx->feature_data; - - - vlib_buffer_t * b0 = vlib_get_buffer (vm, buffer_index); - ipv4_header *ip = vlib_buffer_get_current (b0); - u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; - tcp_hdr_type *tcp = (tcp_hdr_type *)((u8*)ip + ipv4_hdr_len); - - u64 tmp = 0; - tmp = vnet_buffer(b0)->vcgn_uii.key.k.ipv4 = - clib_net_to_host_u32(ip->src_addr); - vnet_buffer(b0)->vcgn_uii.key.k.port = - clib_net_to_host_u16 (tcp->src_port); - - tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.port) << 32; - - PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX], - vnet_buffer(b0)->vcgn_uii.key.k.vrf, - CNAT_TCP) - tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.vrf) << 48; - - CNAT_V4_GET_HASH(tmp, bucket, CNAT_MAIN_HASH_MASK) - - prefetch_target = (u8 *)(&cnat_in2out_hash[bucket]); - vnet_buffer(b0)->vcgn_uii.bucket = bucket; - - /* Prefetch the hash bucket */ - CLIB_PREFETCH(prefetch_target, CLIB_CACHE_LINE_BYTES, LOAD); -} - -static inline void -stage2(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ /* nothing */ } - - -#define SPP_LOG2_CACHE_LINE_BYTES 6 -#define SPP_CACHE_LINE_BYTES (1 << SPP_LOG2_CACHE_LINE_BYTES) - -static inline void -stage3(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index); - uword prefetch_target0, prefetch_target1; - u32 bucket = vnet_buffer(b0)->vcgn_uii.bucket; - - /* read the hash bucket */ - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket - = cnat_in2out_hash[bucket].next; - - if (PREDICT_TRUE(db_index != EMPTY)) { - /* - * Prefetch database keys. We save space by not cache-line - * aligning the DB entries. We don't want to waste LSU - * bandwidth prefetching stuff we won't need. - */ - prefetch_target0 = (uword)(cnat_main_db + db_index); - CLIB_PREFETCH((void*)prefetch_target0, CLIB_CACHE_LINE_BYTES, LOAD); - /* Just beyond DB key #2 */ - prefetch_target1 = prefetch_target0 + - STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports); - /* If the targets are in different lines, do the second prefetch */ - if (PREDICT_FALSE((prefetch_target0 & ~(SPP_CACHE_LINE_BYTES-1)) != - (prefetch_target1 & ~(SPP_CACHE_LINE_BYTES-1)))) { - CLIB_PREFETCH((void *)prefetch_target1, CLIB_CACHE_LINE_BYTES, LOAD); - } - } -} - -static inline void -stage4(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - cnat_main_db_entry_t *db; - vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index); - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket; - - /* - * Note: if the search already failed (empty bucket), - * the answer is already in the pipeline context structure - */ - if (PREDICT_TRUE(db_index != EMPTY)) { - - /* - * Note: hash collisions suck. We can't easily prefetch around them. - * The first trip around the track will be fast. After that, maybe - * not so much... - */ - do { - db = cnat_main_db + db_index; - if (PREDICT_TRUE(db->in2out_key.key64 == - vnet_buffer(b0)->vcgn_uii.key.key64)) { - break; - } - db_index = db->in2out_hash.next; - } while (db_index != EMPTY); - - /* Stick the answer back into the pipeline context structure */ - vnet_buffer(b0)->vcgn_uii.bucket = db_index; - } -} - - -static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node, - u32 bi) -{ - vlib_buffer_t *b0 = vlib_get_buffer (vm, bi); - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket; - spp_ctx_t *ctx = (spp_ctx_t *) &vnet_buffer(b0)->vcgn_uii; - int disposition = CNAT_V4_TCP_I2O_T; - int counter = CNAT_V4_TCP_I2O_PKT_T; - - ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0); - u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; - tcp_hdr_type *tcp = (tcp_hdr_type *)((u8*)ip + ipv4_hdr_len); - vlib_node_t *n = vlib_get_node (vm, cnat_ipv4_tcp_inside_input_node.index); - u32 node_counter_base_index = n->error_heap_index; - vlib_error_main_t * em = &vm->error_main; - cnat_session_entry_t *session_db = NULL; - cnat_main_db_entry_t *db = NULL; - cnat_key_t dest_info; - u32 window; - u8 scale; - - - INCREMENT_NODE_COUNTER(CNAT_V4_TCP_I2O_PKT_IN); - - if (PLATFORM_HANDLE_TTL_DECREMENT) { - if (PREDICT_FALSE(ip->ttl <= 1)) { - /* Try to generate ICMP error msg, as TTL is <= 1 */ - - if (icmpv4_generate_with_throttling - (ctx, ip, ctx->ru.rx.uidb_index)) { - - /* Generated ICMP */ - disposition = CNAT_REWRITE_OUTPUT; - counter = CNAT_V4_TCP_I2O_TTL_GEN; - } else { - /* Could not generated ICMP - drop the packet */ - disposition = CNAT_V4_TCP_I2O_D; - counter = CNAT_V4_TCP_I2O_TTL_GEN_DROP; - } - goto drop_pkt; - } - } - - if (PREDICT_FALSE(db_index == EMPTY)) { - /* Deleted fragment code from here */ - disposition = CNAT_V4_TCP_I2O_E; - counter = CNAT_V4_TCP_I2O_EXCEPTION; - } else { - db = cnat_main_db + db_index; - - /* Handle destination sessions */ - dest_info.k.port = clib_net_to_host_u16(tcp->dest_port); - dest_info.k.ipv4 = clib_net_to_host_u32(ip->dest_addr); - - if(PREDICT_TRUE(!PLATFORM_DBL_SUPPORT)) { - - /* No DBL support, so just update the destn and proceed */ - db->dst_ipv4 = dest_info.k.ipv4; - db->dst_port = dest_info.k.port; - goto update_pkt; - } - - if(PREDICT_FALSE(db->dst_ipv4 != dest_info.k.ipv4 || - db->dst_port != dest_info.k.port)) { - if(PREDICT_TRUE(db->nsessions == 0)) { - /* Should be a static entry - * Note this session as the first session and log - */ - cnat_add_dest_n_log(db, &dest_info); - } else if(PREDICT_FALSE(db->nsessions == 1)) { - /* Destn is not same as in main db. Multiple session - * scenario - */ - dest_info.k.vrf = db->in2out_key.k.vrf; - session_db = cnat_handle_1to2_session(db, &dest_info); - if(PREDICT_FALSE(session_db == NULL)) { - disposition = CNAT_V4_TCP_I2O_D; - counter = CNAT_V4_TCP_I2O_SESSION_DROP; - goto drop_pkt; - } - } else { /* There are already multiple destinations */ - dest_info.k.vrf = db->in2out_key.k.vrf; - /* If session already exists, - * cnat_create_session_db_entry will return the existing db - * else create a new db - * If could not create, return NULL - */ - session_db = cnat_create_session_db_entry(&dest_info, - db, TRUE); - if(PREDICT_FALSE(session_db == NULL)) { - disposition = CNAT_V4_TCP_I2O_D; - counter = CNAT_V4_TCP_I2O_SESSION_DROP; - goto drop_pkt; - } - } - if(PREDICT_TRUE(session_db != 0)) { - /* Have to repeat the window size check for new destinations */ - window = (u32)clib_net_to_host_u16(tcp->window_size); - window = window << session_db->scale; - if(PREDICT_TRUE(!session_db->window)) { - calculate_window_scale(tcp, &scale); - session_db->scale = scale; - session_db->window = window; - } else if (PREDICT_FALSE(session_db->window < - window)) { - /* Update the db entry with window option from packet */ - session_db->window = window; - } else { - /* Do nothing */ - } - session_db->tcp_seq_num = clib_net_to_host_u32(tcp->seq_num); - session_db->ack_no = clib_net_to_host_u32(tcp->ack_num); -#if DEBUG > 1 - printf("\n In2out SDB stages seq no = %u," - " ack no = %u, window = %u\n", - session_db->tcp_seq_num, - session_db->ack_no, - session_db->window); -#endif - - } - } else { - //Update the seq no and ack no for subsequent communication - //after connection establishment - //No need to update window here. Window is already updated - //during connection establishment - window = (u32)clib_net_to_host_u16(tcp->window_size); - window = window << db->scale; - if(PREDICT_FALSE(!ALG_ENABLED_DB(db))) { - //This check is done since proto_data is part of union in main - //db entry - db->proto_data.tcp_seq_chk.seq_no = - clib_net_to_host_u32(tcp->seq_num); - db->proto_data.tcp_seq_chk.ack_no = - clib_net_to_host_u32(tcp->ack_num); - } - if (PREDICT_FALSE(db->diff_window < window)) { - /* Update the db entry with window option from packet */ - db->diff_window = window; - } -#if DEBUG > 1 - printf("\n In2out MainDB seq no = %u," - "\n ack no = %u\n", - db->proto_data.tcp_seq_chk.seq_no, - db->proto_data.tcp_seq_chk.ack_no); - printf("\n In2out MAINDB window = %u\n", - db->diff_window); -#endif - } -update_pkt: - - counter = CNAT_V4_TCP_I2O_PKT_T; - disposition = CNAT_V4_TCP_I2O_T; - - /* NO FRAGMENT & ALG HANDLING. DELETING THE CODE */ - - if (PLATFORM_HANDLE_TTL_DECREMENT) { - /* - * Decrement TTL and update IPv4 checksum - */ - ipv4_decr_ttl_n_calc_csum(ip); - } - - tcp_in2out_nat_mss_n_checksum(ip, - tcp, - db->out2in_key.k.ipv4, - db->out2in_key.k.port, - db - /*, db->in2out_key.k.vrf */); - - /* update transaltion counters */ - db->in2out_pkts++; - in2out_forwarding_count++; - - /* update the timer for good mode, or evil mode dst_ip match */ - - if(PREDICT_FALSE(session_db != NULL)) { - V4_TCP_UPDATE_SESSION_DB_FLAG(session_db, tcp); - CNAT_DB_TIMEOUT_RST(session_db); - } else { - V4_TCP_UPDATE_SESSION_FLAG(db, tcp); - CNAT_DB_TIMEOUT_RST(db); - } - } - -drop_pkt: - - em->counters[node_counter_base_index + counter] += 1; - return disposition; -} - -#include - -static uword cnat_ipv4_tcp_inside_input_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return dispatch_pipeline (vm, node, frame); -} - - -VLIB_REGISTER_NODE (cnat_ipv4_tcp_inside_input_node) = { - .function = cnat_ipv4_tcp_inside_input_node_fn, - .name = "vcgn-v4-tcp-i2o", - .vector_size = sizeof (u32), - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(cnat_ipv4_tcp_inside_input_error_strings), - .error_strings = cnat_ipv4_tcp_inside_input_error_strings, - - .n_next_nodes = CNAT_V4_TCP_I2O_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [CNAT_V4_TCP_I2O_E] = "vcgn-v4-tcp-i2o-e", - [CNAT_V4_TCP_I2O_T] = "ip4-input", - [CNAT_V4_TCP_I2O_D] = "error-drop", - }, -}; - -clib_error_t *cnat_ipv4_tcp_inside_input_init (vlib_main_t *vm) -{ - cnat_ipv4_tcp_inside_input_main_t * mp = &cnat_ipv4_tcp_inside_input_main; - - mp->vlib_main = vm; - mp->vnet_main = vnet_get_main(); - - return 0; -} - -VLIB_INIT_FUNCTION (cnat_ipv4_tcp_inside_input_init); diff --git a/plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_inside_input_exceptions.c b/plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_inside_input_exceptions.c deleted file mode 100644 index bc1bebb0..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_inside_input_exceptions.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - *--------------------------------------------------------------------------- - * cnat_ipv4_tcp_inside_input_exceptions.c - - * cnat_ipv4_tcp_inside_input_exceptions node pipeline stage functions - * - * - * Copyright (c) 2008-2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *--------------------------------------------------------------------------- - */ - -#include -#include -#include -#include - -#include "cnat_db.h" -#include "tcp_header_definitions.h" -#include "cnat_config.h" -#include "cnat_global.h" -#include "cnat_v4_functions.h" - - -#define foreach_cnat_ipv4_tcp_inside_input_exc_error \ -_(CNAT_V4_TCP_I2O_E_T_PKT, "v4 tcp i2o-e transmit natted pkt") \ -_(CNAT_V4_TCP_I2O_E_D_NON_SYN_PKT, "v4 tcp i2o-e non syn drop") \ -_(CNAT_V4_TCP_I2O_E_D_INVALID_PKT, "v4 tcp i2o-e invalid pkt drop") \ -_(CNAT_V4_TCP_I2O_E_DROP, "v4 tcp i2o-e drop") \ -_(CNAT_V4_TCP_I2O_E_GEN_ICMP, "v4 tcp i2o-e gen icmp msg") \ -_(CNAT_V4_TCP_I2O_E_D_NO_SESSION, "v4 tcp i2o-e no session db entry drop") - -typedef enum { -#define _(sym,str) sym, - foreach_cnat_ipv4_tcp_inside_input_exc_error -#undef _ - CNAT_IPV4_TCP_INSIDE_INPUT_EXCEPTIONS_N_ERROR, -} cnat_ipv4_tcp_inside_input_exc_error_t; - - -static char * cnat_ipv4_tcp_inside_input_exc_error_strings[] = { -#define _(sym,string) string, - foreach_cnat_ipv4_tcp_inside_input_exc_error -#undef _ -}; - -typedef struct { - u32 cached_next_index; - /* $$$$ add data here */ - - /* convenience variables */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; -} cnat_ipv4_tcp_inside_input_exc_main_t; - -typedef enum { - CNAT_V4_TCP_I2O_E_T, - //CNAT_V4_TCP_I2O_E_ICMP, - CNAT_V4_TCP_I2O_E_D, - CNAT_V4_TCP_I2O_E_NEXT, -} cnat_ipv4_udp_inside_input_exc_next_t; - -#define CNAT_V4_TCP_I2O_E_ICMP CNAT_V4_TCP_I2O_E_D - -cnat_ipv4_tcp_inside_input_exc_main_t cnat_ipv4_tcp_inside_input_exc_main; -vlib_node_registration_t cnat_ipv4_tcp_inside_input_exc_node; - -#define NSTAGES 2 - -/* - * Use the generic buffer metadata + first line of packet data prefetch - * stage function from . This is usually a Good Idea. - */ -#define stage0 generic_stage0 - - -static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node, - u32 bi) -{ - vlib_buffer_t *b0 = vlib_get_buffer (vm, bi); - vlib_node_t *n = - vlib_get_node (vm, cnat_ipv4_tcp_inside_input_exc_node.index); - u32 node_counter_base_index = n->error_heap_index; - vlib_error_main_t * em = &vm->error_main; - - cnat_gen_icmp_info info; - cnat_db_key_bucket_t ki; - cnat_main_db_entry_t *db = NULL; - ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0); - u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; - tcp_hdr_type *tcp = (tcp_hdr_type *)((u8*)ip + ipv4_hdr_len); - int disposition = CNAT_V4_TCP_I2O_E_T; - int counter = CNAT_V4_TCP_I2O_E_T_PKT; - cnat_key_t dest_info; - u32 window; - u8 scale; - - window = (u32)clib_net_to_host_u16(tcp->window_size); - calculate_window_scale(tcp, &scale); - - dest_info.k.port = clib_net_to_host_u16(tcp->dest_port); - dest_info.k.ipv4 = clib_net_to_host_u32(ip->dest_addr); - - PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX], - dest_info.k.vrf, CNAT_TCP) - - /* for TCP if not SYN or if src_port is 0, silently drop the packet */ - if (PREDICT_FALSE(!((tcp->flags & TCP_FLAG_SYN) && (tcp->src_port)))) { - - /* - * If the packet is dropped due to both reasons, - * count it as invalid packet drop - */ - if (!tcp->src_port) { - counter = CNAT_V4_TCP_I2O_E_D_INVALID_PKT; - } else { - counter = CNAT_V4_TCP_I2O_E_D_NON_SYN_PKT; - } - disposition = CNAT_V4_TCP_I2O_E_D; - goto in2out_e; - } - - PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX], - ki.k.k.vrf, CNAT_TCP) - - ki.k.k.ipv4 = clib_net_to_host_u32(ip->src_addr); - ki.k.k.port = clib_net_to_host_u16(tcp->src_port); - - db = cnat_get_main_db_entry_v2(&ki, PORT_SINGLE, PORT_TYPE_DYNAMIC, &info, - &dest_info); - - -#if DEBUG > 1 - if(PREDICT_TRUE(db)) { - printf("create db %x ip %x->%x port %x->%x dst_ip %x\n", db, - db->in2out_key.k.ipv4, db->out2in_key.k.ipv4, - db->in2out_key.k.port, db->out2in_key.k.port, db->dst_ipv4); - } -#endif - - - if (PREDICT_FALSE(db == 0)) { - /* failed to create new db entry due to either no more port, or user limit reached, - * need to generate ICMP type=3,code=13 msg here, - */ - - /* - * we rate limit the icmp msg per private user, - * so we don't flood a user with icmp msg - * in case the per user port limit reached - */ - if (PREDICT_TRUE(info.gen_icmp_msg == CNAT_ICMP_MSG)) { - /* KEEPING THINGS COMMENTED HERE..MAY NEED TO REVISIT AGAIN */ - #if 0 - u32 *fd = (u32*)ctx->feature_data; - fd[0] = info.svi_addr; - fd[1] = CNAT_ICMP_DEST_UNREACHABLE; - - /* - * Let's reverse the direction from i2o to o2i. - * This will help using the correct VRF in the fib lookup (AVSM) - * especially for the o2i_vrf_override case - */ - ctx->ru.rx.direction = 0; // 0 - o2i, 1 - i2o - #endif - disposition = CNAT_V4_TCP_I2O_E_ICMP; - counter = CNAT_V4_TCP_I2O_E_GEN_ICMP; - - } else { - disposition = CNAT_V4_TCP_I2O_E_D; - counter = CNAT_V4_TCP_I2O_E_DROP; - } - //DEBUG_I2O_DROP(CNAT_DEBUG_DROP_TCP) - } else { - - if (PLATFORM_HANDLE_TTL_DECREMENT) { - /* - * Decrement TTL and update IPv4 checksum - */ - ipv4_decr_ttl_n_calc_csum(ip); - } - - /* NAT the packet and fix checksum */ - - tcp_in2out_nat_mss_n_checksum(ip, - tcp, - db->out2in_key.k.ipv4, - db->out2in_key.k.port, - db - /*, db->in2out_key.k.vrf */); - - /* this must be inside to outside SYN, do mss here */ - - /* update translation counters */ - db->in2out_pkts++; - - /* set keepalive timer */ - - if(PREDICT_TRUE((dest_info.k.ipv4 == db->dst_ipv4) && - (dest_info.k.port == db->dst_port))) { - if(PREDICT_FALSE(!ALG_ENABLED_DB(db))) { - //This check is done since proto_data is part of union in main - //db entry - - db->proto_data.tcp_seq_chk.seq_no = - clib_net_to_host_u32(tcp->seq_num); - db->proto_data.tcp_seq_chk.ack_no = - clib_net_to_host_u32(tcp->ack_num); - db->scale = scale; - db->diff_window = window; - } -#if DEBUG > 1 - PLATFORM_DEBUG_PRINT("\nMain DB seq no = %u," - "ack no = %u, window = %u," - "scale = %u", - db->proto_data.tcp_seq_chk.seq_no, - db->proto_data.tcp_seq_chk.ack_no, - db->diff_window - db->scale); -#endif - V4_TCP_UPDATE_SESSION_FLAG(db, tcp); - /* Check timeout db if there is config for this */ - (void) query_and_update_db_timeout((void *)db, MAIN_DB_TYPE); - db->entry_expires = cnat_current_time; - } else { - /* Got to find out the session entry corresponding to this..*/ - cnat_session_entry_t *sdb; - sdb = cnat_session_db_lookup_entry( - &dest_info, db - cnat_main_db); - if(PREDICT_FALSE(sdb == NULL)) { - disposition = CNAT_V4_TCP_I2O_E_D; - counter = CNAT_V4_TCP_I2O_E_D_NO_SESSION; - goto in2out_e; - } - sdb->tcp_seq_num = clib_net_to_host_u32(tcp->seq_num); - sdb->ack_no = clib_net_to_host_u32(tcp->ack_num); - sdb->scale = scale; - sdb->window = window; - -#if DEBUG > 1 - PLATFORM_DEBUG_PRINT("\nSDB seq no = %u, ack no = %u, window = %u" - "\nSDB scale = %u" , - sdb->tcp_seq_num, - sdb->ack_no, - sdb->window, - sdb->scale); -#endif - V4_TCP_UPDATE_SESSION_DB_FLAG(sdb, tcp); - /* Check timeout db if there is config for this */ - (void) query_and_update_db_timeout((void *)sdb, SESSION_DB_TYPE); - sdb->entry_expires = cnat_current_time; - } - - //PLATFORM_CNAT_SET_TX_VRF(ctx,db->out2in_key.k.vrf) - - counter = CNAT_V4_TCP_I2O_E_T_PKT; - in2out_forwarding_count++; - } - -in2out_e: - - em->counters[node_counter_base_index + counter] += 1; - - return disposition; -} - -#include - -static uword cnat_ipv4_tcp_inside_input_exc_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return dispatch_pipeline (vm, node, frame); -} - -VLIB_REGISTER_NODE (cnat_ipv4_tcp_inside_input_exc_node) = { - .function = cnat_ipv4_tcp_inside_input_exc_node_fn, - .name = "vcgn-v4-tcp-i2o-e", - .vector_size = sizeof (u32), - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(cnat_ipv4_tcp_inside_input_exc_error_strings), - .error_strings = cnat_ipv4_tcp_inside_input_exc_error_strings, - - .n_next_nodes = CNAT_V4_TCP_I2O_E_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [CNAT_V4_TCP_I2O_E_T] = "ip4-input", - [CNAT_V4_TCP_I2O_E_D] = "error-drop", - }, -}; - - -clib_error_t *cnat_ipv4_tcp_inside_input_exc_init (vlib_main_t *vm) -{ - cnat_ipv4_tcp_inside_input_exc_main_t * mp = &cnat_ipv4_tcp_inside_input_exc_main; - - mp->vlib_main = vm; - mp->vnet_main = vnet_get_main(); - - return 0; -} - -VLIB_INIT_FUNCTION (cnat_ipv4_tcp_inside_input_exc_init); diff --git a/plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_outside_input.c b/plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_outside_input.c deleted file mode 100644 index bcf132b1..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_outside_input.c +++ /dev/null @@ -1,382 +0,0 @@ -/* - *--------------------------------------------------------------------------- - * cnat_ipv4_tcp_outside_input.c - cnat_v4_tcp_out2in node pipeline stage functions - * - * - * Copyright (c) 2008-2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *--------------------------------------------------------------------------- - */ - -#include -#include -#include -#include - -#include "cnat_db.h" -#include "tcp_header_definitions.h" -#include "cnat_config.h" -#include "cnat_global.h" -#include "cnat_ipv4_udp.h" -#include "cnat_v4_functions.h" - - -#define foreach_cnat_ipv4_tcp_outside_input_error \ -_(CNAT_V4_TCP_O2I_R_PKT, "v4 tcp o2i pkt received") \ -_(CNAT_V4_TCP_O2I_T_PKT, "v4 tcp o2i pkt natted & transmitted") \ -_(CNAT_V4_TCP_O2I_LOOKUP_FAILED, "v4 tcp o2i lookup failed") \ -_(CNAT_V4_TCP_O2I_TTL_GEN, "v4 tcp o2i generated TTL Expiry ICMP packet") \ -_(CNAT_V4_TCP_O2I_TTL_DROP, "v4 tcp o2i drop due to failure in creating TTL expiry ICMP msg") \ -_(CNAT_V4_TCP_O2I_PTB_GEN, "v4 tcp o2i PTB ICMP pkt generation") \ -_(CNAT_V4_UDP_O2I_PTB_DROP, "v4 tcp o2i drop due to failure in creating PTB ICMP pkt") \ -_(CNAT_V4_TCP_O2I_SESSION_DROP, "v4 tcp o2i drop due to failure in creating session db") \ -_(CNAT_V4_TCP_O2I_SEQ_MISMATCH_DROP, "v4 tcp o2i drop due to TCP sequence mismatch") \ -_(CNAT_V4_TCP_O2I_FILTER_DROP, "v4 tcp o2i drop due to endpoint filtering") \ -_(CNAT_V4_TCP_O2I_NON_SYN_RST_DROP, "v4 tcp o2i drop due no syn/rst flag") \ -_(CNAT_V4_TCP_O2I_FIRST_FRAG_DROP, "v4 tcp o2i first fragment drop") \ -_(CNAT_V4_TCP_O2I_SUB_FRAG_NO_DB_DROP, "v4 tcp o2i subsequest frag no DB drop") - -typedef enum { -#define _(sym,str) sym, - foreach_cnat_ipv4_tcp_outside_input_error -#undef _ - CNAT_IPV4_TCP_OUTSIDE_INPUT_N_ERROR, -} cnat_ipv4_tcp_outside_input_t; - -static char * cnat_ipv4_tcp_outside_input_error_strings[] = { -#define _(sym,string) string, - foreach_cnat_ipv4_tcp_outside_input_error -#undef _ -}; - -typedef struct { - u32 cached_next_index; - /* $$$$ add data here */ - - /* convenience variables */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; -} cnat_ipv4_tcp_outside_input_main_t; - -typedef enum { - //CNAT_V4_TCP_O2I_E, - CNAT_V4_TCP_O2I_T, - CNAT_V4_TCP_O2I_D, - CNAT_V4_TCP_O2I_NEXT, -} cnat_ipv4_tcp_outside_input_next_t; - -cnat_ipv4_tcp_outside_input_main_t cnat_ipv4_tcp_outside_input_main; -vlib_node_registration_t cnat_ipv4_tcp_outside_input_node; - -#define NSTAGES 6 - -/* - * Use the generic buffer metadata + first line of packet data prefetch - * stage function from . This is usually a Good Idea. - */ -#define stage0 generic_stage0 - - -static inline void -stage1(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - u64 a, b, c; - u32 bucket; - u8 *prefetch_target; - - - vlib_buffer_t * b0 = vlib_get_buffer (vm, buffer_index); - ipv4_header *ip = vlib_buffer_get_current (b0); - u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; - tcp_hdr_type *tcp = (tcp_hdr_type *)((u8*)ip + ipv4_hdr_len); - - u64 tmp = 0; - tmp = vnet_buffer(b0)->vcgn_uii.key.k.ipv4 = - clib_net_to_host_u32(ip->dest_addr); - vnet_buffer(b0)->vcgn_uii.key.k.port = - clib_net_to_host_u16 (tcp->dest_port); - - tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.port) << 32; - - PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX], - vnet_buffer(b0)->vcgn_uii.key.k.vrf, - CNAT_TCP) - tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.vrf) << 48; - - CNAT_V4_GET_HASH(tmp, bucket, CNAT_MAIN_HASH_MASK) - - prefetch_target = (u8 *)(&cnat_out2in_hash[bucket]); - vnet_buffer(b0)->vcgn_uii.bucket = bucket; - - /* Prefetch the hash bucket */ - CLIB_PREFETCH(prefetch_target, CLIB_CACHE_LINE_BYTES, LOAD); -} - -static inline void -stage2(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ /* nothing */ } - -#define SPP_LOG2_CACHE_LINE_BYTES 6 -#define SPP_CACHE_LINE_BYTES (1 << SPP_LOG2_CACHE_LINE_BYTES) - -static inline void -stage3(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index); - uword prefetch_target0, prefetch_target1; - u32 bucket = vnet_buffer(b0)->vcgn_uii.bucket; - - /* read the hash bucket */ - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket - = cnat_out2in_hash[bucket].next; - - if (PREDICT_TRUE(db_index != EMPTY)) { - /* - * Prefetch database keys. We save space by not cache-line - * aligning the DB entries. We don't want to waste LSU - * bandwidth prefetching stuff we won't need. - */ - prefetch_target0 = (uword)(cnat_main_db + db_index); - CLIB_PREFETCH((void*)prefetch_target0, CLIB_CACHE_LINE_BYTES, STORE); - /* Just beyond DB key #2 */ - prefetch_target1 = prefetch_target0 + - STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports); - /* If the targets are in different lines, do the second prefetch */ - if (PREDICT_FALSE((prefetch_target0 & ~(SPP_CACHE_LINE_BYTES-1)) != - (prefetch_target1 & ~(SPP_CACHE_LINE_BYTES-1)))) { - CLIB_PREFETCH((void *)prefetch_target1, CLIB_CACHE_LINE_BYTES, STORE); - } - } -} - -static inline void -stage4(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - cnat_main_db_entry_t *db; - vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index); - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket; - - /* - * Note: if the search already failed (empty bucket), - * the answer is already in the pipeline context structure - */ - if (PREDICT_TRUE(db_index != EMPTY)) { - - /* - * Note: hash collisions suck. We can't easily prefetch around them. - * The first trip around the track will be fast. After that, maybe - * not so much... - */ - do { - db = cnat_main_db + db_index; - if (PREDICT_TRUE(db->out2in_key.key64 == - vnet_buffer(b0)->vcgn_uii.key.key64)) { - break; - } - db_index = db->out2in_hash.next; - } while (db_index != EMPTY); - - /* Stick the answer back into the pipeline context structure */ - vnet_buffer(b0)->vcgn_uii.bucket = db_index; - } -} - -static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node, - u32 bi) -{ - vlib_buffer_t *b0 = vlib_get_buffer (vm, bi); - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket; - spp_ctx_t *ctx = (spp_ctx_t *) &vnet_buffer(b0)->vcgn_uii; - int disposition = CNAT_V4_TCP_O2I_T; - int counter = CNAT_V4_TCP_O2I_T_PKT; - - ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0); - u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; - tcp_hdr_type *tcp = (tcp_hdr_type *)((u8*)ip + ipv4_hdr_len); - vlib_node_t *n = vlib_get_node (vm, cnat_ipv4_tcp_outside_input_node.index); - u32 node_counter_base_index = n->error_heap_index; - vlib_error_main_t * em = &vm->error_main; - cnat_session_entry_t *session_db = NULL; - cnat_main_db_entry_t *db = NULL; - cnat_key_t dest_info; - - INCREMENT_NODE_COUNTER(CNAT_V4_TCP_O2I_R_PKT); - - if (PREDICT_FALSE(db_index == EMPTY)) { - nat44_dslite_common_stats[0].no_translation_entry_drops ++; - counter = CNAT_V4_TCP_O2I_LOOKUP_FAILED; - disposition = CNAT_V4_TCP_O2I_D; - } else { - if (PLATFORM_HANDLE_TTL_DECREMENT) { - if (PREDICT_FALSE(ip->ttl <= 1)) { - /* Try to generate ICMP error msg, as TTL is <= 1 */ - if (icmpv4_generate_with_throttling(ctx, - ip, ctx->ru.rx.uidb_index)) { - /* Generated ICMP */ - disposition = CNAT_V4_TCP_O2I_T_PKT; //CNAT_REWRITE_OUTPUT; - counter = CNAT_V4_TCP_O2I_TTL_GEN; - } else { - /* Could not generated ICMP - drop the packet */ - disposition = CNAT_V4_TCP_O2I_D; - counter = CNAT_V4_TCP_O2I_TTL_DROP; - } - goto drop_pkt; - } - } - db = cnat_main_db + db_index; -#if 0 - window = db->diff_window; - stored_seq_no = db->proto_data.tcp_seq_chk.seq_no; - stored_ack_no = db->proto_data.tcp_seq_chk.ack_no; - vrf_map_p = cnat_map_by_vrf + db->vrfmap_index; - vrf_index = (db->in2out_key.k.vrf & CNAT_VRF_MASK); -#endif - /* For Out2In packet, the dest info is src address and port */ - dest_info.k.port = clib_net_to_host_u16(tcp->src_port); - dest_info.k.ipv4 = clib_net_to_host_u32(ip->src_addr); - - if(PREDICT_TRUE(!PLATFORM_DBL_SUPPORT)) { - - /* No DBL support, so just update the destn and proceed */ - db->dst_ipv4 = dest_info.k.ipv4; - db->dst_port = dest_info.k.port; - goto update_pkt; - } - - - if(PREDICT_FALSE(db->dst_ipv4 != dest_info.k.ipv4 || - db->dst_port != dest_info.k.port)) { - - if(PREDICT_TRUE(db->nsessions == 0)) { - /* Should be a static entry - * Note this session as the first session and log - */ - cnat_add_dest_n_log(db, &dest_info); - //goto packet_upd; - } else if(PREDICT_FALSE(db->nsessions == 1)) { - /* Destn is not same as in main db. Multiple session - * scenario - */ - dest_info.k.vrf = db->in2out_key.k.vrf; - session_db = cnat_handle_1to2_session(db, &dest_info); - if(PREDICT_FALSE(session_db == NULL)) { - disposition = CNAT_V4_TCP_O2I_D; - counter = CNAT_V4_TCP_O2I_SESSION_DROP; - goto drop_pkt; - } - } else { /* There are already multiple destinations */ - dest_info.k.vrf = db->in2out_key.k.vrf; - /* If session already exists, - * cnat_create_session_db_entry will return the existing db - * else create a new db - * If could not create, return NULL - */ - session_db = cnat_create_session_db_entry(&dest_info, db, TRUE); - if(PREDICT_FALSE(session_db == NULL)) { - disposition = CNAT_V4_TCP_O2I_D; - counter = CNAT_V4_TCP_O2I_SESSION_DROP; - goto drop_pkt; - } - } - /* useful for ALG only */ - #if 0 - if(PREDICT_TRUE(session_db)) { - stored_seq_no = session_db->tcp_seq_num; - stored_ack_no = session_db->ack_no; - window = session_db->window; - } - #endif - } - - -update_pkt: - - counter = CNAT_V4_TCP_O2I_T_PKT; - - if (PLATFORM_HANDLE_TTL_DECREMENT) { - /* - * Decrement TTL and update IPv4 checksum - */ - ipv4_decr_ttl_n_calc_csum(ip); - } - - /* update ip checksum, newchecksum = ~(~oldchecksum + ~old + new) */ - cnat_v4_recalculate_tcp_checksum(ip, tcp, - &(ip->dest_addr), - &(tcp->dest_port), - db->in2out_key.k.ipv4, - db->in2out_key.k.port); - - /* CNAT_PPTP_ALG_SUPPORT */ - db->out2in_pkts++; - - nat44_dslite_global_stats[0].out2in_forwarding_count++;; - - V4_TCP_UPDATE_SESSION_FLAG(db, tcp); - - - if(PREDICT_FALSE(session_db != NULL)) { - V4_TCP_UPDATE_SESSION_DB_FLAG(session_db, tcp); - CNAT_DB_TIMEOUT_RST(session_db); - } else { - V4_TCP_UPDATE_SESSION_FLAG(db, tcp); - CNAT_DB_TIMEOUT_RST(db); - } - - } - -drop_pkt: - em->counters[node_counter_base_index + counter] += 1; - return disposition; -} - -#include - -static uword cnat_ipv4_tcp_outside_input_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return dispatch_pipeline (vm, node, frame); -} - - -VLIB_REGISTER_NODE (cnat_ipv4_tcp_outside_input_node) = { - .function = cnat_ipv4_tcp_outside_input_node_fn, - .name = "vcgn-v4-tcp-o2i", - .vector_size = sizeof (u32), - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(cnat_ipv4_tcp_outside_input_error_strings), - .error_strings = cnat_ipv4_tcp_outside_input_error_strings, - - .n_next_nodes = CNAT_V4_TCP_O2I_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - //[CNAT_V4_TCP_O2I_E] = "vcgn-v4-tcp-o2i-e", - [CNAT_V4_TCP_O2I_T] = "ip4-input", - [CNAT_V4_TCP_O2I_D] = "error-drop", - }, -}; - -clib_error_t *cnat_ipv4_tcp_outside_input_init (vlib_main_t *vm) -{ - cnat_ipv4_tcp_outside_input_main_t * mp = &cnat_ipv4_tcp_outside_input_main; - - mp->vlib_main = vm; - mp->vnet_main = vnet_get_main(); - - return 0; -} - -VLIB_INIT_FUNCTION (cnat_ipv4_tcp_outside_input_init); diff --git a/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp.h b/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp.h deleted file mode 100644 index 1ccf74a0..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - *----------------------------------------------------------------------------- - * - * Filename: cnat_ipv4_udp.h - * - * Description: common functions for udp node - * - * Assumptions and Constraints: - * - * Copyright (c) 2000-2009 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *----------------------------------------------------------------------------- - */ - -#ifndef __CNAT_IPV4_UDP_H__ -#define __CNAT_IPV4_UDP_H__ - -#include "tcp_header_definitions.h" -#include "cnat_db.h" -#include "cnat_v4_functions.h" -#include "cnat_global.h" -#include "cnat_config.h" - -extern void swap_ip_src_udp_port(ipv4_header *ip, - udp_hdr_type_t *udp, - cnat_main_db_entry_t *db); -extern void swap_ip_dst_udp_port(ipv4_header *ip, - udp_hdr_type_t *udp, - cnat_main_db_entry_t *db, - u16 vrf); -#endif /* __CNAT_IPV4_UDP_H__ */ diff --git a/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_inside_input.c b/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_inside_input.c deleted file mode 100644 index 657c5f1e..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_inside_input.c +++ /dev/null @@ -1,508 +0,0 @@ -/* - *--------------------------------------------------------------------------- - * cnat_ipv4_udp_inside_input.c - cnat_ipv4_udp_inside_input node functions - * - * - * Copyright (c) 2008-2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *--------------------------------------------------------------------------- - */ - -#include -#include -#include -#include - -#include "cnat_global.h" -#include "cnat_db.h" -#include "cnat_ipv4_udp.h" -#include "cnat_pcp_server.h" - - -#define foreach_cnat_ipv4_udp_inside_input_error \ -_(CNAT_V4_UDP_I2O_T_PKT, "v4 udp i2o transmit") \ -_(CNAT_V4_UDP_I2O_MISS_PKT, "v4 udp i2o db miss") \ -_(CNAT_V4_UDP_I2O_TTL_GEN, "v4 udp i2o TTL gen") \ -_(CNAT_V4_UDP_I2O_TTL_DROP, "v4 udp i2o TTL drop") \ -_(CNAT_V4_PCP_PKT, "v4 pcp pkt") \ -_(CNAT_V4_UDP_I2O_SESSION_DROP, "v4 udp i2o session drop") - -typedef enum { -#define _(sym,str) sym, - foreach_cnat_ipv4_udp_inside_input_error -#undef _ - CNAT_IPV4_UDP_INSIDE_INPUT_N_ERROR, -} cnat_ipv4_udp_inside_input_t; - -static char * cnat_ipv4_udp_inside_input_error_strings[] = { -#define _(sym,string) string, - foreach_cnat_ipv4_udp_inside_input_error -#undef _ -}; - -typedef struct { - u32 cached_next_index; - /* $$$$ add data here */ - - /* convenience variables */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; -} cnat_ipv4_udp_inside_input_main_t; - -typedef enum { - CNAT_V4_I2O_FIXME, - CNAT_V4_UDP_I2O_E, - CNAT_REWRITE_OUTPUT, - CNAT_V4_UDP_I2O_T = CNAT_REWRITE_OUTPUT, - CNAT_N_NEXT, -} cnat_ipv4_udp_inside_input_next_t; - -#define CNAT_V4_UDP_I2O_D CNAT_V4_I2O_FIXME -#define CNAT_V4_PCP_T CNAT_V4_I2O_FIXME - -cnat_ipv4_udp_inside_input_main_t cnat_ipv4_udp_inside_input_main; -vlib_node_registration_t cnat_ipv4_udp_inside_input_node; - -#define NSTAGES 6 - -/* - * Use the generic buffer metadata + first line of packet data prefetch - * stage function from . This is usually a Good Idea. - */ -#define stage0 generic_stage0 - -#ifndef TOBE_PORTED -static inline u32 -is_pcp_pkt(u32 addr, u16 port) -{ - return CNAT_NO_CONFIG; -} -#else -static inline u32 -is_pcp_pkt(spp_ctx_t *ctx, u32 addr, u16 port) -{ - cnat_vrfmap_t *my_vrfmap = NULL; - u16 my_vrfmap_index; - - my_vrfmap_index = vrf_map_array[ctx->ru.rx.uidb_index]; - - if (PREDICT_TRUE(my_vrfmap_index != VRF_MAP_ENTRY_EMPTY)) { - - my_vrfmap = cnat_map_by_vrf + my_vrfmap_index; - - if (PREDICT_FALSE( port == my_vrfmap->pcp_server_port)) { - if(PREDICT_TRUE(addr == my_vrfmap->pcp_server_addr)) { - return CNAT_SUCCESS; - } - } - } - - return CNAT_NO_CONFIG; -} -#endif - -inline void swap_ip_src_udp_port(ipv4_header *ip, - udp_hdr_type_t *udp, - cnat_main_db_entry_t *db) -{ - /* - * declare varibale - */ - CNAT_UPDATE_L3_L4_CHECKSUM_DECLARE - /* - * calculate checksum - */ - CNAT_UPDATE_L3_L4_CHECKSUM(((u16)(db->in2out_key.k.ipv4)), - ((u16)(db->in2out_key.k.ipv4 >> 16)), - (db->in2out_key.k.port), - (clib_net_to_host_u16(ip->checksum)), - (clib_net_to_host_u16(udp->udp_checksum)), - ((u16)(db->out2in_key.k.ipv4)), - ((u16)(db->out2in_key.k.ipv4 >> 16)), - (db->out2in_key.k.port)) - -/* #define UDP_PACKET_DEBUG 1 */ - -// Temporary debugs which will be suppressed later -#ifdef UDP_PACKET_DEBUG - if (PREDICT_FALSE(udp_inside_packet_dump_enable)) { - printf("\nIn2Out UDP packet before translation"); - print_udp_pkt(ip); - } -#endif - - //set ip header - ip->src_addr = - clib_host_to_net_u32(db->out2in_key.k.ipv4); - ip->checksum = - clib_host_to_net_u16(new_l3_c); - - u16 frag_offset = - clib_net_to_host_u16(ip->frag_flags_offset); - - if(PREDICT_FALSE(frag_offset & IP_FRAG_OFFSET_MASK)) { - return; /* No need to update UDP fields */ - } - //set udp header - udp->src_port = - clib_host_to_net_u16(db->out2in_key.k.port); - - /* - * No easy way to avoid this if check except by using - * complex logic - may not be worth it. - */ - if (PREDICT_TRUE(udp->udp_checksum)) { - udp->udp_checksum = - clib_host_to_net_u16(new_l4_c); - } - -// Temporary debugs which will be suppressed later -#ifdef UDP_PACKET_DEBUG - if (PREDICT_FALSE(udp_inside_checksum_disable)) { - printf("\nIn2Out UDP checksum 0x%x disabled by force", new_l4_c); - udp->udp_checksum = 0; - } - if (PREDICT_FALSE(udp_inside_packet_dump_enable)) { - printf("\nIn2Out UDP packet after translation"); - print_udp_pkt(ip); - } -#endif -} - -static inline void -stage1(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - u64 a, b, c; - u32 bucket; - u8 *prefetch_target; - - vlib_buffer_t * b0 = vlib_get_buffer (vm, buffer_index); - ipv4_header *ip = vlib_buffer_get_current (b0); - u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; - udp_hdr_type_t *udp = (udp_hdr_type_t *)((u8*)ip + ipv4_hdr_len); - - u64 tmp = 0; - tmp = vnet_buffer(b0)->vcgn_uii.key.k.ipv4 = - clib_net_to_host_u32(ip->src_addr); - vnet_buffer(b0)->vcgn_uii.key.k.port = - clib_net_to_host_u16 (udp->src_port); - - tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.port) << 32; - - PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX], - vnet_buffer(b0)->vcgn_uii.key.k.vrf, - CNAT_UDP) - tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.vrf) << 48; - - CNAT_V4_GET_HASH(tmp, bucket, CNAT_MAIN_HASH_MASK) - - prefetch_target = (u8 *)(&cnat_in2out_hash[bucket]); - vnet_buffer(b0)->vcgn_uii.bucket = bucket; - - /* Prefetch the hash bucket */ - CLIB_PREFETCH(prefetch_target, CLIB_CACHE_LINE_BYTES, LOAD); -} - -static inline void -stage2(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ /* nothing */ } - -#define SPP_LOG2_CACHE_LINE_BYTES 6 -#define SPP_CACHE_LINE_BYTES (1 << SPP_LOG2_CACHE_LINE_BYTES) - -static inline void -stage3(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index); - uword prefetch_target0, prefetch_target1; - u32 bucket = vnet_buffer(b0)->vcgn_uii.bucket; - - /* read the hash bucket */ - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket - = cnat_in2out_hash[bucket].next; - - if (PREDICT_TRUE(db_index != EMPTY)) { - /* - * Prefetch database keys. We save space by not cache-line - * aligning the DB entries. We don't want to waste LSU - * bandwidth prefetching stuff we won't need. - */ - prefetch_target0 = (uword)(cnat_main_db + db_index); - CLIB_PREFETCH((void*)prefetch_target0, CLIB_CACHE_LINE_BYTES, LOAD); - /* Just beyond DB key #2 */ - prefetch_target1 = prefetch_target0 + - STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports); - /* If the targets are in different lines, do the second prefetch */ - if (PREDICT_FALSE((prefetch_target0 & ~(SPP_CACHE_LINE_BYTES-1)) != - (prefetch_target1 & ~(SPP_CACHE_LINE_BYTES-1)))) { - CLIB_PREFETCH((void *)prefetch_target1, CLIB_CACHE_LINE_BYTES, LOAD); - } - } -} - -static inline void -stage4(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - cnat_main_db_entry_t *db; - vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index); - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket; - - /* - * Note: if the search already failed (empty bucket), - * the answer is already in the pipeline context structure - */ - if (PREDICT_TRUE(db_index != EMPTY)) { - - /* - * Note: hash collisions suck. We can't easily prefetch around them. - * The first trip around the track will be fast. After that, maybe - * not so much... - */ - do { - db = cnat_main_db + db_index; - if (PREDICT_TRUE(db->in2out_key.key64 == - vnet_buffer(b0)->vcgn_uii.key.key64)) { - break; - } - db_index = db->in2out_hash.next; - } while (db_index != EMPTY); - - /* Stick the answer back into the pipeline context structure */ - vnet_buffer(b0)->vcgn_uii.bucket = db_index; - } -} - -static u64 pkt_num = 0; -static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node, - u32 bi) -{ - vlib_buffer_t *b0 = vlib_get_buffer (vm, bi); - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket; - spp_ctx_t *ctx = (spp_ctx_t *) &vnet_buffer(b0)->vcgn_uii; - int disposition = CNAT_V4_UDP_I2O_T; - int counter = CNAT_V4_UDP_I2O_T_PKT; - ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0); - u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; - udp_hdr_type_t *udp = (udp_hdr_type_t *)((u8*)ip + ipv4_hdr_len); - vlib_node_t *n = vlib_get_node (vm, cnat_ipv4_udp_inside_input_node.index); - u32 node_counter_base_index = n->error_heap_index; - vlib_error_main_t * em = &vm->error_main; - cnat_session_entry_t *session_db = NULL; - cnat_key_t dest_info; - - pkt_num++; - - if(PREDICT_FALSE(is_pcp_pkt(ip->dest_addr, udp->dest_port) == - CNAT_SUCCESS)) - { - PCP_INCR(input); - disposition = CNAT_V4_PCP_T; - counter = CNAT_V4_PCP_PKT; - - goto pcp_pkt; - } - - if (PLATFORM_HANDLE_TTL_DECREMENT) { - if (PREDICT_FALSE(ip->ttl <= 1)) { - /* Try to generate ICMP error msg, as TTL is <= 1 */ - - if (icmpv4_generate_with_throttling - (ctx, ip, ctx->ru.rx.uidb_index)) { - /* Generated ICMP */ - disposition = CNAT_REWRITE_OUTPUT; - counter = CNAT_V4_UDP_I2O_TTL_GEN; - } else { - /* Could not generated ICMP - drop the packet */ - disposition = CNAT_V4_UDP_I2O_D; - counter = CNAT_V4_UDP_I2O_TTL_DROP; - } - goto drop_pkt; - } - } - if (PREDICT_TRUE(db_index != EMPTY)) { - cnat_main_db_entry_t *db = cnat_main_db + db_index; - - dest_info.k.ipv4 = clib_net_to_host_u32(ip->dest_addr); - - /* MUST revisit: it seems farg is set to 1 for few packets & because of - * this the port is not updated & it becomes 0. Commenting teporarily - * this fargment check & setting dst port with udp dst port value */ - dest_info.k.port = clib_net_to_host_u16(udp->dest_port); - #if 0 // DONOT REMOVE THIS if 0 - if(PREDICT_FALSE(ctx->ru.rx.frag)) { -#ifdef TOBE_PORTED - /* Must have routed through cnat_v4_frag_in2out node */ - u16 *feature_data_ports = (u16 *)&ctx->feature_data[4]; - dest_info.k.port = *feature_data_ports; -#endif - } else { - dest_info.k.port = clib_net_to_host_u16(udp->dest_port); - } - #endif - - - if (PLATFORM_HANDLE_TTL_DECREMENT) { - /* - * Decrement TTL and update IPv4 checksum - */ - ipv4_decr_ttl_n_calc_csum(ip); - } - - if(PREDICT_TRUE(!PLATFORM_DBL_SUPPORT)) { - - /* No DBL support, so just update the destn and proceed */ - db->dst_ipv4 = dest_info.k.ipv4; - db->dst_port = dest_info.k.port; - CNAT_DB_TIMEOUT_RST(db); - goto update_pkt; - } - - if(PREDICT_TRUE((db->dst_ipv4 == dest_info.k.ipv4) && - (db->dst_port == dest_info.k.port))) { - - CNAT_DB_TIMEOUT_RST(db); - goto update_pkt; - } else { - if (PREDICT_FALSE(db->nsessions == 0)) { - /* Should be a static entry - * Note this session as the first session and log - */ - cnat_add_dest_n_log(db, &dest_info); - /* - * update db counter, timer - */ - - CNAT_DB_TIMEOUT_RST(db); - - } else if(PREDICT_TRUE(db->nsessions == 1)) { - /* Destn is not same as in main db. Multiple session - * scenario - */ - //printf(">>> [pkt# %lu] src_ip: 0x%x, db ip: 0x%x, db port: %u; dest ip: 0x%x, dest port: %u\n", - // pkt_num, ntohl(ip->src_addr), db->dst_ipv4, db->dst_port, dest_info.k.ipv4, dest_info.k.port); - - dest_info.k.vrf = db->in2out_key.k.vrf; - session_db = cnat_handle_1to2_session(db, &dest_info); - - if(PREDICT_TRUE(session_db != NULL)) { - /* session exists */ - CNAT_DB_TIMEOUT_RST(session_db); - } else { - /* could not create session db - drop packet */ - disposition = CNAT_V4_UDP_I2O_D; - counter = CNAT_V4_UDP_I2O_SESSION_DROP; - goto drop_pkt; - } - - } else { - /* More than 2 sessions exists */ - - dest_info.k.vrf = db->in2out_key.k.vrf; - - /* If session already exists, - * cnat_create_session_db_entry will return the existing db - * else create a new db - * If could not create, return NULL - */ - session_db = cnat_create_session_db_entry(&dest_info, - db, TRUE); - - if(PREDICT_FALSE(session_db != NULL)) { - /* session exists */ - CNAT_DB_TIMEOUT_RST(session_db); - } else { - /* could not create session db - drop packet */ - disposition = CNAT_V4_UDP_I2O_D; - counter = CNAT_V4_UDP_I2O_SESSION_DROP; - goto drop_pkt; - } - } - } - -update_pkt: - /* - * 1. update src ipv4 addr and src udp port - * 2. update ipv4 checksum and udp checksum - */ - swap_ip_src_udp_port(ip, udp, db); - /* - * update db counter, timer - */ - - db->in2out_pkts++; - - /* - * need to set outside vrf - * from db->out2in_key.k.vrf - */ - - /* Temporarily keeping this commented */ - //PLATFORM_CNAT_SET_TX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_TX], - // db->out2in_key.k.vrf) - - in2out_forwarding_count++; - - } else { - disposition = CNAT_V4_UDP_I2O_E; - counter = CNAT_V4_UDP_I2O_MISS_PKT; - } - -drop_pkt: -pcp_pkt: - - em->counters[node_counter_base_index + counter] += 1; - - return disposition; -} - -#include - -static uword cnat_ipv4_udp_inside_input_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return dispatch_pipeline (vm, node, frame); -} - - -VLIB_REGISTER_NODE (cnat_ipv4_udp_inside_input_node) = { - .function = cnat_ipv4_udp_inside_input_node_fn, - .name = "vcgn-v4-udp-i2o", - .vector_size = sizeof (u32), - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(cnat_ipv4_udp_inside_input_error_strings), - .error_strings = cnat_ipv4_udp_inside_input_error_strings, - - .n_next_nodes = CNAT_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [CNAT_V4_I2O_FIXME] = "error-drop", - // [CNAT_V4_UDP_I2O_T] = "ip4-input", - [CNAT_V4_UDP_I2O_E] = "vcgn-v4-udp-i2o-e", - [CNAT_REWRITE_OUTPUT] = "ip4-input", - }, -}; - -clib_error_t *cnat_ipv4_udp_inside_input_init (vlib_main_t *vm) -{ - cnat_ipv4_udp_inside_input_main_t * mp = &cnat_ipv4_udp_inside_input_main; - - mp->vlib_main = vm; - mp->vnet_main = vnet_get_main(); - - return 0; -} - -VLIB_INIT_FUNCTION (cnat_ipv4_udp_inside_input_init); diff --git a/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_inside_input_exceptions.c b/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_inside_input_exceptions.c deleted file mode 100644 index f078c8d4..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_inside_input_exceptions.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - *--------------------------------------------------------------------------- - * cnat_ipv4_udp_inside_input_exception_stages.c - cnat_ipv4_udp_inside_input_exception node pipeline stage functions - * - * - * Copyright (c) 2008-2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *--------------------------------------------------------------------------- - */ - -#include -#include -#include -#include - -#include "cnat_global.h" -#include "cnat_db.h" -#include "cnat_ipv4_udp.h" - -/* - * Dump these counters via the "show error" CLI command - */ - -#define foreach_cnat_ipv4_udp_inside_input_exc_error \ -_(CNAT_V4_UDP_I2O_T_PKT, "v4 udp i2o transmit") \ -_(CNAT_V4_UDP_I2O_D_PKT, "v4 udp i2o drop") \ -_(CNAT_V4_ICMP_G_I2O_T_PKT, "v4 udp i2o icmp msg gen") \ -_(CNAT_V4_UDP_I2O_DC_PKT, "v4 udp i2o (no config) drop") \ -_(CNAT_V4_UDP_I2O_DR_PKT, "v4 udp i2o (not in run state) drop") \ -_(CNAT_V4_UDP_I2O_DD_PKT, "v4 udp i2o (no direct port) drop") \ -_(CNAT_V4_UDP_I2O_DA_PKT, "v4 udp i2o (no any port) drop") \ -_(CNAT_V4_UDP_I2O_DO_PKT, "v4 udp i2o (out of port limit) drop") \ -_(CNAT_V4_UDP_I2O_DI_PKT, "v4 udp i2o (invalid packet) drop") \ -_(CNAT_V4_UDP_I2O_DS_PKT, "v4 udp i2o (no sessoon db) drop") - -typedef enum { -#define _(sym,str) sym, - foreach_cnat_ipv4_udp_inside_input_exc_error -#undef _ - CNAT_IPV4_UDP_INSIDE_INPUT_EXCEPTIONS_N_ERROR, -} cnat_ipv4_udp_inside_input_exc_error_t; - - -static char * cnat_ipv4_udp_inside_input_exc_error_strings[] = { -#define _(sym,string) string, - foreach_cnat_ipv4_udp_inside_input_exc_error -#undef _ -}; - -typedef struct { - u32 cached_next_index; - /* $$$$ add data here */ - - /* convenience variables */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; -} cnat_ipv4_udp_inside_input_exc_main_t; - -typedef enum { - CNAT_V4_UDP_I2O_T, - CNAT_V4_UDP_I2O_D, - CNAT_V4_ICMP_G_I2O_T = CNAT_V4_UDP_I2O_D, /* TOBE_PORTED */ - CNAT_V4_UDP_INSIDE_INPUT_EXC_N_NEXT, -} cnat_ipv4_udp_inside_input_exc_next_t; - -cnat_ipv4_udp_inside_input_exc_main_t cnat_ipv4_udp_inside_input_exc_main; -vlib_node_registration_t cnat_ipv4_udp_inside_input_exc_node; - -#define NSTAGES 2 - -/* - * Use the generic buffer metadata + first line of packet data prefetch - * stage function from . This is usually a Good Idea. - */ -#define stage0 generic_stage0 - -static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node, - u32 bi) -{ - vlib_buffer_t *b0 = vlib_get_buffer (vm, bi); - vlib_node_t *n = - vlib_get_node (vm, cnat_ipv4_udp_inside_input_exc_node.index); - u32 node_counter_base_index = n->error_heap_index; - vlib_error_main_t * em = &vm->error_main; - - cnat_gen_icmp_info info; - cnat_db_key_bucket_t ki; - spp_ctx_t *ctx __attribute__((unused)) - = (spp_ctx_t *) &vnet_buffer(b0)->vcgn_uii; - cnat_main_db_entry_t *db = NULL; - ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0); - u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; - udp_hdr_type_t *udp = (udp_hdr_type_t *)((u8*)ip + ipv4_hdr_len); - int disposition = CNAT_V4_UDP_I2O_T; - int counter = CNAT_V4_UDP_I2O_T_PKT; - - cnat_key_t dest_info; - - PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX], - vnet_buffer(b0)->vcgn_uii.key.k.vrf, - CNAT_UDP) - - vnet_buffer(b0)->vcgn_uii.key.k.ipv4 = clib_net_to_host_u32(ip->src_addr); - - PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX], - ki.k.k.vrf, CNAT_UDP) - - ki.k.k.ipv4 = clib_net_to_host_u32(ip->src_addr); - - - /* MUST REVISIT: commentting frag check. Unconditional destination port - * update. DONOT remove this #if 0 */ - ki.k.k.port = - clib_net_to_host_u16(udp->src_port); - dest_info.k.port = - clib_net_to_host_u16(udp->dest_port); -#if 0 - if(PREDICT_FALSE(ctx->ru.rx.frag)) { -#ifdef TOBE_PORTED - /* Must have routed through cnat_v4_frag_in2out node */ - u16 *feature_data_ports = (u16 *)&ctx->feature_data[2]; - ki.k.k.port = *feature_data_ports; - feature_data_ports++; - dest_info.k.port = *feature_data_ports; -#endif - } else { - ki.k.k.port = - clib_net_to_host_u16(udp->src_port); - dest_info.k.port = - clib_net_to_host_u16(udp->dest_port); - } -#endif /* if 0 */ - - dest_info.k.ipv4 = clib_net_to_host_u32(ip->dest_addr); - PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX], - dest_info.k.vrf, CNAT_UDP) - - if (PREDICT_TRUE(ki.k.k.port)) { - if (ki.k.k.port & 0x1) { - db = cnat_get_main_db_entry_v2(&ki, PORT_S_ODD, PORT_TYPE_DYNAMIC, - &info, &dest_info); - } else { - db = cnat_get_main_db_entry_v2(&ki, PORT_S_EVEN, PORT_TYPE_DYNAMIC, - &info, &dest_info); - } - } else { - /* - * No UDP port value of 0 - drop it - */ - db = NULL; - info.error = CNAT_ERR_BAD_TCP_UDP_PORT; - } - - if (PREDICT_TRUE((u64)db)) { - - if (PLATFORM_HANDLE_TTL_DECREMENT) { - /* - * Decrement TTL and update IPv4 checksum - */ - ipv4_decr_ttl_n_calc_csum(ip); - } - - /* - * step 6 do nat before fwd pkt - */ - swap_ip_src_udp_port(ip, udp, db); - /* - * update db for this pkt - */ - CNAT_DB_UPDATE_IN2OUT_TIMER - - /* Check timeout db if there is config for this */ - (void) query_and_update_db_timeout((void *)db, MAIN_DB_TYPE); - -/* Temporarily keeping it commented */ - //PLATFORM_CNAT_SET_TX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_TX], - // db->out2in_key.k.vrf) - in2out_forwarding_count++; - - } else { - switch (info.error) { - case (CNAT_NO_VRF_RUN): - em->counters[node_counter_base_index + CNAT_V4_UDP_I2O_DR_PKT] += 1; - break; - case (CNAT_OUT_LIMIT): - em->counters[node_counter_base_index + CNAT_V4_UDP_I2O_DO_PKT] += 1; - break; - case (CNAT_NO_PORT_ANY): - case (CNAT_NO_POOL_ANY): - case (CNAT_BAD_INUSE_ANY): - case (CNAT_NOT_FOUND_ANY): - em->counters[node_counter_base_index + CNAT_V4_UDP_I2O_DA_PKT] += 1; - break; - case (CNAT_INV_PORT_DIRECT): - case (CNAT_DEL_PORT_DIRECT): - case (CNAT_BAD_INUSE_DIRECT): - case (CNAT_NOT_FOUND_DIRECT): - em->counters[node_counter_base_index + CNAT_V4_UDP_I2O_DD_PKT] += 1; - break; - case (CNAT_ERR_BAD_TCP_UDP_PORT): - em->counters[node_counter_base_index + CNAT_V4_UDP_I2O_DI_PKT] += 1; - break; - case (CNAT_ERR_NO_SESSION_DB): - em->counters[node_counter_base_index + CNAT_V4_UDP_I2O_DS_PKT] += 1; - break; - default: - em->counters[node_counter_base_index + CNAT_V4_UDP_I2O_DC_PKT] += 1; - break; - } - /* - * send to icmp msg generate node - */ - if (info.gen_icmp_msg == CNAT_ICMP_MSG) { -#ifdef TOBE_PORTED - u32 *fd = (u32*)ctx->feature_data; - fd[0] = info.svi_addr; - fd[1] = CNAT_ICMP_DEST_UNREACHABLE; -#endif - disposition = CNAT_V4_ICMP_G_I2O_T; - counter = CNAT_V4_ICMP_G_I2O_T_PKT; - } else { - disposition = CNAT_V4_UDP_I2O_D; - counter = CNAT_V4_UDP_I2O_D_PKT; - } - DEBUG_I2O_DROP(CNAT_DEBUG_DROP_UDP) - } - - em->counters[node_counter_base_index + counter] += 1; - - return disposition; -} - - -#include - -static uword cnat_ipv4_udp_inside_input_exc_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return dispatch_pipeline (vm, node, frame); -} - -VLIB_REGISTER_NODE (cnat_ipv4_udp_inside_input_exc_node) = { - .function = cnat_ipv4_udp_inside_input_exc_node_fn, - .name = "vcgn-v4-udp-i2o-e", - .vector_size = sizeof (u32), - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(cnat_ipv4_udp_inside_input_exc_error_strings), - .error_strings = cnat_ipv4_udp_inside_input_exc_error_strings, - - .n_next_nodes = CNAT_V4_UDP_INSIDE_INPUT_EXC_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [CNAT_V4_UDP_I2O_T] = "ip4-input", - [CNAT_V4_UDP_I2O_D] = "error-drop", - }, -}; - - -clib_error_t *cnat_ipv4_udp_inside_input_exc_init (vlib_main_t *vm) -{ - cnat_ipv4_udp_inside_input_exc_main_t * mp = &cnat_ipv4_udp_inside_input_exc_main; - - mp->vlib_main = vm; - mp->vnet_main = vnet_get_main(); - - return 0; -} - -VLIB_INIT_FUNCTION (cnat_ipv4_udp_inside_input_exc_init); - diff --git a/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_outside_input.c b/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_outside_input.c deleted file mode 100644 index 5a24a111..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_outside_input.c +++ /dev/null @@ -1,605 +0,0 @@ - -/* - *--------------------------------------------------------------------------- - * cnat_ipv4_udp_outside_input_stages.c - cnat_ipv4_udp_outside_input node pipeline stage functions - * - * - * Copyright (c) 2008-2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *--------------------------------------------------------------------------- - */ - -#include -#include -#include -#include - -#include "cnat_ipv4_udp.h" -#include "dslite_db.h" -#include "cnat_db.h" -#include "cnat_v4_functions.h" - -//#include -//#include -//#include "cnat_va_db.h" - -#define foreach_cnat_ipv4_udp_outside_input_error \ -_(CNAT_V4_UDP_O2I_T_PKT, "v4 udp o2i transmit") \ -_(CNAT_V4_DSLITE_ENCAP_CTR, "to dslite encap") \ -_(CNAT_V4_UDP_O2I_MISS_PKT, "v4 udp o2i db miss drop") \ -_(CNAT_V4_UDP_O2I_TTL_GEN, "v4 udp o2i TTL gen") \ -_(CNAT_V4_UDP_O2I_TTL_DROP, "v4 udp o2i TTL drop") \ -_(CNAT_V4_UDP_O2I_PTB_GEN, "v4 ptb gen") \ -_(CNAT_V4_UDP_O2I_PTB_DROP, "v4 ptb throttle drop") \ -_(CNAT_V4_UDP_O2I_SESSION_DROP, "v4 udp o2i session drop") \ -_(CNAT_V4_UDP_O2I_FILTER_DROP, "v4 udp o2i drop: end point filtering") \ -_(CNAT_V4_UDP_O2I_SUB_FRAG_NO_DB_DROP, "v4 udp o2i subsequent frag no DB drop") \ -_(CNAT_V4_UDP_O2I_1ST_FRAG_FILTER_DROP, "v4 udp i2o 1st frag filter drop") - -typedef enum { -#define _(sym,str) sym, - foreach_cnat_ipv4_udp_outside_input_error -#undef _ - CNAT_IPV4_UDP_OUTSIDE_INPUT_N_ERROR, -} cnat_ipv4_udp_outside_input_t; - -static char * cnat_ipv4_udp_outside_input_error_strings[] = { -#define _(sym,string) string, - foreach_cnat_ipv4_udp_outside_input_error -#undef _ -}; - -typedef struct { - u32 cached_next_index; - /* $$$$ add data here */ - - /* convenience variables */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; -} cnat_ipv4_udp_outside_input_main_t; - -typedef enum { - //CNAT_V4_O2I_FIXME, - CNAT_V4_UDP_O2I_E, - CNAT_V4_UDP_O2I_T, - CNAT_V4_UDP_O2I_NEXT, -} cnat_ipv4_udp_outside_input_next_t; - -//#define CNAT_V4_DSLITE_ENCAP CNAT_V4_O2I_FIXME -//#define CNAT_V4_UDP_O2I_E CNAT_V4_O2I_FIXME - -cnat_ipv4_udp_outside_input_main_t cnat_ipv4_udp_outside_input_main; -vlib_node_registration_t cnat_ipv4_udp_outside_input_node; - -#define NSTAGES 6 - -/* - * Use the generic buffer metadata + first line of packet data prefetch - * stage function from . This is usually a Good Idea. - */ -#define stage0 generic_stage0 - - -#if 0 -typedef struct cnat_ipv4_udp_outside_input_pipeline_data_ { - //spp_node_main_vector_t *nmv; - dslite_common_pipeline_data_t common_data; - /* Add additional pipeline stage data here... */ - u32 bucket; -#ifdef DSLITE_DEF - u32 user_bucket; - dslite_v4_to_v6_udp_counter_t *udp_counter; - dslite_icmp_gen_counter_t *icmp_gen_counter; - -#endif - cnat_key_t ki; - udp_hdr_type_t *udp; - u8 frag_pkt; -} cnat_ipv4_udp_outside_input_pipeline_data_t; - -#endif - -#define CNAT_UDP_OUTSIDE_UPDATE_FLAG_TIMER(db,dslite_nat44_inst_id) \ - if (PREDICT_FALSE(!(db->flags & CNAT_DB_FLAG_UDP_ACTIVE))) { \ - db->flags |= CNAT_DB_FLAG_UDP_ACTIVE; \ - CNAT_DB_TIMEOUT_RST(db); \ - } else if (PREDICT_FALSE(db->flags & CNAT_DB_DSLITE_FLAG)) { \ - if (PREDICT_TRUE(dslite_table_db_ptr[dslite_nat44_inst_id].mapping_refresh_both_direction)) { \ - CNAT_DB_TIMEOUT_RST(db); \ - } \ - } else if (PREDICT_TRUE(mapping_refresh_both_direction)) { \ - CNAT_DB_TIMEOUT_RST(db); \ - } \ - -#if 0 -static cnat_ipv4_udp_outside_input_pipeline_data_t pctx_data[SPP_MAXDISPATCH]; -#define EXTRA_PIPELINE_ARGS_PROTO , cnat_ipv4_udp_outside_input_pipeline_data_t *pctx -#define EXTRA_PIPELINE_ARGS , pctx - -#endif - -/*inline u32 -is_static_dest_nat_enabled(u16 vrf) -{ - if(static_dest_vrf_map_array[vrf] == 1) { - return CNAT_SUCCESS; - } - return CNAT_NO_CONFIG; -}*/ - -static inline void __attribute__((unused)) -swap_ip_dst(ipv4_header *ip, cnat_main_db_entry_t *db, u16 vrf) -{ - - CNAT_UPDATE_L3_CHECKSUM_DECLARE - /* - * calculate checksum - */ - CNAT_UPDATE_L3_CHECKSUM(((u16)(db->out2in_key.k.ipv4)), - ((u16)(db->out2in_key.k.ipv4 >> 16)), - (clib_host_to_net_u16(ip->checksum)), - ((u16)(db->in2out_key.k.ipv4)), - ((u16)(db->in2out_key.k.ipv4 >> 16))) - //set ip header - ip->dest_addr = - clib_host_to_net_u32(db->in2out_key.k.ipv4); - ip->checksum = - clib_host_to_net_u16(new_l3_c); - -#if 0 - - if(is_static_dest_nat_enabled(vrf) == CNAT_SUCCESS) { - direction = 1; - if(cnat_static_dest_db_get_translation(ip->src_addr, &postmap_ip, vrf, direction) == CNAT_SUCCESS) { - old_ip = spp_net_to_host_byte_order_32(&(ip->src_addr)); - old_postmap_ip = spp_net_to_host_byte_order_32(&postmap_ip); - - CNAT_UPDATE_L3_CHECKSUM(((u16)(old_ip & 0xFFFF)), - ((u16)(old_ip >> 16)), - (spp_net_to_host_byte_order_16(&(ip->checksum))), - ((u16)(old_postmap_ip & 0xFFFF)), - ((u16)(old_postmap_ip >> 16))) - ip->checksum = - clib_host_to_net_u16(new_l3_c); - ip->src_addr = postmap_ip; - } - } -#endif -} - -inline void swap_ip_dst_udp_port(ipv4_header *ip, - udp_hdr_type_t *udp, - cnat_main_db_entry_t *db, u16 vrf) -{ - -#define UDP_PACKET_DEBUG 1 - -// Temporary debugs which will be suppressed later -#ifdef UDP_PACKET_DEBUG - if (PREDICT_FALSE(udp_outside_packet_dump_enable)) { - printf("\nOut2In UDP packet before translation"); - print_udp_pkt(ip); - } -#endif - -#if 0 - if(is_static_dest_nat_enabled(vrf) == CNAT_SUCCESS) { - direction = 1; - if(cnat_static_dest_db_get_translation(ip->src_addr, &postmap_ip, vrf, direction) == CNAT_SUCCESS) { - - CNAT_UPDATE_L3_L4_CHECKSUM_DECLARE - - old_ip = spp_net_to_host_byte_order_32(&(ip->src_addr)); - old_postmap_ip = spp_net_to_host_byte_order_32(&postmap_ip); - - CNAT_UPDATE_L3_L4_CHECKSUM(((u16)(old_ip & 0xFFFF)), - ((u16)(old_ip >> 16)), - (spp_net_to_host_byte_order_16(&(udp->src_port))), - (spp_net_to_host_byte_order_16(&(ip->checksum))), - (spp_net_to_host_byte_order_16(&(udp->udp_checksum))), - ((u16)(old_postmap_ip & 0xFFFF)), - ((u16)(old_postmap_ip >> 16)), - (spp_net_to_host_byte_order_16(&(udp->src_port)))) - - ip->checksum = - clib_host_to_net_u16(new_l3_c); - ip->src_addr = postmap_ip; - if (PREDICT_TRUE(udp->udp_checksum)) { - udp->udp_checksum = clib_host_to_net_u16(new_l4_c); - } - } - } -#endif - /* - * declare variable - */ - CNAT_UPDATE_L3_L4_CHECKSUM_DECLARE - /* - * calculate checksum - */ - CNAT_UPDATE_L3_L4_CHECKSUM(((u16)(db->out2in_key.k.ipv4)), - ((u16)(db->out2in_key.k.ipv4 >> 16)), - (db->out2in_key.k.port), - (clib_net_to_host_u16(ip->checksum)), - (clib_net_to_host_u16(udp->udp_checksum)), - ((u16)(db->in2out_key.k.ipv4)), - ((u16)(db->in2out_key.k.ipv4 >> 16)), - (db->in2out_key.k.port)) - - - - - //set ip header - ip->dest_addr = - clib_host_to_net_u32(db->in2out_key.k.ipv4); - ip->checksum = - clib_host_to_net_u16(new_l3_c); - - //set udp header - udp->dest_port = - clib_host_to_net_u16(db->in2out_key.k.port); - - /* - * No easy way to avoid this if check except by using - * complex logic - may not be worth it. - */ - if (PREDICT_TRUE(udp->udp_checksum)) { - udp->udp_checksum = clib_host_to_net_u16(new_l4_c); - } - - - -// Temporary debugs which will be suppressed later -#ifdef UDP_PACKET_DEBUG - if (PREDICT_FALSE(udp_outside_checksum_disable)) { - printf("\nOut2In UDP checksum 0x%x disabled by force", new_l4_c); - udp->udp_checksum = 0; - } - if (PREDICT_FALSE(udp_outside_packet_dump_enable)) { - printf("\nOut2In UDP packet after translation"); - print_udp_pkt(ip); - } -#endif -} - -static inline void -stage1(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - u64 a, b, c; - u32 bucket; - u8 *prefetch_target; - - vlib_buffer_t * b0 = vlib_get_buffer (vm, buffer_index); - ipv4_header *ip = vlib_buffer_get_current (b0); - u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; - udp_hdr_type_t *udp = (udp_hdr_type_t *)((u8*)ip + ipv4_hdr_len); - - u64 tmp = 0; - tmp = vnet_buffer(b0)->vcgn_uii.key.k.ipv4 = - clib_net_to_host_u32(ip->dest_addr); - vnet_buffer(b0)->vcgn_uii.key.k.port = - clib_net_to_host_u16 (udp->dest_port); - - tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.port) << 32; - - PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX], - vnet_buffer(b0)->vcgn_uii.key.k.vrf, - CNAT_UDP) - tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.vrf) << 48; - - CNAT_V4_GET_HASH(tmp, bucket, CNAT_MAIN_HASH_MASK) - - prefetch_target = (u8 *)(&cnat_out2in_hash[bucket]); - vnet_buffer(b0)->vcgn_uii.bucket = bucket; - - /* Prefetch the hash bucket */ - CLIB_PREFETCH(prefetch_target, CLIB_CACHE_LINE_BYTES, LOAD); -} - -static inline void -stage2(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ /* nothing */ } - -#define SPP_LOG2_CACHE_LINE_BYTES 6 -#define SPP_CACHE_LINE_BYTES (1 << SPP_LOG2_CACHE_LINE_BYTES) - -static inline void -stage3(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index); - uword prefetch_target0, prefetch_target1; - u32 bucket = vnet_buffer(b0)->vcgn_uii.bucket; - - /* read the hash bucket */ - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket - = cnat_out2in_hash[bucket].next; - - if (PREDICT_TRUE(db_index != EMPTY)) { - /* - * Prefetch database keys. We save space by not cache-line - * aligning the DB entries. We don't want to waste LSU - * bandwidth prefetching stuff we won't need. - */ - prefetch_target0 = (uword)(cnat_main_db + db_index); - CLIB_PREFETCH((void*)prefetch_target0, CLIB_CACHE_LINE_BYTES, STORE); - /* Just beyond DB key #2 */ - prefetch_target1 = prefetch_target0 + - STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports); - /* If the targets are in different lines, do the second prefetch */ - if (PREDICT_FALSE((prefetch_target0 & ~(SPP_CACHE_LINE_BYTES-1)) != - (prefetch_target1 & ~(SPP_CACHE_LINE_BYTES-1)))) { - CLIB_PREFETCH((void *)prefetch_target1, CLIB_CACHE_LINE_BYTES, STORE); - } - } -} - -static inline void -stage4(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index) -{ - cnat_main_db_entry_t *db; - vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index); - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket; - - /* - * Note: if the search already failed (empty bucket), - * the answer is already in the pipeline context structure - */ - if (PREDICT_TRUE(db_index != EMPTY)) { - - /* - * Note: hash collisions suck. We can't easily prefetch around them. - * The first trip around the track will be fast. After that, maybe - * not so much... - */ - do { - db = cnat_main_db + db_index; - if (PREDICT_TRUE(db->out2in_key.key64 == - vnet_buffer(b0)->vcgn_uii.key.key64)) { - break; - } - db_index = db->out2in_hash.next; - } while (db_index != EMPTY); - - /* Stick the answer back into the pipeline context structure */ - vnet_buffer(b0)->vcgn_uii.bucket = db_index; - } -} - -#if 0 - -ALWAYS_INLINE( -static inline void -stage5(spp_ctx_t **ctxs, int index, spp_node_t *np, - u8 *disp_used EXTRA_PIPELINE_ARGS_PROTO)) -{ - spp_ctx_t *ctx = ctxs[index]; - u32 db_index = pctx[index].bucket; - /* for nat44, dslite_id will be 1 */ - u16 dslite_id = *(pctx[index].common_data.dslite_id_ptr); - - DSLITE_PREFETCH_COUNTER(pctx[index].udp_counter, - &dslite_all_counters[dslite_id].v46_udp_counters, - dslite_v4_to_v6_udp_counter_t, - v4_to_v6_udp_output_count, - "V4_TO_V6_UDP") - - DSLITE_PREFETCH_COUNTER(pctx[index].icmp_gen_counter, - &dslite_all_counters[dslite_id].dslite_icmp_gen_counters, - dslite_icmp_gen_counter_t, - v6_icmp_gen_count, - "V4_TO_V6_icmp") - -if (PREDICT_TRUE(db_index != EMPTY)) { - cnat_main_db_entry_t *db = cnat_main_db + db_index; - - u32 user_db_index = db->user_index; - DSLITE_PRINTF(1, "UDP o2i, db entry found %u %u %u\n", - db_index, user_db_index, - db->dslite_nat44_inst_id); - uword prefetch_target0 = (uword)(cnat_user_db + user_db_index); - SPP_PREFETCH(prefetch_target0, 0, LOAD); - pctx[index].user_bucket = user_db_index; - DSLITE_PRINTF(1, "UDP: Done with prefetch..\n"); -} else { - DSLITE_PRINTF(1, "UDP: Stage 5, db_index empty...\n"); -} -} - -#endif - - -static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node, - u32 bi) -{ - - vlib_buffer_t *b0 = vlib_get_buffer (vm, bi); - u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket; - //spp_ctx_t *ctx = (spp_ctx_t *) &vnet_buffer(b0)->vcgn_uii; - int disposition = CNAT_V4_UDP_O2I_T; - int counter = CNAT_V4_UDP_O2I_T_PKT; - ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0); - u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; - udp_hdr_type_t *udp = (udp_hdr_type_t *)((u8*)ip + ipv4_hdr_len); - vlib_node_t *n = vlib_get_node (vm, cnat_ipv4_udp_outside_input_node.index); - u32 node_counter_base_index = n->error_heap_index; - vlib_error_main_t * em = &vm->error_main; - cnat_session_entry_t *session_db = NULL; - cnat_main_db_entry_t *db = NULL; - cnat_key_t dest_info; - u16 dslite_nat44_inst_id __attribute__((unused)) = 0; - - dest_info.k.port = clib_net_to_host_u16(udp->src_port); - dest_info.k.ipv4 = clib_net_to_host_u32(ip->src_addr); - - if (PREDICT_TRUE(db_index != EMPTY)) { - /* TTL gen was disabled for nat44 earlier - * But since dslite has got integrated in this - * TTL gen is enabled - */ - - db = cnat_main_db + db_index; - if (PLATFORM_HANDLE_TTL_DECREMENT) { - /* - * Decrement TTL and update IPv4 checksum - */ - ipv4_decr_ttl_n_calc_csum(ip); - } - if(PREDICT_TRUE(!PLATFORM_DBL_SUPPORT)) { - - /* No DBL support, so just update the destn and proceed */ - db->dst_ipv4 = dest_info.k.ipv4; - db->dst_port = dest_info.k.port; - CNAT_UDP_OUTSIDE_UPDATE_FLAG_TIMER(db, 0) - goto update_pkt; - } - - - if(PREDICT_TRUE((db->dst_ipv4 == dest_info.k.ipv4) && - (db->dst_port == dest_info.k.port))) { - - CNAT_UDP_OUTSIDE_UPDATE_FLAG_TIMER(db, 0) - goto update_pkt; - } else { - /* The session entries belonging to this entry are checked to find - * if an entry exist whose destination IP and port match with the - * source IP and port of the packet being processed - */ - dest_info.k.vrf = db->in2out_key.k.vrf; - - if (PREDICT_FALSE(db->nsessions == 0)) { - /* Should be a static entry - * Note this session as the first session and log - */ - cnat_add_dest_n_log(db, &dest_info); - CNAT_UDP_OUTSIDE_UPDATE_FLAG_TIMER(db, 0) - - } else if(PREDICT_TRUE(db->nsessions == 1)) { - - /* Destn is not same as in main db. Multiple session - * scenario - */ - dest_info.k.vrf = db->in2out_key.k.vrf; - session_db = cnat_handle_1to2_session(db, &dest_info); - - if(PREDICT_FALSE(session_db == NULL)) { - disposition = CNAT_V4_UDP_O2I_E; - counter = CNAT_V4_UDP_O2I_SESSION_DROP; - goto drop_pkt; - } - - /* update session_db(cur packet) timer */ - CNAT_UDP_OUTSIDE_UPDATE_FLAG_TIMER(session_db, 0) - } else { - /* More 2 sessions exists */ - - dest_info.k.vrf = db->in2out_key.k.vrf; - - /* If session already exists, - * cnat_create_session_db_entry will return the existing db - * else create a new db - * If could not create, return NULL - */ - session_db = cnat_create_session_db_entry(&dest_info, - db, TRUE); - - if(PREDICT_FALSE(session_db != NULL)) { - /* session exists */ - CNAT_UDP_OUTSIDE_UPDATE_FLAG_TIMER(session_db, 0) - } else { - /* could not create session db - drop packet */ - disposition = CNAT_V4_UDP_O2I_E; - counter = CNAT_V4_UDP_O2I_SESSION_DROP; - goto drop_pkt; - } - } - } - -update_pkt: - - /* - * 1. update dest ipv4 addr and dest udp port - * 2. update ipv4 checksum and udp checksum - */ - //swap_ip_dst(ip, db, db->in2out_key.k.vrf); - swap_ip_dst_udp_port(ip, udp, db, db->in2out_key.k.vrf); - //DSLITE_PRINTF(1, "Done with swap_ip_dst_udp_port..\n"); - - db->out2in_pkts++; - - nat44_dslite_global_stats[0].out2in_forwarding_count++; - - /* #### Temporarily COMMENTED FOR IP ROUTE LOOKUP ISSUE #### */ - - //PLATFORM_CNAT_SET_TX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_TX], - // db->in2out_key.k.vrf) - } else { - disposition = CNAT_V4_UDP_O2I_E; - counter = CNAT_V4_UDP_O2I_MISS_PKT; - /* for NAT44 dslite_id would be 1 */ - nat44_dslite_common_stats[0].no_translation_entry_drops ++; - } - -drop_pkt: - - em->counters[node_counter_base_index + counter] += 1; - return disposition; -} - -#include - -static uword cnat_ipv4_udp_outside_input_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return dispatch_pipeline (vm, node, frame); -} - - -VLIB_REGISTER_NODE (cnat_ipv4_udp_outside_input_node) = { - .function = cnat_ipv4_udp_outside_input_node_fn, - .name = "vcgn-v4-udp-o2i", - .vector_size = sizeof (u32), - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(cnat_ipv4_udp_outside_input_error_strings), - .error_strings = cnat_ipv4_udp_outside_input_error_strings, - - .n_next_nodes = CNAT_V4_UDP_O2I_NEXT, - - /* edit / add dispositions here */ -#if 0 - .next_nodes = { - //[CNAT_V4_O2I_FIXME] = "error-drop", - //[CNAT_V4_UDP_O2I_E] = "vcgn-v4-udp-o2i-e", - [CNAT_V4_UDP_O2I_E] = "vcgn-v4-udp-o2i-e", - [CNAT_V4_UDP_O2I_T] = "ip4-input", - }, -#endif - .next_nodes = { - [CNAT_V4_UDP_O2I_E] = "error-drop", - [CNAT_V4_UDP_O2I_T] = "ip4-input", - }, - -}; - -clib_error_t *cnat_ipv4_udp_outside_input_init (vlib_main_t *vm) -{ - cnat_ipv4_udp_outside_input_main_t * mp = &cnat_ipv4_udp_outside_input_main; - - mp->vlib_main = vm; - mp->vnet_main = vnet_get_main(); - - return 0; -} - -VLIB_INIT_FUNCTION (cnat_ipv4_udp_outside_input_init); diff --git a/plugins/vcgn-plugin/vcgn/cnat_log_api.h b/plugins/vcgn-plugin/vcgn/cnat_log_api.h deleted file mode 100644 index 60cf6836..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_log_api.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_log_api.h - * Declraes the common APIs for logging (both syslog and NFV9) - * Copyright (c) 2013, 20122 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef __CNAT_LOG_API_H__ -#define __CNAT_LOG_API_H__ - -#include "cnat_logging.h" - -static inline void cnat_log_ds_lite_mapping_delete(cnat_main_db_entry_t *db, - dslite_table_entry_t *dslite_entry -#ifndef NO_BULK_LOGGING - , int bulk_alloc -#endif - ) -{ - return; -} - -static inline void cnat_log_ds_lite_mapping_create(cnat_main_db_entry_t *db, - dslite_table_entry_t *dslite_entry -#ifndef NO_BULK_LOGGING - , int bulk_alloc -#endif - ) -{ - return; -} - -static inline void cnat_log_ds_lite_port_limit_exceeded( - dslite_key_t * key, - dslite_table_entry_t *dslite_entry_ptr) -{ - return; - -} - -static inline void cnat_log_nat44_port_limit_exceeded( - cnat_key_t * key, - cnat_vrfmap_t *vrfmap) -{ - return; -} -static inline void cnat_log_nat44_mapping_create(cnat_main_db_entry_t *db, - cnat_vrfmap_t *vrfmap -#ifndef NO_BULK_LOGGING - , int bulk_alloc -#endif - ) -{ - return; -} - -static inline void cnat_log_nat44_mapping_delete(cnat_main_db_entry_t *db, - cnat_vrfmap_t *vrfmap -#ifndef NO_BULK_LOGGING - , int bulk_alloc -#endif - ) -{ - return; -} - -/* Session Logging API for nat44 */ -static inline void cnat_session_log_nat44_mapping_create ( - cnat_main_db_entry_t *db, - cnat_session_entry_t *sdb, - cnat_vrfmap_t *vrfmap ) -{ - return; -} - -static inline void cnat_session_log_nat44_mapping_delete ( - cnat_main_db_entry_t *db, - cnat_session_entry_t *sdb, - cnat_vrfmap_t *vrfmap ) -{ - return; -} - -/* Session Logging API for dslite */ -static inline void cnat_session_log_ds_lite_mapping_create ( - cnat_main_db_entry_t *db, - dslite_table_entry_t *dslite_entry, - cnat_session_entry_t *sdb ) -{ - return; -} - -static inline void cnat_session_log_ds_lite_mapping_delete ( - cnat_main_db_entry_t *db, - dslite_table_entry_t *dslite_entry, - cnat_session_entry_t *sdb ) -{ - return; -} - -#endif /* #ifndef __CNAT_LOG_API_H__ */ - diff --git a/plugins/vcgn-plugin/vcgn/cnat_log_common.h b/plugins/vcgn-plugin/vcgn/cnat_log_common.h deleted file mode 100644 index 52731bc0..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_log_common.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_log_common.h - * Contains macros and definitions that are common to both syslog and nfv9 - * Copyright (c) 2011-2012 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef __CNAT_LOG_COMMON_H__ -#define __CNAT_LOG_COMMON_H__ - -#include -#include -#include - -#include "cnat_db.h" -#include "nat64_db.h" -#include "spp_timers.h" -#include "spp_ctx.h" - -/* - * This corresponds to the length of the IMETRO SHIM Header for RODDICK - * For non-roddick cases, introduce an Ethernet header as well - */ -#if 0 - #if defined(TARGET_RODDICK) - #define CNAT_NFV9_SHIM_HDR_OFFSET 8 - #define CNAT_NFV9_L2_ENCAPS_OFFSET 0 - #else - #define CNAT_NFV9_SHIM_HDR_OFFSET 0 - #define CNAT_NFV9_L2_ENCAPS_OFFSET 16 - #endif -#endif - - #define CNAT_NFV9_IP_HDR_OFFSET 0 - - #define CNAT_NFV9_UDP_HDR_OFFSET \ - (CNAT_NFV9_IP_HDR_OFFSET + sizeof(ipv4_header)) - - #define CNAT_NFV9_HDR_OFFSET \ - (CNAT_NFV9_UDP_HDR_OFFSET + sizeof(udp_hdr_type_t)) - -u32 cnat_get_sys_up_time_in_ms(void); -u32 cnat_get_unix_time_in_seconds(void); -void cnat_dump_time_change_logs(void); -void cnat_handle_sys_time_change (time_t current_unix_time); -/* - * Maximum number of time log changes we maintain - */ - -#define MAX_TIME_CHANGE_LOGS (8) - -typedef struct { - /* - * A timer structure to periodically send NFv9 & syslog logging packets - * that have been waiting to be full for a long time. This will - * ensure add/delete events don't get delayed too much before they - * are sent to the collector. - */ - spp_timer_t log_timer; - - /* - * Whether we have initialized the NFv9 information - */ - u8 cnat_log_init_done; -} cnat_log_global_info_t; - -#endif /* __CNAT_LOG_COMMON_H__ */ diff --git a/plugins/vcgn-plugin/vcgn/cnat_logging.c b/plugins/vcgn-plugin/vcgn/cnat_logging.c deleted file mode 100644 index 71f156a9..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_logging.c +++ /dev/null @@ -1,3500 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_logging.c - * - * Copyright (c) 2009-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include "cnat_config.h" -#include "cnat_global.h" -#include "cnat_v4_functions.h" -#include "tcp_header_definitions.h" -#include "cnat_v4_ftp_alg.h" -#include "cnat_logging.h" -#include "platform_common.h" - -#define CNAT_NFV9_DEBUG_CODE 2 -#if CNAT_NFV9_DEBUG_CODE > 3 - -#define NFV9_COND if ((my_instance_number != 0) && (my_instance_number != 15)) - -#define NFV9_DEBUG_PRINTF1(a) NFV9_COND printf(a); -#define NFV9_DEBUG_PRINTF2(a, b) NFV9_COND printf(a, b); -#define NFV9_DEBUG_PRINTF3(a, b, c) NFV9_COND printf(a, b, c); -#define NFV9_DEBUG_PRINTF4(a, b, c, d) NFV9_COND printf(a, b, c, d); - -#else - -#define NFV9_DEBUG_PRINTF1(a) -#define NFV9_DEBUG_PRINTF2(a, b) -#define NFV9_DEBUG_PRINTF3(a, b, c) -#define NFV9_DEBUG_PRINTF4(a, b, c, d) - -#endif - -static void cnat_nfv9_insert_ingress_vrfid_name_record(cnat_nfv9_logging_info_t *nfv9_logging_info, u16 index); -void cnat_nfv9_ingress_vrfid_name_mapping_create( - cnat_nfv9_logging_info_t *nfv9_logging_info); - - -cnat_nfv9_global_info_t cnat_nfv9_global_info; - -cnat_nfv9_template_t cnat_nfv9_template_info; - -#define CNAT_NFV9_OPTION_TEMPLATE cnat_nfv9_template_info.cnat_nfv9_option_template - -u16 cnat_template_id[MAX_RECORDS] = - {0, CNAT_NFV9_ADD_TEMPLATE_ID, CNAT_NFV9_DEL_TEMPLATE_ID, - CNAT_NFV9_NAT64_ADD_BIB_TEMPLATE_ID,CNAT_NFV9_NAT64_DEL_BIB_TEMPLATE_ID, - CNAT_NFV9_NAT64_ADD_SESSION_TEMPLATE_ID, - CNAT_NFV9_NAT64_DEL_SESSION_TEMPLATE_ID, - CNAT_NFV9_DS_LITE_ADD_TEMPLATE_ID, - CNAT_NFV9_DS_LITE_DEL_TEMPLATE_ID -#ifndef NO_BULK_LOGGING - , CNAT_NFV9_NAT44_BULK_ADD_TEMPLATE_ID, - CNAT_NFV9_NAT44_BULK_DEL_TEMPLATE_ID, - CNAT_NFV9_DS_LITE_BULK_ADD_TEMPLATE_ID, - CNAT_NFV9_DS_LITE_BULK_DEL_TEMPLATE_ID -#endif /* #ifndef NO_BULK_LOGGING */ - , CNAT_NFV9_INGRESS_VRF_ID_NAME_TEMPLATE_ID, - CNAT_NFV9_NAT44_ADD_SESSION_TEMPLATE_ID, - CNAT_NFV9_NAT44_DEL_SESSION_TEMPLATE_ID, - CNAT_NFV9_DS_LITE_ADD_SESSION_TEMPLATE_ID, - CNAT_NFV9_DS_LITE_DEL_SESSION_TEMPLATE_ID - }; - -/* - * Logging information structures - */ -cnat_nfv9_logging_info_t cnat_default_nfv9_logging_info; -cnat_nfv9_logging_info_t *cnat_nfv9_logging_info_pool; -#define NFV9_SERVER_POOL_SIZE 16 -nfv9_server_info_t *nfv9_server_info_pool; - -u32 nfv9_src_id = 0; - -u32 -cnat_get_sys_up_time_in_ms (void) -{ - vlib_main_t * vm = vlib_get_main(); - u32 cnat_curr_time; - - cnat_curr_time = (u32)vlib_time_now (vm); - return cnat_curr_time; -} - -void -cnat_dump_time_change_logs (void) -{ - return; -} - -inline void cnat_nfv9_handle_sys_time_change(time_t current_unix_time) -{ - return; - #if 0 - cnat_handle_sys_time_change(current_unix_time); - #endif -} - -void cnat_nfv9_update_sys_time_change() -{ - cnat_nfv9_logging_info_t *my_nfv9_logging_info = NULL; - pool_foreach (my_nfv9_logging_info, cnat_nfv9_logging_info_pool, ({ - nfv9_server_info_t *server = nfv9_server_info_pool + - my_nfv9_logging_info->server_index; - server->last_template_sent_time = 0; - })); -} - -void nfv9_params_show(u32 logging_index) -{ - cnat_nfv9_logging_info_t *log_info; - if(logging_index == EMPTY) { - PLATFORM_DEBUG_PRINT("\nNetflow logging not configured\n"); - return; - } - - log_info = cnat_nfv9_logging_info_pool + logging_index; - nfv9_server_info_t *server __attribute__((unused)) - = nfv9_server_info_pool + log_info->server_index; - - - PLATFORM_DEBUG_PRINT("\nNetflow parameters --\n"); - PLATFORM_DEBUG_PRINT("Server index %d IPV4 address: %x, port %d, max log size %d\n", - log_info->server_index, server->ipv4_address, - server->port, log_info->max_length_minus_max_record_size); - - PLATFORM_DEBUG_PRINT("Server ref count %d Refresh rate %d timeout rate %d\n", - server->ref_count, server->refresh_rate, - server->timeout_rate); - -} - -/* - * Code to dump NFV9 packets before they are sent - */ -void -cnat_nfv9_dump_logging_context (u32 value1, - cnat_nfv9_logging_info_t *nfv9_logging_info, - u32 value2) -{ - u8 *pkt_ptr; - u32 i; - u32 next_nfv9_template_data_index = 0xffff; - u32 next_data_flow_index = 0xffff; - u32 next_data_record = 0xffff; - u32 data_record_size = 0; - vlib_main_t *vm = vlib_get_main(); - - nfv9_server_info_t *server = nfv9_server_info_pool + - nfv9_logging_info->server_index; - - vlib_cli_output(vm,"\nDumping %s packet at locn %d: time 0x%x", - (value2 == 1) ? "CURRENT" : "QUEUED", - value1, - cnat_nfv9_get_unix_time_in_seconds()); - - vlib_cli_output(vm, "\ni_vrf 0x%x, ip_address 0x%x, port %d", - nfv9_logging_info->i_vrf, - server->ipv4_address, - server->port); - - vlib_cli_output(vm,"\nseq_num %d", - server->sequence_num); - - vlib_cli_output(vm,"\nlast_template_sent time 0x%x, pkts_since_last_template %d", - server->last_template_sent_time, - server->pkts_since_last_template); - - vlib_cli_output(vm, "\npkt_len %d, add_rec_len %d, del_rec_len %d, total_rec_count %d", - nfv9_logging_info->pkt_length, - nfv9_logging_info->record_length[NAT44_ADD_RECORD], - nfv9_logging_info->record_length[NAT44_DEL_RECORD], - nfv9_logging_info->total_record_count); - - vlib_cli_output(vm,"\nbulk_add_rec_len %d, bulk_del_rec_len %d", - nfv9_logging_info->record_length[NAT44_BULK_ADD_RECORD], - nfv9_logging_info->record_length[NAT44_BULK_DEL_RECORD]); - - vlib_cli_output(vm,"\ncurr_logging_ctx 0x%p, timestamp 0x%x, queued_logging_ctx 0x%p", - nfv9_logging_info->current_logging_context, - nfv9_logging_info->current_logging_context_timestamp, - nfv9_logging_info->queued_logging_context); - - vlib_cli_output(vm,"\nnfv9_hdr 0x%p, tmpl_hdr 0x%p, dataflow_hdr 0x%p", - nfv9_logging_info->nfv9_header, - nfv9_logging_info->nfv9_template_header, - nfv9_logging_info->dataflow_header); - - vlib_cli_output(vm,"\nadd_rec 0x%p, del_rec 0x%p, next_data_ptr 0x%p", - nfv9_logging_info->record[NAT44_ADD_RECORD], - nfv9_logging_info->record[NAT44_DEL_RECORD], - nfv9_logging_info->next_data_ptr); - - vlib_cli_output(vm,"\n"); - - pkt_ptr = vlib_buffer_get_current(nfv9_logging_info->current_logging_context); - /* - * Dump along with 8 bytes of SHIM header - */ - for (i = 0; i < (nfv9_logging_info->pkt_length + CNAT_NFV9_IP_HDR_OFFSET); - i = i + 1) { - u8 c1, c2, c3; - if (i == CNAT_NFV9_IP_HDR_OFFSET) { - vlib_cli_output(vm,"\nIP_HEADER: \n"); - } else if (i == CNAT_NFV9_UDP_HDR_OFFSET) { - vlib_cli_output(vm,"\nUDP_HEADER: \n"); - } else if (i == CNAT_NFV9_HDR_OFFSET) { - vlib_cli_output(vm,"\nNFV9 Header: Version:Count: \n"); - } else if (i == (CNAT_NFV9_HDR_OFFSET+4)) { - vlib_cli_output(vm,"\nBoot_Up_Time_In_ms: \n"); - } else if (i == (CNAT_NFV9_HDR_OFFSET+8)) { - vlib_cli_output(vm, "\nUNIX_Time: \n"); - } else if (i == (CNAT_NFV9_HDR_OFFSET+12)) { - vlib_cli_output(vm,"\nSeq_Num: \n"); - } else if (i == (CNAT_NFV9_HDR_OFFSET+16)) { - vlib_cli_output(vm,"\nSource ID: \n"); - } else if (i == (CNAT_NFV9_HDR_OFFSET+20)) { - if (nfv9_logging_info->nfv9_template_header) { - vlib_cli_output(vm,"\nNFV9 TEMPLATE HDR: \n"); - next_nfv9_template_data_index = i + 4; - } else { - next_data_flow_index = i; - } - } else if (i == (CNAT_NFV9_TEMPLATE_OFFSET+CNAT_NFV9_TEMPLATE_LENGTH)) { - if (nfv9_logging_info->nfv9_template_header) { - next_data_flow_index = i; - } - } - - if (i == next_nfv9_template_data_index) { - vlib_cli_output(vm,"\nNFV9 TEMPLATE DATA: \n"); - } else if (i == next_data_flow_index) { - if (*(pkt_ptr + i) == 0x01) { - if (*(pkt_ptr + i + 1) == 0x00) { - data_record_size = 21; - next_data_record = i + 4; - next_data_flow_index = i + *(pkt_ptr + i + 3) + - *(pkt_ptr + i + 2)*0x100; - vlib_cli_output(vm,"\nADD_RECORD (total %d): next_data_flow_index (%d->%d)\n", (next_data_flow_index - i), i, next_data_flow_index); - } else if (*(pkt_ptr + i + 1) == 0x01) { - data_record_size = 11; - next_data_record = i + 4; - next_data_flow_index = i + *(pkt_ptr + i + 3) + - *(pkt_ptr + i + 2)*0x100; - vlib_cli_output(vm,"\nDEL_RECORD (total %d) : next_data_flow_index (%d->%d)\n", (next_data_flow_index - i), i, next_data_flow_index); - } else if (*(pkt_ptr + i + 1) == 0x09) { - data_record_size = 20; - next_data_record = i + 4; - next_data_flow_index = i + *(pkt_ptr + i + 3) + - *(pkt_ptr + i + 2)*0x100; - vlib_cli_output(vm,"\nBULK_ADD_RECORD (total %d) : next_data_flow_index (%d->%d)\n", (next_data_flow_index - i), i, next_data_flow_index); - } else if (*(pkt_ptr + i + 1) == 0x0a) { - data_record_size = 10; - next_data_record = i + 4; - next_data_flow_index = i + *(pkt_ptr + i + 3) + - *(pkt_ptr + i + 2)*0x100; - vlib_cli_output(vm,"\nBULK_DEL_RECORD (total %d) : next_data_flow_index (%d->%d)\n", (next_data_flow_index - i), i, next_data_flow_index); - } - - } - } else if (i == next_data_record) { - vlib_cli_output(vm,"\n"); - next_data_record += data_record_size; - } - - c3 = *(pkt_ptr + i); - - c2 = c3 & 0xf; - c1 = (c3 >> 4) & 0xf; - - - vlib_cli_output(vm,"%c%c ", - ((c1 <= 9) ? (c1 + '0') : (c1 - 10 + 'a')), - ((c2 <= 9) ? (c2 + '0') : (c2 - 10 + 'a'))); - - } - vlib_cli_output(vm,"\n"); -} - -/* - * edt: * * cnat_nfv9_pad_added_to_an_addr - * - * Returns the difference (no# of bytes) between new_addr - * & org_addr - * - * Argument: u8 *new_addr, u8 *org_addr - * returns the difference - */ - -static inline -int cnat_nfv9_pad_added_to_an_addr(u8 *new_addr, u8 *org_addr) -{ - uword addr1 = (uword) new_addr; - uword addr2 = (uword) org_addr; - return (addr1 - addr2); -} - -/* - * edt: * * cnat_nfv9_add_end_of_record_padding - * - * Tries to add padding to data_ptr to ensure it is word aligned - * - * Argument: u8 * data_ptr - * pointer to the data pointer - */ - -static inline -u8 *cnat_nfv9_add_end_of_record_padding (u8 *data_ptr) -{ - uword tmp = (uword) data_ptr; - uword pad_value = (uword) NFV9_PAD_VALUE; - - tmp = (tmp + pad_value) & (~pad_value); - - return ((u8 *) tmp); -} - -/* - * edt: * * cnat_nfv9_pad_end_of_record_length - * - * Tries to add padding to data_ptr to ensure it is word aligned - * - * Argument: u8 * data_ptr - * pointer to the data pointer - */ - -static inline -u16 cnat_nfv9_pad_end_of_record_length (u16 record_length) -{ - u16 pad_value = NFV9_PAD_VALUE; - - return ((record_length + pad_value) & (~pad_value)); -} - -void fill_ip_n_udp_hdr (u32 ipv4_addr, u16 port, - cnat_nfv9_logging_info_t *nfv9_logging_info) -{ - vlib_buffer_t * b0 = nfv9_logging_info->current_logging_context; - ipv4_header *ip_header = vlib_buffer_get_current(b0); - udp_hdr_type_t *udp_header = (udp_hdr_type_t *)((u8*)ip_header + sizeof(ipv4_header)); - vlib_main_t *vm = vlib_get_main(); - u16 ip_length __attribute__((unused)); - u16 pkt_len = nfv9_logging_info->pkt_length; - ip4_address_t *ia0 = 0; - u16 src_port = 0x0a0a; - - /* - * Clear the SHIM header fields. The PD nodes will set it - * appropriately. - */ - PLATFORM_MEMSET_CNAT_LOG_PKT_DATA - - /* - * Don't need a special define for 0x45 - IP version and hdr len - */ - ip_header->version_hdr_len_words = 0x45; - ip_header->tos = 0; - ip_header->frag_flags_offset = 0; - ip_header->ttl = 0xff; - ip_header->protocol = UDP_PROT; - ip_header->dest_addr = clib_host_to_net_u32(ipv4_addr); - ip_length = vlib_buffer_length_in_chain (vm, b0); - ip_header->total_len_bytes = clib_host_to_net_u16(pkt_len); - ia0 = ip4_interface_first_address(&ip4_main, nfv9_logging_info->i_vrf_id, 0); - ip_header->src_addr = ia0->as_u32; - udp_header->src_port = clib_host_to_net_u16(src_port); - udp_header->dest_port = clib_host_to_net_u16(port); - udp_header->udp_checksum = 0; - udp_header->udp_length = - clib_host_to_net_u16(pkt_len - sizeof(ipv4_header)); - ip_header->checksum = ip4_header_checksum((ip4_header_t *)ip_header); -} - -/* - * edt: * * cnat_nfv9_fill_nfv9_ip_header - * - * Tries to fill the fields of the IP header before it - * is sent to the L3 infra node. - * - * Argument: cnat_nfv9_logging_info_t *nfv9_logging_info - * structure that contains the packet context - */ - -static inline -void cnat_nfv9_fill_nfv9_ip_header (cnat_nfv9_logging_info_t *nfv9_logging_info) -{ - u16 new_record_length = 0; - u16 orig_record_length = 0; - vlib_buffer_t * b0 = nfv9_logging_info->current_logging_context; - - /* - * Fill in the IP header and port number of the Netflow collector - * The L3 Infra node will fill in the rest of the fields - */ - - nfv9_logging_info->nfv9_header->count = - clib_host_to_net_u16(nfv9_logging_info->total_record_count); - - /* - * Pad the last add/del record to ensure multiple of 4 bytes - */ - - if(nfv9_logging_info->last_record != RECORD_INVALID) { - - orig_record_length = - nfv9_logging_info->record_length[nfv9_logging_info->last_record]; - - new_record_length = cnat_nfv9_pad_end_of_record_length( - orig_record_length); - - nfv9_logging_info->dataflow_header->dataflow_length = - clib_host_to_net_u16(new_record_length); - } - - /* - * If the record is padded, ensure the padded bytes are ZERO - */ - if (PREDICT_TRUE(new_record_length - orig_record_length)) { - u8 *pkt_ptr = (u8 *) (b0 + nfv9_logging_info->pkt_length); - - /* - * Blindly copy 3 bytes of data to Zero to avoid for loops - * We have sufficient padding bytes for safety and we won't - * go over buffer limits - */ - *pkt_ptr++ = 0; - *pkt_ptr++ = 0; - *pkt_ptr++ = 0; - - nfv9_logging_info->pkt_length += - (new_record_length - orig_record_length); - } - nfv9_server_info_t *server = nfv9_server_info_pool + - nfv9_logging_info->server_index; - fill_ip_n_udp_hdr(server->ipv4_address, - server->port, nfv9_logging_info); - /* - * It is important to set the sw_if_index for the new buffer create - */ - vnet_buffer(b0)->sw_if_index[VLIB_TX] = (u32)~0; - -} - -/* - * edt: * * cnat_nfv9_send_queued_pkt - * - * Tries to send a logging pkt that has been queued earlier - * because it could not be sent due to downstream constipation - * - * Argument: cnat_nfv9_logging_info_t *nfv9_logging_info - * structure that contains the packet context - */ - -static inline -void cnat_nfv9_send_queued_pkt (cnat_nfv9_logging_info_t *nfv9_logging_info) -{ - return; -} - -/* - * edt: * * cnat_nfv9_send_pkt - * - * Tries to send a logging pkt. If the packet cannot be sent - * because of rewrite_output node cannot process it, queue - * it temporarily and try to send it later. - * - * Argument: cnat_nfv9_logging_info_t *nfv9_logging_info - * structure that contains the packet context - */ - -static inline -void cnat_nfv9_send_pkt (cnat_nfv9_logging_info_t *nfv9_logging_info) -{ - cnat_nfv9_fill_nfv9_ip_header(nfv9_logging_info); - - nfv9_server_info_t *server = nfv9_server_info_pool + - nfv9_logging_info->server_index; - - /* Update sequence number just before sending. - * So that, multiple NAT44/NAT64/DSLite instances sharing a - * a single server instance can stamp the sequence number - * in the right sequence (as seen by the server). - */ - server->sequence_num += 1; - nfv9_logging_info->nfv9_header->sequence_num = - clib_host_to_net_u32(server->sequence_num); - -#if DEBUG - cnat_nfv9_dump_logging_context (2, nfv9_logging_info, 1); -#endif -#if 0 /* commented out below */ - send_vpp3_nfv9_pkt(nfv9_logging_info); -#endif - nfv9_logging_info->current_logging_context = NULL; - /* - * Increase last packet sent count - */ - server->pkts_since_last_template++; - - /* - * If we are sending an nfv9 tempate with this packet - * log this timestamp - */ - if (nfv9_logging_info->nfv9_template_header) { - server->last_template_sent_time = - cnat_nfv9_get_unix_time_in_seconds(); - server->pkts_since_last_template = 0; - } - - return; -} - -/* - * send_vpp3_nfv9_pkt: to send multiple b0 in a frame - */ - -static inline -void send_vpp3_nfv9_pkt (cnat_nfv9_logging_info_t *nfv9_logging_info) -{ - vlib_node_t *output_node; - vlib_main_t *vm = vlib_get_main(); - vlib_frame_t *f; - vlib_buffer_t *b0; - u32 *to_next; - u32 bi=0; - ipv4_header *ip; - - //Lets check and send it to ip4-lookup node - output_node = vlib_get_node_by_name (vm, (u8 *) "ip4-lookup"); - f = vlib_get_frame_to_node (vm, output_node->index); - - if ( nfv9_logging_info->current_logging_context != NULL) { - /* Build a pkt from whole cloth */ - b0 = nfv9_logging_info->current_logging_context; - ip = vlib_buffer_get_current(b0); - to_next = vlib_frame_vector_args (f); - bi = vlib_get_buffer_index (vm, b0); - to_next[0] = bi; - - f->n_vectors = 1; - b0->current_length = clib_net_to_host_u16(ip->total_len_bytes); - vlib_put_frame_to_node (vm, output_node->index, f); - } - return; -} -/* - * edt: * * cnat_nfv9_send_pkt_always_success - * - * Tries to send a logging pkt. This cannot fail due to downstream - * constipation because we have already checked if the rewrite_output - * node can accept it. - * - * Argument: cnat_nfv9_logging_info_t *nfv9_logging_info - * structure that contains the packet context - * - * Argument: vlib_node_t *output_node - * vlib_node_t structure for rewrite_output node - */ - -static inline -void cnat_nfv9_send_pkt_always_success ( - cnat_nfv9_logging_info_t *nfv9_logging_info, - vlib_node_t *output_node) -{ - nfv9_server_info_t *server = nfv9_server_info_pool + - nfv9_logging_info->server_index; - vlib_main_t * vm = vlib_get_main(); - - /* - * At this point we either have a current or queued logging context - */ - if (PREDICT_TRUE(nfv9_logging_info->current_logging_context != NULL)) { - server->sequence_num += 1; - nfv9_logging_info->nfv9_header->sequence_num = - clib_host_to_net_u32(server->sequence_num); - cnat_nfv9_fill_nfv9_ip_header(nfv9_logging_info); - - nfv9_logging_info->current_logging_context->current_length = - nfv9_logging_info->pkt_length; - vlib_cli_output(vm, "\nNFV9: 3. Sending Current packet\n"); -#if DEBUG - cnat_nfv9_dump_logging_context (3, nfv9_logging_info, 1); -#endif - send_vpp3_nfv9_pkt(nfv9_logging_info); - nfv9_logging_info->current_logging_context = NULL; - } else { - /* - * For queued logging context, nfv9_header-> count is already set - */ - nfv9_logging_info->queued_logging_context->current_length = - nfv9_logging_info->pkt_length; - vlib_cli_output(vm,"\nNFV9: 4. Sending Queued packet\n"); -#if DEBUG - cnat_nfv9_dump_logging_context (4, nfv9_logging_info, 2); -#endif - send_vpp3_nfv9_pkt(nfv9_logging_info); - - nfv9_logging_info->queued_logging_context = NULL; - } - - /* - * NF Logging info already deleted, just free it and return - */ - if (PREDICT_FALSE(nfv9_logging_info->deleted)) { - pool_put(cnat_nfv9_logging_info_pool, nfv9_logging_info); - return; - } - - /* - * Increase last packet sent count and timestamp - */ - server->pkts_since_last_template++; - - /* - * If we are sending an nfv9 tempate with this packet - * log this timestamp - */ - if (nfv9_logging_info->nfv9_template_header) { - server->last_template_sent_time = - cnat_nfv9_get_unix_time_in_seconds(); - server->pkts_since_last_template = 0; - } -} - -/* - * edt: * * cnat_nfv9_create_logging_context - * - * Tries to create a logging context with packet buffer - * to send a new logging packet - * - * Argument: cnat_nfv9_logging_info_t *nfv9_logging_info - * structure that contains the nfv9 logging info and will store - * the packet context as well. - */ - -static inline -void cnat_nfv9_create_logging_context ( - cnat_nfv9_logging_info_t *nfv9_logging_info, - cnat_nfv9_template_add_flag_t template_flag) -{ - vlib_main_t *vm = vlib_get_main(); - vlib_buffer_t *b0; - static u32 bi; - u8 i; - - /* - * If queued_logging_context_index is non-EMPTY, we already have a logging - * packet queued to be sent. First try sending this before allocating - * a new context. We can have only one active packet context per - * nfv9_logging_info structure - */ - if (PREDICT_FALSE(nfv9_logging_info->queued_logging_context != NULL)) { - cnat_nfv9_send_queued_pkt(nfv9_logging_info); - /* - * If we cannot still send the queued pkt, just return - * Downstream Constipation count would have increased anyway - */ - if (nfv9_logging_info->queued_logging_context != NULL) { - cnat_global_counters.nfv9_logging_context_creation_deferred_count++; - return; - } - } - - - /* - * No context can be allocated, return silently - * calling routine will handle updating the error counters - */ - if (vlib_buffer_alloc (vm, &bi, 1) != 1) { - vlib_cli_output(vm, "buffer allocation failure"); - return; - } - /* Build a pkt from whole cloth */ - b0 = vlib_get_buffer (vm, bi); - b0->current_data = 0; - - nfv9_server_info_t *server = nfv9_server_info_pool + - nfv9_logging_info->server_index; - - nfv9_logging_info->current_logging_context = b0; - nfv9_logging_info->current_logging_context_timestamp = - cnat_nfv9_get_sys_up_time_in_ms(); - - - nfv9_logging_info->nfv9_header = - (nfv9_header_t *) (vlib_buffer_get_current(b0) + - (sizeof(ipv4_header)) + - (sizeof(udp_hdr_type_t))); - - nfv9_logging_info->nfv9_header->version = - clib_host_to_net_u16(CNAT_NFV9_VERSION_NUMBER); - - nfv9_logging_info->nfv9_header->sys_up_time = - clib_host_to_net_u32(cnat_nfv9_get_sys_up_time_in_ms()); - - nfv9_logging_info->nfv9_header->timestamp = - clib_host_to_net_u32(cnat_nfv9_get_unix_time_in_seconds()); - - - nfv9_logging_info->nfv9_header->source_id = - clib_host_to_net_u32(nfv9_src_id); - - nfv9_logging_info->dataflow_header = 0; - - for(i = 0; i < MAX_RECORDS;i++) { - nfv9_logging_info->record[i] = NULL; - nfv9_logging_info->record_length[i] = 0; - } - nfv9_logging_info->last_record = 0; - - - nfv9_logging_info->nfv9_template_header = 0; - nfv9_logging_info->next_data_ptr = - (u8 *) (vlib_buffer_get_current(b0) + - sizeof(ipv4_header) + sizeof(udp_hdr_type_t) + - sizeof(nfv9_header_t)); - - nfv9_logging_info->pkt_length = (CNAT_NFV9_TEMPLATE_OFFSET - - CNAT_NFV9_IP_HDR_OFFSET); - - - /* - * Now we have 0 records to start with - */ - - nfv9_logging_info->total_record_count = 0; - - if ((template_flag == cnat_nfv9_template_add_always) || - (server->pkts_since_last_template > - server->refresh_rate) || - ((cnat_nfv9_get_unix_time_in_seconds() - - server->last_template_sent_time) > - server->timeout_rate)) { - - /* - * Send a new template - */ - nfv9_logging_info->nfv9_template_header = - (cnat_nfv9_template_t *) nfv9_logging_info->next_data_ptr; - - clib_memcpy(nfv9_logging_info->nfv9_template_header, - &cnat_nfv9_template_info, - sizeof(cnat_nfv9_template_info)); - - /* - * Templates are sent irrespective of particular service-type config - */ - nfv9_logging_info->total_record_count = MAX_RECORDS - 1; - - nfv9_logging_info->pkt_length += CNAT_NFV9_TEMPLATE_LENGTH; - - /* - * Set the data pointer beyond the template field - */ - nfv9_logging_info->next_data_ptr = - (u8 *) (nfv9_logging_info->nfv9_template_header + 1); - /* - * Setting template_sent flag as TRUE. this will be checked in - * handle_vrfid_name_mapping() - */ - server->template_sent = TEMPLATE_SENT_TRUE; - } -} - -void cnat_nfv9_record_create ( - cnat_nfv9_logging_info_t *nfv9_logging_info, u16 cur_record) -{ - int byte_diff = 0; - u16 last_record = nfv9_logging_info->last_record; - - if(last_record != 0 && last_record != cur_record) { - u16 orig_length, new_length; - - orig_length = nfv9_logging_info->record_length[last_record]; - new_length = cnat_nfv9_pad_end_of_record_length(orig_length); - - /* - * The padding bytes are required after the last record - * Ensure length of last record accounts for padding bytes - */ - nfv9_logging_info->dataflow_header->dataflow_length = - clib_host_to_net_u16(new_length); - - /* - * Since we are working on the del record, set add record to 0 - */ - nfv9_logging_info->record[last_record] = 0; - - nfv9_logging_info->record_length[last_record] = 0; - - nfv9_logging_info->last_record = 0; - } - - nfv9_logging_info->last_record = cur_record; - - /* - * The padding bytes are required after the last record - * Ensure that we skip over the padding bytes - */ - nfv9_logging_info->dataflow_header = (nfv9_dataflow_record_header_t *) - cnat_nfv9_add_end_of_record_padding(nfv9_logging_info->next_data_ptr); - /* - * Get the difference - */ - byte_diff = cnat_nfv9_pad_added_to_an_addr( - (u8 *)nfv9_logging_info->dataflow_header, - nfv9_logging_info->next_data_ptr); - if(byte_diff > 0) { - /* - * Update the packet length to account for the pad bytes - */ - nfv9_logging_info->pkt_length += byte_diff; - u8 *pkt_ptr = nfv9_logging_info->next_data_ptr; - - /* - * Blindly copy 3 bytes of data to Zero to avoid for loops - * We have sufficient padding bytes for safety and we won't - * go over buffer limits - */ - *pkt_ptr++ = 0; - *pkt_ptr++ = 0; - *pkt_ptr++ = 0; - } - /* - * Initialize the template_id and the length of the add record - */ - nfv9_logging_info->dataflow_header->dataflow_template_id = - clib_host_to_net_u16(cnat_template_id[cur_record]); - - nfv9_logging_info->record[cur_record] = - (u8 *) (nfv9_logging_info->dataflow_header + 1); - - nfv9_logging_info->record_length[cur_record] = - CNAT_NFV9_DATAFLOW_RECORD_HEADER_LENGTH; - - /* - * Update the length of the total NFV9 record - */ - nfv9_logging_info->pkt_length += - CNAT_NFV9_DATAFLOW_RECORD_HEADER_LENGTH; - - /* - * Set the data pointer beyond the dataflow header field - */ - nfv9_logging_info->next_data_ptr = - (u8 *) (nfv9_logging_info->dataflow_header + 1); - -} - -static void cnat_nfv9_insert_add_record( - cnat_nfv9_logging_info_t *nfv9_logging_info, - cnat_main_db_entry_t *db, - cnat_vrfmap_t *vrfmap) -{ - u16 my_proto_mask; - u8 my_protocol; - nfv9_add_record_t nfv9_logging_add_record; - if (PREDICT_FALSE(nfv9_logging_info->record[NAT44_ADD_RECORD] == NULL)) { - cnat_nfv9_record_create(nfv9_logging_info, NAT44_ADD_RECORD); - } - - /* - * We should definitely have add_record now, no need to sanitize - */ - - nfv9_logging_add_record.inside_vrf_id = - clib_host_to_net_u32(vrfmap->i_vrf_id); - - nfv9_logging_add_record.outside_vrf_id = - clib_host_to_net_u32(vrfmap->o_vrf_id); - - nfv9_logging_add_record.inside_ip_addr = - clib_host_to_net_u32(db->in2out_key.k.ipv4); - nfv9_logging_add_record.outside_ip_addr = - clib_host_to_net_u32(db->out2in_key.k.ipv4); - - nfv9_logging_add_record.inside_ip_port = - clib_host_to_net_u16(db->in2out_key.k.port); - nfv9_logging_add_record.outside_ip_port = - clib_host_to_net_u16(db->out2in_key.k.port); - - my_proto_mask = db->in2out_key.k.vrf & CNAT_PRO_MASK; - my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT : - ((my_proto_mask == CNAT_TCP) ? TCP_PROT : - ((my_proto_mask == CNAT_ICMP) ? ICMP_PROT : GRE_PROT))); - - nfv9_logging_add_record.protocol = my_protocol; - - clib_memcpy(nfv9_logging_info->record[NAT44_ADD_RECORD], - &nfv9_logging_add_record, CNAT_NFV9_ADD_RECORD_LENGTH); - - nfv9_logging_info->record_length[NAT44_ADD_RECORD] - += CNAT_NFV9_ADD_RECORD_LENGTH; - - nfv9_logging_info->pkt_length += CNAT_NFV9_ADD_RECORD_LENGTH; - - nfv9_logging_info->record[NAT44_ADD_RECORD] - += CNAT_NFV9_ADD_RECORD_LENGTH; - nfv9_logging_info->next_data_ptr = - nfv9_logging_info->record[NAT44_ADD_RECORD]; - - nfv9_logging_info->dataflow_header->dataflow_length = - clib_host_to_net_u32( - nfv9_logging_info->record_length[NAT44_ADD_RECORD]); - -} - - -static void cnat_nfv9_ds_lite_insert_add_record( - cnat_nfv9_logging_info_t *nfv9_logging_info, - cnat_main_db_entry_t *db, - dslite_table_entry_t *dslite_entry) -{ - - nfv9_ds_lite_add_record_t nfv9_logging_add_record = {0}; - cnat_user_db_entry_t *udb = NULL; - u16 my_proto_mask; - u8 my_protocol; - - udb = cnat_user_db + db->user_index; - if (PREDICT_FALSE(!udb)) { - return; - } - if (PREDICT_FALSE(nfv9_logging_info->record[DS_LITE_ADD_RECORD] == NULL)) { - cnat_nfv9_record_create(nfv9_logging_info, DS_LITE_ADD_RECORD); - } - /* - * We should definitely have add_record now, no need to sanitize - */ - nfv9_logging_add_record.inside_vrf_id = - clib_host_to_net_u32(dslite_entry->i_vrf_id); - nfv9_logging_add_record.outside_vrf_id = - clib_host_to_net_u32(dslite_entry->o_vrf_id); - -#ifdef DSLITE_USER_IPV4 - nfv9_logging_add_record.inside_ip_addr = - clib_host_to_net_u32(db->in2out_key.k.ipv4); -#else - /* - * Inside ipv4 address is sent as 0.0.0.0 for ds-lite case as - * ipv6 is user here. - */ - nfv9_logging_add_record.inside_ip_addr = 0; -#endif - - nfv9_logging_add_record.inside_v6_src_addr[0] = - clib_host_to_net_u32(udb->ipv6[0]); - nfv9_logging_add_record.inside_v6_src_addr[1] = - clib_host_to_net_u32(udb->ipv6[1]); - nfv9_logging_add_record.inside_v6_src_addr[2] = - clib_host_to_net_u32(udb->ipv6[2]); - nfv9_logging_add_record.inside_v6_src_addr[3] = - clib_host_to_net_u32(udb->ipv6[3]); - - nfv9_logging_add_record.outside_ip_addr = - clib_host_to_net_u32(db->out2in_key.k.ipv4); - - nfv9_logging_add_record.inside_ip_port = - clib_host_to_net_u16(db->in2out_key.k.port); - nfv9_logging_add_record.outside_ip_port = - clib_host_to_net_u16(db->out2in_key.k.port); - - my_proto_mask = db->in2out_key.k.vrf & CNAT_PRO_MASK; - - my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT : - ((my_proto_mask == CNAT_TCP) ? TCP_PROT : - ((my_proto_mask == CNAT_ICMP) ? ICMP_PROT : 0))); - nfv9_logging_add_record.protocol = my_protocol; - - clib_memcpy(nfv9_logging_info->record[DS_LITE_ADD_RECORD], - &nfv9_logging_add_record, CNAT_NFV9_DS_LITE_ADD_RECORD_LENGTH); - - nfv9_logging_info->record_length[DS_LITE_ADD_RECORD] - += CNAT_NFV9_DS_LITE_ADD_RECORD_LENGTH; - - nfv9_logging_info->pkt_length += CNAT_NFV9_DS_LITE_ADD_RECORD_LENGTH; - nfv9_logging_info->total_record_count += 1; - - nfv9_logging_info->record[DS_LITE_ADD_RECORD] - += CNAT_NFV9_DS_LITE_ADD_RECORD_LENGTH; - nfv9_logging_info->next_data_ptr = - nfv9_logging_info->record[DS_LITE_ADD_RECORD]; - - nfv9_logging_info->dataflow_header->dataflow_length = - clib_host_to_net_u32( - nfv9_logging_info->record_length[DS_LITE_ADD_RECORD]); -} - - -static void cnat_nfv9_ds_lite_insert_del_record( - cnat_nfv9_logging_info_t *nfv9_logging_info, - cnat_main_db_entry_t *db, - dslite_table_entry_t *dslite_entry) -{ - - nfv9_ds_lite_del_record_t nfv9_logging_del_record = {0}; - cnat_user_db_entry_t *udb = NULL; - u16 my_proto_mask; - u8 my_protocol; - - udb = cnat_user_db + db->user_index; - if (PREDICT_FALSE(!udb)) { - return; - } - if (PREDICT_FALSE(nfv9_logging_info->record[DS_LITE_DEL_RECORD] == NULL)) { - cnat_nfv9_record_create(nfv9_logging_info, DS_LITE_DEL_RECORD); - } - /* - * We should definitely have a del record now. - * No need to sanitize - */ - nfv9_logging_del_record.inside_vrf_id = - clib_host_to_net_u32(dslite_entry->i_vrf_id); - -#ifdef DSLITE_USER_IPV4 - nfv9_logging_del_record.inside_ip_addr = - clib_host_to_net_u32(db->in2out_key.k.ipv4); -#else - /* - * Inside ipv4 address is sent as 0.0.0.0 for ds-lite case as - * ipv6 is user here. - */ - nfv9_logging_del_record.inside_ip_addr = 0; -#endif - - nfv9_logging_del_record.inside_v6_src_addr[0] = - clib_host_to_net_u32(udb->ipv6[0]); - nfv9_logging_del_record.inside_v6_src_addr[1] = - clib_host_to_net_u32(udb->ipv6[1]); - nfv9_logging_del_record.inside_v6_src_addr[2] = - clib_host_to_net_u32(udb->ipv6[2]); - nfv9_logging_del_record.inside_v6_src_addr[3] = - clib_host_to_net_u32(udb->ipv6[3]); - - nfv9_logging_del_record.inside_ip_port = - clib_host_to_net_u16(db->in2out_key.k.port); - - my_proto_mask = db->in2out_key.k.vrf & CNAT_PRO_MASK; - - my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT : - ((my_proto_mask == CNAT_TCP) ? TCP_PROT : - ((my_proto_mask == CNAT_ICMP) ? ICMP_PROT : 0))); - nfv9_logging_del_record.protocol = my_protocol; - - clib_memcpy(nfv9_logging_info->record[DS_LITE_DEL_RECORD], - &nfv9_logging_del_record, CNAT_NFV9_DS_LITE_DEL_RECORD_LENGTH); - - nfv9_logging_info->record_length[DS_LITE_DEL_RECORD] += - CNAT_NFV9_DS_LITE_DEL_RECORD_LENGTH; - - nfv9_logging_info->pkt_length += CNAT_NFV9_DS_LITE_DEL_RECORD_LENGTH; - nfv9_logging_info->total_record_count += 1; - - nfv9_logging_info->record[DS_LITE_DEL_RECORD] - += CNAT_NFV9_DS_LITE_DEL_RECORD_LENGTH; - nfv9_logging_info->next_data_ptr = - nfv9_logging_info->record[DS_LITE_DEL_RECORD]; - - nfv9_logging_info->dataflow_header->dataflow_length = - clib_host_to_net_u32( - nfv9_logging_info->record_length[DS_LITE_DEL_RECORD]); -} - -#ifndef NO_BULK_LOGGING -static void cnat_nfv9_insert_bulk_add_record( - cnat_nfv9_logging_info_t *nfv9_logging_info, - cnat_main_db_entry_t *db, - cnat_vrfmap_t *vrfmap, - int bulk_alloc_start_port) -{ - nfv9_bulk_add_record_t nfv9_logging_bulk_add_record; - bulk_alloc_size_t bulk_size = BULKSIZE_FROM_VRFMAP(vrfmap); - if (PREDICT_FALSE(nfv9_logging_info->record[NAT44_BULK_ADD_RECORD] == NULL)) { - cnat_nfv9_record_create(nfv9_logging_info, NAT44_BULK_ADD_RECORD); - } - - /* - * We should definitely have add_record now, no need to sanitize - */ - - nfv9_logging_bulk_add_record.inside_vrf_id = - clib_host_to_net_u32(vrfmap->i_vrf_id); - nfv9_logging_bulk_add_record.outside_vrf_id = - clib_host_to_net_u32(vrfmap->o_vrf_id); - - nfv9_logging_bulk_add_record.inside_ip_addr = - clib_host_to_net_u32(db->in2out_key.k.ipv4); - nfv9_logging_bulk_add_record.outside_ip_addr = - clib_host_to_net_u32(db->out2in_key.k.ipv4); - - nfv9_logging_bulk_add_record.outside_ip_port_start = - clib_host_to_net_u16(bulk_alloc_start_port); - nfv9_logging_bulk_add_record.outside_ip_port_end = - clib_host_to_net_u16(bulk_alloc_start_port + bulk_size -1); - - clib_memcpy(nfv9_logging_info->record[NAT44_BULK_ADD_RECORD], - &nfv9_logging_bulk_add_record, CNAT_NFV9_BULK_ADD_RECORD_LENGTH); - - nfv9_logging_info->record_length[NAT44_BULK_ADD_RECORD] - += CNAT_NFV9_BULK_ADD_RECORD_LENGTH; - - nfv9_logging_info->pkt_length += CNAT_NFV9_BULK_ADD_RECORD_LENGTH; - - nfv9_logging_info->record[NAT44_BULK_ADD_RECORD] - += CNAT_NFV9_BULK_ADD_RECORD_LENGTH; - nfv9_logging_info->next_data_ptr = - nfv9_logging_info->record[NAT44_BULK_ADD_RECORD]; - - nfv9_logging_info->dataflow_header->dataflow_length = - clib_host_to_net_u32( - nfv9_logging_info->record_length[NAT44_BULK_ADD_RECORD]); - -} - - -static void cnat_nfv9_ds_lite_insert_bulk_add_record( - cnat_nfv9_logging_info_t *nfv9_logging_info, - cnat_main_db_entry_t *db, - dslite_table_entry_t *dslite_entry, - int bulk_alloc_start_port) -{ - - nfv9_ds_lite_bulk_add_record_t nfv9_logging_bulk_add_record = {0}; - cnat_user_db_entry_t *udb = NULL; - bulk_alloc_size_t bulk_size = BULKSIZE_FROM_VRFMAP(dslite_entry); - - if (PREDICT_FALSE(nfv9_logging_info->record[DS_LITE_BULK_ADD_RECORD] == NULL)) { - cnat_nfv9_record_create(nfv9_logging_info, DS_LITE_BULK_ADD_RECORD); - } - udb = cnat_user_db + db->user_index; - if (PREDICT_FALSE(!udb)) { - return; - } - /* - * We should definitely have add_record now, no need to sanitize - */ - - nfv9_logging_bulk_add_record.inside_vrf_id = - clib_host_to_net_u32(dslite_entry->i_vrf_id); - nfv9_logging_bulk_add_record.outside_vrf_id = - clib_host_to_net_u32(dslite_entry->o_vrf_id); - -#ifdef DSLITE_USER_IPV4 - nfv9_logging_bulk_add_record.inside_ip_addr = - clib_host_to_net_u32(db->in2out_key.k.ipv4); -#else - /* - * Inside ipv4 address is sent as 0.0.0.0 for ds-lite case as - * ipv6 is user here. - */ - nfv9_logging_bulk_add_record.inside_ip_addr = 0; -#endif - - nfv9_logging_bulk_add_record.inside_v6_src_addr[0] = - clib_host_to_net_u32(udb->ipv6[0]); - nfv9_logging_bulk_add_record.inside_v6_src_addr[1] = - clib_host_to_net_u32(udb->ipv6[1]); - nfv9_logging_bulk_add_record.inside_v6_src_addr[2] = - clib_host_to_net_u32(udb->ipv6[2]); - nfv9_logging_bulk_add_record.inside_v6_src_addr[3] = - clib_host_to_net_u32(udb->ipv6[3]); - - nfv9_logging_bulk_add_record.outside_ip_addr = - clib_host_to_net_u32(db->out2in_key.k.ipv4); - - nfv9_logging_bulk_add_record.outside_ip_port_start = - clib_host_to_net_u16(bulk_alloc_start_port); - nfv9_logging_bulk_add_record.outside_ip_port_end = - clib_host_to_net_u16(bulk_alloc_start_port + bulk_size -1); - - clib_memcpy(nfv9_logging_info->record[DS_LITE_BULK_ADD_RECORD], - &nfv9_logging_bulk_add_record, CNAT_NFV9_DS_LITE_BULK_ADD_RECORD_LENGTH); - - nfv9_logging_info->record_length[DS_LITE_BULK_ADD_RECORD] - += CNAT_NFV9_DS_LITE_BULK_ADD_RECORD_LENGTH; - - nfv9_logging_info->pkt_length += CNAT_NFV9_DS_LITE_BULK_ADD_RECORD_LENGTH; - nfv9_logging_info->total_record_count += 1; - nfv9_logging_info->record[DS_LITE_BULK_ADD_RECORD] - += CNAT_NFV9_DS_LITE_BULK_ADD_RECORD_LENGTH; - nfv9_logging_info->next_data_ptr = - nfv9_logging_info->record[DS_LITE_BULK_ADD_RECORD]; - nfv9_logging_info->dataflow_header->dataflow_length = - clib_host_to_net_u32( - nfv9_logging_info->record_length[DS_LITE_BULK_ADD_RECORD]); -} - - -static void cnat_nfv9_ds_lite_insert_bulk_del_record( - cnat_nfv9_logging_info_t *nfv9_logging_info, - cnat_main_db_entry_t *db, - dslite_table_entry_t *dslite_entry, - int bulk_alloc_start_port) -{ - - nfv9_ds_lite_bulk_del_record_t nfv9_logging_bulk_del_record = {0}; - cnat_user_db_entry_t *udb = NULL; - - if (PREDICT_FALSE(nfv9_logging_info->record[DS_LITE_BULK_DEL_RECORD] == NULL)) { - cnat_nfv9_record_create(nfv9_logging_info, DS_LITE_BULK_DEL_RECORD); - } - udb = cnat_user_db + db->user_index; - if (PREDICT_FALSE(!udb)) { - return; - } - /* - * We should definitely have add_record now, no need to sanitize - */ - - nfv9_logging_bulk_del_record.inside_vrf_id = - clib_host_to_net_u32(dslite_entry->i_vrf_id); - -#ifdef DSLITE_USER_IPV4 - nfv9_logging_bulk_del_record.inside_ip_addr = - clib_host_to_net_u32(db->in2out_key.k.ipv4); -#else - nfv9_logging_bulk_del_record.inside_ip_addr = - clib_host_to_net_u32(0); -#endif - - nfv9_logging_bulk_del_record.inside_v6_src_addr[0] = - clib_host_to_net_u32(udb->ipv6[0]); - nfv9_logging_bulk_del_record.inside_v6_src_addr[1] = - clib_host_to_net_u32(udb->ipv6[1]); - nfv9_logging_bulk_del_record.inside_v6_src_addr[2] = - clib_host_to_net_u32(udb->ipv6[2]); - nfv9_logging_bulk_del_record.inside_v6_src_addr[3] = - clib_host_to_net_u32(udb->ipv6[3]); - - nfv9_logging_bulk_del_record.outside_ip_port_start = - clib_host_to_net_u16(bulk_alloc_start_port); - - clib_memcpy(nfv9_logging_info->record[DS_LITE_BULK_DEL_RECORD], - &nfv9_logging_bulk_del_record, - CNAT_NFV9_DS_LITE_BULK_DEL_RECORD_LENGTH); - nfv9_logging_info->record_length[DS_LITE_BULK_DEL_RECORD] += - CNAT_NFV9_DS_LITE_BULK_DEL_RECORD_LENGTH; - nfv9_logging_info->pkt_length += - CNAT_NFV9_DS_LITE_BULK_DEL_RECORD_LENGTH; - nfv9_logging_info->total_record_count += 1; - nfv9_logging_info->record[DS_LITE_BULK_DEL_RECORD] += - CNAT_NFV9_DS_LITE_BULK_DEL_RECORD_LENGTH; - nfv9_logging_info->next_data_ptr = - nfv9_logging_info->record[DS_LITE_BULK_DEL_RECORD]; - nfv9_logging_info->dataflow_header->dataflow_length = - clib_host_to_net_u32( - nfv9_logging_info->record_length[DS_LITE_BULK_DEL_RECORD]); -} -#endif /* #ifndef NO_BULK_LOGGING */ - -static void cnat_nfv9_insert_del_record( - cnat_nfv9_logging_info_t *nfv9_logging_info, - cnat_main_db_entry_t *db, - cnat_vrfmap_t *vrfmap) -{ - u16 my_proto_mask; - u8 my_protocol; - nfv9_del_record_t nfv9_logging_del_record; - - if (PREDICT_FALSE(nfv9_logging_info->record[NAT44_DEL_RECORD] == NULL)) { - cnat_nfv9_record_create(nfv9_logging_info, NAT44_DEL_RECORD); - } - - /* - * We should definitely have add_record now, no need to sanitize - */ - - nfv9_logging_del_record.inside_vrf_id = - clib_host_to_net_u32(vrfmap->i_vrf_id); - - nfv9_logging_del_record.inside_ip_addr = - clib_host_to_net_u32(db->in2out_key.k.ipv4); - - nfv9_logging_del_record.inside_ip_port = - clib_host_to_net_u16(db->in2out_key.k.port); - - my_proto_mask = db->in2out_key.k.vrf & CNAT_PRO_MASK; - my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT : - ((my_proto_mask == CNAT_TCP) ? TCP_PROT : - ((my_proto_mask == CNAT_ICMP) ? ICMP_PROT : GRE_PROT))); - - nfv9_logging_del_record.protocol = my_protocol; - - clib_memcpy(nfv9_logging_info->record[NAT44_DEL_RECORD], - &nfv9_logging_del_record, CNAT_NFV9_DEL_RECORD_LENGTH); - - nfv9_logging_info->record_length[NAT44_DEL_RECORD] - += CNAT_NFV9_DEL_RECORD_LENGTH; - - nfv9_logging_info->pkt_length += CNAT_NFV9_DEL_RECORD_LENGTH; - - nfv9_logging_info->record[NAT44_DEL_RECORD] - += CNAT_NFV9_DEL_RECORD_LENGTH; - nfv9_logging_info->next_data_ptr = - nfv9_logging_info->record[NAT44_DEL_RECORD]; - - nfv9_logging_info->dataflow_header->dataflow_length = - clib_host_to_net_u32( - nfv9_logging_info->record_length[NAT44_DEL_RECORD]); - -} - -#ifndef NO_BULK_LOGGING -static void cnat_nfv9_insert_bulk_del_record( - cnat_nfv9_logging_info_t *nfv9_logging_info, - cnat_main_db_entry_t *db, - cnat_vrfmap_t *vrfmap, - int bulk_alloc_start_port) -{ - nfv9_bulk_del_record_t nfv9_logging_bulk_del_record; - if (PREDICT_FALSE(nfv9_logging_info->record[NAT44_BULK_DEL_RECORD] == NULL)) { - cnat_nfv9_record_create(nfv9_logging_info, NAT44_BULK_DEL_RECORD); - } - - /* - * We should definitely have add_record now, no need to sanitize - */ - - nfv9_logging_bulk_del_record.inside_vrf_id = - clib_host_to_net_u32(vrfmap->i_vrf_id); - - nfv9_logging_bulk_del_record.inside_ip_addr = - clib_host_to_net_u32(db->in2out_key.k.ipv4); - - nfv9_logging_bulk_del_record.outside_ip_port_start = - clib_host_to_net_u16(bulk_alloc_start_port); - - clib_memcpy(nfv9_logging_info->record[NAT44_BULK_DEL_RECORD], - &nfv9_logging_bulk_del_record, CNAT_NFV9_BULK_DEL_RECORD_LENGTH); - - nfv9_logging_info->record_length[NAT44_BULK_DEL_RECORD] - += CNAT_NFV9_BULK_DEL_RECORD_LENGTH; - - nfv9_logging_info->pkt_length += CNAT_NFV9_BULK_DEL_RECORD_LENGTH; - - nfv9_logging_info->record[NAT44_BULK_DEL_RECORD] - += CNAT_NFV9_BULK_DEL_RECORD_LENGTH; - nfv9_logging_info->next_data_ptr = - nfv9_logging_info->record[NAT44_BULK_DEL_RECORD]; - - nfv9_logging_info->dataflow_header->dataflow_length = - clib_host_to_net_u32( - nfv9_logging_info->record_length[NAT44_BULK_DEL_RECORD]); - -} - -#endif /* #ifndef NO_BULK_LOGGING */ -/* - * edt: * * cnat_nfv9_log_mapping_create - * - * Tries to log a creation of mapping record - * - * Argument: cnat_main_db_entry_t *db - * Main DB entry being created - * - * Argument: cnat_vrfmap_t *vrfmap - * VRF Map for the Main DB entry being created - */ -void cnat_nfv9_log_mapping_create (cnat_main_db_entry_t *db, - cnat_vrfmap_t *vrfmap -#ifndef NO_BULK_LOGGING - , int bulk_alloc -#endif - ) -{ - cnat_nfv9_logging_info_t *nfv9_logging_info = 0; - vlib_main_t * vm = vlib_get_main(); - - if (PREDICT_FALSE(vrfmap->nfv9_logging_index == EMPTY)) { - - //vlib_cli_output(vm, "\n1. Log Mapping failed"); - /* - * No logging configured, silently return - */ - return; - } - - if (cnat_nfv9_logging_info_pool == NULL) { - vlib_cli_output(vm, "%s: info_pool pointer is NULL !!!!\n", __func__); - return; - } - nfv9_logging_info = - cnat_nfv9_logging_info_pool + vrfmap->nfv9_logging_index; - - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) { - cnat_nfv9_create_logging_context(nfv9_logging_info, - cnat_nfv9_template_add_default); - - /* - * If still empty, return after increasing the count - */ - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) { - //vlib_cli_output(vm, "\n2. Log Mapping failed"); - return; - } - - } - -#ifndef NO_BULK_LOGGING - if(bulk_alloc > 0) { /* new bulk alloc - use bulk add template */ - cnat_nfv9_insert_bulk_add_record(nfv9_logging_info, db, vrfmap, - bulk_alloc); - } else if(bulk_alloc == CACHE_ALLOC_NO_LOG_REQUIRED) - return; /* No logging required.. bulk port usage */ - else /* Individual logging .. fall back to old method */ -#endif - cnat_nfv9_insert_add_record(nfv9_logging_info, db, vrfmap); - - nfv9_logging_info->total_record_count += 1; - - /* - * If we have exceeded the packet length, let us send the - * packet now. There is buffer of additional bytes beyond - * max_pkt_length to ensure that the last add/delete record - * can be stored safely. - */ - if (PREDICT_FALSE(nfv9_logging_info->pkt_length > - nfv9_logging_info->max_length_minus_max_record_size)) { - cnat_nfv9_send_pkt(nfv9_logging_info); - } -} - -/* - * edt: * * cnat_nfv9_log_mapping_delete - * - * Tries to log a deletion of mapping record - * - * Argument: cnat_main_db_entry_t *db - * Main DB entry being deleted - * - * Argument: cnat_vrfmap_t *vrfmap - * VRF Map for the Main DB entry being deleted - */ -void cnat_nfv9_log_mapping_delete (cnat_main_db_entry_t * db, - cnat_vrfmap_t *vrfmap -#ifndef NO_BULK_LOGGING - , int bulk_alloc -#endif - ) -{ - cnat_nfv9_logging_info_t *nfv9_logging_info = 0; - - if (PREDICT_FALSE(vrfmap->nfv9_logging_index == EMPTY)) { - //vlib_cli_output(vm, "\n3. Log Mapping failed"); - /* - * No logging configured, silently return - */ - return; - } - - nfv9_logging_info = - cnat_nfv9_logging_info_pool + vrfmap->nfv9_logging_index; - - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) { - cnat_nfv9_create_logging_context(nfv9_logging_info, - cnat_nfv9_template_add_default); - - /* - * If still empty, return after increasing the count - */ - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) { - //vlib_cli_output(vm, "\n4. Log Mapping failed"); - return; - } - } -#ifndef NO_BULK_LOGGING - if(bulk_alloc > 0) { /* new bulk alloc - use bulk add template */ - cnat_nfv9_insert_bulk_del_record(nfv9_logging_info, db, vrfmap, - bulk_alloc); - } else if(bulk_alloc == CACHE_ALLOC_NO_LOG_REQUIRED) - return; /* No logging required.. bulk port usage */ - else /* Individual logging .. fall back to old method */ -#endif - cnat_nfv9_insert_del_record(nfv9_logging_info, db, vrfmap); - - nfv9_logging_info->total_record_count += 1; - - /* - * If we have exceeded the packet length, let us send the - * packet now. There is buffer of additional bytes beyond - * max_pkt_length to ensure that the last add/delete record - * can be stored safely. - */ - if (PREDICT_FALSE(nfv9_logging_info->pkt_length > - nfv9_logging_info->max_length_minus_max_record_size)) { - cnat_nfv9_send_pkt(nfv9_logging_info); - } -} - - -/* NAT64 Related routines */ - -/* - * edt: * * cnat_nfv9_bib_mapping_create - * - * Tries to log a creation of Bib mapping record - * - * Argument: nat64_bib_entry_t *db - * BIB DB entry being created - * - * Argument: nat64_table_entry_t *nat64_entry - * NAT64 Instance where this BIB belongs - */ -void cnat_nfv9_bib_mapping_create (nat64_bib_entry_t *db, - nat64_table_entry_t *nat64_entry) -{ - cnat_nfv9_logging_info_t *nfv9_logging_info = 0; - u16 my_proto_mask; - u8 my_protocol; - nfv9_nat64_add_bib_record_t nfv9_logging_add_record; - - if (PREDICT_FALSE(nat64_entry->logging_index == EMPTY)) { - /* - * No logging configured, silently return - */ - return; - } - - nfv9_logging_info = - cnat_nfv9_logging_info_pool + nat64_entry->logging_index; - - - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) { - cnat_nfv9_create_logging_context(nfv9_logging_info, - cnat_nfv9_template_add_default); - - /* - * If still empty, return after increasing the count - */ - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) { - return; - } - } - - if (PREDICT_FALSE(nfv9_logging_info->record[NAT64_ADD_BIB_RECORD] == NULL)){ - cnat_nfv9_record_create(nfv9_logging_info,NAT64_ADD_BIB_RECORD); - } - - - nfv9_logging_add_record.inside_v6_src_addr[0] = - clib_host_to_net_u32(db->v6_in_key.ipv6[0]); - nfv9_logging_add_record.inside_v6_src_addr[1] = - clib_host_to_net_u32(db->v6_in_key.ipv6[1]); - nfv9_logging_add_record.inside_v6_src_addr[2] = - clib_host_to_net_u32(db->v6_in_key.ipv6[2]); - nfv9_logging_add_record.inside_v6_src_addr[3] = - clib_host_to_net_u32(db->v6_in_key.ipv6[3]); - - - nfv9_logging_add_record.outside_v4_src_addr = - clib_host_to_net_u32(db->v4_out_key.k.ipv4); - - nfv9_logging_add_record.inside_src_port = - clib_host_to_net_u16(db->v6_in_key.port); - nfv9_logging_add_record.outside_src_port = - clib_host_to_net_u16(db->v4_out_key.k.port); - - my_proto_mask = db->v6_in_key.vrf & CNAT_PRO_MASK; - - my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT : - ((my_proto_mask == CNAT_TCP) ? TCP_PROT : - ((my_proto_mask == CNAT_ICMP) ? IPV6_PROTO_ICMPV6 : 0))); - nfv9_logging_add_record.protocol = my_protocol; - - - clib_memcpy(nfv9_logging_info->record[NAT64_ADD_BIB_RECORD], - &nfv9_logging_add_record, CNAT_NFV9_NAT64_ADD_BIB_RECORD_LENGTH); - - nfv9_logging_info->record_length[NAT64_ADD_BIB_RECORD] += - CNAT_NFV9_NAT64_ADD_BIB_RECORD_LENGTH; - nfv9_logging_info->pkt_length += CNAT_NFV9_NAT64_ADD_BIB_RECORD_LENGTH; - nfv9_logging_info->total_record_count += 1; - - nfv9_logging_info->record[NAT64_ADD_BIB_RECORD] - += CNAT_NFV9_NAT64_ADD_BIB_RECORD_LENGTH; - - nfv9_logging_info->next_data_ptr = - nfv9_logging_info->record[NAT64_ADD_BIB_RECORD]; - - nfv9_logging_info->dataflow_header->dataflow_length = - clib_host_to_net_u32( - nfv9_logging_info->record_length[NAT64_ADD_BIB_RECORD]); - - /* - * If we have exceeded the packet length, let us send the - * packet now. There is buffer of additional bytes beyond - * max_pkt_length to ensure that the last add/delete record - * can be stored safely. - */ - if (PREDICT_FALSE(nfv9_logging_info->pkt_length > - nfv9_logging_info->max_length_minus_max_record_size)) { - cnat_nfv9_send_pkt(nfv9_logging_info); - } -} - - -/* - * edt: * * cnat_nfv9_session_mapping_create - * - * Tries to log a creation of Bib mapping record - * - * Argument: nat64_bib_entry_t *bdb - * BIB DB entry for the session that is created - * - * Argument: nat64_session_entry_t *sdb - * Session DB entry being created - * - * Argument: nat64_table_entry_t *nat64_entry - * NAT64 Instance where this BIB and Session belongs - */ -void cnat_nfv9_session_mapping_create (nat64_bib_entry_t *bdb, - nat64_session_entry_t *sdb, - nat64_table_entry_t *nat64_entry_ptr) -{ - cnat_nfv9_logging_info_t *nfv9_logging_info = 0; - u16 my_proto_mask; - u8 my_protocol; - u32 dest_v6[4]; - nfv9_nat64_add_session_record_t nfv9_logging_add_record; - u8 *ipv6_addr_ptr; - u8 *ipv4_addr_ptr; - - - if (PREDICT_FALSE(nat64_entry_ptr->logging_index == EMPTY)) { - /* - * No logging configured, silently return - */ - return; - } - - nfv9_logging_info = - cnat_nfv9_logging_info_pool + nat64_entry_ptr->logging_index; - - - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) { - cnat_nfv9_create_logging_context(nfv9_logging_info, - cnat_nfv9_template_add_default); - - /* - * If still empty, return after increasing the count - */ - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)){ - return; - } - } - - if (PREDICT_FALSE(nfv9_logging_info->record[NAT64_ADD_SESSION_RECORD] - == NULL)){ - cnat_nfv9_record_create(nfv9_logging_info, NAT64_ADD_SESSION_RECORD); - } - - - nfv9_logging_add_record.inside_v6_src_addr[0] = - clib_host_to_net_u32(bdb->v6_in_key.ipv6[0]); - nfv9_logging_add_record.inside_v6_src_addr[1] = - clib_host_to_net_u32(bdb->v6_in_key.ipv6[1]); - nfv9_logging_add_record.inside_v6_src_addr[2] = - clib_host_to_net_u32(bdb->v6_in_key.ipv6[2]); - nfv9_logging_add_record.inside_v6_src_addr[3] = - clib_host_to_net_u32(bdb->v6_in_key.ipv6[3]); - - - nfv9_logging_add_record.outside_v4_src_addr = - clib_host_to_net_u32(bdb->v4_out_key.k.ipv4); - - - nfv9_logging_add_record.outside_v4_dest_addr = - clib_host_to_net_u32(sdb->v4_dest_key.k.ipv4); - - /* Need to create the V6 address using prefix */ - dest_v6[0] = nat64_entry_ptr->v6_prefix[0]; - dest_v6[1] = nat64_entry_ptr->v6_prefix[1]; - dest_v6[2] = nat64_entry_ptr->v6_prefix[2]; - dest_v6[3] = nat64_entry_ptr->v6_prefix[3]; - - ipv6_addr_ptr = (u8 *) (&(dest_v6[0])); - ipv4_addr_ptr = (u8 *) (&(sdb->v4_dest_key.k.ipv4)); - - *(ipv6_addr_ptr + nat64_entry_ptr->octet0_position) = *(ipv4_addr_ptr); - *(ipv6_addr_ptr + nat64_entry_ptr->octet1_position) = *(ipv4_addr_ptr + 1); - *(ipv6_addr_ptr + nat64_entry_ptr->octet2_position) = *(ipv4_addr_ptr + 2); - *(ipv6_addr_ptr + nat64_entry_ptr->octet3_position) = *(ipv4_addr_ptr + 3); - - nfv9_logging_add_record.inside_v6_dest_addr[0] = - clib_host_to_net_u32(dest_v6[0]); - nfv9_logging_add_record.inside_v6_dest_addr[1] = - clib_host_to_net_u32(dest_v6[1]); - nfv9_logging_add_record.inside_v6_dest_addr[2] = - clib_host_to_net_u32(dest_v6[2]); - nfv9_logging_add_record.inside_v6_dest_addr[3] = - clib_host_to_net_u32(dest_v6[3]); - - nfv9_logging_add_record.outside_v4_dest_addr = - clib_host_to_net_u32(sdb->v4_dest_key.k.ipv4); - - nfv9_logging_add_record.inside_src_port = - clib_host_to_net_u16(bdb->v6_in_key.port); - nfv9_logging_add_record.outside_src_port = - clib_host_to_net_u16(bdb->v4_out_key.k.port); - - nfv9_logging_add_record.dest_port = - clib_host_to_net_u16(sdb->v4_dest_key.k.port); - - - my_proto_mask = bdb->v6_in_key.vrf & CNAT_PRO_MASK; - - my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT : - ((my_proto_mask == CNAT_TCP) ? TCP_PROT : - ((my_proto_mask == CNAT_ICMP) ? IPV6_PROTO_ICMPV6 : 0))); - nfv9_logging_add_record.protocol = my_protocol; - - - clib_memcpy(nfv9_logging_info->record[NAT64_ADD_SESSION_RECORD], - &nfv9_logging_add_record, CNAT_NFV9_NAT64_ADD_SESSION_RECORD_LENGTH); - - nfv9_logging_info->record_length[NAT64_ADD_SESSION_RECORD] += - CNAT_NFV9_NAT64_ADD_SESSION_RECORD_LENGTH; - nfv9_logging_info->pkt_length += CNAT_NFV9_NAT64_ADD_SESSION_RECORD_LENGTH; - nfv9_logging_info->total_record_count += 1; - - nfv9_logging_info->record[NAT64_ADD_SESSION_RECORD] - += CNAT_NFV9_NAT64_ADD_SESSION_RECORD_LENGTH; - - nfv9_logging_info->next_data_ptr = - nfv9_logging_info->record[NAT64_ADD_SESSION_RECORD]; - - nfv9_logging_info->dataflow_header->dataflow_length = - clib_host_to_net_u32( - nfv9_logging_info->record_length[NAT64_ADD_SESSION_RECORD]); - - /* - * If we have exceeded the packet length, let us send the - * packet now. There is buffer of additional bytes beyond - * max_pkt_length to ensure that the last add/delete record - * can be stored safely. - */ - if (PREDICT_FALSE(nfv9_logging_info->pkt_length > - nfv9_logging_info->max_length_minus_max_record_size)) { - cnat_nfv9_send_pkt(nfv9_logging_info); - } -} - - -/* - * edt: * * cnat_nfv9_bib_mapping_delete - * - * Tries to log a deletion of Bib mapping record - * - * Argument: nat64_bib_entry_t *db - * BIB DB entry being created - * - * Argument: nat64_table_entry_t *nat64_entry - * NAT64 Instance where this BIB belongs - */ -void cnat_nfv9_bib_mapping_delete (nat64_bib_entry_t *db, - nat64_table_entry_t *nat64_entry) -{ - cnat_nfv9_logging_info_t *nfv9_logging_info = 0; - u16 my_proto_mask; - u8 my_protocol; - nfv9_nat64_del_bib_record_t nfv9_logging_del_record; - if (PREDICT_FALSE(nat64_entry->logging_index == EMPTY)) { - /* - * No logging configured, silently return - */ - return; - } - - nfv9_logging_info = - cnat_nfv9_logging_info_pool + nat64_entry->logging_index; - - - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) { - cnat_nfv9_create_logging_context(nfv9_logging_info, - cnat_nfv9_template_add_default); - - /* - * If still empty, return after increasing the count - */ - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)){ - return; - } - } - - if (PREDICT_FALSE(nfv9_logging_info->record[NAT64_DEL_BIB_RECORD] == NULL)){ - cnat_nfv9_record_create(nfv9_logging_info,NAT64_DEL_BIB_RECORD); - } - - - nfv9_logging_del_record.inside_v6_src_addr[0] = - clib_host_to_net_u32(db->v6_in_key.ipv6[0]); - nfv9_logging_del_record.inside_v6_src_addr[1] = - clib_host_to_net_u32(db->v6_in_key.ipv6[1]); - nfv9_logging_del_record.inside_v6_src_addr[2] = - clib_host_to_net_u32(db->v6_in_key.ipv6[2]); - nfv9_logging_del_record.inside_v6_src_addr[3] = - clib_host_to_net_u32(db->v6_in_key.ipv6[3]); - - - nfv9_logging_del_record.inside_src_port = - clib_host_to_net_u16(db->v6_in_key.port); - - my_proto_mask = db->v6_in_key.vrf & CNAT_PRO_MASK; - - my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT : - ((my_proto_mask == CNAT_TCP) ? TCP_PROT : - ((my_proto_mask == CNAT_ICMP) ? IPV6_PROTO_ICMPV6 : 0))); - nfv9_logging_del_record.protocol = my_protocol; - - - clib_memcpy(nfv9_logging_info->record[NAT64_DEL_BIB_RECORD], - &nfv9_logging_del_record, CNAT_NFV9_NAT64_DEL_BIB_RECORD_LENGTH); - - nfv9_logging_info->record_length[NAT64_DEL_BIB_RECORD] += - CNAT_NFV9_NAT64_DEL_BIB_RECORD_LENGTH; - nfv9_logging_info->pkt_length += CNAT_NFV9_NAT64_DEL_BIB_RECORD_LENGTH; - nfv9_logging_info->total_record_count += 1; - - nfv9_logging_info->record[NAT64_DEL_BIB_RECORD] - += CNAT_NFV9_NAT64_DEL_BIB_RECORD_LENGTH; - - nfv9_logging_info->next_data_ptr = - nfv9_logging_info->record[NAT64_DEL_BIB_RECORD]; - - nfv9_logging_info->dataflow_header->dataflow_length = - clib_host_to_net_u32( - nfv9_logging_info->record_length[NAT64_DEL_BIB_RECORD]); - - /* - * If we have exceeded the packet length, let us send the - * packet now. There is buffer of additional bytes beyond - * max_pkt_length to ensure that the last add/delete record - * can be stored safely. - */ - if (PREDICT_FALSE(nfv9_logging_info->pkt_length > - nfv9_logging_info->max_length_minus_max_record_size)) { - cnat_nfv9_send_pkt(nfv9_logging_info); - } -} - - -/* - * edt: * * cnat_nfv9_session_mapping_delete - * - * Tries to log a deletion of Bib mapping record - * - * Argument: nat64_bib_entry_t *bdb - * BIB DB entry for the session that is created - * - * Argument: nat64_session_entry_t *sdb - * Session DB entry being created - * - * Argument: nat64_table_entry_t *nat64_entry - * NAT64 Instance where this BIB and Session belongs - */ -void cnat_nfv9_session_mapping_delete (nat64_bib_entry_t *bdb, - nat64_session_entry_t *sdb, - nat64_table_entry_t *nat64_entry_ptr) -{ - cnat_nfv9_logging_info_t *nfv9_logging_info = 0; - u16 my_proto_mask; - u8 my_protocol; - u32 dest_v6[4]; - nfv9_nat64_del_session_record_t nfv9_logging_del_record; - u8 *ipv6_addr_ptr; - u8 *ipv4_addr_ptr; - - if (PREDICT_FALSE(nat64_entry_ptr->logging_index == EMPTY)) { - /* - * No logging configured, silently return - */ - return; - } - - nfv9_logging_info = - cnat_nfv9_logging_info_pool + nat64_entry_ptr->logging_index; - - - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) { - cnat_nfv9_create_logging_context(nfv9_logging_info, - cnat_nfv9_template_add_default); - - /* - * If still empty, return after increasing the count - */ - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)){ - return; - } - } - - if (PREDICT_FALSE(nfv9_logging_info->record[NAT64_DEL_SESSION_RECORD] - == NULL)){ - cnat_nfv9_record_create(nfv9_logging_info, NAT64_DEL_SESSION_RECORD); - } - - - nfv9_logging_del_record.inside_v6_src_addr[0] = - clib_host_to_net_u32(bdb->v6_in_key.ipv6[0]); - nfv9_logging_del_record.inside_v6_src_addr[1] = - clib_host_to_net_u32(bdb->v6_in_key.ipv6[1]); - nfv9_logging_del_record.inside_v6_src_addr[2] = - clib_host_to_net_u32(bdb->v6_in_key.ipv6[2]); - nfv9_logging_del_record.inside_v6_src_addr[3] = - clib_host_to_net_u32(bdb->v6_in_key.ipv6[3]); - - /* Need to create the V6 address using prefix */ - dest_v6[0] = nat64_entry_ptr->v6_prefix[0]; - dest_v6[1] = nat64_entry_ptr->v6_prefix[1]; - dest_v6[2] = nat64_entry_ptr->v6_prefix[2]; - dest_v6[3] = nat64_entry_ptr->v6_prefix[3]; - - ipv6_addr_ptr = (u8 *) (&(dest_v6[0])); - ipv4_addr_ptr = (u8 *) (&(sdb->v4_dest_key.k.ipv4)); - - *(ipv6_addr_ptr + nat64_entry_ptr->octet0_position) = *(ipv4_addr_ptr); - *(ipv6_addr_ptr + nat64_entry_ptr->octet1_position) = *(ipv4_addr_ptr + 1); - *(ipv6_addr_ptr + nat64_entry_ptr->octet2_position) = *(ipv4_addr_ptr + 2); - *(ipv6_addr_ptr + nat64_entry_ptr->octet3_position) = *(ipv4_addr_ptr + 3); - - nfv9_logging_del_record.inside_v6_dest_addr[0] = - clib_host_to_net_u32(dest_v6[0]); - nfv9_logging_del_record.inside_v6_dest_addr[1] = - clib_host_to_net_u32(dest_v6[1]); - nfv9_logging_del_record.inside_v6_dest_addr[2] = - clib_host_to_net_u32(dest_v6[2]); - nfv9_logging_del_record.inside_v6_dest_addr[3] = - clib_host_to_net_u32(dest_v6[3]); - - nfv9_logging_del_record.inside_src_port = - clib_host_to_net_u16(bdb->v6_in_key.port); - - nfv9_logging_del_record.dest_port = - clib_host_to_net_u16(sdb->v4_dest_key.k.port); - - - my_proto_mask = bdb->v6_in_key.vrf & CNAT_PRO_MASK; - - my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT : - ((my_proto_mask == CNAT_TCP) ? TCP_PROT : - ((my_proto_mask == CNAT_ICMP) ? IPV6_PROTO_ICMPV6 : 0))); - nfv9_logging_del_record.protocol = my_protocol; - - clib_memcpy(nfv9_logging_info->record[NAT64_DEL_SESSION_RECORD], - &nfv9_logging_del_record, CNAT_NFV9_NAT64_DEL_SESSION_RECORD_LENGTH); - - nfv9_logging_info->record_length[NAT64_DEL_SESSION_RECORD] += - CNAT_NFV9_NAT64_DEL_SESSION_RECORD_LENGTH; - nfv9_logging_info->pkt_length += CNAT_NFV9_NAT64_DEL_SESSION_RECORD_LENGTH; - nfv9_logging_info->total_record_count += 1; - - nfv9_logging_info->record[NAT64_DEL_SESSION_RECORD] - += CNAT_NFV9_NAT64_DEL_SESSION_RECORD_LENGTH; - - nfv9_logging_info->next_data_ptr = - nfv9_logging_info->record[NAT64_DEL_SESSION_RECORD]; - - nfv9_logging_info->dataflow_header->dataflow_length = - clib_host_to_net_u32( - nfv9_logging_info->record_length[NAT64_DEL_SESSION_RECORD]); - - /* - * If we have exceeded the packet length, let us send the - * packet now. There is buffer of additional bytes beyond - * max_pkt_length to ensure that the last add/delete record - * can be stored safely. - */ - if (PREDICT_FALSE(nfv9_logging_info->pkt_length > - nfv9_logging_info->max_length_minus_max_record_size)) { - cnat_nfv9_send_pkt(nfv9_logging_info); - } -} - -/* - * edt: * * cnat_nfv9_nat44_log_session_create - * - * Tries to log a creation of mapping record (session based) - * - * Argument: cnat_main_db_entry_t *db - * Main DB entry being created - * Arugment: cnat_session_entry_t *sdb - * Session DB entry if the destination is not the first dest - * Argument: cnat_vrfmap_t *vrfmap - * VRF Map for the Main DB entry being created - */ - -void cnat_nfv9_nat44_log_session_create(cnat_main_db_entry_t *db, - cnat_session_entry_t *sdb, - cnat_vrfmap_t *vrfmap) -{ - cnat_nfv9_logging_info_t *nfv9_logging_info = 0; - u16 my_proto_mask; - u8 my_protocol; - nfv9_add_session_record_t nfv9_logging_add_session_record; - - if (PREDICT_FALSE(vrfmap->nfv9_logging_index == EMPTY)) { - //vlib_cli_output(vm,"\n1. Log Mapping failed"); - /* - * No logging configured, silently return - */ - return; - } - - nfv9_logging_info = - cnat_nfv9_logging_info_pool + vrfmap->nfv9_logging_index; - - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) { - cnat_nfv9_create_logging_context(nfv9_logging_info, - cnat_nfv9_template_add_default); - - /* - * If still empty, return after increasing the count - */ - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) { - //vlib_cli_output(vm,"\n2. Log Mapping failed"); - return; - } - } - - if(PREDICT_FALSE(nfv9_logging_info->record[ - NAT44_ADD_SESSION_RECORD] == NULL)) { - cnat_nfv9_record_create(nfv9_logging_info, NAT44_ADD_SESSION_RECORD); - } - - /* - * We should definitely have add_record now, no need to sanitize - */ - nfv9_logging_add_session_record.inside_vrf_id = - clib_host_to_net_u32(vrfmap->i_vrf_id); - nfv9_logging_add_session_record.outside_vrf_id = - clib_host_to_net_u32(vrfmap->o_vrf_id); - - nfv9_logging_add_session_record.inside_ip_addr = - clib_host_to_net_u32(db->in2out_key.k.ipv4); - nfv9_logging_add_session_record.outside_ip_addr = - clib_host_to_net_u32(db->out2in_key.k.ipv4); - - /* If sdb is null, it is assumed that logging is being done - * for the first destination which is held in the main db - - * itself - */ - if(PREDICT_TRUE(sdb == NULL)) { - nfv9_logging_add_session_record.dest_ip_addr = - clib_host_to_net_u32(db->dst_ipv4); - nfv9_logging_add_session_record.dest_port = - clib_host_to_net_u16(db->dst_port); - } else { - nfv9_logging_add_session_record.dest_ip_addr = - clib_host_to_net_u32(sdb->v4_dest_key.k.ipv4); - nfv9_logging_add_session_record.dest_port = - clib_host_to_net_u16(sdb->v4_dest_key.k.port); - } - - nfv9_logging_add_session_record.inside_ip_port = - clib_host_to_net_u16(db->in2out_key.k.port); - nfv9_logging_add_session_record.outside_ip_port = - clib_host_to_net_u16(db->out2in_key.k.port); - - - my_proto_mask = db->in2out_key.k.vrf & CNAT_PRO_MASK; - - my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT : - ((my_proto_mask == CNAT_TCP) ? TCP_PROT : - ((my_proto_mask == CNAT_ICMP) ? ICMP_PROT : GRE_PROT))); - nfv9_logging_add_session_record.protocol = my_protocol; - - clib_memcpy(nfv9_logging_info->record[NAT44_ADD_SESSION_RECORD], - &nfv9_logging_add_session_record, - CNAT_NFV9_NAT44_ADD_SESSION_RECORD_LENGTH); - - nfv9_logging_info->record_length[NAT44_ADD_SESSION_RECORD] - += CNAT_NFV9_NAT44_ADD_SESSION_RECORD_LENGTH; - nfv9_logging_info->pkt_length += CNAT_NFV9_NAT44_ADD_SESSION_RECORD_LENGTH; - nfv9_logging_info->total_record_count += 1; - - - nfv9_logging_info->record[NAT44_ADD_SESSION_RECORD] - += CNAT_NFV9_NAT44_ADD_SESSION_RECORD_LENGTH; - - nfv9_logging_info->next_data_ptr = - nfv9_logging_info->record[NAT44_ADD_SESSION_RECORD]; - - nfv9_logging_info->dataflow_header->dataflow_length = - clib_host_to_net_u32( - nfv9_logging_info->record_length[NAT44_ADD_SESSION_RECORD]); - - /* - * If we have exceeded the packet length, let us send the - * packet now. There is buffer of additional bytes beyond - * max_pkt_length to ensure that the last add/delete record - * can be stored safely. - */ - if (PREDICT_FALSE(nfv9_logging_info->pkt_length > - nfv9_logging_info->max_length_minus_max_record_size)) { - cnat_nfv9_send_pkt(nfv9_logging_info); - } -} - -/* - * edt: * * cnat_nfv9_nat44_log_session_delete - * - * Tries to log a deletion of mapping record (session based) - * - * Argument: cnat_main_db_entry_t *db - * Main DB entry being created - * Arugment: cnat_session_entry_t *sdb - * Session DB entry if the destination is not the first dest - * Argument: cnat_vrfmap_t *vrfmap - * VRF Map for the Main DB entry being deleted - */ - -void cnat_nfv9_nat44_log_session_delete(cnat_main_db_entry_t *db, - cnat_session_entry_t *sdb, - cnat_vrfmap_t *vrfmap) -{ - cnat_nfv9_logging_info_t *nfv9_logging_info = 0; - u16 my_proto_mask; - u8 my_protocol; - nfv9_del_session_record_t nfv9_logging_del_session_record; - - if (PREDICT_FALSE(vrfmap->nfv9_logging_index == EMPTY)) { - //vlib_cli_output(vm, "\n1. Log Mapping failed"); - /* - * No logging configured, silently return - */ - return; - } - - nfv9_logging_info = - cnat_nfv9_logging_info_pool + vrfmap->nfv9_logging_index; - - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) { - cnat_nfv9_create_logging_context(nfv9_logging_info, - cnat_nfv9_template_add_default); - - /* - * If still empty, return after increasing the count - */ - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) { - //vlib_cli_output(vm, "\n2. Log Mapping failed"); - return; - } - } - - if(PREDICT_FALSE(nfv9_logging_info->record[ - NAT44_DEL_SESSION_RECORD] == NULL)) { - cnat_nfv9_record_create(nfv9_logging_info, NAT44_DEL_SESSION_RECORD); - } - - /* - * We should definitely have add_record now, no need to sanitize - */ - nfv9_logging_del_session_record.inside_vrf_id = - clib_host_to_net_u32(vrfmap->i_vrf_id); - - nfv9_logging_del_session_record.inside_ip_addr = - clib_host_to_net_u32(db->in2out_key.k.ipv4); - - /* If sdb is null, it is assumed that logging is being done - * for the first destination which is held in the main db - * itself - */ - if(PREDICT_TRUE(sdb == NULL)) { - nfv9_logging_del_session_record.dest_ip_addr = - clib_host_to_net_u32(db->dst_ipv4); - nfv9_logging_del_session_record.dest_port = - clib_host_to_net_u16(db->dst_port); - } else { - nfv9_logging_del_session_record.dest_ip_addr = - clib_host_to_net_u32(sdb->v4_dest_key.k.ipv4); - nfv9_logging_del_session_record.dest_port = - clib_host_to_net_u16(sdb->v4_dest_key.k.port); - } - - nfv9_logging_del_session_record.inside_ip_port = - clib_host_to_net_u16(db->in2out_key.k.port); - - my_proto_mask = db->in2out_key.k.vrf & CNAT_PRO_MASK; - my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT : - ((my_proto_mask == CNAT_TCP) ? TCP_PROT : - ((my_proto_mask == CNAT_ICMP) ? ICMP_PROT : GRE_PROT))); - - nfv9_logging_del_session_record.protocol = my_protocol; - - clib_memcpy(nfv9_logging_info->record[NAT44_DEL_SESSION_RECORD], - &nfv9_logging_del_session_record, - CNAT_NFV9_NAT44_DEL_SESSION_RECORD_LENGTH); - - nfv9_logging_info->record_length[NAT44_DEL_SESSION_RECORD] - += CNAT_NFV9_NAT44_DEL_SESSION_RECORD_LENGTH; - nfv9_logging_info->pkt_length += CNAT_NFV9_NAT44_DEL_SESSION_RECORD_LENGTH; - nfv9_logging_info->total_record_count += 1; - - nfv9_logging_info->record[NAT44_DEL_SESSION_RECORD] - += CNAT_NFV9_NAT44_DEL_SESSION_RECORD_LENGTH; - - nfv9_logging_info->next_data_ptr = - nfv9_logging_info->record[NAT44_DEL_SESSION_RECORD]; - - nfv9_logging_info->dataflow_header->dataflow_length = - clib_host_to_net_u32( - nfv9_logging_info->record_length[NAT44_DEL_SESSION_RECORD]); - - /* - * If we have exceeded the packet length, let us send the - * packet now. There is buffer of additional bytes beyond - * max_pkt_length to ensure that the last add/delete record - * can be stored safely. - */ - if (PREDICT_FALSE(nfv9_logging_info->pkt_length > - nfv9_logging_info->max_length_minus_max_record_size)) { - cnat_nfv9_send_pkt(nfv9_logging_info); - } -} - -/* - * DS-Lite APIs for netflow logging - */ - -/* - * edt: * * cnat_nfv9_ds_lite_mapping_create - * - * Tries to log a creation of mapping record - * - * Argument: cnat_main_db_entry_t *db - * Main DB entry being created - * - * Argument: dslite_table_entry_t *dslite_entry - * ds-lite instance for the Main DB entry being created - */ -void cnat_nfv9_ds_lite_mapping_create(cnat_main_db_entry_t *db, - dslite_table_entry_t *dslite_entry -#ifndef NO_BULK_LOGGING - , int bulk_alloc -#endif - ) -{ - - cnat_nfv9_logging_info_t *nfv9_logging_info = NULL; - - if (PREDICT_FALSE(!(db && dslite_entry))) { - return; - } - if (PREDICT_FALSE(dslite_entry->nfv9_logging_index == EMPTY)) { - /* - * no logging configured, silently return - */ - return; - } - - nfv9_logging_info = - cnat_nfv9_logging_info_pool + dslite_entry->nfv9_logging_index; - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) { - cnat_nfv9_create_logging_context(nfv9_logging_info, - cnat_nfv9_template_add_default); - /* - * If still empty, return after increasing the count - */ - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) { - return; - } - } -#ifndef NO_BULK_LOGGING - if(bulk_alloc > 0) { /* new bulk alloc - use bulk add template */ - cnat_nfv9_ds_lite_insert_bulk_add_record(nfv9_logging_info, - db, dslite_entry, bulk_alloc); - } else if(bulk_alloc == CACHE_ALLOC_NO_LOG_REQUIRED) - return; /* No logging required.. bulk port usage */ - else /* Individual logging .. fall back to old method */ -#endif /*NO_BULK_LOGGING*/ - cnat_nfv9_ds_lite_insert_add_record(nfv9_logging_info, db, dslite_entry); - /* - * If we have exceeded the packet length, let us send the - * packet now. There is buffer of additional bytes beyond - * max_pkt_length to ensure that the last add/delete record - * can be stored safely. - */ - if (PREDICT_FALSE(nfv9_logging_info->pkt_length > - nfv9_logging_info->max_length_minus_max_record_size)) { - cnat_nfv9_send_pkt(nfv9_logging_info); - } -} - -/* - * edt: * * cnat_nfv9_ds_lite_mapping_delete - * - * Tries to log a deletion of mapping record - * - * Argument: cnat_main_db_entry_t *db - * Main DB entry being deleted - * - * Argument: dslite_table_entry_t *dslite_entry - * ds-lite instance for the Main DB entry being deleted - */ -void cnat_nfv9_ds_lite_mapping_delete(cnat_main_db_entry_t *db, - dslite_table_entry_t *dslite_entry -#ifndef NO_BULK_LOGGING - , int bulk_alloc -#endif - ) -{ - - cnat_nfv9_logging_info_t *nfv9_logging_info = NULL; - if (PREDICT_FALSE(!(db && dslite_entry))) { - return; - } - if (PREDICT_FALSE(dslite_entry->nfv9_logging_index == EMPTY)) { - /* - * No logging configured, silently return - */ - return; - } - nfv9_logging_info = - cnat_nfv9_logging_info_pool + dslite_entry->nfv9_logging_index; - - - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) { - cnat_nfv9_create_logging_context(nfv9_logging_info, - cnat_nfv9_template_add_default); - /* - * If still empty, return after increasing the count - */ - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) { - return; - } - } -#ifndef NO_BULK_LOGGING - if(bulk_alloc > 0) { /* new bulk alloc - use bulk add template */ - cnat_nfv9_ds_lite_insert_bulk_del_record(nfv9_logging_info, - db, dslite_entry, bulk_alloc); - } else if(bulk_alloc == CACHE_ALLOC_NO_LOG_REQUIRED) - return; /* No logging required.. bulk port usage */ - else /* Individual logging .. fall back to old method */ -#endif /*NO_BULK_LOGGING*/ - cnat_nfv9_ds_lite_insert_del_record(nfv9_logging_info, db, dslite_entry); - /* - * If we have exceeded the packet length, let us send the - * packet now. There is buffer of additional bytes beyond - * max_pkt_length to ensure that the last add/delete record - * can be stored safely. - */ - if (PREDICT_FALSE(nfv9_logging_info->pkt_length > - nfv9_logging_info->max_length_minus_max_record_size)) { - cnat_nfv9_send_pkt(nfv9_logging_info); - } -} - -/* - * edt: * * cnat_nfv9_dslite_log_session_create - * - * Tries to log a creation of mapping record (session based) - * Argument: cnat_main_db_entry_t *db - * Main DB entry being created - * Arugment: cnat_session_entry_t *sdb - * Session DB entry if the destination is not the first dest - * Argument: dslite_table_entry_t *dslite_entry, - * dslite table entry for dslite instance - */ - -void cnat_nfv9_ds_lite_log_session_create( - cnat_main_db_entry_t *db, - dslite_table_entry_t *dslite_entry, - cnat_session_entry_t *sdb) -{ - - nfv9_ds_lite_add_session_record_t nfv9_logging_add_record ; - cnat_user_db_entry_t *udb = NULL; - u16 my_proto_mask; - u8 my_protocol; - cnat_nfv9_logging_info_t *nfv9_logging_info = 0; - - if (PREDICT_FALSE(dslite_entry->nfv9_logging_index == EMPTY)) { - /* - * no logging configured, silently return - */ - return; - } - - nfv9_logging_info = - cnat_nfv9_logging_info_pool + dslite_entry->nfv9_logging_index; - udb = cnat_user_db + db->user_index; - - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) { - cnat_nfv9_create_logging_context(nfv9_logging_info, - cnat_nfv9_template_add_default); - - /* - * If still empty, return after increasing the count - */ - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) { - return; - } - } - - udb = cnat_user_db + db->user_index; - if (PREDICT_FALSE(!udb)) { - return; - } - if (PREDICT_FALSE(nfv9_logging_info->record[DS_LITE_ADD_SESSION_RECORD] == NULL)) { - cnat_nfv9_record_create(nfv9_logging_info, DS_LITE_ADD_SESSION_RECORD); - } - /* - * We should definitely have add_record now, no need to sanitize - */ - nfv9_logging_add_record.inside_vrf_id = - clib_host_to_net_u32(dslite_entry->i_vrf_id); - nfv9_logging_add_record.outside_vrf_id = - clib_host_to_net_u32(dslite_entry->o_vrf_id); - - nfv9_logging_add_record.inside_ip_addr = - clib_host_to_net_u32(db->in2out_key.k.ipv4); - - nfv9_logging_add_record.inside_v6_src_addr[0] = - clib_host_to_net_u32(udb->ipv6[0]); - nfv9_logging_add_record.inside_v6_src_addr[1] = - clib_host_to_net_u32(udb->ipv6[1]); - nfv9_logging_add_record.inside_v6_src_addr[2] = - clib_host_to_net_u32(udb->ipv6[2]); - nfv9_logging_add_record.inside_v6_src_addr[3] = - clib_host_to_net_u32(udb->ipv6[3]); - - nfv9_logging_add_record.outside_ip_addr = - clib_host_to_net_u32(db->out2in_key.k.ipv4); - - nfv9_logging_add_record.inside_ip_port = - clib_host_to_net_u16(db->in2out_key.k.port); - nfv9_logging_add_record.outside_ip_port = - clib_host_to_net_u16(db->out2in_key.k.port); - - /* If sdb is null, it is assumed that logging is being done - * for the first destination which is held in the main db - - * itself - */ - if(PREDICT_TRUE(sdb == NULL)) { - nfv9_logging_add_record.dest_ip_addr = - clib_host_to_net_u32(db->dst_ipv4); - nfv9_logging_add_record.dest_port = - clib_host_to_net_u16(db->dst_port); - } else { - nfv9_logging_add_record.dest_ip_addr = - clib_host_to_net_u32(sdb->v4_dest_key.k.ipv4); - nfv9_logging_add_record.dest_port = - clib_host_to_net_u16(sdb->v4_dest_key.k.port); - } - - - my_proto_mask = db->in2out_key.k.vrf & CNAT_PRO_MASK; - - my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT : - ((my_proto_mask == CNAT_TCP) ? TCP_PROT : - ((my_proto_mask == CNAT_ICMP) ? ICMP_PROT : 0))); - nfv9_logging_add_record.protocol = my_protocol; - - clib_memcpy(nfv9_logging_info->record[DS_LITE_ADD_SESSION_RECORD], - &nfv9_logging_add_record, CNAT_NFV9_DS_LITE_ADD_SESSION_RECORD_LENGTH); - - nfv9_logging_info->record_length[DS_LITE_ADD_SESSION_RECORD] - += CNAT_NFV9_DS_LITE_ADD_SESSION_RECORD_LENGTH; - - nfv9_logging_info->pkt_length += CNAT_NFV9_DS_LITE_ADD_SESSION_RECORD_LENGTH; - nfv9_logging_info->total_record_count += 1; - - nfv9_logging_info->record[DS_LITE_ADD_SESSION_RECORD] - += CNAT_NFV9_DS_LITE_ADD_SESSION_RECORD_LENGTH; - nfv9_logging_info->next_data_ptr = - nfv9_logging_info->record[DS_LITE_ADD_SESSION_RECORD]; - - nfv9_logging_info->dataflow_header->dataflow_length = - clib_host_to_net_u32( - nfv9_logging_info->record_length[DS_LITE_ADD_SESSION_RECORD]); - - /* - * If we have exceeded the packet length, let us send the - * packet now. There is buffer of additional bytes beyond - * max_pkt_length to ensure that the last add/delete record - * can be stored safely. - */ - if (PREDICT_FALSE(nfv9_logging_info->pkt_length > - nfv9_logging_info->max_length_minus_max_record_size)) { - cnat_nfv9_send_pkt(nfv9_logging_info); - } - -} - -/* - * edt: * * cnat_nfv9_dslite_log_session_delete - * - * Tries to log a creation of mapping record (session based) - * Argument: cnat_main_db_entry_t *db - * Main DB entry being created - * Arugment: cnat_session_entry_t *sdb - * Session DB entry if the destination is not the first dest - * Argument: dslite_table_entry_t *dslite_entry, - * dslite table entry for dslite instance - */ - -void cnat_nfv9_ds_lite_log_session_delete( - cnat_main_db_entry_t *db, - dslite_table_entry_t *dslite_entry, - cnat_session_entry_t *sdb) -{ - - nfv9_ds_lite_del_session_record_t nfv9_logging_add_record = {0}; - cnat_user_db_entry_t *udb = NULL; - u16 my_proto_mask; - u8 my_protocol; - cnat_nfv9_logging_info_t *nfv9_logging_info = NULL; - - if (PREDICT_FALSE(dslite_entry->nfv9_logging_index == EMPTY)) { - /* - * no logging configured, silently return - */ - return; - } - - nfv9_logging_info = - cnat_nfv9_logging_info_pool + dslite_entry->nfv9_logging_index; - udb = cnat_user_db + db->user_index; - - if (PREDICT_FALSE(!udb)) { - return; - } - - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) { - cnat_nfv9_create_logging_context(nfv9_logging_info, - cnat_nfv9_template_add_default); - - /* - * If still empty, return after increasing the count - */ - if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) { - return; - } - } - - if (PREDICT_FALSE(nfv9_logging_info->record[DS_LITE_DEL_SESSION_RECORD] == NULL)) { - cnat_nfv9_record_create(nfv9_logging_info, DS_LITE_DEL_SESSION_RECORD); - } - /* - * We should definitely have add_record now, no need to sanitize - */ - nfv9_logging_add_record.inside_vrf_id = - clib_host_to_net_u32(dslite_entry->i_vrf_id); - - nfv9_logging_add_record.inside_ip_addr = - clib_host_to_net_u32(db->in2out_key.k.ipv4); - - nfv9_logging_add_record.inside_v6_src_addr[0] = - clib_host_to_net_u32(udb->ipv6[0]); - nfv9_logging_add_record.inside_v6_src_addr[1] = - clib_host_to_net_u32(udb->ipv6[1]); - nfv9_logging_add_record.inside_v6_src_addr[2] = - clib_host_to_net_u32(udb->ipv6[2]); - nfv9_logging_add_record.inside_v6_src_addr[3] = - clib_host_to_net_u32(udb->ipv6[3]); - - nfv9_logging_add_record.inside_ip_port = - clib_host_to_net_u16(db->in2out_key.k.port); - - /* If sdb is null, it is assumed that logging is being done - * for the first destination which is held in the main db - * itself - */ - if(PREDICT_TRUE(sdb == NULL)) { - nfv9_logging_add_record.dest_ip_addr = - clib_host_to_net_u32(db->dst_ipv4); - nfv9_logging_add_record.dest_port = - clib_host_to_net_u16(db->dst_port); - } else { - nfv9_logging_add_record.dest_ip_addr = - clib_host_to_net_u32(sdb->v4_dest_key.k.ipv4); - nfv9_logging_add_record.dest_port = - clib_host_to_net_u16(sdb->v4_dest_key.k.port); - } - - - my_proto_mask = db->in2out_key.k.vrf & CNAT_PRO_MASK; - - my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT : - ((my_proto_mask == CNAT_TCP) ? TCP_PROT : - ((my_proto_mask == CNAT_ICMP) ? ICMP_PROT : 0))); - nfv9_logging_add_record.protocol = my_protocol; - - clib_memcpy(nfv9_logging_info->record[DS_LITE_DEL_SESSION_RECORD], - &nfv9_logging_add_record, CNAT_NFV9_DS_LITE_DEL_SESSION_RECORD_LENGTH); - - nfv9_logging_info->record_length[DS_LITE_DEL_SESSION_RECORD] - += CNAT_NFV9_DS_LITE_DEL_SESSION_RECORD_LENGTH; - - nfv9_logging_info->pkt_length += CNAT_NFV9_DS_LITE_DEL_SESSION_RECORD_LENGTH; - nfv9_logging_info->total_record_count += 1; - - nfv9_logging_info->record[DS_LITE_DEL_SESSION_RECORD] - += CNAT_NFV9_DS_LITE_DEL_SESSION_RECORD_LENGTH; - nfv9_logging_info->next_data_ptr = - nfv9_logging_info->record[DS_LITE_DEL_SESSION_RECORD]; - - nfv9_logging_info->dataflow_header->dataflow_length = - clib_host_to_net_u32( - nfv9_logging_info->record_length[DS_LITE_DEL_SESSION_RECORD]); - - /* - * If we have exceeded the packet length, let us send the - * packet now. There is buffer of additional bytes beyond - * max_pkt_length to ensure that the last add/delete record - * can be stored safely. - */ - if (PREDICT_FALSE(nfv9_logging_info->pkt_length > - nfv9_logging_info->max_length_minus_max_record_size)) { - cnat_nfv9_send_pkt(nfv9_logging_info); - } - -} - - -/* - * netflow logging API for ingress vrf_id to name mapping - */ - -/* - * edt: * * handle_vrfid_name_mapping - * It will search for valid natflow entry in netflow pool, - * once found one, will send all vrfid name mapping info - * using that entry - */ - - -static inline __attribute__((unused)) -void handle_vrfid_name_mapping(void) -{ - cnat_nfv9_logging_info_t *nfv9_logging_info = NULL; - - pool_foreach (nfv9_logging_info, cnat_nfv9_logging_info_pool, ({ - if(PREDICT_FALSE(nfv9_logging_info == NULL)) { - continue; - } - nfv9_server_info_t *server = nfv9_server_info_pool + - nfv9_logging_info->server_index; - if(server->template_sent == TEMPLATE_SENT_TRUE) { - cnat_nfv9_ingress_vrfid_name_mapping_create(nfv9_logging_info); - server->template_sent = TEMPLATE_SENT_FALSE; - } - })); -} - -/* - * edt: * * cnat_nfv9_ingress_vrfid_name_mapping_create - * - * Tries to log vrfid-name mapping record - * Argument: netflow pointer - */ - - -void cnat_nfv9_ingress_vrfid_name_mapping_create( - cnat_nfv9_logging_info_t *nfv9_logging_info) -{ - u16 index = 0; - - for (index = 0; index < MAX_VRFID; index++) { - if(vrfid_name_map[index].ref_count == 0) { - continue; - } - if (PREDICT_FALSE( - nfv9_logging_info->current_logging_context == NULL)) { - cnat_nfv9_create_logging_context(nfv9_logging_info, - cnat_nfv9_template_add_default); - } - cnat_nfv9_insert_ingress_vrfid_name_record( - nfv9_logging_info,index); - if (PREDICT_FALSE(nfv9_logging_info->pkt_length > - nfv9_logging_info->max_length_minus_max_record_size) || - PREDICT_FALSE(index == MAX_VRFID - 1)) { - if (PREDICT_TRUE(nfv9_logging_info->current_logging_context - != NULL)) { - cnat_nfv9_send_pkt(nfv9_logging_info); - } - } - }/*for()*/ - return; -} - -static void cnat_nfv9_insert_ingress_vrfid_name_record( - cnat_nfv9_logging_info_t *nfv9_logging_info, u16 index) -{ - nfv9_ingress_vrfid_name_record_t nfv9_ingress_vrfid_name_record = {0}; - - if (PREDICT_FALSE( - nfv9_logging_info->record[INGRESS_VRF_ID_NAME_RECORD] == NULL)) { - cnat_nfv9_record_create(nfv9_logging_info, INGRESS_VRF_ID_NAME_RECORD); - } - nfv9_ingress_vrfid_name_record.ingress_vrf_id = - clib_host_to_net_u32(vrfid_name_map[index].vrf_id); - - clib_memcpy(nfv9_ingress_vrfid_name_record.ingress_vrf_name, - vrfid_name_map[index].vrf_name, NFV9_VRF_NAME_LEN); - - clib_memcpy(nfv9_logging_info->record[INGRESS_VRF_ID_NAME_RECORD], - &nfv9_ingress_vrfid_name_record, - CNAT_NFV9_INGRESS_VRFID_NAME_RECORD_LENGTH); - - nfv9_logging_info->record_length[INGRESS_VRF_ID_NAME_RECORD] - += CNAT_NFV9_INGRESS_VRFID_NAME_RECORD_LENGTH; - - nfv9_logging_info->pkt_length += - CNAT_NFV9_INGRESS_VRFID_NAME_RECORD_LENGTH; - - nfv9_logging_info->total_record_count += 1; - - nfv9_logging_info->record[INGRESS_VRF_ID_NAME_RECORD] - += CNAT_NFV9_INGRESS_VRFID_NAME_RECORD_LENGTH; - - nfv9_logging_info->next_data_ptr = - nfv9_logging_info->record[INGRESS_VRF_ID_NAME_RECORD]; - - nfv9_logging_info->dataflow_header->dataflow_length = - clib_host_to_net_u32( - nfv9_logging_info->record_length[INGRESS_VRF_ID_NAME_RECORD]); - return; -} -/* - * edt: * * cnat_log_timer_handler - * - * Timer handler for sending any pending NFV9 record - * - * Argument: spp_timer_t * timer_p - * Timer handler structure - */ -void handle_pending_nfv9_pkts() -{ - vlib_node_t *output_node; - vlib_main_t * vm = vlib_get_main(); - cnat_nfv9_logging_info_t *my_nfv9_logging_info = 0; - u32 current_timestamp = cnat_nfv9_get_sys_up_time_in_ms(); - u32 current_unix_time_in_seconds = cnat_nfv9_get_unix_time_in_seconds(); - - output_node = vlib_get_node_by_name (vm, (u8 *) "ip4-lookup"); - - pool_foreach (my_nfv9_logging_info, cnat_nfv9_logging_info_pool, ({ - nfv9_server_info_t *server = nfv9_server_info_pool + - my_nfv9_logging_info->server_index; - if (my_nfv9_logging_info->queued_logging_context || - (my_nfv9_logging_info->current_logging_context && - (current_timestamp - - my_nfv9_logging_info->current_logging_context_timestamp) - > 1000)) { - /* - * If there is a current logging context and timestamp - * indicates it is pending for long, send it out - * Also if there is a queued context send it out as well - */ - vlib_cli_output(vm, "\nNFV9_TIMER: queued %p, curr %p", - my_nfv9_logging_info->queued_logging_context, - my_nfv9_logging_info->current_logging_context); - - - cnat_nfv9_send_pkt_always_success(my_nfv9_logging_info, - output_node); - } else { - /* - * If the last_template_sent_time is too far back in time - * send the template even if there is no NFv9 records to send - */ - if ((my_nfv9_logging_info->queued_logging_context == NULL) && - (my_nfv9_logging_info->current_logging_context == NULL) && - ((current_unix_time_in_seconds - - server->last_template_sent_time) > - server->timeout_rate)) { - cnat_nfv9_create_logging_context(my_nfv9_logging_info, - cnat_nfv9_template_add_always); - if (PREDICT_TRUE(my_nfv9_logging_info->current_logging_context - != NULL)) { - cnat_nfv9_send_pkt(my_nfv9_logging_info); - } - } - } - })); -} - -/* - * Code to initialize NFV9 Template. This is done when a NFV9 is enabled - * It is done only once and later used when sending NFV9 template records. - */ -static void -cnat_nfv9_template_init (void) -{ - cnat_nfv9_template_info.flowset_id = - clib_host_to_net_u16(CNAT_NFV9_TEMPLATE_FLOWSET_ID); - cnat_nfv9_template_info.length = - clib_host_to_net_u16(CNAT_NFV9_TEMPLATE_LENGTH - - CNAT_NFV9_OPTION_TEMPLATE_LENGTH); - /* - * Create the add Template - */ - cnat_nfv9_template_info.add_template_id = - clib_host_to_net_u16(CNAT_NFV9_ADD_TEMPLATE_ID); - cnat_nfv9_template_info.add_field_count = - clib_host_to_net_u16(CNAT_NFV9_ADD_FIELD_COUNT); - - cnat_nfv9_template_info.add_inside_vrf_id_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE); - cnat_nfv9_template_info.add_inside_vrf_id_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE); - - cnat_nfv9_template_info.add_outside_vrf_id_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_TYPE); - cnat_nfv9_template_info.add_outside_vrf_id_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_SIZE); - - cnat_nfv9_template_info.add_inside_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.add_inside_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.add_outside_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.add_outside_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.add_inside_ip_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE); - cnat_nfv9_template_info.add_inside_ip_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE); - - cnat_nfv9_template_info.add_outside_ip_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_TYPE); - cnat_nfv9_template_info.add_outside_ip_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_SIZE); - - cnat_nfv9_template_info.add_protocol_field_type = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE); - cnat_nfv9_template_info.add_protocol_field_size = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE); - - /* - * Create the delete Template - */ - cnat_nfv9_template_info.del_template_id = - clib_host_to_net_u16(CNAT_NFV9_DEL_TEMPLATE_ID); - cnat_nfv9_template_info.del_field_count = - clib_host_to_net_u16(CNAT_NFV9_DEL_FIELD_COUNT); - - cnat_nfv9_template_info.del_inside_vrf_id_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE); - cnat_nfv9_template_info.del_inside_vrf_id_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE); - - cnat_nfv9_template_info.del_inside_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.del_inside_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.del_inside_ip_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE); - cnat_nfv9_template_info.del_inside_ip_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE); - - cnat_nfv9_template_info.del_protocol_field_type = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE); - cnat_nfv9_template_info.del_protocol_field_size = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE); - - - /* Create NAT64 BIB Add template */ -#if 0 - cnat_nfv9_template_info.nat64_add_bib_template_id = - clib_host_to_net_u16(CNAT_NFV9_NAT64_ADD_BIB_TEMPLATE_ID); - cnat_nfv9_template_info.nat64_add_bib_field_count = - clib_host_to_net_u16(CNAT_NFV9_NAT64_ADD_BIB_FIELD_COUNT); - - - cnat_nfv9_template_info.nat64_add_bib_inside_ipv6_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.nat64_add_bib_inside_ipv6_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.nat64_add_bib_outside_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.nat64_add_bib_outside_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.nat64_add_bib_inside_ip_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE); - cnat_nfv9_template_info.nat64_add_bib_inside_ip_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE); - - cnat_nfv9_template_info.nat64_add_bib_outside_ip_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_TYPE); - cnat_nfv9_template_info.nat64_add_bib_outside_ip_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_SIZE); - - cnat_nfv9_template_info.nat64_add_bib_protocol_field_type = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE); - cnat_nfv9_template_info.nat64_add_bib_protocol_field_size = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE); - - - /* NAT64 BIB Delete */ - cnat_nfv9_template_info.nat64_del_bib_template_id = - clib_host_to_net_u16(CNAT_NFV9_NAT64_DEL_BIB_TEMPLATE_ID); - cnat_nfv9_template_info.nat64_del_bib_field_count = - clib_host_to_net_u16(CNAT_NFV9_NAT64_DEL_BIB_FIELD_COUNT); - - cnat_nfv9_template_info.nat64_del_bib_inside_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.nat64_del_bib_inside_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.nat64_del_bib_inside_ip_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE); - cnat_nfv9_template_info.nat64_del_bib_inside_ip_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE); - - cnat_nfv9_template_info.nat64_del_bib_protocol_field_type = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE); - cnat_nfv9_template_info.nat64_del_bib_protocol_field_size = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE); - - - /* NAt64 SESSION ADD */ - - cnat_nfv9_template_info.nat64_add_session_template_id = - clib_host_to_net_u16(CNAT_NFV9_NAT64_ADD_SESSION_TEMPLATE_ID); - cnat_nfv9_template_info.nat64_add_session_field_count = - clib_host_to_net_u16(CNAT_NFV9_NAT64_ADD_SESSION_FIELD_COUNT); - - - cnat_nfv9_template_info.nat64_add_session_inside_ipv6_src_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.nat64_add_session_inside_ipv6_src_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.nat64_add_session_outside_ip_src_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.nat64_add_session_outside_ip_src_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_SIZE); - - - cnat_nfv9_template_info.nat64_add_session_inside_ipv6_dst_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_DST_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.nat64_add_session_inside_ipv6_dst_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_DST_ADDR_FIELD_SIZE); - - - cnat_nfv9_template_info.nat64_add_session_outside_ip_dst_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_DST_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.nat64_add_session_outside_ip_dst_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_DST_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.nat64_add_session_inside_ip_src_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE); - cnat_nfv9_template_info.nat64_add_session_inside_ip_src_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE); - - - cnat_nfv9_template_info.nat64_add_session_outside_ip_src_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_TYPE); - cnat_nfv9_template_info.nat64_add_session_outside_ip_src_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_SIZE); - - - cnat_nfv9_template_info.nat64_add_session_ip_dest_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_TYPE); - cnat_nfv9_template_info.nat64_add_session_ip_dest_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_SIZE); - - cnat_nfv9_template_info.nat64_add_session_protocol_field_type = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE); - cnat_nfv9_template_info.nat64_add_session_protocol_field_size = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE); - - - - /* Session Delete */ - cnat_nfv9_template_info.nat64_del_session_template_id = - clib_host_to_net_u16(CNAT_NFV9_NAT64_DEL_SESSION_TEMPLATE_ID); - cnat_nfv9_template_info.nat64_del_session_field_count = - clib_host_to_net_u16(CNAT_NFV9_NAT64_DEL_SESSION_FIELD_COUNT); - - cnat_nfv9_template_info.nat64_del_session_inside_ip_src_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.nat64_del_session_inside_ip_src_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.nat64_del_session_inside_ip_dst_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_DST_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.nat64_del_session_inside_ip_dst_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_DST_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.nat64_del_session_inside_ip_src_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE); - cnat_nfv9_template_info.nat64_del_session_inside_ip_src_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE); - - cnat_nfv9_template_info.nat64_del_session_inside_ip_dst_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_TYPE); - cnat_nfv9_template_info.nat64_del_session_inside_ip_dst_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_SIZE); - - cnat_nfv9_template_info.nat64_del_session_protocol_field_type = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE); - cnat_nfv9_template_info.nat64_del_session_protocol_field_size = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE); -#endif - /* - * Create the nat44 session add Template - */ - cnat_nfv9_template_info.nat44_session_add_template_id = - clib_host_to_net_u16(CNAT_NFV9_NAT44_ADD_SESSION_TEMPLATE_ID); - cnat_nfv9_template_info.nat44_session_add_field_count = - clib_host_to_net_u16(CNAT_NFV9_NAT44_ADD_SESSION_FIELD_COUNT); - - cnat_nfv9_template_info.nat44_session_add_inside_vrf_id_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE); - cnat_nfv9_template_info.nat44_session_add_inside_vrf_id_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE); - - cnat_nfv9_template_info.nat44_session_add_outside_vrf_id_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_TYPE); - cnat_nfv9_template_info.nat44_session_add_outside_vrf_id_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_SIZE); - - cnat_nfv9_template_info.nat44_session_add_inside_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.nat44_session_add_inside_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.nat44_session_add_outside_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.nat44_session_add_outside_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.nat44_session_add_inside_ip_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE); - cnat_nfv9_template_info.nat44_session_add_inside_ip_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE); - - cnat_nfv9_template_info.nat44_session_add_outside_ip_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_TYPE); - cnat_nfv9_template_info.nat44_session_add_outside_ip_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_SIZE); - - cnat_nfv9_template_info.nat44_session_add_dest_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_DESTINATION_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.nat44_session_add_dest_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_DESTINATION_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.nat44_session_add_dest_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_TYPE); - cnat_nfv9_template_info.nat44_session_add_dest_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_SIZE); - - cnat_nfv9_template_info.nat44_session_add_protocol_field_type = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE); - cnat_nfv9_template_info.nat44_session_add_protocol_field_size = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE); - - /* - * Create the nat44 session del Template - */ - cnat_nfv9_template_info.nat44_session_del_template_id = - clib_host_to_net_u16(CNAT_NFV9_NAT44_DEL_SESSION_TEMPLATE_ID); - cnat_nfv9_template_info.nat44_session_del_field_count = - clib_host_to_net_u16(CNAT_NFV9_NAT44_DEL_SESSION_FIELD_COUNT); - - cnat_nfv9_template_info.nat44_session_del_inside_vrf_id_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE); - cnat_nfv9_template_info.nat44_session_del_inside_vrf_id_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE); - - cnat_nfv9_template_info.nat44_session_del_inside_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.nat44_session_del_inside_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.nat44_session_del_dest_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_DESTINATION_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.nat44_session_del_dest_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_DESTINATION_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.nat44_session_del_inside_ip_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE); - cnat_nfv9_template_info.nat44_session_del_inside_ip_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE); - - cnat_nfv9_template_info.nat44_session_del_dest_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_TYPE); - cnat_nfv9_template_info.nat44_session_del_dest_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_SIZE); - - cnat_nfv9_template_info.nat44_session_del_protocol_field_type = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE); - cnat_nfv9_template_info.nat44_session_del_protocol_field_size = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE); - /* - * Ds-lite add template - */ -#if 0 - cnat_nfv9_template_info.add_dslite_template_id = - clib_host_to_net_u16(CNAT_NFV9_DS_LITE_ADD_TEMPLATE_ID); - cnat_nfv9_template_info.add_dslite_field_count = - clib_host_to_net_u16(CNAT_NFV9_DS_LITE_ADD_FIELD_COUNT); - - cnat_nfv9_template_info.add_dslite_inside_vrf_id_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE); - cnat_nfv9_template_info.add_dslite_inside_vrf_id_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE); - - cnat_nfv9_template_info.add_dslite_outside_vrf_id_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_TYPE); - cnat_nfv9_template_info.add_dslite_outside_vrf_id_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_SIZE); - - cnat_nfv9_template_info.add_dslite_inside_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.add_dslite_inside_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.add_dslite_inside_ipv6_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.add_dslite_inside_ipv6_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.add_dslite_outside_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.add_dslite_outside_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.add_dslite_inside_ip_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE); - cnat_nfv9_template_info.add_dslite_inside_ip_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE); - - cnat_nfv9_template_info.add_dslite_outside_ip_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_TYPE); - cnat_nfv9_template_info.add_dslite_outside_ip_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_SIZE); - - cnat_nfv9_template_info.add_dslite_protocol_field_type = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE); - cnat_nfv9_template_info.add_dslite_protocol_field_size = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE); - - /* - * Ds-lite delete template - */ - cnat_nfv9_template_info.del_dslite_template_id = - clib_host_to_net_u16(CNAT_NFV9_DS_LITE_DEL_TEMPLATE_ID); - cnat_nfv9_template_info.del_dslite_field_count = - clib_host_to_net_u16(CNAT_NFV9_DS_LITE_DEL_FIELD_COUNT); - - cnat_nfv9_template_info.del_dslite_inside_vrf_id_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE); - cnat_nfv9_template_info.del_dslite_inside_vrf_id_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE); - - cnat_nfv9_template_info.del_dslite_inside_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.del_dslite_inside_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.del_dslite_inside_ipv6_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.del_dslite_inside_ipv6_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.del_dslite_inside_ip_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE); - cnat_nfv9_template_info.del_dslite_inside_ip_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE); - - cnat_nfv9_template_info.del_dslite_protocol_field_type = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE); - cnat_nfv9_template_info.del_dslite_protocol_field_size = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE); - - /* - * Ds-lite session add template - */ - - cnat_nfv9_template_info.add_dslite_session_template_id = - clib_host_to_net_u16(CNAT_NFV9_DS_LITE_ADD_SESSION_TEMPLATE_ID); - cnat_nfv9_template_info.add_dslite_session_field_count = - clib_host_to_net_u16(CNAT_NFV9_DS_LITE_ADD_SESSION_FIELD_COUNT); - - cnat_nfv9_template_info.add_dslite_session_inside_vrf_id_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE); - cnat_nfv9_template_info.add_dslite_session_inside_vrf_id_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE); - - cnat_nfv9_template_info.add_dslite_session_outside_vrf_id_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_TYPE); - cnat_nfv9_template_info.add_dslite_session_outside_vrf_id_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_SIZE); - - cnat_nfv9_template_info.add_dslite_session_inside_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.add_dslite_session_inside_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.add_dslite_session_inside_ipv6_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.add_dslite_session_inside_ipv6_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.add_dslite_session_outside_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.add_dslite_session_outside_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.add_dslite_session_inside_ip_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE); - cnat_nfv9_template_info.add_dslite_session_inside_ip_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE); - - cnat_nfv9_template_info.add_dslite_session_outside_ip_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_TYPE); - cnat_nfv9_template_info.add_dslite_session_outside_ip_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_SIZE); - - cnat_nfv9_template_info.add_dslite_session_dest_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_DESTINATION_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.add_dslite_session_dest_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_DESTINATION_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.add_dslite_session_dest_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_TYPE); - cnat_nfv9_template_info.add_dslite_session_dest_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_SIZE); - - cnat_nfv9_template_info.add_dslite_session_protocol_field_type = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE); - cnat_nfv9_template_info.add_dslite_session_protocol_field_size = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE); - - /* - * Ds-lite session delete template - */ - cnat_nfv9_template_info.del_dslite_session_template_id = - clib_host_to_net_u16(CNAT_NFV9_DS_LITE_DEL_SESSION_TEMPLATE_ID); - cnat_nfv9_template_info.del_dslite_session_field_count = - clib_host_to_net_u16(CNAT_NFV9_DS_LITE_DEL_SESSION_FIELD_COUNT); - - cnat_nfv9_template_info.del_dslite_session_inside_vrf_id_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE); - cnat_nfv9_template_info.del_dslite_session_inside_vrf_id_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE); - - cnat_nfv9_template_info.del_dslite_session_inside_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.del_dslite_session_inside_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.del_dslite_session_inside_ipv6_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.del_dslite_session_inside_ipv6_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.del_dslite_session_inside_ip_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE); - cnat_nfv9_template_info.del_dslite_session_inside_ip_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE); - - cnat_nfv9_template_info.del_dslite_session_dest_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_DESTINATION_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.del_dslite_session_dest_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_DESTINATION_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.del_dslite_session_dest_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_TYPE); - cnat_nfv9_template_info.del_dslite_session_dest_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_SIZE); - - cnat_nfv9_template_info.del_dslite_session_protocol_field_type = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE); - cnat_nfv9_template_info.del_dslite_session_protocol_field_size = - clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE); - - /* Create add bulk template */ - cnat_nfv9_template_info.bulk_add_template_id = - clib_host_to_net_u16(CNAT_NFV9_NAT44_BULK_ADD_TEMPLATE_ID); - cnat_nfv9_template_info.bulk_add_field_count = - clib_host_to_net_u16(CNAT_NFV9_NAT44_BULK_ADD_FIELD_COUNT); - - cnat_nfv9_template_info.bulk_add_inside_vrf_id_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE); - cnat_nfv9_template_info.bulk_add_inside_vrf_id_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE); - - cnat_nfv9_template_info.bulk_add_outside_vrf_id_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_TYPE); - cnat_nfv9_template_info.bulk_add_outside_vrf_id_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_SIZE); - - cnat_nfv9_template_info.bulk_add_inside_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.bulk_add_inside_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.bulk_add_outside_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.bulk_add_outside_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.bulk_add_outside_start_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_START_FIELD_TYPE); - cnat_nfv9_template_info.bulk_add_outside_start_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_START_FIELD_SIZE); - - cnat_nfv9_template_info.bulk_add_outside_end_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_END_FIELD_TYPE); - cnat_nfv9_template_info.bulk_add_outside_end_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_END_FIELD_SIZE); - - /* - * Create the bulk delete Template - */ - cnat_nfv9_template_info.bulk_del_template_id = - clib_host_to_net_u16(CNAT_NFV9_NAT44_BULK_DEL_TEMPLATE_ID); - cnat_nfv9_template_info.bulk_del_field_count = - clib_host_to_net_u16(CNAT_NFV9_NAT44_BULK_DEL_FIELD_COUNT); - - cnat_nfv9_template_info.bulk_del_inside_vrf_id_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE); - cnat_nfv9_template_info.bulk_del_inside_vrf_id_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE); - - cnat_nfv9_template_info.bulk_del_inside_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.bulk_del_inside_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.bulk_del_outside_start_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_START_FIELD_TYPE); - cnat_nfv9_template_info.bulk_del_outside_start_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_START_FIELD_SIZE); - - /* - * Ds-lite bulk add template - */ - cnat_nfv9_template_info.bulk_dslite_add_template_id = - clib_host_to_net_u16(CNAT_NFV9_DS_LITE_BULK_ADD_TEMPLATE_ID); - cnat_nfv9_template_info.bulk_dslite_add_field_count = - clib_host_to_net_u16(CNAT_NFV9_DS_LITE_BULK_ADD_FIELD_COUNT); - - cnat_nfv9_template_info.bulk_dslite_add_inside_vrf_id_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE); - cnat_nfv9_template_info.bulk_dslite_add_inside_vrf_id_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE); - - cnat_nfv9_template_info.bulk_dslite_add_outside_vrf_id_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_TYPE); - cnat_nfv9_template_info.bulk_dslite_add_outside_vrf_id_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_SIZE); - - cnat_nfv9_template_info.bulk_dslite_add_inside_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.bulk_dslite_add_inside_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.bulk_dslite_add_inside_ipv6_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.bulk_dslite_add_inside_ipv6_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.bulk_dslite_add_outside_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.bulk_dslite_add_outside_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.bulk_dslite_add_outside_start_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_START_FIELD_TYPE); - cnat_nfv9_template_info.bulk_dslite_add_outside_start_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_START_FIELD_SIZE); - - cnat_nfv9_template_info.bulk_dslite_add_outside_end_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_END_FIELD_TYPE); - cnat_nfv9_template_info.bulk_dslite_add_outside_end_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_END_FIELD_SIZE); - - /* - * Ds-lite bulk delete template - */ - - cnat_nfv9_template_info.bulk_dslite_del_template_id = - clib_host_to_net_u16(CNAT_NFV9_DS_LITE_BULK_DEL_TEMPLATE_ID); - cnat_nfv9_template_info.bulk_dslite_del_field_count = - clib_host_to_net_u16(CNAT_NFV9_DS_LITE_BULK_DEL_FIELD_COUNT); - - cnat_nfv9_template_info.bulk_dslite_del_inside_vrf_id_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE); - cnat_nfv9_template_info.bulk_dslite_del_inside_vrf_id_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE); - - cnat_nfv9_template_info.bulk_dslite_del_inside_ip_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.bulk_dslite_del_inside_ip_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.bulk_dslite_del_inside_ipv6_addr_field_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_TYPE); - cnat_nfv9_template_info.bulk_dslite_del_inside_ipv6_addr_field_size = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_SIZE); - - cnat_nfv9_template_info.bulk_dslite_del_outside_start_port_field_type = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_START_FIELD_TYPE); - cnat_nfv9_template_info.bulk_dslite_del_outside_start_port_field_size = - clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_START_FIELD_SIZE); - -#endif /* NO_BULK_LOGGING */ - - /* - * Ingress vrfid - name mapping - */ - CNAT_NFV9_OPTION_TEMPLATE.flowset_id = - clib_host_to_net_u16(CNAT_NFV9_OPTION_TEMPLATE_FLOWSET_ID); - CNAT_NFV9_OPTION_TEMPLATE.length = - clib_host_to_net_u16(CNAT_NFV9_OPTION_TEMPLATE_LENGTH); - - CNAT_NFV9_OPTION_TEMPLATE.ingress_vrfid_name_map_template_id = - clib_host_to_net_u16(CNAT_NFV9_INGRESS_VRF_ID_NAME_TEMPLATE_ID); - /* currently no scope field supported */ - CNAT_NFV9_OPTION_TEMPLATE.ingress_vrfid_name_map_scope_len = 0; - CNAT_NFV9_OPTION_TEMPLATE.ingress_vrfid_name_map_option_len = - clib_host_to_net_u16(CNAT_NFV9_INGRESS_VRF_ID_NAME_OPTION_LEN); - CNAT_NFV9_OPTION_TEMPLATE.ingress_vrfid_name_map_vrfid_option_type = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE); - CNAT_NFV9_OPTION_TEMPLATE.ingress_vrfid_name_map_vrfid_option_len = - clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE); - CNAT_NFV9_OPTION_TEMPLATE.ingress_vrfid_name_map_vrfname_option_type = - clib_host_to_net_u16(CNAT_NFV9_INGRESS_VRF_NAME_FIELD_TYPE); - CNAT_NFV9_OPTION_TEMPLATE.ingress_vrfid_name_map_vrfname_option_len = - clib_host_to_net_u16(CNAT_NFV9_INGRESS_VRF_NAME_FIELD_SIZE); - - /* - * Set the padding (which was added to make the size of template - * multiple of 4) to zero - */ - CNAT_NFV9_OPTION_TEMPLATE.padding1 = 0; -} - -/* - * one time function - * has to be called at the init time - */ -void cnat_nfv9_logging_init() -{ - if (!cnat_nfv9_global_info.cnat_nfv9_init_done) { - cnat_nfv9_template_init(); - - /* Pre allocate for NFV9_SERVER_POOL_SIZE. Will be good - * enough for most deployments - */ - pool_alloc(nfv9_server_info_pool, NFV9_SERVER_POOL_SIZE); - int i; - nfv9_server_info_t *server __attribute__((unused)); - for(i = 0; i < NFV9_SERVER_POOL_SIZE; i++) { - pool_get(nfv9_server_info_pool, server); - } - - for(i = 0; i < NFV9_SERVER_POOL_SIZE; i++) { - pool_put(nfv9_server_info_pool, nfv9_server_info_pool + i); - } - - memset(&cnat_nfv9_global_info, 0 , sizeof(cnat_nfv9_global_info_t)); - ASSERT(cnat_nfv9_global_info.cnat_nfv9_disp_node_index != (u16)~0); - - cnat_nfv9_global_info.cnat_nfv9_global_collector_index = EMPTY; - cnat_nfv9_global_info.cnat_nfv9_init_done = 1; - - /* - * src id is set to infra IPv4 address + octeon core number - */ - nfv9_src_id = my_instance_number; - } -} diff --git a/plugins/vcgn-plugin/vcgn/cnat_logging.h b/plugins/vcgn-plugin/vcgn/cnat_logging.h deleted file mode 100644 index 7bd43ecf..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_logging.h +++ /dev/null @@ -1,1091 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_logging.h - * - * Copyright (c) 2009, 2012 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef __CNAT_LOGGING_H__ -#define __CNAT_LOGGING_H__ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "nat64_db.h" -#include "cnat_log_common.h" -#include "dslite_defs.h" - -#define NFV9_DEF_PATH_MTU 1500 -#define NFV9_VRF_NAME_LEN 12 - -/* one time call at the beginning */ -void cnat_nfv9_logging_init(); - -/* - * unconditional call - * will check logging config inside - */ -void cnat_nfv9_log_mapping_create(cnat_main_db_entry_t * db, - cnat_vrfmap_t *vrfmap -#ifndef NO_BULK_LOGGING - , int bulk_alloc -#endif - ); - -void cnat_nfv9_nat44_log_session_create(cnat_main_db_entry_t * db, - cnat_session_entry_t * sdb, - cnat_vrfmap_t *vrfmap); - -void cnat_nfv9_nat44_log_session_delete(cnat_main_db_entry_t * db, - cnat_session_entry_t * sdb, - cnat_vrfmap_t *vrfmap); - - -/* - * unconditional call - * will check logging config inside - */ -void cnat_nfv9_log_mapping_delete(cnat_main_db_entry_t * db, - cnat_vrfmap_t *vrfmap -#ifndef NO_BULK_LOGGING - , int bulk_alloc -#endif - ); - -/* nat44 syslog APIs */ -void cnat_syslog_nat44_mapping_create(cnat_main_db_entry_t *db, - cnat_vrfmap_t *vrfmap, cnat_session_entry_t * sdb -#ifndef NO_BULK_LOGGING - , int bulk_alloc -#endif - ); - -void cnat_syslog_nat44_mapping_delete(cnat_main_db_entry_t *db, - cnat_vrfmap_t *vrfmap, cnat_session_entry_t *sdb -#ifndef NO_BULK_LOGGING - , int bulk_alloc -#endif - ); - -/* - * dslite - */ -void cnat_nfv9_ds_lite_mapping_create(cnat_main_db_entry_t *db, - dslite_table_entry_t *dslite_entry -#ifndef NO_BULK_LOGGING - , int bulk_alloc -#endif - ); - -void cnat_nfv9_ds_lite_mapping_delete(cnat_main_db_entry_t *db, - dslite_table_entry_t *dslite_entry -#ifndef NO_BULK_LOGGING - , int bulk_alloc -#endif - ); -void cnat_nfv9_ds_lite_log_session_create(cnat_main_db_entry_t * db, - dslite_table_entry_t *dslite_entry, - cnat_session_entry_t * sdb); - -void cnat_nfv9_ds_lite_log_session_delete(cnat_main_db_entry_t * db, - dslite_table_entry_t *dslite_entry, - cnat_session_entry_t * sdb); - -/* - * nat64 - */ - -void cnat_nfv9_bib_mapping_create (nat64_bib_entry_t *db, - nat64_table_entry_t *nat64_entry); - -void cnat_nfv9_session_mapping_create (nat64_bib_entry_t *bdb, - nat64_session_entry_t *sdb, - nat64_table_entry_t *nat64_entry_ptr); - -void cnat_nfv9_bib_mapping_delete (nat64_bib_entry_t *db, - nat64_table_entry_t *nat64_entry); - -void cnat_nfv9_session_mapping_delete (nat64_bib_entry_t *bdb, - nat64_session_entry_t *sdb, - nat64_table_entry_t *nat64_entry_ptr); - -typedef enum { - RECORD_INVALID = 0, - NAT44_ADD_RECORD, - NAT44_DEL_RECORD, - NAT64_ADD_BIB_RECORD, - NAT64_DEL_BIB_RECORD, - NAT64_ADD_SESSION_RECORD, - NAT64_DEL_SESSION_RECORD, - DS_LITE_ADD_RECORD, - DS_LITE_DEL_RECORD, - NAT44_BULK_ADD_RECORD, - NAT44_BULK_DEL_RECORD, - DS_LITE_BULK_ADD_RECORD, - DS_LITE_BULK_DEL_RECORD, - INGRESS_VRF_ID_NAME_RECORD, - NAT44_ADD_SESSION_RECORD, - NAT44_DEL_SESSION_RECORD, - DS_LITE_ADD_SESSION_RECORD, - DS_LITE_DEL_SESSION_RECORD, - MAX_RECORDS -} netflow_record; - -typedef enum { - TEMPLATE_SENT_FALSE = 0, - TEMPLATE_SENT_TRUE = 1 -} netflow_template_sent; - -#define cnat_nfv9_get_sys_up_time_in_ms cnat_get_sys_up_time_in_ms - -#define cnat_nfv9_get_unix_time_in_seconds cnat_get_unix_time_in_seconds - -#define cnat_nfv9_dump_time_change_logs cnat_dump_time_change_logs - - -/* - * Netflow V9 Specific Defines and structures - */ - -#define CNAT_NFV9_VERSION_NUMBER 9 - -#define CNAT_NFV9_TEMPLATE_FLOWSET_ID 0 -#define CNAT_NFV9_OPTION_TEMPLATE_FLOWSET_ID 1 - -#define CNAT_NFV9_ADD_FIELD_COUNT 7 -#define CNAT_NFV9_DEL_FIELD_COUNT 4 -#define CNAT_NFV9_DS_LITE_ADD_FIELD_COUNT 8 -#define CNAT_NFV9_DS_LITE_DEL_FIELD_COUNT 5 -#define CNAT_NFV9_NAT64_ADD_BIB_FIELD_COUNT 5 -#define CNAT_NFV9_NAT64_DEL_BIB_FIELD_COUNT 3 -#define CNAT_NFV9_NAT64_ADD_SESSION_FIELD_COUNT 8 -#define CNAT_NFV9_NAT64_DEL_SESSION_FIELD_COUNT 5 -#define CNAT_NFV9_NAT44_ADD_SESSION_FIELD_COUNT 9 -#define CNAT_NFV9_NAT44_DEL_SESSION_FIELD_COUNT 6 -#define CNAT_NFV9_DS_LITE_ADD_SESSION_FIELD_COUNT 10 -#define CNAT_NFV9_DS_LITE_DEL_SESSION_FIELD_COUNT 7 - -#define CNAT_NFV9_ADD_TEMPLATE_ID 256 -#define CNAT_NFV9_DEL_TEMPLATE_ID 257 -#define CNAT_NFV9_NAT64_ADD_BIB_TEMPLATE_ID 258 -#define CNAT_NFV9_NAT64_DEL_BIB_TEMPLATE_ID 259 -#define CNAT_NFV9_NAT64_ADD_SESSION_TEMPLATE_ID 260 -#define CNAT_NFV9_NAT64_DEL_SESSION_TEMPLATE_ID 261 -#define CNAT_NFV9_INGRESS_VRF_ID_NAME_TEMPLATE_ID 262 -#define CNAT_NFV9_DS_LITE_ADD_TEMPLATE_ID 267 -#define CNAT_NFV9_DS_LITE_DEL_TEMPLATE_ID 268 -#define CNAT_NFV9_NAT44_ADD_SESSION_TEMPLATE_ID 271 -#define CNAT_NFV9_NAT44_DEL_SESSION_TEMPLATE_ID 272 -#define CNAT_NFV9_DS_LITE_ADD_SESSION_TEMPLATE_ID 273 -#define CNAT_NFV9_DS_LITE_DEL_SESSION_TEMPLATE_ID 274 - -#ifndef NO_BULK_LOGGING -#define CNAT_NFV9_NAT44_BULK_ADD_TEMPLATE_ID 265 -#define CNAT_NFV9_NAT44_BULK_DEL_TEMPLATE_ID 266 -#define CNAT_NFV9_DS_LITE_BULK_ADD_TEMPLATE_ID 269 -#define CNAT_NFV9_DS_LITE_BULK_DEL_TEMPLATE_ID 270 - -#define CNAT_NFV9_NAT44_BULK_ADD_FIELD_COUNT 6 -#define CNAT_NFV9_NAT44_BULK_DEL_FIELD_COUNT 3 -#define CNAT_NFV9_DS_LITE_BULK_ADD_FIELD_COUNT 7 -#define CNAT_NFV9_DS_LITE_BULK_DEL_FIELD_COUNT 4 - -#define CNAT_NFV9_OUTSIDE_IP_PORT_START_FIELD_TYPE 361 -#define CNAT_NFV9_OUTSIDE_IP_PORT_START_FIELD_SIZE 2 - -#define CNAT_NFV9_OUTSIDE_IP_PORT_END_FIELD_TYPE 362 -#define CNAT_NFV9_OUTSIDE_IP_PORT_END_FIELD_SIZE 2 - -#endif /* #ifndef NO_BULK_LOGGING */ - -#define CNAT_NFV9_INGRESS_VRF_NAME_FIELD_TYPE 236 -#define CNAT_NFV9_INGRESS_VRF_NAME_FIELD_SIZE 12 -/* 4 byte for vrf_id + 4 byte for vrf_name (option fields) */ -#define CNAT_NFV9_INGRESS_VRF_ID_NAME_OPTION_LEN 8 -extern u16 cnat_template_id[MAX_RECORDS]; - -#define CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE 234 -#define CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE 4 - -#define CNAT_NFV9_OUTSIDE_VRFID_FIELD_TYPE 235 -#define CNAT_NFV9_OUTSIDE_VRFID_FIELD_SIZE 4 - -#define CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE 8 -#define CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE 4 - -#define CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_TYPE 225 -#define CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_SIZE 4 - -#define CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE 7 -#define CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE 2 - -#define CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_TYPE 227 -#define CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_SIZE 2 - -#define CNAT_NFV9_PROTOCOL_FIELD_TYPE 4 -#define CNAT_NFV9_PROTOCOL_FIELD_SIZE 1 - -/* IPv6 related info */ - -#define CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_TYPE 27 -#define CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_SIZE 16 - -#define CNAT_NFV9_INSIDE_IPV6_DST_ADDR_FIELD_TYPE 28 -#define CNAT_NFV9_INSIDE_IPV6_DST_ADDR_FIELD_SIZE 16 - -#define CNAT_NFV9_OUTSIDE_IP_DST_ADDR_FIELD_TYPE 226 -#define CNAT_NFV9_OUTSIDE_IP_DST_ADDR_FIELD_SIZE 4 - -#define CNAT_NFV9_INSIDE_DST_PORT_FIELD_TYPE 11 -#define CNAT_NFV9_INSIDE_DST_PORT_FIELD_SIZE 2 - -#define CNAT_NFV9_DESTINATION_IP_ADDR_FIELD_TYPE 12 -#define CNAT_NFV9_DESTINATION_IP_ADDR_FIELD_SIZE 4 - - -typedef struct { - u16 version; - u16 count; - u32 sys_up_time; /* time in ms since system was booted */ - u32 timestamp; /* UNIX time in seconds since 1970 */ - u32 sequence_num; - u32 source_id; -} nfv9_header_t; - -/* - * Hardcoded - need to be fixed - */ -#define CNAT_NFV9_SOURCE_ID_VALUE 0x1234 - -typedef struct { - u16 flowset_id; - u16 length; - - u16 ingress_vrfid_name_map_template_id; - u16 ingress_vrfid_name_map_scope_len; - u16 ingress_vrfid_name_map_option_len; - u16 ingress_vrfid_name_map_vrfid_option_type; - u16 ingress_vrfid_name_map_vrfid_option_len; - u16 ingress_vrfid_name_map_vrfname_option_type; - u16 ingress_vrfid_name_map_vrfname_option_len; - /* - * Adding the padding so as to make the tempalate - * structure end on a 4 byte boundary - */ - u16 padding1; - -} cnat_nfv9_option_template_t; - -/* - * The following structure defines the Netflow Template that - * will be exported to the Netflow Collector - */ - -typedef struct { - u16 flowset_id; - u16 length; - - u16 add_template_id; - u16 add_field_count; - u16 add_inside_vrf_id_field_type; - u16 add_inside_vrf_id_field_size; - u16 add_outside_vrf_id_field_type; - u16 add_outside_vrf_id_field_size; - u16 add_inside_ip_addr_field_type; - u16 add_inside_ip_addr_field_size; - u16 add_outside_ip_addr_field_type; - u16 add_outside_ip_addr_field_size; - u16 add_inside_ip_port_field_type; - u16 add_inside_ip_port_field_size; - u16 add_outside_ip_port_field_type; - u16 add_outside_ip_port_field_size; - u16 add_protocol_field_type; - u16 add_protocol_field_size; - - u16 del_template_id; - u16 del_field_count; - u16 del_inside_vrf_id_field_type; - u16 del_inside_vrf_id_field_size; - u16 del_inside_ip_addr_field_type; - u16 del_inside_ip_addr_field_size; - u16 del_inside_ip_port_field_type; - u16 del_inside_ip_port_field_size; - u16 del_protocol_field_type; - u16 del_protocol_field_size; -#if 0 - /* NAT64 related info */ - u16 nat64_add_bib_template_id; - u16 nat64_add_bib_field_count; - u16 nat64_add_bib_inside_ipv6_addr_field_type; - u16 nat64_add_bib_inside_ipv6_addr_field_size; - u16 nat64_add_bib_outside_ip_addr_field_type; - u16 nat64_add_bib_outside_ip_addr_field_size; - u16 nat64_add_bib_inside_ip_port_field_type; - u16 nat64_add_bib_inside_ip_port_field_size; - u16 nat64_add_bib_outside_ip_port_field_type; - u16 nat64_add_bib_outside_ip_port_field_size; - u16 nat64_add_bib_protocol_field_type; - u16 nat64_add_bib_protocol_field_size; - - u16 nat64_del_bib_template_id; - u16 nat64_del_bib_field_count; - u16 nat64_del_bib_inside_ip_addr_field_type; - u16 nat64_del_bib_inside_ip_addr_field_size; - u16 nat64_del_bib_inside_ip_port_field_type; - u16 nat64_del_bib_inside_ip_port_field_size; - u16 nat64_del_bib_protocol_field_type; - u16 nat64_del_bib_protocol_field_size; - - - u16 nat64_add_session_template_id; - u16 nat64_add_session_field_count; - u16 nat64_add_session_inside_ipv6_src_addr_field_type; - u16 nat64_add_session_inside_ipv6_src_addr_field_size; - u16 nat64_add_session_outside_ip_src_addr_field_type; - u16 nat64_add_session_outside_ip_src_addr_field_size; - u16 nat64_add_session_inside_ipv6_dst_addr_field_type; - u16 nat64_add_session_inside_ipv6_dst_addr_field_size; - u16 nat64_add_session_outside_ip_dst_addr_field_type; - u16 nat64_add_session_outside_ip_dst_addr_field_size; - u16 nat64_add_session_inside_ip_src_port_field_type; - u16 nat64_add_session_inside_ip_src_port_field_size; - u16 nat64_add_session_outside_ip_src_port_field_type; - u16 nat64_add_session_outside_ip_src_port_field_size; - u16 nat64_add_session_ip_dest_port_field_type; - u16 nat64_add_session_ip_dest_port_field_size; - u16 nat64_add_session_protocol_field_type; - u16 nat64_add_session_protocol_field_size; - - u16 nat64_del_session_template_id; - u16 nat64_del_session_field_count; - u16 nat64_del_session_inside_ip_src_addr_field_type; - u16 nat64_del_session_inside_ip_src_addr_field_size; - u16 nat64_del_session_inside_ip_dst_addr_field_type; - u16 nat64_del_session_inside_ip_dst_addr_field_size; - u16 nat64_del_session_inside_ip_src_port_field_type; - u16 nat64_del_session_inside_ip_src_port_field_size; - u16 nat64_del_session_inside_ip_dst_port_field_type; - u16 nat64_del_session_inside_ip_dst_port_field_size; - u16 nat64_del_session_protocol_field_type; - u16 nat64_del_session_protocol_field_size; - - /* - * Ds-Lite specific info - */ - u16 add_dslite_template_id; - u16 add_dslite_field_count; - u16 add_dslite_inside_vrf_id_field_type; - u16 add_dslite_inside_vrf_id_field_size; - u16 add_dslite_outside_vrf_id_field_type; - u16 add_dslite_outside_vrf_id_field_size; - u16 add_dslite_inside_ip_addr_field_type; - u16 add_dslite_inside_ip_addr_field_size; - u16 add_dslite_inside_ipv6_addr_field_type; - u16 add_dslite_inside_ipv6_addr_field_size; - u16 add_dslite_outside_ip_addr_field_type; - u16 add_dslite_outside_ip_addr_field_size; - u16 add_dslite_inside_ip_port_field_type; - u16 add_dslite_inside_ip_port_field_size; - u16 add_dslite_outside_ip_port_field_type; - u16 add_dslite_outside_ip_port_field_size; - u16 add_dslite_protocol_field_type; - u16 add_dslite_protocol_field_size; - - u16 del_dslite_template_id; - u16 del_dslite_field_count; - u16 del_dslite_inside_vrf_id_field_type; - u16 del_dslite_inside_vrf_id_field_size; - u16 del_dslite_inside_ip_addr_field_type; - u16 del_dslite_inside_ip_addr_field_size; - u16 del_dslite_inside_ipv6_addr_field_type; - u16 del_dslite_inside_ipv6_addr_field_size; - u16 del_dslite_inside_ip_port_field_type; - u16 del_dslite_inside_ip_port_field_size; - u16 del_dslite_protocol_field_type; - u16 del_dslite_protocol_field_size; -#endif - -//#ifndef NO_BULK_LOGGING /* commenting for time being */ -#if 0 - u16 bulk_add_template_id; - u16 bulk_add_field_count; - u16 bulk_add_inside_vrf_id_field_type; - u16 bulk_add_inside_vrf_id_field_size; - u16 bulk_add_outside_vrf_id_field_type; - u16 bulk_add_outside_vrf_id_field_size; - u16 bulk_add_inside_ip_addr_field_type; - u16 bulk_add_inside_ip_addr_field_size; - u16 bulk_add_outside_ip_addr_field_type; - u16 bulk_add_outside_ip_addr_field_size; - u16 bulk_add_outside_start_port_field_type; - u16 bulk_add_outside_start_port_field_size; - u16 bulk_add_outside_end_port_field_type; - u16 bulk_add_outside_end_port_field_size; - - u16 bulk_del_template_id; - u16 bulk_del_field_count; - u16 bulk_del_inside_vrf_id_field_type; - u16 bulk_del_inside_vrf_id_field_size; - u16 bulk_del_inside_ip_addr_field_type; - u16 bulk_del_inside_ip_addr_field_size; - u16 bulk_del_outside_start_port_field_type; - u16 bulk_del_outside_start_port_field_size; - - /* ds-lite bulk logging create delete event */ - - u16 bulk_dslite_add_template_id; - u16 bulk_dslite_add_field_count; - u16 bulk_dslite_add_inside_vrf_id_field_type; - u16 bulk_dslite_add_inside_vrf_id_field_size; - u16 bulk_dslite_add_outside_vrf_id_field_type; - u16 bulk_dslite_add_outside_vrf_id_field_size; - u16 bulk_dslite_add_inside_ip_addr_field_type; - u16 bulk_dslite_add_inside_ip_addr_field_size; - u16 bulk_dslite_add_inside_ipv6_addr_field_type; - u16 bulk_dslite_add_inside_ipv6_addr_field_size; - u16 bulk_dslite_add_outside_ip_addr_field_type; - u16 bulk_dslite_add_outside_ip_addr_field_size; - u16 bulk_dslite_add_outside_start_port_field_type; - u16 bulk_dslite_add_outside_start_port_field_size; - u16 bulk_dslite_add_outside_end_port_field_type; - u16 bulk_dslite_add_outside_end_port_field_size; - - u16 bulk_dslite_del_template_id; - u16 bulk_dslite_del_field_count; - u16 bulk_dslite_del_inside_vrf_id_field_type; - u16 bulk_dslite_del_inside_vrf_id_field_size; - u16 bulk_dslite_del_inside_ip_addr_field_type; - u16 bulk_dslite_del_inside_ip_addr_field_size; - u16 bulk_dslite_del_inside_ipv6_addr_field_type; - u16 bulk_dslite_del_inside_ipv6_addr_field_size; - u16 bulk_dslite_del_outside_start_port_field_type; - u16 bulk_dslite_del_outside_start_port_field_size; - -#endif /* NO_BULK_LOGGING */ - - u16 nat44_session_add_template_id; - u16 nat44_session_add_field_count; - u16 nat44_session_add_inside_vrf_id_field_type; - u16 nat44_session_add_inside_vrf_id_field_size; - u16 nat44_session_add_outside_vrf_id_field_type; - u16 nat44_session_add_outside_vrf_id_field_size; - u16 nat44_session_add_inside_ip_addr_field_type; - u16 nat44_session_add_inside_ip_addr_field_size; - u16 nat44_session_add_outside_ip_addr_field_type; - u16 nat44_session_add_outside_ip_addr_field_size; - u16 nat44_session_add_inside_ip_port_field_type; - u16 nat44_session_add_inside_ip_port_field_size; - u16 nat44_session_add_outside_ip_port_field_type; - u16 nat44_session_add_outside_ip_port_field_size; - u16 nat44_session_add_dest_ip_addr_field_type; - u16 nat44_session_add_dest_ip_addr_field_size; - u16 nat44_session_add_dest_port_field_type; - u16 nat44_session_add_dest_port_field_size; - u16 nat44_session_add_protocol_field_type; - u16 nat44_session_add_protocol_field_size; - - u16 nat44_session_del_template_id; - u16 nat44_session_del_field_count; - u16 nat44_session_del_inside_vrf_id_field_type; - u16 nat44_session_del_inside_vrf_id_field_size; - u16 nat44_session_del_inside_ip_addr_field_type; - u16 nat44_session_del_inside_ip_addr_field_size; - u16 nat44_session_del_dest_ip_addr_field_type; - u16 nat44_session_del_dest_ip_addr_field_size; - u16 nat44_session_del_inside_ip_port_field_type; - u16 nat44_session_del_inside_ip_port_field_size; - u16 nat44_session_del_dest_port_field_type; - u16 nat44_session_del_dest_port_field_size; - u16 nat44_session_del_protocol_field_type; - u16 nat44_session_del_protocol_field_size; - -#if 0 - u16 add_dslite_session_template_id; - u16 add_dslite_session_field_count; - u16 add_dslite_session_inside_vrf_id_field_type; - u16 add_dslite_session_inside_vrf_id_field_size; - u16 add_dslite_session_outside_vrf_id_field_type; - u16 add_dslite_session_outside_vrf_id_field_size; - u16 add_dslite_session_inside_ip_addr_field_type; - u16 add_dslite_session_inside_ip_addr_field_size; - u16 add_dslite_session_inside_ipv6_addr_field_type; - u16 add_dslite_session_inside_ipv6_addr_field_size; - u16 add_dslite_session_outside_ip_addr_field_type; - u16 add_dslite_session_outside_ip_addr_field_size; - u16 add_dslite_session_inside_ip_port_field_type; - u16 add_dslite_session_inside_ip_port_field_size; - u16 add_dslite_session_outside_ip_port_field_type; - u16 add_dslite_session_outside_ip_port_field_size; - u16 add_dslite_session_dest_ip_addr_field_type; - u16 add_dslite_session_dest_ip_addr_field_size; - u16 add_dslite_session_dest_port_field_type; - u16 add_dslite_session_dest_port_field_size; - u16 add_dslite_session_protocol_field_type; - u16 add_dslite_session_protocol_field_size; - - u16 del_dslite_session_template_id; - u16 del_dslite_session_field_count; - u16 del_dslite_session_inside_vrf_id_field_type; - u16 del_dslite_session_inside_vrf_id_field_size; - u16 del_dslite_session_inside_ip_addr_field_type; - u16 del_dslite_session_inside_ip_addr_field_size; - u16 del_dslite_session_inside_ipv6_addr_field_type; - u16 del_dslite_session_inside_ipv6_addr_field_size; - u16 del_dslite_session_dest_ip_addr_field_type; - u16 del_dslite_session_dest_ip_addr_field_size; - u16 del_dslite_session_inside_ip_port_field_type; - u16 del_dslite_session_inside_ip_port_field_size; - u16 del_dslite_session_dest_port_field_type; - u16 del_dslite_session_dest_port_field_size; - u16 del_dslite_session_protocol_field_type; - u16 del_dslite_session_protocol_field_size; -#endif - - /* - * Netflow option template - * Ingress VRF ID - Name mapping - * This template will be sent under flowset id 1 - */ - cnat_nfv9_option_template_t cnat_nfv9_option_template; -} cnat_nfv9_template_t; - -/* - * The Dataflow header for each add/delete record group - */ -typedef struct { - u16 dataflow_template_id; - u16 dataflow_length; -} nfv9_dataflow_record_header_t; - -/* - * NFv9 Add record definition - */ - -/* - * pad bytes needed to make the structure a multiple of 4 bytes - */ -#define CNAT_NFV9_ADD_RECORD_PAD_BYTES (3) -#define CNAT_NFV9_DEL_RECORD_PAD_BYTES (1) - -#define CNAT_NFV9_NAT64_ADD_BIB_RECORD_PAD_BYTES (3) -#define CNAT_NFV9_NAT64_DEL_BIB_RECORD_PAD_BYTES (1) -#define CNAT_NFV9_NAT64_ADD_SESSION_RECORD_PAD_BYTES (1) -#define CNAT_NFV9_NAT64_DEL_SESSION_RECORD_PAD_BYTES (3) -#define CNAT_NFV9_NAT44_ADD_SESSION_RECORD_PAD_BYTES (1) -#define CNAT_NFV9_NAT44_DEL_SESSION_RECORD_PAD_BYTES (3) - -#define CNAT_NFV9_DS_LITE_ADD_RECORD_PAD_BYTES (3) -#define CNAT_NFV9_DS_LITE_DEL_RECORD_PAD_BYTES (1) -#define CNAT_NFV9_DS_LITE_ADD_SESSION_RECORD_PAD_BYTES (1) -#define CNAT_NFV9_DS_LITE_DEL_SESSION_RECORD_PAD_BYTES (3) - -#define CNAT_NFV9_INGRESS_VRFID_NAME_RECORD_PAD_BYTES (0) - -typedef struct { - u32 inside_vrf_id; - u32 outside_vrf_id; - u32 inside_ip_addr; - u32 outside_ip_addr; - u16 inside_ip_port; - u16 outside_ip_port; - u8 protocol; - u8 pad[CNAT_NFV9_ADD_RECORD_PAD_BYTES]; -} nfv9_add_record_t; - -/* - * NFv9 Delete record definition - */ -typedef struct { - u32 inside_vrf_id; - u32 inside_ip_addr; - u16 inside_ip_port; - u8 protocol; - u8 pad[CNAT_NFV9_DEL_RECORD_PAD_BYTES]; -} nfv9_del_record_t; - -#ifndef NO_BULK_LOGGING - -#define CNAT_NFV9_BULK_ADD_RECORD_PAD_BYTES (0) -#define CNAT_NFV9_BULK_DEL_RECORD_PAD_BYTES (2) - -typedef struct { - u32 inside_vrf_id; - u32 outside_vrf_id; - u32 inside_ip_addr; - u32 outside_ip_addr; - u16 outside_ip_port_start; - u16 outside_ip_port_end; - u8 pad[CNAT_NFV9_BULK_ADD_RECORD_PAD_BYTES]; -} nfv9_bulk_add_record_t; - -/* - * NFv9 Delete record definition - */ -typedef struct { - u32 inside_vrf_id; - u32 inside_ip_addr; - u16 outside_ip_port_start; - u8 pad[CNAT_NFV9_BULK_DEL_RECORD_PAD_BYTES]; -} nfv9_bulk_del_record_t; - -/* - * DS-lite bulk port (user based) add record definition - */ - -#define CNAT_NFV9_DS_LITE_BULK_ADD_RECORD_PAD_BYTES (0) -#define CNAT_NFV9_DS_LITE_BULK_DEL_RECORD_PAD_BYTES (2) - -typedef struct { - u32 inside_vrf_id; - u32 outside_vrf_id; - u32 inside_ip_addr; - u32 inside_v6_src_addr[4]; - u32 outside_ip_addr; - u16 outside_ip_port_start; - u16 outside_ip_port_end; - u8 pad[CNAT_NFV9_DS_LITE_BULK_ADD_RECORD_PAD_BYTES]; -} nfv9_ds_lite_bulk_add_record_t; - - -/* - * DS-lite bulk port (user based) delete record definition - */ - -typedef struct { - u32 inside_vrf_id; - u32 inside_ip_addr; - u32 inside_v6_src_addr[4]; - u16 outside_ip_port_start; - u8 pad[CNAT_NFV9_DS_LITE_BULK_DEL_RECORD_PAD_BYTES]; -} nfv9_ds_lite_bulk_del_record_t; - -#endif /* NO_BULK_LOGGING */ - -/* NAT64 related structures */ - -typedef struct { - u32 inside_v6_src_addr[4]; - u32 outside_v4_src_addr; - u16 inside_src_port; - u16 outside_src_port; - u8 protocol; - u8 pad[CNAT_NFV9_NAT64_ADD_BIB_RECORD_PAD_BYTES]; -} nfv9_nat64_add_bib_record_t; - - -typedef struct { - u32 inside_v6_src_addr[4]; - u32 outside_v4_src_addr; - u32 inside_v6_dest_addr[4]; - u32 outside_v4_dest_addr; - u16 inside_src_port; - u16 outside_src_port; - u16 dest_port; - u8 protocol; - u8 pad[CNAT_NFV9_NAT64_ADD_SESSION_RECORD_PAD_BYTES]; -} nfv9_nat64_add_session_record_t; - - -typedef struct { - u32 inside_v6_src_addr[4]; - u16 inside_src_port; - u8 protocol; - u8 pad[CNAT_NFV9_NAT64_DEL_BIB_RECORD_PAD_BYTES]; -} nfv9_nat64_del_bib_record_t; - - -typedef struct { - u32 inside_v6_src_addr[4]; - u32 inside_v6_dest_addr[4]; - u16 inside_src_port; - u16 dest_port; - u8 protocol; - u8 pad[CNAT_NFV9_NAT64_DEL_SESSION_RECORD_PAD_BYTES]; -} nfv9_nat64_del_session_record_t; - -/* - * NFv9 Session based Add record definition - */ -typedef struct { - u32 inside_vrf_id; - u32 outside_vrf_id; - u32 inside_ip_addr; - u32 outside_ip_addr; - u16 inside_ip_port; - u16 outside_ip_port; - u32 dest_ip_addr; - u16 dest_port; - u8 protocol; - u8 pad[CNAT_NFV9_NAT44_ADD_SESSION_RECORD_PAD_BYTES]; -} nfv9_add_session_record_t; - -/* - * NFv9 Session based del record definition - */ -typedef struct { - u32 inside_vrf_id; - u32 inside_ip_addr; - u32 dest_ip_addr; - u16 inside_ip_port; - u16 dest_port; - u8 protocol; - u8 pad[CNAT_NFV9_NAT44_DEL_SESSION_RECORD_PAD_BYTES]; -} nfv9_del_session_record_t; - -/* - * DS-lite NFv9 create record structure - */ -typedef struct { - u32 inside_vrf_id; - u32 outside_vrf_id; - u32 inside_ip_addr; - u32 inside_v6_src_addr[4]; - u32 outside_ip_addr; - u16 inside_ip_port; - u16 outside_ip_port; - u8 protocol; - u8 pad[CNAT_NFV9_DS_LITE_ADD_RECORD_PAD_BYTES]; -} nfv9_ds_lite_add_record_t; - -typedef struct { - u32 inside_vrf_id; - u32 inside_ip_addr; - u32 inside_v6_src_addr[4]; - u16 inside_ip_port; - u8 protocol; - u8 pad[CNAT_NFV9_DS_LITE_DEL_RECORD_PAD_BYTES]; -} nfv9_ds_lite_del_record_t; - -/* - * NFv9 Session based Add record definition - */ -typedef struct { - u32 inside_vrf_id; - u32 outside_vrf_id; - u32 inside_ip_addr; - u32 inside_v6_src_addr[4]; - u32 outside_ip_addr; - u16 inside_ip_port; - u16 outside_ip_port; - u32 dest_ip_addr; - u16 dest_port; - u8 protocol; - u8 pad[CNAT_NFV9_DS_LITE_ADD_SESSION_RECORD_PAD_BYTES]; -} nfv9_ds_lite_add_session_record_t; - -/* - * NFv9 Session based del record definition - */ -typedef struct { - u32 inside_vrf_id; - u32 inside_ip_addr; - u32 inside_v6_src_addr[4]; - u32 dest_ip_addr; - u16 inside_ip_port; - u16 dest_port; - u8 protocol; - u8 pad[CNAT_NFV9_DS_LITE_DEL_SESSION_RECORD_PAD_BYTES]; -} nfv9_ds_lite_del_session_record_t; - - -typedef struct { - u32 ingress_vrf_id; - u8 ingress_vrf_name[NFV9_VRF_NAME_LEN]; - u8 pad[CNAT_NFV9_INGRESS_VRFID_NAME_RECORD_PAD_BYTES]; -} nfv9_ingress_vrfid_name_record_t; - -#define CNAT_NFV9_TEMPLATE_OFFSET \ - (CNAT_NFV9_HDR_OFFSET + sizeof(nfv9_header_t)) - -#define CNAT_NFV9_TEMPLATE_LENGTH (sizeof(cnat_nfv9_template_t)) -#define CNAT_NFV9_OPTION_TEMPLATE_LENGTH (sizeof(cnat_nfv9_option_template_t)) - -#define CNAT_NFV9_DATAFLOW_RECORD_HEADER_LENGTH \ - (sizeof(nfv9_dataflow_record_header_t)) - -/* - * No padding is needed for the add/delete records - reduce padding bytes - */ - -#define CNAT_NFV9_ADD_RECORD_LENGTH (sizeof(nfv9_add_record_t) - \ - CNAT_NFV9_ADD_RECORD_PAD_BYTES) - -#define CNAT_NFV9_DEL_RECORD_LENGTH (sizeof(nfv9_del_record_t) - \ - CNAT_NFV9_DEL_RECORD_PAD_BYTES) - -#define CNAT_NFV9_DS_LITE_ADD_RECORD_LENGTH (sizeof(nfv9_ds_lite_add_record_t) - \ - CNAT_NFV9_DS_LITE_ADD_RECORD_PAD_BYTES) -#define CNAT_NFV9_DS_LITE_DEL_RECORD_LENGTH (sizeof(nfv9_ds_lite_del_record_t) - \ - CNAT_NFV9_DS_LITE_DEL_RECORD_PAD_BYTES) -#ifndef NO_BULK_LOGGING -#define CNAT_NFV9_BULK_ADD_RECORD_LENGTH (sizeof(nfv9_bulk_add_record_t) - \ - CNAT_NFV9_BULK_ADD_RECORD_PAD_BYTES) -#define CNAT_NFV9_BULK_DEL_RECORD_LENGTH (sizeof(nfv9_bulk_del_record_t) - \ - CNAT_NFV9_BULK_DEL_RECORD_PAD_BYTES) - -#define CNAT_NFV9_DS_LITE_BULK_ADD_RECORD_LENGTH (sizeof(nfv9_ds_lite_bulk_add_record_t) - \ - CNAT_NFV9_DS_LITE_BULK_ADD_RECORD_PAD_BYTES) -#define CNAT_NFV9_DS_LITE_BULK_DEL_RECORD_LENGTH (sizeof(nfv9_ds_lite_bulk_del_record_t) - \ - CNAT_NFV9_DS_LITE_BULK_DEL_RECORD_PAD_BYTES) - - -#endif /* NO_BULK_LOGGING */ - -#define CNAT_NFV9_INGRESS_VRFID_NAME_RECORD_LENGTH (sizeof(nfv9_ingress_vrfid_name_record_t) - \ - CNAT_NFV9_INGRESS_VRFID_NAME_RECORD_PAD_BYTES) - -#define CNAT_NFV9_NAT64_ADD_BIB_RECORD_LENGTH \ - (sizeof(nfv9_nat64_add_bib_record_t) - \ - CNAT_NFV9_NAT64_ADD_BIB_RECORD_PAD_BYTES) - -#define CNAT_NFV9_NAT64_DEL_BIB_RECORD_LENGTH \ - (sizeof(nfv9_nat64_del_bib_record_t) - \ - CNAT_NFV9_NAT64_DEL_BIB_RECORD_PAD_BYTES) - -#define CNAT_NFV9_NAT64_ADD_SESSION_RECORD_LENGTH \ - (sizeof(nfv9_nat64_add_session_record_t) - \ - CNAT_NFV9_NAT64_ADD_SESSION_RECORD_PAD_BYTES) - -#define CNAT_NFV9_NAT64_DEL_SESSION_RECORD_LENGTH \ - (sizeof(nfv9_nat64_del_session_record_t) - \ - CNAT_NFV9_NAT64_DEL_SESSION_RECORD_PAD_BYTES) - -#define CNAT_NFV9_MAX_SINGLE_RECORD_LENGTH \ - (sizeof(nfv9_ds_lite_add_session_record_t) - \ - CNAT_NFV9_DS_LITE_ADD_SESSION_RECORD_PAD_BYTES) - -#define CNAT_NFV9_NAT44_ADD_SESSION_RECORD_LENGTH \ - (sizeof(nfv9_add_session_record_t) -\ - CNAT_NFV9_NAT44_ADD_SESSION_RECORD_PAD_BYTES) - -#define CNAT_NFV9_NAT44_DEL_SESSION_RECORD_LENGTH \ - (sizeof(nfv9_del_session_record_t) -\ - CNAT_NFV9_NAT44_DEL_SESSION_RECORD_PAD_BYTES) - -#define CNAT_NFV9_DS_LITE_ADD_SESSION_RECORD_LENGTH \ - (sizeof(nfv9_ds_lite_add_session_record_t) -\ - CNAT_NFV9_DS_LITE_ADD_SESSION_RECORD_PAD_BYTES) - -#define CNAT_NFV9_DS_LITE_DEL_SESSION_RECORD_LENGTH \ - (sizeof(nfv9_ds_lite_del_session_record_t) -\ - CNAT_NFV9_DS_LITE_DEL_SESSION_RECORD_PAD_BYTES) - -/* - * Minimum value of the path MTU value - */ -#define CNAT_NFV9_MIN_RECORD_SIZE (60 + \ - CNAT_NFV9_DATAFLOW_RECORD_HEADER_LENGTH + \ - CNAT_NFV9_TEMPLATE_LENGTH + \ - CNAT_NFV9_MAX_SINGLE_RECORD_LENGTH) - -/* - * Let us put the maximum length of the netflow data to be 1400 - */ -#define CNAT_NFV9_MAX_PKT_LENGTH 1400 - -/* - * Data structures and defines to store NFV9 specific info - */ -#define CNAT_NFV9_INVALID_LOGGING_INDEX 0xffffffff - -/* - * Padding value between ADD and DELETE records. This can be atmost 3 bytes - */ -#define NFV9_PAD_VALUE (3) - -typedef struct { - /* NFV9 server specific info - * For now, it will maintain only package sequence count. - * Later it will maintain server address, port, etc. - * Though it currently has server address and port, it is only for - * cross refernce - */ - u32 ipv4_address; /* Destination IP address of the collector */ - u16 port; /* Destination port number of the collector */ - u16 refresh_rate; /* Refresh rate in packets after which template is sent */ - u16 timeout_rate; /* Timeout rate in seconds after which template is sent */ - u16 ref_count; /* Num of instances using this data */ - u32 sequence_num; /* Sequence number of the logging packet */ - /* - * Keep track of the time and packets since last template send - */ - u32 last_template_sent_time; - u32 pkts_since_last_template; - u8 template_sent; /* used while sending vrfid-name mapping */ - -} nfv9_server_info_t; - -/* - * This structure store the Netflow Logging information on per NFv9 - * collector basis. This structure is allocated from a pool and index - * to this structure is stored VRF MAP structures - */ -typedef struct { - /* - * nat64_id will be 0 for nat44 config and i_vrf_id, i_vrf will be 0 - * for nat64 config. Nat64_id will be used while nat64 collector is - * search and i_vrf* for nat44 collector - */ - /* Similarly for ds_lite, ds_lite_id will be used and nat64_id, - * ivrf_id shall be set to 0 - */ - u32 i_vrf_id; /* Inside VRF ID corresponding to this collector */ - u16 i_vrf; /* Inside VRF (uidb_index) corresponding to this collector */ - u16 nat64_id; /* NAT64 instance for to this collector */ - u16 ds_lite_id; /* DS Lite instance for this collector */ - - /* - * This field determines the maximum size of the Netflow V9 information - * that can be stored in a logging packet - */ - u16 max_length_minus_max_record_size; - - /* - * Indicates if the entry is already deleted - */ - u16 deleted; - - u16 pkt_length; /* Length of the currently NFv9 information */ - u16 record_length[MAX_RECORDS]; /* Length of delete record */ - u16 total_record_count; /* Total number of records including templates */ - - u8 logging_policy; - - /* - * Keep track of the time and packets since last template send - */ - u32 last_template_sent_time; - u32 pkts_since_last_template; - - /* Server info */ - u32 server_index; - - /* - * current logging context - */ - vlib_buffer_t *current_logging_context; - - /* - * Timestamp in UNIX seconds corresponding to when the current - * logging packet was created - */ - u32 current_logging_context_timestamp; - - /* - * Queued logging context waiting to be sent to the l3 infra node - */ - vlib_buffer_t *queued_logging_context; - - /* - * Headers corresponding to various records in this - * current nfv9 logging context - */ - nfv9_header_t *nfv9_header; - cnat_nfv9_template_t *nfv9_template_header; - nfv9_dataflow_record_header_t *dataflow_header; - u8 *record[MAX_RECORDS]; - u8 *next_data_ptr; - u8 last_record; - u32 nfv9_logging_next_index; - u32 ip4_input_node_index; - vlib_frame_t *f; - u32 *to_next; -} cnat_nfv9_logging_info_t; - - -/* - * Global structure for CGN APP configuration - */ -typedef struct { - /* - * Global NFv9 Logging Collector Index - */ - u32 cnat_nfv9_global_collector_index; - - /* - * Node index corresponding to the infra L3 output node - * to which the nfv9 logging node will send the packet - */ - u16 cnat_nfv9_disp_node_index; - - /* - * Whether we have initialized the NFv9 information - */ - u8 cnat_nfv9_init_done; -} cnat_nfv9_global_info_t; - -typedef enum { - cnat_nfv9_template_add_default, - cnat_nfv9_template_add_always -} cnat_nfv9_template_add_flag_t; - -extern cnat_nfv9_template_t cnat_nfv9_template_info; - -extern cnat_nfv9_logging_info_t cnat_default_nfv9_logging_info; -extern cnat_nfv9_logging_info_t *cnat_nfv9_logging_info_pool; - -extern cnat_nfv9_global_info_t cnat_nfv9_global_info; -extern nfv9_server_info_t *nfv9_server_info_pool; - -/* #define DEBUG_NF_SERVER_CONFIG 1 */ -static inline void nfv9_delete_server_info(cnat_nfv9_logging_info_t *nfv9_info) -{ - nfv9_server_info_t *server = nfv9_server_info_pool + - nfv9_info->server_index; - if(nfv9_info->server_index == EMPTY) { -#ifdef DEBUG_NF_SERVER_CONFIG - if(my_instance_number == 1) { - PLATFORM_DEBUG_PRINT("Deleting empty server info\n"); - } -#endif /* #ifdef DEBUG_NF_SERVER_CONFIG */ - return; - } - - /* Check if this server is not used by anyone.. if not delete */ - /* Caller of this function does not need it..so decrement ref count */ - server->ref_count--; - if(!(server->ref_count)) { -#ifdef DEBUG_NF_SERVER_CONFIG - if(my_instance_number == 1) { - PLATFORM_DEBUG_PRINT("Deleting nfv9 server %x, %d at %d\n", - server->ipv4_address, - server->port, - nfv9_info->server_index); - } -#endif /* #ifdef DEBUG_NF_SERVER_CONFIG */ - pool_put(nfv9_server_info_pool, server); - nfv9_info->server_index = EMPTY; - } -#ifdef DEBUG_NF_SERVER_CONFIG - else { - if(my_instance_number == 1) { - PLATFORM_DEBUG_PRINT("Not Deleting nfv9 server %x, %d rc %d\n", - server->ipv4_address, - server->port, - server->ref_count); - } - } -#endif /* #ifdef DEBUG_NF_SERVER_CONFIG */ - return; -} - -void handle_pending_nfv9_pkts(); -#endif /* __CNAT_LOGGING_H__ */ diff --git a/plugins/vcgn-plugin/vcgn/cnat_pcp_server.h b/plugins/vcgn-plugin/vcgn/cnat_pcp_server.h deleted file mode 100644 index c77c6a87..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_pcp_server.h +++ /dev/null @@ -1,398 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_pcp_server.h - * - * Copyright (c) 2009-2012 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef __CNAT_PCP_SERVER_H__ -#define __CNAT_PCP_SERVER_H__ - -#include "dslite_defs.h" - -/* Debug utils of PCP */ -#define PCP_DBG(debug, ...) \ - if(PREDICT_FALSE(cnat_pcp_debug_flag >= debug)) { \ - printf("%s:%s:%d - ", \ - __FILE__, __FUNCTION__, __LINE__);\ - printf(__VA_ARGS__);\ - printf("\n"); \ - } - -#define PCP_DUMP_PDATA \ - if(PREDICT_FALSE(cnat_pcp_debug_flag >= 100)) { \ - printf("%s:%s:%d - \n", \ - __FILE__, __FUNCTION__, __LINE__);\ - printf("src - ip = %X, proto = %d, port = %d i_vrf = %d, o_vrf = %d\n", \ - pcp_data.src_ip[3], pcp_data.proto, pcp_data.src_port, pcp_data.i_vrf, pcp_data.o_vrf); \ - printf(" third party ip = %X\n", pcp_data.third_party_ip[3]); \ - printf("map - ip = %X, port = %d \n", \ - pcp_data.ext_ip[3], pcp_data.ext_port);\ - printf("remote - ip = %X, port = %d \n", \ - pcp_data.peer_ip[3], pcp_data.peer_port); \ - printf("req life time = %d \n", pcp_data.req_lifetime); \ - printf("drop = %d \n", pcp_data.drop);\ - printf("udp_len = %d \n", pcp_data.udp_len); \ - printf("pm = %p \n", pcp_data.pm); \ - printf("cnat_proto = %X \n", pcp_data.cnat_proto); \ - printf("inst_id = %X \n", pcp_data.inst_id); \ - printf("======================================================\n"); \ - } - -#define PCP_DUMP_PACKET(ip, len) pcp_hex_dump(ip, len) - -#ifdef TOBE_PORTED -#define PCP_INCR(counter) pcp_counters.pcp_##counter++ ; -#else -#define PCP_INCR(counter) -#endif - -typedef struct pcp_debug_counters { - u64 pcp_input; - u64 pcp_output; - u64 pcp_service_nat44; - u64 pcp_service_dslite; - /* below all are drops */ - u64 pcp_drops; - u64 pcp_i2o_key_inuse; - u64 pcp_throttle_drops; - u64 pcp_udp_len; - u64 pcp_nrequest; - u64 pcp_min_udp_len; - u64 pcp_max_udp_len; - u64 pcp_mod4_len; - u64 pcp_invalid_3rd_len; - u64 pcp_invalid_option; - u64 pcp_version; - u64 pcp_invalid_opcode; - u64 pcp_invalid_client_ip; - u64 pcp_invalid_proto; - u64 pcp_invalid_port; - u64 pcp_invalid_vrfmap; - u64 pcp_invalid_ext_addr; - u64 pcp_out_addr_inuse; - u64 pcp_exact_match; - u64 pcp_exact_entry_created; - u64 pcp_exact_db_alloc_failed; - u64 pcp_udb_mismatch; - u64 pcp_noexact_db_allocated; - u64 pcp_static_entry_present; - u64 pcp_entry_deleted; - u64 pcp_3rd_party_option; - - /* map counters */ - u64 pcp_map_input; - u64 pcp_map_min_len; - u64 pcp_map_max_len; - u64 pcp_map_invalid_option; - u64 pcp_map_invalid_option_len; - u64 pcp_map_pref_fail_option; - u64 pcp_map_invalid_delete_req; - u64 pcp_map_delete_req; - u64 pcp_map_create_req; - u64 pcp_map_refresh; - - /* peer counters */ - u64 pcp_peer_input; - u64 pcp_peer_invalid_len; - u64 pcp_peer_delete_req; - u64 pcp_peer_create_req; - u64 pcp_peer_addr_mistmatch; - u64 pcp_peer_refresh; - -} pcp_debug_counters_t; - -typedef struct { - u16 msg_id; - u8 rc; - u8 pad[5]; - - /* better to have a group structures rather than individual - variables, any change in counters is will automatically - reflect here */ - pcp_debug_counters_t counters; -} pcp_show_counters_resp_t ; - - - -/* PCP opcodes */ -typedef enum pcp_opcode { - PCP_OPCODE_MAP = 1, - PCP_OPCODE_PEER = 2 -}pcp_opcode_t; - - -/* PCP opcodes */ -typedef enum pcp_options { - PCP_OPTION_3RD_PARTY = 1, - PCP_OPTION_PREF_FAIL = 2, - PCP_OPTION_FILTER = 3 -} pcp_options_t; - -/* PCP Result codes */ -typedef enum pcp_result_codes { - PCP_SUCCESS = 0, - PCP_ERR_UNSUPP_VERSION = 1, - PCP_ERR_NOT_AUTHORIZED = 2, - PCP_ERR_MALFORMED_REQUEST = 3, - PCP_ERR_UNSUPP_OPCODE = 4, - PCP_ERR_UNSUPP_OPTION = 5, - PCP_ERR_MALFORMED_OPTION = 6, - PCP_ERR_NETWORK_FAILURE = 7, - PCP_ERR_NO_RESOURCES = 8, - PCP_ERR_UNSUPP_PROTOCOL = 9, - PCP_ERR_USER_EX_QUOTA = 10, - PCP_ERR_CANNOT_PROVIDE_EXTERNAL = 11, - PCP_ERR_ADDRESS_MISMATCH = 12, - PCP_ERR_EXCESSIVE_REMOTE_PEERS = 13 -} pcp_result_codes_t; - -#define PCP_DISABLED 0 -#define PCP_ENABLED 1 - -#define PCP_DROP 1 - -#define PCP_STATIC_LIFETIME 0xFFFFFFFF -#define PCP_MAX_LIFETIME 0x00015180 /* 24 hours = 86400 seconds*/ - -#define PCP_VERSION_SUPPORTED 1 - -#define PCP_NO_PREF_FAIL_OPTION 0 -#define PCP_PREF_FAIL_OPTION 1 - -#define CNAT_DEF_PCP_PORT 5351 - -#define PCP_REQ_RESP_BIT 0x80 -#define PCP_RESPONSE(r_opcode) (r_opcode & PCP_REQ_RESP_BIT) -#define PCP_REQUEST(r_opcode) !(PCP_RESPONSE(r_opcode)) - -#define PCP_REQ_OPCODE(r_opcode) (r_opcode & 0x7F) - -/* 24 bytes */ -#define PCP_COMMON_HDR_LEN sizeof(pcp_request_t) - -/* 8 bytes */ -#define UDP_HDR_LEN sizeof(udp_hdr_type_t) - -#define PCP_PREF_FAIL_OPTION_SIZE \ - sizeof(pcp_prefer_fail_option_t) - -#define PCP_3RD_PARTY_OPTION_SIZE \ - sizeof(pcp_3rd_party_option_t) - -#define PCP_MIN_LEN PCP_COMMON_HDR_LEN - -/* 24+8=32 bytes */ -#define PCP_MIN_UDP_LEN (PCP_MIN_LEN + UDP_HDR_LEN) - -#define PCP_MAX_LEN 1024 - -/* 1024+8 = 1032 bytes */ -#define PCP_MAX_UDP_LEN (PCP_MAX_LEN + UDP_HDR_LEN) - -/* 24+ 24 = 48 bytes */ -#define PCP_MAP_OPCODE_MIN_LEN (PCP_COMMON_HDR_LEN + \ - sizeof( pcp_map_option_specific_data_t)) - -/* 24 + 44 = 68 bytes */ -#define PCP_PEER_OPCODE_MIN_LEN (PCP_COMMON_HDR_LEN + \ - sizeof( pcp_peer_option_specific_data_t)) - -/* 48 + 8 = 56 bytes */ -#define PCP_MAP_OPCODE_MIN_UDP_LEN (PCP_MAP_OPCODE_MIN_LEN + \ - UDP_HDR_LEN ) - -#define PCP_GET_MAP_OPTION_OFFSET(req) \ - ((u8*)req + PCP_MAP_OPCODE_MIN_LEN) - -#define PCP_GET_PEER_OPTION_OFFSET(req) \ - ((u8*)req + PCP_PEER_OPCODE_MIN_LEN) - - -#define PCP_REQ_TOTAL_LEN(udp) (udp->udp_length - \ - UDP_HDR_LEN) -/* 56 + 4 = 60 bytes */ -#define PCP_MAP_OPCODE_PREF_FAIL_OPTION_LEN \ - (PCP_MAP_OPCODE_MIN_UDP_LEN + \ - sizeof(pcp_prefer_fail_option_t)) - - -/* 68 + 8 = 76 bytes */ -#define PCP_PEER_OPCODE_MIN_UDP_LEN (PCP_PEER_OPCODE_MIN_LEN + \ - UDP_HDR_LEN) - -#define PCP_MUST_OPTION(option_code) (option_code & 0x80) - - - -/* 56 + 20 = 76*/ -#define PCP_DSLITE_MAP_OPCODE_MIN_UDP_LEN \ - ( PCP_MAP_OPCODE_MIN_UDP_LEN + \ - PCP_3RD_PARTY_OPTION_SIZE) - -/* 60 + 20 = 80 */ -#define PCP_DSLITE_MAP_OPCODE_MAX_UDP_LEN \ - ( PCP_MAP_OPCODE_PREF_FAIL_OPTION_LEN + \ - PCP_3RD_PARTY_OPTION_SIZE) - -/* 76 + 20 = 96 */ -#define PCP_DSLITE_PEER_OPCODE_MIN_UDP_LEN \ - ( PCP_PEER_OPCODE_MIN_UDP_LEN + \ - PCP_3RD_PARTY_OPTION_SIZE) - - -#define PCP_SET_CNAT_PROTO(proto) \ - pcp_data.cnat_proto = (proto == TCP_PROT) ? CNAT_TCP: \ - (proto == UDP_PROT)? CNAT_UDP : CNAT_ICMP; - -#define PCP_SET_REQ_LIFETIME() \ - if(pcp_data.db->flags & CNAT_DB_FLAG_STATIC_PORT) { \ - pcp_data.db->proto_data.seq_pcp.pcp_lifetime = \ - PCP_STATIC_LIFETIME; \ - pcp_data.req_lifetime = PCP_STATIC_LIFETIME; \ - } else { \ - pcp_data.db->proto_data.seq_pcp.pcp_lifetime = \ - pcp_data.req_lifetime + cnat_current_time ; \ - } - - -/* per second not more than PCP_THROTTLE_LIMIT - * delete requests will be handled. - * this excludes , specific entries, in which - * only one entry needs to be deleted - */ -#define PCP_THROTTLE_LIMIT 2 - -typedef struct pcp_request { - u8 ver; - u8 r_opcode; - u16 reserved; - u32 req_lifetime; - u32 ip[4]; /* ipv4 will be represented - by the ipv4 mapped ipv6 */ -} pcp_request_t; - -typedef struct pcp_response { - u8 ver; - u8 r_opcode; - u8 reserved; - u8 result_code; - u32 lifetime; - u32 epochtime; - u32 reserved1[3]; -} pcp_response_t; - - -typedef struct pcp_options_hdr { - u8 code; - u8 reserved; - u16 len; - u8 data[0]; -} pcp_options_hdr_t; - - -/* same for both request and response */ -typedef struct pcp_map_option_specific_data { - u8 protocol; - u8 reserved[3]; - u16 int_port; - u16 ext_port; - u32 ext_ip[4]; /* ipv4 will be represnted - by the ipv4 mapped ipv6 */ -} pcp_map_option_specific_data_t; - -/* same for both request and response */ -typedef struct pcp_peer_option_specific_data { - u8 protocol; - u8 reserved[3]; - u16 int_port; - u16 ext_port; - u32 ext_ip[4]; /* ipv4 will be represented - by the ipv4 mapped ipv6 */ - u16 peer_port; - u16 reserved1; - u32 peer_ip[4]; -} pcp_peer_option_specific_data_t; - -typedef struct pcp_prefer_fail_option { - u8 option; - u8 reserved; - u16 len; -} pcp_prefer_fail_option_t; - - -typedef struct pcp_3rd_party_option{ - u8 option; - u8 reserved; - u16 len; - u32 ip[4]; -} pcp_3rd_party_option_t; - -/* structure used as pipeline data */ - -typedef struct pcp_pipeline_data { - - union { - - u8 *p; - ipv4_header *ip ; - ipv6_header_t *ipv6 ; - - } l3addr; - - udp_hdr_type_t *udp; - pcp_request_t *req; - pcp_response_t *resp; - pcp_opcode_t opcode; - u32 src_ip[4]; - u16 src_port; - u8 proto; - u16 i_vrf; - u16 o_vrf; - u32 ext_ip[4]; - u16 ext_port; - u32 third_party_ip[4]; - - /* valid for peer opcode */ - u32 peer_ip[4]; - u32 peer_port; - u32 req_lifetime; - u32 udp_len; - pcp_options_t pref_fail; - pcp_options_t third_party; - u8 *option_spec; - pcp_result_codes_t ret_code; - cnat_portmap_v2_t *pm; - cnat_main_db_entry_t *db; - cnat_vrfmap_t *vrfmap; - dslite_table_entry_t *inst_ptr; - u16 inst_id; - u32 flags; - u16 cnat_proto; - - /* is packet needs to be dropped ? */ - u8 drop; - /* nat44, dslite, nat64 */ -#define PCP_SERVICE_NAT44 1 -#define PCP_SERVICE_DSLITE 2 -#define PCP_SERVICE_NAT64 3 - u8 service_type; - -#define PCP_REQ_ENTRY_PRESENT 1 -#define PCP_REQ_EXT_MAP_PRESENT 1 - u8 state; -} pcp_pipeline_data_t; - -#endif /* __CNAT_PCP_sERVER_H__ */ diff --git a/plugins/vcgn-plugin/vcgn/cnat_ports.c b/plugins/vcgn-plugin/vcgn/cnat_ports.c deleted file mode 100644 index 943fb3ed..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_ports.c +++ /dev/null @@ -1,1113 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_ports.c - port allocator - * - * Copyright (c) 2008-2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ -#include -#include -#include -#include -#include -#include -#include - -#include "cnat_db.h" -#include "cnat_config.h" -#include "cnat_global.h" -#include "cnat_logging.h" -#include "spp_timers.h" -#include "platform_common.h" -#include "cgn_bitmap.h" -#include "spp_platform_trace_log.h" -#include "cnat_ports.h" - -#if 1 /* TOBE_PORTED */ -/* Following is defined elsewhere. */ -#define msg_spp_err(s) \ -do { \ - fprintf(stderr,(i8 *)s); \ - fputs("\n", stderr); \ -} while(0); -#endif - - -#define PM_90_PERCENT_USE 58980 -/* - * instance number provisioned from HW - */ -u8 my_instance_number = 0; - -typedef struct { - u32 cached_next_index; - /* $$$$ add data here */ - - /* convenience variables */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; -} cnat_ports_main_t; - -cnat_ports_main_t cnat_ports_main; - -static u32 rseed_port; /* random number generator seed */ - -void -cnat_db_dump_portmap_for_vrf (u32 vrfmap_index) -{ - u32 i, pm_len; - cnat_vrfmap_t *my_vrfmap = cnat_map_by_vrf + vrfmap_index; - cnat_portmap_v2_t *pm, *my_pm __attribute__((unused)); - - pm = my_vrfmap->portmap_list; - pm_len = vec_len(pm); - - for (i = 0; i < pm_len; i++) { - my_pm = pm + i; - - PLATFORM_DEBUG_PRINT("pm %d: IPv4 Addr 0x%x - in use %d private_ip_users_count %d\n", - i, my_pm->ipv4_address, my_pm->inuse, - my_pm->private_ip_users_count); - - PLATFORM_DEBUG_PRINT("pm %d: IPv4 Addr 0x%x - in use %d " - "private_ip_users_count %d\n", - i, my_pm->ipv4_address, my_pm->inuse, - my_pm->private_ip_users_count); - } -} - -void -cnat_db_dump_portmaps () -{ - u32 i, vrfmap_index; - - for (i = 0; i < CNAT_MAX_VRFMAP_ENTRIES; i++) { - vrfmap_index = vrf_map_array[i]; - - if (vrfmap_index == VRF_MAP_ENTRY_EMPTY) { - continue; - } - - PLATFORM_DEBUG_PRINT("\n\nDumping the port map for uidb_index %d\n", i); - cnat_db_dump_portmap_for_vrf(vrfmap_index); - } -} - -#ifndef NO_BULK_LOGGING -static int check_if_stat_alloc_ok_for_bulk(cnat_portmap_v2_t *pm, - u16 i_port, bulk_alloc_size_t bulk_size, - u16 static_port_range) -{ - uword bit_test_result; - if(BULK_ALLOC_SIZE_NONE == bulk_size) return 1; /* No issues */ - - if(i_port < static_port_range) return 1; /* we don't want bulk */ - - i_port = (i_port/bulk_size) * bulk_size; - bit_test_result = cgn_clib_bitmap_check_if_all(pm->bm, i_port, bulk_size); - return(bit_test_result); -} -#else /* dummy */ -inline static int check_if_stat_alloc_ok_for_bulk(cnat_portmap_v2_t *pm, - u16 i_port, bulk_alloc_size_t bulk_size, - u16 static_port_range) -{ - return 1; -} -#endif /* NO_BULK_LOGGING */ -/* - * cnat_port_alloc_static_v2 - * public ipv4 address/port allocator for Static Port commands - * tries to allocate same outside port as inside port - */ -cnat_errno_t -cnat_static_port_alloc_v2 ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - port_pair_t pair_type, - u32 i_ipv4_address, - u16 i_port, - u32 *index, - u32 *o_ipv4_address, - u16 *o_port, - u16 static_port_range -#ifndef NO_BULK_LOGGING - , bulk_alloc_size_t bulk_size, - int *nfv9_log_req -#endif - , u16 ip_n_to_1 - ) -{ - u32 i, hash_value, my_index, found, max_attempts; - u16 start_bit, new_port; - cnat_portmap_v2_t *my_pm = 0; - u32 pm_len = vec_len(pm); - uword bit_test_result; - -#ifndef NO_BULK_LOGGING - *nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED; -#endif - - if (PREDICT_FALSE(pm_len == 0)) { - return (CNAT_NO_POOL_ANY); - } - - switch (atype) { - - case PORT_ALLOC_ANY: - - found = 0; - - /* - * Try to hash the IPv4 address to get an index value to select the pm - */ - hash_value = (i_ipv4_address & 0xffff) ^ - ((i_ipv4_address > 16) & 0xffff); - - /* - * If pm_len <= 256, compact the hash to 8 bits - */ - if (PREDICT_TRUE(pm_len <= 256)) { - hash_value = (hash_value & 0xff) ^ ((hash_value > 8) & 0xff); - } - - /* - * Ensure that the hash value is in the range 0 .. (pm_len-1) - */ - my_index = hash_value % pm_len; - - for (i = 0; i < PORT_PROBE_LIMIT; i++) { - my_pm = pm + my_index; - if(PREDICT_TRUE(ip_n_to_1)) { - if(PREDICT_TRUE(my_pm->private_ip_users_count < ip_n_to_1)) { - /* - * Try to find a PM with atlest 33% free and my_port free - */ - if (PREDICT_TRUE((my_pm->inuse < ((BITS_PER_INST*2)/3)) && - clib_bitmap_get_no_check(my_pm->bm, - i_port) == 1) -#ifndef NO_BULK_LOGGING - && check_if_stat_alloc_ok_for_bulk(my_pm, i_port, - bulk_size, - static_port_range) -#endif - ) { - found = 1; - break; - } - } - - } else { - /* - * Try to find a PM with atlest 33% free and my_port free - */ - if (PREDICT_TRUE((my_pm->inuse < ((BITS_PER_INST*2)/3)) && - clib_bitmap_get_no_check(my_pm->bm, - i_port) == 1) -#ifndef NO_BULK_LOGGING - && check_if_stat_alloc_ok_for_bulk(my_pm, i_port, - bulk_size, - static_port_range) -#endif - ) { - found = 1; - break; - } - } - my_index = (my_index + 1) % pm_len; - } - - /* - * If not found do it the hard way . - * "hard" way, best-fit. - */ - if (!found) { - u32 min_inuse_any, min_inuse_myport; - u32 min_index_any, min_index_myport; - - min_inuse_any = min_inuse_myport = PORTS_PER_ADDR + 1; - min_index_any = min_index_myport = ~0; - for (i = 0; i < pm_len; i++) { - my_pm = pm + i; - if(PREDICT_TRUE(ip_n_to_1)) { - if(PREDICT_TRUE(my_pm->private_ip_users_count < ip_n_to_1)) { - if (PREDICT_FALSE(my_pm->inuse < min_inuse_any)) { - min_inuse_any = my_pm->inuse; - min_index_any = my_pm - pm; - } - if (PREDICT_FALSE(my_pm->inuse < min_inuse_myport)) { - if (PREDICT_TRUE(clib_bitmap_get_no_check( - my_pm->bm,i_port) == 1) -#ifndef NO_BULK_LOGGING - && check_if_stat_alloc_ok_for_bulk(my_pm, - i_port,bulk_size,static_port_range) -#endif - ) { - min_inuse_myport = my_pm->inuse; - min_index_myport = my_pm - pm; - } - } - - } - - } else { - if (PREDICT_FALSE(my_pm->inuse < min_inuse_any)) { - min_inuse_any = my_pm->inuse; - min_index_any = my_pm - pm; - } - if (PREDICT_FALSE(my_pm->inuse < min_inuse_myport)) { - if (PREDICT_TRUE(clib_bitmap_get_no_check( - my_pm->bm, i_port) == 1) -#ifndef NO_BULK_LOGGING - && check_if_stat_alloc_ok_for_bulk(my_pm, i_port, - bulk_size, static_port_range) -#endif - ) { - min_inuse_myport = my_pm->inuse; - min_index_myport = my_pm - pm; - } - } - } - } - - /* - * Check if we have an exactly matching PM that has - * myport free. If so use it. If no such PM is - * available, use any PM - */ - if (PREDICT_TRUE(min_inuse_myport < PORTS_PER_ADDR)) { - my_pm = pm + min_index_myport; - my_index = min_index_myport; - found = 1; - } else if (PREDICT_TRUE(min_inuse_any < PORTS_PER_ADDR)) { - my_pm = pm + min_index_any; - my_index = min_index_any; - found = 1; - } - } - - if (!found) { - return (CNAT_NO_PORT_ANY); - } - break; - - case PORT_ALLOC_DIRECTED: - my_index = *index; - if (PREDICT_FALSE(my_index > pm_len)) { - return (CNAT_INV_PORT_DIRECT); - } - my_pm = pm + my_index; - break; - - default: - return (CNAT_ERR_PARSER); - } - - /* Allocate a matching port if possible */ - start_bit = i_port; - found = 0; - max_attempts = BITS_PER_INST; -#ifndef NO_BULK_LOGGING - if((BULK_ALLOC_SIZE_NONE != bulk_size) && - (i_port >= static_port_range)) { - start_bit = (start_bit/bulk_size) * bulk_size; - max_attempts = BITS_PER_INST/bulk_size; - } -#endif /* NO_BULK_LOGGING */ - - for (i = 0; i < max_attempts; i++) { -#ifndef NO_BULK_LOGGING - if((BULK_ALLOC_SIZE_NONE != bulk_size) && - (i_port >= static_port_range)) { - bit_test_result = cgn_clib_bitmap_check_if_all(my_pm->bm, - start_bit, bulk_size); - } - else -#endif /* #ifndef NO_BULK_LOGGING */ - bit_test_result = clib_bitmap_get_no_check(my_pm->bm, start_bit); - - if (PREDICT_TRUE(bit_test_result)) { -#ifndef NO_BULK_LOGGING - if((BULK_ALLOC_SIZE_NONE != bulk_size) && - (i_port >= static_port_range)) { - *nfv9_log_req = start_bit; - if(i==0) new_port = i_port; /* First go */ - else { - new_port = bit2port(start_bit); - if (pair_type == PORT_S_ODD && (new_port & 0x1) == 0) - new_port++; - } - found = 1; - break; - } - else { -#endif /* NO_BULK_LOGGING */ - new_port = bit2port(start_bit); - if (pair_type == PORT_S_ODD) { - if ((new_port & 0x1) == 1) { - found = 1; - break; - } - } else if (pair_type == PORT_S_EVEN) { - if ((new_port & 0x1) == 0) { - found = 1; - break; - } - } else { - found = 1; - break; - } -#ifndef NO_BULK_LOGGING - } -#endif - } -#ifndef NO_BULK_LOGGING - if((BULK_ALLOC_SIZE_NONE != bulk_size) && - (i_port >= static_port_range)) - start_bit = (start_bit + bulk_size) % BITS_PER_INST; - else { -#endif /* NO_BULK_LOGGING */ - start_bit = (start_bit + 1) % BITS_PER_INST; - if(PREDICT_FALSE(start_bit == 0)) { - start_bit = 1; /* Port 0 is invalid, so start from 1 */ - } -#ifndef NO_BULK_LOGGING - } -#endif - } /* End of for loop */ - - if (!found) { - /* Port allocation failure */ - if (atype == PORT_ALLOC_DIRECTED) { - return (CNAT_NOT_FOUND_DIRECT); - } else { - return (CNAT_NOT_FOUND_ANY); - } - } - - /* Accounting */ - cgn_clib_bitmap_clear_no_check(my_pm->bm, new_port); - (my_pm->inuse)++; - - *index = my_pm - pm; - *o_ipv4_address = my_pm->ipv4_address; - - *o_port = new_port; - - return (CNAT_SUCCESS); -} - -/* - * Try to allocate a portmap structure based on atype field - */ -cnat_portmap_v2_t * -cnat_dynamic_addr_alloc_from_pm ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - u32 *index, - cnat_errno_t *err, - u16 ip_n_to_1, - u32 *rseed_ip) -{ - u32 i, pm_len; - int my_index; - int min_inuse, min_index; - - cnat_portmap_v2_t *my_pm = 0; - *err = CNAT_NO_POOL_ANY; - - pm_len = vec_len(pm); - - switch(atype) { - case PORT_ALLOC_ANY: - if (PREDICT_FALSE(pm_len == 0)) { - my_pm = 0; - *err = CNAT_NO_POOL_ANY; - goto done; - } - - /* "Easy" way, first address with at least 200 free ports */ - for (i = 0; i < PORT_PROBE_LIMIT; i++) { - *rseed_ip = randq1(*rseed_ip); - my_index = (*rseed_ip) % pm_len; - my_pm = pm + my_index; - if (PREDICT_FALSE(ip_n_to_1)) { - if(PREDICT_TRUE(ip_n_to_1 == 1)) { - if (PREDICT_FALSE(0 == my_pm->inuse)) { - goto done; - } - } else { - if(PREDICT_TRUE(my_pm->private_ip_users_count < ip_n_to_1)) { - if (PREDICT_FALSE(my_pm->inuse < ((BITS_PER_INST*2)/3))) { - goto done; - } - } - } - } else { - if (PREDICT_FALSE(my_pm->inuse < ((BITS_PER_INST*2)/3))) { - goto done; - } - } - } - - /* "hard" way, best-fit. $$$$ Throttle complaint */ - min_inuse = PORTS_PER_ADDR + 1; - min_index = ~0; - for (i = 0; i < pm_len; i++) { - my_pm = pm + i; - if (PREDICT_FALSE(ip_n_to_1)) { - if(PREDICT_TRUE(ip_n_to_1 == 1)) { - if (PREDICT_FALSE(!my_pm->inuse)) { - min_inuse = my_pm->inuse; - min_index = my_pm - pm; - } - } else { - if(PREDICT_TRUE(my_pm->private_ip_users_count < ip_n_to_1)) { - if (PREDICT_TRUE(my_pm->inuse < min_inuse)) { - min_inuse = my_pm->inuse; - min_index = my_pm - pm; - } - - } - } - - } else { - if (PREDICT_TRUE(my_pm->inuse < min_inuse)) { - min_inuse = my_pm->inuse; - min_index = my_pm - pm; - } - } - } - - if (PREDICT_TRUE(min_inuse < PORTS_PER_ADDR)) { - my_pm = pm + min_index; - my_index = min_index; - goto done; - } - - /* Completely out of ports */ -#ifdef DEBUG_PRINTF_ENABLED - PLATFORM_DEBUG_PRINT("%s out of ports\n", __FUNCTION__); -#endif - - my_pm = 0; - *err = CNAT_NO_PORT_ANY; - break; - - - case PORT_ALLOC_DIRECTED: - //ASSERT(*index < pm_len); - if (PREDICT_FALSE(*index > pm_len)) { - my_pm = 0; - *err = CNAT_INV_PORT_DIRECT; - goto done; - } - my_pm = pm + *index; - my_index = *index; - break; - - default: - msg_spp_err("bad allocation type in cnat_port_alloc"); - my_pm = 0; - *err = CNAT_ERR_PARSER; - break; - } - - done: - if (PREDICT_FALSE(my_pm == NULL)) { - return (my_pm); - } - - if (PREDICT_FALSE(my_pm->inuse >= BITS_PER_INST)) { - my_pm = 0; - if (atype == PORT_ALLOC_DIRECTED) { - *err = CNAT_BAD_INUSE_DIRECT; - } else { - *err = CNAT_BAD_INUSE_ANY; - } - } - - return (my_pm); -} - - -/* - * cnat_port_alloc_v2 - * public ipv4 address/port allocator for dynamic ports - * - * 200K users / 20M translations means vec_len(cnat_portmap) will be - * around 300. - * - */ -cnat_errno_t -cnat_dynamic_port_alloc_v2 ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - port_pair_t pair_type, - u32 *index, - u32 *o_ipv4_address, - u16 *o_port, - u16 static_port_range -#ifndef NO_BULK_LOGGING - , bulk_alloc_size_t bulk_size, - int *nfv9_log_req -#endif - , u16 ip_n_to_1, - u32 *rseed_ip - ) -{ - int i; - cnat_errno_t my_err = CNAT_NO_POOL_ANY; - cnat_portmap_v2_t *my_pm = 0; - u16 start_bit; - u16 new_port; - uword bit_test_result; - uword max_trys_to_find_port; - - ASSERT(index); - ASSERT(o_ipv4_address); - ASSERT(o_port); - - my_pm = cnat_dynamic_addr_alloc_from_pm(pm, atype, index, &my_err, ip_n_to_1, - rseed_ip); - - if (PREDICT_FALSE(my_pm == NULL)) { - return (my_err); - } - if(PREDICT_FALSE(my_pm->dyn_full == 1)) { - if (atype == PORT_ALLOC_DIRECTED) { - return (CNAT_NOT_FOUND_DIRECT); - } else { - return (CNAT_NOT_FOUND_ANY); - } - } - -#if DEBUG > 1 - PLATFORM_DEBUG_PRINT("ALLOC_PORT_V2: My_Instance_Number %d: IP addr 0x%x, Inuse %d\n", - my_instance_number, my_pm->ipv4_address, my_pm->inuse); -#endif - - rseed_port = randq1(rseed_port); - - /* - * Exclude the static port range for allocating dynamic ports - */ - start_bit = (rseed_port) % (BITS_PER_INST - static_port_range); - start_bit = start_bit + static_port_range; - -#ifndef NO_BULK_LOGGING - *nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED; - if(BULK_ALLOC_SIZE_NONE != bulk_size) - { - /* We need the start port of the range to be alined on integer multiple - * of bulk_size */ - max_trys_to_find_port = BITS_PER_INST/bulk_size; - start_bit= ((start_bit + bulk_size -1)/bulk_size) * bulk_size; - } - else -#endif /* #ifndef NO_BULK_LOGGING */ - max_trys_to_find_port = BITS_PER_INST; - - /* Allocate a random port / port-pair */ - for (i = 0; i < max_trys_to_find_port; i++) { - - /* start_bit is only a u16.. so it can rollover and become zero */ - if (PREDICT_FALSE( /* (start_bit >= BITS_PER_INST) || FIXME u16 cannot be >= 65536 */ - (start_bit < static_port_range))) { - start_bit = static_port_range; -#ifndef NO_BULK_LOGGING - if(BULK_ALLOC_SIZE_NONE != bulk_size) { - start_bit= ((start_bit + bulk_size -1)/bulk_size) * bulk_size; - } -#endif /* #ifndef NO_BULK_LOGGING */ - } - /* Scan forward from random position */ -#ifndef NO_BULK_LOGGING - if(BULK_ALLOC_SIZE_NONE != bulk_size) { - bit_test_result = cgn_clib_bitmap_check_if_all(my_pm->bm, - start_bit, bulk_size); - } - else -#endif /* #ifndef NO_BULK_LOGGING */ - bit_test_result = clib_bitmap_get_no_check(my_pm->bm, start_bit); - - if (PREDICT_TRUE(bit_test_result)) { - new_port = bit2port(start_bit); -#ifndef NO_BULK_LOGGING - if(BULK_ALLOC_SIZE_NONE != bulk_size) - *nfv9_log_req = new_port; -#endif - if ((pair_type == PORT_S_ODD) && - (!(new_port & 0x1))) { -#ifndef NO_BULK_LOGGING - if(BULK_ALLOC_SIZE_NONE != bulk_size) { - start_bit++; /* Just use the next one in the bulk range */ - new_port++; - goto found2; - } -#endif /* #ifndef NO_BULK_LOGGING */ - goto notfound; - } else if ((pair_type == PORT_S_EVEN) && - (new_port & 0x1)) { - goto notfound; - } - - /* OK we got one or two suitable ports */ - goto found2; - } - - notfound: -#ifndef NO_BULK_LOGGING - if(BULK_ALLOC_SIZE_NONE != bulk_size) - start_bit += bulk_size; - else -#endif /* #ifndef NO_BULK_LOGGING */ - start_bit++; - - } /* end of for loop */ - - /* Completely out of ports */ - - /* Port allocation failure */ - /* set dyn_full flag. This would be used to verify - * for further dyn session before searching for port - */ - if (atype == PORT_ALLOC_DIRECTED) { - my_pm->dyn_full = 1; - return (CNAT_NOT_FOUND_DIRECT); - } else { - my_pm->dyn_full = 1; - return (CNAT_NOT_FOUND_ANY); - } - - - found2: - - /* Accounting */ - cgn_clib_bitmap_clear_no_check (my_pm->bm, start_bit); - (my_pm->inuse)++; - - *index = my_pm - pm; - *o_ipv4_address = my_pm->ipv4_address; - - *o_port = new_port; - return (CNAT_SUCCESS); -} - -#ifdef TOBE_PORTED -/* - * cnat_alloc_port_from_pm - * Given a portmap structure find port/port_pair that are free - * - * The assumption in this function is that bit in bm corresponds - * to a port number. This is TRUE and hence there is no call - * to the function bit2port here, though it is done in other - * places in this file. - * - */ -static u32 -cnat_alloc_port_from_pm ( - u32 start_port, - u32 end_port, - cnat_portmap_v2_t *my_pm, - port_pair_t pair_type -#ifndef NO_BULK_LOGGING - , bulk_alloc_size_t bulk_size, - int *nfv9_log_req -#endif /* #ifnded NO_BULK_ALLOCATION */ - ) -{ - u32 i; - u32 start_bit; - u32 total_ports = end_port - start_port + 1; - uword bit_test_result; - uword max_trys_to_find_port; - - rseed_port = randq1(rseed_port); - - start_bit = rseed_port % total_ports; - start_bit = start_bit + start_port; -#ifndef NO_BULK_LOGGING - *nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED; - if(BULK_ALLOC_SIZE_NONE != bulk_size) - { - /* We need the start port of the range to be alined on integer multiple - * of bulk_size */ - max_trys_to_find_port = total_ports/bulk_size; - start_bit= ((start_bit + bulk_size -1)/bulk_size) * bulk_size; - } - else -#endif /* #ifndef NO_BULK_LOGGING */ - max_trys_to_find_port = total_ports; - - /* Allocate a random port / port-pair */ - for (i = 0; i < max_trys_to_find_port; i++) { - /* start_bit is only a u16.. so it can rollover and become zero */ - if (PREDICT_FALSE((start_bit >= end_port) || - (start_bit < start_port))) { - start_bit = start_port; -#ifndef NO_BULK_LOGGING - if(BULK_ALLOC_SIZE_NONE != bulk_size) { - start_bit= ((start_bit + bulk_size -1)/bulk_size) * bulk_size; - } -#endif /* #ifndef NO_BULK_LOGGING */ - } - - /* Scan forward from random position */ -#ifndef NO_BULK_LOGGING - if(BULK_ALLOC_SIZE_NONE != bulk_size) { - bit_test_result = cgn_clib_bitmap_check_if_all(my_pm->bm, - start_bit, bulk_size); - } - else -#endif /* #ifndef NO_BULK_LOGGING */ - bit_test_result = clib_bitmap_get_no_check(my_pm->bm, start_bit); - - if (PREDICT_TRUE(bit_test_result)) { -#ifndef NO_BULK_LOGGING - if(BULK_ALLOC_SIZE_NONE != bulk_size) { - /* Got the entire bulk range */ - *nfv9_log_req = bit2port(start_bit); - return start_bit; - } else { -#endif /* #ifndef NO_BULK_LOGGING */ - /* - * For PORT_PAIR, first port has to be Even - * subsequent port <= end_port - * subsequent port should be unallocated - */ - if ((start_bit & 0x1) || - ((start_bit + 1) > end_port) || - (clib_bitmap_get_no_check(my_pm->bm, - (start_bit + 1)) == 0)) { - goto notfound; - } - return (start_bit); -#ifndef NO_BULK_LOGGING - } -#endif /* #ifndef NO_BULK_LOGGING */ - } /* if( free port found ) */ - -notfound: -#ifndef NO_BULK_LOGGING - if(BULK_ALLOC_SIZE_NONE != bulk_size) { - start_bit += bulk_size; - } else -#endif /* #ifndef NO_BULK_LOGGING */ - start_bit++; - - } - return (BITS_PER_INST); -} - -/* - * cnat_dynamic_port_alloc_rtsp - * public ipv4 address/port allocator for dynamic ports - * - * 200K users / 20M translations means vec_len(cnat_portmap) will be - * around 300. - * - */ - -cnat_errno_t -cnat_dynamic_port_alloc_rtsp ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - port_pair_t pair_type, - u16 start_range, - u16 end_range, - u32 *index, - u32 *o_ipv4_address, - u16 *o_port -#ifndef NO_BULK_LOGGING - , bulk_alloc_size_t bulk_size, - int *nfv9_log_req -#endif - , u32 *rseed_ip - ) -{ - - u32 current_timestamp; - cnat_errno_t my_err = CNAT_NO_POOL_ANY; - cnat_portmap_v2_t *my_pm = 0; - u32 alloc_bit; - - ASSERT(index); - ASSERT(o_ipv4_address); - ASSERT(o_port); - - my_pm = cnat_dynamic_addr_alloc_from_pm(pm, atype, index, &my_err, 0,rseed_ip); - - if (PREDICT_FALSE(my_pm == NULL)) { - return (my_err); - } - -#if DEBUG > 1 - PLATFORM_DEBUG_PRINT("ALLOC_PORT_V2: My_Instance_Number %d: IP addr 0x%x, Inuse %d\n", - my_instance_number, my_pm->ipv4_address, my_pm->inuse); -#endif - - alloc_bit = - cnat_alloc_port_from_pm(start_range, end_range, my_pm, pair_type -#ifndef NO_BULK_LOGGING - , bulk_size, nfv9_log_req -#endif /* #ifndef NO_BULK_LOGGING */ - ); - - if (alloc_bit < BITS_PER_INST) { - if (pair_type == PORT_PAIR) { - /* Accounting */ - cgn_clib_bitmap_clear_no_check (my_pm->bm, alloc_bit); - cgn_clib_bitmap_clear_no_check (my_pm->bm, alloc_bit+1); - (my_pm->inuse) += 2; - } else { - /* Accounting */ - cgn_clib_bitmap_clear_no_check (my_pm->bm, alloc_bit); - (my_pm->inuse)++; - } - - *index = my_pm - pm; - *o_ipv4_address = my_pm->ipv4_address; - - *o_port = bit2port(alloc_bit);; - - return (CNAT_SUCCESS); - } - - /* Completely out of ports */ - current_timestamp = spp_trace_log_get_unix_time_in_seconds(); - if (PREDICT_FALSE((current_timestamp - my_pm->last_sent_timestamp) > - 1000)) { - spp_printf(CNAT_NO_EXT_PORT_AVAILABLE, 0, NULL); - my_pm->last_sent_timestamp = current_timestamp; - } - - - /* Port allocation failure */ - if (atype == PORT_ALLOC_DIRECTED) { - return (CNAT_NOT_FOUND_DIRECT); - } else { - return (CNAT_NOT_FOUND_ANY); - } -} -#else -cnat_errno_t -cnat_dynamic_port_alloc_rtsp ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - port_pair_t pair_type, - u16 start_range, - u16 end_range, - u32 *index, - u32 *o_ipv4_address, - u16 *o_port -#ifndef NO_BULK_LOGGING - , bulk_alloc_size_t bulk_size, - int *nfv9_log_req -#endif - , u32 *rseed_ip - ) -{ - return (CNAT_NOT_FOUND_ANY); -} -#endif - - -/* - * cnat_mapped_static_port_alloc_v2 - * / - */ -cnat_errno_t -cnat_mapped_static_port_alloc_v2 ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - u32 *index, - u32 ipv4_address, - u16 port -#ifndef NO_BULK_LOGGING - , int *nfv9_log_req, - bulk_alloc_size_t bulk_size -#endif - , u16 ip_n_to_1 - ) -{ - int i; - u32 pm_len; - u16 bm_bit; - cnat_portmap_v2_t *my_pm = 0; - u32 my_index; - - ASSERT(index); - - /* - * Map the port to the bit in the pm bitmap structure. - * Note that we use ports from 1024..65535, so - * port number x corresponds to (x-1024) position in bitmap - */ - bm_bit = port2bit(port); - - pm_len = vec_len(pm); - - switch(atype) { - case PORT_ALLOC_ANY: - if (PREDICT_FALSE(pm_len == 0)) { - return (CNAT_NO_POOL_ANY); - } - - /* - * Find the pm that is allocated for this translated IP address - */ - my_index = pm_len; - - for (i = 0; i < pm_len; i++) { - my_pm = pm + i; - if (PREDICT_FALSE(my_pm->ipv4_address == ipv4_address)) { - my_index = i; - break; - } - } - - if ((PREDICT_FALSE(my_index >= pm_len)) || - ((PREDICT_FALSE(ip_n_to_1)) && (PREDICT_TRUE(my_pm->private_ip_users_count >= ip_n_to_1)))) { - return (CNAT_NO_POOL_ANY); - } - - break; - - case PORT_ALLOC_DIRECTED: - if (PREDICT_FALSE(*index > pm_len)) { - return (CNAT_INV_PORT_DIRECT); - } - - my_index = *index; - my_pm = pm + my_index; - if (PREDICT_FALSE(my_pm->ipv4_address != ipv4_address)) { - if (PREDICT_FALSE(global_debug_flag && CNAT_DEBUG_GLOBAL_ALL)) { - PLATFORM_DEBUG_PRINT("Delete all main db entry for that particular in ipv4 address\n"); - } - return (CNAT_INV_PORT_DIRECT); - } - - break; - - default: - msg_spp_err("bad allocation type in cnat_port_alloc"); - return (CNAT_ERR_PARSER); - } - - - if (PREDICT_FALSE(my_pm == NULL)) { - return (CNAT_NO_POOL_ANY); - } - - /* - * Check if the port is already allocated to some other mapping - */ - if (PREDICT_FALSE(clib_bitmap_get_no_check (my_pm->bm, bm_bit) == 0)) { - return (CNAT_NO_POOL_ANY); - } - -#if DEBUG > 1 - PLATFORM_DEBUG_PRINT("ALLOC_PORT_V2: My_Instance_Number %d: IP addr 0x%x, Inuse %d\n", - my_instance_number, my_pm->ipv4_address, my_pm->inuse); -#endif - - /* - * Indicate that the port is already allocated - */ - cgn_clib_bitmap_clear_no_check (my_pm->bm, bm_bit); - (my_pm->inuse)++; - - *index = my_index; - - return (CNAT_SUCCESS); -} - -void cnat_port_free_v2 ( - cnat_portmap_v2_t *pm, - int index, - port_pair_t pair_type, - u16 base_port, - u16 static_port_range) -{ - cnat_portmap_v2_t *my_pm; - uword bit; - - /* check for valid portmap */ - if (PREDICT_FALSE(index > vec_len(pm))) { - spp_printf(CNAT_INVALID_INDEX_TO_FREE_PORT, 0, 0); - return; - } - - my_pm = pm + index; - bit = port2bit(base_port); - -#if DEBUG > 0 - if(clib_bitmap_get_no_check(my_pm->bm, bit)) - ASSERT(clib_bitmap_get_no_check(my_pm->bm, bit) == 0); -#endif - - cgn_clib_bitmap_set_no_check(my_pm->bm, bit); - - my_pm->inuse -= 1; - if(base_port >= static_port_range) { - /* Clear the full flag. we can have a new dynamic session now */ - my_pm->dyn_full = 0; - } - - return; -} - -void cnat_portmap_dump_v2 (cnat_portmap_v2_t *pm, u16 print_limit) -{ - int i; - u32 inuse =0; - - ASSERT(pm); - - for (i = 0; i < BITS_PER_INST; i++) { - if (PREDICT_FALSE(clib_bitmap_get_no_check (pm->bm, i) == 0)) { - if (PREDICT_TRUE(inuse++ < print_limit)) - PLATFORM_DEBUG_PRINT(" %d", bit2port(i)); - } - } - if (PREDICT_FALSE(inuse >= print_limit)) { - PLATFORM_DEBUG_PRINT("%d printed, print limit is %d\n", - inuse, print_limit); - } - PLATFORM_DEBUG_PRINT("\n"); -} - - -/* - * cnat_ports_init - */ -clib_error_t *cnat_ports_init(vlib_main_t *vm) -{ - cnat_ports_main_t *mp = &cnat_ports_main; - - mp->vlib_main = vm; - mp->vnet_main = vnet_get_main(); - - /* suppress crypto-random port numbering */ -#ifdef SOON - if (spp_get_int_prop("no_crypto_random_ports") == 0) - crypto_random32(&seed); -#endif - - return 0; -} - -VLIB_INIT_FUNCTION(cnat_ports_init); - diff --git a/plugins/vcgn-plugin/vcgn/cnat_ports.h b/plugins/vcgn-plugin/vcgn/cnat_ports.h deleted file mode 100644 index bc1fb0d2..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_ports.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_ports.h - port database definitions - * - * Copyright (c) 2007-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef __CNAT_PORTS_H__ -#define __CNAT_PORTS_H__ - -#include "platform_common.h" -#include "cnat_bulk_port_defs.h" - -#define PORTS_PER_ADDR 65536 - -#define CNAT_INSTS PLATFORM_CNAT_INSTS - -#define BITS_PER_INST (PORTS_PER_ADDR) - -/* - * Ensure that atleast few 4 bit ports are available for RTSP - * in case we want to map 4 digit inside ports to 4 digit outside ports - */ -#define MIN_STATIC_PORT_RANGE_FOR_RTSP (9900) - -extern u8 my_instance_number; - -/* - * Now it is a 1-to-1 mapping between bit and port values - */ -static inline u16 bit2port (u32 bit) -{ - return bit; -} - -static inline uword port2bit (u16 port) -{ - return port; -} - -/* - * Port bitmap structure - * THIS structure is not used to be REMOVED.... - */ - - -typedef struct { - u32 ipv4_address; /* native bit order */ - u16 vrf; - u16 pad; - u32 threshold_crossed; - uword bm[(BITS_PER_INST + BITS(uword)-1)/BITS(uword)]; -} cnat_portmap_t; - -//cnat_portmap_t *cnat_portmap; - - -typedef struct { - u32 inuse; - u32 delete_time; - u32 ipv4_address; /* native bit order */ - u32 last_sent_timestamp; - uword bm[(BITS_PER_INST + BITS(uword)-1)/BITS(uword)]; - u32 dyn_full; - u32 private_ip_users_count; /* number of private ip's(subscribers) to this - public ip */ -} cnat_portmap_v2_t; - - -typedef enum { - PORT_SINGLE=0, - PORT_PAIR=1, - PORT_S_EVEN=2, - PORT_S_ODD=3, -} port_pair_t; - -typedef enum { - PORT_TYPE_DYNAMIC=0, - PORT_TYPE_STATIC=1, - PORT_TYPE_RTSP=2, -} port_type_t; - - -typedef enum { - PORT_ALLOC_ANY=1, - PORT_ALLOC_DIRECTED=2, -} port_alloc_t; - -#define PORT_PROBE_LIMIT 20 - - -/* - * randq1 - * Linear congruential random number generator with - * extensively studied properties. See Numerical Recipes in C - * 2nd Ed. page 284. Known to behave according to the test vector - * supplied in the text, on X86 and Octeon. - */ -static inline u32 randq1 (u32 prev) -{ - return (1664525L*prev + 1013904223L); -} - -cnat_errno_t -cnat_static_port_alloc_v2( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - port_pair_t pair_type, - u32 i_ipv4_address, - u16 i_port, - u32 *index, - u32 *o_ipv4_address, - u16 *o_port, - u16 static_port_range -#ifndef NO_BULK_LOGGING - , bulk_alloc_size_t bulk_size, - int *nfv9_log_req -#endif /* NO_BULK_LOGGING */ - , u16 ip_n_to_1 - ); - -cnat_errno_t -cnat_mapped_static_port_alloc_v2 ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - u32 *index, - u32 ipv4_address, - u16 port -#ifndef NO_BULK_LOGGING - , int *nfv9_log_req, - bulk_alloc_size_t bulk_size -#endif - , u16 ip_n_to_1 - ); - -cnat_errno_t -cnat_dynamic_port_alloc_v2( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - port_pair_t pair_type, - u32 *index, - u32 *o_ipv4_address, - u16 *o_port, - u16 static_port_range -#ifndef NO_BULK_LOGGING - , bulk_alloc_size_t bulk_size, - int *nfv9_log_req -#endif - , u16 ip_n_to_1, - u32 *rseed_ip - ); - - -cnat_errno_t -cnat_dynamic_port_alloc_rtsp ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - port_pair_t pair_type, - u16 start_range, - u16 end_range, - u32 *index, - u32 *o_ipv4_address, - u16 *o_port -#ifndef NO_BULK_LOGGING - , bulk_alloc_size_t bulk_size, - int *nfv9_log_req -#endif - , u32 *rseed_ip - ); - -void cnat_port_free_v2( - cnat_portmap_v2_t *pm, - int index, - port_pair_t ptype, - u16 base_port, - u16 static_port_range); - -void cnat_portmap_dump_v2(cnat_portmap_v2_t *pm, - u16 print_limit); - - - -cnat_errno_t -nat64_static_port_alloc ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - port_pair_t pair_type, - u32 *i_ipv6_address, - u16 i_port, - u32 *index, - u32 *o_ipv4_address, - u16 *o_port); - - - -#endif /* __CNAT_PORTS_H__ */ diff --git a/plugins/vcgn-plugin/vcgn/cnat_show.c b/plugins/vcgn-plugin/vcgn/cnat_show.c deleted file mode 100644 index 68c52756..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_show.c +++ /dev/null @@ -1,810 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_show.c - translation database definitions - * - * Copyright (c) 2007-2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "cnat_db.h" -#include "cnat_config.h" -#include "cnat_global.h" -#include "cnat_logging.h" -#include "spp_ctx.h" -#include "spp_timers.h" -#include "platform_common.h" -#include "cnat_syslog.h" -#include "cnat_v4_pptp_alg.h" -#include "platform_common.h" - -#ifndef TOBE_PORTED -/* The following variable is in cnat_config_msg_handler.c which - * is to be ported later.. if required - */ -u32 total_address_pool_allocated = 0; -#endif - -#ifndef NO_BULK_LOGGING -#define CNAT_MY_VRFMAP_PRINT \ -PLATFORM_DEBUG_PRINT("i-uidx 0x%x o-uidx 0x%x i-vrfid 0x%x o-vrfid 0x%x\n" \ - "status %d del time 0x%x tcp mss 0x%x pm list 0x%x\n" \ - "bulk size %d\n" \ - "ip n:1 %d\n" \ - "NFV9 template index 0x%x\n" \ - "SYSLOG template index 0x%x\n" \ - "Netflow Session Logging %d \n" \ - "Syslog Session Logging %d \n" \ - "PCP Server 0x%x, Port %u \n", \ - my_vrfmap->i_vrf, my_vrfmap->o_vrf, my_vrfmap->i_vrf_id, \ - my_vrfmap->o_vrf_id, my_vrfmap->status, my_vrfmap->delete_time, \ - my_vrfmap->tcp_mss, my_vrfmap->portmap_list, \ - BULKSIZE_FROM_VRFMAP(my_vrfmap), \ - my_vrfmap->ip_n_to_1, \ - my_vrfmap->nfv9_logging_index, \ - my_vrfmap->syslog_logging_index,\ - my_vrfmap->nf_logging_policy, \ - my_vrfmap->syslog_logging_policy, \ - my_vrfmap->pcp_server_addr, \ - my_vrfmap->pcp_server_port); -#else -#define CNAT_MY_VRFMAP_PRINT \ -PLATFORM_DEBUG_PRINT("i-uidx 0x%x o-uidx 0x%x i-vrfid 0x%x o-vrfid 0x%x\n" \ - "status %d del time 0x%x tcp mss 0x%x pm list 0x%x\n" \ - "NFV9 template index 0x%x\n ip n:1 %d\n", \ - my_vrfmap->i_vrf, my_vrfmap->o_vrf, my_vrfmap->i_vrf_id, \ - my_vrfmap->o_vrf_id, my_vrfmap->status, my_vrfmap->delete_time, \ - my_vrfmap->tcp_mss, my_vrfmap->portmap_list, \ - my_vrfmap->nfv9_logging_index, my_vrfmap->ip_n_to_1); -#endif /* NO_BULK_LOGGING */ - -#define CNAT_MY_LOGGING_INFO_PRINT \ -do { \ - cnat_syslog_logging_info_t *my_syslog_info = 0; \ - PLATFORM_DEBUG_PRINT("SYSLOG config: \n"); \ - pool_foreach (my_syslog_info, cnat_syslog_logging_info_pool, ({ \ - if (my_syslog_info->i_vrf == my_vrfmap->i_vrf) { \ - PLATFORM_DEBUG_PRINT(" \ - ipv4[0x%x], port[%u], hostname[%s]\n", \ - my_syslog_info->ipv4_address, my_syslog_info->port, \ - my_syslog_info->header_hostname); \ - break; \ - } \ - })); \ -}while (0) \ -; - - -void printf_ipv4(u32 ad) -{ - u8 a __attribute__((unused)), b __attribute__((unused)), - c __attribute__((unused)), d __attribute__((unused)); - - a = ad>>24; - b = (ad>>16) & 0xFF; - c = (ad>>8) & 0xFF; - d = (ad>>0) & 0xFF; - - PLATFORM_DEBUG_PRINT("%d.%d.%d.%d", a, b, c, d); -} -void cnat_main_db_entry_dump (cnat_main_db_entry_t *db) -{ - PLATFORM_DEBUG_PRINT("Main DB entry at %p, index %ld dst_ip %x\n", - db, db - cnat_main_db, db->dst_ipv4); - /* only dump hash next index if it's non EMPTY */ - if (db->out2in_hash.next != EMPTY || db->in2out_hash.next != EMPTY) - PLATFORM_DEBUG_PRINT("out2in hash %u, in2out hash %u\n", - db->out2in_hash.next, - db->in2out_hash.next); - PLATFORM_DEBUG_PRINT("out2in key ipv4 0x%08X, port 0x%04X (%5d), vrf %d, protocol %s\n", - db->out2in_key.k.ipv4, - db->out2in_key.k.port, - db->out2in_key.k.port, - db->out2in_key.k.vrf & CNAT_VRF_MASK, - (db->out2in_key.k.vrf & CNAT_PRO_MASK) == CNAT_UDP ? "UDP" : - ((db->in2out_key.k.vrf & CNAT_PRO_MASK) == CNAT_TCP ? "TCP" : - ((db->in2out_key.k.vrf & CNAT_PRO_MASK) == CNAT_ICMP ? "ICMP" : "PPTP ALG"))); - - PLATFORM_DEBUG_PRINT("in2out key ipv4 0x%08X, port 0x%04X (%5d), vrf %d, protocol %s\n", - db->in2out_key.k.ipv4, - db->in2out_key.k.port, - db->in2out_key.k.port, - db->in2out_key.k.vrf & CNAT_VRF_MASK, - (db->in2out_key.k.vrf & CNAT_PRO_MASK) == CNAT_UDP ? "UDP" : - ((db->in2out_key.k.vrf & CNAT_PRO_MASK) == CNAT_TCP ? "TCP" : - ((db->in2out_key.k.vrf & CNAT_PRO_MASK) == CNAT_ICMP ? "ICMP" : "UNKNOWN"))); - - PLATFORM_DEBUG_PRINT("user %d, user ports (nxt) %d (prev) %d, vrfmap_index 0x%x\n", - db->user_index, db->user_ports.next, db->user_ports.prev, - db->vrfmap_index); - PLATFORM_DEBUG_PRINT("timeout %d \n", db->timeout); - PLATFORM_DEBUG_PRINT("flags 0x%x ", db->flags); - - if (db->flags & CNAT_DB_FLAG_TCP_ACTIVE) { - PLATFORM_DEBUG_PRINT(" TCP_ACTIVE "); - } else if (db->flags & CNAT_DB_FLAG_UDP_ACTIVE) { - PLATFORM_DEBUG_PRINT(" UDP_ACTIVE "); - } else if (db->flags & CNAT_DB_FLAG_STATIC_PORT) { - PLATFORM_DEBUG_PRINT(" STATIC_PORT "); - } - - PLATFORM_DEBUG_PRINT(" ALG dlt0 0x%02X dlt1 0x%02X\n", db->alg.alg_dlt[0], db->alg.alg_dlt[1]); - PLATFORM_DEBUG_PRINT("\n"); - - PLATFORM_DEBUG_PRINT("out2in_pkts: %u\n", db->out2in_pkts); - PLATFORM_DEBUG_PRINT("in2out_pkts: %u\n", db->in2out_pkts); - PLATFORM_DEBUG_PRINT("entry_expires: %u current time: %u\n", db->entry_expires, cnat_current_time); - PLATFORM_DEBUG_PRINT("-------------------------\n"); -} - -void cnat_user_db_entry_dump (cnat_user_db_entry_t *up) -{ - u32 db_entry_index, first_db_entry_index; - cnat_main_db_entry_t *ep; - - PLATFORM_DEBUG_PRINT("User DB entry at %p, index %ld\n", - up, up - cnat_user_db); - PLATFORM_DEBUG_PRINT("translation list head index %u, %u translations portmapindex 0x%x\n", - up->translation_list_head_index, - up->ntranslations, up->portmap_index); - PLATFORM_DEBUG_PRINT("source ipv4 0x%x, source port 0x%x, vrf %d\n", - up->key.k.ipv4, - up->key.k.port, - up->key.k.vrf); - first_db_entry_index = db_entry_index = up->translation_list_head_index; - if (first_db_entry_index != EMPTY) { - PLATFORM_DEBUG_PRINT("Port translation list:\n"); - do { - PLATFORM_DEBUG_PRINT(" [%d]\n", db_entry_index); - ep = cnat_main_db + db_entry_index; - db_entry_index = ep->user_ports.next; - } while (first_db_entry_index != db_entry_index); - } else { - PLATFORM_DEBUG_PRINT("WARNING: empty translation list!\n"); - } - PLATFORM_DEBUG_PRINT("-------------------------\n"); -} - -void cnat_user_db_entry_dump_summary (cnat_user_db_entry_t *up) -{ - u32 db_entry_index, first_db_entry_index; - u32 total_entries = 0; - - PLATFORM_DEBUG_PRINT("User DB entry at %p, index %ld\n", - up, up - cnat_user_db); - PLATFORM_DEBUG_PRINT("translation list head index %u, %u translations portmapindex 0x%x\n", - up->translation_list_head_index, - up->ntranslations, up->portmap_index); - PLATFORM_DEBUG_PRINT("source ipv4 0x%x, source port 0x%x, vrf %d\n", - up->key.k.ipv4, - up->key.k.port, - up->key.k.vrf); - first_db_entry_index = db_entry_index = up->translation_list_head_index; - if (first_db_entry_index != EMPTY) { - PLATFORM_DEBUG_PRINT("Port translation list:\n"); - do { - total_entries++; - } while (first_db_entry_index != db_entry_index); - PLATFORM_DEBUG_PRINT("TOTAL_ENTRIES: %d\n", total_entries); - } else { - PLATFORM_DEBUG_PRINT("WARNING: empty translation list!\n"); - } - PLATFORM_DEBUG_PRINT("-------------------------\n"); -} - -/* for internal development and UT only */ -void cnat_db_dump_main_by_index (int argc, unsigned long *argv) -{ - u32 index, i, len; - u32 active_count, scan_count; - - if (argc != 1) { - PLATFORM_DEBUG_PRINT("invalid input %d\n", argc); - return; - } - - index = argv[0]; - - len = vec_len(cnat_main_db); - - active_count = pool_elts(cnat_main_db); - - if (index >= active_count) { - PLATFORM_DEBUG_PRINT("Index %u >= total active entries %u\n", index, active_count); - return; - } - - scan_count = 0; - for (i=0; i< len; i++) { - if(pool_is_free_index(cnat_main_db, i)) continue; - - if (index == scan_count) { - cnat_main_db_entry_dump(cnat_main_db + i); - break; - } - scan_count++; - } -} - -void cnat_db_dump_main (int argc, unsigned long *argv) -{ - cnat_main_db_entry_t *db; - - pool_foreach(db, cnat_main_db, ({ - cnat_main_db_entry_dump(db); - })); -} - -void cnat_db_dump_main_summary (int argc, unsigned long *argv) -{ - cnat_main_db_entry_t *db; - u32 num_entries = 0; - - pool_foreach(db, cnat_main_db, ({ - num_entries++; - })); - - PLATFORM_DEBUG_PRINT("\nNum main entries %d\n", num_entries); -} - -void cnat_db_dump_user (int argc, unsigned long *argv) -{ - cnat_user_db_entry_t *up; - - pool_foreach(up, cnat_user_db, ({ - cnat_user_db_entry_dump(up); - })); -} - -void cnat_db_dump_user_summary (int argc, unsigned long *argv) -{ - cnat_user_db_entry_t *up; - - pool_foreach(up, cnat_user_db, ({ - cnat_user_db_entry_dump_summary(up); - })); -} - -void cnat_db_dump_hashes (int argc, unsigned long *argv) -{ - int i; - - PLATFORM_DEBUG_PRINT("Main DB out2in hash:\n"); - for (i = 0; i < vec_len(cnat_out2in_hash); i++) { - if (cnat_out2in_hash[i].next != EMPTY) { - PLATFORM_DEBUG_PRINT("[%d]: %u\n", i, cnat_out2in_hash[i].next); - } - } - PLATFORM_DEBUG_PRINT("Main DB in2out hash:\n"); - for (i = 0; i < vec_len(cnat_in2out_hash); i++) { - if (cnat_in2out_hash[i].next != EMPTY) { - PLATFORM_DEBUG_PRINT("[%d]: %u\n", i, cnat_in2out_hash[i].next); - } - } - - PLATFORM_DEBUG_PRINT("User hash:\n"); - for (i = 0; i < vec_len(cnat_user_hash); i++) { - if (cnat_user_hash[i].next != EMPTY) { - PLATFORM_DEBUG_PRINT("[%d]: %u\n", i, cnat_user_hash[i].next); - } - } - PLATFORM_DEBUG_PRINT("-------------------------\n"); -} - - -#ifdef OLD_VRFMAP - -void cnat_db_dump_cdb (int argc, unsigned long *argv) -{ - int k; - int verbose=0; - int all = 0; - - if (argc > 0) { - verbose = 1; - } - - if (argc > 1) { - all = 1; - } - - PLATFORM_DEBUG_PRINT ("%d vrfmap vectors \n", vec_len(cnat_portmap_by_vrf)); - - for (k = 0; k < vec_len(cnat_portmap_by_vrf); k++) { - PLATFORM_DEBUG_PRINT("index%d: status %d i_vrf 0x%x o_vrf 0x%x\n", k, - cnat_portmap_by_vrf[k].status, - cnat_portmap_by_vrf[k].i_vrf, - cnat_portmap_by_vrf[k].o_vrf); - cnat_db_dump_address_portmap(verbose, all, - cnat_portmaps[k], - cnat_portmaps_inuse[k]); - } -} - -void cnat_db_dump_i_vrf (int argc, unsigned long *argv) -{ - u32 k; - u32 vrf =0; - int verbose=0; - int all = 0; - - if (!argc) { - PLATFORM_DEBUG_PRINT("need vrf input ,return\n"); - return; - } - - if (argc > 0) { - vrf = argv[0]; - } - - if (argc > 1) { - verbose = 1; - } - - if (argc > 2) { - all = 1; - } - - PLATFORM_DEBUG_PRINT ("%d vrfmap vectors \n", vec_len(cnat_portmap_by_vrf)); - - for (k = 0; k < vec_len(cnat_portmap_by_vrf); k++) { - if (cnat_portmap_by_vrf[k].i_vrf == vrf) { - PLATFORM_DEBUG_PRINT("%d: i_vrf 0x%x o_vrf 0x%x\n", k, - cnat_portmap_by_vrf[k].i_vrf, - cnat_portmap_by_vrf[k].o_vrf); - cnat_db_dump_address_portmap(verbose, all, - cnat_portmaps[k], - cnat_portmaps_inuse[k]); - return; - } - } - PLATFORM_DEBUG_PRINT("not found\n"); -} - -void cnat_db_dump_o_vrf (int argc, unsigned long *argv) -{ - u32 k; - int verbose=0; - int all = 0; - u32 vrf =0; - - if (!argc) { - PLATFORM_DEBUG_PRINT("need vrf input ,return\n"); - return; - } - - if (argc > 0) { - vrf = argv[0]; - } - - if (argc > 1) { - verbose = 1; - } - - if (argc > 2) { - all = 1; - } - - PLATFORM_DEBUG_PRINT ("%d vrfmap vectors \n", vec_len(cnat_portmap_by_vrf)); - - for (k = 0; k < vec_len(cnat_portmap_by_vrf); k++) { - if (cnat_portmap_by_vrf[k].o_vrf == vrf) { - PLATFORM_DEBUG_PRINT("index%d: status %d i_vrf 0x%x o_vrf 0x%x\n", k, - cnat_portmap_by_vrf[k].status, - cnat_portmap_by_vrf[k].i_vrf, - cnat_portmap_by_vrf[k].o_vrf); - cnat_db_dump_address_portmap(verbose, all, - cnat_portmaps[k], - cnat_portmaps_inuse[k]); - return; - } - } - PLATFORM_DEBUG_PRINT("not found\n"); -} -#endif - -#ifdef TOBE_PORTED -/* This does not seem to be used */ -void cnat_db_mem_usage_cmd (int argc, unsigned long *argv) -{ - pool_header_t * p; - _VEC *_v; - u32 bitmap_bytes=0, free_indices_bytes=0, vec_bytes=0, total_bytes=0; - - if (cnat_main_db) { - p = pool_header(cnat_main_db); - if (p->free_bitmap) { - _v = _vec_find(p->free_bitmap); - bitmap_bytes = _v->alen; - } else { - bitmap_bytes = 0; - } - if (p->free_indices) { - _v = _vec_find(p->free_indices); - free_indices_bytes = _v->alen; - } else { - free_indices_bytes = 0; - } - _v = _vec_find(cnat_main_db); - vec_bytes = _v->alen; - } else { - vec_bytes = 0; - } - - total_bytes = bitmap_bytes + free_indices_bytes + vec_bytes; - - PLATFORM_DEBUG_PRINT ("Main DB: %d total bytes, %d bitmap, %d indices, %d vec\n", - total_bytes, bitmap_bytes, free_indices_bytes, vec_bytes); - PLATFORM_DEBUG_PRINT (" vector length %d\n", vec_len(cnat_main_db)); - - if (cnat_user_db) { - p = pool_header(cnat_user_db); - if (p->free_bitmap) { - _v = _vec_find(p->free_bitmap); - bitmap_bytes = _v->alen; - } else { - bitmap_bytes = 0; - } - if (p->free_indices) { - _v = _vec_find(p->free_indices); - free_indices_bytes = _v->alen; - } else { - free_indices_bytes = 0; - } - _v = _vec_find(cnat_user_db); - vec_bytes = _v->alen; - } else { - vec_bytes = 0; - } - - total_bytes = bitmap_bytes + free_indices_bytes + vec_bytes; - - PLATFORM_DEBUG_PRINT ("User DB: %d total bytes, %d bitmap, %d indices, %d vec\n", - total_bytes, bitmap_bytes, free_indices_bytes, vec_bytes); - PLATFORM_DEBUG_PRINT (" vector length %d\n", vec_len(cnat_user_db)); - - _v = _vec_find(cnat_out2in_hash); - PLATFORM_DEBUG_PRINT("out2in hash: %d total bytes\n", _v->alen); - - _v = _vec_find(cnat_in2out_hash); - PLATFORM_DEBUG_PRINT("in2out hash: %d total bytes\n", _v->alen); -} -#endif - -static void print_server_ip_address (vlib_main_t *vm, u32 ip) -{ - unsigned char bytes[4]; - bytes[0] = ip & 0xFF; - bytes[1] = (ip >> 8) & 0xFF; - bytes[2] = (ip >> 16) & 0xFF; - bytes[3] = (ip >> 24) & 0xFF; - vlib_cli_output(vm, "\tIP Address : %d.%d.%d.%d\n", bytes[0], bytes[1], bytes[2], bytes[3]); -} - -void cnat_nfv9_show_collector (vlib_main_t *vm, cnat_nfv9_logging_info_t *my_nfv9_logging_info) -{ - nfv9_server_info_t *server = nfv9_server_info_pool + - my_nfv9_logging_info->server_index; -#if 0 - vlib_cli_output(vm,"\tVRF - 0x%x - %s\n", my_nfv9_logging_info->i_vrf, - my_nfv9_logging_info->deleted?"DELETED":"ACTIVE"); -#endif - print_server_ip_address(vm, clib_net_to_host_u32(server->ipv4_address)); - vlib_cli_output(vm,"\tPort : %d\n", server->port); - vlib_cli_output(vm,"\tTimeout : %d\n", server->timeout_rate); - vlib_cli_output(vm,"\tRefresh Rate : %d\n", server->refresh_rate); - vlib_cli_output(vm,"\tMax Pkt Size : %d\n", my_nfv9_logging_info->max_length_minus_max_record_size); - - return; -} - -void cnat_db_dump_policy (int argc, unsigned long *argv) -{ - - PLATFORM_CNAT_DB_DUMP_POLICY_PRINT(); - - if (cnat_nfv9_global_info.cnat_nfv9_init_done) { - if (cnat_nfv9_global_info.cnat_nfv9_global_collector_index != EMPTY) { - cnat_nfv9_logging_info_t *my_nfv9_logging_info; - nfv9_server_info_t *server __attribute__((unused)); - - my_nfv9_logging_info = cnat_nfv9_logging_info_pool + - cnat_nfv9_global_info.cnat_nfv9_global_collector_index; - server = nfv9_server_info_pool + - my_nfv9_logging_info->server_index; - - PLATFORM_DEBUG_PRINT("NFv9 logging ip 0x%x port 0x%x refresh-rate %d timeout %d\n", - server->ipv4_address, - server->port, - server->refresh_rate, - server->timeout_rate); - PLATFORM_DEBUG_PRINT("NFv9 path_mtu = %d\n", - my_nfv9_logging_info->max_length_minus_max_record_size); - } else { - PLATFORM_DEBUG_PRINT("NFv9 global logging is not configured\n"); - } - } else { - PLATFORM_DEBUG_PRINT("NFv9 LOGGING is not configured\n"); - } - -} - -#ifdef OLD_VRFMAP -void cnat_show_cdb (int verbose) -{ - int k, l, i; - for (i = 0; i < vec_len(cnat_portmap_by_vrf); i++) { - PLATFORM_DEBUG_PRINT("i_vrf %d : o_vrf %d\n", - cnat_portmap_by_vrf[i].i_vrf, - cnat_portmap_by_vrf[i].o_vrf); - } - - PLATFORM_DEBUG_PRINT("port limit %d\n", cnat_main_db_max_ports_per_user); - - PLATFORM_DEBUG_PRINT ("%d portmap vectors\n", vec_len(cnat_portmaps)); - - for (k = 0; k < vec_len(cnat_portmaps); k++) { - cnat_portmap_t *pm; - u16 *inuse; - pm = cnat_portmaps[k]; - inuse = cnat_portmaps_inuse[k]; - for (l = 0; l < vec_len(pm); l++) { - if (inuse[l] || verbose ) { - u32 net_address; - net_address = - spp_host_to_net_byte_order_32((pm+l)->ipv4_address); - printf_ipv4(net_address); - PLATFORM_DEBUG_PRINT (": %d inuse\n", inuse[l]); - if (verbose && inuse[l]) { - cnat_portmap_dump (pm+l, inuse+l); - } - } - } - } -} -#endif - - - -/* v2 show command */ -void cnat_show_address_portmap_sumary (cnat_portmap_v2_t *pm) -{ - cnat_portmap_v2_t *my_pm =0; - u32 first_address = 0; - u32 second_address = 0; - u32 last_address = 0; - u32 i, pm_len; - - if ((pm_len = vec_len(pm))) { - PLATFORM_DEBUG_PRINT("%d portmap in this list 0x%lx\n", - pm_len, (u32)pm); - for (i = 0; i < pm_len; i++) { - my_pm = pm + i; - if (!first_address) { - first_address = my_pm->ipv4_address; - } else if (!second_address) { - second_address = my_pm->ipv4_address; - } - last_address = my_pm->ipv4_address; - } - - if (first_address) { - PLATFORM_DEBUG_PRINT("1. 0x%08x", first_address); - } - if (second_address) { - PLATFORM_DEBUG_PRINT(", 2. 0x%08x", second_address); - } - - if ((last_address != first_address) && - (last_address != second_address)) { - PLATFORM_DEBUG_PRINT(", ....., %d. 0x%08x", pm_len, last_address); - } - PLATFORM_DEBUG_PRINT("\n"); - } else { - PLATFORM_DEBUG_PRINT("ZERO POOL ADDRESSES in this list 0x%x \n", (u32)pm); - } -} - - -void cnat_show_address_portmap (int verbose, int all, - cnat_portmap_v2_t *pm, u16 port_limit) -{ - cnat_portmap_v2_t *my_pm =0; - u32 i, pm_len; - - pm_len = vec_len(pm); - if (!all) { - cnat_show_address_portmap_sumary(pm); - } else { - PLATFORM_DEBUG_PRINT("%d portmap in this list 0x%x \n", pm_len, (u32)pm); - } - - for (i = 0; i < pm_len; i++) { - - my_pm = pm + i; - if (all) { - PLATFORM_DEBUG_PRINT("pm:0x%x ip address:0x%x del_time 0x%x inuse:%d\n", - (u32)my_pm, my_pm->ipv4_address, my_pm->delete_time, my_pm->inuse); - } else if (my_pm->inuse) { - PLATFORM_DEBUG_PRINT("pm:0x%x ip address:0x%x inuse:%d\n", - (u32)my_pm, my_pm->ipv4_address, my_pm->inuse); - } - - if (verbose && (my_pm->inuse)) { - if(PREDICT_FALSE(!port_limit)) { - cnat_portmap_dump_v2 (my_pm, cnat_main_db_max_ports_per_user); - } - else { - cnat_portmap_dump_v2 (my_pm, port_limit); - } - } - } - - PLATFORM_DEBUG_PRINT("\n"); -} - - -void cnat_show_cdb_v2 (int verbose, int all) -{ - cnat_vrfmap_t *my_vrfmap = 0; - cnat_portmap_v2_t *pm =0; - PLATFORM_DEBUG_PRINT("port limit %d\n", cnat_main_db_max_ports_per_user); - PLATFORM_DEBUG_PRINT("total address pool allocated %d\n", total_address_pool_allocated); - PLATFORM_DEBUG_PRINT("icmp rate limit %d (per core %d)\n", - cnat_main_db_icmp_rate_limit, cnat_main_db_icmp_rate_limit_core); - PLATFORM_DEBUG_PRINT("dynamic port range start %d\n", cnat_static_port_range); - if (pptp_cfg.enable == PPTP_DISABLED) { - PLATFORM_DEBUG_PRINT("PPTP alg disabled \n"); - } else { - PLATFORM_DEBUG_PRINT("PPTP alg enabled \n"); - } - - if (ftp_alg_enabled) { - PLATFORM_DEBUG_PRINT("FTP alg enabled\n"); - } else { - PLATFORM_DEBUG_PRINT("FTP alg disabled\n"); - } - - pool_foreach (my_vrfmap, cnat_map_by_vrf, ({ - CNAT_MY_VRFMAP_PRINT - CNAT_MY_LOGGING_INFO_PRINT - PLATFORM_DEBUG_PRINT("per vrf port limit %d\n", my_vrfmap->port_limit); - pm = my_vrfmap->portmap_list; - cnat_show_address_portmap(verbose, all, pm, my_vrfmap->port_limit); - - })); -} - - -void cnat_show_cdb_command_v2(int argc, unsigned long *argv) -{ - int verbose=0; - int all = 0; - - if (argc > 0) { - verbose = 1; - } - - if (argc > 1) { - all = 1; - } - - cnat_show_cdb_v2(verbose, all); -} - -void cnat_show_ivrf_command_v2 (int argc, unsigned long *argv) -{ - u32 vrf =0; - int verbose=0; - int all = 0; - cnat_vrfmap_t *my_vrfmap = 0; - cnat_portmap_v2_t *pm =0; - - if (!argc) { - PLATFORM_DEBUG_PRINT("need vrf input ,return\n"); - return; - } - if (argc > 0) { - vrf = argv[0]; - } - if (argc > 1) { - verbose = 1; - } - if (argc > 2) { - all = 1; - } - PLATFORM_DEBUG_PRINT ("%lld vrfmap vectors \n", pool_elts(cnat_map_by_vrf)); - pool_foreach (my_vrfmap, cnat_map_by_vrf, ({ - if (my_vrfmap->i_vrf == vrf) { - CNAT_MY_VRFMAP_PRINT - pm = my_vrfmap->portmap_list; - cnat_show_address_portmap(verbose, all, pm,my_vrfmap->port_limit); - return; - } - })); - PLATFORM_DEBUG_PRINT("not found\n"); -} - -void cnat_show_ovrf_command_v2 (int argc, unsigned long *argv) -{ - u32 not_found =1; - u32 vrf =0; - int verbose=0; - int all = 0; - cnat_vrfmap_t *my_vrfmap = 0; - cnat_portmap_v2_t *pm =0; - - if (!argc) { - PLATFORM_DEBUG_PRINT("need vrf input ,return\n"); - return; - } - if (argc > 0) { - vrf = argv[0]; - } - if (argc > 1) { - verbose = 1; - } - if (argc > 2) { - all = 1; - } - PLATFORM_DEBUG_PRINT("%d vrfmap vectors \n", pool_elts(cnat_map_by_vrf)); - pool_foreach (my_vrfmap, cnat_map_by_vrf, ({ - if (my_vrfmap->o_vrf == vrf) { - CNAT_MY_VRFMAP_PRINT - pm = my_vrfmap->portmap_list; - cnat_show_address_portmap(verbose, all, pm,my_vrfmap->port_limit); - not_found = 0; - } - })); - if (not_found) { - PLATFORM_DEBUG_PRINT("not found\n"); - } -} - -void cnat_timeout_db_entry_dump (cnat_timeout_db_entry_t *up) -{ - u32 db_entry_index __attribute__((unused)), - first_db_entry_index __attribute__((unused)); - - PLATFORM_DEBUG_PRINT("Timeout DB entry at index %ld\n", up - cnat_timeout_db); - PLATFORM_DEBUG_PRINT("Desnt key 0x%16llx\n", up->t_key.timeout_key.key64); - PLATFORM_DEBUG_PRINT("Timeout value %d\n", up->t_key.timeout_value); - PLATFORM_DEBUG_PRINT("Hash Next 0x%x\n", up->t_hash.next); - -} - -void cnat_db_dump_timeout () -{ - cnat_timeout_db_entry_t *up; - pool_header_t *h; - u32 used __attribute__((unused)), free __attribute__((unused)); - - h = pool_header(cnat_timeout_db); - free = vec_len(h->free_indices); - used = (vec_len(cnat_timeout_db) - free); - - PLATFORM_DEBUG_PRINT("Timeout DB Free %d, Used %d\n",free, used); - - pool_foreach(up, cnat_timeout_db, ({ - cnat_timeout_db_entry_dump(up); - })); -} - diff --git a/plugins/vcgn-plugin/vcgn/cnat_show_api.h b/plugins/vcgn-plugin/vcgn/cnat_show_api.h deleted file mode 100644 index 5904c7e2..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_show_api.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __CNAT_SHOW_API_H__ -#define __CNAT_SHOW_API_H__ - -typedef struct _spp_api_cnat_v4_show_inside_entry_req { - u16 _spp_msg_id; - u16 vrf_id; - u32 ipv4_addr; - u16 start_port; - u16 end_port; - u8 flags; - u8 all_entries; - u8 protocol; -} spp_api_cnat_v4_show_inside_entry_req_t; - -typedef struct _spp_api_cnat_v4_show_outside_entry_req { - u16 _spp_msg_id; - u16 vrf_id; - u32 ipv4_addr; - u16 start_port; - u16 end_port; - u8 flags; - u8 protocol; -} spp_api_cnat_v4_show_outside_entry_req_t; - - -#endif diff --git a/plugins/vcgn-plugin/vcgn/cnat_show_response.h b/plugins/vcgn-plugin/vcgn/cnat_show_response.h deleted file mode 100644 index bec1bd97..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_show_response.h +++ /dev/null @@ -1,580 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_show_response.h show command response structs - * - * Copyright (c) 2007-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef __CNAT_SHOW_RESPONSE_H__ -#define __CNAT_SHOW_RESPONSE_H__ - -/* - * Flags indicating the type of translation entry - */ -#define CNAT_TRANSLATION_ENTRY_ALL 0x0 -#define CNAT_TRANSLATION_ENTRY_STATIC 0x1 -#define CNAT_TRANSLATION_ENTRY_ALG 0x2 -#define CNAT_TRANSLATION_ENTRY_DYNAMIC 0x4 - -/* for PCP support */ -#define CNAT_TRANSLATION_ENTRY_PCPI_DYNAMIC 0x08 -#define CNAT_TRANSLATION_ENTRY_PCPE_DYNAMIC 0x10 - -#define MAX_NODE_NAME_LEN 18 -#define MAX_CTR_NAME_LEN 10 - -/* - * show translation entry response structures - */ -typedef struct { - u16 call_id; - u16 cnat_call_id; /* mapped call Id */ - u16 dst_call_id; /* dest call id */ -} cnat_v4_show_gre_entry; - -typedef struct { - u16 msg_id; - u16 rc; /* o/p parameter. */ - u16 num_entries; /* Number of entries sent as output */ - u16 vrf_id; /* vrf id */ - u32 pns_ip; - cnat_v4_show_gre_entry entries[0]; -} cnat_v4_show_gre_entry_resp; - -/* - * show translation entry response structures - */ -typedef struct { - u32 ipv4_addr; - u16 src_port; - u16 cnat_port; /* port which replaced the src port */ - u8 protocol; - u8 pad; - u16 flags; - u16 nsessions; - u32 in2out_packets; - u32 out2in_packets; -} cnat_v4_show_translation_entry; - -typedef struct { - u16 msg_id; - u8 rc; /* o/p parameter. */ - u8 num_entries; /* Number of entries sent as output */ - u16 vrf_id; /* vrf id */ - u16 pad; - cnat_v4_show_translation_entry entries[0]; -} cnat_v4_show_entry_resp; - -/* - * show free/used ipv4 address/port response structure - */ -typedef struct { - u32 ip_addr; - u32 free_used_ports; -} cnat_v4_show_free_used_entry; - -typedef struct { - u16 msg_id; - u8 rc; - u8 count; - u32 max_ports; - cnat_v4_show_free_used_entry entry_list[0]; -} cnat_v4_show_free_used_entry_resp; - -/* - * Node name to id mapping - */ -typedef struct { - u8 node_id; - u8 pad; - char node_name[MAX_NODE_NAME_LEN]; -} cnat_statistics_node_name; - -typedef struct { - u16 msg_id; - u8 rc; - u8 num_nodes; - cnat_statistics_node_name node_name_array[0]; -} cnat_statistics_node_name_mapping_resp; - -/* - * Counter name to id mapping - */ -typedef struct { - u8 node_id; - u8 counter_id; - char counter_name[MAX_CTR_NAME_LEN]; -} cnat_statistics_counter_name; - -typedef struct { - u16 msg_id; - u8 rc; - u8 num_counters; - cnat_statistics_counter_name counter_name_array[0]; -} cnat_statistics_counter_name_mapping_resp; - - -/* - * Node name to id mapping - */ -typedef struct { - u16 msg_id; - u8 rc; - u8 num_nodes; - u32 pad; - u64 counters [0]; -} cnat_statistics_counter_values; - -/* - * Summary Stats - */ -typedef struct { - u32 eaddr; - u32 ports_used; -} pool_address_usage_t; - -typedef struct { - u16 msg_id; - u8 rc; - u8 pad; - u16 max_pkt_size; - u16 pool_address_copied; - u32 active_translations; - u32 translation_create_rate; - u32 translation_delete_rate; - u32 in2out_forwarding_rate; - u32 out2in_forwarding_rate; - u32 dummy; - u64 in2out_drops_port_limit_exceeded; - u64 in2out_drops_system_limit_reached; - u64 in2out_drops_resource_depletion; - u64 no_translation_entry_drops; - u64 pptp_active_tunnels; - u64 pptp_active_channels; - u64 pptp_ctrlmsg_drops; - u32 no_sessions; - - u32 pool_address_totally_free; - u32 pool_address_used; /* The following array size will be lesser of - (pool_address_used, 200) */ - u32 num_subscribers; - u64 drops_sessiondb_limit_exceeded; - u64 in2out_drops_src_ip_no_config; // for deterministic nat on brahmos - pool_address_usage_t pool_address_usage[0]; -} cnat_show_statistics_summary_resp; - - -typedef struct { - u16 msg_id; - u8 rc; - u8 pad; - u64 o2i_tcp_seq_mismatch_drop; - u64 o2i_tcp_seq_mismatch; - u64 o2i_sessions_created; - u64 o2i_end_point_filter_drop; -} cnat_show_counters_summary_resp; - - -typedef struct { - u16 msg_id; - u8 rc; - u8 pad; - - /* - * XLAT statistics - */ - u64 v6_to_v4_tcp_input_count; - u64 v6_to_v4_tcp_non_translatable_drop_count; - u64 v6_to_v4_tcp_invalid_next_hdr_drop_count; - u64 v6_to_v4_tcp_no_db_drop_count; - u64 v6_to_v4_tcp_output_count; - - u64 v4_to_v6_tcp_input_count; - u64 v4_to_v6_tcp_no_db_drop_count; - u64 v4_to_v6_tcp_output_count; - - u64 v6_to_v4_udp_input_count; - u64 v6_to_v4_udp_non_translatable_drop_count; - u64 v6_to_v4_udp_invalid_next_hdr_drop_count; - u64 v6_to_v4_udp_no_db_drop_count; - u64 v6_to_v4_udp_output_count; - - u64 v4_to_v6_udp_input_count; - u64 v4_to_v6_udp_no_db_drop_count; - u64 v4_to_v6_udp_output_count; - u64 v4_to_v6_udp_frag_crc_zero_drop_count; - u64 v4_to_v6_udp_crc_zero_recycle_sent_count; - u64 v4_to_v6_udp_crc_zero_recycle_drop_count; - - u64 v6_to_v4_icmp_qry_input_count; - u64 v6_to_v4_icmp_no_db_drop_count; - u64 v6_to_v4_icmp_frag_drop_count; - u64 v6_to_v4_icmp_invalid_next_hdr_drop_count; - u64 v6_to_v4_icmp_non_translatable_drop_count; - u64 v6_to_v4_icmp_non_translatable_fwd_count; - u64 v6_to_v4_icmp_unsupported_type_drop_count; - u64 v6_to_v4_icmp_err_output_count; - u64 v6_to_v4_icmp_qry_output_count; - - u64 v4_to_v6_icmp_qry_input_count; - u64 v4_to_v6_icmp_no_db_drop_count; - u64 v4_to_v6_icmp_frag_drop_count; - u64 v4_to_v6_icmp_unsupported_type_drop_count; - u64 v4_to_v6_icmp_err_output_count; - u64 v4_to_v6_icmp_qry_output_count; - - u64 v6_to_v4_subsequent_frag_input_count; - u64 v6_to_v4_subsequent_frag_non_translatable_drop_count; - u64 v6_to_v4_subsequent_frag_invalid_next_hdr_drop_count; - u64 v6_to_v4_subsequent_frag_no_db_drop_count; - u64 v6_to_v4_subsequent_frag_output_count; - - u64 v4_to_v6_subsequent_frag_input_count; - u64 v4_to_v6_subsequent_frag_no_db_drop_count; - u64 v4_to_v6_subsequent_frag_output_count; - - u64 v4_to_v6_subsequent_frag_drop_count; - u64 v4_to_v6_subsequent_frag_throttled_count; - u64 v4_to_v6_subsequent_frag_timeout_drop_count; - u64 v4_to_v6_subsequent_frag_tcp_input_count; - u64 v4_to_v6_subsequent_frag_udp_input_count; - u64 v4_to_v6_subsequent_frag_icmp_input_count; - - u64 v6_to_v4_options_input_count; - u64 v6_to_v4_options_drop_count; - u64 v6_to_v4_options_forward_count; - u64 v6_to_v4_options_no_db_drop_count; - u64 v6_to_v4_unsupp_proto_count; - - u64 v4_to_v6_options_input_count; - u64 v4_to_v6_options_drop_count; - u64 v4_to_v6_options_forward_count; - u64 v4_to_v6_options_no_db_drop_count; - u64 v4_to_v6_unsupp_proto_count; - - u64 v4_icmp_gen_count; - u64 v6_icmp_gen_count; -} xlat_show_statistics_summary_resp; - -typedef struct { - u16 msg_id; - u8 rc; - u8 pad; - /* Total v4 packets to BR */ - u64 v4_to_v6_input_total_count; - /* Total v4 tunneled packets to BR */ - u64 v4_to_v6_41_input_total_count; - /* proto 41 packets without minimum, of 40, v6 payload */ - u64 v4_to_v6_41_insuff_v6payld_count; - /* total proto 41 packets being considered for decap */ - u64 v4_to_v6_41_valid_count; - /* proto 41 packets that failed security check*/ - u64 v4_to_v6_41_sec_check_fail_count; - /* packets with no active db entry */ - u64 v4_to_v6_no_db_drop_count; - /* proto 41 packets actually getting decapped */ - u64 v4_to_v6_41_decap_count; - /* total v4 packets which are neither icmp nor 41 */ - u64 v4_to_v6_unsupported_protocol_count; - /* v4 tunneled packets with invalid v6 source address */ - u64 v4_to_v6_41_invalid_v6_source; - /* total icmpv4 packets destined to BR */ - u64 v4_forus_icmp_input_count; - /* total icmpv4 echo replies by BR */ - u64 v4_icmp_reply_count; - /* total icmpv4 error messages translated to icmpv6 by BR */ - u64 v4_to_v6_icmp_translation_count; - /* total packets with icmpv4 type/code which are not supported by BR */ - u64 v4_icmp_unsupported_count; - /* total icmpv4 packets which are rate-limited by BR */ - u64 v4_icmp_throttled_count; - /* total ICMPv4 error messages which could not be translated */ - u64 v4_icmp_non_translatable_drop_count; - - /* ipv4 defrag stats */ - u64 v4_to_v6_frag_input_count; - u64 v4_to_v6_frag_sec_check_fail_count; - u64 v4_to_v6_frag_reassem_count; - u64 v4_to_v6_frag_timeout_drop_count; - u64 v4_to_v6_frag_icmp_input_count; - u64 v4_to_v6_frag_41_insuff_v6payld_count; - u64 v4_to_v6_frag_no_db_drop_count; - u64 v4_to_v6_frag_unsupported_protocol_count; - u64 v4_to_v6_frag_41_invalid_v6_source; - u64 v4_to_v6_frag_throttled_count; - u64 v4_to_v6_frag_dup_count; - u64 v4_to_v6_frag_reassem_frag_count; - u64 v4_to_v6_frag_disable_count; - u64 v4_to_v6_frag_drop_count; - - /* total v6 packets input to BR */ - u64 v6_to_v4_total_input_count; - /* v6 packets with no active db entry */ - u64 v6_to_v4_no_db_drop_count; - /* forus v6 packets with next header other than icmpv6 */ - u64 v6_to_v4_forus_unsupp_proto_count; - /* total v6 packets that got tunneled */ - u64 v6_to_v4_encap_count; - /* total icmpv6 packets destined to BR */ - u64 v6_forus_icmp_input_count; - /* total icmpv6 echo replies by BR */ - u64 v6_icmp_reply_count; - /* total icmpv6 PTB messages generated by BR */ - u64 v6_ptb_generated_count; - /* total ipv6 packets for which PTBv6 was NOT generated by BR */ - u64 v6_ptb_not_generated_drop_count; - /* total icmpv6 Neighbor Advertisements generated by BR */ - u64 v6_na_generated_count; - /* total icmpv6 TTL expiry messages generated by BR */ - u64 v6_ttl_expiry_generated_count; - /* total ICMPv6 fragments, which are dropped by BR */ - u64 v6_to_v4_frag_icmp_input_count; - /* total packets with icmpv6 type/code which are not supported by BR */ - u64 v6_icmp_unsupported_count; - /* total icmpv6 packets which are rate-limited by BR */ - u64 v6_icmp_throttled_count; -} v6rd_show_statistics_summary_resp; - -typedef struct { - u16 msg_id; - u8 rc; - u8 pad; - - /* Total Incoming Count */ - u64 v4_input_count; - /* Total Drop Count */ - u64 v4_drop_count; - /* Total Output Count */ - u64 v4_to_v6_output_count; - /* TCP Incoming Count */ - u64 v4_tcp_input_count; - /* TCP Output Count */ - u64 v4_tcp_output_count; - /* UDP Incoming Count */ - u64 v4_udp_input_count; - /* UDP Output Count */ - u64 v4_udp_output_count; - /* ICMPv4 Incoming Count */ - u64 v4_icmp_input_count; - /* ICMPv4 Output Count */ - u64 v4_to_v6_icmp_output_count; - /* Invalid UIDB Drop Count */ - u64 v4_invalid_uidb_drop_count; - /* NoDb Drop Count */ - u64 v4_no_db_drop_count; - /* TTL Expire Drop Count */ - u64 v4_ttl_expire_drop_count; - /* Invalid IP Destination Drop Count */ - u64 v4_invalid_destination_prefix_drop_count; - /* Packet Execeeding Path MTU Drop Count */ - u64 v4_path_mtu_exceed_count; - /* Unsupported Protocol Drop Count */ - u64 v4_invalid_proto_type_drop_count; - /* ICMPv4 Generated for TTL Expire Count */ - u64 v4_ttl_expiry_generated_count; - /* ICMPv4 Generated for Error Count */ - u64 v4_icmp_error_gen_count; - /* ICMPv4 Packets Rate-Limited Count */ - u64 v4_icmp_throttled_drop_count; - /* TCP MSS Changed Count */ - u64 v4_tcp_mss_changed_count; - - /* Total Incoming Count */ - u64 v6_input_count; - /* Total Drop Count */ - u64 v6_drop_count; - /* Total Output Count */ - u64 v6_to_v4_output_count; - /* TCP Incoming Count */ - u64 v6_tcp_input_count; - /* TCP Output Count */ - u64 v6_tcp_output_count; - /* UDP Incoming Count */ - u64 v6_udp_input_count; - /* UDP Output Count */ - u64 v6_udp_output_count; - /* ICMPv4 Incoming Count */ - u64 v6_icmpv4_input_count; - /* ICMPv4 Output Count */ - u64 v6_icmpv4_output_count; - /* Invalid UIDB Drop Count */ - u64 v6_invalid_uidb_drop_count; - /* NoDb Drop Count */ - u64 v6_no_db_drop_count; - /* TTL Expire Drop Count */ - u64 v6_ttl_expire_drop_count; - /* Invalid IPv6 Destination Drop Count */ - u64 v6_invalid_destination_drop_count; - /* Invalid Source Prefix Drop Count */ - u64 v6_invalid_source_prefix_drop_count; - /* Unsupported Protocol Drop Count */ - u64 v6_invalid_proto_type_drop_count; - /* ICMPv6 Input Count */ - u64 v6_icmp_input_count; - /* ICMPv6 Invalid UIDB Drop Count */ - u64 v6_icmp_invalid_uidb_drop_count; - /* ICMPv6 NoDb Drop Count */ - u64 v6_icmp_no_db_drop_count; - /* ICMPv6 TTL Expire Drop Count */ - u64 v6_icmp_ttl_expire_drop_count; - /* ICMPv6 Invalid IPv6 Destination Drop Count */ - u64 v6_icmp_invalid_destination_drop_count; - /* ICMPv6 Unsupported Type Drop Count */ - u64 v6_icmp_unsupported_type_drop_count; - /* ICMPv6 Invalid NxtHdr Drop Count*/ - u64 v6_icmp_unsupported_nxthdr_drop_count; - /* ICMPv6 Frag Drop Count */ - u64 v6_icmp_frag_drop_count; - /* ICMPv6 Forus Count */ - u64 v6_forus_icmp_input_count; - /* ICMPv6 Echo Response Received Count */ - u64 v6_received_echo_response_count; - /* ICMPv6 Echo Replies Count */ - u64 v6_echo_reply_count; - /* ICMPv6 Translated to ICMPV4 Output Count*/ - u64 v6_to_v4_icmp_output_count; - /* ICMPv6 Generated for TTL Expire Count */ - u64 v6_ttl_expiry_generated_count; - /* ICMPv6 Generated for Error Count */ - u64 v6_icmp_error_gen_count; - /* ICMPv6 Packets Rate-Limited Count */ - u64 v6_icmp_throttled_drop_count; - /* TCP MSS Changed Count */ - u64 v6_tcp_mss_changed_count; - - /*Total Input Count*/ - u64 v4_to_v6_frag_input_count; - /*Total Drop Count*/ - u64 v4_to_v6_frag_drop_count; - /*Reassembled Output Count*/ - u64 v4_to_v6_frag_reassem_count; - - /*TCP Input Count*/ - u64 v4_to_v6_frag_tcp_input_count; - /*UDP Input Count*/ - u64 v4_to_v6_frag_udp_input_count; - /*ICMPv4 Input Count*/ - u64 v4_to_v6_frag_icmp_input_count; - - /*Invalid UIDB Drop Count */ - u64 v4_to_v6_frag_invalid_uidb_drop_count; - /*NoDb Drop Count*/ - u64 v4_to_v6_frag_no_db_drop_count; - /*Unsupported Protocol Drop Count*/ - u64 v4_to_v6_frag_invalid_proto_type_drop_count; - /*Throttled Count*/ - u64 v4_to_v6_frag_throttled_count; - /*Timeout Drop Count*/ - u64 v4_to_v6_frag_timeout_drop_count; - /*Duplicates Drop Count*/ - u64 v4_to_v6_frag_dup_count; - - /*Total Input Count*/ - u64 v6_to_v4_inner_frag_input_count; - /*Total Drop Count*/ - u64 v6_to_v4_inner_frag_drop_count; - /*Total Output Count*/ - u64 v6_to_v4_inner_frag_output_count; - - /*TCP Input Count*/ - u64 v6_to_v4_inner_frag_tcp_input_count; - /*UDP Input Count*/ - u64 v6_to_v4_inner_frag_udp_input_count; - /*ICMPv4 Input Count*/ - u64 v6_to_v4_inner_frag_icmp_input_count; - - /*Invalid Source Prefix Drop Count*/ - u64 v6_to_v4_inner_frag_invalid_source_prefix_drop_count; - /*Unsupported Protocol Drop Count*/ - u64 v6_to_v4_inner_frag_invalid_proto_type_drop_count; - /*Throttled Count*/ - u64 v6_to_v4_inner_frag_throttled_count; - /*Timeout Drop Count*/ - u64 v6_to_v4_inner_frag_timeout_drop_count; - /*Duplicates Drop Count*/ - u64 v6_to_v4_inner_frag_dup_count; - - /*ICMPv6 Generated for Error Count */ - u64 v6_to_v4_inner_frag_icmp_error_gen_count; - /*ICMPv6 Packets Rate-Limited Count */ - u64 v6_to_v4_inner_frag_icmp_throttled_drop_count; - - /*TCP MSS Changed Count */ - u64 v6_to_v4_inner_frag_tcp_mss_changed_count; - -} mape_show_statistics_summary_resp; - -/* - * The following are the command types for Generic Command cases - */ -#define CNAT_DEBUG_GENERIC_COMMAND_READ_MEM 1 -#define CNAT_DEBUG_GENERIC_COMMAND_WRITE_MEM 2 -#define CNAT_DEBUG_GENERIC_COMMAND_DB_SUMMARY 3 -#define CNAT_DEBUG_GENERIC_COMMAND_USER_DB_PM 4 -#define CNAT_DEBUG_GET_CGN_DB_SUMMARY 5 - -typedef enum { - CNAT_DEBUG_GENERIC_COMMAND_DUMP_POLICY, - CNAT_DEBUG_GENERIC_COMMAND_DUMP_MAIN_DB, - CNAT_DEBUG_GENERIC_COMMAND_DUMP_USER_DB, - CNAT_DEBUG_GENERIC_COMMAND_DUMP_HASHES_DB, - CNAT_DEBUG_GENERIC_COMMAND_DUMP_VRF_MAP, - CNAT_DEBUG_GENERIC_COMMAND_DUMP_SUMMARY_DB, - CNAT_DEBUG_GENERIC_COMMAND_DUMP_STATS, - CNAT_DEBUG_GENERIC_COMMAND_CLEAR_STATS, - CNAT_DEBUG_GENERIC_COMMAND_DUMP_NODE_COUNTER, - CNAT_DEBUG_GENERIC_COMMAND_CLEAR_NODE_COUNTER, - CNAT_DEBUG_GENERIC_COMMAND_DUMP_CNAT_COUNTER, - CNAT_DEBUG_GENERIC_COMMAND_DUMP_VA, - CNAT_DEBUG_GENERIC_COMMAND_SHOW_CONFIG, - CNAT_DEBUG_GENERIC_COMMAND_SHOW_NFV9, - CNAT_DEBUG_GENERIC_COMMAND_SHOW_IVRF, - CNAT_DEBUG_GENERIC_COMMAND_SHOW_OVRF, - CNAT_DEBUG_SPP_LOG, - CNAT_DEBUG_GENERIC_COMMAND_DEBUG_OPTIONS, - CNAT_DEBUG_GENERIC_COMMAND_DUMP_DEBUG_LEVELS, - CNAT_DEBUG_GENERIC_COMMAND_DEBUG_FLAGS, - CNAT_READ_TEMP_SENSORS, - CNAT_BLOCK_OCTEON_SENSOR_READ, - CNAT_DEBUG_GENERIC_COMMAND_DUMP_MAIN_DB_SUMMARY, - CNAT_DEBUG_GENERIC_COMMAND_DUMP_USER_DB_SUMMARY, - CNAT_DEBUG_DUMP_6RD_STATS, - CNAT_DEBUG_TIMEOUT_DB_SUMMARY, - CNAT_NAT64_STFUL_DEBUG_COMMAND, - CNAT_DEBUG_SET_BULK_SIZE, - CNAT_DEBUG_SHOW_BULK_STAT, - CNAT_DEBUG_CLEAR_BULK_STAT, - CNAT_DEBUG_SHOW_BULK_ALLOC, - CNAT_DEBUG_NAT64, - CNAT_DEBUG_NAT44_IN2OUT_FRAG_STATS, -} cnat_debug_dump_type_t; - -typedef enum { - CNAT_DEBUG_FLAG_UDP_INSIDE_CHECKSUM_MODIFY, - CNAT_DEBUG_FLAG_UDP_OUTSIDE_CHECKSUM_MODIFY, - CNAT_DEBUG_FLAG_UDP_INSIDE_PACKET_DUMP, - CNAT_DEBUG_FLAG_UDP_OUTSIDE_PACKET_DUMP, -} cnat_debug_flag_type_t; - -typedef struct { - u16 spp_msg_id; - u8 rc; - u8 core; - u32 num_bytes; - u8 raw_data[0]; -} cnat_generic_command_resp; - -extern u32 db_free_entry (void * p); -#endif /*__CNAT_SHOW_RESPONSE_H__*/ diff --git a/plugins/vcgn-plugin/vcgn/cnat_syslog.c b/plugins/vcgn-plugin/vcgn/cnat_syslog.c deleted file mode 100644 index 91758f14..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_syslog.c +++ /dev/null @@ -1,1787 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_syslog.c - * - * Copyright (c) 2011-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#include -#include "cnat_syslog.h" -#include "platform_common.h" -#include "cnat_db.h" -#include "cnat_log_common.h" -#include - -#define SYSLOG_DELIMITER ' ' -#define SYSLOG_FIELD_ABSENT '-' -/* #define SHOW_SYSLOG_TIMESTAMP 1 TO DO. Remove this later */ -/* - * Defining the below macro here for now. Assumption is, syslog packets - * are sent out via same channel as that of NFV9. - * Has to be overridden if this assumption is false. - */ -#define PLATFORM_SYSLOG_DISP_NODE_IDX PLATFORM_NFV9_DISP_NODE_IDX - -cnat_syslog_global_info_t cnat_syslog_global_info; -cnat_syslog_logging_info_t *cnat_syslog_logging_info_pool; -cnat_syslog_global_counters_t cnat_syslog_global_counter; -extern u32 syslog_debug_flag; - -#define CNAT_SYSLOG_DEBUG_CODE 2 - -#if CNAT_SYSLOG_DEBUG_CODE > 3 -#define SYSLOG_COND if(my_instance_number == 0) - -#define SYSLOG_DEBUG_PRINTF1(a) SYSLOG_COND printf(a); -#define SYSLOG_DEBUG_PRINTF2(a, b) SYSLOG_COND printf(a, b); -#define SYSLOG_DEBUG_PRINTF3(a, b, c) SYSLOG_COND printf(a, b, c); -#define SYSLOG_DEBUG_PRINTF4(a, b, c, d) SYSLOG_COND printf(a, b, c, d); - -#else - -#define SYSLOG_DEBUG_PRINTF1(a) -#define SYSLOG_DEBUG_PRINTF2(a, b) -#define SYSLOG_DEBUG_PRINTF3(a, b, c) -#define SYSLOG_DEBUG_PRINTF4(a, b, c, d) - -#endif - - -void syslog_params_show(u32 logging_index) -{ - cnat_syslog_logging_info_t *log_info __attribute__((unused)); - if(logging_index == EMPTY) { - PLATFORM_DEBUG_PRINT("\nSyslog logging not configured\n"); - return; - } - - log_info = cnat_syslog_logging_info_pool + logging_index; - - PLATFORM_DEBUG_PRINT("\nSyslog parameters --\n"); - PLATFORM_DEBUG_PRINT("IPV4 address: %x, port %d, max log size %d\n", - log_info->ipv4_address, - log_info->port, log_info->max_length_minus_max_record_size); - PLATFORM_DEBUG_PRINT("Host name: %s, priority %d", - log_info->header_hostname, log_info->header_priority); - -} - -/* Util function to copy a number as ASCII in to a buf in a - * faster way (should be faster than sprintf) - */ - -const unsigned char ascii_numbers[][3] = - { {'0', '0', '0'}, - {'1', '0', '0'}, - {'2', '0', '0'}, - {'3', '0', '0'}, - {'4', '0', '0'}, - {'5', '0', '0'}, - {'6', '0', '0'}, - {'7', '0', '0'}, - {'8', '0', '0'}, - {'9', '0', '0'}, - {'1', '0', '0'}, - {'1', '1', '0'}, - {'1', '2', '0'}, - {'1', '3', '0'}, - {'1', '4', '0'}, - {'1', '5', '0'}, - {'1', '6', '0'}, - {'1', '7', '0'}, - {'1', '8', '0'}, - {'1', '9', '0'}, - {'2', '0', '0'}, - {'2', '1', '0'}, - {'2', '2', '0'}, - {'2', '3', '0'}, - {'2', '4', '0'}, - {'2', '5', '0'}, - {'2', '6', '0'}, - {'2', '7', '0'}, - {'2', '8', '0'}, - {'2', '9', '0'}, - {'3', '0', '0'}, - {'3', '1', '0'}, - {'3', '2', '0'}, - {'3', '3', '0'}, - {'3', '4', '0'}, - {'3', '5', '0'}, - {'3', '6', '0'}, - {'3', '7', '0'}, - {'3', '8', '0'}, - {'3', '9', '0'}, - {'4', '0', '0'}, - {'4', '1', '0'}, - {'4', '2', '0'}, - {'4', '3', '0'}, - {'4', '4', '0'}, - {'4', '5', '0'}, - {'4', '6', '0'}, - {'4', '7', '0'}, - {'4', '8', '0'}, - {'4', '9', '0'}, - {'5', '0', '0'}, - {'5', '1', '0'}, - {'5', '2', '0'}, - {'5', '3', '0'}, - {'5', '4', '0'}, - {'5', '5', '0'}, - {'5', '6', '0'}, - {'5', '7', '0'}, - {'5', '8', '0'}, - {'5', '9', '0'}, - {'6', '0', '0'}, - {'6', '1', '0'}, - {'6', '2', '0'}, - {'6', '3', '0'}, - {'6', '4', '0'}, - {'6', '5', '0'}, - {'6', '6', '0'}, - {'6', '7', '0'}, - {'6', '8', '0'}, - {'6', '9', '0'}, - {'7', '0', '0'}, - {'7', '1', '0'}, - {'7', '2', '0'}, - {'7', '3', '0'}, - {'7', '4', '0'}, - {'7', '5', '0'}, - {'7', '6', '0'}, - {'7', '7', '0'}, - {'7', '8', '0'}, - {'7', '9', '0'}, - {'8', '0', '0'}, - {'8', '1', '0'}, - {'8', '2', '0'}, - {'8', '3', '0'}, - {'8', '4', '0'}, - {'8', '5', '0'}, - {'8', '6', '0'}, - {'8', '7', '0'}, - {'8', '8', '0'}, - {'8', '9', '0'}, - {'9', '0', '0'}, - {'9', '1', '0'}, - {'9', '2', '0'}, - {'9', '3', '0'}, - {'9', '4', '0'}, - {'9', '5', '0'}, - {'9', '6', '0'}, - {'9', '7', '0'}, - {'9', '8', '0'}, - {'9', '9', '0'}, - {'1', '0', '0'}, - {'1', '0', '1'}, - {'1', '0', '2'}, - {'1', '0', '3'}, - {'1', '0', '4'}, - {'1', '0', '5'}, - {'1', '0', '6'}, - {'1', '0', '7'}, - {'1', '0', '8'}, - {'1', '0', '9'}, - {'1', '1', '0'}, - {'1', '1', '1'}, - {'1', '1', '2'}, - {'1', '1', '3'}, - {'1', '1', '4'}, - {'1', '1', '5'}, - {'1', '1', '6'}, - {'1', '1', '7'}, - {'1', '1', '8'}, - {'1', '1', '9'}, - {'1', '2', '0'}, - {'1', '2', '1'}, - {'1', '2', '2'}, - {'1', '2', '3'}, - {'1', '2', '4'}, - {'1', '2', '5'}, - {'1', '2', '6'}, - {'1', '2', '7'}, - {'1', '2', '8'}, - {'1', '2', '9'}, - {'1', '3', '0'}, - {'1', '3', '1'}, - {'1', '3', '2'}, - {'1', '3', '3'}, - {'1', '3', '4'}, - {'1', '3', '5'}, - {'1', '3', '6'}, - {'1', '3', '7'}, - {'1', '3', '8'}, - {'1', '3', '9'}, - {'1', '4', '0'}, - {'1', '4', '1'}, - {'1', '4', '2'}, - {'1', '4', '3'}, - {'1', '4', '4'}, - {'1', '4', '5'}, - {'1', '4', '6'}, - {'1', '4', '7'}, - {'1', '4', '8'}, - {'1', '4', '9'}, - {'1', '5', '0'}, - {'1', '5', '1'}, - {'1', '5', '2'}, - {'1', '5', '3'}, - {'1', '5', '4'}, - {'1', '5', '5'}, - {'1', '5', '6'}, - {'1', '5', '7'}, - {'1', '5', '8'}, - {'1', '5', '9'}, - {'1', '6', '0'}, - {'1', '6', '1'}, - {'1', '6', '2'}, - {'1', '6', '3'}, - {'1', '6', '4'}, - {'1', '6', '5'}, - {'1', '6', '6'}, - {'1', '6', '7'}, - {'1', '6', '8'}, - {'1', '6', '9'}, - {'1', '7', '0'}, - {'1', '7', '1'}, - {'1', '7', '2'}, - {'1', '7', '3'}, - {'1', '7', '4'}, - {'1', '7', '5'}, - {'1', '7', '6'}, - {'1', '7', '7'}, - {'1', '7', '8'}, - {'1', '7', '9'}, - {'1', '8', '0'}, - {'1', '8', '1'}, - {'1', '8', '2'}, - {'1', '8', '3'}, - {'1', '8', '4'}, - {'1', '8', '5'}, - {'1', '8', '6'}, - {'1', '8', '7'}, - {'1', '8', '8'}, - {'1', '8', '9'}, - {'1', '9', '0'}, - {'1', '9', '1'}, - {'1', '9', '2'}, - {'1', '9', '3'}, - {'1', '9', '4'}, - {'1', '9', '5'}, - {'1', '9', '6'}, - {'1', '9', '7'}, - {'1', '9', '8'}, - {'1', '9', '9'}, - {'2', '0', '0'}, - {'2', '0', '1'}, - {'2', '0', '2'}, - {'2', '0', '3'}, - {'2', '0', '4'}, - {'2', '0', '5'}, - {'2', '0', '6'}, - {'2', '0', '7'}, - {'2', '0', '8'}, - {'2', '0', '9'}, - {'2', '1', '0'}, - {'2', '1', '1'}, - {'2', '1', '2'}, - {'2', '1', '3'}, - {'2', '1', '4'}, - {'2', '1', '5'}, - {'2', '1', '6'}, - {'2', '1', '7'}, - {'2', '1', '8'}, - {'2', '1', '9'}, - {'2', '2', '0'}, - {'2', '2', '1'}, - {'2', '2', '2'}, - {'2', '2', '3'}, - {'2', '2', '4'}, - {'2', '2', '5'}, - {'2', '2', '6'}, - {'2', '2', '7'}, - {'2', '2', '8'}, - {'2', '2', '9'}, - {'2', '3', '0'}, - {'2', '3', '1'}, - {'2', '3', '2'}, - {'2', '3', '3'}, - {'2', '3', '4'}, - {'2', '3', '5'}, - {'2', '3', '6'}, - {'2', '3', '7'}, - {'2', '3', '8'}, - {'2', '3', '9'}, - {'2', '4', '0'}, - {'2', '4', '1'}, - {'2', '4', '2'}, - {'2', '4', '3'}, - {'2', '4', '4'}, - {'2', '4', '5'}, - {'2', '4', '6'}, - {'2', '4', '7'}, - {'2', '4', '8'}, - {'2', '4', '9'}, - {'2', '5', '0'}, - {'2', '5', '1'}, - {'2', '5', '2'}, - {'2', '5', '3'}, - {'2', '5', '4'}, - {'2', '5', '5'} - }; - -inline static int -byte_to_ascii_decimal_unaligned( - unsigned char *ptr, unsigned char num) -{ - *ptr++ = ascii_numbers[num][0]; - if(PREDICT_FALSE(num < 10)) { - return 1; - } - *ptr++ = ascii_numbers[num][1]; - if(PREDICT_FALSE(num < 100)) { - return 2; - } - *ptr++ = ascii_numbers[num][2]; - return 3; -} - -/* Copies the dotted decimal format of ipv4 - * in to the space provided and - * returns the number of bytes copied - */ -inline static int __attribute__((unused)) -copy_ipv4_addr(unsigned char *ptr, u32 ipv4) -{ - unsigned char *temp = ptr; - temp += byte_to_ascii_decimal_unaligned(temp, (ipv4 >> 24)); - *temp++ = '.'; - temp += byte_to_ascii_decimal_unaligned(temp, ((ipv4 >> 16) & 0xFF)); - *temp++ = '.'; - temp += byte_to_ascii_decimal_unaligned(temp, ((ipv4 >> 8) & 0xFF)); - *temp++ = '.'; - temp += byte_to_ascii_decimal_unaligned(temp, (ipv4 & 0xFF)); - - return (temp - ptr); -} - -#ifdef TOBE_PORTED -/* - * edt: * * cnat_syslog_fill_ip_header - * - * Tries to fill the fields of the IP header before it - * is sent to the L3 infra node. - * - * Argument: cnat_syslog_logging_info_t *logging_info - * structure that contains the packet context - */ -inline -void cnat_syslog_fill_ip_header (cnat_syslog_logging_info_t *logging_info) -{ - spp_ctx_t *ctx; - - /* - * Fill in the IP header and port number of the Netflow collector - * The L3 Infra node will fill in the rest of the fields - */ - ctx = logging_info->current_logging_context; - fill_ip_n_udp_hdr(ctx, logging_info->ipv4_address, - logging_info->port, logging_info->pkt_length); - -} -#else -inline -void cnat_syslog_fill_ip_header (cnat_syslog_logging_info_t *logging_info) -{ - return; -} -#endif - -#ifndef TOBE_PORTED -void cnat_syslog_logging_init() -{ - return; -} - -void cnat_syslog_log_mapping_create(cnat_main_db_entry_t * db, - cnat_vrfmap_t *vrfmap) -{ - return; -} - -void cnat_syslog_log_mapping_delete(cnat_main_db_entry_t * db, - cnat_vrfmap_t *vrfmap) -{ - return; -} - -void cnat_syslog_ds_lite_port_limit_exceeded( - dslite_key_t * key, - dslite_table_entry_t *dslite_entry) -{ - return; -} - -void cnat_syslog_nat44_mapping_create(cnat_main_db_entry_t *db, - cnat_vrfmap_t *vrfmap, cnat_session_entry_t * sdb -#ifndef NO_BULK_LOGGING - , int bulk_alloc -#endif - ) -{ - return; -} - -/* Following are in cnat_util.c which are not ported */ -/* This function is defined in cnat_util.c which need to be ported */ -cnat_icmp_msg_t icmp_msg_gen_allowed () -{ - return 1; -} - -void cnat_syslog_nat44_mapping_delete(cnat_main_db_entry_t *db, - cnat_vrfmap_t *vrfmap, cnat_session_entry_t *sdb -#ifndef NO_BULK_LOGGING - , int bulk_alloc -#endif - ) -{ - return; -} - -u32 -cnat_get_unix_time_in_seconds (void) -{ - return 0; -} -#else /* TOBE_PORTED */ -void -cnat_syslog_dump_logging_context (u32 value1, - cnat_syslog_logging_info_t *logging_info, - u32 value2) -{ - u8 *pkt_ptr; - u32 i; - - if (PREDICT_TRUE(syslog_debug_flag == 0)) { - return; - } - /* - * Reduce the logging to few cores, to enable easier debugging - */ - if ((my_instance_number & 0x7) != 0) { - return; - } - printf("\nDumping %s packet at locn %d: time 0x%x", - (value2 == 1) ? "CURRENT" : "QUEUED", - value1, - cnat_get_unix_time_in_seconds()); - - printf("\ni_vrf 0x%x, ip_address 0x%x, port %d, pkt len %d", - 0 /* TO DP Add vrf like nfv9_logging_info->i_vrf */, - logging_info->ipv4_address, - logging_info->port, - logging_info->pkt_length); - printf("\n"); - - if (value2 == 1) { - pkt_ptr = logging_info->current_logging_context->packet_data; - } else { - pkt_ptr = logging_info->queued_logging_context->packet_data; - } - - /* - * Dump along with 8 bytes of SHIM header - */ - for (i = 0; i < - (logging_info->pkt_length + CNAT_NFV9_IP_HDR_OFFSET); - i = i + 1) { - u8 c1, c2, c3; - - if (i == 0) { - printf("\nL2_HEADER + SHIM_HEADER: \n"); - } else if (i == CNAT_NFV9_IP_HDR_OFFSET) { - printf("\nIP_HEADER: \n"); - } else if (i == CNAT_NFV9_UDP_HDR_OFFSET) { - printf("\nUDP_HEADER: \n"); - } else if (i == CNAT_NFV9_HDR_OFFSET) { - printf("\nSyslog content..\n"); - while(i < - (logging_info->pkt_length + CNAT_NFV9_HDR_OFFSET)) { - printf("%c", (u8)(*(pkt_ptr + i))); - i++; - if((u8)(*(pkt_ptr + i)) == '[') /* new record begins */ - printf("\n"); - } - return; - } - - c3 = *(pkt_ptr + i); - c2 = c3 & 0xf; - c1 = (c3 >> 4) & 0xf; - - printf("%c%c ", - ((c1 <= 9) ? (c1 + '0') : (c1 - 10 + 'a')), - ((c2 <= 9) ? (c2 + '0') : (c2 - 10 + 'a'))); - - } - - printf("\n"); -} - - -/* - * edt: * * cnat_syslog_send_pkt - * - * Tries to send a logging pkt. If the packet cannot be sent - * because of rewrite_output node cannot process it, queue - * it temporarily and try to send it later. - * - * Argument: cnat_syslog_logging_info_t *logging_info - * structure that contains the packet context - */ -inline -void cnat_syslog_send_pkt (cnat_syslog_logging_info_t *logging_info) -{ - spp_node_t *output_node; - - cnat_syslog_fill_ip_header(logging_info); - - output_node = spp_get_nodes() + - cnat_syslog_global_info.cnat_syslog_disp_node_index; - - cnat_syslog_dump_logging_context (2, logging_info, 1); - - if (PREDICT_TRUE(output_node->sf.nused < SPP_MAXDISPATCH)) { - /* - * Move the logging context to output node - */ - logging_info->current_logging_context->current_length = - logging_info->pkt_length; - PLATFORM_SET_CTX_RU_TX_FROM_NODE(logging_info->current_logging_context, \ - NODE_LOGGING); - spp_dispatch_make_node_runnable(output_node); - output_node->sf.ctxs[output_node->sf.nused++] = - logging_info->current_logging_context; - - if(PREDICT_FALSE(syslog_debug_flag > 10)) - printf("\nSyslog: 2. Sending Current packet\n"); - } else { - /* - * Queue the context into the logging_info structure, - * We will try to send it later. Currently, we will - * restrict to only one context queued. - */ - cnat_syslog_global_counter.downstream_constipation_count++; - if(PREDICT_FALSE(syslog_debug_flag > 10)) - printf("\nSyslog: 2. Downstream congestion \n"); - - /* - * Attach the current logging context which is full to the - * queued context list in logging_info structure - */ - logging_info->queued_logging_context = - logging_info->current_logging_context; - } - - /* - * Whether the context is queued or not, set the current context index - * to EMPTY, as the earlier context can no more be used to send - * more logging records. - */ - logging_info->current_logging_context = NULL; -} - - -/* - * edt: * * cnat_syslog_send_queued_pkt - * - * Tries to send a logging pkt that has been queued earlier - * because it could not be sent due to downstream constipation - * - * Argument: cnat_syslog_logging_info_t *logging_info - * structure that contains the packet context - */ -inline -void cnat_syslog_send_queued_pkt (cnat_syslog_logging_info_t *logging_info) -{ - spp_node_t *output_node; - - output_node = spp_get_nodes() + - cnat_syslog_global_info.cnat_syslog_disp_node_index; - - cnat_syslog_dump_logging_context(1, logging_info, 2); - - if(PREDICT_TRUE(output_node->sf.nused < SPP_MAXDISPATCH)) { - /* - * Move the logging context to output node - */ - /** This looks like a bug to me .. need to confirm ***** - logging_info->queued_logging_context->current_length = - nfv9_logging_info->pkt_length; ***/ - PLATFORM_SET_CTX_RU_TX_FROM_NODE(logging_info->queued_logging_context, - NODE_LOGGING) - spp_dispatch_make_node_runnable(output_node); - output_node->sf.ctxs[output_node->sf.nused++] = - logging_info->queued_logging_context; - - SYSLOG_DEBUG_PRINTF1("\nSYSLOG: 1. Sending Queued packet\n") - - /* - * Context has been queued, it will be freed after the pkt - * is sent. Clear this from the logging_context_info structure - */ - logging_info->queued_logging_context = NULL; - - } else { - cnat_syslog_global_counter.downstream_constipation_count++; - } -} - -/* - * edt: * * handle_pending_syslog_pkts - * - * Timer handler for sending any pending syslog record - * - */ -inline -void handle_pending_syslog_pkts() -{ - spp_node_t *output_node; - cnat_syslog_logging_info_t *my_logging_info = 0; - u32 current_timestamp = cnat_get_sys_up_time_in_ms(); - i16 sf_nused; - - output_node = spp_get_nodes() + - cnat_syslog_global_info.cnat_syslog_disp_node_index; - - sf_nused = output_node->sf.nused; - - pool_foreach (my_logging_info, cnat_syslog_logging_info_pool, ({ - /* - * Check if no more logging contexts can be queued - */ - if (PREDICT_FALSE(sf_nused >= SPP_MAXDISPATCH)) { - break; - } - if (my_logging_info->queued_logging_context) - cnat_syslog_send_queued_pkt (my_logging_info); - - if(my_logging_info->current_logging_context && - ((current_timestamp - - my_logging_info->current_logging_context_timestamp) - > 1000)) { - /* - * If there is a current logging context and timestamp - * indicates it is pending for long, send it out - * Also if there is a queued context send it out as well - */ - SYSLOG_DEBUG_PRINTF4("\nLOG_TIMER: queued %p, curr %p, sf_nused %d", - my_logging_info->queued_logging_context, - my_logging_info->current_logging_context, - sf_nused); - cnat_syslog_send_pkt(my_logging_info); - } - })); -} - -const unsigned char hex_numbers_single_digit[] = - { '0', '1', '2', '3', '4', '5', '6', '7', '8', - '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - -inline static int u16_to_ascii_decimal_aligned( - unsigned char *ptr, u16 num, u16 min_digits) -{ - /* The logic below is replicated in - * function u16_to_ascii_decimal_unaligned - * except the use of min_digits - * Replication is done to optimize run time - * if you fix a bug here, check u16_to_ascii_decimal_unaligned - * as well (and vice versa) - */ - unsigned char *temp = ptr; - int no_leading_zeros = 0; - - if(num > 9999 || min_digits == 5) { - *temp++ = hex_numbers_single_digit[num/10000]; - num = num%10000; - no_leading_zeros = 1; - } - - if(no_leading_zeros || num > 999 || min_digits == 4) { - *temp++ = hex_numbers_single_digit[num/1000]; - num = num%1000; - no_leading_zeros = 1; - } - - if(no_leading_zeros || num > 99 || min_digits == 3) { - *temp++ = hex_numbers_single_digit[num/100]; - num = num%100; - no_leading_zeros = 1; - } - - if(no_leading_zeros || num > 9 || min_digits == 2) { - *temp++ = hex_numbers_single_digit[num/10]; - num = num%10; - } - - *temp++ = hex_numbers_single_digit[num]; - - return temp-ptr; -} - -inline static int u16_to_ascii_decimal_unaligned( - unsigned char *ptr, u16 num) -{ - /* - * return u16_to_ascii_decimal_aligned(ptr, num, 0); - * should do the job.. however, to opimize the run time - * the code of u16_to_ascii_decimal_aligned is being - * repeated here without the use of min_digits - * if you fix a bug here, please check - * u16_to_ascii_decimal_aligned as well (and vice versa) - */ - unsigned char *temp = ptr; - int no_leading_zeros = 0; - - if(num > 9999) { - *temp++ = hex_numbers_single_digit[num/10000]; - num = num%10000; - no_leading_zeros = 1; - } - - if(no_leading_zeros || num > 999) { - *temp++ = hex_numbers_single_digit[num/1000]; - num = num%1000; - no_leading_zeros = 1; - } - - if(no_leading_zeros || num > 99) { - *temp++ = hex_numbers_single_digit[num/100]; - num = num%100; - no_leading_zeros = 1; - } - - if(no_leading_zeros || num > 9) { - *temp++ = hex_numbers_single_digit[num/10]; - num = num%10; - } - - *temp++ = hex_numbers_single_digit[num]; - - return temp-ptr; -} - -static int syslog_get_timestamp(unsigned char *ts) -{ - static const char *months[] = {"Jan ", "Feb ", "Mar ", "Apr ", "May ", - "Jun ", "Jul ", "Aug ", "Sep ", "Oct ", "Nov ", "Dec " }; - - unsigned char *temp = ts; - /* Inserts time stamp in the syslog format and returns lenght - * assumes that ts has sufficient space - */ - /* China Telecom has demanded that the time stamp has to be - * in the format '2011 Jun 7 12:34:08' - */ - time_t time = (time_t)cnat_get_unix_time_in_seconds(); - struct tm tm1; - - gmtime_r(&time, &tm1); - /* Now put the pieces together */ - /* Year */ - ts += u16_to_ascii_decimal_unaligned(ts, (tm1.tm_year + 1900)); - *ts++ = SYSLOG_DELIMITER; - /* Month */ - clib_memcpy(ts, months[tm1.tm_mon], 4); - ts += 4; /* DELIMITER taken care */ - /* day */ - ts += u16_to_ascii_decimal_unaligned(ts, tm1.tm_mday); - *ts++ = SYSLOG_DELIMITER; - /* hours */ - ts += u16_to_ascii_decimal_aligned(ts, tm1.tm_hour, 2); - *ts++ = ':'; - /* minutes */ - ts += u16_to_ascii_decimal_aligned(ts, tm1.tm_min, 2); - *ts++ = ':'; - /* seconds */ - ts += u16_to_ascii_decimal_aligned(ts, tm1.tm_sec, 2); - return ts - temp; -} - -/* Ensure that the order of the below array matches with - * syslog_service_type enum - */ -static char *syslog_service_string[] = { "NAT44", "DSLITE" }; - -/* Ensure that the order of below array matches with - * syslog_event_type_t enum - */ -typedef struct { - char *event_name; - int name_length; -} syslog_event_description_type; - -const static syslog_event_description_type sys_log_event[] = { - { "UserbasedA", 10 }, /* yes, 10 is strlen of "UserbasedA" */ - { "UserbasedW", 10 }, - { "SessionbasedA", 13 }, - { "SessionbasedW", 13 }, - { "SessionbasedAD", 14 }, - { "SessionbasedWD", 14 }, - { "Portblockrunout", 15 }, - { "TCPseqmismatch", 14}, - { "Invalid", 7 } -}; - -inline static int syslog_fill_header(const cnat_syslog_logging_info_t *log_info, - syslog_service_type_t s_type) -{ - /* Forms the syslog header and returns the lenght - * Assumes that header has sufficient space - */ - - /* Sample header (as agreed for China Telecom requirements -- - * <134> 1 2011 May 31 10:30:45 192.168.2.3 - - NAT44 - - */ - - unsigned char *temp, *header; - int count; - temp = header = (unsigned char *) - &(log_info->current_logging_context->packet_data[CNAT_NFV9_HDR_OFFSET]); - *temp++ = '<'; - temp += byte_to_ascii_decimal_unaligned(temp, - log_info->header_priority); - *temp++ = '>'; - *temp++ = SYSLOG_DELIMITER; - *temp++ = '1'; /* Syslog version -- always set to 1 */ - *temp++ = SYSLOG_DELIMITER; - temp += syslog_get_timestamp(temp); - *temp++ = SYSLOG_DELIMITER; - count = strlen(log_info->header_hostname); - clib_memcpy(temp, log_info->header_hostname, count); - temp += count; - *temp++ = SYSLOG_DELIMITER; - *temp++ = SYSLOG_FIELD_ABSENT; /* App name - nil value */ - *temp++ = SYSLOG_DELIMITER; - *temp++ = SYSLOG_FIELD_ABSENT; /* Proc ID - nil value for now */ - *temp++ = SYSLOG_DELIMITER; - /* Now the msg id */ - count = strlen(syslog_service_string[s_type]); - clib_memcpy(temp, syslog_service_string[s_type], count); - temp += count; - *temp++ = SYSLOG_DELIMITER; - *temp++ = SYSLOG_FIELD_ABSENT; /* No structured elements */ - *temp++ = SYSLOG_DELIMITER; -#ifdef SHOW_SYSLOG_TIMESTAMP - printf("\nSysLog TS: %s : Length %d", header, temp - header); -#endif /* SHOW_SYSLOG_TIMESTAMP */ - return temp-header; -} - -extern void cnat_logging_init(); - -/* one time call at the beginning */ -void cnat_syslog_logging_init() -{ - if(PREDICT_TRUE(cnat_syslog_global_info.cnat_syslog_init_done)) - return; /* Already done */ - - cnat_logging_init(); - cnat_syslog_global_info.cnat_syslog_disp_node_index = - spp_lookup_node_index(PLATFORM_SYSLOG_DISP_NODE_IDX); - ASSERT(cnat_syslog_global_info.cnat_syslog_disp_node_index != (u16)~0); - - cnat_syslog_global_info.cnat_syslog_init_done = 1; -} - -/* - * edt: * * cnat_syslog_create_logging_context - * - * Tries to create a logging context with packet buffer - * to send a new logging packet - * - * Argument: cnat_syslog_logging_info_t *logging_info - * structure that contains the logging info and will store - * the packet context as well. - */ -inline -void cnat_syslog_create_logging_context ( - cnat_syslog_logging_info_t *logging_info, - syslog_service_type_t s_type) -{ - spp_ctx_t *ctx; - - /* - * If queued_logging_context_index is non-EMPTY, we already have a logging - * packet queued to be sent. First try sending this before allocating - * a new context. We can have only one active packet context per - * logging_info structure - */ - - if (PREDICT_FALSE(logging_info->queued_logging_context != NULL)) { - cnat_syslog_send_queued_pkt(logging_info); - /* - * If we cannot still send the queued pkt, just return - * Downstream Constipation count would have increased anyway - */ - if (logging_info->queued_logging_context != NULL) { - cnat_syslog_global_counter.logging_context_creation_deferred_count++; - return; - } - } - - /* - * If no context can be allocated, return silently - * calling routine will handle updating the error counters - */ - if (spp_ctx_alloc(&ctx, 1) < 1) { - cnat_syslog_global_counter.logging_context_creation_fail_count++; - SYSLOG_DEBUG_PRINTF1("\nCould not allocate ctx for syslog"); - return; - } - - // Allocate packet buffer (used for AVSM currently) - PLATFORM_ALLOC_NFV9_PKT_BUFFER(ctx, 0); - - logging_info->current_logging_context = ctx; - - PLATFORM_SET_CTX_RU_TX_FROM_NODE(ctx, NODE_LOGGING); - - ctx->flags = SPP_CTX_END_OF_PACKET; - ctx->next_ctx_this_packet = (spp_ctx_t*) SPP_CTX_NO_NEXT_CTX; - ctx->current_header = &ctx->packet_data[CNAT_NFV9_HDR_OFFSET]; - - logging_info->pkt_length = syslog_fill_header(logging_info, s_type); - logging_info->pkt_length += (CNAT_NFV9_HDR_OFFSET - - CNAT_NFV9_IP_HDR_OFFSET); - logging_info->current_logging_context_timestamp = - cnat_get_sys_up_time_in_ms(); - -} - -inline static int u16_to_ascii_hex_unaligned( - unsigned char *ptr, u16 num) -{ - unsigned char nibble, *temp; - int no_leading_zeros = 0; - temp = ptr; - nibble = (num >> 12); - if(nibble) { - *temp++ = hex_numbers_single_digit[nibble]; - no_leading_zeros = 1; - } - - nibble = (num >> 8) & 0xF; - if(nibble || no_leading_zeros) { - *temp++ = hex_numbers_single_digit[nibble]; - no_leading_zeros = 1; - } - - nibble = (num >> 4) & 0xF; - if(nibble || no_leading_zeros) { - *temp++ = hex_numbers_single_digit[nibble]; - } - - *temp++ = hex_numbers_single_digit[num & 0xF]; - - return temp-ptr; -} - -inline static int ipv6_int_2_str(u32 ipv6[], unsigned char *ipv6_str) -{ -/* DC stands for Double Colon. - * Refer http://tools.ietf.org/html/rfc5952 for - * more details on text representations of - * IPV6 address - */ -#define DC_NOT_USED_YET 0 -#define DC_IN_USE 1 /* Zeros are skipped */ -#define DC_ALREADY_USED 2 /* Cannot skip zeros anymore */ - int i; - u16 *ipv6_temp = (u16 *)ipv6; - unsigned char *temp = ipv6_str; - int double_colon = DC_NOT_USED_YET; - for(i = 0; i < 7; i++) { - if(ipv6_temp[i]) { - ipv6_str += u16_to_ascii_hex_unaligned(ipv6_str, ipv6_temp[i]); - *ipv6_str++ = ':'; - if(double_colon == DC_IN_USE) { /* Cannot use DC anymore */ - double_colon = DC_ALREADY_USED; - } - } else { - if(double_colon == DC_IN_USE) { - /* Skip this zero as well */ - continue; - } else if((ipv6_temp[i+1]) - /* DC makes sense if there is more than one contiguous zero */ - || (double_colon != DC_NOT_USED_YET)) { - ipv6_str += u16_to_ascii_hex_unaligned(ipv6_str, - ipv6_temp[i]); - *ipv6_str++ = ':'; - } else { /* Start using DC */ - *ipv6_str++ = ':'; /* The 2nd colon */ - double_colon = DC_IN_USE; - } - } - } - if(ipv6_temp[7]) { - ipv6_str += u16_to_ascii_hex_unaligned(ipv6_str, ipv6_temp[7]); - } else if(double_colon != DC_IN_USE) { - *ipv6_str++ = '0'; - } - *ipv6_str = 0; - - return ipv6_str - temp; -} - -/* insert syslog record for nat44 */ - -void cnat_syslog_insert_nat44_record( - cnat_syslog_logging_info_t *log_info, - cnat_main_db_entry_t *db, cnat_vrfmap_t *vrfmap, - cnat_session_entry_t *sdb, int bulk_alloc, syslog_event_type_t e_type) -{ - /* This record should like this - - * [EventName - * < Translated Source IP> - * - * ] - */ - u32 original_source = db->in2out_key.k.ipv4; - u32 translated_ip = db->out2in_key.k.ipv4; - cnat_user_db_entry_t *udb = cnat_user_db + db->user_index; - unsigned char *temp, *record; - u32 network_order_ipv6[4]; - - SYSLOG_CONFIG_DEBUG_PRINTF(4,"In Function %s\n", __func__); - temp = record = &(log_info->current_logging_context->packet_data[ - CNAT_NFV9_IP_HDR_OFFSET + log_info->pkt_length]); - - if (PREDICT_FALSE(!udb)) { - SYSLOG_DEBUG_PRINTF1("\nnull udb!"); - return; - } - - /* Now we point to the location where record needs to be inserted */ - *record++ = '['; /* Open the record */ - - /* Copy the record type */ - clib_memcpy(record, sys_log_event[e_type].event_name, - sys_log_event[e_type].name_length); - record += sys_log_event[e_type].name_length; - *record++ = SYSLOG_DELIMITER; - - /* Copy the Protocol type */ - if(PREDICT_FALSE( - e_type == sessionbased_assign || e_type == sessionbased_withdraw || - e_type == sessionbased_assignD || e_type == sessionbased_withdrawD)) { - u16 my_proto_mask; - my_proto_mask = db->in2out_key.k.vrf & CNAT_PRO_MASK; - if(PREDICT_TRUE(my_proto_mask == CNAT_TCP)) { - *record++ = '6'; - } else if(PREDICT_TRUE(my_proto_mask == CNAT_UDP)) { - *record++ = '1'; - *record++ = '7'; - } else if(PREDICT_TRUE(my_proto_mask == CNAT_ICMP)) { - *record++ = '1'; - } else { /* Default, assume GRE (for PPTP) */ - *record++ = '4'; - *record++ = '7'; - } - } else { - *record++ = SYSLOG_FIELD_ABSENT; - } - *record++ = SYSLOG_DELIMITER; - - /* Copy the Original Source IP */ - record += copy_ipv4_addr(record, original_source); - *record++ = SYSLOG_DELIMITER; - - /* copy configured VRF NAME */ - clib_memcpy(record, log_info->vrf_name, log_info->vrf_name_len); - record += log_info->vrf_name_len; - *record++ = SYSLOG_DELIMITER; - - /* No IPV6 source address for nat44 */ - *record++ = SYSLOG_FIELD_ABSENT; - *record++ = SYSLOG_DELIMITER; - - /* Copy the translated IP address */ - record += copy_ipv4_addr(record, translated_ip); - *record++ = SYSLOG_DELIMITER; - - /* Copy the Original port */ - if(e_type == sessionbased_assign || e_type == sessionbased_withdraw || - e_type == sessionbased_assignD || e_type == sessionbased_withdrawD) { - record += u16_to_ascii_decimal_unaligned( - record, db->in2out_key.k.port); - } else { - *record++ = SYSLOG_FIELD_ABSENT; - } - *record++ = SYSLOG_DELIMITER; - - /* Copy the start outside port */ - record += u16_to_ascii_decimal_unaligned(record, bulk_alloc); - *record++ = SYSLOG_DELIMITER; - - /* Copy the last outside port */ - if(e_type == userbased_assign || e_type == userbased_withdraw) { - record += u16_to_ascii_decimal_unaligned(record, - (bulk_alloc + BULKSIZE_FROM_VRFMAP(vrfmap) - 1)); - } else { - *record++ = SYSLOG_FIELD_ABSENT; - } - *record++ = SYSLOG_DELIMITER; - - /* Copy destination ip and port in case for DBL*/ - if(PREDICT_FALSE(e_type == sessionbased_assignD || e_type == sessionbased_withdrawD)) { - if(PREDICT_TRUE(sdb == NULL)) { - record += copy_ipv4_addr(record,db->dst_ipv4); - *record++ = SYSLOG_DELIMITER; - record += u16_to_ascii_decimal_unaligned(record, db->dst_port); - } else { - record += copy_ipv4_addr(record, sdb->v4_dest_key.k.ipv4); - *record++ = SYSLOG_DELIMITER; - record += u16_to_ascii_decimal_unaligned(record, sdb->v4_dest_key.k.port); - } - } else { - *record++ = '-'; - *record++ = SYSLOG_DELIMITER; - *record++ = '-'; - } - *record++ = SYSLOG_DELIMITER; - - *record++ = ']'; /* End of the reocrd */ - - log_info->pkt_length += record - temp; -} - -void cnat_syslog_insert_record( - cnat_syslog_logging_info_t *log_info, - cnat_main_db_entry_t *db, dslite_table_entry_t *dslite_entry, - cnat_session_entry_t *sdb, int bulk_alloc, syslog_event_type_t e_type) -{ - /* This record should like this - - * [EventName - * < Translated Source IP> - * - * ] - */ - u32 original_source = db->in2out_key.k.ipv4; - u32 translated_ip = db->out2in_key.k.ipv4; - cnat_user_db_entry_t *udb = cnat_user_db + db->user_index; - unsigned char *temp, *record; - u32 network_order_ipv6[4]; - - temp = record = &(log_info->current_logging_context->packet_data[ - CNAT_NFV9_IP_HDR_OFFSET + log_info->pkt_length]); - - if (PREDICT_FALSE(!udb)) { - SYSLOG_DEBUG_PRINTF1("\nnull udb!"); - return; - } - - /* Now we point to the location where record needs to be inserted */ - *record++ = '['; /* Open the record */ - - /* Copy the record type */ - clib_memcpy(record, sys_log_event[e_type].event_name, - sys_log_event[e_type].name_length); - record += sys_log_event[e_type].name_length; - *record++ = SYSLOG_DELIMITER; - - /* Copy the Protocol type */ - if(PREDICT_FALSE( - e_type == sessionbased_assign || e_type == sessionbased_withdraw || - e_type == sessionbased_assignD || e_type == sessionbased_withdrawD)) { - u16 my_proto_mask; - my_proto_mask = db->in2out_key.k.vrf & CNAT_PRO_MASK; - if(PREDICT_TRUE(my_proto_mask == CNAT_TCP)) { - *record++ = '6'; - } else if(PREDICT_TRUE(my_proto_mask == CNAT_UDP)) { - *record++ = '1'; - *record++ = '7'; - } else { - *record++ = '1'; - } - } else { - *record++ = SYSLOG_FIELD_ABSENT; - } - - *record++ = SYSLOG_DELIMITER; - - /* Copy the Original Source IP */ -#ifdef DSLITE_USER_IPV4 - record += copy_ipv4_addr(record, original_source); -#else - /* - * Do not include inside ipv4 address for B4 element level port limiting - */ - *record++ = SYSLOG_FIELD_ABSENT; -#endif - *record++ = SYSLOG_DELIMITER; - - /* copy configured VRF NAME */ - clib_memcpy(record, log_info->vrf_name, log_info->vrf_name_len); - record += log_info->vrf_name_len; - *record++ = SYSLOG_DELIMITER; - - /* Copy the IPV6 source address */ - /* CSCtt16960 Fix. */ - network_order_ipv6[0] = htonl(udb->ipv6[0]); - network_order_ipv6[1] = htonl(udb->ipv6[1]); - network_order_ipv6[2] = htonl(udb->ipv6[2]); - network_order_ipv6[3] = htonl(udb->ipv6[3]); - - inet_ntop(AF_INET6,network_order_ipv6,record,INET6_ADDRSTRLEN); - record += strlen(record); - *record++ = SYSLOG_DELIMITER; - - /* Copy the translated IP address */ - record += copy_ipv4_addr(record, translated_ip); - *record++ = SYSLOG_DELIMITER; - - /* Copy the Original port */ - if(e_type == sessionbased_assign || e_type == sessionbased_withdraw || - e_type == sessionbased_assignD || e_type == sessionbased_withdrawD) { - record += u16_to_ascii_decimal_unaligned( - record, db->in2out_key.k.port); - } else { - *record++ = SYSLOG_FIELD_ABSENT; - } - *record++ = SYSLOG_DELIMITER; - - /* Copy the start outside port */ - record += u16_to_ascii_decimal_unaligned(record, bulk_alloc); - *record++ = SYSLOG_DELIMITER; - - /* Copy the last outside port */ - if(e_type == userbased_assign || e_type == userbased_withdraw) { - record += u16_to_ascii_decimal_unaligned(record, - (bulk_alloc + BULKSIZE_FROM_VRFMAP(dslite_entry) - 1)); - } else { - *record++ = SYSLOG_FIELD_ABSENT; - } - *record++ = SYSLOG_DELIMITER; - - if(PREDICT_FALSE(e_type == sessionbased_assignD || e_type == sessionbased_withdrawD)) { - if(sdb == NULL) { - record += copy_ipv4_addr(record, db->dst_ipv4); - *record++ = SYSLOG_DELIMITER; - record += u16_to_ascii_decimal_unaligned(record, db->dst_port); - } else { - record += copy_ipv4_addr(record, sdb->v4_dest_key.k.ipv4); - *record++ = SYSLOG_DELIMITER; - record += u16_to_ascii_decimal_unaligned(record, sdb->v4_dest_key.k.port); - } - } else { - *record++ = '-'; - *record++ = SYSLOG_DELIMITER; - *record++ = '-'; - } - *record++ = SYSLOG_DELIMITER; - - *record++ = ']'; /* End of the reocrd */ - - log_info->pkt_length += record - temp; -} - -#define SYSLOG_PRECHECK(entry, s_type) \ - if(PREDICT_FALSE((entry)->syslog_logging_index == EMPTY)) { \ - SYSLOG_DEBUG_PRINTF1("\n1. Log Mapping failed") \ - return; \ - } \ - logging_info = \ - cnat_syslog_logging_info_pool + (entry)->syslog_logging_index; \ - if(PREDICT_FALSE(logging_info->current_logging_context == NULL)) { \ - cnat_syslog_create_logging_context(logging_info, s_type); \ - if(PREDICT_FALSE(logging_info->current_logging_context == NULL)) { \ - SYSLOG_DEBUG_PRINTF1("\n2. Log Mapping failed") \ - return; \ - } \ - } - -void cnat_syslog_nat44_mapping_create(cnat_main_db_entry_t *db, - cnat_vrfmap_t *vrfmap, cnat_session_entry_t * sdb -#ifndef NO_BULK_LOGGING - , int bulk_alloc -#endif - ) -{ - cnat_syslog_logging_info_t *logging_info = 0; - syslog_event_type_t e_type; - int start_port; - - SYSLOG_CONFIG_DEBUG_PRINTF(4,"In Function %s\n", __func__); - SYSLOG_PRECHECK(vrfmap, NAT44) - -#ifndef NO_BULK_LOGGING - if(bulk_alloc > 0) { /* new bulk alloc - use bulk add template */ - e_type = userbased_assign; - start_port = bulk_alloc; - } else if(bulk_alloc == CACHE_ALLOC_NO_LOG_REQUIRED) { - return; /* No logging required.. bulk port usage */ - } - else { /* Individual logging .. fall back to old method */ -#endif - if(vrfmap->syslog_logging_policy == SESSION_LOG_ENABLE) { - e_type = sessionbased_assignD; - } else { - e_type = sessionbased_assign; - } - start_port = db->out2in_key.k.port; -#ifndef NO_BULK_LOGGING - } -#endif - - cnat_syslog_insert_nat44_record(logging_info, db, vrfmap, sdb, - start_port, e_type); - - /* - * If we have exceeded the packet length, let us send the - * packet now. There is buffer of additional bytes beyond - * max_pkt_length to ensure that the last add/delete record - * can be stored safely. - */ - - if (PREDICT_FALSE(logging_info->pkt_length > - logging_info->max_length_minus_max_record_size)) { - cnat_syslog_send_pkt(logging_info); - } -} - -void cnat_syslog_ds_lite_mapping_create(cnat_main_db_entry_t *db, - dslite_table_entry_t *dslite_entry, cnat_session_entry_t *sdb -#ifndef NO_BULK_LOGGING - , int bulk_alloc -#endif - ) -{ - cnat_syslog_logging_info_t *logging_info = 0; - syslog_event_type_t e_type; - int start_port; - - SYSLOG_PRECHECK(dslite_entry, DSLite) - -#ifndef NO_BULK_LOGGING - if(bulk_alloc > 0) { /* new bulk alloc - use bulk add template */ - e_type = userbased_assign; - start_port = bulk_alloc; - } else if(bulk_alloc == CACHE_ALLOC_NO_LOG_REQUIRED) { - return; /* No logging required.. bulk port usage */ - } - else { /* Individual logging .. fall back to old method */ -#endif - if(PREDICT_FALSE(dslite_entry->syslog_logging_policy == SESSION_LOG_ENABLE)) { - e_type = sessionbased_assignD; - } else { - e_type = sessionbased_assign; - } - start_port = db->out2in_key.k.port; -#ifndef NO_BULK_LOGGING - } -#endif - - cnat_syslog_insert_record(logging_info, db, dslite_entry, sdb, - start_port, e_type); - - /* - * If we have exceeded the packet length, let us send the - * packet now. There is buffer of additional bytes beyond - * max_pkt_length to ensure that the last add/delete record - * can be stored safely. - */ - - if (PREDICT_FALSE(logging_info->pkt_length > - logging_info->max_length_minus_max_record_size)) { - cnat_syslog_send_pkt(logging_info); - } -} - -void cnat_syslog_nat44_mapping_delete(cnat_main_db_entry_t *db, - cnat_vrfmap_t *vrfmap, cnat_session_entry_t *sdb -#ifndef NO_BULK_LOGGING - , int bulk_alloc -#endif - ) -{ - cnat_syslog_logging_info_t *logging_info = 0; - syslog_event_type_t e_type; - int start_port; - - SYSLOG_CONFIG_DEBUG_PRINTF(4,"In Function %s\n", __func__); - SYSLOG_PRECHECK(vrfmap, NAT44) - -#ifndef NO_BULK_LOGGING - if(bulk_alloc > 0) { /* new bulk alloc - use bulk add template */ - e_type = userbased_withdraw; - start_port = bulk_alloc; - } else if(bulk_alloc == CACHE_ALLOC_NO_LOG_REQUIRED) { - return; /* No logging required.. bulk port usage */ - } - else { /* Individual logging .. fall back to old method */ -#endif - if(vrfmap->syslog_logging_policy == SESSION_LOG_ENABLE) { - e_type = sessionbased_withdrawD; - } else { - e_type = sessionbased_withdraw; - } - start_port = db->out2in_key.k.port; -#ifndef NO_BULK_LOGGING - } -#endif - cnat_syslog_insert_nat44_record(logging_info, db, vrfmap, sdb, - start_port, e_type); - /* - * If we have exceeded the packet length, let us send the - * packet now. There is buffer of additional bytes beyond - * max_pkt_length to ensure that the last add/delete record - * can be stored safely. - */ - if (PREDICT_FALSE(logging_info->pkt_length > - logging_info->max_length_minus_max_record_size)) { - cnat_syslog_send_pkt(logging_info); - } -} - -void cnat_syslog_ds_lite_mapping_delete(cnat_main_db_entry_t *db, - dslite_table_entry_t *dslite_entry, cnat_session_entry_t *sdb -#ifndef NO_BULK_LOGGING - , int bulk_alloc -#endif - ) -{ - cnat_syslog_logging_info_t *logging_info = 0; - syslog_event_type_t e_type; - int start_port; - - SYSLOG_PRECHECK(dslite_entry, DSLite) - -#ifndef NO_BULK_LOGGING - if(bulk_alloc > 0) { /* new bulk alloc - use bulk add template */ - e_type = userbased_withdraw; - start_port = bulk_alloc; - } else if(bulk_alloc == CACHE_ALLOC_NO_LOG_REQUIRED) { - return; /* No logging required.. bulk port usage */ - } - else { /* Individual logging .. fall back to old method */ -#endif - if(PREDICT_FALSE(dslite_entry->syslog_logging_policy == SESSION_LOG_ENABLE)) { - e_type = sessionbased_withdrawD; - } else { - e_type = sessionbased_withdraw; - } - start_port = db->out2in_key.k.port; -#ifndef NO_BULK_LOGGING - } -#endif - cnat_syslog_insert_record(logging_info, db, dslite_entry, sdb, - start_port, e_type); - - /* - * If we have exceeded the packet length, let us send the - * packet now. There is buffer of additional bytes beyond - * max_pkt_length to ensure that the last add/delete record - * can be stored safely. - */ - - if (PREDICT_FALSE(logging_info->pkt_length > - logging_info->max_length_minus_max_record_size)) { - cnat_syslog_send_pkt(logging_info); - } -} - -void cnat_syslog_dslite_insert_port_exceeded( - cnat_syslog_logging_info_t *log_info, - dslite_key_t * key) -{ - /* This record should like this - - * [Portblockrunout - * - - - - -] - */ - u32 network_order_ipv6[4]; - unsigned char *temp, *record; - - temp = record = &(log_info->current_logging_context->packet_data[ - CNAT_NFV9_IP_HDR_OFFSET + log_info->pkt_length]); - - /* Now we point to the location where record needs to be inserted */ - *record++ = '['; /* Open the record */ - - /* Copy the record type */ - clib_memcpy(record, sys_log_event[port_block_runout].event_name, - sys_log_event[port_block_runout].name_length); - record += sys_log_event[port_block_runout].name_length; - *record++ = SYSLOG_DELIMITER; - - u16 my_proto_mask; - my_proto_mask = key->ipv4_key.k.vrf & CNAT_PRO_MASK; - if(PREDICT_TRUE(my_proto_mask == CNAT_TCP)) { - *record++ = '6'; - } else if(PREDICT_TRUE(my_proto_mask == CNAT_UDP)) { - *record++ = '1'; - *record++ = '7'; - } else { - *record++ = '1'; - } - *record++ = SYSLOG_DELIMITER; - - /* Copy the Original Source IP */ - record += copy_ipv4_addr(record, key->ipv4_key.k.ipv4); - *record++ = SYSLOG_DELIMITER; - - /* copy configured VRF NAME */ - clib_memcpy(record, log_info->vrf_name, log_info->vrf_name_len); - record += log_info->vrf_name_len; - *record++ = SYSLOG_DELIMITER; - - /* Copy the IPV6 source address */ - network_order_ipv6[0] = htonl(key->ipv6[0]); - network_order_ipv6[1] = htonl(key->ipv6[1]); - network_order_ipv6[2] = htonl(key->ipv6[2]); - network_order_ipv6[3] = htonl(key->ipv6[3]); - - inet_ntop(AF_INET6,network_order_ipv6,record,INET6_ADDRSTRLEN); - record += strlen(record); - *record++ = SYSLOG_DELIMITER; - - *record++ = SYSLOG_FIELD_ABSENT; /* No translated source ip */ - *record++ = SYSLOG_DELIMITER; - - record += u16_to_ascii_decimal_unaligned( - record, key->ipv4_key.k.port); - *record++ = SYSLOG_DELIMITER; - - *record++ = SYSLOG_FIELD_ABSENT; /* No translated start port */ - *record++ = SYSLOG_DELIMITER; - - *record++ = SYSLOG_FIELD_ABSENT; /* No translated end port */ - *record++ = SYSLOG_DELIMITER; - - /*No Destination Info*/ - *record++ = '-'; - *record++ = SYSLOG_DELIMITER; - *record++ = '-'; - *record++ = SYSLOG_DELIMITER; - - *record++ = ']'; /* End of the reocrd */ - - log_info->pkt_length += record - temp; -} - -void cnat_syslog_ds_lite_port_limit_exceeded( - dslite_key_t * key, - dslite_table_entry_t *dslite_entry) -{ - cnat_syslog_logging_info_t *logging_info = 0; - - SYSLOG_PRECHECK(dslite_entry, DSLite) - - cnat_syslog_dslite_insert_port_exceeded(logging_info, key); - - /* - * If we have exceeded the packet length, let us send the - * packet now. There is buffer of additional bytes beyond - * max_pkt_length to ensure that the last add/delete record - * can be stored safely. - */ - - if (PREDICT_FALSE(logging_info->pkt_length > - logging_info->max_length_minus_max_record_size)) { - cnat_syslog_send_pkt(logging_info); - } -} - -void cnat_syslog_nat44_insert_port_exceeded( - cnat_syslog_logging_info_t *log_info, - cnat_key_t * key) -{ - /* This record should like this - - * [Portblockrunout - * - - - - - -] - */ - unsigned char *temp, *record; - - temp = record = &(log_info->current_logging_context->packet_data[ - CNAT_NFV9_IP_HDR_OFFSET + log_info->pkt_length]); - - /* Now we point to the location where record needs to be inserted */ - *record++ = '['; /* Open the record */ - - /* Copy the record type */ - clib_memcpy(record, sys_log_event[port_block_runout].event_name, - sys_log_event[port_block_runout].name_length); - record += sys_log_event[port_block_runout].name_length; - *record++ = SYSLOG_DELIMITER; - - u16 my_proto_mask; - my_proto_mask = key->k.vrf & CNAT_PRO_MASK; - if(PREDICT_TRUE(my_proto_mask == CNAT_TCP)) { - *record++ = '6'; - } else if(PREDICT_TRUE(my_proto_mask == CNAT_UDP)) { - *record++ = '1'; - *record++ = '7'; - } else { - *record++ = '1'; - } - *record++ = SYSLOG_DELIMITER; - - /* Copy the Original Source IP */ - record += copy_ipv4_addr(record, key->k.ipv4); - *record++ = SYSLOG_DELIMITER; - - /* copy configured VRF NAME */ - clib_memcpy(record, log_info->vrf_name, log_info->vrf_name_len); - record += log_info->vrf_name_len; - *record++ = SYSLOG_DELIMITER; - - /* No IPV6 source address for nat44 */ - *record++ = '-'; - *record++ = SYSLOG_DELIMITER; - - *record++ = '-'; /* No translated source ip */ - *record++ = SYSLOG_DELIMITER; - - record += u16_to_ascii_decimal_unaligned( - record, key->k.port); - *record++ = SYSLOG_DELIMITER; - - *record++ = '-'; /* No translated start port */ - *record++ = SYSLOG_DELIMITER; - - *record++ = '-'; /* No translated end port */ - *record++ = SYSLOG_DELIMITER; - - /*No Destination Info*/ - *record++ = '-'; - *record++ = SYSLOG_DELIMITER; - *record++ = '-'; - *record++ = SYSLOG_DELIMITER; - - *record++ = ']'; /* End of the reocrd */ - - log_info->pkt_length += record - temp; -} - -void cnat_syslog_nat44_port_limit_exceeded( - cnat_key_t * key, - cnat_vrfmap_t *vrfmap) -{ - cnat_syslog_logging_info_t *logging_info = 0; - - SYSLOG_PRECHECK(vrfmap, NAT44) - - cnat_syslog_nat44_insert_port_exceeded(logging_info, key); - - /* - * If we have exceeded the packet length, let us send the - * packet now. There is buffer of additional bytes beyond - * max_pkt_length to ensure that the last add/delete record - * can be stored safely. - */ - - if (PREDICT_FALSE(logging_info->pkt_length > - logging_info->max_length_minus_max_record_size)) { - cnat_syslog_send_pkt(logging_info); - } -} - -void cnat_syslog_nat44_insert_tcp_seq_mismatch( - cnat_syslog_logging_info_t *log_info, - cnat_main_db_entry_t *db) -{ - /* This record should like this - - * [TCPseqmismatch - * - - - -] - */ - unsigned char *temp, *record; - - temp = record = &(log_info->current_logging_context->packet_data[ - CNAT_NFV9_IP_HDR_OFFSET + log_info->pkt_length]); - - /* Now we point to the location where record needs to be inserted */ - *record++ = '['; /* Open the record */ - - /* Copy the record type */ - clib_memcpy(record, sys_log_event[tcp_seq_mismatch].event_name, - sys_log_event[tcp_seq_mismatch].name_length); - record += sys_log_event[tcp_seq_mismatch].name_length; - *record++ = SYSLOG_DELIMITER; - - /* Next field is TCP */ - *record++ = '6'; - *record++ = SYSLOG_DELIMITER; - - /* Copy the Original Source IP */ - record += copy_ipv4_addr(record, db->in2out_key.k.ipv4); - *record++ = SYSLOG_DELIMITER; - - /* copy configured VRF NAME */ - clib_memcpy(record, log_info->vrf_name, log_info->vrf_name_len); - record += log_info->vrf_name_len; - *record++ = SYSLOG_DELIMITER; - - /* No IPV6 source address for nat44 */ - *record++ = '-'; - *record++ = SYSLOG_DELIMITER; - - record += copy_ipv4_addr(record, db->out2in_key.k.ipv4); - *record++ = SYSLOG_DELIMITER; - - record += u16_to_ascii_decimal_unaligned( - record, db->in2out_key.k.port); - *record++ = SYSLOG_DELIMITER; - - record += u16_to_ascii_decimal_unaligned( - record, db->out2in_key.k.port); - *record++ = SYSLOG_DELIMITER; - - *record++ = '-'; /* No translated end port */ - *record++ = SYSLOG_DELIMITER; - - /*No Destination Info*/ - *record++ = '-'; - *record++ = SYSLOG_DELIMITER; - *record++ = '-'; - *record++ = SYSLOG_DELIMITER; - - *record++ = ']'; /* End of the reocrd */ - - log_info->pkt_length += record - temp; -} - -void cnat_syslog_nat44_tcp_seq_mismatch( - cnat_main_db_entry_t *db, - cnat_vrfmap_t *vrfmap) -{ - cnat_syslog_logging_info_t *logging_info = 0; - - SYSLOG_PRECHECK(vrfmap, NAT44) - - cnat_syslog_nat44_insert_tcp_seq_mismatch(logging_info, db); - - /* - * If we have exceeded the packet length, let us send the - * packet now. There is buffer of additional bytes beyond - * max_pkt_length to ensure that the last add/delete record - * can be stored safely. - */ - - if (PREDICT_FALSE(logging_info->pkt_length > - logging_info->max_length_minus_max_record_size)) { - cnat_syslog_send_pkt(logging_info); - } -} -#endif diff --git a/plugins/vcgn-plugin/vcgn/cnat_syslog.h b/plugins/vcgn-plugin/vcgn/cnat_syslog.h deleted file mode 100644 index 931f4b9c..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_syslog.h +++ /dev/null @@ -1,190 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_syslog.h - * - * Copyright (c) 2011-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef __CNAT_SYSLOG_H__ -#define __CNAT_SYSLOG_H__ - -#include -#include -#include -#include - -#include "cnat_db.h" -#include "nat64_db.h" -#include "cnat_log_common.h" -#include "dslite_defs.h" - -#define SYSLOG_CONFIG_DEBUG_PRINTF(level, ...) \ - if (config_debug_level > level) PLATFORM_DEBUG_PRINT(__VA_ARGS__); - - -/* one time call at the beginning */ -void cnat_syslog_logging_init(); - -/* - * unconditional call - * will check logging config inside - */ -void cnat_syslog_log_mapping_create(cnat_main_db_entry_t * db, - cnat_vrfmap_t *vrfmap); - -/* - * unconditional call - * will check logging config inside - */ -void cnat_syslog_log_mapping_delete(cnat_main_db_entry_t * db, - cnat_vrfmap_t *vrfmap); - -void cnat_syslog_ds_lite_mapping_create(cnat_main_db_entry_t *db, - dslite_table_entry_t *dslite_entry, cnat_session_entry_t *sdb -#ifndef NO_BULK_LOGGING - , int bulk_alloc -#endif - ); - -void cnat_syslog_ds_lite_port_limit_exceeded( - dslite_key_t * key, - dslite_table_entry_t *dslite_entry); - -#define SYSLOG_TIMESTAMP_LENGTH 20 - -#define CNAT_SYSLOG_VERSION_NUMBER 1 -#define CNAT_SYSLOG_PRIORITY 16*8+6 -/* facility = local0 + severity = info */ - -#define MAX_SYSLOG_HOSTNAME_LEN 32 - -/* 6 for priority + space - * 2 for version + space - * 21 YYYY MMM DD HH:MM:SS + space - * 33 for hostname + space - * 4 for App Name (-) + space + Proc ID (-) + space - * 7 for Msg ID (DSLite is the longest Msg ID so far + space - * 2 for Structured data (-) + space - */ -#define MAX_SYSLOG_HEADER_LEN 75 - -/* 18 for Event Name (Portblockrunout is the longest as of now) - * 3 for L4 (including space) - * 16 for original souce IP + space - * 33 for inside vrf name + space - * 40 for original source IPV6 + space - * 16 for translated source IP + space - * 6 for original port + space - * 6 for translated first source port + space - * 5 for translated last source port - * 2 for [] enclosure - */ -#define MAX_SYSLOG_RECORD_LEN 145 - -typedef enum { - NAT44, - DSLite -} syslog_service_type_t; - -typedef enum { - userbased_assign, - userbased_withdraw, - sessionbased_assign, - sessionbased_withdraw, - sessionbased_assignD, - sessionbased_withdrawD, - port_block_runout, - tcp_seq_mismatch, - max_syslog_event_type -} syslog_event_type_t; - -/* - * This structure store the Syslog Logging information on per - * collector basis. This structure is allocated from a pool and index - * to this structure is stored VRF MAP structures - */ -typedef struct { - /* - * nat64_id will be 0 for nat44 config and i_vrf_id, i_vrf will be 0 - * for nat64 config. Nat64_id will be used while nat64 collector is - * search and i_vrf* for nat44 collector - */ - /* Similarly for ds_lite, ds_lite_id will be used and nat64_id, - * ivrf_id shall be set to 0 - */ - u32 i_vrf_id; /* Inside VRF ID corresponding to this collector */ - u16 i_vrf; /* Inside VRF (uidb_index) corresponding to this collector */ - u16 ds_lite_id; /* DS Lite instance for this collector */ - u16 port; /* Destination port number of the collector */ - - /* - * This field determines the maximum size of the Syslog information - * that can be stored in a logging packet - */ - u16 max_length_minus_max_record_size; - u32 ipv4_address; /* Destination IP address of the collector */ - /* - * Timestamp in UNIX seconds corresponding to when the current - * logging packet was created - */ - u32 current_logging_context_timestamp; - - /* - * Indicates if the entry is already deleted - */ - u8 deleted; - - u8 header_priority; - u16 pkt_length; - - char header_hostname[MAX_SYSLOG_HOSTNAME_LEN]; - char vrf_name[VRF_NAME_LEN_STORED]; - u16 vrf_name_len; - u8 logging_policy; - /* - * current logging context - */ - spp_ctx_t *current_logging_context; - spp_ctx_t *queued_logging_context; - -} cnat_syslog_logging_info_t; - - -/* - * Global structure for CGN APP configuration - */ -typedef struct { - - u16 cnat_syslog_disp_node_index; - - /* - * Whether we have initialized the Syslog information - */ - u8 cnat_syslog_init_done; - -} cnat_syslog_global_info_t; - -typedef struct { - u64 logging_context_creation_fail_count; - u64 downstream_constipation_count; - u64 logging_context_creation_deferred_count; -} cnat_syslog_global_counters_t; - -extern cnat_syslog_logging_info_t *cnat_syslog_logging_info_pool; -extern cnat_syslog_global_info_t cnat_syslog_global_info; - -#define SYSLOG_DEF_PATH_MTU 1500 - -#endif /* __CNAT_SYSLOG_H__ */ diff --git a/plugins/vcgn-plugin/vcgn/cnat_util.c b/plugins/vcgn-plugin/vcgn/cnat_util.c deleted file mode 100644 index c3697b6b..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_util.c +++ /dev/null @@ -1,2256 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_util.c - cnat helpers - * - * Copyright (c) 2009-2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tcp_header_definitions.h" - -#if 0 -void spp_api_cnat_v4_config_dummy_t_handler -(spp_api_cnat_v4_config_dummy_t *mp); - -void spp_api_cnat_v4_config_dummy_max_t_handler -(spp_api_cnat_v4_config_dummy_max_t *mp); - -void spp_api_cnat_v4_config_icmp_timeout_t_handler -(spp_api_cnat_v4_config_icmp_timeout_t *mp); - -void spp_api_cnat_clear_db_request_t_handler -(spp_api_cnat_clear_db_request_t *mp); - -void spp_api_cnat_v4_debug_global_t_handler -(spp_api_cnat_v4_debug_global_t *mp); - -void spp_api_cnat_v4_show_outside_entry_req_t_handler -(spp_api_cnat_v4_show_outside_entry_req_t *mp); - -void spp_api_cnat_v4_show_inside_entry_req_t_handler -(spp_api_cnat_v4_show_inside_entry_req_t *mp); - -void spp_api_cnat_show_statistics_summary_req_t_handler -(spp_api_cnat_show_statistics_summary_req_t *mp); - -void cnat_db_create_db_entries_cmd (int argc, unsigned long *argv) -{ - int i, j ; - int nusers = 3000; - - cnat_db_key_bucket_t key_info; - cnat_main_db_entry_t *db; - cnat_gen_icmp_info info; - cnat_key_t dest_info_dummy; - - memset(&dest_info_dummy, 0, sizeof(cnat_key_t)); - printf ("Create %d users, 100 translations each...\n", nusers); - - for (i = 0; i < nusers; i++) { - for (j = 0; j < 100; j++) { - - key_info.k.k.vrf = CNAT_TCP | (1 & CNAT_VRF_MASK); - key_info.k.k.ipv4 = 0x0c000001+i; - key_info.k.k.port = 1024+j; - - db = cnat_get_main_db_entry_v2(&key_info, PORT_SINGLE, - PORT_TYPE_DYNAMIC, &info, &dest_info_dummy); - - if (db == 0) { - printf ("OOPS: cnat_main_db_create failed users %d trans %d\n", i, j); - return; /*jli*/ - } - - db->entry_expires = cnat_current_time; - - } - } -} - -void db_test_clear (int argc, unsigned long *argv) -{ - spp_api_cnat_clear_db_request_t mp; - - mp.wildcard = argv[0]; - mp.protocol = argv[1]; - mp.port_num = argv[2]; - mp.inside_vrf = argv[3]; - mp.ip_addr = argv[4]; - spp_api_cnat_clear_db_request_t_handler(&mp); -} - -/* test code*/ -void cnat_db_test_show (int argc, unsigned long *argv) -{ - - spp_api_cnat_v4_show_inside_entry_req_t mp1[2000]; - spp_api_cnat_v4_show_outside_entry_req_t mp2[30000]; - - if (argc > 1) { - if (argc != 7) { - printf("Usage: db test show dec((which)) dec((vrf)) dec((proto)) dec((ip)) dec((start_port)) dec((end_port)) dec((flags))\n"); - return; - } - - mp1[0].vrf_id = argv[1]; - mp1[0].protocol = argv[2];; - mp1[0].ipv4_addr = argv[3]; - mp1[0].start_port = argv[4]; - mp1[0].end_port = argv[5]; - mp1[0].flags = argv[6]; - mp1[0].all_entries = 0; - - if (argv[0] == 1) { - spp_api_cnat_v4_show_inside_entry_req_t_handler (&(mp1[0])); - } else { - spp_api_cnat_v4_show_outside_entry_req_t_handler (&(mp2[0])); - } - - return; - } else { - printf("inside entries \n"); - mp1[0].ipv4_addr = 0x016994CA; - mp1[0].vrf_id = 1; - mp1[0].all_entries = 0; - mp1[0].start_port = 32765; - mp1[0].end_port = 65535; - mp1[0].protocol = 2; - mp1[0].flags = 3; - - spp_api_cnat_v4_show_inside_entry_req_t_handler (&(mp1[0])); - - mp2[0].ipv4_addr = 0x640200c1; - mp2[0].vrf_id = 0; - mp2[0].start_port = 1025; - mp2[0].end_port = 62235; - mp2[0].protocol = 2; - mp2[0].flags = 3; - - spp_api_cnat_v4_show_outside_entry_req_t_handler (&(mp2[0])); - } - -#if 1 - { - spp_api_cnat_stats_node_mapping_t mp3[20000]; - spp_api_cnat_stats_counter_mapping_t mp4[20000]; - spp_api_cnat_stats_counter_values_t mp5[23000]; - - mp3[0].rc = 0; - spp_api_cnat_stats_node_mapping_t_handler (&mp3); - mp4[0].rc = 0; - spp_api_cnat_stats_counter_mapping_t_handler (&mp4); - - mp5[0].flag = 1; - spp_api_cnat_stats_counter_values_t_handler(&mp5); - } -#endif - -#if 0 - mp1.ipv4_addr = 0x0A010102; - mp1.vrf_id = 1; - mp1.all_entries = 1; - mp1.protocol = 1; - - spp_api_cnat_v4_show_inside_entry_req_t_handler (&mp1); - - - mp1.ipv4_addr = 0x0A010103; - mp1.vrf_id = 1; - mp1.all_entries = 1; - mp1.protocol = 2; - - spp_api_cnat_v4_show_inside_entry_req_t_handler (&mp1); - - mp6[0].inside_vrf_id = 1; - mp6[0].start_ipv4_address = 0x64020001; - mp6[0].end_ipv4_address = 0x64020101; - mp6[0].free_addr = 0; - mp6[0].flags = CNAT_TRANSLATION_ENTRY_STATIC; - - spp_api_cnat_v4_show_freeUsed_entry_req_t_handler(&mp6); - -#endif - printf("returned here"); - - return; -} - - - -void cnat_db_clear_all_entries (int argc, unsigned long *argv) -{ - cnat_main_db_entry_t * db; - u32 index; - - pool_header_t * p = vec_header(cnat_main_db, sizeof(pool_header_t) ); - - for(index = 0; index < vec_len(cnat_main_db); index++) { - - if ( !clib_bitmap_get(p->free_bitmap, index)) { - - db = cnat_main_db + index; - cnat_delete_main_db_entry_v2(db); - - } - } - -} - - -void spp_log_cmd (int argc, unsigned long *argv) -{ - u16 num_traces; - u16 error_code; - u16 num_args; - u32 arg[7]; - u8 i; - - num_traces = argv[0]; - - for (i = 0; i < num_traces; i++) { - error_code = argv[1 + 4*i]; - num_args = argv[2 + 4*i]; - arg[0] = argv[3 + 4*i]; - arg[1] = argv[4 + 4*i]; - - spp_printf(error_code, num_args, arg); - } -} - - -void cnat_db_create_random_entries (int argc, unsigned long *argv) -{ - - platform_cnat_db_create_random_entries(); -} - -#define MAX_DEPTH 10 - -void show_user_db_hash_chain_len() { - - u32 max_len, len, n, i, max_idx, index, used; - cnat_user_db_entry_t * udb; - u32 hash_depth[MAX_DEPTH]; - - memset(hash_depth, 0, sizeof(u32)*MAX_DEPTH); - - n = vec_len(cnat_user_hash); - - used = 0; - max_len = 0; - for(i=0;iuser_hash.next; - } - - if(len < (MAX_DEPTH-1) ) { - hash_depth[len]++; - } else { - hash_depth[MAX_DEPTH-1]++; - } - - if (max_len < len) { - max_len = len; - max_idx = cnat_user_hash[i].next; - } - } - - printf("Max user db hash length %u, total buckets %u used %u\n", - max_len, n, used); - - for( i=1; i<(MAX_DEPTH - 1); i++) { - printf("Hash chain len %02d, entries count %d\n", i, hash_depth[i]); - } - - printf("Hash chain len >%02d, entries count %d\n", - MAX_DEPTH-1, hash_depth[MAX_DEPTH-1]); - -} - -void show_main_db_hash_chain_len() { - - u32 max_len, len, n, i, max_idx, index, used; - cnat_main_db_entry_t * db; - u32 hash_depth[MAX_DEPTH]; - - memset(hash_depth, 0, sizeof(u32)*MAX_DEPTH); - - n = vec_len(cnat_in2out_hash); - - used = 0; - max_len = 0; - for(i=0;iin2out_hash.next; - } - - if(len < (MAX_DEPTH-1) ) { - hash_depth[len]++; - } else { - hash_depth[MAX_DEPTH-1]++; - } - - if (max_len < len) { - max_len = len; - max_idx = cnat_in2out_hash[i].next; - } - } - - printf("Max main db I2O hash length %u, total buckets %u used %u\n", - max_len, n, used); - - for( i=1; i<(MAX_DEPTH - 1); i++) { - printf("Hash chain len %02d, entries count %d\n", i, hash_depth[i]); - } - - printf("Hash chain len >%02d, entries count %d\n", - MAX_DEPTH-1, hash_depth[MAX_DEPTH-1]); - - - memset(hash_depth, 0, sizeof(u32)*MAX_DEPTH); - - n = vec_len(cnat_out2in_hash); - used = 0; - max_len = 0; - - for(i=0;iout2in_hash.next; - } - - if(len < (MAX_DEPTH-1) ) { - hash_depth[len]++; - } else { - hash_depth[MAX_DEPTH-1]++; - } - - if (max_len < len) { - max_len = len; - max_idx = cnat_in2out_hash[i].next; - } - } - - printf("Max main db O2I hash length %u, total buckets %u used %u\n", - max_len, n, used); - - for( i=1; i<(MAX_DEPTH - 1); i++) { - printf("Hash chain len %02d, entries count %d\n", i, hash_depth[i]); - } - - printf("Hash chain len >%02d, entries count %d\n", - MAX_DEPTH-1, hash_depth[MAX_DEPTH-1]); - - -} - -u32 db_free_entry (void * p) { - - pool_header_t * h; - u32 free; - - h = pool_header(p); - - free = p == 0 ? 0: vec_len(h->free_indices); - - return free; -} - -void cnat_db_summary (int argc, unsigned long *argv) { - - PLATFORM_DEBUG_PRINT("\n-----------------------------------------"); - PLATFORM_DEBUG_PRINT("\nSummary DB"); - PLATFORM_DEBUG_PRINT("\n-----------------------------------------\n"); - u32 count1, count2, i; -#ifndef NO_NAT64_DEF - extern void nat64_session_db_summary(); -#endif - /* main db active entry count*/ - count1 = vec_len(cnat_main_db); - count2 = db_free_entry(cnat_main_db); - - PLATFORM_DEBUG_PRINT("main db entries: total %u, active %u, free %u\n", count1, count1 - count2, count2); - - /* user db active entry count */ - count1 = vec_len(cnat_user_db); - count2 = db_free_entry(cnat_user_db); - - PLATFORM_DEBUG_PRINT("user db entries: total %u, active %u, free %u\n", count1, count1 - count2, count2); - - - /* user db active entry count */ -#ifndef NO_NAT64_DEF - nat64_session_db_summary(); -#endif - - /* main db hash i2o o2i usage count */ - count1 = 0; - count2 = 0; - - for (i=0; i< CNAT_MAIN_HASH_SIZE; i++) { - - if(cnat_in2out_hash[i].next != ~0) count1++; - if(cnat_out2in_hash[i].next != ~0) count2++; - - } - - PLATFORM_DEBUG_PRINT("main hash in2out: total %6u, used %u (%.2f%%)\n", - CNAT_MAIN_HASH_SIZE, count1, - (100.0*count1)/CNAT_MAIN_HASH_SIZE); - - PLATFORM_DEBUG_PRINT("main hash out2in: total %6u, used %u (%.2f%%)\n", - CNAT_MAIN_HASH_SIZE, count2, - (100.0 * count1)/CNAT_MAIN_HASH_SIZE); - - /* use db hashing usage count */ - - count1 = 0; - - for (i=0; i< CNAT_USER_HASH_SIZE; i++) { - if(cnat_user_hash[i].next != ~0) count1++; - } - - PLATFORM_DEBUG_PRINT("user db hash: total %6u, used %u (%.2f%%)\n", - CNAT_USER_HASH_SIZE, count1, - (100.0*count1)/CNAT_USER_HASH_SIZE); - - PLATFORM_DEBUG_PRINT("\nNull pointer exceptions:\n"); - PLATFORM_DEBUG_PRINT("packet_pool: null enq : %10u, null deq : %10u\n",null_enq_pkt, null_deq_pkt); - PLATFORM_DEBUG_PRINT("ctx_pool : null enq : %10u, null deq : %10u\n",null_enq_ctx, null_deq_ctx); - PLATFORM_DEBUG_PRINT("wqe_pool : null enq : %10u, null deq : %10u\n",null_enq_wqe, null_deq_wqe); - - PLATFORM_DEBUG_PRINT("\nReceived Packet Errors on SPI:\n"); - PLATFORM_DEBUG_PRINT("rcv_pkt_errs: %10u\n",rcv_pkt_errs); - - PLATFORM_DEBUG_PRINT("\nctx/sf allocation failure errors: \n"); -#ifndef CGN_PERF_SCALE_DEBUG - PLATFORM_DEBUG_PRINT("Warning: collection of error counts is disabled.\n"); - PLATFORM_DEBUG_PRINT("sf alloc errors: %10u, ctx alloc errors: %10u\n",sf_alloc_errs,ctx_alloc_errs); -#else - for(i=0;iTimestamp : %10u, sf errors: %10u, ctx errors: %10u\n",\ - i,err_cnt_arr[i].timestamp,\ - err_cnt_arr[i].sf_error_counter, \ - err_cnt_arr[i].ctx_error_counter); -#endif -} - -void cnat_db_hash_summary (int argc, unsigned long *argv) { - - show_main_db_hash_chain_len(); - - show_user_db_hash_chain_len(); -} - -/* - * cnat_port_alloc - * This function is now deprecated... - * - */ -#ifdef LB_PORT -int cnat_port_alloc (cnat_portmap_t *cnat_portmap, u16 *portmap_inuse, - int cnat_instance, - port_alloc_t atype, port_pair_t ptype, - int *index, u32 *ipv4_address, u16 *base_port) -#else -int cnat_port_alloc (cnat_portmap_t *cnat_portmap, u16 *portmap_inuse, - port_alloc_t atype, port_pair_t ptype, - int *index, u32 *ipv4_address, u16 *base_port) -#endif -{ - - return (0); -} - -/* - * cnat_port_free - * This function is now deprecated... - * - */ -#ifdef LB_PORT -void cnat_port_free (cnat_portmap_t *cnat_portmap, u16 *portmap_inuse, - int instance, int index, port_pair_t ptype, u16 base_port) -#else -void cnat_port_free (cnat_portmap_t *cnat_portmap, u16 *portmap_inuse, - int index, port_pair_t ptype, u16 base_port) -#endif -{ -} - -void spp_api_cnat_port_allocate_t_handler(spp_api_cnat_port_allocate_t *mp) -{ - int i, j, k1, k2; - int pm_index; - u32 ipv4_address; - u16 aport; - int rv; - char *out1, *out2, *out_f; - port_alloc_t pt1, pt2; - cnat_portmap_t *pm = 0; - u16 *pm_inuse = 0; - u32 *firstp =0; - u32 nr_ports =0; - u32 nodd_ports = 0; - u32 neven_ports = 0; -#ifdef LB_PORT - u32 my_instance = 1; -#endif - char out_r[12] = "allocated-r"; - char out_o[12] = "allocated-o"; - char out_e[12] = "allocated-e"; - - - /* - * this command is run after db create portmap - * vrf is hardcode to 1 - */ - - /* Already have a portmap vector for this VRF? */ - for (i = 0; i < vec_len(cnat_portmap_indices_by_vrf); i++) { - if (cnat_portmap_indices_by_vrf[i] == mp->vrf) { - pm = cnat_portmaps[i]; - pm_inuse = cnat_portmaps_inuse[i]; - goto found_portmaps; - } - } - - printf("need to run db create portmaps first 0x%d\n", - vec_len(cnat_portmap_indices_by_vrf)); - return; - -found_portmaps: - nr_ports = mp->nr_ports; - nodd_ports = mp->nodd_ports; - neven_ports = mp->neven_ports; - - if ((nr_ports + nodd_ports + neven_ports ) > (PORTS_PER_ADDR)) { - printf("invalid port# nr_ports %d + odd %d + even %d " - "should be less than 200 \n", nr_ports, nodd_ports, neven_ports); - return; - } - - /* - * first port - */ - firstp = nr_ports ? (&nr_ports) : (nodd_ports ? (&nodd_ports) : (&neven_ports)); - if (!(*firstp)) { - printf("invalid port# nr_ports %d odd %d even %d ", - nr_ports, nodd_ports, neven_ports); - } - out_f = nr_ports ? out_r : (nodd_ports ? out_o : out_e); - -#ifdef LB_PORT - rv = cnat_port_alloc (pm, pm_inuse, my_instance, - PORT_ALLOC_ANY, PORT_S_ODD, - &pm_index, &ipv4_address, &aport); -#else - rv = cnat_port_alloc (pm, pm_inuse, - PORT_ALLOC_ANY, PORT_S_ODD, - &pm_index, &ipv4_address, &aport); -#endif - - if (!rv) { - printf("failed-o\n"); - return; - } - printf("%s %8d %10x %8d\n", out_f, - pm_index, ipv4_address, aport); - - (*firstp)--; - - for (i=0; i < nr_ports; i++) { -#ifdef LB_PORT - rv = cnat_port_alloc (pm, pm_inuse, my_instance, - PORT_ALLOC_DIRECTED, PORT_SINGLE, - &pm_index, &ipv4_address, &aport); -#else - rv = cnat_port_alloc (pm, pm_inuse, - PORT_ALLOC_DIRECTED, PORT_SINGLE, - &pm_index, &ipv4_address, &aport); -#endif - if (rv) { - printf("%s %8d %10x %8d\n", out_r, - pm_index, ipv4_address, aport); - } else { - printf("%s failed\n", out_r); - return; - } - } - - if (nodd_ports > neven_ports) { - k1 = nodd_ports; - k2 = neven_ports; - pt1 = PORT_S_ODD; - pt2 = PORT_S_EVEN; - out1 = out_o; - out2 = out_e; - } else { - k1= neven_ports; - pt1 = PORT_S_EVEN; - k2 = nodd_ports; - pt2 = PORT_S_ODD; - out1 = out_e; - out2 = out_o; - } - - j = 0; - for (i=0; i < k1; i++) { -#ifdef LB_PORT - rv = cnat_port_alloc (pm, pm_inuse, my_instance, - PORT_ALLOC_DIRECTED, pt1, - &pm_index, &ipv4_address, &aport); -#else - rv = cnat_port_alloc (pm, pm_inuse, - PORT_ALLOC_DIRECTED, pt1, - &pm_index, &ipv4_address, &aport); -#endif - if (rv) { - printf("%s %8d %10x %8d\n", out1, - pm_index, ipv4_address, aport); - } else { - printf("%s failed\n", out1); - return; - } - - if (j < k2) { -#ifdef LB_PORT - rv = cnat_port_alloc (pm, pm_inuse, my_instance, - PORT_ALLOC_DIRECTED, pt2, - &pm_index, &ipv4_address, &aport); -#else - rv = cnat_port_alloc (pm, pm_inuse, - PORT_ALLOC_DIRECTED, pt2, - &pm_index, &ipv4_address, &aport); -#endif - - if (rv) { - printf("%s %8d %10x %8d\n", out2, - pm_index, ipv4_address, aport); - j++; - } else { - printf("%s failed\n", __FUNCTION__); - return; - } - } - } -} - -void cnat_db_summary_stats (int argc, unsigned long *argv) -{ - spp_api_cnat_show_statistics_summary_req_t mp[50000]; - - spp_api_cnat_show_statistics_summary_req_t_handler(&(mp[0])); -} - -void cnat_debug_global_test (int argc, unsigned long *argv) -{ - spp_api_cnat_v4_debug_global_t *mp; - spp_api_cnat_v4_config_dummy_t mp1; - spp_api_cnat_v4_config_icmp_timeout_t mp2[10]; - - mp = spp_msg_api_alloc (sizeof (*mp)); - memset(mp, 0, sizeof (*mp)); - - - mp->_spp_msg_id = SPP_API_CNAT_V4_DEBUG_GLOBAL; - mp->debug_flag = argv[0]; - - platform_send_msg(mp); - - mp2[0].default_value = 3; - - spp_api_cnat_v4_config_dummy_t_handler(&mp1); - spp_api_cnat_v4_config_icmp_timeout_t_handler(&(mp2[0])); -} - -void cnat_debug_inside_test (int argc, unsigned long *argv) -{ - - spp_api_cnat_v4_debug_in2out_private_addr_t *mp; - - mp = spp_msg_api_alloc (sizeof (*mp)); - memset(mp, 0, sizeof (*mp)); - - - mp->_spp_msg_id = SPP_API_CNAT_V4_DEBUG_IN2OUT_PRIVATE_ADDR; - - mp->start_addr = spp_host_to_net_byte_order_32(argv[0]); - mp->end_addr = spp_host_to_net_byte_order_32(argv[1]); - mp->i_vrf = spp_host_to_net_byte_order_16(argv[2]); - mp->debug_flag = spp_host_to_net_byte_order_32(argv[3]); - - platform_send_msg(mp); -} - -void cnat_config_ports_user (int argc, unsigned long *argv) -{ - spp_api_cnat_v4_config_port_limit_t *mp; - - mp = spp_msg_api_alloc (sizeof (*mp)); - memset(mp, 0, sizeof (*mp)); - - - mp->_spp_msg_id = SPP_API_CNAT_V4_CONFIG_PORT_LIMIT; - - mp->port_limit = spp_host_to_net_byte_order_16(argv[0]); - - platform_send_msg(mp); - -} - -void cnat_debug_outside_test (int argc, unsigned long *argv) -{ - - spp_api_cnat_v4_debug_out2in_public_addr_t *mp; - - mp = spp_msg_api_alloc (sizeof (*mp)); - memset(mp, 0, sizeof (*mp)); - - - mp->_spp_msg_id = SPP_API_CNAT_V4_DEBUG_OUT2IN_PUBLIC_ADDR; - - mp->start_addr = spp_host_to_net_byte_order_32(argv[0]); - mp->end_addr = spp_host_to_net_byte_order_32(argv[1]); - mp->o_vrf = spp_host_to_net_byte_order_16(argv[2]); - mp->debug_flag = spp_host_to_net_byte_order_32(argv[3]); - - platform_send_msg(mp); -} - -void cnat_debug_udp_dump (int argc, unsigned long *argv) -{ - - spp_api_cnat_p2mp_debug_request_t *mp; - - mp = spp_msg_api_alloc (sizeof (*mp)); - memset(mp, 0, sizeof (*mp)); - - - mp->_spp_msg_id = SPP_API_CNAT_P2MP_DEBUG_REQUEST; - mp->dump_type = - spp_host_to_net_byte_order_16(CNAT_DEBUG_GENERIC_COMMAND_DEBUG_FLAGS); - - if (spp_host_to_net_byte_order_32(argv[0]) == 1) { - mp->param[0] = spp_host_to_net_byte_order_32( - CNAT_DEBUG_FLAG_UDP_INSIDE_PACKET_DUMP); - } else { - mp->param[0] = spp_host_to_net_byte_order_32( - CNAT_DEBUG_FLAG_UDP_OUTSIDE_PACKET_DUMP); - } - mp->param[1] = spp_host_to_net_byte_order_32(argv[1]); - - platform_send_msg(mp); - - - -} - -void cnat_debug_udp_crc (int argc, unsigned long *argv) -{ - spp_api_cnat_p2mp_debug_request_t *mp; - - mp = spp_msg_api_alloc (sizeof (*mp)); - memset(mp, 0, sizeof (*mp)); - - - mp->_spp_msg_id = SPP_API_CNAT_P2MP_DEBUG_REQUEST; - mp->dump_type = - spp_host_to_net_byte_order_16(CNAT_DEBUG_GENERIC_COMMAND_DEBUG_FLAGS); - - if (spp_host_to_net_byte_order_32(argv[0]) == 1) { - mp->param[0] = spp_host_to_net_byte_order_32( - CNAT_DEBUG_FLAG_UDP_INSIDE_CHECKSUM_MODIFY); - } else { - mp->param[0] = spp_host_to_net_byte_order_32( - CNAT_DEBUG_FLAG_UDP_OUTSIDE_CHECKSUM_MODIFY); - } - mp->param[1] = spp_host_to_net_byte_order_32(argv[1]); - - platform_send_msg(mp); - -} - -void cnat_db_allocate_port_cmd (int argc, unsigned long *argv) -{ - spp_api_cnat_port_allocate_t *mp; - - - if (!argc) { - printf("no port# defined\n"); - return; - } - - if ( argc < 3) { - printf("no port# defined\n"); - return; - } - - if ((argc == 3) && (argv[0] == 0) && (argv[1] == 0) && (argv[2] == 0)) { - printf("no port# defined\n"); - return; - } - - mp = spp_msg_api_alloc (sizeof (*mp)); - memset(mp, 0, sizeof (*mp)); - - - mp->_spp_msg_id = SPP_API_CNAT_PORT_ALLOCATE; - mp->nr_ports = argv[0]; - mp->nodd_ports = argv[1]; - mp->neven_ports = argv[2]; - mp->vrf = 1; - - platform_send_msg(mp); -} - - -void spp_api_cnat_port_clear_t_handler(spp_api_cnat_port_clear_t *mp) -{ - u32 i; - cnat_portmap_t *pm = 0; - u16 *pm_inuse = 0; -#ifdef LB_PORT - u32 my_instance = 1; -#endif - - - /* - * this command is run after db create port - * vrf is hardcode to 1 - */ - - /* Already have a portmap vector for this VRF? */ - for (i = 0; i < vec_len(cnat_portmap_indices_by_vrf); i++) { - if (cnat_portmap_indices_by_vrf[i] == mp->vrf) { - pm = cnat_portmaps[i]; - pm_inuse = cnat_portmaps_inuse[i]; - goto found_portmaps; - } - } - - printf("portmap is not created 0x%d\n", - vec_len(cnat_portmap_indices_by_vrf)); - return; - -found_portmaps: - if (mp->pm_index >= vec_len(pm)) { - printf("invalid port_index 0x%d >= 0x%d\n", - mp->pm_index, vec_len(pm)); - return; - } - -#ifdef LB_PORT - cnat_port_free(pm, pm_inuse, my_instance, - mp->pm_index, PORT_SINGLE, mp->port); -#else - cnat_port_free(pm, pm_inuse, - mp->pm_index, PORT_SINGLE, mp->port); -#endif - printf("\n pm_index %d port %d is deleted\n", mp->pm_index, mp->port); -} - - - -void cnat_db_clear_port_cmd (int argc, unsigned long *argv) -{ - spp_api_cnat_port_clear_t *mp; - - if (!argc) { - printf("no port# defined\n"); - return; - } - - if ( argc < 2 ) { - printf("no port# defined\n"); - return; - } - - if (argc > 2) { - printf("too many port# defined\n"); - return; - } - - mp = spp_msg_api_alloc (sizeof (*mp)); - memset(mp, 0, sizeof (*mp)); - - - mp->_spp_msg_id = SPP_API_CNAT_PORT_CLEAR; - mp->pm_index = argv[0]; - mp->port = argv[1]; - mp->vrf = 1; - - platform_send_msg(mp); -} - - -void spp_api_cnat_v4_add_vrf_map_t_handler -(spp_api_cnat_v4_add_vrf_map_t *mp); - -void spp_api_cnat_v4_del_vrf_map_t_handler -(spp_api_cnat_v4_del_vrf_map_t *mp); - -void spp_api_cnat_v4_add_static_port_t_handler -(spp_api_cnat_v4_add_static_port_t *mp); - -void spp_api_cnat_v4_del_static_port_t_handler -(spp_api_cnat_v4_del_static_port_t *mp); - - -void cnat_db_create_vrfmap_cmd (int argc, unsigned long *argv) -{ - spp_api_cnat_v4_add_vrf_map_t *mp; - - if ((argc != 4)) { - printf("need right input\n"); - return; - } - - mp = spp_msg_api_alloc (sizeof (*mp)); - memset(mp, 0, sizeof (*mp)); - mp->_spp_msg_id = SPP_API_CNAT_V4_ADD_VRF_MAP; - mp->i_vrf = spp_host_to_net_byte_order_16(argv[0]); - mp->o_vrf = spp_host_to_net_byte_order_16(argv[1]); - mp->start_addr[0] = spp_host_to_net_byte_order_32(argv[2]); - mp->end_addr[0] = spp_host_to_net_byte_order_32(argv[3]); - - /* - * Some hardcoded values for the vrf ids - */ - mp->i_vrf_id = spp_host_to_net_byte_order_32(0x00000100 | mp->i_vrf); - mp->o_vrf_id = spp_host_to_net_byte_order_32(0x00000200 | mp->o_vrf); - - platform_send_msg(mp); -} - - -void cnat_db_delete_vrfmap_cmd (int argc, unsigned long *argv) -{ - spp_api_cnat_v4_del_vrf_map_t *mp; - - if (argc != 4) { - printf("need right input\n"); - return; - } - - mp = spp_msg_api_alloc (sizeof (*mp)); - memset(mp, 0, sizeof (*mp)); - mp->_spp_msg_id = SPP_API_CNAT_V4_DEL_VRF_MAP; - mp->i_vrf = spp_host_to_net_byte_order_16(argv[0]); - mp->start_addr[0] = spp_host_to_net_byte_order_32(argv[2]); - mp->end_addr[0] = spp_host_to_net_byte_order_32(argv[3]); - - platform_send_msg(mp); -} - -void cnat_db_add_svi_cmd (int argc, unsigned long *argv) -{ - spp_api_cnat_config_svi_params_t *mp; - - if (argc != 3) { - printf("need right input\n"); - return; - } - - - mp = spp_msg_api_alloc (sizeof (*mp)); - memset(mp, 0, sizeof (*mp)); - mp->_spp_msg_id = SPP_API_CNAT_CONFIG_SVI_PARAMS; - mp->uidb_index = spp_host_to_net_byte_order_16(argv[1]); - mp->svi_ipv4_addr = spp_host_to_net_byte_order_32(argv[2]); - platform_send_msg(mp); - return; -} - - - -void spp_api_cnat_port_create_t_handler(spp_api_cnat_port_create_t *mp) -{ - int i, j, k1, k2; - int my_index; - u32 ipv4_address; - u16 aport; - u32 pm_len =0; - cnat_errno_t rv; - u16 i_vrf; - char *out1, *out2, *out_f; - port_alloc_t pt1, pt2; - cnat_vrfmap_t *my_vrfmap; - cnat_portmap_v2_t *pm = 0; - u32 *firstp =0; - u32 nr_ports =0; - u32 nodd_ports = 0; - u32 neven_ports = 0; -#ifdef LB_PORT - u32 my_instance = 1; -#endif - char out_r[12] = "allocated-r"; - char out_o[12] = "allocated-o"; - char out_e[12] = "allocated-e"; -#ifndef NO_BULK_LOGGING - int nfv9_log_req; -#endif - - nr_ports = mp->nr_ports; - nodd_ports = mp->nodd_ports; - neven_ports = mp->neven_ports; - i_vrf = mp->vrf; - - /* - * this command is run after db create vrfmap - * or using vrf id in init function - */ - /* Already have a portmap vector for this VRF? */ - pool_foreach (my_vrfmap, cnat_map_by_vrf, ({ - if ((my_vrfmap->status == S_RUN) && - (my_vrfmap->i_vrf == i_vrf)) { - pm = my_vrfmap->portmap_list; - pm_len = vec_len(pm); - if (pm_len) { - goto found_portmaps; - } - } - })); - - printf("need to run db create vrfmaps first for this vrf0x%d\n", pm_len); - return; - -found_portmaps: - - if ((nr_ports + nodd_ports + neven_ports ) > (PORTS_PER_ADDR)) { - printf("invalid port# nr_ports %d + odd %d + even %d " - "should be less than 200 \n", nr_ports, nodd_ports, neven_ports); - return; - } - - /* - * first port - */ - firstp = nr_ports ? (&nr_ports) : (nodd_ports ? (&nodd_ports) : (&neven_ports)); - if (!(*firstp)) { - printf("invalid port# nr_ports %d odd %d even %d ", - nr_ports, nodd_ports, neven_ports); - } - out_f = nr_ports ? out_r : (nodd_ports ? out_o : out_e); - - rv = cnat_dynamic_port_alloc_v2 (pm, PORT_ALLOC_ANY, PORT_S_ODD, - &my_index, &ipv4_address, &aport, - cnat_static_port_range -#ifndef NO_BULK_LOGGING - , BULKSIZE_FROM_VRFMAP(my_vrfmap), - &nfv9_log_req -#endif - , 0, - &(my_vrfmap->rseed_ip) - ); - - if (rv != CNAT_SUCCESS) { - printf("failed-o\n"); - return; - } - printf("%s %8d %10x %8d\n", out_f, - my_index, ipv4_address, aport); - - (*firstp)--; - - for (i=0; i < nr_ports; i++) { - rv = cnat_dynamic_port_alloc_v2 (pm, PORT_ALLOC_DIRECTED, PORT_SINGLE, - &my_index, &ipv4_address, &aport, - cnat_static_port_range -#ifndef NO_BULK_LOGGING - , BULKSIZE_FROM_VRFMAP(my_vrfmap), - &nfv9_log_req -#endif - , 0, - &(my_vrfmap->rseed_ip) - ); - - if (rv == CNAT_SUCCESS) { - printf("%s %8d %10x %8d\n", out_r, - my_index, ipv4_address, aport); - } else { - printf("%s failed\n", __FUNCTION__); - return; - } - } - - if (nodd_ports > neven_ports) { - k1 = nodd_ports; - k2 = neven_ports; - pt1 = PORT_S_ODD; - pt2 = PORT_S_EVEN; - out1 = out_o; - out2 = out_e; - } else { - k1= neven_ports; - pt1 = PORT_S_EVEN; - k2 = nodd_ports; - pt2 = PORT_S_ODD; - out1 = out_e; - out2 = out_o; - } - - j = 0; - for (i=0; i < k1; i++) { - rv = cnat_dynamic_port_alloc_v2 (pm, PORT_ALLOC_DIRECTED, pt1, - &my_index, &ipv4_address, &aport, - cnat_static_port_range -#ifndef NO_BULK_LOGGING - , BULKSIZE_FROM_VRFMAP(my_vrfmap), - &nfv9_log_req -#endif - , 0, - &(my_vrfmap->rseed_ip) - ); - - if (rv == CNAT_SUCCESS) { - printf("%s %8d %10x %8d\n", out1, - my_index, ipv4_address, aport); - } else { - printf("%s failed\n", __FUNCTION__); - return; - } - - if (j < k2) { - rv = cnat_dynamic_port_alloc_v2 (pm, PORT_ALLOC_DIRECTED, pt2, - &my_index, &ipv4_address, &aport, - cnat_static_port_range -#ifndef NO_BULK_LOGGING - , BULKSIZE_FROM_VRFMAP(my_vrfmap), - &nfv9_log_req -#endif - , 0, - &(my_vrfmap->rseed_ip) - ); - - if (rv == CNAT_SUCCESS) { - printf("%s %8d %10x %8d\n", out2, - my_index, ipv4_address, aport); - j++; - } else { - printf("%s failed\n", __FUNCTION__); - return; - return; - } - } - } -} - - -void cnat_db_create_port_cmd (int argc, unsigned long *argv) -{ - spp_api_cnat_port_create_t *mp; - - if (argc != 4) { - printf("no proper input defined\n"); - return; - } - - if ((argv[0] == 0) && (argv[1] == 0) && (argv[2] == 0)) { - printf("no port# defined\n"); - return; - } - - mp = spp_msg_api_alloc (sizeof (*mp)); - memset(mp, 0, sizeof (*mp)); - - - mp->_spp_msg_id = SPP_API_CNAT_PORT_CREATE; - mp->nr_ports = argv[0]; - mp->nodd_ports = argv[1]; - mp->neven_ports = argv[2]; - mp->vrf = argv[3]; - - platform_send_msg(mp); -} - -void spp_api_cnat_port_delete_t_handler(spp_api_cnat_port_delete_t *mp) -{ - u32 pm_len; - cnat_vrfmap_t *my_vrfmap; - cnat_portmap_v2_t *pm = 0; - - u32 my_index, my_port; - u16 i_vrf; -#ifdef LB_PORT - u32 my_instance = 1; -#endif - - my_index = mp->pm_index; - my_port = mp->port; - i_vrf = mp->vrf; - - /* - * this command is run after db create port - */ - pool_foreach (my_vrfmap, cnat_map_by_vrf, ({ - if (my_vrfmap->i_vrf == i_vrf) { - pm = my_vrfmap->portmap_list; - pm_len = vec_len(pm); - if (pm_len) { - goto found_portmaps; - } - } - })); - - printf("portmap is not created 0x%d\n", - vec_len(cnat_portmap_indices_by_vrf)); - return; - -found_portmaps: - if (my_index >= pm_len) { - printf("invalid port_index 0x%d >= 0x%d\n", - my_index, pm_len); - return; - } - -#ifdef LB_PORT - cnat_port_free_v2(pm, my_instance, - my_index, PORT_SINGLE, mp->port,cnat_static_port_range); -#else - cnat_port_free_v2(pm, my_index, PORT_SINGLE, mp->port,cnat_static_port_range); -#endif - printf("\n pm_index %d port %d is deleted\n", mp->pm_index, mp->port); -} - -void cnat_db_delete_port_cmd (int argc, unsigned long *argv) -{ - spp_api_cnat_port_clear_t *mp; - - if (argc != 3) { - printf("no proper input defined\n"); - return; - } - - mp = spp_msg_api_alloc (sizeof (*mp)); - memset(mp, 0, sizeof (*mp)); - - - mp->_spp_msg_id = SPP_API_CNAT_PORT_DELETE; - mp->pm_index = argv[0]; - mp->port = argv[1]; - mp->vrf = argv[2]; - platform_send_msg(mp); -} - -void cnat_db_create_static_fwd_cmd (int argc, unsigned long *argv) -{ - spp_api_cnat_v4_add_static_port_t *mp; - - if (argc != 4) { - printf("need right input\n"); - return; - } - - mp = spp_msg_api_alloc (sizeof (*mp)); - memset(mp, 0, sizeof (*mp)); - mp->_spp_msg_id = SPP_API_CNAT_V4_ADD_STATIC_PORT; - mp->i_vrf = spp_host_to_net_byte_order_16(argv[0]); - mp->i_ip = spp_host_to_net_byte_order_32(argv[1]); - mp->i_port = spp_host_to_net_byte_order_16(argv[2]); - mp->proto = argv[3]; - - platform_send_msg(mp); - return; -} - -void cnat_db_create_static_fwd_stby_cmd (int argc, unsigned long *argv) -{ - spp_api_cnat_v4_add_static_port_t *mp; - - if (argc != 7) { - printf("need right input\n"); - return; - } - - mp = spp_msg_api_alloc (sizeof (*mp)); - memset(mp, 0, sizeof (*mp)); - mp->_spp_msg_id = SPP_API_CNAT_V4_ADD_STATIC_PORT; - mp->i_vrf = spp_host_to_net_byte_order_16(argv[0]); - mp->i_ip = spp_host_to_net_byte_order_32(argv[1]); - mp->i_port = spp_host_to_net_byte_order_16(argv[2]); - mp->proto = argv[3]; - mp->o_vrf_id = spp_host_to_net_byte_order_32(argv[4]); - mp->o_ip = spp_host_to_net_byte_order_32(argv[5]); - mp->o_port = spp_host_to_net_byte_order_16(argv[6]); - -printf("\ni_vrf %d, ip 0x%x, port %d, o_ip, port %d", mp->i_vrf, mp->i_ip, mp->i_port, mp->o_ip, mp->o_port); - - platform_send_msg(mp); - return; -} - -void cnat_db_delete_static_fwd_cmd (int argc, unsigned long *argv) -{ - spp_api_cnat_v4_del_static_port_t *mp; - - if (argc != 3) { - printf("need right input\n"); - return; - } - - mp = spp_msg_api_alloc (sizeof (*mp)); - memset(mp, 0, sizeof (*mp)); - mp->_spp_msg_id = SPP_API_CNAT_V4_DEL_STATIC_PORT; - mp->i_vrf = spp_host_to_net_byte_order_16(argv[0]); - mp->i_ip = spp_host_to_net_byte_order_32(argv[1]); - mp->i_port = spp_host_to_net_byte_order_16(argv[2]); - - platform_send_msg(mp); - return; -} - -void cnat_nfv9_create_cmd (int argc, unsigned long *argv) -{ - spp_api_cnat_v4_config_nfv9_logging_t *mp; - - if (argc < 3) { - printf("nfv9 create i_vrf ip_addr port [refresh_rate] [timeout] [mtu]"); - return; - } - - mp = spp_msg_api_alloc (sizeof (*mp)); - memset(mp, 0, sizeof (*mp)); - mp->_spp_msg_id = SPP_API_CNAT_V4_CONFIG_NFV9_LOGGING; - mp->enable = 1; - mp->i_vrf = spp_host_to_net_byte_order_16(argv[0]); - - mp->ipv4_address = spp_host_to_net_byte_order_32(argv[1]); - mp->port = spp_host_to_net_byte_order_16(argv[2]); - - if (argc > 3) { - mp->refresh_rate = spp_host_to_net_byte_order_16(argv[3]); - mp->timeout_rate = spp_host_to_net_byte_order_16(argv[4]); - mp->path_mtu = spp_host_to_net_byte_order_16(argv[5]); - } else { - mp->refresh_rate = spp_host_to_net_byte_order_16(1000); - mp->timeout_rate = spp_host_to_net_byte_order_16(30); - mp->path_mtu = spp_host_to_net_byte_order_16(1500); - } - platform_send_msg(mp); -} - -void cnat_delete_cgn (int argc, unsigned long *argv) -{ - void *mp_send; - spp_api_cnat_del_cgn_t *mp; - u32 mp_size; - - mp_size = sizeof(spp_api_cnat_del_cgn_t); - - mp = spp_msg_api_alloc(mp_size); - memset(mp, 0, mp_size); - - mp->_spp_msg_id = SPP_API_CNAT_DEL_CGN; - - mp_send = mp; - - platform_send_msg(mp); -} - -void cnat_debug_global_all (int argc, unsigned long *argv) -{ - spp_api_cnat_v4_debug_global_t *mp; - - mp = spp_msg_api_alloc (sizeof (*mp)); - memset(mp, 0, sizeof (*mp)); - - mp->_spp_msg_id = SPP_API_CNAT_V4_DEBUG_GLOBAL; - mp->debug_flag = CNAT_DEBUG_GLOBAL_ALL; - - platform_send_msg(mp); -} - -void cnat_debug_global_none (int argc, unsigned long *argv) -{ - spp_api_cnat_v4_debug_global_t *mp; - - mp = spp_msg_api_alloc (sizeof (*mp)); - memset(mp, 0, sizeof (*mp)); - - mp->_spp_msg_id = SPP_API_CNAT_V4_DEBUG_GLOBAL; - mp->debug_flag = CNAT_DEBUG_NONE; - - platform_send_msg(mp); -} - - -void cnat_bulk_cmd (int argc, unsigned long *argv) -{ - void *mp_send; - - if (argc < 1) { - printf("\nargc = %d", argc); - printf("\n1. bulk cmd [0=static-port, 1=bulk_vrf, 2=policy_knob]"); - return; - } - - - switch (argv[0]) { - case 0: - { - spp_api_cnat_v4_bulk_add_delete_static_port_t *mp; - spp_api_cnat_v4_add_static_port_t *mp_sp; - u32 mp_size = - sizeof(spp_api_cnat_v4_bulk_add_delete_static_port_t) + - (sizeof(spp_api_cnat_v4_add_static_port_t))*2; - - mp = spp_msg_api_alloc(mp_size); - memset(mp, 0, mp_size); - - mp->_spp_msg_id = SPP_API_CNAT_V4_BULK_ADD_DELETE_STATIC_PORT; - - mp->num_static_port_entries = spp_host_to_net_byte_order_32(3); - - mp_sp = (spp_api_cnat_v4_add_static_port_t *) &(mp->pad2); - - mp_sp->_spp_msg_id = spp_host_to_net_byte_order_16( - SPP_API_CNAT_V4_ADD_STATIC_PORT); - mp_sp->proto = 2; - mp_sp->i_vrf = spp_host_to_net_byte_order_16(0x1); - mp_sp->i_ip = spp_host_to_net_byte_order_32(0x11111111); - mp_sp->i_port = spp_host_to_net_byte_order_16(0x7777); - - mp_sp++; - - - mp_sp->_spp_msg_id = spp_host_to_net_byte_order_16( - SPP_API_CNAT_V4_ADD_STATIC_PORT); - mp_sp->proto = 1; - mp_sp->i_vrf = spp_host_to_net_byte_order_16(0x1); - mp_sp->i_ip = spp_host_to_net_byte_order_32(0x22222222); - mp_sp->i_port = spp_host_to_net_byte_order_16(0x6666); - - mp_sp++; - - - mp_sp->_spp_msg_id = spp_host_to_net_byte_order_16( - SPP_API_CNAT_V4_ADD_STATIC_PORT); - mp_sp->proto = 1; - mp_sp->i_vrf = spp_host_to_net_byte_order_16(0x1); - mp_sp->i_ip = spp_host_to_net_byte_order_32(0x33333333); - mp_sp->i_port = spp_host_to_net_byte_order_16(0x5555); - - mp_send = mp; - - } - break; - - case 1: - { - spp_api_cnat_v4_bulk_vrf_map_t *mp; - spp_api_cnat_v4_single_vrf_map_req *mp_sp; - - u32 mp_size = sizeof(spp_api_cnat_v4_bulk_vrf_map_t) + - (sizeof(spp_api_cnat_v4_single_vrf_map_req))*2; - - mp = spp_msg_api_alloc(mp_size); - memset(mp, 0, mp_size); - - mp->_spp_msg_id = SPP_API_CNAT_V4_BULK_VRF_MAP; - - mp->num_vrfmap_entries = spp_host_to_net_byte_order_32(3); - - mp_sp = (spp_api_cnat_v4_single_vrf_map_req *) - &(mp->vrf_policy_enable); - - mp_sp->i_vrf_id = spp_host_to_net_byte_order_32(0xe0000001); - mp_sp->o_vrf_id = spp_host_to_net_byte_order_32(0xe0000000); - mp_sp->i_vrf = spp_host_to_net_byte_order_16(0x1); - mp_sp->o_vrf = spp_host_to_net_byte_order_16(0x0); - mp_sp->start_addr = spp_host_to_net_byte_order_32(0x11111100); - mp_sp->end_addr = spp_host_to_net_byte_order_32(0x111111ff); - mp_sp->vrf_policy_enable = spp_host_to_net_byte_order_16(0x3); - mp_sp->tcp_mss_value = spp_host_to_net_byte_order_16(0x111); - mp_sp->vrf_nfv9_logging_ipv4_address = spp_host_to_net_byte_order_32(0x11000001); - mp_sp->vrf_nfv9_logging_udp_port = spp_host_to_net_byte_order_16(0x1001); - mp_sp->vrf_nfv9_refresh_rate = spp_host_to_net_byte_order_16(0x100); - mp_sp->vrf_nfv9_timeout_rate = spp_host_to_net_byte_order_16(0x10); - mp_sp->vrf_nfv9_path_mtu = spp_host_to_net_byte_order_16(0x100); - - mp_sp++; - - mp_sp->i_vrf_id = spp_host_to_net_byte_order_32(0xe0000002); - mp_sp->o_vrf_id = spp_host_to_net_byte_order_32(0xe0000000); - mp_sp->i_vrf = spp_host_to_net_byte_order_16(0x2); - mp_sp->o_vrf = spp_host_to_net_byte_order_16(0x0); - mp_sp->start_addr = spp_host_to_net_byte_order_32(0x22220000); - mp_sp->end_addr = spp_host_to_net_byte_order_32(0x2222ffff); - mp_sp->vrf_policy_enable = spp_host_to_net_byte_order_16(0x1); - mp_sp->tcp_mss_value = spp_host_to_net_byte_order_16(0x222); - mp_sp->vrf_nfv9_logging_ipv4_address = spp_host_to_net_byte_order_32(0x22000002); - mp_sp->vrf_nfv9_logging_udp_port = spp_host_to_net_byte_order_16(0x2002); - mp_sp->vrf_nfv9_refresh_rate = spp_host_to_net_byte_order_16(0x200); - mp_sp->vrf_nfv9_timeout_rate = spp_host_to_net_byte_order_16(0x20); - mp_sp->vrf_nfv9_path_mtu = spp_host_to_net_byte_order_16(0x200); - - mp_sp++; - - mp_sp->i_vrf_id = spp_host_to_net_byte_order_32(0xe0000003); - mp_sp->o_vrf_id = spp_host_to_net_byte_order_32(0xe0000007); - mp_sp->i_vrf = spp_host_to_net_byte_order_16(0x3); - mp_sp->o_vrf = spp_host_to_net_byte_order_16(0x7); - mp_sp->start_addr = spp_host_to_net_byte_order_32(0x33333000); - mp_sp->end_addr = spp_host_to_net_byte_order_32(0x33333fff); - mp_sp->vrf_policy_enable = spp_host_to_net_byte_order_16(0x1); - mp_sp->tcp_mss_value = spp_host_to_net_byte_order_16(0x333); - mp_sp->vrf_nfv9_logging_ipv4_address = spp_host_to_net_byte_order_32(0x33000003); - mp_sp->vrf_nfv9_logging_udp_port = spp_host_to_net_byte_order_16(0x3003); - mp_sp->vrf_nfv9_refresh_rate = spp_host_to_net_byte_order_16(0x300); - mp_sp->vrf_nfv9_timeout_rate = spp_host_to_net_byte_order_16(0x30); - mp_sp->vrf_nfv9_path_mtu = spp_host_to_net_byte_order_16(0x300); - - mp_send = mp; - } - break; - - case 2: - { - spp_api_cnat_v4_bulk_policy_knob_t *mp; - - u32 mp_size = - sizeof(spp_api_cnat_v4_bulk_policy_knob_t) + - (sizeof(spp_api_cnat_v4_single_vrf_map_req))*2; - - mp = spp_msg_api_alloc(mp_size); - memset(mp, 0, mp_size); - - mp->_spp_msg_id = SPP_API_CNAT_V4_BULK_POLICY_KNOB; - - mp->port_limit = spp_host_to_net_byte_order_16(345); - mp->icmp_timeout = spp_host_to_net_byte_order_16(300); - mp->udp_init_timeout = spp_host_to_net_byte_order_16(175); - mp->udp_act_timeout = spp_host_to_net_byte_order_16(133); - mp->tcp_init_timeout = spp_host_to_net_byte_order_16(222); - mp->tcp_act_timeout = spp_host_to_net_byte_order_16(2345); - - mp->nat_policy_enable = spp_host_to_net_byte_order_32(0x7); - - mp->global_nfv9_logging_ipv4_address = spp_host_to_net_byte_order_32(0x77777777); - mp->global_nfv9_logging_udp_port = spp_host_to_net_byte_order_16(0x7007); - mp->global_nfv9_refresh_rate = spp_host_to_net_byte_order_16(0x700); - mp->global_nfv9_timeout_rate = spp_host_to_net_byte_order_16(0x70); - mp->global_nfv9_path_mtu = spp_host_to_net_byte_order_16(0x700); - - mp_send = mp; - } - break; - - - default: - printf("\nargv[2] = %d", argv[2]); - printf("\n2. bulk cmd [0=static-port, 1=bulk_vrf, 2=policy_knob+bulk_vrf]"); - return; - - } - platform_send_msg(mp_send); -} - -void cnat_nfv9_delete_cmd (int argc, unsigned long *argv) -{ - spp_api_cnat_v4_config_nfv9_logging_t *mp; - - if (argc != 1) { - printf("nfv9 delete i_vrf "); - return; - } - - mp = spp_msg_api_alloc (sizeof (*mp)); - memset(mp, 0, sizeof (*mp)); - mp->_spp_msg_id = SPP_API_CNAT_V4_CONFIG_NFV9_LOGGING; - mp->enable = 0; - mp->i_vrf = spp_host_to_net_byte_order_16(argv[0]); - platform_send_msg(mp); -} - -void cnat_generic_cmd (int argc, unsigned long *argv) -{ - spp_api_cnat_generic_command_request_t *mp; - - if (argc != 9) { - printf("generic command core type p1 p2 p3 p4 p5 p6 p7 "); - return; - } - - /* - * Allocate a large buffer for message req and resp structure - */ - mp = spp_msg_api_alloc (MAX_DEBUG_BUFFER_SIZE); - memset(mp, 0, MAX_DEBUG_BUFFER_SIZE); - mp->_spp_msg_id = SPP_API_CNAT_GENERIC_COMMAND_REQUEST; - mp->core_num = argv[0]; - mp->params[0] = spp_host_to_net_byte_order_32(argv[1]); - mp->params[1] = spp_host_to_net_byte_order_32(argv[2]); - mp->params[2] = spp_host_to_net_byte_order_32(argv[3]); - mp->params[3] = spp_host_to_net_byte_order_32(argv[4]); - mp->params[4] = spp_host_to_net_byte_order_32(argv[5]); - mp->params[5] = spp_host_to_net_byte_order_32(argv[6]); - mp->params[6] = spp_host_to_net_byte_order_32(argv[7]); - mp->params[7] = spp_host_to_net_byte_order_32(argv[8]); - platform_send_msg(mp); -} - -u32 icmp_sent_timestamps; /* 32 KB array per core */ -u8 v4_pkt_count = 0; - -cnat_icmp_msg_t icmp_msg_gen_allowed () -{ -#ifdef DISABLE_ICMP_THROTTLE_FOR_DEBUG_PURPOSE - return CNAT_ICMP_MSG; -#else - u32 current_timestamp; - spp_node_main_vector_t *nmv; - u32 updated_timestamp; - - v4_pkt_count ++; - - nmv = spp_get_node_main_vectorized_inline(); - - current_timestamp = nmv->ticks / nmv->ticks_per_second; - - PLATFORM_UPDATE_TIMESTAMP - if (PREDICT_FALSE(icmp_sent_timestamps != updated_timestamp)) { - v4_pkt_count = 1; - /* update timestamp */ - icmp_sent_timestamps = updated_timestamp; - } - if (PREDICT_TRUE(v4_pkt_count <= cnat_main_db_icmp_rate_limit_core)) { - return CNAT_ICMP_MSG; - } else { - return CNAT_NO_ICMP_MSG; - } -#endif -} - -u32 v6_icmp_sent_timestamps; /* 32 KB array per core */ -u8 v6_pkt_count = 0; - -cnat_icmp_msg_t v6_icmp_msg_gen_allowed () -{ -#ifdef DISABLE_ICMP_THROTTLE_FOR_DEBUG_PURPOSE - return CNAT_ICMP_MSG; -#else - u32 current_timestamp; - spp_node_main_vector_t *nmv; - u32 updated_timestamp; - - nmv = spp_get_node_main_vectorized_inline(); - - current_timestamp = nmv->ticks / nmv->ticks_per_second; - PLATFORM_UPDATE_TIMESTAMP - v6_pkt_count ++; - - if (PREDICT_FALSE(v6_icmp_sent_timestamps != updated_timestamp)) { - v6_pkt_count = 1; - /* update timestamp */ - v6_icmp_sent_timestamps = updated_timestamp; - } - if (PREDICT_TRUE(v6_pkt_count <= cnat_main_db_icmp_rate_limit_core)) { - return CNAT_ICMP_MSG; - } else { - return CNAT_NO_ICMP_MSG; - } -#endif -} - -u32 v4_udp_crc_zero_timestamps; -u32 v4_udp_crc_zero_pkt_count = 0; -int v4_crc_zero_udp_allowed () -{ - PLATFORM_V4_CRC_ZERO_UDP_ALLOWED - /* Currently not supported for Brahmos. we need to take care of this */ - spp_node_main_vector_t *nmv; - u32 hash_value, current_timestamp; - - nmv = spp_get_node_main_vectorized_inline(); - - current_timestamp = nmv->ticks / nmv->ticks_per_second; - v4_udp_crc_zero_pkt_count++; - if (PREDICT_FALSE(v4_udp_crc_zero_timestamps != current_timestamp)) { - v4_udp_crc_zero_pkt_count = 1; - v4_udp_crc_zero_timestamps = current_timestamp; - } - if (PREDICT_TRUE(v4_udp_crc_zero_pkt_count <= - crc_zero_udp_rate_limit_core)) { - return 1; - } else { - return 0; - } -} - -/* - * ipv4_decr_ttl_n_calc_csum() - * - It decrements the TTL and calculates the incremental IPv4 checksum - */ - -ALWAYS_INLINE( -void ipv4_decr_ttl_n_calc_csum(ipv4_header *ipv4)) -{ - u32 checksum; - u16 old; - - old = ntohs(*(u16 *)&ipv4->ttl); - - /* Decrement TTL */ - ipv4->ttl--; - - /* Calculate incremental checksum */ - checksum = old + (~ntohs(*(u16 *)&ipv4->ttl) & 0xFFFF); - checksum += ntohs(ipv4->checksum); - checksum = (checksum & 0xFFFF) + (checksum >> 16); - ipv4->checksum = htons(checksum + (checksum >> 16)); -} - -ALWAYS_INLINE( -void calc_ipv4_checksum (ipv4_header *ipv4)) -{ - u16 *data = (u16 *) ipv4; - u32 checksum = 0; - - checksum = crc_calc(ipv4); - - /* Now produce the 1's complement */ - ipv4->checksum = spp_host_to_net_byte_order_16(((u16) (~(u16)checksum))); -} - -ALWAYS_INLINE( -void calc_v4_icmp_checksum (icmp_v4_t *icmp, int ipv4_payload_size)) -{ - u16 *data = (u16 *) icmp; - int num_hwords = (ipv4_payload_size)/2; - u32 checksum = 0; - - icmp->checksum = 0; - if (PREDICT_FALSE((ipv4_payload_size%2) != 0)) { - num_hwords += 1; - /* Append 0's in the last octet */ - *((u8 *)data + ipv4_payload_size) = 0; - } - while (num_hwords) { - checksum += (u32)spp_net_to_host_byte_order_16(data++); - num_hwords--; - } - - /* Add in the carry of the original sum */ - checksum = (checksum & 0xFFFF) + (checksum >> 16); - /* Add in the carry of the final sum */ - checksum = (checksum & 0xFFFF) + (checksum >> 16); - /* Now produce the 1's complement */ - icmp->checksum = spp_host_to_net_byte_order_16(((u16) (~(u16)checksum))); -} - -ALWAYS_INLINE( -void calc_v6_icmp_checksum (ipv6_header_t *ipv6, u16 ip_payload_size)) -{ - u16 *data; - u16 *data1; - int i; - icmp_v6_t *icmp; - int num_hwords = (ip_payload_size)/2; - u32 checksum = 0; - pseudo_v6_header_t pseudo_header; - - icmp = (icmp_v6_t *) ((u8 *)ipv6 + IPV6_HDR_LEN); - data = (u16 *) icmp; - icmp->checksum = 0; - -#if 1 - if (PREDICT_FALSE((ip_payload_size%2) != 0)) { - num_hwords += 1; - /* Append 0's in the last octet */ - *((u8 *)data + ip_payload_size) = 0; - } -#endif - - /* construct the pseudo header */ - - pseudo_header.src_addr[0] = ipv6->src_addr[0]; - pseudo_header.src_addr[1] = ipv6->src_addr[1]; - pseudo_header.src_addr[2] = ipv6->src_addr[2]; - pseudo_header.src_addr[3] = ipv6->src_addr[3]; - pseudo_header.dst_addr[0] = ipv6->dst_addr[0]; - pseudo_header.dst_addr[1] = ipv6->dst_addr[1]; - pseudo_header.dst_addr[2] = ipv6->dst_addr[2]; - pseudo_header.dst_addr[3] = ipv6->dst_addr[3]; - pseudo_header.payload_length = spp_host_to_net_byte_order_16(ip_payload_size); - pseudo_header.next_header = spp_host_to_net_byte_order_16(ipv6->next_header); - - data1 = (u16 *) &pseudo_header; - - /* sizeof(pseudo_v6_header_t) = 36 */ - for (i = 0; i < 18; i++) { - checksum += (u32)spp_net_to_host_byte_order_16(data1++); - } - -checksum_calc: - - if (PREDICT_TRUE(num_hwords)) { - checksum += (u32)spp_net_to_host_byte_order_16(data); - num_hwords--; - data++; - goto checksum_calc; - } - - /* Add in the carry of the original sum */ - checksum = (checksum & 0xFFFF) + (checksum >> 16); - /* Add in the carry of the final sum */ - checksum = (checksum & 0xFFFF) + (checksum >> 16); - /* Now produce the 1's complement */ - icmp->checksum = spp_host_to_net_byte_order_16(((u16) (~(u16)checksum))); -} - -void icmp_error_generate_v6 (spp_ctx_t *ctx, u8 icmp_type, - u8 icmp_code, u16 uidb_index) { - - u16 ip_hdr_len, ip_payload_size; - u32 *src_p, * dst_p; - icmp_v6_t *icmp; - int i; - ipv6_header_t *ip_old, *ip_new; - u16 icmp_payload_len; - - /* - * As per RFC 2463, we limit the maximum size of generated ICMPv6 message to * 1280. And hence if the packet is bigger than 1280, then it needs to be - * truncated. Also, if the packet had multiple chained buffers, we need to - * free all chained buffers, except the first one. - */ - free_all_but_first_chained_buffers(ctx); - - ip_hdr_len = IPV6_HDR_LEN; - /* offset to ip payload */ - - ip_old = (ipv6_header_t *)PLATFORM_CTX_CURRENT_HDR; - ip_new = (ipv6_header_t *) ((u8 *) PLATFORM_CTX_CURRENT_HDR - ICMPV6_ERR_SIZE); - icmp = (icmp_v6_t*) ( (u8*)ip_new + ip_hdr_len); - - icmp_payload_len = ip_hdr_len + - spp_net_to_host_byte_order_16(&(ip_old->payload_length)) ; - - ip_payload_size = ICMPV6_HDR_SIZE + icmp_payload_len; - /* - * There is no easy way to predict this case as the probablity that the IPv6 - * pkt is big depends on the type of traffic. Let us optimize the big - * pkt case as it involves more processing - * - * If the pkt size exceeds IPV6_MIN_PATH_MTU truncate it to IPV6_MIN_PATH_MTU - */ - if (PREDICT_TRUE((ip_payload_size + ip_hdr_len) > IPV6_MIN_PATH_MTU)) { - ip_payload_size = IPV6_MIN_PATH_MTU - ip_hdr_len; - } - - /* Following ICMP op has to be after ip header being copied */ - icmp->type = icmp_type; - icmp->code = icmp_code; - - ip_new->version_trafficclass_flowlabel = spp_host_to_net_byte_order_32( - VERSION_TRAFFICCLASS_FLOWLABEL); - ip_new->payload_length = spp_host_to_net_byte_order_16(ip_payload_size); - ip_new->next_header = IPV6_PROTO_ICMPV6; - ip_new->hop_limit = 64; - ip_new->dst_addr[0] = ip_old->src_addr[0]; - ip_new->dst_addr[1] = ip_old->src_addr[1]; - ip_new->dst_addr[2] = ip_old->src_addr[2]; - ip_new->dst_addr[3] = ip_old->src_addr[3]; - - ip_new->src_addr[0] = - spp_host_to_net_byte_order_32(svi_params_array[uidb_index].ipv6_addr[0]); - ip_new->src_addr[1] = - spp_host_to_net_byte_order_32(svi_params_array[uidb_index].ipv6_addr[1]); - ip_new->src_addr[2] = - spp_host_to_net_byte_order_32(svi_params_array[uidb_index].ipv6_addr[2]); - ip_new->src_addr[3] = - spp_host_to_net_byte_order_32(svi_params_array[uidb_index].ipv6_addr[3]); - /* calc checksum for icmp */ - - calc_v6_icmp_checksum(ip_new, ip_payload_size); -#if 0 - printf("Flow = 0x%x\n", ip_new->version_trafficclass_flowlabel); - printf("Hoplimit = 0x%x\n", ip_new->hop_limit); - printf("Length= 0x%x\n", ip_new->payload_length); - printf("Next header = 0x%x\n", ip_new->next_header); - printf("Src add0 = 0x%x\n", ip_new->src_addr[0]); - printf("Src add1 = 0x%x\n", ip_new->src_addr[1]); - printf("Src add2 = 0x%x\n", ip_new->src_addr[2]); - printf("Src add3 = 0x%x\n", ip_new->src_addr[3]); - printf("Dst add0 = 0x%x\n", ip_new->dst_addr[0]); - printf("Dst add1 = 0x%x\n", ip_new->dst_addr[1]); - printf("Dst add2 = 0x%x\n", ip_new->dst_addr[2]); - printf("Dst add3 = 0x%x\n", ip_new->dst_addr[3]); - printf("Icmp type = 0x%x\n", icmp->type); - printf("Icmp code = 0x%x\n", icmp->code); - - printf("\n\nICMP packet:\n"); - for (i = 0; i < 10; i ++) { - printf("0x%x " , *((u8 *)icmp + i)); - if ((i%16) == 15) { - printf("\n"); - } - } -#endif - - ctx->current_header -= ICMPV6_ERR_SIZE; - ctx->current_length = ip_payload_size + ip_hdr_len; - PLATFORM_CNAT_SET_TX_VRF(ctx,uidb_index); -} - -void icmp_error_generate_v2 (ipv4_header *ip, u8 icmp_type, - u8 icmp_code, u16 mtu, u32 src_ip) -{ - - u16 ip_hdr_len, ip_payload_size; - u32 *src_p, * dst_p; - icmp_v4_t *icmp; - - ip_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; /* offset to ip payload */ - icmp = (icmp_v4_t*) ( (u8*)ip + ip_hdr_len); - ip_payload_size = sizeof(icmp_v4_t) + ip_hdr_len + - ICMP_UNREACHABLE_IP_PAYLOAD_SIZE; - - src_p = (u32*) - ((u8*)ip + ip_hdr_len + ICMP_UNREACHABLE_IP_PAYLOAD_SIZE - 4); - dst_p = (u32*) ((u8*)src_p + sizeof(ipv4_header) + - sizeof(icmp_v4_t)); - - while(src_p >= (u32*)ip) *dst_p-- = *src_p--; - - /* Following ICMP op has to be after ip header being copied */ - icmp->type = icmp_type; - icmp->code = icmp_code; - icmp->identifier = 0; - icmp->sequence = 0; - if(PREDICT_FALSE(mtu != 0)) { - icmp->sequence = spp_host_to_net_byte_order_16(mtu); - } - - - /* build icmp header, keep original tos, identification values */ - ip->version_hdr_len_words = 0x45; - ip->total_len_bytes = sizeof(ipv4_header) + ip_payload_size; - ip->total_len_bytes = spp_host_to_net_byte_order_16(ip->total_len_bytes); - ip->frag_flags_offset = 0; - ip->ttl = 64; - ip->protocol = ICMP_PROT; - ip->checksum = 0; - ip->dest_addr = ip->src_addr; - ip->src_addr = spp_host_to_net_byte_order_32(src_ip); - - /* calc checksum for ip and icmp */ - - calc_ipv4_checksum(ip); - calc_v4_icmp_checksum( (icmp_v4_t *) ((u8*) ip + sizeof(ipv4_header)), - ip_payload_size); -} - -void icmp_error_generate (ipv4_header *ip, u8 icmp_type, - u8 icmp_code, u16 uidb_index) { - - u16 ip_hdr_len, ip_payload_size; - u32 *src_p, * dst_p; - icmp_v4_t *icmp; - - ip_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; /* offset to ip payload */ - icmp = (icmp_v4_t*) ( (u8*)ip + ip_hdr_len); - ip_payload_size = sizeof(icmp_v4_t) + ip_hdr_len + - ICMP_UNREACHABLE_IP_PAYLOAD_SIZE; - - src_p = (u32*) - ((u8*)ip + ip_hdr_len + ICMP_UNREACHABLE_IP_PAYLOAD_SIZE - 4); - dst_p = (u32*) ((u8*)src_p + sizeof(ipv4_header) + - sizeof(icmp_v4_t)); - - while(src_p >= (u32*)ip) *dst_p-- = *src_p--; - - /* Following ICMP op has to be after ip header being copied */ - icmp->type = icmp_type; - icmp->code = icmp_code; - icmp->identifier = 0; - icmp->sequence = 0; - - - /* build icmp header, keep original tos, identification values */ - ip->version_hdr_len_words = 0x45; - ip->total_len_bytes = sizeof(ipv4_header) + ip_payload_size; - ip->total_len_bytes = spp_host_to_net_byte_order_16(ip->total_len_bytes); - ip->frag_flags_offset = 0; - ip->ttl = 64; - ip->protocol = ICMP_PROT; - ip->checksum = 0; - ip->dest_addr = ip->src_addr; - - ip->src_addr = spp_host_to_net_byte_order_32(svi_params_array[uidb_index].ipv4_addr); - - /* calc checksum for ip and icmp */ - - calc_ipv4_checksum(ip); - calc_v4_icmp_checksum( (icmp_v4_t *) ((u8*) ip + sizeof(ipv4_header)), - ip_payload_size); -#if 0 - printf("version_hdr_len_words = 0x%x\n", ip->version_hdr_len_words); - printf("total_len_bytes = 0x%x\n", ip->total_len_bytes); - printf("Frag = 0x%x\n", ip->frag_flags_offset); - printf("ttl = 0x%x\n", ip->ttl); - printf("Protocol = 0x%x\n", ip->protocol); - printf("checksum = 0x%x\n", ip->checksum); - printf("Dest addr = 0x%x\n", ip->dest_addr); - printf("Src addr = 0x%x\n", ip->src_addr); - printf("Icmp type = 0x%x\n", icmp->type); - printf("Icmp code = 0x%x\n", icmp->code); -#endif - -} - -int icmpv4_generate_with_throttling_v2 (spp_ctx_t *ctx, ipv4_header *ipv4, - int icmp_type, int icmp_code, - u16 mtu, u32 src_ip) -{ - u16 ip_hdr_len; - icmp_v4_t *icmp; - u16 rx_uidb_index = ctx->ru.rx.uidb_index; - if (icmp_msg_gen_allowed()) { - free_all_but_first_chained_buffers(ctx); - icmp_error_generate_v2(ipv4, icmp_type, icmp_code, mtu, src_ip); - ctx->current_length = (u16) - ((u8*)ctx->current_header - ctx->packet_data) + - spp_net_to_host_byte_order_16(&ipv4->total_len_bytes); - PLATFORM_CNAT_SET_TX_VRF(ctx,rx_uidb_index); - return 1; - } else { - return 0; - } -} - -int icmpv4_generate_with_throttling (spp_ctx_t *ctx, ipv4_header *ipv4, - u16 rx_uidb_index) -{ - int icmp_type; - int icmp_code; - - if (icmp_msg_gen_allowed()) { - /* ICMP error would be small, so one buffer is enough. Clear the other */ - free_all_but_first_chained_buffers(ctx); - - icmp_type = ICMPV4_TIMEEXCEEDED; - icmp_code = ICMPV4_TIMTTL; - icmp_error_generate(ipv4, icmp_type, icmp_code, rx_uidb_index); - ctx->current_length = (u16) - ((u8*)ctx->current_header - ctx->packet_data) + - spp_net_to_host_byte_order_16(&ipv4->total_len_bytes); - PLATFORM_CNAT_SET_TX_VRF(ctx,rx_uidb_index); - return 1; - } else { - return 0; - } -} - -int icmpv4_generate_with_throttling_v1 (spp_ctx_t *ctx, ipv4_header *ipv4, - u16 rx_uidb_index, u32 type, u32 code) -{ - if (icmp_msg_gen_allowed()) { - /* ICMP error would be small, so one buffer is enough. Clear the other */ - free_all_but_first_chained_buffers(ctx); - - icmp_error_generate(ipv4, type, code, rx_uidb_index); - ctx->current_length = (u16) - ((u8*)ctx->current_header - ctx->packet_data) + - spp_net_to_host_byte_order_16(&ipv4->total_len_bytes); - PLATFORM_CNAT_SET_TX_VRF(ctx,rx_uidb_index); - return 1; - } else { - return 0; - } -} - - -int icmpv6_generate_with_throttling (spp_ctx_t *ctx, ipv6_header_t *ipv6, - u16 rx_uidb_index) -{ - int icmp_type; - int icmp_code; - - if (v6_icmp_msg_gen_allowed()) { - icmp_type = ICMPV6_TIMEEXCEEDED; - icmp_code = ICMPV6_TIMTTL; - icmp_error_generate_v6(ctx, icmp_type, icmp_code, rx_uidb_index); - return 1; - } else { - return 0; - } -} - -int icmpv6_generate_with_throttling_v1 (spp_ctx_t *ctx, ipv6_header_t *ipv6, - u16 rx_uidb_index, u32 type, u32 code) -{ - - if (v6_icmp_msg_gen_allowed()) { - icmp_error_generate_v6(ctx, type, code, rx_uidb_index); - return 1; - } else { - return 0; - } -} -#endif - -void calculate_window_scale(tcp_hdr_type *tcp_header, u8 *scale) { - - u8 check_options = 0; - - *scale = 0; - check_options = ((tcp_header->flags & TCP_FLAG_SYN) && - (((tcp_header->hdr_len>>4) << 2) > sizeof(tcp_hdr_type))); - - if (PREDICT_FALSE(check_options)) { - u8 *options_ptr = tcp_findoption(tcp_header, TCP_OPTION_WINDOW_SCALE); - - /* - * TCP option field: | kind 1B | len 1B | value 2B| - * where kind != [0, 1] - */ - if (PREDICT_TRUE(options_ptr && - (options_ptr[1] == TCP_OPTION_WINDOW_SCALE))) { - u8 *ptr = (u8*)(options_ptr + 2); - *scale = *ptr; - - if(PREDICT_FALSE(*scale >= 14)) { - *scale = 14; - } - - return; - } - } -} - -#if 0 -ALWAYS_INLINE( -void cnat_log_nat44_tcp_seq_mismatch( - cnat_main_db_entry_t *db, - cnat_vrfmap_t *vrfmap)) -{ - /* As of now, Netflow does not require this to be logged - * So only syslog - */ - if(PREDICT_TRUE(db->flags & CNAT_TAC_SEQ_MISMATCH)) { - /* Already logged ..*/ - return; - } - /* else, set the flag and call the log API */ - - db->flags = db->flags | CNAT_TAC_SEQ_MISMATCH; - - cnat_syslog_nat44_tcp_seq_mismatch(db, vrfmap); -} - - -static int cnat_util_init (void *notused) -{ - /* run SPP_API_CNAT_PORTMAP_CREATE first*/ - spp_msg_api_set_handler(SPP_API_CNAT_PORT_ALLOCATE, - spp_api_cnat_port_allocate_t_handler); - - - spp_msg_api_set_handler(SPP_API_CNAT_PORT_CLEAR, - spp_api_cnat_port_clear_t_handler); - - /* run vrfmap config first */ - spp_msg_api_set_handler(SPP_API_CNAT_PORT_CREATE, - spp_api_cnat_port_create_t_handler); - - spp_msg_api_set_handler(SPP_API_CNAT_PORT_DELETE, - spp_api_cnat_port_delete_t_handler); - return 0; -} - -void -print_ipv6_pkt (ipv6_header_t *ip) -{ - u32 i, total_len, l4_len=0; - - u8 *pkt = (u8 *) ip; - - total_len = spp_net_to_host_byte_order_16(&ip->payload_length); - - /* we rarely need to debug > 200 bytes of packet */ - if(total_len > 200) { - total_len = 200; - } - - printf("\n======== PRINTING PKT START======\n"); - printf("======== IPv6 PAYLOAD LEN %d ===========\n", total_len); - for (i=0; i < 40; i++) { - printf(" %02X ", *(pkt + i)); - if(i%16==15) - printf("\n"); - } - - if (ip->next_header == IPV6_PROTO_TCP) { - printf("\n======== TCP HEADER =================\n"); - l4_len = 20; - } - else if (ip->next_header == IPV6_PROTO_UDP) { - printf("\n======== UDP HEADER =================\n"); - l4_len = 8; - } - else if (ip->next_header == IPV6_PROTO_ICMPV6) { - printf("\n======== ICMP HEADER =================\n"); - l4_len = 8; - } - - for (i=40; i < (l4_len + 40); i++) { - printf(" %02X ", *(pkt + i)); - } - - printf("\n======== LAYER4 PAYLOAD ===================\n"); - for (i=(l4_len + 40); i < total_len; i++) { - printf(" %02X ", *(pkt + i)); - if(i%16==15) - printf("\n"); - } - - printf("\n======== PRINTING PKT END =======\n"); -} - - - -PLATFORM_SPP_INIT_FUNCTION(cnat_util_init); -#endif diff --git a/plugins/vcgn-plugin/vcgn/cnat_v4_ftp_alg.h b/plugins/vcgn-plugin/vcgn/cnat_v4_ftp_alg.h deleted file mode 100644 index df3dfcb0..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_v4_ftp_alg.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_v4_ftp_alg.h - * - * Copyright (c) 2012-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef __CNAT_V4_FTP_ALG_H__ -#define __CNAT_V4_FTP_ALG_H__ - - -#include -#include - -#include "tcp_header_definitions.h" -#include "dslite_defs.h" -#include "dslite_db.h" - -/* shorter form of byte order functions */ - -#define net2host16(x) clib_net_to_host_u16( x) -#define net2host32(x) clib_net_to_host_u32( x) -#define net2host64(x) clib_net_to_host_u64( x) -#define host2net16(x) clib_host_to_net_u16(x) -#define host2net32(x) clib_host_to_net_u32(x) -#define host2net64(x) clib_host_to_net_u64(x) - -//#define BIGENDIAN - -typedef struct iphdrtype_ { - u8 v_ihl; /* version and IP header length */ - u8 tos; /* type of service */ - u16 tl; /* total length */ - u16 id; /* identifier */ - u16 ipreserved: 1; - u16 dontfragment: 1; - u16 morefragments: 1; - u16 fo: 13; /* fragment offset */ - u8 ttl; /* time to live */ - u8 prot; /* protocol type */ - u16 checksum; /* checksum */ - u32 srcadr; /* IP source address */ - u32 dstadr; /* IP destination address */ -} iphdrtype; - - -typedef struct tcptype_ { - u16 sourceport; - u16 destinationport; - u32 sequencenumber; - u32 acknowledgementnumber; - u8 dataoffset; - u8 flags; -#if 0 -/* bypass the ENDIAN part */ -#ifdef BIGENDIAN - u8 reserved: 2; - u8 urg: 1; - u8 ack: 1; - u8 psh: 1; - u8 rst: 1; - u8 syn: 1; - u8 fin: 1; -#else - u8 fin: 1; - u8 syn: 1; - u8 rst: 1; - u8 psh: 1; - u8 ack: 1; - u8 urg: 1; - u8 reserved2: 2; -#endif -#endif - - u16 window; - u16 checksum; - u16 urgentpointer; - u8 data[0]; -} tcptype ; - - -int watch_ftp_port_cmd (iphdrtype *ip, - tcptype *tcp, - u32 * ip_addr, - u16 * port); - - -u8 * ftp_test_pkt_gen (u32 ip_addr, u16 port); - -int update_ftp_port(u8 * pkt, u32 new_ip, u16 new_port, i8 * delta, - cnat_main_db_entry_t *db_tcp_control, - dslite_table_entry_t *dslite_entry_ptr, - ipv6_header_t *ipv6_hdr); -/* - * caller needs to check if it's a ftp packet - * this function returns 1 - * if packet being updated for PORT - * otherwise return 0. - * Assume IP header DOES NOT have option fields - */ - -int cnat_ftp_alg ( u8* pkt, i8 * delta, cnat_main_db_entry_t *db, - dslite_table_entry_t *dslite_entry_ptr, - ipv6_header_t *ipv6_hdr); - -#define FTP_ALG_DEBUG_PRINTF_ENABLED 1 - -#ifdef FTP_ALG_DEBUG_PRINTF_ENABLED - -#define FTP_ALG_DEBUG_PRINTF(...) { \ - if (global_debug_flag & CNAT_DEBUG_FTP_ALG) { \ - printf(__VA_ARGS__); \ - } } - -#else - -#define FTP_ALG_DEBUG_PRINTF(...) - -#endif - -#endif /* __CNAT_V4_FTP_ALG_H__ */ diff --git a/plugins/vcgn-plugin/vcgn/cnat_v4_functions.c b/plugins/vcgn-plugin/vcgn/cnat_v4_functions.c deleted file mode 100644 index d3051fba..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_v4_functions.c +++ /dev/null @@ -1,364 +0,0 @@ -/* - *--------------------------------------------------------------------------- - * cnat_v4_funtions.c - * - * Copyright (c) 2008-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *--------------------------------------------------------------------------- - */ -#include -#include -#include -#include - - -#include "tcp_header_definitions.h" -#include "cnat_db.h" -#include "cnat_config.h" -#include "cnat_v4_functions.h" -#include "dslite_defs.h" -#include "dslite_db.h" - -static u32 tcp_logging_count; -static u32 tcp_logging_overflow; - -static tcp_logging_struct_t tcp_logging_array[MAX_TCP_LOGGING_COUNT]; - -/* - * Function to log TCP pkts checksum changes.. - */ -void -tcp_debug_logging ( - u32 seq_num, - u32 ack_num, - u32 old_ip, - u32 new_ip, - u16 old_port, - u16 new_port, - u16 old_ip_crc, - u16 new_ip_crc, - u16 old_tcp_crc, - u16 new_tcp_crc) -{ - tcp_logging_array[tcp_logging_count].seq_num = seq_num; - tcp_logging_array[tcp_logging_count].ack_num = ack_num; - tcp_logging_array[tcp_logging_count].old_ip = old_ip; - tcp_logging_array[tcp_logging_count].new_ip = new_ip; - tcp_logging_array[tcp_logging_count].old_port = old_port; - tcp_logging_array[tcp_logging_count].new_port = new_port; - tcp_logging_array[tcp_logging_count].old_ip_crc = old_ip_crc; - tcp_logging_array[tcp_logging_count].new_ip_crc = new_ip_crc; - tcp_logging_array[tcp_logging_count].old_tcp_crc = old_tcp_crc; - tcp_logging_array[tcp_logging_count].new_tcp_crc = new_tcp_crc; - - tcp_logging_count++; - - if (tcp_logging_count >= MAX_TCP_LOGGING_COUNT) { - tcp_logging_overflow = 1; - tcp_logging_count = 0; - } -} - -/* - * Function to dmp TCP pkts logged.. - */ -void -tcp_debug_logging_dump (void) -{ - u32 i, total_count, start_entry; - - if (tcp_logging_overflow) { - total_count = MAX_TCP_LOGGING_COUNT; - start_entry = tcp_logging_count; - printf("Logging Entries Wrapped Around, displaying %d entries\n", - total_count); - } else { - total_count = tcp_logging_count; - start_entry = 0; - printf("Displaying %d entries\n", total_count); - } - - printf("SEQ ACK IP_O IP_N PORT_O PORT_N L3_CRC_O L3_CRC_N L4_CRC_O L4_CRC_N\n"); - - for (i = 0; i < total_count; i++) { - u32 entry = (i + start_entry) % MAX_TCP_LOGGING_COUNT; - - printf("%04d: 0x%08x 0x%08x 0x%08x 0x%08x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", - entry, - tcp_logging_array[entry].seq_num, - tcp_logging_array[entry].ack_num, - tcp_logging_array[entry].old_ip, - tcp_logging_array[entry].new_ip, - tcp_logging_array[entry].old_port, - tcp_logging_array[entry].new_port, - tcp_logging_array[entry].old_ip_crc, - tcp_logging_array[entry].new_ip_crc, - tcp_logging_array[entry].old_tcp_crc, - tcp_logging_array[entry].new_tcp_crc); - } -} - -/* - * Function to enable TCP logging - */ -void -tcp_debug_logging_enable_disable (u32 enable_flag) -{ - switch (enable_flag) { - - case TCP_LOGGING_DISABLE: - if (tcp_logging_enable_flag == TCP_LOGGING_DISABLE) { - printf("\nTCP Logging ALREADY DISABLED\n"); - } else { - printf("\nTCP Logging DISABLED\n"); - } - tcp_logging_enable_flag = 0; - break; - - case TCP_LOGGING_ENABLE: - if (tcp_logging_enable_flag == TCP_LOGGING_ENABLE) { - printf("\nTCP Logging ALREADY ENABLED\n"); - } else { - tcp_logging_enable_flag = 1; - tcp_logging_count = 0; - tcp_logging_overflow = 0; - - printf("\nTCP Logging ENABLED\n"); - } - break; - - case TCP_LOGGING_PACKET_DUMP: - tcp_debug_logging_dump(); - break; - - case TCP_LOGGING_SUMMARY_DUMP: - default: - printf("\ntcp_logging_enable_flag %d, tcp_log_count %d\n", - tcp_logging_enable_flag, tcp_logging_count); - printf("To Enable TCP LOGGING provide a flag value of %d\n", - TCP_LOGGING_ENABLE); - break; - } -} - -void hex_dump (u8 * p, int len) { - int i; - for (i=0;itotal_len_bytes); - - printf("\n======== PRINTING PKT START======\n"); - printf("======== IP PACKET LEN %d ===========\n", total_len); - for (i=0; i < 20; i++) { - printf(" %02X ", *(pkt + i)); - } - - printf("\n======== ICMP HEADER =================\n"); - for (i=20; i < 28; i++) { - printf(" %02X ", *(pkt + i)); - } - - printf("\n======== ICMP BODY ===================\n"); - for (i=28; i < total_len; i++) { - printf(" %02X ", *(pkt + i)); - } - - printf("\n======== PRINTING PKT END =======\n"); -} - -void -print_udp_pkt (ipv4_header *ip) -{ - u32 i, total_len, udp_len; - - u8 *pkt = (u8 *) ip; - - total_len = clib_net_to_host_u16(ip->total_len_bytes); - udp_len = total_len - 20; - - printf("\n======== PRINTING PKT START======\n"); - printf("======== IP PACKET LEN %d ===========\n", total_len); - for (i=0; i < 20; i++) { - printf(" %02X ", *(pkt + i)); - } - printf("\n======== UDP PSEUDO HEADER ==========\n"); - for (i=12; i < 20; i++) { - printf(" %02X ", *(pkt + i)); - } - printf(" 00 11 %02X %02X ", udp_len >> 8, udp_len & 0xff); - - printf("\n======== UDP HEADER =================\n"); - for (i=20; i < 28; i++) { - printf(" %02X ", *(pkt + i)); - } - printf("\n======== UDP BODY ===================\n"); - for (i=28; i < total_len; i++) { - printf(" %02X ", *(pkt + i)); - } - - printf("\n======== PRINTING PKT END =======\n"); -} - -void -print_tcp_pkt (ipv4_header *ip) -{ - u32 i, total_len, tcp_len; - - u8 *pkt = (u8 *) ip; - - total_len = clib_net_to_host_u16(ip->total_len_bytes); - tcp_len = total_len - 20; - - printf("\n======== PRINTING PKT START======\n"); - printf("======== IP PACKET LEN %d ===========\n", total_len); - for (i=0; i < 20; i++) { - printf(" %02X ", *(pkt + i)); - } - printf("\n======== TCP PSEUDO HEADER ==========\n"); - for (i=12; i < 20; i++) { - printf(" %02X ", *(pkt + i)); - } - printf(" 00 06 %02X %02X ", tcp_len >> 8, tcp_len & 0xff); - - printf("\n======== TCP HEADER =================\n"); - for (i=20; i < 40; i++) { - printf(" %02X ", *(pkt + i)); - } - printf("\n======== TCP BODY ===================\n"); - for (i=40; i < total_len; i++) { - printf(" %02X ", *(pkt + i)); - } - - printf("\n======== PRINTING PKT END =======\n"); -} - -/* IN: ipv4 and tcp header pointer, - * new ipv4 addr and port value - * main db index for accessing per vrf mss value - * DO: - * NAT - * mss adjust if needed - * ip & tcp checksum update (incremental) - */ - -inline void tcp_in2out_nat_mss_n_checksum (ipv4_header * ip, - tcp_hdr_type * tcp, - u32 ipv4_addr, - u16 port, - cnat_main_db_entry_t * db) -{ - u8 *mss_ptr; - u8 check_mss = 0; - u16 mss_old, mss_new; - cnat_vrfmap_t * vrf_map_p; - - cnat_v4_recalculate_tcp_checksum(ip, - tcp, - &(ip->src_addr), - &(tcp->src_port), - ipv4_addr, - port); - u16 frag_offset = - clib_net_to_host_u16(ip->frag_flags_offset); - - if(PREDICT_FALSE(frag_offset & IP_FRAG_OFFSET_MASK)) { - return; /* No TCP Header at all */ - } - - /* - * check SYN bit and if options field is present - * If yes, proceed to extract the options and get TCP MSS value - */ - check_mss = ((tcp->flags & TCP_FLAG_SYN) && - (((tcp->hdr_len>>4) << 2) > sizeof(tcp_hdr_type))); - - if (PREDICT_FALSE(check_mss)) { - - /* get per VRF mss config */ - if(PREDICT_FALSE(db->flags & (CNAT_DB_DSLITE_FLAG))) { - mss_new = dslite_table_db_ptr[db->dslite_nat44_inst_id].tcp_mss; - } else { - vrf_map_p = cnat_map_by_vrf + db->vrfmap_index; - mss_new = vrf_map_p->tcp_mss; - } - DSLITE_PRINTF(1, "Check MSS true..%u\n", mss_new); - /* - * If TCP MSS is not configured, skip the MSS checks - */ - if (PREDICT_FALSE(mss_new != V4_TCP_MSS_NOT_CONFIGURED_VALUE)) { - - /* if mss_ptr != NULL, then it points to MSS option */ - mss_ptr = tcp_findoption(tcp, TCP_OPTION_MSS); - - /* - * TCP option field: | kind 1B | len 1B | value 2B| - * where kind != [0,1] - */ - if (PREDICT_TRUE(mss_ptr && (mss_ptr[1] == 4))) { - - u16 *ptr = (u16*)(mss_ptr + 2); - - mss_old = clib_net_to_host_u16(*ptr); - - if (PREDICT_FALSE(mss_old > mss_new)) { - u32 sum32; - u16 mss_old_r, old_tcp_checksum_r; - - *ptr = clib_host_to_net_u16(mss_new); - - mss_old_r = ~mss_old; - - old_tcp_checksum_r = - ~clib_net_to_host_u16(tcp->tcp_checksum); - - /* - * Revise the TCP checksum - */ - sum32 = old_tcp_checksum_r + mss_old_r + mss_new; - FILL_CHECKSUM(tcp->tcp_checksum, sum32) - - if (PREDICT_FALSE(tcp_logging_enable_flag)) { - tcp_debug_logging( - clib_net_to_host_u32(tcp->seq_num), - clib_net_to_host_u32(tcp->ack_num), - 0, - 0, - mss_old, - mss_new, - 0, - 0, - ~old_tcp_checksum_r, - clib_net_to_host_u16(tcp->tcp_checksum)); - } - } - } - } - } -} - -u32 get_my_svi_intf_ip_addr() { - return 0x01010101; -} diff --git a/plugins/vcgn-plugin/vcgn/cnat_v4_functions.h b/plugins/vcgn-plugin/vcgn/cnat_v4_functions.h deleted file mode 100644 index 2429e5e1..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_v4_functions.h +++ /dev/null @@ -1,342 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_v4_functions.h - * - * Copyright (c) 2007-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef __CNAT_V4_FUNCTOINS__ -#define __CNAT_V4_FUNCTOINS__ - -#include "tcp_header_definitions.h" -#include "cnat_db.h" -#include "spp_ctx.h" - -#include "platform_common.h" - -/* - * Defines and structures to enable TCP packet logging - */ -#define TCP_LOGGING_DISABLE 0 -#define TCP_LOGGING_ENABLE 1 -#define TCP_LOGGING_PACKET_DUMP 2 -#define TCP_LOGGING_SUMMARY_DUMP 3 - -#define MAX_TCP_LOGGING_COUNT 1024 - -typedef struct tcp_logging_struct { - u32 seq_num; - u32 ack_num; - u32 old_ip; - u32 new_ip; - u16 old_port; - u16 new_port; - u16 old_ip_crc; - u16 new_ip_crc; - u16 old_tcp_crc; - u16 new_tcp_crc; -} tcp_logging_struct_t; - -void tcp_debug_logging_dump (void); -void tcp_debug_logging_enable_disable (u32 enable_flag); - -void -tcp_debug_logging ( - u32 seq_num, - u32 ack_num, - u32 old_ip, - u32 new_ip, - u16 old_port, - u16 new_port, - u16 old_ip_crc, - u16 new_ip_crc, - u16 old_tcp_crc, - u16 new_tcp_crc); - -#define JLI printf("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); fflush(stdout); - -#define CNAT_ICMP_DEST_UNREACHABLE 100 -#define INCREMENT_NODE_COUNTER(c) \ - em->counters[node_counter_base_index + c] += 1; - -#define V4_TCP_UPDATE_SESSION_FLAG(db, tcp) \ -if ((tcp->flags & TCP_FLAG_ACK) && (tcp->flags & TCP_FLAG_SYN)) { \ - db->flags |= CNAT_DB_FLAG_TCP_ACTIVE; \ -} \ -if ((tcp->flags & TCP_FLAG_RST) || (tcp->flags & TCP_FLAG_FIN)) { \ - db->flags &= ~CNAT_DB_FLAG_TCP_ACTIVE; \ - db->flags |= CNAT_DB_FLAG_TCP_CLOSING; \ -} - -#define V4_TCP_UPDATE_SESSION_DB_FLAG(sdb, tcp) \ -if ((tcp->flags & TCP_FLAG_ACK) && (tcp->flags & TCP_FLAG_SYN)) { \ - sdb->flags |= CNAT_DB_FLAG_TCP_ACTIVE; \ -} \ -if ((tcp->flags & TCP_FLAG_RST) || (tcp->flags & TCP_FLAG_FIN)) { \ - sdb->flags &= ~CNAT_DB_FLAG_TCP_ACTIVE; \ - sdb->flags |= CNAT_DB_FLAG_TCP_CLOSING; \ -} - -/* - * Code to recalculate checksum after ACK/SEQ number changes - * This macro assumes, we have pointer to tcp structure - * referenced by the name "tcp" - */ -#define CNAT_UPDATE_TCP_SEQ_ACK_CHECKSUM(old_val32, new_val32) \ -{ \ - u16 old_val_lower, old_val_upper, old_tcp_cr; \ - u16 new_val_lower, new_val_upper, new_tcp_cr; \ - u32 sum32; \ - \ - old_val_lower = ~((u16) old_val32); \ - old_val_upper = ~((u16) (old_val32 >> 16)); \ - old_tcp_cr = ~net2host16(&tcp->tcp_checksum); \ - new_val_lower = (u16) new_val32; \ - new_val_upper = (u16) (new_val32 >> 16); \ - \ - sum32 = old_val_lower + old_val_upper + old_tcp_cr + \ - new_val_lower + new_val_upper; \ - \ - sum32 = (sum32 & 0xffff) + ((sum32 >> 16) & 0xffff); \ - sum32 = (sum32 & 0xffff) + ((sum32 >> 16) & 0xffff); \ - new_tcp_cr = ~((u16)sum32); \ - \ - tcp->tcp_checksum = host2net16(new_tcp_cr); \ -} - -/* - * newchecksum = ~(~oldchecksum + ~old + new) - * old/new for l3 checksum: ip address - */ -#define CNAT_UPDATE_L3_CHECKSUM_DECLARE \ -u16 old_l3_1r, old_l3_2r; \ -u16 old_l3_cr, new_l3_c; \ -u32 new32; - -#define CNAT_UPDATE_L3_CHECKSUM(old_l3_1, old_l3_2, old_l3_c, \ - new_l3_1, new_l3_2) \ -old_l3_1r = ~(old_l3_1); \ -old_l3_2r = ~(old_l3_2); \ -old_l3_cr = ~(old_l3_c); \ -new32 = old_l3_cr + old_l3_1r + old_l3_2r + new_l3_1 + new_l3_2; \ -new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \ -new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \ -new_l3_c = ~((u16)new32); - - -/* - * newchecksum = ~(~oldchecksum + ~old + new) - * old/new for l3 checksum: ip address - * old/new for l4 checksum: ip address and port - */ -#define CNAT_UPDATE_L3_L4_CHECKSUM_DECLARE \ -u16 old_l3_1r, old_l3_2r, old_l4r; \ -u16 old_l3_cr, old_l4_cr; \ -u16 new_l3_c, new_l4_c; \ -u32 sum32, new32; - -#define CNAT_UPDATE_L3_L4_CHECKSUM(old_l3_1, old_l3_2, old_l4, \ - old_l3_c, old_l4_c, \ - new_l3_1, new_l3_2, new_l4) \ -old_l3_1r = ~(old_l3_1); \ -old_l3_2r = ~(old_l3_2); \ -old_l3_cr = ~(old_l3_c); \ -sum32 = old_l3_1r + old_l3_2r + new_l3_1 + new_l3_2; \ -new32 = old_l3_cr + sum32; \ -new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \ -new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \ -new_l3_c = ~((u16)new32); \ -old_l4r = ~(old_l4); \ -old_l4_cr = ~(old_l4_c); \ -sum32 += old_l4r + new_l4; \ -new32 = old_l4_cr + sum32; \ -new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \ -new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \ -new_l4_c = ~((u16)new32); - -/* - * For ICMP checksums, we don't use the top IP header for checksum calculation - */ -#define CNAT_UPDATE_L3_ICMP_CHECKSUM(old_l3_1, old_l3_2, old_l4, \ - old_l3_c, old_l4_c, \ - new_l3_1, new_l3_2, new_l4) \ -old_l3_1r = ~(old_l3_1); \ -old_l3_2r = ~(old_l3_2); \ -old_l3_cr = ~(old_l3_c); \ -sum32 = old_l3_1r + old_l3_2r + new_l3_1 + new_l3_2; \ -new32 = old_l3_cr + sum32; \ -new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \ -new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \ -new_l3_c = ~((u16)new32); \ -old_l4r = ~(old_l4); \ -old_l4_cr = ~(old_l4_c); \ -sum32 = old_l4r + new_l4; \ -new32 = old_l4_cr + sum32; \ -new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \ -new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \ -new_l4_c = ~((u16)new32); - - -/* - * icmp error type message: - * newchecksum = ~(~oldchecksum + ~old + new) - * old/new for outlayer ip checksum: ip address - * old/new for outlayer icmp checksum: - * out-layer: ip address - * inner-layer: ip addr, port, l3 checksum, l4 checksum - */ -#define CNAT_UPDATE_ICMP_ERR_CHECKSUM_DECLARE \ -u16 old_ip_1r, old_ip_2r, old_ip_port_r, old_ip_cr, old_icmp_cr; \ -u16 new_icmp_c; \ -u32 sum32; - - -#define CNAT_UPDATE_ICMP_ERR_CHECKSUM(old_ip_1, old_ip_2, old_ip_port, old_ip_c, old_icmp_c, \ - new_ip_1, new_ip_2, new_ip_port, new_ip_c) \ -old_ip_1r = ~(old_ip_1); \ -old_ip_2r = ~(old_ip_2); \ -old_ip_port_r = ~(old_ip_port); \ -old_ip_cr = ~(old_ip_c); \ -old_icmp_cr = ~(old_icmp_c); \ -sum32 = old_ip_1r + old_ip_2r + new_ip_1 + new_ip_2 + \ - old_ip_port_r + new_ip_port + old_ip_cr + new_ip_c; \ -new32 = old_icmp_cr + sum32; \ -new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \ -new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \ -new_icmp_c = ~((u16)new32); \ - -/* - * Add the two 16 bit parts of the 32 bit field - * Repeat it one more time to take care of any overflow - * Complement the u16 value and store it in network format - */ -#define FILL_CHECKSUM(checksum_field, sum32) { \ - sum32 = (sum32 & 0xffff) + ((sum32>>16) & 0xffff); \ - sum32 = (sum32 & 0xffff) + ((sum32>>16) & 0xffff); \ - checksum_field = clib_host_to_net_u16(~((u16) sum32)); \ -} - -static inline void -cnat_v4_recalculate_tcp_checksum (ipv4_header *ip, - tcp_hdr_type *tcp, - u32 *ip_addr_ptr, - u16 *tcp_port_addr_ptr, - u32 new_ip, - u16 new_port) -{ - u32 old_ip_addr, old_ip32_r, new_ip32, sum32; - u16 old_port_r, old_ip_checksum_r, old_tcp_checksum_r; - - u16 *p16; - - p16 = (u16*) ip_addr_ptr; - - old_ip_addr = *ip_addr_ptr; - old_ip32_r = (((u16) ~clib_net_to_host_u16(*p16)) + - ((u16) ~clib_net_to_host_u16(*(p16+1)))); - - old_port_r = ~clib_net_to_host_u16(*tcp_port_addr_ptr); - - *ip_addr_ptr = clib_host_to_net_u32(new_ip); - - new_ip32 = (new_ip & 0xffff) + ((new_ip >> 16) & 0xffff); - - old_ip_checksum_r = ~clib_net_to_host_u16(ip->checksum); - - /* - * Recalculate the new IP checksum - */ - sum32 = old_ip32_r + new_ip32 + old_ip_checksum_r; - - FILL_CHECKSUM(ip->checksum, sum32); - - u16 frag_offset = - clib_net_to_host_u16((ip->frag_flags_offset)); - - if(PREDICT_FALSE(frag_offset & IP_FRAG_OFFSET_MASK)) { - return; /* No need to update TCP fields */ - } - - *tcp_port_addr_ptr = clib_host_to_net_u16(new_port); - old_tcp_checksum_r = ~clib_net_to_host_u16(tcp->tcp_checksum); - - /* - * Recalculate the new TCP checksum - */ - sum32 = old_ip32_r + new_ip32 + - old_port_r + new_port + old_tcp_checksum_r; - - FILL_CHECKSUM(tcp->tcp_checksum, sum32); - - if (PREDICT_FALSE(tcp_logging_enable_flag)) { - tcp_debug_logging( - clib_net_to_host_u32(tcp->seq_num), - clib_net_to_host_u32(tcp->ack_num), - clib_net_to_host_u32(old_ip_addr), - clib_net_to_host_u32(*ip_addr_ptr), - ~old_port_r, - clib_net_to_host_u16(*tcp_port_addr_ptr), - ~old_ip_checksum_r, - clib_net_to_host_u16(ip->checksum), - ~old_tcp_checksum_r, - clib_net_to_host_u16(tcp->tcp_checksum)); - } -} - - -extern void tcp_in2out_nat_mss_n_checksum (ipv4_header *ip, - tcp_hdr_type *tcp, - u32 ipv4_addr, - u16 port, - cnat_main_db_entry_t * db); - -void hex_dump(u8 * p, int len); - -u32 get_my_svi_intf_ip_addr(); - -/* - * in cnat_v4_icmp_gen.c, - * return 1 if icmp msg allow to generate - * for this user - */ - -u32 icmp_msg_gen_allowed (); - -cnat_icmp_msg_t v6_icmp_msg_gen_allowed(); - -int v4_crc_zero_udp_allowed(); -void ipv4_decr_ttl_n_calc_csum(ipv4_header *ipv4); -int icmpv4_generate_with_throttling (spp_ctx_t *ctx, ipv4_header *ipv4, - u16 rx_uidb_index); - -int icmpv6_generate_with_throttling (spp_ctx_t *ctx, ipv6_header_t *ipv4, - u16 rx_uidb_index); - -void icmp_error_generate_v6(spp_ctx_t *ctx, u8 icmp_type, - u8 icmp_code, u16 uidb_index); - -void calculate_window_scale(tcp_hdr_type *tcp_header, u8 *scale); - -void cnat_log_nat44_tcp_seq_mismatch( - cnat_main_db_entry_t *db, - cnat_vrfmap_t *vrfmap); -void print_icmp_pkt (ipv4_header *ip); -void print_udp_pkt (ipv4_header *ip); -void print_tcp_pkt (ipv4_header *ip); -void print_ipv6_pkt (ipv6_header_t *ip); - - -#endif - diff --git a/plugins/vcgn-plugin/vcgn/cnat_v4_pptp_alg.h b/plugins/vcgn-plugin/vcgn/cnat_v4_pptp_alg.h deleted file mode 100644 index 5a6d4243..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_v4_pptp_alg.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_v4_pptp_alg.h - * - * Copyright (c) 2009-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef __CNAT_V4_PPTP_ALG_H__ -#define __CNAT_V4_PPTP_ALG_H__ - -/* Debug utils of PPTP */ -#define PPTP_DBG(debug, ...) \ - if(PREDICT_FALSE(cnat_pptp_debug_flag >= debug)) { \ - PLATFORM_DEBUG_PRINT("%s:%s:%d - ", \ - __FILE__, __FUNCTION__, __LINE__);\ - PLATFORM_DEBUG_PRINT(__VA_ARGS__);\ - PLATFORM_DEBUG_PRINT("\n"); \ - } - -#define PPTP_DUMP_PACKET(ip, len) pptp_hex_dump(ip, len) - - -#define PPTP_DISABLED 0 -#define PPTP_ENABLED 1 - -#define PPTP_GRE_TIMEOUT 60 /*sec */ - -#define TCP_PPTP_PORT 1723 - -#define PPTP_PAC 0 -#define PPTP_PNS 1 - -/* PPTP MSG TYPE */ - -#define PPTP_MSG_TYPE_CONTROL 1 -#define PPTP_MSG_TYPE_MGMT 2 - -/* PPTP control messages */ - -/* control connection mgmt */ -#define PPTP_START_CC_RQ 1 -#define PPTP_START_CC_RP 2 -#define PPTP_STOP_CC_RQ 3 -#define PPTP_STOP_CC_RP 4 -#define PPTP_ECHO_RQ 5 -#define PPTP_ECHO_RP 6 - -/* call mgmt */ -#define PPTP_OBOUND_CALL_RQ 7 -#define PPTP_OBOUND_CALL_RP 8 -#define PPTP_IBOUND_CALL_RQ 9 -#define PPTP_IBOUND_CALL_RP 10 -#define PPTP_IBOUND_CALL_CN 11 -#define PPTP_CALL_CLEAR_RQ 12 -#define PPTP_CALL_DISCON_NT 13 - -/* other */ - -#define PPTP_WAN_ERR_NT 14 -#define PPTP_SET_LINK_INF 15 - -#define PPTP_MIN_HDR_LEN 8 - -/* Byte offsets from start of TCP Data(PPTP header) */ - -#define PPTP_CTRL_MGMT_TYPE_OFFSET 0x02 -#define PPTP_CC_TYPE_OFFSET 0x08 -#define PPTP_HDR_CALL_ID_OFFSET 0x0c -#define PPTP_HDR_PEER_CALL_ID_OFFSET 0x0e - -#define PPTP_HDR_RESULT_CODE_OFFSET_STCCRP 0x0e -#define PPTP_HDR_RESULT_CODE_OFFSET 0x10 - - -/* Offset of control/mgmt msg types - from start of TCP header */ - -#define TCP_HEADER_SIZE(tcp) \ - ((tcp->hdr_len>>4) << 2) - - -#define PPTP_MSG_START_OFFSET(tcp) \ - ((u8*)tcp + TCP_HEADER_SIZE(tcp)) - - -#define PPTP_CC_MSG_TYPE_OFFSET(tcp) \ - (PPTP_MSG_START_OFFSET(tcp) + \ - PPTP_CC_TYPE_OFFSET ) - -#define PPTP_MGMT_MSG_TYPE_OFFSET(tcp) \ - ( PPTP_MSG_START_OFFSET(tcp) + \ - PPTP_CTRL_MGMT_TYPE_OFFSET ) - -#define PPTP_CALL_ID_OFFSET(tcp) \ - ( PPTP_MSG_START_OFFSET(tcp) + \ - PPTP_HDR_CALL_ID_OFFSET ) - -#define PPTP_PEER_CALL_ID_OFFSET(tcp) \ - ( PPTP_MSG_START_OFFSET(tcp) + \ - PPTP_HDR_PEER_CALL_ID_OFFSET ) - -#define PPTP_RESULT_CODE_OFFSET(tcp) \ - ( PPTP_MSG_START_OFFSET(tcp) + \ - PPTP_HDR_RESULT_CODE_OFFSET ) - -#define PPTP_RESULT_CODE_OFFSET_STCCRP(tcp) \ - ( PPTP_MSG_START_OFFSET(tcp) + \ - PPTP_HDR_RESULT_CODE_OFFSET_STCCRP) - -/* values */ -#define PPTP_CC_MSG_TYPE(tcp) \ - (u16*)PPTP_CC_MSG_TYPE_OFFSET(tcp) - -#define PPTP_MGMT_MSG_TYPE(tcp) \ - (u16*)PPTP_MGMT_MSG_TYPE_OFFSET(tcp) - -#define PPTP_CALL_ID(tcp) \ - (u16*)PPTP_CALL_ID_OFFSET(tcp) - -#define PPTP_PEER_CALL_ID(tcp) \ - (u16*)PPTP_PEER_CALL_ID_OFFSET(tcp) - -#define PPTP_RESULT_CODE(tcp) \ - *(u8*)PPTP_RESULT_CODE_OFFSET(tcp); - -#define PPTP_RESULT_CODE_STCCRP(tcp) \ - *(u8*)PPTP_RESULT_CODE_OFFSET_STCCRP(tcp); - - -/* other code */ -#define PPTP_CHAN_SUCCESS 1 - - -/* Data structures */ - -extern u32 cnat_pptp_debug_flag; - -#endif /* __CNAT_V4_PPTP_ALG_H__ */ diff --git a/plugins/vcgn-plugin/vcgn/cnat_v4_tcp_in2out_stages.c b/plugins/vcgn-plugin/vcgn/cnat_v4_tcp_in2out_stages.c deleted file mode 100644 index 220ced46..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_v4_tcp_in2out_stages.c +++ /dev/null @@ -1,679 +0,0 @@ -/* - *--------------------------------------------------------------------------- - * cnat_v4_tcp_in2out_stages.c - cnat_v4_tcp_in2out node pipeline stage functions - * - * - * Copyright (c) 2008-2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *--------------------------------------------------------------------------- - */ - -#include -#include -#include -#include - -#include "cnat_db.h" -/* #include */ -#include "ipv4_packet.h" -#include "tcp_header_definitions.h" -#include "cnat_config.h" -#include "cnat_global.h" -#include "cnat_v4_functions.h" -#include "cnat_v4_ftp_alg.h" -#include "cnat_v4_pptp_alg.h" - -#define foreach_cnat_ipv4_tcp_inside_input_error \ -_(TCP_NAT_IN, "packets received") \ -_(TCP_NAT, "packets NATed") \ -_(TCP_EXCEPTION, "packets to exception") \ -_(TCP_TTL_GEN, "Generated TTL Expiry ICMP packet") \ -_(TCP_TTL_DROP, "Could not generate TTL Expiry ICMP packet") \ -_(TCP_SESSION_DROP, "Could not generate session") \ -_(TCP_FRAG_DROP, "Non-first Fragment received") - -typedef enum { -#define _(sym,str) sym, - foreach_cnat_ipv4_tcp_inside_input_error -#undef _ - CNAT_IPV4_TCP_INSIDE_INPUT_N_ERROR, -} cnat_ipv4_tcp_inside_input_t; - -static char * cnat_ipv4_tcp_inside_input_error_strings[] = { -#define _(sym,string) string, - foreach_cnat_ipv4_tcp_inside_input_error -#undef _ - - - -typedef struct cnat_v4_tcp_in2out_pipeline_data_ { - spp_node_main_vector_t *nmv; - /* Add additional pipeline stage data here... */ - u32 bucket; - u16 src_port; /* Added for handling fragments */ - u16 dst_port; /* Added for handling fragments */ -} cnat_v4_tcp_in2out_pipeline_data_t; - -static cnat_v4_tcp_in2out_pipeline_data_t pctx_data[SPP_MAXDISPATCH]; - -#define EXTRA_PIPELINE_ARGS_PROTO , cnat_v4_tcp_in2out_pipeline_data_t *pctx -#define EXTRA_PIPELINE_ARGS , pctx - -ALWAYS_INLINE( -static inline void -stage0(spp_ctx_t **ctxs, int index, spp_node_t *np, - u8 *disp_used EXTRA_PIPELINE_ARGS_PROTO)) -{ - spp_ctx_t *ctx = ctxs[index]; - /* - * Prefetch the context header. This is almost always - * the right thing to do - */ - SPP_PREFETCH_CTX(ctx); -} - -ALWAYS_INLINE( -static inline void -stage1(spp_ctx_t **ctxs, int index, spp_node_t *np, - u8 *disp_used EXTRA_PIPELINE_ARGS_PROTO)) -{ - spp_ctx_t *ctx = ctxs[index]; - /* got ctx, prefetch packet data separately */ - SPP_PREFETCH_CTX_DATA(ctx, 1*CACHE_DATA_QUANTUM); -} - -ALWAYS_INLINE( -static inline void -stage2(spp_ctx_t **ctxs, int index, spp_node_t *np, - u8 *disp_used EXTRA_PIPELINE_ARGS_PROTO)) -{ - spp_ctx_t *ctx = ctxs[index]; - u64 a, b, c; - u32 bucket; - cnat_feature_data_t *fd = (cnat_feature_data_t *)ctx->feature_data; - ipv4_header *ip; - tcp_hdr_type * tcp; - u8 *prefetch_target; - - INCREMENT_NODE_COUNTER(np, TCP_NAT_IN); - - /* extract the key from ctx and save it to feature_data */ - - ip = (ipv4_header *)(ctx->current_header); - ctx->application_start = (ip->version_hdr_len_words & 0xf) << 2; - tcp = (tcp_hdr_type*) ((u8 *)ip + ctx->application_start); - - PLATFORM_CNAT_SET_RX_VRF(ctx,fd->dbl.k.k.vrf, CNAT_TCP, 1); - fd->dbl.k.k.ipv4 = spp_net_to_host_byte_order_32(&ip->src_addr); - - if(PREDICT_FALSE(ctx->ru.rx.frag)) { - /* Must have routed through cnat_v4_frag_in2out node - * Since feature data of the ctx is being used for other - * purposes here, copy them to extra stage argument - */ - u16 *feature_data_ports = (u16 *)&ctx->feature_data[2]; - pctx[index].src_port = fd->dbl.k.k.port = *feature_data_ports; - feature_data_ports++; - pctx[index].dst_port = *feature_data_ports; - } else { - fd->dbl.k.k.port = spp_net_to_host_byte_order_16(&tcp->src_port); - pctx[index].dst_port = - spp_net_to_host_byte_order_16(&tcp->dest_port); - } - -#if 0 - /* extra info for evil mode, or default value for dst_ipv4 field in good mode */ - fd->dbl.dst_ipv4 = address_dependent_filtering ? - spp_net_to_host_byte_order_32(&ip->dest_addr) : 0; -#endif - - CNAT_V4_GET_HASH(fd->dbl.k.key64, - bucket, CNAT_MAIN_HASH_MASK) - - prefetch_target = (u8 *)(&cnat_in2out_hash[bucket]); - pctx[index].bucket = bucket; - - /* Prefetch the hash bucket */ - SPP_PREFETCH(prefetch_target, 0, LOAD); - -} - -ALWAYS_INLINE( -static inline void -stage3(spp_ctx_t **ctxs, int index, spp_node_t *np, - u8 *disp_used EXTRA_PIPELINE_ARGS_PROTO)) -{ - u32 db_index; - u32 bucket; - uword prefetch_target0, prefetch_target1; - - bucket = pctx[index].bucket; - - /* read the hash bucket */ - db_index = pctx[index].bucket = cnat_in2out_hash[bucket].next; - if (PREDICT_TRUE(db_index != EMPTY)) { - - /* - * Prefetch database keys. We save space by not cache-line - * aligning the DB entries. We don't want to waste LSU - * bandwidth prefetching stuff we won't need. - */ - - prefetch_target0 = (uword)(cnat_main_db + db_index); - - SPP_PREFETCH(prefetch_target0, 0, LOAD); - - /* Just beyond DB key #2 */ - - prefetch_target1 = prefetch_target0 + - STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports); - - /* If the targets are in different lines, do the second prefetch */ - - if (PREDICT_FALSE((prefetch_target0 & ~(SPP_CACHE_LINE_BYTES-1)) != - (prefetch_target1 & ~(SPP_CACHE_LINE_BYTES-1)))) { - - SPP_PREFETCH(prefetch_target1, 0, LOAD); - - } - } -} - -static inline void -stage4(spp_ctx_t **ctxs, int index, spp_node_t *np, - u8 *disp_used EXTRA_PIPELINE_ARGS_PROTO) -{ - spp_ctx_t *ctx = ctxs[index]; - u32 db_index = pctx[index].bucket; - cnat_main_db_entry_t *db; - cnat_feature_data_t *fd; - - /* - * Note: if the search already failed (empty bucket), - * the answer is already in the pipeline context structure - */ - if (PREDICT_FALSE(db_index == EMPTY)) { - return; - } - - fd = (cnat_feature_data_t *)ctx->feature_data; - - /* - * Note: hash collisions suck. We can't easily prefetch around them. - * The first trip around the track will be fast. After that, maybe - * not so much... - */ - do { - - db = cnat_main_db + db_index; - if (PREDICT_TRUE(db->in2out_key.key64 == fd->dbl.k.key64)) - break; - db_index = db->in2out_hash.next; - - } while (db_index != EMPTY); - - /* even in evil mode, for in2out, we nat all packets regardless mode and dst_ip */ - - /* Stick the answer back into the pipeline context structure */ - pctx[index].bucket = db_index; -} - -ALWAYS_INLINE( -static inline void -stage5(spp_ctx_t **ctxs, int index, spp_node_t *np, - u8 *disp_used EXTRA_PIPELINE_ARGS_PROTO)) -{ - spp_ctx_t *ctx = ctxs[index]; - u32 db_index = pctx[index].bucket; - cnat_feature_data_t *fd = (cnat_feature_data_t *)ctx->feature_data; - int disposition; - cnat_main_db_entry_t *db; - /* Below two pointers are just to keep the cnat_ftp_alg call happy*/ - dslite_table_entry_t *dslite_entry_ptr = NULL; - ipv6_header_t *ipv6_hdr = NULL; - tcp_hdr_type *tcp; - ipv4_header *ip; - i8 delta; - u32 seq, seq1; - u32 window; - u8 scale; - int rc; - - ip = (ipv4_header *) ctx->current_header; - - if (PLATFORM_HANDLE_TTL_DECREMENT) { - if (PREDICT_FALSE(ip->ttl <= 1)) { - /* Try to generate ICMP error msg, as TTL is <= 1 */ - - if (icmpv4_generate_with_throttling - (ctx, ip, ctx->ru.rx.uidb_index)) { - /* Generated ICMP */ - disposition = CNAT_REWRITE_OUTPUT; - INCREMENT_NODE_COUNTER(np, TCP_TTL_GEN); - } else { - /* Could not generated ICMP - drop the packet */ - disposition = CNAT_DROP; - INCREMENT_NODE_COUNTER(np, TCP_TTL_DROP); - } - goto drop_pkt; - } - } - - if (PREDICT_FALSE(db_index == EMPTY)) { - if(PREDICT_FALSE(ctx->ru.rx.frag)) { - /* Must have routed through cnat_v4_frag_in2out node */ - u16 frag_offset = - spp_net_to_host_byte_order_16(&(ip->frag_flags_offset)); - if(PREDICT_FALSE(frag_offset & IP_FRAG_OFFSET_MASK)) { - INCREMENT_NODE_COUNTER(np, TCP_FRAG_DROP); - disposition = CNAT_DROP; - goto drop_pkt; - } else { - INCREMENT_NODE_COUNTER(np, TCP_EXCEPTION); - disposition = CNAT_V4_TCP_IE; - } - } else { - INCREMENT_NODE_COUNTER(np, TCP_EXCEPTION); - disposition = CNAT_V4_TCP_IE; - } - } else { - cnat_key_t dest_info; - cnat_session_entry_t *session_db = NULL; - db = cnat_main_db + db_index; - /* Handle destination sessions */ - tcp = (tcp_hdr_type*) ((u8*)ip + ctx->application_start); - dest_info.k.port = pctx[index].dst_port; - dest_info.k.ipv4 = spp_net_to_host_byte_order_32(&(ip->dest_addr)); - - if(PREDICT_TRUE(!PLATFORM_DBL_SUPPORT)) { - - /* No DBL support, so just update the destn and proceed */ - db->dst_ipv4 = dest_info.k.ipv4; - db->dst_port = dest_info.k.port; - goto update_pkt; - } - - if(PREDICT_FALSE(db->dst_ipv4 != dest_info.k.ipv4 || - db->dst_port != dest_info.k.port)) { - if(PREDICT_TRUE(db->nsessions == 0)) { - /* Should be a static entry - * Note this session as the first session and log - */ - cnat_add_dest_n_log(db, &dest_info); - } else if(PREDICT_FALSE(db->nsessions == 1)) { - /* Destn is not same as in main db. Multiple session - * scenario - */ - dest_info.k.vrf = db->in2out_key.k.vrf; - session_db = cnat_handle_1to2_session(db, &dest_info); - if(PREDICT_FALSE(session_db == NULL)) { - disposition = CNAT_DROP; - INCREMENT_NODE_COUNTER(np, TCP_SESSION_DROP); - goto drop_pkt; - } - } else { /* There are already multiple destinations */ - dest_info.k.vrf = db->in2out_key.k.vrf; - /* If session already exists, - * cnat_create_session_db_entry will return the existing db - * else create a new db - * If could not create, return NULL - */ - session_db = cnat_create_session_db_entry(&dest_info, - db, TRUE); - if(PREDICT_FALSE(session_db == NULL)) { - disposition = CNAT_DROP; - INCREMENT_NODE_COUNTER(np, TCP_SESSION_DROP); - goto drop_pkt; - } - } - if(PREDICT_TRUE(session_db)) { - /* Have to repeat the window size check for new destinations */ - window = (u32)spp_net_to_host_byte_order_16( - &tcp->window_size); - window = window << session_db->scale; - if(PREDICT_TRUE(!session_db->window)) { - calculate_window_scale(tcp, &scale); - session_db->scale = scale; - session_db->window = window; - } else if (PREDICT_FALSE(session_db->window < - window)) { - /* Update the db entry with window option from packet */ - session_db->window = window; - } else { - /* Do nothing */ - } - session_db->tcp_seq_num = spp_net_to_host_byte_order_32( - &tcp->seq_num); - session_db->ack_no = spp_net_to_host_byte_order_32( - &tcp->ack_num); - if (PREDICT_FALSE(global_debug_flag && CNAT_DEBUG_GLOBAL_ALL)) { - PLATFORM_DEBUG_PRINT("\n In2out SDB stages seq no = %u," - " ack no = %u, window = %u\n", - session_db->tcp_seq_num, - session_db->ack_no, - session_db->window); - } - } - } else { - //Update the seq no and ack no for subsequent communication - //after connection establishment - //No need to update window here. Window is already updated - //during connection establishment - window = (u32)spp_net_to_host_byte_order_16( - &tcp->window_size); - window = window << db->scale; - if(PREDICT_FALSE(!ALG_ENABLED_DB(db))) { - //This check is done since proto_data is part of union in main - //db entry - db->proto_data.tcp_seq_chk.seq_no = - spp_net_to_host_byte_order_32( - &tcp->seq_num); - db->proto_data.tcp_seq_chk.ack_no = - spp_net_to_host_byte_order_32( - &tcp->ack_num); - } - if (PREDICT_FALSE(db->diff_window < window)) { - /* Update the db entry with window option from packet */ - db->diff_window = window; - } - if (PREDICT_FALSE(global_debug_flag && CNAT_DEBUG_GLOBAL_ALL)) { - PLATFORM_DEBUG_PRINT("\n In2out MainDB seq no = %u," - "\n ack no = %u\n", - db->proto_data.tcp_seq_chk.seq_no, - db->proto_data.tcp_seq_chk.ack_no); - PLATFORM_DEBUG_PRINT("\n In2out MAINDB window = %u\n", - db->diff_window); - } - } -update_pkt: - - INCREMENT_NODE_COUNTER(np, TCP_NAT); - - disposition = CNAT_REWRITE_OUTPUT; - - /* NAT the packet and update checksum (increamental) */ - - /* If it is a non-first fragment, we need not worry about - * ALGs as the packet does not have TCP header.. - * However, under a very race scenario when this non-first - * fragment is containing an FTP PORT command OR RTSP command - * we cannot handle that case.. in that case the ALG will fail - * Do not want to add a lot of complexity to handle one in million - * of such ALG case - */ - u16 frag_offset = - spp_net_to_host_byte_order_16(&(ip->frag_flags_offset)); - - if(PREDICT_FALSE(frag_offset & IP_FRAG_OFFSET_MASK)) { - /* Non first fragment.. no TCP header */ - FTP_ALG_DEBUG_PRINTF("Non first frag.. cannot handle ALG"); - goto handle_ttl_n_checksum; - } - - FTP_ALG_DEBUG_PRINTF("src port 0x%x, dst_port 0x%x", - spp_net_to_host_byte_order_16(&tcp->src_port), - spp_net_to_host_byte_order_16(&tcp->dest_port)) - - /* handle FTP ALG */ - if (PREDICT_FALSE(ftp_alg_enabled && - (spp_net_to_host_byte_order_16(&tcp->src_port) == 21 || - spp_net_to_host_byte_order_16(&tcp->dest_port) == 21))) { - - if(PREDICT_FALSE((db->flags & CNAT_DB_FLAG_PPTP_TUNNEL_ACTIVE) || - (db->flags & CNAT_DB_FLAG_PPTP_TUNNEL_INIT))) - { - /* FTP on a PPTP Control session? Ignore FTP */ - goto handle_ttl_n_checksum; - } - - if (PREDICT_FALSE(tcp->flags & (TCP_FLAG_SYN | TCP_FLAG_RST | - TCP_FLAG_FIN))) { - - FTP_ALG_DEBUG_PRINTF("SYN Case setting delta = 0") - - /* reset the delta */ - if(PREDICT_FALSE(session_db != NULL)) { - session_db->alg.delta = 0; - } else { - db->alg.delta = 0; - } - - } else { - - /* need to adjust seq # for in2out pkt if delta is not 0 */ - if (PREDICT_TRUE((session_db && (session_db->alg.delta != 0)) - || ((!session_db) && (db->alg.delta != 0)))) { - seq = net2host32(&tcp->seq_num); - - FTP_ALG_DEBUG_PRINTF("Orig Seq Num 0x%x", seq) - /* - * for ftp packets, due to PORT command translation, - * we may have cases that a packet/payload len gets - * changed for tcp, we need to adjust the packet's - * sequence numbers to match the changes. The delta - * of orig pkt len and new len is in alg_dlt[1] together - * with the sequence number that cuased the delta. When - * there are multiple len changes, we keep theprevious - * delta in alg_dlt[0] for case like pkt retransmission. - * So depends on packet seq number, we decide to use - * either latest delta or previous delta ([0]) - * We won't be here if both delta values are 0 - */ - if(PREDICT_FALSE(session_db != NULL)) { - seq1 = seq > session_db->tcp_seq_num ? - (seq + session_db->alg.alg_dlt[1]): - (seq + session_db->alg.alg_dlt[0]); - } else { - seq1 = seq > db->proto_data.seq_pcp.tcp_seq_num ? - (seq + db->alg.alg_dlt[1]): - (seq + db->alg.alg_dlt[0]); - } - - FTP_ALG_DEBUG_PRINTF("Old_seq_num 0x%x New Seq Num 0x%x", - seq, seq1) - - if (PREDICT_TRUE(seq1 != seq)) { - - tcp->seq_num = host2net32(seq1); - - FTP_ALG_DEBUG_PRINTF("Old TCP Checksum 0x%x", - net2host16(&tcp->tcp_checksum)) - - /* - * fix checksum incremental for seq # changes - * newchecksum = ~(~oldchecksum + ~old + new) - */ - CNAT_UPDATE_TCP_SEQ_ACK_CHECKSUM(seq, seq1) - } /* There is a diff in seq */ - - } /* ALG Delta is non zero */ - - rc = cnat_ftp_alg((u8*) ip, &delta, db, dslite_entry_ptr, ipv6_hdr); - - FTP_ALG_DEBUG_PRINTF("cnat_ftp_alg rc 0x%x", rc) - - /*if located PORT cmd, packet being updated, take the delta and seq # */ - if (PREDICT_FALSE(rc)) { - - /* set alg flag for this ftp control connection */ - if(PREDICT_FALSE(session_db != NULL)) { - session_db->flags |= CNAT_DB_FLAG_ALG_CTRL_FLOW; - } else { - db->flags |= CNAT_DB_FLAG_ALG_CTRL_FLOW; - } - - /* - * rc != 0 indicates this packet has triggered a new pkt len delta - * we need to update db entry's seq# with seq# of this packet. - * - * Move alg_dlt[1] to [0], (current delta -> previous delta) - * then apply latest delta to alg_dlt[1] (keep [1] as latest delta) - */ - if(PREDICT_FALSE(session_db != NULL)) { - session_db->tcp_seq_num = net2host32(&tcp->seq_num); - session_db->alg.alg_dlt[0] = session_db->alg.alg_dlt[1]; - - /* accumulate the delta ! */ - session_db->alg.alg_dlt[1] += delta; - FTP_ALG_DEBUG_PRINTF( - "cnat_ftp_alg seq_num 0x%x, dlt0 0x%x, dlt1 0x%x", - session_db->tcp_seq_num, - session_db->alg.alg_dlt[0], - session_db->alg.alg_dlt[1]) - - } else { - db->proto_data.seq_pcp.tcp_seq_num = net2host32(&tcp->seq_num); - db->alg.alg_dlt[0] = db->alg.alg_dlt[1]; - - /* accumulate the delta ! */ - db->alg.alg_dlt[1] += delta; - - FTP_ALG_DEBUG_PRINTF( - "cnat_ftp_alg seq_num 0x%x, dlt0 0x%x, dlt1 0x%x", - db->proto_data.seq_pcp.tcp_seq_num, - db->alg.alg_dlt[0], - db->alg.alg_dlt[1]) - } - ctx->current_length += delta; - }/* cnat_ftp_alg returned non zero */ - } /* It is not a SYN, RST or FIN */ - } else if (PREDICT_FALSE(rtsp_alg_port_num && - ((spp_net_to_host_byte_order_16(&tcp->dest_port) == rtsp_alg_port_num) || - (spp_net_to_host_byte_order_16(&tcp->src_port) == rtsp_alg_port_num))) ) { - - if (PREDICT_FALSE(tcp->flags & (TCP_FLAG_SYN | TCP_FLAG_RST | - TCP_FLAG_FIN))) { - - FTP_ALG_DEBUG_PRINTF("SYN Case setting delta = 0") - - /* reset the delta */ - if(PREDICT_FALSE(session_db != NULL)) { - session_db->alg.delta = 0; - } else { - db->alg.delta = 0; - } - - } else { -#define RTSP_ALG_DELTA_MASK 0xFF - /* need to adjust seq # for in2out pkt if delta is not 0 */ - if (PREDICT_FALSE((session_db && - (session_db->alg.delta & RTSP_ALG_DELTA_MASK) != 0) || - ((!session_db) && - (db->alg.delta & RTSP_ALG_DELTA_MASK) != 0))) { - seq = net2host32(&tcp->seq_num); - - if(PREDICT_FALSE(session_db != NULL)) { - seq1 = seq > session_db->tcp_seq_num ? - (seq + db->alg.alg_dlt[1]): - (seq + db->alg.alg_dlt[0]); - } else { - seq1 = seq > db->proto_data.seq_pcp.tcp_seq_num ? - (seq + db->alg.alg_dlt[1]): - (seq + db->alg.alg_dlt[0]); - } - - FTP_ALG_DEBUG_PRINTF("Old_seq_num 0x%x New Seq Num 0x%x", - seq, seq1) - - if (PREDICT_TRUE(seq1 != seq)) { - - tcp->seq_num = host2net32(seq1); - - FTP_ALG_DEBUG_PRINTF("Old TCP Checksum 0x%x", - net2host16(&tcp->tcp_checksum)) - - /* - * fix checksum incremental for seq # changes - * newchecksum = ~(~oldchecksum + ~old + new) - */ - CNAT_UPDATE_TCP_SEQ_ACK_CHECKSUM(seq, seq1) - } - - } - } - if ((session_db && (!session_db->alg.il)) || - ((!session_db) && (!db->alg.il))) { - cnat_rtsp_alg((u8*) ip, - &delta, - db, - ctx->current_length, - NULL, - NULL); - } - } -handle_ttl_n_checksum: - if (PLATFORM_HANDLE_TTL_DECREMENT) { - /* - * Decrement TTL and update IPv4 checksum - */ - ipv4_decr_ttl_n_calc_csum(ip); - } - - tcp_in2out_nat_mss_n_checksum(ip, - tcp, - db->out2in_key.k.ipv4, - db->out2in_key.k.port, - db); -/* CNAT_PPTP_ALG_SUPPORT */ - /* code to handle pptp control msgs */ - if(PREDICT_FALSE( - (spp_net_to_host_byte_order_16(&tcp->dest_port) == - TCP_PPTP_PORT))) { - - u32 ret; - - PPTP_DBG(3, "PPTP mgmt/ctrl msg recieved"); - - ret = cnat_handle_pptp_msg(ctx, db , tcp, PPTP_PNS ); - - if( PREDICT_FALSE( ret != CNAT_SUCCESS) ) { - PPTP_DBG(3, "PPTP mgmt/ctrl msg drop"); - disposition = CNAT_DROP; - PPTP_INCR(ctrl_msg_drops); - goto drop_pkt; - } - } - -/* CNAT_PPTP_ALG_SUPPORT */ - - /* update transaltion counters */ - db->in2out_pkts++; - - in2out_forwarding_count++; - - PLATFORM_CNAT_SET_TX_VRF(ctx,db->out2in_key.k.vrf); - - /* update the timer for good mode, or evil mode dst_ip match */ - -// if (!address_dependent_filtering || fd->dbl.dst_ipv4 == db->dst_ipv4) { - if(PREDICT_FALSE(session_db != NULL)) { - V4_TCP_UPDATE_SESSION_DB_FLAG(session_db, tcp); - CNAT_DB_TIMEOUT_RST(session_db); - } else { - V4_TCP_UPDATE_SESSION_FLAG(db, tcp); - CNAT_DB_TIMEOUT_RST(db); - } - -// } - - } - - /* Pick up the answer and put it into the context */ - fd->dbl.db_index = db_index; - -drop_pkt: - - DISP_PUSH_CTX(np, ctx, disposition, disp_used, last_disposition, last_contexts_ptr, last_nused_ptr); - -} - diff --git a/plugins/vcgn-plugin/vcgn/cnat_va_db.c b/plugins/vcgn-plugin/vcgn/cnat_va_db.c deleted file mode 100644 index 7423bdf2..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_va_db.c +++ /dev/null @@ -1,286 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_va_db.c - virtual assembly database - * - * Copyright (c) 2009, 2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -va_bucket_t va_bucket[VA_BUCKETS]; - -void va_bucket_init () { - - u32 i; - - /* - * set the pointer in each bucket - * points to nowhere - */ - for (i=0; i [%d, %d]\n", - bucket_index, entry_p->src_port, - entry_p->dst_port, key->e.src_port, key->e.dst_port) - - /* found match entry, update it */ - entry_p->src_port = key->e.src_port; - entry_p->dst_port = key->e.dst_port; - - FRAG_DEBUG_PRINTF3("VA_ADD_NEW: Existing bucket %d, counter %d\n", - bucket_index, - va_bucket[bucket_index].new_entry_counter) - - } else { - - /* no match, add a new one */ - head = va_bucket[bucket_index].head_entry; - next = va_bucket[bucket_index].next_available_entry; - - FRAG_DEBUG_PRINTF5( - "\nVA_ADD_NEW: Filling bucket %d, index %d with key 0x%llx %x\n", - bucket_index, next, key->k.key64, key->k.key32) - - va_bucket[bucket_index].va_entry[next] = key->e; - - /* increase next pointer */ - va_bucket[bucket_index].next_available_entry = (next+1) & VA_BUCKET_MASK; - - if (PREDICT_FALSE(head == va_bucket[bucket_index].next_available_entry)) { - /* adjust head circular pointer */ - va_bucket[bucket_index].head_entry = (head+1) & VA_BUCKET_MASK; - } - - va_bucket[bucket_index].new_entry_counter++; - - FRAG_DEBUG_PRINTF4( - "VA_ADD_NEW: NEW bucket %d, entry %d counter %d\n", - bucket_index, next, va_bucket[bucket_index].new_entry_counter) - } -} - - -/* - * use the key, - * return pointer to the entry if found, - * NULL if not - */ - -inline -va_entry_t * va_db_lookup (u32 bucket_index, va_lookup_key * key) -{ - - u32 index, next; - va_entry_t * entry_p; - va_bucket_t * bucket; - - bucket = &va_bucket[bucket_index]; - index = bucket->head_entry; - next = bucket->next_available_entry; - entry_p = NULL; - - FRAG_DEBUG_PRINTF4( - "\nVA_DB_LOOKUP: bucket index %d head %d next %d\n", - bucket_index, index, next) - - /* loop through the entries in the bucket */ - while( index != next) { - - if(PREDICT_TRUE(memcmp(&bucket->va_entry[index], key, VA_KEY_SIZE)==0)) { - - entry_p = &bucket->va_entry[index]; - /*In add frag entry function we are again assigning key's src - port to entry_p's src port. So when a main DB entry is deleted/ - timed out, and again another entry is created for the same - src ip and src port pair, the frag's entry_p will have the - previous port info stored and not updated. Hence the below - line is not required*/ - - /* *(u32*)&key->e.src_port = *(u32*)&entry_p->src_port; */ - /* do two ports as u32 :) */ - - break; - } - - index = (index +1) & VA_BUCKET_MASK; - - } - -#ifdef FRAG_DEBUG - if (PREDICT_TRUE(entry_p)) { - FRAG_DEBUG_PRINTF3("VA_DB_LOOKUP: bucket index %d entry index %d\n", - bucket_index, index) - FRAG_DEBUG_PRINTF5("VA_DB_LOOKUP: SRC-->DST [0x%x, %d] [0x%x, %d]\n", - entry_p->src_ip, entry_p->src_port, - entry_p->dst_ip, entry_p->dst_port) - FRAG_DEBUG_PRINTF3("[vrf 0x%x, id 0x%x]\n", - entry_p->vrf, entry_p->ip_id) - } else { - FRAG_DEBUG_PRINTF1("\nNULL ENTRY\n") - } -#endif - - return entry_p; - -} - -inline -int va_db_delete_entry (u32 bucket_index, va_lookup_key * key) -{ - - u32 index, next; - int entry_found = 0; - va_bucket_t * bucket; - - bucket = &va_bucket[bucket_index]; - index = bucket->head_entry; - next = bucket->next_available_entry; - - FRAG_DEBUG_PRINTF4( - "\nVA_DB_DELETE_ENTRY: bucket index %d head %d next %d\n", - bucket_index, index, next); - - /* loop through the entries in the bucket */ - while( index != next) { - if(PREDICT_TRUE(memcmp(&bucket->va_entry[index], key, - VA_KEY_SIZE)==0)) { - /* Clear the entry */ - FRAG_DEBUG_PRINTF1("Entry found in delete API"); - memset(&bucket->va_entry[index], 0, sizeof(va_entry_t)); - entry_found = 1; - break; - } - index = (index +1) & VA_BUCKET_MASK; - } - return entry_found; -} - - - -void cnat_va_bucket_used (int argc, unsigned long * argv) -{ - - u32 i, sum = 0;; - - for(i=0;i 0)) sum ++; - } - - PLATFORM_DEBUG_PRINT("buckets in use: %d\n", sum); - - sum = 0; - for(i=0; i= VA_BUCKETS)) { - PLATFORM_DEBUG_PRINT("invalid bucket index %d\n", index); - return; - } - - PLATFORM_DEBUG_PRINT("\n====== Bucket %d ======\n", index); - - PLATFORM_DEBUG_PRINT("bucket head index %d\n", va_bucket[index].head_entry); - - PLATFORM_DEBUG_PRINT("bucket next index %d\n", va_bucket[index].next_available_entry); - - PLATFORM_DEBUG_PRINT(" source IP dest IP VRF ip-id srcP dstP\n"); - - for(i=0;i - -#define FRAG_DEBUG 1 - -/* virtual assemble hash database size ~ 16B x 64K = 1MB */ - -#define VA_TOTAL_ENTRIES (64*1024) -#define VA_ENTRY_PER_BUCKET (8) /* make sure size is power of 2 for circular FIFO */ -#define VA_BUCKET_MASK (VA_ENTRY_PER_BUCKET -1) -#define VA_BUCKETS (VA_TOTAL_ENTRIES / VA_ENTRY_PER_BUCKET) -#define VA_KEY_SIZE 12 - -typedef struct _va_entry { - /* key: top 12 bytes */ - u32 src_ip; - u32 dst_ip; - u16 vrf; /* overloaded with protocol info with top two bits */ - u16 ip_id; - - /* values */ - u16 src_port; - u16 dst_port; -} va_entry_t; - -typedef struct _va_keys { - u64 key64; /* src & dst IP */ - u32 key32; /* vrf, protocol and ip_id */ -} va_keys; - -typedef union { - va_entry_t e; - va_keys k; -} va_lookup_key; - -typedef struct _va_bucket_t { - u32 head_entry; - u32 next_available_entry; /* ~0 for empty bucket */ - u32 new_entry_counter; /* for debug purpose */ - va_entry_t va_entry[VA_ENTRY_PER_BUCKET]; -} va_bucket_t; - -extern va_bucket_t va_bucket[]; /* hash table in cnat_va_db.c */ - -void va_bucket_init (); - -inline void va_db_add_new_entry (u32 bucket_index, va_lookup_key * ); -inline int va_db_delete_entry (u32 bucket_index, va_lookup_key * ); -inline va_entry_t * va_db_lookup (u32 bucket_index, va_lookup_key * key); - -#ifdef FRAG_DEBUG - -#define FRAG_DEBUG_PRINTF1(a) \ - if (frag_debug_flag) { \ - PLATFORM_DEBUG_PRINT(a); \ - } - -#define FRAG_DEBUG_PRINTF2(a, b) \ - if (frag_debug_flag) { \ - PLATFORM_DEBUG_PRINT(a, b); \ - } - -#define FRAG_DEBUG_PRINTF3(a, b, c) \ - if (frag_debug_flag) { \ - PLATFORM_DEBUG_PRINT(a, b, c); \ - } - -#define FRAG_DEBUG_PRINTF4(a, b, c, d) \ - if (frag_debug_flag) { \ - PLATFORM_DEBUG_PRINT(a, b, c, d); \ - } - -#define FRAG_DEBUG_PRINTF5(a, b, c, d, e) \ - if (frag_debug_flag) { \ - PLATFORM_DEBUG_PRINT(a, b, c, d, e); \ - } - -#define FRAG_DEBUG_PRINTF6(a, b, c, d, e, f) \ - if (frag_debug_flag) { \ - PLATFORM_DEBUG_PRINT(a, b, c, d, e, f); \ - } -#else - -#define FRAG_DEBUG_PRINTF1(a) - -#define FRAG_DEBUG_PRINTF2(a, b) - -#define FRAG_DEBUG_PRINTF3(a, b, c) - -#define FRAG_DEBUG_PRINTF4(a, b, c, d) - -#define FRAG_DEBUG_PRINTF5(a, b, c, d, e) - -#define FRAG_DEBUG_PRINTF6(a, b, c, d, e, f) - -#endif - -#endif /* __CNAT_VA_DB_H__ */ - - diff --git a/plugins/vcgn-plugin/vcgn/dslite_db.h b/plugins/vcgn-plugin/vcgn/dslite_db.h deleted file mode 100644 index 2269b98c..00000000 --- a/plugins/vcgn-plugin/vcgn/dslite_db.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - *------------------------------------------------------------------ - * dslite_db.h - Stateful DSLITE translation database definitions - * - * Copyright (c) 2010-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ -#ifndef __DSLITE_DB_H__ -#define __DSLITE_DB_H__ - -#include "cnat_cli.h" -#include "index_list.h" -#include "cnat_ports.h" -#include "cnat_db.h" -#include "dslite_defs.h" - -#define DSLITE_PRINTF(level, ...) \ - if (dslite_debug_level > level) PLATFORM_DEBUG_PRINT(__VA_ARGS__); -/* -#define DSLITE_PRINTF(lvl, ...) \ -{ \ - avsm_dispatlib_debug (__VA_ARGS__); \ -} -*/ - -#define HASH_ENHANCE 4 -//#define DSLITE_DEF -#define DSLITE_MAIN_DB_SIZE (20000000 / PLATFORM_CNAT_INSTS) -#define DSLITE_MAIN_HASH_SIZE \ - (HASH_ENHANCE * PLATFORM_CNAT_MAIN_PRELIM_HASH_SIZE) - -#define DSLITE_MAIN_HASH_MASK (DSLITE_MAIN_HASH_SIZE-1) - - -/* nb: 200000 users / 64 CNAT = 3125, 76% occupancy */ -#define DSLITE_USER_HASH_SIZE CNAT_USER_HASH_SIZE -#define DSLITE_USER_HASH_MASK (DSLITE_USER_HASH_SIZE-1) - -/* No. of per ip/port config will be limited to 1000 */ -#define DSLITE_TIMEOUT_HASH_SIZE 1000 -#define DSLITE_TIMEOUT_HASH_MASK (DSLITE_TIMEOUT_HASH_SIZE - 1) -#define DSLITE_TIMEOUT_FULL_MASK 0xFFFFFFFFFFFFFFFF - -#define CNAT_MAX_SESSIONS_PER_BIB 0xFFFF - -#define FORCE_DEL 1 /* Delete static BIB entries as well */ - -/* default timeout values */ -#define DSLITE_UDP_DEFAULT 300 /* 5 min */ -#define DSLITE_UDP_MIN 120 /* 2 min */ -#define DSLITE_TCP_TRANS 240 /* 4 min */ -#define DSLITE_TCP_EST 7200 /* 2 hrs */ -#define DSLITE_TCP_V4_SYN 6 /* 6 sec */ -#define DSLITE_FRAG_MIN 2 /* 2 sec */ -#define DSLITE_ICMP_DEFAULT 60 /* 1 min */ - -extern u32 dslite_translation_create_count; -extern u32 dslite_translation_delete_count; -extern u32 dslite_translation_create_rate; -extern u32 dslite_translation_delete_rate; -extern u32 dslite_in2out_forwarding_count; -extern u32 dslite_in2out_forwarding_rate; -extern u32 dslite_out2in_forwarding_count; -extern u32 dslite_out2in_forwarding_rate; - -#define DSLITE_V6_GET_HASH(in_key, hash, mask) \ - a = in_key->ipv6[0] ^ in_key->ipv6[1] ^ in_key->ipv6[2] ^ in_key->ipv6[3] \ - ^ in_key->ipv4_key.k.ipv4 ^ ((in_key->ipv4_key.k.port << 16) | in_key->ipv4_key.k.vrf); \ - DSLITE_PRINTF(1, "%x:%x:%x:%x:%x:%x:%x\n", in_key->ipv6[0], in_key->ipv6[1], in_key->ipv6[2], in_key->ipv6[3], \ - in_key->ipv4_key.k.ipv4, in_key->ipv4_key.k.port, in_key->ipv4_key.k.vrf); \ - b = c = 0x9e3779b9;\ - /* Jenkins hash, arbitrarily use c as the "answer" */ \ - hash_mix32(a, b, c); \ - hash = c & mask; \ - - -#define DSLITE_V6_GET_USER_HASH(ipv6, hash, mask) \ - a = ipv6[0] ^ ipv6[1] ^ ipv6[2] ^ ipv6[3]; \ - b = c = 0x9e3779b9;\ - /* Jenkins hash, arbitrarily use c as the "answer" */ \ - hash_mix32(a, b, c); \ - hash = c & mask; \ - -#define DSLITE_V4_GET_HASH(in_key, hash, mask) \ - a = in_key.ipv4 ^ ((in_key.port << 16) | in_key.vrf); \ - b = c = 0x9e3779b9; \ - /* Jenkins hash, arbitrarily use c as the "answer" */ \ - hash_mix32(a, b, c); \ - hash = c & mask; - -#define PRIVATE_V4_ADDR_CHECK(addr, invalid) \ - invalid = 0; \ - int range1 = ((addr & 0xFF000000) >> 24); \ - int range2 = ((addr & 0xFFF00000) >> 20); \ - int range3 = ((addr & 0xFFFF0000) >> 16); \ - int range4 = ((addr & 0xFFFFFFF8) >> 3); \ - if(range1 != 0xa && range2 != 0xac1 && range3 != 0xc0a8 && range4 != 0x18000000) \ - invalid = 1; - -#define V4_MAPPED_V6_CHECK(v6_addr, invalid) \ - invalid = 0; \ - int word1 = v6_addr[0]; \ - int word2 = v6_addr[1]; \ - int word3 = v6_addr[2]; \ - if(!((word1 == 0) && (word2 == 0) && (word3 == 0x0000FFFF))) \ - invalid = 1; - - -extern dslite_table_entry_t dslite_table_array[DSLITE_MAX_DSLITE_ENTRIES]; -extern dslite_table_entry_t *dslite_table_ptr; - -#define DSLITE_CMP_V6_KEY(key1, key2) \ - memcmp(key1, key2, sizeof(dslite_v6_key_t)) - -#define DSLITE_CMP_V4_KEY(key1, key2) \ - memcmp(key1, key2, sizeof(dslite_v4_key_t)) - - -#define DSLITE_CMP_V6_IP(ip1, ip2) \ - memcmp(ip1, ip2, (sizeof(u32) * 4)) - - -#define DSLITE_CMP_V6_KEY1(key1, key2) \ - (key1.ipv6[0] == key2.ipv6[0]) && (key1.ipv6[1] == key2.ipv6[1]) && \ - (key1.ipv6[2] == key2.ipv6[2]) && (key1.ipv6[3] == key2.ipv6[3]) && \ - (key1.port == key2.port) && (key1.vrf == key2.vrf) - - -#define DSLITE_CMP_V6_IP1(ip1, ip2) \ - ((ip1[0] == ip2[0]) && (ip1[1] == ip2[1]) && \ - (ip1[2] == ip2[2]) && (ip1[3] == ip2[3])) - -#define DSLITE_CMP_V4_KEY1(key1, key2) \ - (key1.key64 == key2.key64) - -cnat_main_db_entry_t* -dslite_get_main_db_entry_v2(dslite_db_key_bucket_t *ki, - port_pair_t port_pair_type, - port_type_t port_type, - cnat_gen_icmp_info *info, - dslite_table_entry_t *dslite_entry_ptr, - cnat_key_t *dest_info); - -cnat_main_db_entry_t* -dslite_main_db_lookup_entry(dslite_db_key_bucket_t *ki); - - -cnat_user_db_entry_t* -dslite_user_db_lookup_entry(dslite_db_key_bucket_t *uki); - -cnat_user_db_entry_t* -dslite_user_db_create_entry(dslite_db_key_bucket_t *uki, u32 portmap_index); - -cnat_main_db_entry_t* -dslite_create_main_db_entry_and_hash(dslite_db_key_bucket_t *ki, - cnat_db_key_bucket_t *ko, - cnat_user_db_entry_t *udb); - -#endif diff --git a/plugins/vcgn-plugin/vcgn/dslite_defs.h b/plugins/vcgn-plugin/vcgn/dslite_defs.h deleted file mode 100644 index 4860adcb..00000000 --- a/plugins/vcgn-plugin/vcgn/dslite_defs.h +++ /dev/null @@ -1,336 +0,0 @@ -/* - *------------------------------------------------------------------ - * dslite_defs.h - DSLITE structure definiitions - * - * Copyright (c) 2011-2012 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef __DSLITE_DEFS_H__ -#define __DSLITE_DEFS_H__ - -#ifdef TOBE_PORTED -#include "spp_platform_common.h" -#include "cgse_defs.h" -#endif -#include "cnat_cli.h" -#include "cnat_config.h" -#include "cnat_ports.h" -#include "cnat_bulk_port_defs.h" - -extern u32 ds_lite_config_debug_level; - -#define SWAP_IPV6_ADDR(ipv6_hdr, dslite_entry_ptr) \ - ipv6_hdr->dst_addr[0] = ipv6_hdr->src_addr[0]; \ - ipv6_hdr->dst_addr[1] = ipv6_hdr->src_addr[1]; \ - ipv6_hdr->dst_addr[2] = ipv6_hdr->src_addr[2]; \ - ipv6_hdr->dst_addr[3] = ipv6_hdr->src_addr[3]; \ - ipv6_hdr->src_addr[0] = spp_host_to_net_byte_order_32(dslite_entry_ptr->AFTR_v6_address[0]); \ - ipv6_hdr->src_addr[1] = spp_host_to_net_byte_order_32(dslite_entry_ptr->AFTR_v6_address[1]); \ - ipv6_hdr->src_addr[2] = spp_host_to_net_byte_order_32(dslite_entry_ptr->AFTR_v6_address[2]); \ - ipv6_hdr->src_addr[3] = spp_host_to_net_byte_order_32(dslite_entry_ptr->AFTR_v6_address[3]); - -#define DSLITE_SET_TX_PKT_TYPE(type) { \ - ctx->ru.tx.packet_type = type; \ -} - -#define DSLITE_INC_STATS_V4(PTR, COUNTER, IPV4_SRC_ADDR) { \ - PTR->COUNTER++; \ -} - -#define DSLITE_INC_STATS_V6(PTR, COUNTER, IPV6_DEST_ADDR) { \ - PTR->COUNTER++; \ -} - - -#define DSLITE_INVALID_UIDX 0xffff /*invalid svi app uidb index */ -#define DSLITE_INVALID_VRFID 0xffffffff /*invalid vrf id */ - -#define DSLITE_VRF_MASK 0x3fff -#define DSLITE_MAX_VRFMAP_ENTRIES (DSLITE_VRF_MASK + 1) - -#define DSLITE_VRFMAP_ENTRY_INVALID 0xffff - -#define DSLITE_V6_PREFIX_MASK_MIN 16 -#define DSLITE_V6_PREFIX_MASK_MAX 96 -#define DSLITE_V6_PREFIX_MASK_MULTIPLE 8 - -#define DSLITE_TUNNEL_MTU_MIN 1280 -#define DSLITE_TUNNEL_MTU_MAX 9216 - -#define DSLITE_TUNNEL_TTL_MIN 0 -#define DSLITE_TUNNEL_TTL_MAX 255 - -#define DSLITE_TUNNEL_TOS_MIN 0 -#define DSLITE_TUNNEL_TOS_MAX 255 - -#define DSLITE_V4_MASK_MAX 32 - -//#define XLAT_MAX_FRAG_ID_COUNTERS (256) -#define DSLITE_AFTR_IPV4_ADDR 0xC0000001 - -#define DSLITE_MAX_TAP_RG_ENTRIES 2 -#define DSLITE_MAX_DSLITE_ENTRIES (256) -#define DSLITE_MAX_DSLITE_ID (DSLITE_MAX_DSLITE_ENTRIES-1) -/* Define the below value as 64 if first 64 entries are for NAT44 */ -#define DSLITE_INDEX_OFFSET 1 - -#define DSLITE_INVALID_DSLITE_ID (0) - -#define DSLITE_TABLE_ENTRY_DELETED 0 -#define DSLITE_TABLE_ENTRY_ACTIVE 1 -#define DSLITE_TABLE_ENTRY_DORMANT 2 -#define DSLITE_TABLE_ENTRY_INVALID_UIDB 3 - -typedef struct { - u16 tcp_initial_setup_timeout; - u16 tcp_active_timeout; - u16 udp_init_session_timeout; - u16 udp_act_session_timeout; - u16 icmp_session_timeout; - u16 temp; -} dslite_timeout_info_t; - - -typedef struct { - - u16 state; /* To use nat44 enums ?? TBD */ - u16 dslite_id; /* DSLITE_ID value for this table entry - for easy access */ - - u16 i_vrf; /* V6 uidb index */ - u16 o_vrf; /* V4 uidb index */ - - u16 cnat_main_db_max_ports_per_user; /* port limit */ - u16 tcp_mss; /*tcp max segment size for this inside vrf */ - - u32 delete_time; - - cnat_portmap_v2_t *portmap_list; - - u32 nfv9_logging_index; - u32 syslog_logging_index; - u32 AFTR_v6_address[4]; - -#define DSLITE_IPV4_TOS_OVERRIDE_FLAG 0x00000001 -#define DSLITE_IPV6_TOS_OVERRIDE_FLAG 0x00000002 -#define DSLITE_IPV4_TTL_OVERRIDE_FLAG 0x00000004 -#define DSLITE_IPV6_TTL_OVERRIDE_FLAG 0x00000008 -#define DSLITE_IPV6_FRAG_REASSEMB_ENG 0x00000010 -#define DSLITE_FTP_ALG_ENABLE 0x00000020 -#define DSLITE_RTSP_ALG_ENABLE 0x00000040 -#define DSLITE_NETFLOW_ENABLE 0x00000080 -#define DSLITE_SYSLOG_ENABLE 0x00000100 - - u16 feature_flags; - u16 tunnel_mtu; - - u8 ipv4_ttl_value; - u8 ipv6_ttl_value; - u8 ipv4_tos_value; - u8 ipv6_tos_value; - - u32 v4_if_num; /* V4 SVI ifnum */ - u32 v6_if_num; /* V6 SVI ifnum */ - u32 i_vrf_id; //inside vrf id - u32 o_vrf_id; //outside vrf id - - dslite_timeout_info_t timeout_info; - u16 cnat_static_port_range; - u16 dyn_start_port; - - u32 AFTR_v4_addr; - bulk_alloc_size_t bulk_size; /* should be equivalent to u16 - 2 bytes */ - u32 pcp_server_addr; - u16 pcp_server_port; - u8 mapping_refresh_both_direction; - u8 pad; - u16 rtsp_port; -#define DSLITE_BIDIR_REFRESH 1 - u8 dslite_enable; /* DS-Lite enable check flag */ - u8 syslog_logging_policy; /* DS-Lite Session Logging check flag */ - u8 nf_logging_policy; - - u8 temp1; - u16 temp2; - u32 temp3; - u32 rseed_ip; -} dslite_table_entry_t; - -typedef struct { - u64 v4_to_v6_invalid_uidb_drop_count; - u64 v6_to_v4_invalid_uidb_drop_count; - u64 v4_to_v6_frag_invalid_uidb_drop_count; -} dslite_global_counters_t; - -typedef struct { - u32 tap_enable; - u32 ipv4_addr; - u32 ipv6_addr[4]; -} dslite_tap_rg_t; - -extern dslite_table_entry_t *dslite_table_db_ptr; - - -#define DSLITE_ADD_UIDB_INDEX_DSLITE_ID_MAPPING(uidb_index, dslite_id) \ - *(cgse_uidb_index_cgse_id_mapping_ptr + uidb_index) = dslite_id; - -extern u8 my_instance_number; - -extern void dslite_clear_counters(u16 dslite_id); -extern void dslite_clear_per_RG_counters(); -extern dslite_global_counters_t dslite_global_counters; -extern u32 dslite_config_debug_level; -extern u32 dslite_data_path_debug_level; -extern u32 dslite_defrag_debug_level; -extern u32 dslite_debug_level; - -typedef struct { - u64 v6_to_v4_tcp_input_count; - u64 v6_to_v4_tcp_nat_error; - u64 v6_to_v4_tcp_output_count; -} dslite_v6_to_v4_tcp_counter_t; - -typedef struct { - u64 v4_to_v6_tcp_input_count; - u64 v4_to_v6_tcp_no_entry; - u64 v4_to_v6_tcp_output_count; -} dslite_v4_to_v6_tcp_counter_t; - -typedef struct { - u64 v6_to_v4_udp_input_count; - u64 v6_to_v4_udp_nat_error; - u64 v6_to_v4_udp_output_count; -} dslite_v6_to_v4_udp_counter_t; - -typedef struct { - u64 v4_to_v6_udp_input_count; - u64 v4_to_v6_udp_no_entry; - u64 v4_to_v6_udp_output_count; -} dslite_v4_to_v6_udp_counter_t; - -typedef struct { - u64 v6_to_v4_icmp_qry_input_count; - u64 v6_to_v4_icmp_qry_nat_error; - u64 v6_to_v4_icmp_qry_output_count; -} dslite_v6_to_v4_icmp_qry_counter_t; - -typedef struct { - u64 v4_to_v6_icmp_qry_input_count; - u64 v4_to_v6_icmp_qry_no_nat_entry; - u64 v4_to_v6_icmp_qry_output_count; -} dslite_v4_to_v6_icmp_qry_counter_t; - -typedef struct { - u64 v6_to_v4_icmp_error_input_count; - u64 v6_to_v4_icmp_error_nat_error; - u64 v6_to_v4_icmp_error_output_count; -} dslite_v6_to_v4_icmp_error_counter_t; - -typedef struct { - u64 v4_to_v6_icmp_error_input_count; - u64 v4_to_v6_icmp_error_no_nat_entry; - u64 v4_to_v6_icmp_error_output_count; -} dslite_v4_to_v6_icmp_error_counter_t; - -typedef struct { - u64 v6_icmp_error_input_count; - u64 v6_AFTR_echo_reply_count; - u64 v6_to_v4_icmp_error_unsupported_type_drop_count; - u64 v6_to_v4_icmp_error_no_db_entry_count; - u64 v6_to_v4_icmp_err_throttled_count; - u64 v6_to_v4_icmp_error_xlated_count; -} dslite_v6_icmp_error_counter_t; - -typedef struct { - u64 v4_to_v6_ttl_gen_count; - u64 v4_to_v6_icmp_throttle_count; - u64 v4_to_v6_ptb_gen_count; - u64 v4_to_v6_aftr_v4_echo_reply_count; - u64 v6_to_v4_ttl_gen_count; - u64 v6_to_v4_icmp_throttle_count; - u64 v6_to_v4_admin_prohib_icmp_count; - u64 v6_to_v4_aftr_v4_echo_reply_count; - u64 v6_icmp_gen_count; -} dslite_icmp_gen_counter_t; - -typedef struct { - u64 dslite_input_tunnel_pkt; - u64 dslite_encap_count; - u64 dslite_decap_count; - u64 dslite_sec_check_failed; - u64 dslite_unsupp_packet; -} dslite_common_counter_t; - -typedef struct { - - dslite_v6_to_v4_tcp_counter_t v64_tcp_counters; - dslite_v4_to_v6_tcp_counter_t v46_tcp_counters; - dslite_v6_to_v4_udp_counter_t v64_udp_counters; - dslite_v4_to_v6_udp_counter_t v46_udp_counters; - dslite_v6_to_v4_icmp_qry_counter_t v64_icmp_counters; - dslite_v4_to_v6_icmp_qry_counter_t v46_icmp_counters; - dslite_v6_to_v4_icmp_error_counter_t v64_icmp_error_counters; - dslite_v4_to_v6_icmp_error_counter_t v46_icmp_error_counters; - dslite_v6_icmp_error_counter_t dslite_v6_icmp_err_counters; - dslite_icmp_gen_counter_t dslite_icmp_gen_counters; - dslite_common_counter_t dslite_common_counters; -} dslite_counters_t; - -typedef struct { - u32 active_translations; - u32 translation_create_rate; - u32 translation_delete_rate; - u32 in2out_forwarding_rate; - u32 out2in_forwarding_rate; - u32 in2out_drops_port_limit_exceeded; - u32 in2out_drops_system_limit_reached; - u32 in2out_drops_resource_depletion; - u32 no_translation_entry_drops; - u32 pool_address_totally_free; - u32 num_subscribers; - u32 dummy; - u64 drops_sessiondb_limit_exceeded; -} dslite_common_stats_t; - -typedef struct { - u16 msg_id; - u8 rc; - u8 pad[5]; - dslite_counters_t counters; -} dslite_show_statistics_summary_resp; - - -#define CMD_GENERATE_PTB 0x1 -#define CMD_GENERATE_TTL 0x2 - -/* - * This structure is to provide abstraction for data exchanged from one - * VPP node to its disposition or further in the dslite node graph. - */ -typedef struct { - u32 icmp_gen_type; // ctx->feature_data[0] - u32 reserved1; // ctx->feature_data[1] - u32 reserved2; // ctx->feature_data[2] - u32 reserved3; // ctx->feature_data[3] -} dslite_feature_data_t; - -extern dslite_counters_t dslite_all_counters[DSLITE_MAX_DSLITE_ENTRIES]; -//extern dslite_inst_gen_counter_t dslite_inst_gen_counters[DSLITE_MAX_DSLITE_ENTRIES]; - - - extern void dslite_show_config(void); -#define STAT_PORT_RANGE_FROM_INST_PTR(inst) ((inst)->cnat_static_port_range) - -#endif /* __DSLITE_DEFS_H__ */ - diff --git a/plugins/vcgn-plugin/vcgn/index_list.c b/plugins/vcgn-plugin/vcgn/index_list.c deleted file mode 100644 index ec1b83b0..00000000 --- a/plugins/vcgn-plugin/vcgn/index_list.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - *------------------------------------------------------------------ - * index_list.c - vector-index-based lists. 64-bit pointers suck. - * - * Copyright (c) 2008-2009, 2011 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#include -#include -//#include -#include -#include "index_list.h" - -/* - * index_slist_addhead - * - * args: headp -- pointer to e.g. a hash bucket - * vector -- vector containing the list - * elsize -- size of an element in this vector - * offset -- offset in each vector element of this list thread - * index_to_add -- index in the vector to add to the list - * - * Adds new items to the head of the list. Try not to screw up the args! - */ -void index_slist_addhead (index_slist_t *headp, - u8 *vector, u32 elsize, u32 offset, u32 index_to_add) -{ - return (index_slist_addhead_inline(headp, vector, elsize, offset, - index_to_add)); -} - -/* - * index_slist_remelem - * - * args: headp -- pointer to e.g. a hash bucket - * vector -- vector containing the list - * elsize -- size of an element in this vector - * offset -- offset in each vector element of this list thread - * index_to_del -- index in the vector to delete from the list - * - * Try not to screw up the args! - */ - -int index_slist_remelem (index_slist_t *headp, - u8 *vector, u32 elsize, u32 offset, - u32 index_to_delete) -{ - return (index_slist_remelem_inline(headp, vector, elsize, offset, - index_to_delete)); -} - - -/* - * index_dlist_addtail - * - * Append the indicated vector element to the doubly-linked list - * whose first element is pointed to by headp. - * - * args: head_index -- listhead vector element index. - * vector -- vector containing the list - * elsize -- size of an element in this vector - * offset -- offset in each vector element of this list thread - * index_to_add -- index in the vector to add to the list - * - * Do not call this routine to create the listhead. Simply set - * index_dlist->next = index_dlist->prev = index of item. - * - * Try not to screw up the args. - */ - -void index_dlist_addtail (u32 head_index, u8 *vector, u32 elsize, - u32 offset, u32 index_to_add) -{ - index_dlist_t *elp; - index_dlist_t *elp_next; - index_dlist_t *headp; - - headp = (index_dlist_t *)(vector + offset + elsize*head_index); - elp = (index_dlist_t *)(vector + offset + elsize*index_to_add); - elp->next = index_to_add; - elp->prev = index_to_add; - - elp->next = headp->next; - headp->next = index_to_add; - - elp_next = (index_dlist_t *)(vector + offset + elsize*elp->next); - elp->prev = elp_next->prev; - elp_next->prev = index_to_add; -} - -u32 index_dlist_remelem (u32 head_index, - u8 *vector, u32 elsize, u32 offset, - u32 index_to_delete) -{ - u32 rv = head_index; - index_dlist_t *headp, *elp, *elp_next; - - elp = (index_dlist_t *)(vector + offset + elsize*index_to_delete); - - /* Deleting the head index? */ - if (PREDICT_FALSE(head_index == index_to_delete)) { - rv = elp->next; - /* The only element on the list? */ - if (PREDICT_FALSE(rv == head_index)) - rv = EMPTY; - } - - headp = (index_dlist_t *)(vector + offset + elsize*elp->prev); - headp->next = elp->next; - elp_next = (index_dlist_t *)(vector + offset + elsize*elp->next); - elp_next->prev = elp->prev; - - elp->next = elp->prev = EMPTY; - - return rv; -} - - -#ifdef TEST_CODE2 - -typedef struct tv_ { - char junk[43]; - index_dlist_t l; -} tv_t; - - -void index_list_test_cmd(int argc, unsigned long *argv) -{ - int i, j; - u32 head_index; - index_dlist_t *headp; - tv_t *tp=0; - - vec_validate(tp, 3); - head_index = 3; - - memset(tp, 0xa, sizeof(tp[0])*vec_len(tp)); - - /* Here's how to set up the head element... */ - headp = &((tp + head_index)->l); - headp->next = headp->prev = head_index; - - for (i = 0; i < 3; i++) { - index_dlist_addtail(head_index, (u8 *)tp, sizeof(tp[0]), - STRUCT_OFFSET_OF(tv_t, l), i); - printf("headp next %d prev %d\n", - headp->next, headp->prev); - for (j = 0; j <= 3; j++) { - printf ("[%d]: next %d prev %d\n", j, - tp[j].l.next, tp[j].l.prev); - } - printf("---------------\n"); - - } - - printf("After all adds:\n"); - - printf("headp next %d prev %d\n", - headp->next, headp->prev); - - for (j = 0; j <= 3; j++) { - printf ("[%d]: next %d prev %d\n", j, - tp[j].l.next, tp[j].l.prev); - } - printf("---------------\n"); - - head_index = index_dlist_remelem (head_index, (u8 *)tp, sizeof(tp[0]), - STRUCT_OFFSET_OF(tv_t, l), 1); - - printf("after delete 1, head index %d\n", head_index); - headp = &((tp + head_index)->l); - printf("headp next %d prev %d\n", - headp->next, headp->prev); - for (j = 0; j <= 3; j++) { - printf ("[%d]: next %d prev %d\n", j, - tp[j].l.next, tp[j].l.prev); - } - printf("---------------\n"); - - index_dlist_addtail(head_index, (u8 *)tp, sizeof(tp[0]), - STRUCT_OFFSET_OF(tv_t, l), 1); - - printf("after re-add 1, head index %d\n", head_index); - headp = &((tp + head_index)->l); - printf("headp next %d prev %d\n", - headp->next, headp->prev); - for (j = 0; j <= 3; j++) { - printf ("[%d]: next %d prev %d\n", j, - tp[j].l.next, tp[j].l.prev); - } - printf("---------------\n"); - - for (i = 3; i >= 0; i--) { - head_index = index_dlist_remelem (head_index, (u8 *)tp, sizeof(tp[0]), - STRUCT_OFFSET_OF(tv_t, l), i); - printf("after delete, head index %d\n", head_index); - if (head_index != EMPTY) { - headp = &((tp + head_index)->l); - printf("headp next %d prev %d\n", - headp->next, headp->prev); - for (j = 0; j <= 3; j++) { - printf ("[%d]: next %d prev %d\n", j, - tp[j].l.next, tp[j].l.prev); - } - } else { - printf("empty list\n"); - } - printf("---------------\n"); - } -} -#endif /* test code 2 */ - -#ifdef TEST_CODE - -typedef struct tv_ { - char junk[43]; - index_slist_t l; -} tv_t; - - -void index_list_test_cmd(int argc, unsigned long *argv) -{ - int i, j; - tv_t *tp = 0; - index_slist_t *buckets = 0; - - vec_add1((u32 *)buckets, EMPTY); - vec_validate(tp, 9); - - for (i = 0; i < 10; i++) { - index_slist_addhead(buckets, (u8 *)tp, sizeof(*tp), - STRUCT_OFFSET_OF(tv_t, l), i); - } - - printf ("after adds, buckets[0] = %u\n", buckets[0]); - - for (j = 0; j < 10; j++) { - printf("tp[%d] next %u\n", j, tp[j].l); - - } - - for (i = 0; i < 10; i++) { - if (PREDICT_FALSE(index_slist_remelem(buckets, (u8 *) tp, sizeof(*tp), - STRUCT_OFFSET_OF(tv_t, l), i))) { - printf("OUCH: remelem failure at index %d\n", i); - } - if (PREDICT_FALSE(tp[i].l.next != EMPTY)) { - printf("OUCH: post-remelem next not EMPTY, index %d\n", i); - } - } - - printf ("after deletes, buckets[0] = %x\n", buckets[0]); - - for (i = 0; i < 10; i++) { - index_slist_addhead(buckets, (u8 *)tp, sizeof(*tp), - STRUCT_OFFSET_OF(tv_t, l), i); - } - - printf ("after adds, buckets[0] = %u\n", buckets[0]); - - for (j = 0; j < 10; j++) { - printf("tp[%d] next %u\n", j, tp[j].l); - - } - - for (i = 9; i >= 0; i--) { - if (PREDICT_FALSE(index_slist_remelem(buckets, (u8 *) tp, sizeof(*tp), - STRUCT_OFFSET_OF(tv_t, l), i))) { - printf("OUCH: remelem failure at index %d\n", i); - } - if ((tp[i].l.next != EMPTY)) { - printf("OUCH: post-remelem next not EMPTY, index %d\n", i); - } - } - - printf ("after deletes, buckets[0] = %x\n", buckets[0]); - - printf("add evens, then odds...\n"); - - for (i = 0; i < 10; i += 2) { - index_slist_addhead(buckets, (u8 *)tp, sizeof(*tp), - STRUCT_OFFSET_OF(tv_t, l), i); - - printf ("head = buckets[0].next = %d\n", buckets[0].next); - for (j = 0; j < 10; j++) { - printf("tp[%d] next %u\n", j, tp[j].l); - } - printf("-------------\n"); - } - - for (i = 1; i < 10; i += 2) { - index_slist_addhead(buckets, (u8 *)tp, sizeof(*tp), - STRUCT_OFFSET_OF(tv_t, l), i); - - printf ("head = buckets[0].next = %d\n", buckets[0].next); - for (j = 0; j < 10; j++) { - printf("tp[%d] next %u\n", j, tp[j].l); - } - printf("-------------\n"); - } - - printf ("after adds, buckets[0] = %u\n", buckets[0]); - - for (j = 0; j < 10; j++) { - printf("tp[%d] next %u\n", j, tp[j].l); - - } - - for (i = 9; i >= 0; i--) { - if (PREDICT_FALSE(index_slist_remelem(buckets, (u8 *) tp, sizeof(*tp), - STRUCT_OFFSET_OF(tv_t, l), i))) { - printf("OUCH: remelem failure at index %d\n", i); - } - if (PREDICT_FALSE(tp[i].l.next != EMPTY)) { - printf("OUCH: post-remelem next not EMPTY, index %d\n", i); - } - } - - printf ("after deletes, buckets[0] = %x\n", buckets[0]); - - vec_free(buckets); - vec_free(tp); -} -#endif /* test code */ diff --git a/plugins/vcgn-plugin/vcgn/index_list.h b/plugins/vcgn-plugin/vcgn/index_list.h deleted file mode 100644 index 498cd7eb..00000000 --- a/plugins/vcgn-plugin/vcgn/index_list.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - *------------------------------------------------------------------ - * index_list.h - vector-index-based doubly-linked lists - * - * Copyright (c) 2008-2009 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef _INDEX_LIST_H_ -#define _INDEX_LIST_H_ 1 - -/* An index we can't possibly see in practice... */ -#define EMPTY ((u32)~0) - -typedef struct index_slist_ { - u32 next; -} index_slist_t; - -/* - * index_slist_addhead - * - * args: headp -- pointer to e.g. a hash bucket - * vector -- vector containing the list - * elsize -- size of an element in this vector - * offset -- offset in each vector element of this list thread - * index_to_add -- index in the vector to add to the list - * - * Adds new items to the head of the list. Try not to screw up the args! - */ -static inline void - index_slist_addhead_inline (index_slist_t *headp, - u8 *vector, u32 elsize, - u32 offset, u32 index_to_add) -{ - index_slist_t *addme; - - addme = (index_slist_t *)(vector + offset + elsize*index_to_add); - addme->next = EMPTY; - - if (headp->next == EMPTY) { - headp->next = index_to_add; - return; - } else { - addme->next = headp->next; - headp->next = index_to_add; - } -} - -/* - * index_slist_remelem - * - * args: headp -- pointer to e.g. a hash bucket - * vector -- vector containing the list - * elsize -- size of an element in this vector - * offset -- offset in each vector element of this list thread - * index_to_del -- index in the vector to delete from the list - * - * Try not to screw up the args! - */ - -static inline int - index_slist_remelem_inline (index_slist_t *headp, - u8 *vector, u32 elsize, - u32 offset, u32 index_to_delete) -{ - index_slist_t *findme; - index_slist_t *prev; - index_slist_t *cur; - - findme = (index_slist_t *)(vector + offset + elsize*index_to_delete); - - if (headp->next == index_to_delete) { - headp->next = findme->next; - findme->next = EMPTY; - return 0; - } - - prev = (index_slist_t *)(vector + offset + elsize*headp->next); - cur = (index_slist_t *)(vector + offset + elsize*prev->next); - while (cur != findme) { - if (cur->next == EMPTY) - return (1); - prev = cur; - cur = (index_slist_t *)(vector + offset + elsize*cur->next); - } - prev->next = findme->next; - findme->next = EMPTY; - return 0; -} - -void index_slist_addhead (index_slist_t *headp, - u8 *vector, u32 elsize, u32 offset, u32 index); -int index_slist_remelem (index_slist_t *headp, - u8 *vector, u32 elsize, u32 offset, u32 index); - -typedef struct index_dlist_ { - u32 next; - u32 prev; -} index_dlist_t; - -void index_dlist_addtail (u32 head_index, u8 *vector, u32 elsize, - u32 offset, u32 index_to_add); - -u32 index_dlist_remelem (u32 head_index, - u8 *vector, u32 elsize, u32 offset, - u32 index_to_delete); -#endif /* _INDEX_LIST_H_ */ diff --git a/plugins/vcgn-plugin/vcgn/nat64_db.h b/plugins/vcgn-plugin/vcgn/nat64_db.h deleted file mode 100644 index 837464f6..00000000 --- a/plugins/vcgn-plugin/vcgn/nat64_db.h +++ /dev/null @@ -1,480 +0,0 @@ -/* - *------------------------------------------------------------------ - * nat64_db.h - Stateful NAT64 translation database definitions - * - * Copyright (c) 2010-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ -#ifndef __NAT64_DB_H__ -#define __NAT64_DB_H__ - -#include "cnat_cli.h" -#include "index_list.h" -#include "cnat_ports.h" -#include "cnat_db.h" -#include "nat64_defs.h" -#include "cnat_bulk_port_defs.h" - -nat64_vrfmap_t *nat64_map_by_vrf; - -#define SESSION_OPT - -#define HASH_ENHANCE 4 - - -#define NAT64_MAIN_DB_SIZE \ - (PLATFORM_NAT64_MAX_SESSIONS / PLATFORM_CNAT_INSTS) -#define NAT64_MAIN_HASH_SIZE \ - (HASH_ENHANCE * PLATFORM_CNAT_MAIN_PRELIM_HASH_SIZE) - -#define NAT64_MAIN_HASH_MASK (NAT64_MAIN_HASH_SIZE-1) - - -/* nb: 200000 users / 64 CNAT = 3125, 76% occupancy */ -#define NAT64_USER_HASH_SIZE CNAT_USER_HASH_SIZE -#define NAT64_USER_HASH_MASK (NAT64_USER_HASH_SIZE-1) - -/* Number of sessions per BIB entry/NAT64 translation - - nsessions is u16 type. So selected 0xFFFF - - Ideally Sessions per transltion will not reach the limit - - Only DoS can possible. It can take care of it */ -#define NAT64_MAX_SESSIONS_PER_BIB 0xFFFF - -/* No. of per ip/port config will be limited to 1000 */ -/* totally 25K across all instances) */ -#define NAT64_TIMEOUT_HASH_SIZE \ - PLATFORM_NAT64_TIMEOUT_HASH_SIZE - -#define NAT64_TIMEOUT_HASH_MASK (NAT64_TIMEOUT_HASH_SIZE - 1) -#define NAT64_TIMEOUT_FULL_MASK 0xFFFFFFFFFFFFFFFF - - -#define FORCE_DEL 1 /* Delete static BIB entries as well */ - -/* default timeout values */ -#define NAT64_UDP_DEFAULT 300 /* 5 min */ -#define NAT64_UDP_MIN 120 /* 2 min */ -#define NAT64_TCP_TRANS 240 /* 4 min */ -#define NAT64_TCP_EST 7200 /* 2 hrs */ -#define NAT64_TCP_V4_SYN 6 /* 6 sec */ -#define NAT64_FRAG_MIN 2 /* 2 sec */ -#define NAT64_ICMP_DEFAULT 60 /* 1 min */ - - -#define NAT64_V6_GET_HASH(in_key, hash, mask) \ - a = in_key->ipv6[0] ^ in_key->ipv6[1] ^ in_key->ipv6[2] ^ in_key->ipv6[3] \ - ^ ((in_key->port << 16) | in_key->vrf); \ - b = c = 0x9e3779b9;\ - /* Jenkins hash, arbitrarily use c as the "answer" */ \ - hash_mix32(a, b, c); \ - hash = c & mask; \ - - -#define NAT64_V4_GET_HASH(in_key, hash, mask) \ - a = in_key.ipv4 ^ ((in_key.port << 16) | in_key.vrf); \ - b = c = 0x9e3779b9; \ - /* Jenkins hash, arbitrarily use c as the "answer" */ \ - hash_mix32(a, b, c); \ - hash = c & mask; - - - -#define NAT64_V6_GET_SESSION_HASH(bib_index, in_addr, port, vrf, hash, mask) \ - a = bib_index ^ in_addr[0] ^ in_addr[1] ^ in_addr[2] ^ in_addr[3] \ - ^ port ^ vrf; \ - b = c = 0x9e3779b9; \ - /* Jenkins hash, arbitrarily use c as the "answer" */ \ - hash_mix32(a, b, c); \ - hash = c & mask; - -#define NAT64_V4_GET_SESSION_HASH(bib_index, in_addr, port, vrf, hash, mask) \ - a = bib_index ^ in_addr ^ port ^ vrf; \ - b = c = 0x9e3779b9; \ - /* Jenkins hash, arbitrarily use c as the "answer" */ \ - hash_mix32(a, b, c); \ - hash = c & mask; - - -extern index_slist_t *nat64_bib_out2in_hash; -extern index_slist_t *nat64_bib_in2out_hash; -extern index_slist_t *nat64_bib_user_hash; -extern index_slist_t *nat64_session_out2in_hash; -#ifndef SESSION_OPT -extern index_slist_t *nat64_session_in2out_hash; -#endif -extern index_slist_t *nat64_frag_out2in_hash; -extern index_slist_t *nat64_frag_in2out_hash; -extern index_slist_t *nat64_timeout_hash; - - -/* - * nat64_ bib_entry_t - * This structure depicts Binding Information Base of NAT64 sessions. - * It stores information about the inside v6 source transport address and - * corresponding outside v4 source transport address for each protocol. - */ - -typedef struct { - - index_slist_t nat64_bib_out2in_hash; - index_slist_t nat64_bib_in2out_hash; - - /* 0x08 */ - u16 flags; /* flags in cnat_db.h (cnat_main_db_entry_t) */ -#define NAT64_DB_FLAG_STATIC_PORT CNAT_DB_FLAG_STATIC_PORT -#define NAT64_DB_NAT64_FLAG CNAT_DB_NAT64_FLAG -#define NAT64_DB_FLAG_ALG_ENTRY CNAT_DB_FLAG_ALG_ENTRY -#define NAT64_DB_FLAG_PCPI CNAT_DB_FLAG_PCPI -#define NAT64_DB_FLAG_PCPE CNAT_DB_FLAG_PCPE - - /* 0x0A */ - u16 nat64_inst_id; - /* 0x0C */ - u32 user_index; - - /* 0x10 */ - nat64_v4_key_t v4_out_key; - - /* 0x18 */ - nat64_v6_key_t v6_in_key; - - /* 0x2C */ - index_dlist_t user_ports; - /* 0x34 */ - u32 session_head_index; - /* 0x38 - 56B*/ - u16 nsessions; - u16 pad2; - - /* 0x3C - 60B */ - u32 in2outpkts; - u32 out2inpkts; - /* 0x44 - 68B */ - - /* 0x42 - 70B */ - union { /* used by FTP ALG, pkt len delta due to FTP PORT cmd */ - u16 delta; - i8 alg_dlt[2]; /* two delta values, 0 for previous, 1 for current */ - u16 il; /* Used to indicate if interleaved mode is used - in case of RTSP ALG */ - } alg; - - u16 temp1; - - u32 entry_expires; - - u32 temp3; - /* unused, temp1 ,temp2 and temp3 put to make it in sync with nat44 main db entry size */ - /* size of = 0x54 = 84 B */ - u32 unused; - -} nat64_bib_entry_t ; - -/* - * nat64_bib_user_entry_t - * This structure stores information about translations of a particular user - * (User here refers to a same inside source address) - */ -typedef struct { - /* 0x00 */ - index_slist_t user_hash; - /* 0x04 */ - u16 ntranslations; - /* 0x06 */ - u8 icmp_msg_count; - /* 0x07 */ - u8 flags; -#define NAT64_USER_DB_NAT64_FLAG CNAT_USER_DB_NAT64_FLAG - - /* 0x08 */ - u32 translation_list_head_index; - /* 0x0C */ - u32 portmap_index; - /* 0x10 */ - nat64_v6_key_t v6_in_key; - /* 0x24 = 36 B */ - - u32 align1; /* Make it 8B boundary and in sync with nat44 user db entry size */ -#ifndef NO_BULK_LOGGING - /* size of = 0x28 = 40 B */ - /* Now adding 8 more bytes for bulk allocation.. This makes it - * 0x30 (48). For nat64 stful, we may support bulk allocation - * later */ - /* Indicates the currently used bulk port range */ - i16 bulk_port_range_cache[BULK_RANGE_CACHE_SIZE]; -#endif /* NO_BULK_LOGGING */ -} nat64_bib_user_entry_t; - -/* - * nat64_session_entry_t - * This structure represents the session table. It maintains the information - * about the flow of the packets. It would consist of source and destination - * (inside and outside) ipv4 and ipv4 transport addresses. - */ -typedef struct { - - /* 0x00 */ - index_slist_t nat64_session_out2in_hash; - - /* 0x04 */ - u32 bib_index; /* would point to v4/v6 src transport address */ - - /* 0x08 */ - nat64_v4_key_t v4_dest_key; - -#ifndef SESSION_OPT - index_slist_t nat64_session_in2out_hash; - nat64_v6_key_t v6_dest_key; -#endif - - /* 0x10 */ - u16 flags;/* Will be used for flags same as nat44 session */ - - /* 0x12 */ - u16 timeout; - - /* 0x14 */ - u32 entry_expires; - /* 0x18 */ - index_dlist_t bib_list; - /* 0x20 = 32 B */ - - union { /* alg same as cnat_main_db_t */ - u16 delta; - i8 alg_dlt[2]; - u16 il; - } alg; - - /* 0x22 */ - u16 tcp_flags; /* Mainly TCP events - check nat64_tcp_sm.h */ - - /* 0x24 */ - u32 tcp_seq_num; - - /* 0x28 */ /* unused1, unused2 and unused3 are put to make it in sync with - * cnat_session_db */ - u32 unused1; - - /* 0x2C */ - u32 unused2; - - /* 0x30 */ - u16 unused3; - - /* 0x32 - 50B */ - -} nat64_session_entry_t; - -/* - * nat64_session_tcp_init_entry_t - * This structure will be used to store information about v4 initiation - * tcp entries. - */ -typedef struct { - nat64_v6_key_t v6_in_key; - nat64_v4_key_t v4_out_key; -} nat64_session_tcp_init_entry_t; - -/* - * nat64_in_v6_frag_entry_t - * This structure will be used to store information about fragment flows - * that are coming from inside v6 hosts. - */ -typedef struct { - index_slist_t nat64_frag_in2out_hash; - - u32 v6_src_addr[4]; - u32 v6_destn_addr[4]; - u32 frag_iden; - u16 vrf; - u16 pad1; -} nat64_in_v6_frag_entry_t ; - -/* - * nat64_out_v4_frag_entry_t - * This structure will be used to store information about fragment flows - * that are coming from outside v4 machines. - */ -typedef struct { - index_slist_t nat64_frag_out2in_hash; - - u32 v4_src_addr; - u32 v4_destn_addr; - u16 frag_iden; - u16 vrf; -} nat64_out_v4_frag_entry_t ; - -/* - * nat64_timeout _t - * These following structures will be used to store information destination - * timeouts configured. - */ -typedef struct { - nat64_v4_key_t timeout_key; - u16 timeout_value; -} nat64_timeout_t; - -/* - * nat64_timeout_db_entry_t - */ -typedef struct { - nat64_timeout_t t_key; - index_slist_t t_hash; -} nat64_timeout_db_entry_t; - - -typedef union { - cnat_main_db_entry_t nat44_main_db; - nat64_bib_entry_t nat64_bib_db; -} cgse_nat_db_entry_t; - -typedef union { - cnat_session_entry_t nat44_session_db; - nat64_session_entry_t nat64_session_db; -} cgse_nat_session_db_entry_t; - -typedef union { - cnat_user_db_entry_t nat44_user_db; - nat64_bib_user_entry_t nat64_user_db; -} cgse_nat_user_db_entry_t; - -extern index_slist_t *nat64_bib_out2in_hash; -extern index_slist_t *nat64_bib_in2out_hash; -extern index_slist_t *nat64_bib_user_hash; -extern index_slist_t *nat64_session_out2in_hash; -extern index_slist_t *nat64_session_in2out_hash; -extern index_slist_t *nat64_frag_out2in_hash; -extern index_slist_t *nat64_frag_in2out_hash; -extern index_slist_t *nat64_timeout_hash; - -extern nat64_bib_entry_t *nat64_bib_db; -extern nat64_bib_user_entry_t *nat64_bib_user_db; -extern nat64_session_entry_t *nat64_session_db; -extern nat64_in_v6_frag_entry_t *nat64_in_frag_db; -extern nat64_out_v4_frag_entry_t *nat64_out_frag_db; -extern nat64_session_tcp_init_entry_t *nat64_tcp_init_db ; -extern nat64_timeout_db_entry_t *nat64_timeout_db; - -extern nat64_table_entry_t nat64_table_array[NAT64_MAX_NAT64_ENTRIES]; -extern nat64_table_entry_t *nat64_table_ptr; - -extern cgse_nat_db_entry_t *cgse_nat_db; -extern cgse_nat_user_db_entry_t *cgse_user_db; -extern cgse_nat_session_db_entry_t *cgse_session_db; - -void nat64_bib_user_db_delete (nat64_bib_user_entry_t *up); - -nat64_bib_user_entry_t* -nat64_bib_user_db_create_entry(nat64_v6_key_t *uki, u32 bucket, - u32 portmap_index); - -nat64_bib_user_entry_t* -nat64_bib_user_db_lookup_entry(nat64_v6_key_t *uki, u32 *bucket); - - -nat64_bib_entry_t* -nat64_bib_db_lookup_entry(nat64_v6_key_t *ki); - -void nat64_bib_db_in2out_hash_delete (nat64_bib_entry_t *ep); - -void nat64_bib_db_out2in_hash_delete (nat64_bib_entry_t *ep); - -nat64_bib_entry_t * -nat64_create_bib_db_entry_and_hash(nat64_v6_key_t *ki, - nat64_v4_key_t *ko, - nat64_bib_user_entry_t *udb); - - -void nat64_delete_bib_db_entry (nat64_bib_entry_t *ep, u8 force); - -nat64_bib_entry_t * -nat64_bib_db_lookup_entry_out2in (nat64_v4_key_t *ko); - -nat64_bib_entry_t * -nat64_get_bib_db_entry (nat64_v6_key_t *ki, - port_pair_t port_pair_type, - port_type_t port_type, - cnat_gen_icmp_info *info); - - -nat64_bib_entry_t* -nat64_create_static_bib_db_entry (nat64_v6_key_t *ki, - nat64_v4_key_t *ko, - nat64_table_entry_t *my_table, - cnat_gen_icmp_info *info); - - - -//void nat64_session_db_in2out_hash_delete (nat64_session_entry_t *ep); -void nat64_session_db_out2in_hash_delete (nat64_session_entry_t *ep); - -/*nat64_session_entry_t * -nat64_session_db_lookup_entry(nat64_v6_key_t *ki, u32 bib_index); */ - - -nat64_session_entry_t * -nat64_session_db_lookup_entry_out2in (nat64_v4_key_t *ko,u32 bib_index); - -/* -nat64_session_entry_t * -nat64_create_session_db_entry(nat64_v6_key_t *ki, - nat64_v4_key_t *ko, - nat64_bib_entry_t *bdb); -*/ -nat64_session_entry_t * -nat64_create_session_db_entry_v2( nat64_v4_key_t *ko, - nat64_bib_entry_t *bdb); - - -//void nat64_delete_session_db_entry (nat64_session_entry_t *ep); -void nat64_delete_session_db_entry_v2 (nat64_session_entry_t *ep, u8 force); - -u32 nat64_timeout_db_hash_lookup (nat64_v4_key_t t_key); - -u16 query_and_update_db_timeout_nat64(nat64_session_entry_t *db); - -void nat64_timeout_db_hash_add (nat64_timeout_db_entry_t *t_entry); - -u16 nat64_timeout_db_create (nat64_timeout_t t_entry); - -void nat64_timeout_db_delete(nat64_v4_key_t t_key); - -#define NAT64_CMP_V6_KEY(key1, key2) \ - memcmp(key1, key2, sizeof(nat64_v6_key_t)) - -#define NAT64_CMP_V4_KEY(key1, key2) \ - memcmp(key1, key2, sizeof(nat64_v4_key_t)) - - -#define NAT64_CMP_V6_IP(ip1, ip2) \ - memcmp(ip1, ip2, (sizeof(u32) * 4)) - - -#define NAT64_CMP_V6_KEY1(key1, key2) \ - (key1.ipv6[0] == key2.ipv6[0]) && (key1.ipv6[1] == key2.ipv6[1]) && \ - (key1.ipv6[2] == key2.ipv6[2]) && (key1.ipv6[3] == key2.ipv6[3]) && \ - (key1.port == key2.port) && (key1.vrf == key2.vrf) - - -#define NAT64_CMP_V6_IP1(ip1, ip2) \ - ((ip1[0] == ip2[0]) && (ip1[1] == ip2[1]) && \ - (ip1[2] == ip2[2]) && (ip1[3] == ip2[3])) - -#define NAT64_CMP_V4_KEY1(key1, key2) \ - (key1.key64 == key2.key64) - - -extern u8 nat64_timeout_dirty_flag[NAT64_MAX_NAT64_ENTRIES]; - -#endif diff --git a/plugins/vcgn-plugin/vcgn/nat64_defs.h b/plugins/vcgn-plugin/vcgn/nat64_defs.h deleted file mode 100644 index 47e431a7..00000000 --- a/plugins/vcgn-plugin/vcgn/nat64_defs.h +++ /dev/null @@ -1,576 +0,0 @@ -/* - *------------------------------------------------------------------ - * nat64_defs.h - NAT64 structure definiitions - * - * Copyright (c) 2007-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef __NAT64_DEFS_H__ -#define __NAT64_DEFS_H__ - -#ifdef TOBE_PORTED -#include "spp_platform_common.h" -#include "cgse_defs.h" -#include "xlat_defs.h" -#endif -#include "cnat_cli.h" -#include "cnat_ports.h" -#include "tcp_header_definitions.h" -#include "nat64_tcp_sm.h" -#include "cnat_db.h" - -#define NAT64_MAX_FRAG_ID_COUNTERS (256) - -#define NAT64_MAX_NAT64_ENTRIES 500 - -#define NAT64_MAX_ID (NAT64_MAX_NAT64_ENTRIES-1) - -#define NAT64_INVALID_ID (0) - -#define NAT64_MAX_CFG_INSTANCES 64 - -#define NAT64_TABLE_ENTRY_DELETED 0 -#define NAT64_TABLE_ENTRY_ACTIVE 1 -#define NAT64_TABLE_ENTRY_DORMANT 2 -#define NAT64_TABLE_ENTRY_INVALID_UIDB 3 - -#define NAT64_MAX_TRANSLATION_ENTRIES PLATFORM_MAX_TRANSLATION_ENTRIES - -#define NAT64_WKP_PREFIX_LEN 96 -#define NAT64_WKP_PREFIX_0 0x0064FF9B -#define NAT64_WKP_PREFIX_1 0x00000000 -#define NAT64_WKP_PREFIX_2 0x00000000 -#define NAT64_WKP_PREFIX_3 0x00000000 - - -/* Reset the expiry time only if it is not 0 -** if it is 0 - then queue for delete by clear command -**/ - -#define NAT64_TIMEOUT_RST(db) \ - if(PREDICT_TRUE(db->entry_expires !=0 )) \ - db->entry_expires = cnat_current_time; - -extern u32 nat64_config_debug_level; -extern u32 nat64_data_path_debug_level; - -extern u32 nat64_translation_create_count[NAT64_MAX_NAT64_ENTRIES]; -extern u32 nat64_translation_delete_count[NAT64_MAX_NAT64_ENTRIES]; -extern u32 nat64_translation_create_rate[NAT64_MAX_NAT64_ENTRIES]; -extern u32 nat64_translation_delete_rate[NAT64_MAX_NAT64_ENTRIES]; -extern u32 nat64_in2out_forwarding_count[NAT64_MAX_NAT64_ENTRIES]; -extern u32 nat64_in2out_forwarding_rate[NAT64_MAX_NAT64_ENTRIES]; -extern u32 nat64_out2in_forwarding_count[NAT64_MAX_NAT64_ENTRIES]; -extern u32 nat64_out2in_forwarding_rate[NAT64_MAX_NAT64_ENTRIES]; - -extern u32 nat64_translation_create_count_old[NAT64_MAX_NAT64_ENTRIES]; -extern u32 nat64_translation_delete_count_old[NAT64_MAX_NAT64_ENTRIES]; -extern u32 nat64_in2out_forwarding_count_old[NAT64_MAX_NAT64_ENTRIES]; -extern u32 nat64_out2in_forwarding_count_old[NAT64_MAX_NAT64_ENTRIES]; - -extern u16 *nat64_frag_id_counter_ptr; - -typedef struct { - u64 v6_to_v4_tcp_input_count; - u64 v6_to_v4_tcp_non_translatable_drop_count; - u64 v6_to_v4_tcp_state_drop_count; - u64 v6_to_v4_tcp_no_db_drop_count; - u64 v6_to_v4_tcp_output_count; -} nat64_v6_to_v4_tcp_counter_t; - -typedef struct { - u64 v4_to_v6_tcp_input_count; - u64 v4_to_v6_tcp_no_db_drop_count; - u64 v4_to_v6_tcp_v4_init_policy_drop_count; - u64 v4_to_v6_tcp_state_drop_count; - u64 v4_to_v6_tcp_output_count; - u64 v4_to_v6_tcp_filter_drop_count; -} nat64_v4_to_v6_tcp_counter_t; - -typedef struct { - u64 v6_to_v4_udp_input_count; - u64 v6_to_v4_udp_non_translatable_drop_count; - u64 v6_to_v4_udp_no_db_drop_count; - u64 v6_to_v4_udp_output_count; - u64 v6_to_v4_udp_checksum_zero_count; -} nat64_v6_to_v4_udp_counter_t; - -typedef struct { - u64 v4_to_v6_udp_input_count; - u64 v4_to_v6_udp_no_db_drop_count; - u64 v4_to_v6_udp_filter_drop_count; - u64 v4_to_v6_udp_output_count; - u64 v4_to_v6_udp_crc_zero_drop_count; - u64 v4_to_v6_udp_frag_crc_zero_drop_count; - u64 v4_to_v6_udp_crc_zero_recycle_sent_count; - u64 v4_to_v6_udp_crc_zero_recycle_drop_count; -} nat64_v4_to_v6_udp_counter_t; - -typedef struct { - u64 v6_to_v4_icmp_input_count; - u64 v6_to_v4_icmp_no_db_drop_count; - u64 v6_to_v4_icmp_non_translatable_drop_count; - u64 v6_to_v4_icmp_qry_output_count; -} nat64_v6_to_v4_icmp_counter_t; - -typedef struct { - u64 v4_to_v6_icmp_input_count; - u64 v4_to_v6_icmp_no_db_drop_count; - u64 v4_to_v6_icmp_filter_drop; - u64 v4_to_v6_icmp_qry_output_count; -} nat64_v4_to_v6_icmp_counter_t; - -typedef struct { - u64 v6_to_v4_icmp_error_input_count; - u64 v6_to_v4_icmp_error_no_db_drop_count; - u64 v6_to_v4_icmp_error_invalid_next_hdr_drop_count; - u64 v6_to_v4_icmp_error_non_translatable_drop_count; - u64 v6_to_v4_icmp_error_unsupported_type_drop_count; - u64 v6_to_v4_icmp_error_output_count; -} nat64_v6_to_v4_icmp_error_counter_t; - -typedef struct { - u64 v4_to_v6_icmp_error_input_count; - u64 v4_to_v6_icmp_error_no_db_drop_count; - u64 v4_to_v6_icmp_error_unsupported_type_drop_count; - u64 v4_to_v6_icmp_error_unsupported_protocol_drop_count; - u64 v4_to_v6_icmp_error_output_count; -} nat64_v4_to_v6_icmp_error_counter_t; - - - -typedef struct { - u64 nat64_v4_frag_input_count; - u64 nat64_v4_frag_forward_count; - u64 nat64_v4_frag_drop_count; - u64 nat64_v4_frag_throttled_count; - u64 nat64_v4_frag_timeout_drop_count; - u64 nat64_v4_frag_tcp_input_count; - u64 nat64_v4_frag_udp_input_count; - u64 nat64_v4_frag_icmp_input_count; - - u64 nat64_v6_frag_input_count; - u64 nat64_v6_frag_forward_count; - u64 nat64_v6_frag_drop_count; - u64 nat64_v6_frag_throttled_count; - u64 nat64_v6_frag_timeout_drop_count; - u64 nat64_v6_frag_tcp_input_count; - u64 nat64_v6_frag_udp_input_count; - u64 nat64_v6_frag_icmp_input_count; - u64 nat64_v6_frag_invalid_input_count; -} nat64_frag_counter_t; - -typedef struct { - u64 v6_to_v4_options_input_count; - u64 v6_to_v4_options_drop_count; - u64 v6_to_v4_options_forward_count; - u64 v6_to_v4_options_no_db_drop_count; - u64 v6_to_v4_unsupp_proto_count; - - u64 v4_to_v6_options_input_count; - u64 v4_to_v6_options_drop_count; - u64 v4_to_v6_options_forward_count; - u64 v4_to_v6_options_no_db_drop_count; - u64 v4_to_v6_unsupp_proto_count; -} nat64_options_counter_t; - -typedef struct { - u64 v4_icmp_gen_count; - u64 v6_icmp_gen_count; -} nat64_icmp_gen_counter_t; - -typedef struct{ - u32 nat64_num_translations; - u32 nat64_num_dynamic_translations; - u32 nat64_num_static_translations; - u32 nat64_sessions; - u64 nat64_port_limit_exceeded; - u64 nat64_system_limit_reached; - u64 nat64_resource_depletion_drops; - u64 nat64_no_translation_entry_drops; - u64 nat64_filtering_drops ; - u64 nat64_invalid_ipv6_prefix_drops; - u32 num_subscribers; - u32 dummy; - u64 drops_sessiondb_limit_exceeded; -} nat64_inst_gen_counter_t; - -typedef struct { - - nat64_v6_to_v4_tcp_counter_t v64_tcp_counters; - nat64_v4_to_v6_tcp_counter_t v46_tcp_counters; - nat64_v6_to_v4_udp_counter_t v64_udp_counters; - nat64_v4_to_v6_udp_counter_t v46_udp_counters; - nat64_v6_to_v4_icmp_counter_t v64_icmp_counters; - nat64_v4_to_v6_icmp_counter_t v46_icmp_counters; - nat64_v6_to_v4_icmp_error_counter_t v64_icmp_error_counters; - nat64_v4_to_v6_icmp_error_counter_t v46_icmp_error_counters; - nat64_frag_counter_t nat64_frag_counters; - nat64_options_counter_t nat64_options_counters; - nat64_icmp_gen_counter_t nat64_icmp_gen_counters; - -} nat64_counters_t; - -/* - * nat64_portmap_v2_t - * This structure stores information about the IP address and ports - * available for NAT for this nat64 instance. - */ - -typedef struct { - u32 delete_time; - u32 last_sent_timestamp; - u32 inuse; - u32 ipv4_address; /* native bit order */ - uword bm[(BITS_PER_INST + BITS(uword)-1)/BITS(uword)]; -} nat64_portmap_t; - -/* - * nat64_v4_db_key_t - * This structure gives information about the v4 transport address - * (ipv4, port, protocol) - */ -typedef struct { - u32 ipv4; - u16 port; - u16 vrf; //bit0-12:inst_id, bit13:unused, bit14-15:protocol -} nat64_v4_db_key_t; - -/* Union will be easier while compare/hash */ -typedef union { - nat64_v4_db_key_t k; - u64 key64; -} nat64_v4_key_t; -/* - * nat64_v6_db_key_t - * This structure gives information about the v6 transport address - * (ipv6, port, protocol) - */ -typedef struct { - u32 ipv6[4]; - u16 port; - u16 vrf; //bit0-12:inst_id, bit13:unused, bit14-15:protocol -} nat64_v6_key_t; - - -typedef struct { - u16 udp_timeout; - u16 tcp_trans_timeout; - u16 tcp_est_timeout; - u16 tcp_v4_init_timeout; - u16 frag_timeout; - u16 icmp_timeout; -} nat64_timeout_info_t; - -#define NAT64_UDP_DEF 300 /* 5min */ -#define NAT64_TCP_TRANS_DEF 240 /* 4min */ -#define NAT64_TCP_EST_DEF 7200 /* 2Hrs */ -#define NAT64_TCP_V4_DEF 6 /* 6 sec */ -#define NAT64_FRAG_DEF 2 /* 2 sec */ -#define NAT64_ICMP_DEF 60 /* 60 sec */ - -/* - * nat64_table_entry_t - * This structure is used to store information regarding every nat64 instance. - */ - -/* structure will hold the L4 information, of a particular frag stream set - * src_port - holds the original src port - * dst_port - holds the original dst port - * total_len - useful only in ICMP nodes - * cnat_port - vlaue used for looksups - * next_prot - Protocol after translation */ - -typedef struct l4_frag_info { - u16 next_node_idx; - u16 src_port; - u16 dst_port; - u16 total_length; - u8 protocol; - u16 cnat_prot; - u16 next_prot; -} l4_frag_info_t; - -typedef struct { - u16 state; - u16 nat64_id; /* nat64_id value for this table entry - for easy access */ - - u16 v4_uidb_index; /* V4 uidb index */ - u16 v6_uidb_index; /* V6 uidb index */ - - u8 octet0_position; - u8 octet1_position; - u8 octet2_position; - u8 octet3_position; - - u16 v4_to_v6_tcp_mss; /* TCP MSS */ - u16 v6_to_v4_tcp_mss; /* TCP MSS */ - - /* - * V6 NAT64 prefix value and mask size - */ - u32 v6_prefix[4]; - u32 v6_prefix_mask[4]; - - u8 v6_prefix_mask_len; - u8 ubits_reserved_on; -#define IPV4_TOS_OVERRIDE_FLAG 0x1 -#define IPV6_TOS_OVERRIDE_FLAG 0x2 -#define NAT64_STFUL_RTSP_ALG_ENABLE 0x4 - u8 feature_flags; - - u8 ipv4_tos_value; - u8 ipv6_tos_value; - u8 df_bit_clear; - u8 ipv6_mtu_set; - - u8 filtering_policy; -#define NAT64_ADDRESS_DEPENDENT_ENABLE 1 - u8 tcp_policy; -#define NAT64_TCP_SECURITY_FLAG_DISABLE 1 - u8 ftp_flags; - - u8 tcp_v4_init_enable; -#define NAT64_TCP_V4_INIT_ENABLE 1 - - u8 logging_policy; -#define NAT64_BIB_LOG_ENABLE 0 /* Default */ -#define NAT64_SESSION_LOG_ENABLE 1 - -#define NAT64_BIDIR_REFRESH 1 /* 1 - timer refresh in both direction */ -#define NAT64_UNIDIR_REFRESH 0 /* 0 - default (only v6 side refresh timer)*/ - - u8 nat64_refresh_both_direction; /* 0 - default (only v6 side refresh timer) */ -#define NAT64_BIDIR_REFRESH 1 /* 1 - timer refresh in both direction */ - - u8 udp_zero_checksum; /* 0 - default (calc checksum) */ -#define NAT64_UDP_ZERO_CHECKSUM_DROP 1 /* 1 -drop */ - - u16 port_limit; - - cnat_portmap_v2_t *port_map; - - u32 logging_index; - - nat64_timeout_info_t timeout_info; - /* - * These fields are not used much, let us keep it in the end - */ - u32 v4_vrf_id; /* V4 vrf id */ - u32 v6_vrf_id; /* V6 vrf id */ - - u32 v4_if_num; /* V4 SVI ifnum */ - u32 v6_if_num; /* V6 SVI ifnum */ - - u16 dyn_start_port; - - u16 pcp_server_port; - u32 pcp_server_addr[4]; - u32 rseed_ip; -#define NAT64_FRAG_ENABLE 1 -#define NAT64_FRAG_DISABLE 0 - u8 frag_state; - u8 nat64_enable; /* Enable/Disable this instance. */ - - u16 rtsp_port; - -} nat64_table_entry_t; - - - -extern nat64_table_entry_t nat64_table_array[NAT64_MAX_NAT64_ENTRIES]; -extern nat64_table_entry_t *nat64_table_ptr; -extern nat64_counters_t nat64_all_counters[NAT64_MAX_NAT64_ENTRIES]; -extern nat64_inst_gen_counter_t nat64_inst_gen_counters[NAT64_MAX_NAT64_ENTRIES]; - -typedef struct nat64_common_pipeline_data_ { -#ifdef TOBE_PORTED - spp_node_main_vector_t *nmv; -#endif - - u16 *nat64_id_ptr; - - nat64_table_entry_t *nat64_entry_ptr; - -} nat64_common_pipeline_data_t; - -typedef struct nat64_v6_to_v4_pipeline_data_ { - nat64_common_pipeline_data_t common_data; - - u32 bib_bucket; - u32 session_bucket; - - nat64_v6_key_t v6_in_key; - nat64_v6_key_t v6_dest_key; - - /* - * IPv6 Data, everthing in host order except for the addr fields - */ - u32 version_trafficclass_flowlabel; - - u16 payload_length; - u8 next_header; - u8 hop_limit; - - /* - * These Address fields are in Network Order, so that - * it is easy to extract the IPv4 address from them - */ - u32 ipv6_src[4]; - - u32 ipv6_dst[4]; - - u8 frag_next_header; - u8 frag_reserved; - u16 frag_offset_res_m; - u32 frag_identification; - - ipv4_header *ipv4_header; - union { - struct _v4_l4_info { - u8 *ipv4_l4_header; - u8 pad0; - u8 pad1; - u8 pad2; - u8 pad3; - } v4_l4_info; - struct _v4_icmp_info { - icmp_v4_t *ipv4_icmp_header; - u8 old_icmp_type; - u8 new_icmp_type; - u8 old_icmp_code; - u8 new_icmp_code; - u16 checksum; - u16 old_iden; // length (ICMP extn), ptr (param) - u16 new_iden; // ----- do ------------- - u16 old_seq; // MTU for PTB case - u16 new_seq; // ----- do ------------- - } v4_icmp_info; - struct _v4_udp_info { - udp_hdr_type_t *ipv4_udp_header; - u8 pad0; - u8 pad1; - u8 pad2; - u8 pad3; - } v4_udp_info; - struct _v4_tcp_info { - tcp_hdr_type *ipv4_tcp_header; - u16 old_src_port; - u16 new_src_port; - u16 dest_port; - nat64_tcp_events tcp_event; - } v4_tcp_info; - } l4_u; - - - l4_frag_info_t *frag_info; /* port for tcp/udp, ident - icmp */ - - - /* Counters will be added here */ - union { - nat64_v6_to_v4_tcp_counter_t *tcp_counter; - nat64_v6_to_v4_udp_counter_t *udp_counter; - nat64_v6_to_v4_icmp_counter_t *icmp_counter; - nat64_v6_to_v4_icmp_error_counter_t *icmp_error_counter; - nat64_frag_counter_t *frag_counter; - nat64_options_counter_t *options_counter; - } nat64_ctr_u; - nat64_icmp_gen_counter_t *icmp_gen_counter; -} nat64_v6_to_v4_pipeline_data_t; - - -typedef struct nat64_v4_to_v6_pipeline_data_ { - nat64_common_pipeline_data_t common_data; - - u32 bib_bucket; - u32 session_bucket; - - nat64_v4_key_t v4_src_key; /* Will be translated using Prefix */ - nat64_v4_key_t v4_dest_key; /* will be the out key for NAT64 */ - - /* - * IPv4 data - */ - u8 version_hdr_len_words; - u8 tos; - u16 total_len_bytes; - - u16 identification; - u16 frag_flags_offset; - - u8 ttl; - u8 protocol; - u16 l4_checksum; - - u32 ipv4_src_addr; - u32 ipv4_dst_addr; - - /* - * Pointers to IPv6 headers - */ - ipv6_header_t *ipv6_header; - ipv6_frag_header_t *ipv6_frag_header; - - union { - struct _v6_l4_info { - u8 *ipv6_l4_header; - u8 pad0; - u8 pad1; - u8 pad2; - u8 pad3; - } v6_l4_info; - struct _v6_icmp_info { - icmp_v6_t *ipv6_icmp_header; - u8 old_icmp_type; - u8 new_icmp_type; - u8 old_icmp_code; - u8 new_icmp_code; - u16 old_iden; // length (ICMP extn), ptr (param) - u16 new_iden; // ----- do ------------- - u16 old_seq; // MTU for PTB case - u16 new_seq; // ----- do ------------- - } v6_icmp_info; - struct _v6_udp_info { - udp_hdr_type_t *ipv6_udp_header; - u8 pad0; - u8 pad1; - u8 pad2; - u8 pad3; - } v6_udp_info; - struct _v6_tcp_info { - tcp_hdr_type *ipv6_tcp_header; - u16 old_dest_port; - u16 new_dest_port; - u16 src_port; - nat64_tcp_events tcp_event; - } v6_tcp_info; - } l4_u; - - l4_frag_info_t *frag_info; /* port for tcp/udp, ident - icmp */ - - /* Need to add counters here */ - union { - nat64_v4_to_v6_tcp_counter_t *tcp_counter; - nat64_v4_to_v6_udp_counter_t *udp_counter; - nat64_v4_to_v6_icmp_counter_t *icmp_counter; - nat64_v4_to_v6_icmp_error_counter_t *icmp_error_counter; - nat64_frag_counter_t *frag_counter; - nat64_options_counter_t *options_counter; - } nat64_ctr_u; - nat64_icmp_gen_counter_t *icmp_gen_counter; - -} nat64_v4_to_v6_pipeline_data_t; - -#endif diff --git a/plugins/vcgn-plugin/vcgn/nat64_tcp_sm.h b/plugins/vcgn-plugin/vcgn/nat64_tcp_sm.h deleted file mode 100644 index 3a505bc1..00000000 --- a/plugins/vcgn-plugin/vcgn/nat64_tcp_sm.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - *------------------------------------------------------------------ - * nat64_tcp_sm.h - Stateful NAT64 translation TCP State machine - * - * Copyright (c) 2011 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ -#ifndef __NAT64_TCP_SM_H__ -#define __NAT64_TCP_SM_H__ - - -/* TCP States */ -typedef enum { - TCP_CLOSED, - TCP_V4_INIT, - TCP_V6_INIT, - TCP_ESTABLISHED, - TCP_V4_FIN_RCV, - TCP_V6_FIN_RCV, - TCP_V4V6_FIN_RCV, - TCP_TRANS, - TCP_NONE -} nat64_tcp_states; - -/* TCP Events */ -typedef enum { - TCP_TIMEOUT_EV, - TCP_V6_SYN_EV, - TCP_V4_SYN_EV, - TCP_V6_FIN_EV, - TCP_V4_FIN_EV, - TCP_V6_RST_EV, - TCP_V4_RST_EV, - TCP_DEFAULT_EV, - TCP_EV_COUNT -} nat64_tcp_events; - -/* TCP Actions */ -typedef enum { - TCP_FORWARD, - TCP_COND_FORWARD, /* Conditional forward, based on presence of - * session and bib entries */ - TCP_STORE, - TCP_PROBE, - TCP_CREATE_SESSION, - TCP_DELETE_SESSION, - TCP_DROP, - TCP_ACTION_NONE, - TCP_ACTION_COUNT -} nat64_tcp_actions; - -typedef struct { - nat64_tcp_states next_state; - nat64_tcp_actions action; -} nat64_tcp_trans_t; - -typedef struct { - nat64_tcp_trans_t event[TCP_EV_COUNT]; -} nat64_tcp_state_trans_t; - -extern nat64_tcp_state_trans_t nat64_tcp_sm_lookup[TCP_NONE]; - -/* -inline void -nat64_update_v6_to_v4_tcp (nat64_v6_to_v4_pipeline_data_t *pctx_ptr, - nat64_bib_entry_t *bib_ptr); - -inline u8 nat64_v6_to_v4_tcp_perform_action ( - spp_ctx_t *ctx, - nat64_v6_to_v4_pipeline_data_t *pctx_ptr, - nat64_bib_entry_t *bib_db, - nat64_session_entry_t *session_db); - -inline void -nat64_copy_tcp_into_pctx (nat64_v6_to_v4_pipeline_data_t *pctx_ptr); -*/ - - - -#endif diff --git a/plugins/vcgn-plugin/vcgn/platform_common.h b/plugins/vcgn-plugin/vcgn/platform_common.h deleted file mode 100644 index 2805b607..00000000 --- a/plugins/vcgn-plugin/vcgn/platform_common.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - *--------------------------------------------------------------------------- - * platform_common.h -- file has all platform related macros defined as NULL - * included "platform_common_override.h will have actual - * platform specific defines - * - * Copyright (c) 2011-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *--------------------------------------------------------------------------- - */ -#ifndef __PLATFORM_COMMON_H__ -#define __PLATFORM_COMMON_H__ - -/* $$$ FIXME causes printf format warnings */ -#define PLATFORM_DEBUG_PRINT(...) /* printf(__VA_ARGS__) */ -#define PLATFORM_FILL_DST_ADDR_PORT_TABLE -#define PLATFORM_SET_CTX_RU_TX_FROM_NODE(ctx, value) -#define PLATFORM_SET_CTX_RU_TX_DST_IPPORT_IDX(ctx, value) -#define PLATFORM_SET_CTX_RU_TX_PKT_TYPE(ctx, type) -#define PLATFORM_SET_RX_VRF(ctx, rx_vrf, hardcode, mask) -#define PLATFORM_SET_TX_VRF(ctx, tx_vrf) -/* PLATFORM_CNAT_SET_RX_VRF definition is not same as PLATFORM_SET_RX_VRF, - * So, maintaining two different definitions - */ -#define PLATFORM_CNAT_SET_RX_VRF(ctx, rx_vrf, proto) -#define PLATFORM_CNAT_SET_TX_VRF(ctx, tx_vrf) - -#define PLATFORM_PRINT_TESTING_PG() -#define PLATFORM_INIT_TEMP_SENSORS() -#define PLATFORM_READ_CPU_SENSORS(value) -#define PLATFORM_SET_TEMP_READ_BLOCK(var, val) -#define PLATFORM_NFV9_DISP_NODE_IDX - - -/* Assumption is, syslog packets - * are sent out via same channel as that of NFV9. - * Has to be overridden if this assumption is false. - */ -#define PLATFORM_SYSLOG_DISP_NODE_IDX PLATFORM_NFV9_DISP_NODE_IDX - -#define PLATFORM_CNAT_DB_DUMP_POLICY_PRINT() -#define PLATFORM_PRINT_CTX_VALUES(ctx) -#define PLATFORM_ADD_VRF_MAP_HANDLE_PARTITION(uidb_index, partition_id) -#define PLATFORM_DEL_VRF_MAP_HANDLE_PARTITION(uidb_index, partition_id) -#define PLATFORM_ALLOC_NFV9_PKT_BUFFER(ctx, to_lc_cpu) -#define PLATFORM_SET_DSLITE_ENABLE_FLAG(uidb_index, dslite_id) -#define PLATFORM_CHECK_DSLITE_ENABLE_FLAG - -#define PLATFORM_CNAT_INSTS 1 -#define PLATFORM_HANDLE_TTL_DECREMENT 0 // Don't handle TTL in NAT44 Application (default). - -// For ISM, we need to copy the ipv6->hop_limit to ipv4 ttl. -#define PLATFORM_6RD_COPY_TTL_IPV6_TO_IPV4 0 - -//For ISM case, need to allow as the TTL decrement happens at ingress LC -#define PLATFORM_6RD_ALLOW_TTL_1 0 - -#define PLATFORM_HANDLE_ICMP_TTL_EXPIRED 0 // Don't handle ICMP_ERROR msg for TTL <=1 in NAT44 App (default). - -#define PLATFORM_IPV4_FRAG_FRAG_HOLD_LIMIT 1 -#define PLATFORM_MAX_IPV4_CTX_ENTRIES 1 -#define PLATFORM_MAPE_FRAG 0 - -#define PLATFORM_ADDR_MASK_PER_CORE 0 -#define PLATFORM_ADDR_MASK_PER_CORE_PER_PARTITION 0 -#define PLATFORM_MAX_CORES 1 -#define PLATFORM_MAX_CORES_PER_PARTITION 1 -#define PLATFORM_MAX_NAT_ENTRIES 1 -#define PLATFORM_MAX_USER_ENTRIES 1 -#define PLATFORM_CNAT_MAX_ADDR_POOL_SIZE 0x1 -#define PLATFORM_DBL_SUPPORT 0 /* Default no DBL support, no NAT44 session table */ - -#define PLATFORM_MAX_DB_ENTRY_PER_SCAN 1 -#define PLATFORM_MAX_DB_ENTRY_SELECTED_PER_SCAN 1 -#define MAX_COMBINED_DB_ENTRIES_PER_SCAN 0 - -#define PLATFORM_CNAT_TIMEOUT_IPPROT_MASK 0 -#define PLATFORM_CNAT_TIMEOUT_PORTPROT_MASK 0 - -#define PLATFORM_MAX_SHOW_BUFFER_SIZE 1700 -#define PLATFORM_MAX_TRANSLATION_ENTRIES (50) -#define PLATFORM_MAX_UTIL_ENTRIES (100) -#define PLATFORM_MAX_NAT44_UTIL_ENTRIES ((64)/PLATFORM_MAX_CORES) - -#define PLATFORM_CNAT_NFV9_SHIM_HDR_OFFSET 0 -#define PLATFORM_CNAT_NFV9_L2_ENCAPS_OFFSET 0 - - -/* Below are nat64 statful related define */ -#define PLATFORM_NAT64_SET_RX_VRF(rx_vrf, proto, inst_id) \ - rx_vrf = proto | (inst_id & CNAT_VRF_MASK); - -#define PLATFORM_NAT64_MAX_TRANSLATION_ENTRIES (30) -#define PLATFORM_DS_LITE_MAX_TRANSLATION_ENTRIES (30) - -#define PLATFORM_SET_NAT64_ENABLE_FLAG(uidb_index, nat64_id) \ - { \ - nat64_set_enable_flag(nat64_id, ENABLE); \ - } - -#define PLATFORM_CHECK_NAT64_ENABLE_FLAG 1 -#define PLATFORM_SET_MAPE_ENABLE_FLAG(uidb_index, mape_id) -#define PLATFORM_CHECK_MAPE_ENABLE_FLAG 1 - -/* very small number , PD has correct value. - this is bcoz, if platform doesnt support nat64..shudnt take too much..*/ -#define PLATFORM_NAT64_MAX_SESSIONS 10 -#define PLATFORM_NAT64_TIMEOUT_HASH_SIZE 10 -#define PLATFORM_MAP_ADDR_PER_CORE 1024 - -#define ENABLE 1 -#define DISABLE 0 - -/* Platform Xlat inline learn function */ -#define PLATFORM_INLINE_LEARN_FUNC(a,b,c) - - -/* Checksum calculation to be done in software */ -#define PLATFORM_XLAT_SW_CHECKSUM_CALC 0 - - -/* Below include overrides all the above null defs and defines platform specific - define */ -#include "platform_common_override.h" - -#endif /* __PLATFORM_COMMON_H__ */ diff --git a/plugins/vcgn-plugin/vcgn/platform_common_override.h b/plugins/vcgn-plugin/vcgn/platform_common_override.h deleted file mode 100644 index d6d3b078..00000000 --- a/plugins/vcgn-plugin/vcgn/platform_common_override.h +++ /dev/null @@ -1,304 +0,0 @@ -/* - *--------------------------------------------------------------------------- - * platform_common_override.h -- Files has actual platform specific defines. - * Will only included by platform_common.h - * - * Copyright (c) 2011-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *--------------------------------------------------------------------------- - */ - -#ifndef __PLATFORM_COMMON_OVERRIDE_H__ -#define __PLATFORM_COMMON_OVERRIDE_H__ - -extern unsigned char my_octeon_id; - -#undef PLATFORM_DBL_SUPPORT -#define PLATFORM_DBL_SUPPORT 1 // Destination Based logging support - // NAT44 session table required. - -#undef PLATFORM_ADDR_MASK_PER_CORE -/* commenting this. Currently we are considering only single core */ -//#define PLATFORM_ADDR_MASK_PER_CORE 0x3f // Using 64 cores -#define PLATFORM_ADDR_MASK_PER_CORE 0x01 - -#undef MAX_COMBINED_DB_ENTRIES_PER_SCAN -#define MAX_COMBINED_DB_ENTRIES_PER_SCAN 128 - -#undef PLATFORM_MAX_CORES -#define PLATFORM_MAX_CORES (PLATFORM_ADDR_MASK_PER_CORE + 1) - -// Roddick does not have any partition of cores -#undef PLATFORM_ADDR_MASK_PER_CORE_PER_PARTITION -#define PLATFORM_ADDR_MASK_PER_CORE_PER_PARTITION \ - PLATFORM_ADDR_MASK_PER_CORE - -#undef PLATFORM_MAX_CORES_PER_PARTITION -#define PLATFORM_MAX_CORES_PER_PARTITION PLATFORM_MAX_CORES - -#undef PLATFORM_CNAT_INSTS -//#define PLATFORM_CNAT_INSTS 64 -#define PLATFORM_CNAT_INSTS 1 /* currently its only single instance */ - -#undef PLATFORM_MAX_NAT_ENTRIES -//#define PLATFORM_MAX_NAT_ENTRIES 20000000 // 20M -#define PLATFORM_MAX_NAT_ENTRIES 1666660 // ~80M/48 (79999680/48) - -#undef PLATFORM_MAX_USER_ENTRIES -#define PLATFORM_MAX_USER_ENTRIES 20800 // ~1M/48 (998400/48) - - -/* 524288: - (20000000 translations) / (64 CNAT INSTANCES) = 312500 - nearest higher number which is power of 2 next to 312500 -*/ -#undef PLATFORM_CNAT_MAIN_PRELIM_HASH_SIZE -//#define PLATFORM_CNAT_MAIN_PRELIM_HASH_SIZE 524288 -#define PLATFORM_CNAT_MAIN_PRELIM_HASH_SIZE (5<<20) -/* 4096: - (200000 users) / (64 CNAT INSTANCES) = 3125 - nearest higher number which is power of 2 next to 3125 -*/ -#undef PLATFORM_CNAT_USER_PRELIM_HASH_SIZE -#define PLATFORM_CNAT_USER_PRELIM_HASH_SIZE 4096 - -#undef PLATFORM_CNAT_MAX_ADDR_POOL_SIZE -#define PLATFORM_CNAT_MAX_ADDR_POOL_SIZE 0x10000 // max /16 - -#undef PLATFORM_MAX_DB_ENTRY_PER_SCAN -#define PLATFORM_MAX_DB_ENTRY_PER_SCAN 400 - -#undef PLATFORM_MAX_DB_ENTRY_SELECTED_PER_SCAN -#define PLATFORM_MAX_DB_ENTRY_SELECTED_PER_SCAN 100 // 1/4th of above - -#undef PLATFORM_CNAT_TIMEOUT_IPPROT_MASK -#define PLATFORM_CNAT_TIMEOUT_IPPROT_MASK 0xFFFFFFFF0000FFFF - -#undef PLATFORM_CNAT_TIMEOUT_PORTPROT_MASK -#define PLATFORM_CNAT_TIMEOUT_PORTPROT_MASK 0x00000000FFFFFFFF - -#ifdef TARGET_RODDICK /* EVB doesnt need it */ -#undef PLATFORM_FILL_DST_ADDR_PORT_TABLE -#define PLATFORM_FILL_DST_ADDR_PORT_TABLE fill_dst_addr_port_table(); -#endif - - -#ifndef RODDICK_ON_LINUX_OR_EVB -#undef PLATFORM_SET_CTX_RU_TX_FROM_NODE -#undef PLATFORM_SET_CTX_RU_TX_DST_IPPORT_IDX -#undef PLATFORM_SET_CTX_RU_TX_PKT_TYPE - -#define PLATFORM_SET_CTX_RU_TX_FROM_NODE(ctx, value) \ - (vnet_buffer(ctx))->vcgn_uii.ru.tx.from_node = value; -#define PLATFORM_SET_CTX_RU_TX_DST_IPPORT_IDX(ctx, value) \ - (vnet_buffer(ctx))->vcgn_uii.ru.tx.dst_ip_port_idx = value; -#define PLATFORM_SET_CTX_RU_TX_PKT_TYPE(ctx, type) \ - (vnet_buffer(ctx))->vcgn_uii.ru.tx.packet_type = type; -#endif - -#undef PLATFORM_SET_RX_VRF -#undef PLATFORM_SET_TX_VRF -#ifdef TARGET_RODDICK -#define PLATFORM_SET_RX_VRF(ctx, rx_vrf, hardcode, mask) \ - rx_vrf = (ctx->ru.rx.uidb_index & CNAT_VRF_MASK); -#define PLATFORM_SET_TX_VRF(ctx, tx_vrf) \ - ctx->ru.tx.uidb_index = tx_vrf; -#else /*EVB */ -#define PLATFORM_SET_RX_VRF(ctx, rx_vrf, hardcode, mask) \ - rx_vrf = hardcode; -#define PLATFORM_SET_TX_VRF(ctx, tx_vrf) -#endif - -#undef PLATFORM_CNAT_SET_RX_VRF -#undef PLATFORM_CNAT_SET_TX_VRF - -#define PLATFORM_CNAT_SET_RX_VRF(if_index, rx_vrf, proto) \ - rx_vrf = proto | ((if_index) & CNAT_VRF_MASK); - -#define PLATFORM_CNAT_SET_TX_VRF(if_index, tx_vrf) \ - (if_index) = ((tx_vrf) & CNAT_VRF_MASK); - - - -#undef PLATFORM_NAT64_SET_RX_VRF - -#ifdef TARGET_RODDICK - -#define PLATFORM_NAT64_SET_RX_VRF(rx_vrf, proto, inst_id) \ - rx_vrf = proto | (inst_id & CNAT_VRF_MASK); - -#else /* EVB */ - -#define PLATFORM_NAT64_SET_RX_VRF(rx_vrf, proto, inst_id) \ - rx_vrf = proto | inst_id; - -#endif - -#ifdef TARGET_EVB -#define VRF_MAP_CONFIG -#endif - -#undef PLATFORM_PRINT_TESTING_PG -#if defined(TARGET_LINUX_UDVR) || defined(CNAT_PG) -#define PLATFORM_PRINT_TESTING_PG() printf("testing pg\n"); -#else -#define PLATFORM_PRINT_TESTING_PG() -#endif - -#ifdef TARGET_RODDICK -#undef PLATFORM_INIT_TEMP_SENSORS -#undef PLATFORM_READ_CPU_SENSORS -#undef PLATFORM_SET_TEMP_READ_BLOCK - -#define PLATFORM_INIT_TEMP_SENSORS() Init_temperature_sensors(); -#define PLATFORM_READ_CPU_SENSORS(value) read_octeon_sensors(value); -#define PLATFORM_SET_TEMP_READ_BLOCK(var, val) var = &val->param[0]; -#endif - -#undef PLATFORM_HANDLE_ICMP_TTL_EXPIRED -#define PLATFORM_HANDLE_ICMP_TTL_EXPIRED 1 // handle TTL in NAT44 Application (for AVSM) - -#undef PLATFORM_NFV9_DISP_NODE_IDX -#ifdef TARGET_RODDICK -#define PLATFORM_NFV9_DISP_NODE_IDX "roddick_infra_l3_tx" -#else /* EVB */ -#define PLATFORM_NFV9_DISP_NODE_IDX "cnat_rewrite_output" -#endif - -#undef PLATFORM_CNAT_DB_DUMP_POLICY_PRINT -#define PLATFORM_CNAT_DB_DUMP_POLICY_PRINT() \ - printf("my instance:%d\n" \ - "icmp timeout %d udp init timeout %d act timeout %d\n" \ - "tcp init timeout %d act timeout %d mapping refresh %d\n" \ - "port limit per user %d ftp alg %d lb debug %d\n" \ - "icmp rate limit 0x%x config delete timer 0x%x\n" \ - "global debug flag 0x%x\n" \ - "icmp rate limit (pkts/per sec) %d\n" \ - "dynamic port range start %d\n" \ - "debug ivrf 0x%x flag 0x%x start_addr 0x%x end_addr 0x%x\n" \ - "debug ovrf 0x%x flag 0x%x start_addr 0x%x end_addr 0x%x\n", \ - my_instance_number, \ - icmp_session_timeout, udp_init_session_timeout, udp_act_session_timeout, \ - tcp_initial_setup_timeout, tcp_active_timeout, \ - mapping_refresh_both_direction, cnat_main_db_max_ports_per_user, \ - ftp_alg_enabled, lb_debug_enable, per_user_icmp_msg_limit, \ - config_delete_timeout, \ - global_debug_flag, \ - cnat_main_db_icmp_rate_limit, \ - cnat_static_port_range, \ - debug_i_vrf, debug_i_flag, debug_i_addr_start, debug_i_addr_end, \ - debug_o_vrf, debug_o_flag, debug_o_addr_start, debug_o_addr_end); - - -#undef PLATFORM_PRINT_CTX_VALUES -#ifdef TARGET_RODDICK -#define PLATFORM_PRINT_CTX_VALUES(ctx) \ - printf("\nAFTER: %s cur_hdr %p, uidb %d, pkt_type %d, cur_len %d\n", \ - type_str, \ - ctx->current_header, \ - ctx->ru.tx.uidb_index, \ - ctx->ru.tx.packet_type, \ - ctx->current_length); -#else /* EVB */ -#define PLATFORM_PRINT_CTX_VALUES(ctx) \ - printf("\nAFTER: %s cur_hdr %p, cur_len %d\n", \ - type_str,\ - ctx->current_header, \ - ctx->current_length); -#endif - -#undef PLATFORM_ADD_VRF_MAP_HANDLE_PARTITION -#define PLATFORM_ADD_VRF_MAP_HANDLE_PARTITION(uidb_index, partition_id) - -#undef PLATFORM_DEL_VRF_MAP_HANDLE_PARTITION -#define PLATFORM_DEL_VRF_MAP_HANDLE_PARTITION(uidb_index, partition_id) - -#undef PLATFORM_ALLOC_NFV9_PKT_BUFFER -#define PLATFORM_ALLOC_NFV9_PKT_BUFFER(ctx, to_lc_cpu) - -#undef PLATFORM_CNAT_NFV9_SHIM_HDR_OFFSET -#ifdef TARGET_RODDICK -// This corresponds to the length of the IMETRO SHIM Header for RODDICK -#define PLATFORM_CNAT_NFV9_SHIM_HDR_OFFSET 8 -#else -#define PLATFORM_CNAT_NFV9_SHIM_HDR_OFFSET 0 -#endif - -#undef PLATFORM_CNAT_NFV9_L2_ENCAPS_OFFSET -#ifdef TARGET_RODDICK -#define PLATFORM_CNAT_NFV9_L2_ENCAPS_OFFSET 0 -#else -#define PLATFORM_CNAT_NFV9_L2_ENCAPS_OFFSET 16 -#endif - -#undef PLATFORM_MAX_SHOW_BUFFER_SIZE -#undef PLATFORM_MAX_TRANSLATION_ENTRIES -#undef PLATFORM_MAX_UTIL_ENTRIES - -#define PLATFORM_MAX_SHOW_BUFFER_SIZE 1700 -#define PLATFORM_MAX_TRANSLATION_ENTRIES (50) -#define PLATFORM_NAT64_MAX_TRANSLATION_ENTRIES (30) -#define PLATFORM_MAX_UTIL_ENTRIES (100) - - -#undef PLATFORM_NAT64_MAX_SESSIONS -#undef PLATFORM_NAT64_TIMEOUT_HASH_SIZE -#define PLATFORM_NAT64_MAX_SESSIONS 20000000 -#define PLATFORM_NAT64_TIMEOUT_HASH_SIZE 24001 /* Ref: CSCtr36242 */ - -#undef PLATFORM_CHECK_DSLITE_ENABLE_FLAG -#define PLATFORM_CHECK_DSLITE_ENABLE_FLAG 1 - -/* Fragment hold limit is Platform specific */ -/* For Roddick, it is 63 due to hardware limitation */ -#undef PLATFORM_IPV4_FRAG_FRAG_HOLD_LIMIT -#define PLATFORM_IPV4_FRAG_FRAG_HOLD_LIMIT 63 - -#undef PLATFORM_MAX_IPV4_CTX_ENTRIES -#define PLATFORM_MAX_IPV4_CTX_ENTRIES 80 - -#undef PLATFORM_DIRN_IN_TO_OUT -#undef PLATFORM_DIRN_OUT_TO_IN -#undef PLATFORM_SET_SVI_PARAMS_FIELD - -#define PLATFORM_DIRN_IN_TO_OUT -#define PLATFORM_DIRN_OUT_TO_IN -#define PLATFORM_SET_SVI_PARAMS_FIELD(var, value) - -#undef PLATFORM_GET_NFV9_L3_HDR_OFFSET -#define PLATFORM_GET_NFV9_L3_HDR_OFFSET \ - ((u8 *)ctx + ctx->data + CNAT_NFV9_IP_HDR_OFFSET); - -#undef PLATFORM_GET_NFV9_L4_HDR_OFFSET -#define PLATFORM_GET_NFV9_L4_HDR_OFFSET \ - ((u8 *) ctx + ctx->data + CNAT_NFV9_UDP_HDR_OFFSET); - -#undef PLATFORM_MEMSET_CNAT_LOG_PKT_DATA -#define PLATFORM_MEMSET_CNAT_LOG_PKT_DATA - -/* - Index 0 -- SE_P2MP - Index 1 -- HA Destination 1 - Index 2 -- HA Destination 2 - Index 3 -- EXT_LOG_SRVR -*/ -enum { - NODE_CGNCFG, - NODE_HA, - NODE_PD_CONFIG, - NODE_LOGGING, - NODE_TRACE_BACKUP, - NODE_MAX, -}; - -#endif /* __PLATFORM_COMMON_OVERRIDE_H__ */ diff --git a/plugins/vcgn-plugin/vcgn/spp_ctx.h b/plugins/vcgn-plugin/vcgn/spp_ctx.h deleted file mode 100644 index 2d3c95c8..00000000 --- a/plugins/vcgn-plugin/vcgn/spp_ctx.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - *------------------------------------------------------------------ - * spp_ctx.h - packet / context definitions - * - * Copyright (c) 2007-2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef __SPP_CTX_H__ -#define __SPP_CTX_H__ - -/* Packet header / data */ - -/* Any change to spp_ctx_t structure should be updated in vnet/buffer.h - * as well. - */ -typedef struct _spp_ctx { -#ifdef TOBE_PORTED - /* Following fields are required to handle multibuffer */ - u32 num_buffers; /* Number of buffers part of packet */ - vlib_buffer_t *next_ctx_this_packet; - - /* Following is used by non-UDP protocols */ -#define SPP_CTX_FEATURE_DATA_SIZE 16 - - u8 feature_data[SPP_CTX_FEATURE_DATA_SIZE]; -#endif - - union { /* Roddick specific */ - u32 roddick_info; - struct __tx_pkt_info { /* Used by PI to PI communication for TX */ - u32 uidb_index:16; /* uidb_index to transmit */ - u32 packet_type:2; /* 1-IPv4, 2-Ipv6, - 0,3 - Unused */ - u32 ipv4_defrag:1; /* 0 - Normal, 1 - update first - * segment size - * (set by 6rd defrag node) - */ - - u32 dst_ip_port_idx:4;/* Index to dst_ip_port_table */ - u32 from_node:4; - u32 calc_chksum:1; - u32 reserved:4; - } tx; - struct __rx_pkt_info { /* Used by PD / PI communication */ - u32 uidb_index:16; /* uidb_index received in packet */ - u32 packet_type:2; /* 1-IPv4, 2-Ipv6, - 0,3 - Unused */ - u32 icmp_type:1; /* 0-ICMP query type, 1-ICMP error type */ - u32 protocol_type:2; /* 1-TCP, 2-UDP, 3-ICMP, 0 - Unused */ - u32 ipv4_defrag:1; /* 0 - Normal, 1 - update first - * segment size - * (set by 6rd defrag node) - */ - - u32 direction:1; /* 0-Outside, 1-Inside */ - u32 frag:1; /*IP fragment-1, Otherwise-0*/ - u32 option:1; /* 0-No IP option (v4) present, non-fragHdr - * option hdr present (v6) - */ - u32 df_bit:1; /* IPv4 DF bit copied here */ - u32 reserved1:6; - } rx; - } ru; -} spp_ctx_t; - -#endif diff --git a/plugins/vcgn-plugin/vcgn/spp_platform_trace_log.c b/plugins/vcgn-plugin/vcgn/spp_platform_trace_log.c deleted file mode 100644 index a96894f9..00000000 --- a/plugins/vcgn-plugin/vcgn/spp_platform_trace_log.c +++ /dev/null @@ -1,989 +0,0 @@ -/* - *------------------------------------------------------------------ - * spp_platform_trace_log.c - * - * Copyright (c) 2008-2011, 2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *--------------------------------------------------------------------------- - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tcp_header_definitions.h" -#include "platform_common.h" -#include "spp_platform_trace_log.h" - -#define WORD_SIZE sizeof(u32) - -int temperature_read_blocked = 1; - -spp_cnat_logger_tbl_t spp_cnat_logger_table[] = -{ - { CNAT_ERROR_SUCCESS, - 3, - 0, - {"i-vrf", - "ipv4 addr", - "port"} - }, - { CNAT_NO_CONFIG_ERROR, - 3, - 180, - {"i-vrf", - "ipv4 addr", - "port"} - }, - { CNAT_NO_VRF_RUN_ERROR, - 3, - 180, - {"i-vrf", - "ipv4 addr", - "port"} - }, - { CNAT_NO_POOL_FOR_ANY_ERROR, - 3, - 180, - {"i-vrf", - "ipv4 addr", - "port"} - }, - { CNAT_NO_PORT_FOR_ANY_ERROR, - 3, - 60, - {"i-vrf", - "ipv4 addr", - "port"} - }, - { CNAT_BAD_INUSE_ANY_ERROR, - 3, - 60, - {"i-vrf", - "ipv4 addr", - "port"} - }, - { CNAT_NOT_FOUND_ANY_ERROR, - 3, - 60, - {"i-vrf", - "ipv4 addr", - "port"} - }, - { CNAT_INV_PORT_FOR_DIRECT_ERROR, - 3, - 60, - {"i-vrf", - "ipv4 addr", - "port"} - }, - { CNAT_BAD_INUSE_DIRECT_ERROR, - 3, - 1, - {"i-vrf", - "ipv4 addr", - "port"} - }, - { CNAT_NOT_FOUND_DIRECT_ERROR, - 3, - 1, - {"i-vrf", - "ipv4 addr", - "port"} - }, - { CNAT_OUT_OF_PORT_LIMIT_ERROR, - 3, - 60, - {"i-vrf", - "ipv4 addr", - "port"} - }, - { CNAT_MAIN_DB_CREATE_ERROR, - 0, - 30, - {""} - }, - { CNAT_LOOKUP_ERROR, - 1, - 30, - {"Type"} - }, - { CNAT_INDEX_MISMATCH_ERROR, - 2, - 30, - {"in2out_index", - "out2in_index"} - }, - { CNAT_PACKET_DROP_ERROR, - 3, - 15, - {"i-vrf", - "ipv4 addr", - "port"} - }, - { CNAT_INV_UNUSED_USR_INDEX, - 1, - 10, - {"invalid/unused user index"} - }, - { CNAT_INVALID_VRFMAP_INDEX, - 0, - 60, - {""} - }, - { CNAT_USER_OUT_OF_PORTS, - 2, - 1800, - {"i-vrf", - "ipv4 addr"} - }, - { CNAT_EXT_PORT_THRESH_EXCEEDED, - 2, - 180, - {"i-vrf", - "ipv4 address"} - }, - { CNAT_EXT_PORT_THRESH_NORMAL, - 2, - 180, - {"vrf", - "ipv4 address"} - }, - { CNAT_NO_EXT_PORT_AVAILABLE, - 0, - 1, - {"",} - }, - { CNAT_SESSION_THRESH_EXCEEDED, - 2, - 1800, - {"vrf", - "ipv4 address"} - }, - { CNAT_SESSION_THRESH_NORMAL, - 2, - 30, /* changed to 30 */ - {"vrf", - "ipv4 address"} - }, - { WQE_ALLOCATION_ERROR, - 0, - 180, /* changed to 180 */ - {""} - }, - { ERROR_PKT_DROPPED, - 2, - 60, /* changed to 60 */ - {"spi-port", - "error-code"} - }, - { SYSMGR_PD_KEY_CREATION_ERROR, - 0, - 30, - {""} - }, - { SYSMGR_PD_SHMEM_ID_ERROR, - 0, - 1, - {""} - }, - { SYSMGR_PD_SHMEM_ATTACH_ERROR, - 0, - 1, - {""} - }, - { OCTEON_CKHUM_SKIPPED, - 2, - 60, /* changed to 60 */ - {"version", - "protocol"} - }, - { PK0_SEND_STATUS, - 1, - 15, - {"status"} - }, - { CMD_BUF_ALLOC_ERR, - 0, - 60, - {""} - }, - { SPP_CTX_ALLOC_FAILED, - 1, - 300, /* every 5 min */ - {"node"} - }, - { SPP_MAX_DISPATCH_REACHED, - 1, - 60, - {"node"} - }, - { HA_SIGCHILD_RECV, - 3, - 1, - {"pid", - "uid", - "signal",} - }, - { SIGACTION_ERR, - 0, - 1, - {""} - }, - { HA_INVALID_SEQ_OR_CONFIG_OR_TYPE, - 2, - 10, - {"seq-id or config option", - "Type"} - }, - { NODE_CREATION_ERROR, - 1, - 1, - {"node"} - }, - - { CNAT_CLI_INVALID_INPUT, - 4, - 0, - {"Error Type", - "Passed", - "Expected", - "Type"} - }, - { CNAT_DUMMY_HANDLER_HIT, - 1, - 0, - {"Handler"} - }, - { CNAT_CONFIG_ERROR, - 5, - 0, - {"Sub code", - "Param 1", - "Param 2", - "Param 3", - "Param 4"} - }, - { CNAT_NFV9_ERROR, - 1, - 180, /* changed to 180 */ - {"Sub code"} - }, - { CNAT_CMVX_TWSI_READ_WRITE_FAIL, - 3, - 180, - {"Operation", - "Location", - "Data"} - }, - { CNAT_TEMP_SENSOR_TIMEOUT, - 0, - 180, - {""} - }, - { CNAT_TEMP_SENSOR_DATA_MISMATCH, - 2, - 180, - {"Actual", - "Expected"} - }, - { CNAT_TEMP_SENSOR_CONFIG_FAILED, - 1, - 180, - {"Glik"} - }, - { HA_APP_NOT_RESPONDING, - 2, - 180, - {"CPU", - "Core"} - }, - { HA_DATA_PATH_TEST_FAILED, - 0, - 30, - {""} - }, - { CNAT_WRONG_PORT_ALLOC_TYPE, - 3, - 60, - {"i-vrf", - "ipv4 addr", - "port"} - }, - { CNAT_NEW_PORT_ALLOC_ERROR, - 3, - 60, - {"i-vrf", - "ipv4 addr", - "port"} - }, - { CNAT_INVALID_INDEX_TO_FREE_PORT, - 0, - 60, - {""} - }, - { CNAT_DELETE_DB_ENTRY_NO_PORTMAP, - 0, - 60, - {""} - }, - { CNAT_MAIN_DB_LIMIT_ERROR, - 0, - 180, - {""} - }, - { CNAT_USER_DB_LIMIT_ERROR, - 0, - 180, - {""} - }, - { CNAT_FRAG_DB_ERROR, - 1, - 180, - {"Type"} - }, - - { DROP_PKT_DUMP, - 0, - 20, - {""} - } -}; - -#define LOG_TABLE_MAX_ENTRIES \ - (sizeof(spp_cnat_logger_table)/sizeof(spp_cnat_logger_table[0])) - -u32 error_code_timestamps[LOG_TABLE_MAX_ENTRIES]; -spp_timer_t sensor_timer; -spp_trace_log_global_info_t spp_trace_log_global_info; -spp_global_counters_t spp_global_counters; - -/* - * Logging information structures - */ -spp_trace_log_info_t spp_default_trace_log_info; -spp_trace_log_info_t *spp_trace_log_info_pool; - -#ifdef TOBE_PORTED -/* - * The following 2 functions are temporary hacks until - * we have RTC support from the PD nodes - */ -inline -u32 spp_trace_log_get_sys_up_time_in_ms (void) -{ - spp_node_main_vector_t *nmv; - u32 sys_up_time; - - nmv = spp_get_node_main_vectorized_inline(); - - sys_up_time = (u32) (nmv->ticks / nmv->ticks_per_ms); - - return (sys_up_time); -} - -u32 spp_trace_log_get_unix_time_in_seconds (void) -{ - spp_node_main_vector_t *nmv; - u32 unix_time; - - nmv = spp_get_node_main_vectorized_inline(); - - unix_time = (u32) (nmv->ticks / nmv->ticks_per_second); - - return (unix_time); -} - -/* - * edt: * * spp_trace_log_send_queued_pkt - * - * Tries to send a logging pkt that has been queued earlier - * because it could not be sent due to downstream constipation - * - * Argument: spp_trace_log_info_t *trace_logging_info - * structure that contains the packet context - */ -inline -void spp_trace_log_send_queued_pkt (spp_trace_log_info_t *trace_logging_info) -{ - spp_node_t *output_node; - - output_node = spp_get_nodes() + - spp_trace_log_global_info.spp_trace_log_disp_node_index; - - if (PREDICT_TRUE(output_node->sf.nused < SPP_MAXDISPATCH)) { - /* - * Move the logging context to output node - */ - spp_dispatch_make_node_runnable(output_node); - output_node->sf.ctxs[output_node->sf.nused++] = - trace_logging_info->queued_logging_context; - - /* - * Context has been queued, it will be freed after the pkt - * is sent. Clear this from the logging_context_info structure - */ - trace_logging_info->queued_logging_context = NULL; - - } else { - /* - * Can't do much, just return, may be we can send it later - */ - spp_global_counters.spp_trace_log_downstream_constipation_count++; - } -} - -/* - * edt: * * spp_trace_log_send_pkt - * - * Tries to send a logging pkt. If the packet cannot be sent - * because of rewrite_output node cannot process it, queue - * it temporarily and try to send it later. - * - * Argument: spp_trace_log_info_t *trace_logging_info - * structure that contains the packet context - */ -inline -void spp_trace_log_send_pkt (spp_trace_log_info_t *trace_logging_info) -{ - spp_node_t *output_node; - - - output_node = spp_get_nodes() + - spp_trace_log_global_info.spp_trace_log_disp_node_index; - - if (PREDICT_TRUE(output_node->sf.nused < SPP_MAXDISPATCH)) { - /* - * Move the logging context to output node - */ - spp_dispatch_make_node_runnable(output_node); - output_node->sf.ctxs[output_node->sf.nused++] = - trace_logging_info->current_logging_context; - - } else { - /* - * Queue the context into the logging_info structure, - * We will try to send it later. Currently, we will - * restrict to only one context queued. - */ - spp_global_counters.spp_trace_log_downstream_constipation_count++; - - /* - * Attach the current logging context which is full to the - * queued context list in trace_logging_info structure - */ - trace_logging_info->queued_logging_context = - trace_logging_info->current_logging_context; - - /* - * Whether the context is queued or not, set the current context index - * to EMPTY, as the earlier context can no more be used to send - * more logging records. - */ - } - - trace_logging_info->current_logging_context = NULL; -} - -/* - * edt: * * spp_trace_log_send_pkt_always_success - * - * Tries to send a logging pkt. This cannot fail due to downstream - * constipation because we have already checked if the rewrite_output - * node can accept it. - * - * Argument: spp_trace_log_info_t *trace_logging_info - * structure that contains the packet context - * - * Argument: spp_node_t *output_node - * spp_node_t structure for rewrite_output node - */ -inline -void spp_trace_log_send_pkt_always_success ( - spp_trace_log_info_t *trace_logging_info, - spp_node_t *output_node) -{ - /* - * At this point we either have a current or queued logging context - */ - if (PREDICT_TRUE(trace_logging_info->current_logging_context != NULL)) { - - output_node->sf.ctxs[output_node->sf.nused++] = - trace_logging_info->current_logging_context; - - trace_logging_info->current_logging_context = NULL; - } else { - /* - * For queued logging context - */ - output_node->sf.ctxs[output_node->sf.nused++] = - trace_logging_info->queued_logging_context; - - trace_logging_info->queued_logging_context = NULL; - } - - /* - * Move the logging context to output node - */ - spp_dispatch_make_node_runnable(output_node); - -} - -/* - * edt: * * spp_create_trace_log_context - * - * Tries to create a logging context with packet buffer - * to send a new logging packet - * - * Argument: spp_trace_log_info_t *trace_logging_info - * structure that contains the nfv9 logging info and will store - * the packet context as well. - */ -inline -void spp_create_trace_log_context ( - spp_trace_log_info_t *trace_logging_info) -{ - spp_ctx_t *ctx; - - /* - * If queued_logging_context_index is non-EMPTY, we already have a logging - * packet queued to be sent. First try sending this before allocating - * a new context. We can have only one active packet context per - * trace_logging_info structure - */ - if (PREDICT_FALSE(trace_logging_info->queued_logging_context != NULL)) { - spp_trace_log_send_queued_pkt(trace_logging_info); - /* - * If we cannot still send the queued pkt, just return - * Downstream Constipation count would have increased anyway - */ - if (trace_logging_info->queued_logging_context != NULL) { - spp_global_counters.spp_trace_log_context_creation_deferred_count++; - return; - } - } - - - /* - * No context can be allocated, return silently - * calling routine will handle updating the error counters - */ - if (spp_ctx_alloc(&ctx, 1) < 1) { - spp_global_counters.spp_trace_log_context_creation_fail_count++; - return; - } - - trace_logging_info->current_logging_context = ctx; - trace_logging_info->pkt_length = 0; - - trace_logging_info->current_logging_context_timestamp = - spp_trace_log_get_sys_up_time_in_ms(); - - ctx->flags = SPP_CTX_END_OF_PACKET; - ctx->ru.tx.from_node = NODE_TRACE_BACKUP; - ctx->ru.tx.dst_ip_port_idx = EXT_TRACE_BACKUP_INDEX; - ctx->next_ctx_this_packet = (spp_ctx_t*) SPP_CTX_NO_NEXT_CTX; - ctx->current_header = &ctx->packet_data[SPP_TRACE_LOG_HDR_OFFSET]; - ctx->current_length = 0; - - trace_logging_info->log_record = 0; - trace_logging_info->total_record_count = 0; - trace_logging_info->next_data_ptr = - (u8 *) &ctx->packet_data[SPP_TRACE_LOG_HDR_OFFSET]; - -} - -/* - * edt: * * spp_trace_log_add_record_create - * - * Tries to create an add record to the NFV9 packet - * - * Argument: spp_trace_log_info_t *trace_logging_info - * structure that contains the nfv9 logging info and will store - * the packet context as well. - */ -inline -void spp_trace_log_add_record_create (spp_trace_log_info_t *trace_logging_info) -{ - - trace_logging_info->log_header = - (spp_trace_log_hdr_t *) (trace_logging_info->next_data_ptr); - - /* - * Initialize the number of traces recorded - */ - trace_logging_info->log_header->num_traces = - spp_host_to_net_byte_order_32(0); - - - trace_logging_info->log_record = - (spp_trace_log_t *) (trace_logging_info->log_header + 1); - - /* - * Update the length of the total pkt - */ - trace_logging_info->pkt_length += - SPP_LOG_TRACE_HEADER_LENGTH; - - /* - * Set the data pointer beyond the trace header field - */ - trace_logging_info->next_data_ptr = - (u8 *) (trace_logging_info->log_header + 1); - -} - -/* - * edt: * * spp_trace_logger - * - * Tries to log spp/cnat event/errors - * - * Argument: u8 *error_code - * Error code passed - * - * Argument: optional arguments - */ -void spp_trace_logger (u16 error_code, u16 num_args, u32 *arg) -{ - spp_trace_log_info_t *trace_logging_info = 0; - u8 i; - - trace_logging_info = - spp_trace_log_info_pool + - spp_trace_log_global_info.spp_log_pool_index[SPP_LOG_LTRACE]; - - if (PREDICT_FALSE(trace_logging_info->current_logging_context == NULL)) { - spp_create_trace_log_context(trace_logging_info); - - /* - * If still empty, return after increasing the count - */ - if (PREDICT_FALSE(trace_logging_info->current_logging_context == NULL)) { - return; - } - } - - if (PREDICT_FALSE(trace_logging_info->log_record == NULL)) { - spp_trace_log_add_record_create(trace_logging_info); - } - - /* - * We should definitely have add_record now, no need to sanitize - */ - trace_logging_info->log_record->error_code = - spp_host_to_net_byte_order_16(error_code); - trace_logging_info->log_record->num_args = - spp_host_to_net_byte_order_16(num_args); - - for (i = 0; i < num_args; i++) { - trace_logging_info->log_record->arg[i] = - spp_host_to_net_byte_order_32(*(arg + i)); - } - - trace_logging_info->pkt_length += SPP_TRACE_LOG_RECORD_LENGTH + WORD_SIZE*num_args; - trace_logging_info->current_logging_context->current_length = - trace_logging_info->pkt_length; - trace_logging_info->total_record_count += 1; - - trace_logging_info->next_data_ptr = - (u8 *) (trace_logging_info->next_data_ptr + WORD_SIZE + WORD_SIZE*num_args); - - trace_logging_info->log_record = - (spp_trace_log_t *) (trace_logging_info->next_data_ptr); - - /* - * Initialize the number of traces recorded - */ - trace_logging_info->log_header->num_traces = - spp_host_to_net_byte_order_32(trace_logging_info->total_record_count); - - - - /* - * If we have exceeded the packet length, let us send the - * packet now. There is buffer of additional bytes beyond - * max_pkt_length to ensure that the last add/delete record - * can be stored safely. - */ - if (trace_logging_info->pkt_length > - trace_logging_info->max_length_minus_max_record_size) { - spp_trace_log_send_pkt(trace_logging_info); - } -} - - -/* - * edt: * * spp_trace_log_timer_handler - * - * Timer handler for sending any pending NFV9 record - * - * Argument: spp_timer_t * timer_p - * Timer handler structure - */ -inline -void spp_trace_log_timer_handler (spp_timer_t * timer_p) -{ - spp_node_t *output_node; - spp_trace_log_info_t *trace_logging_info = 0; - u32 current_timestamp = spp_trace_log_get_sys_up_time_in_ms(); - i16 sf_nused; - - output_node = spp_get_nodes() + - spp_trace_log_global_info.spp_trace_log_disp_node_index; - - sf_nused = output_node->sf.nused; - - pool_foreach (trace_logging_info, spp_trace_log_info_pool, ({ - /* - * Check if no more logging contexts can be queued - */ - if (PREDICT_FALSE(sf_nused >= SPP_MAXDISPATCH)) { - break; - } - - /* - * If there is a current logging context and timestamp - * indicates it is pending for long, send it out - * Also if there is a queued context send it out as well - */ - if (trace_logging_info->queued_logging_context || - (trace_logging_info->current_logging_context && - (current_timestamp - - trace_logging_info->current_logging_context_timestamp) - > 1000)) { - spp_trace_log_send_pkt_always_success(trace_logging_info, - output_node); - sf_nused++; - } - })); - - timer_p->expires = - spp_timer_in_n_ms_inline(1000); /* every 1 sec */ - spp_timer_start(timer_p); - -} -inline -void spp_sensor_timer_handler (spp_timer_t * timer_p) -{ -#ifdef TARGET_RODDICK - if (!temperature_read_blocked) { - Init_temperature_sensors(); - read_octeon_sensors(TEMPERATURE_SENSOR_QUIET_MODE); - } - - timer_p->expires = - spp_timer_in_n_ms_inline(60000); /* every 1 sec */ - spp_timer_start(timer_p); - -#endif -} -void init_trace_log_buf_pool (void) -{ - spp_trace_log_info_t *my_spp_log_info; - u8 found; - spp_log_type_t log_type; - - /* - * Init SPP logging info as needed, this will be done only once - */ - spp_trace_log_init(); - - found = 0; - - for (log_type = SPP_LOG_LTRACE; log_type < SPP_LOG_MAX; log_type++ ) { - /* Do we already have a map for this log type? */ - pool_foreach (my_spp_log_info, spp_trace_log_info_pool, ({ - if (my_spp_log_info->log_type == log_type) { - found = 1; - break; - } - })); - - /* - * Entry not present - */ - if (!found) { - pool_get(spp_trace_log_info_pool, my_spp_log_info); - memset(my_spp_log_info, 0, sizeof(*my_spp_log_info)); - - /* - * Make the current and head logging context indeices as EMPTY. - * When first logging happens, these get set correctly - */ - my_spp_log_info->current_logging_context = NULL; - my_spp_log_info->queued_logging_context = NULL; - - my_spp_log_info->log_type = log_type; - my_spp_log_info->max_length_minus_max_record_size = - SPP_TRACE_LOG_MAX_PKT_LENGTH; - - spp_trace_log_global_info.spp_log_pool_index[log_type] = - my_spp_log_info - spp_trace_log_info_pool; - } - - } - - return; -} - - -/* - * one time function - * has to be called at the init time - */ -void spp_trace_log_init (void) -{ - if (!spp_trace_log_global_info.spp_trace_log_init_done) { - -#ifdef TARGET_RODDICK - spp_trace_log_global_info.spp_trace_log_disp_node_index = - spp_lookup_node_index("roddick_infra_l3_tx"); -#elif defined(TARGET_BOOSTER) - spp_trace_log_global_info.spp_trace_log_disp_node_index = - spp_lookup_node_index("booster_infra_l3_tx"); -#endif - ASSERT(spp_trace_log_global_info.spp_trace_log_disp_node_index != (u16)~0); - - spp_trace_log_global_info.log_timer.cb_index = - spp_timer_register_callback(spp_trace_log_timer_handler); - spp_trace_log_global_info.log_timer.expires = - spp_timer_in_n_ms_inline(1000); /* every 1 sec */ - spp_timer_start(&spp_trace_log_global_info.log_timer); - - if (!my_core_id) { - sensor_timer.cb_index = - spp_timer_register_callback(spp_sensor_timer_handler); - sensor_timer.expires = - spp_timer_in_n_ms_inline(60000); /* every 1 sec */ - spp_timer_start(&sensor_timer); - } - - spp_trace_log_global_info.spp_trace_log_init_done = 1; - - /* - * Set MSC ip_addr, port values - */ -#ifdef TARGET_RODDICK - dst_ipv4_port_table[EXT_TRACE_BACKUP_INDEX].ipv4_address = - vpp_boot_params.msc_ip_address; - switch(vpp_boot_params.octeon_number) { - case 0: - dst_ipv4_port_table[EXT_TRACE_BACKUP_INDEX].port = 0x15BF; - break; - case 1: - dst_ipv4_port_table[EXT_TRACE_BACKUP_INDEX].port = 0x15BF; - break; - case 2: - dst_ipv4_port_table[EXT_TRACE_BACKUP_INDEX].port = 0x15BF; - break; - case 3: - dst_ipv4_port_table[EXT_TRACE_BACKUP_INDEX].port = 0x15BF; - break; - } -#else - dst_ipv4_port_table[EXT_TRACE_BACKUP_INDEX].ipv4_address = 0x01020304; - dst_ipv4_port_table[EXT_TRACE_BACKUP_INDEX].port = 0x15BF; -#endif - - } -} - -void spp_printf (u16 error_code, u16 num_args, u32 *arg) -{ - u32 current_timestamp; - spp_node_main_vector_t *nmv; - - if (PREDICT_FALSE(error_code >= LOG_TABLE_MAX_ENTRIES)) - { - /* printf("Error code invalid %d, %d, %d, %d\n", - error_code, LOG_TABLE_MAX_ENTRIES, - sizeof(spp_cnat_logger_table), sizeof(spp_cnat_logger_table[0])); - */ - return; /* Should not happen */ - } - - nmv = spp_get_node_main_vectorized_inline(); - current_timestamp = nmv->ticks / nmv->ticks_per_second; - - /* Check if any further hashing is required */ - - if (PREDICT_FALSE(error_code == DUMP_PKT_IDX)) { -#ifdef TARGET_RODDICK || defined(TARGET_BOOSTER) - spp_trace_logger(error_code, num_args, arg); -#else - u8 j ; - - printf("PKT DUMP :: "); - for (j = 0 ; j < num_args; j++) { - printf("0x%x ", arg[j]); - if (j == (num_args - 1)) { - printf("\n"); - } - } -#endif - } else if (PREDICT_TRUE((current_timestamp - error_code_timestamps[error_code]) >= - spp_cnat_logger_table[error_code].rate_limit_time)) { - /* update timestamp */ - error_code_timestamps[error_code] = current_timestamp; - -#ifdef TARGET_RODDICK || defined(TARGET_BOOSTER) - spp_trace_logger(error_code, num_args, arg); -#else - u8 j ; - - for (j = 0 ; j < num_args; j++) { - printf("%s: %d ", spp_cnat_logger_table[error_code].param_name[j], arg[j]); - if (j == (num_args - 1)) { - printf("\n"); - } - } -#endif - } -} - -#else /* TOBE_PORTEED */ -void spp_trace_logger(u16 error_code, u16 num_args, u32 *arg) -{ - /* To be filled */ -} - -void spp_trace_log_init(void) -{ - /* To be filled */ -} - -void init_trace_log_buf_pool(void) -{ - /* To be filled */ -} - -void spp_printf(u16 error_code, u16 num_args, u32 *arg) -{ - /* To be filled */ -} - -inline u32 spp_trace_log_get_unix_time_in_seconds (void) -{ - vlib_main_t *vlib_main; - - vlib_main = vlib_get_main(); - return(vlib_time_now((vlib_main_t *) vlib_main)); -} - -#endif /* TOBE_PORTED */ - diff --git a/plugins/vcgn-plugin/vcgn/spp_platform_trace_log.h b/plugins/vcgn-plugin/vcgn/spp_platform_trace_log.h deleted file mode 100644 index 36da710f..00000000 --- a/plugins/vcgn-plugin/vcgn/spp_platform_trace_log.h +++ /dev/null @@ -1,358 +0,0 @@ -/* - *------------------------------------------------------------------ - * spp_platform_trace_log.h - * - * Copyright (c) 2009-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef __SPP_PLATFORM_TRACE_LOG_H__ -#define __SPP_PLATFORM_TRACE_LOG_H__ - -#include -#include -#include -#include -#include -#include - -#include "spp_ctx.h" -#include "spp_timers.h" - - -typedef enum { - SPP_LOG_LTRACE, - SPP_LOG_MAX -} spp_log_type_t; - -typedef struct { - u32 num_traces; -} spp_trace_log_hdr_t; - -typedef struct { - u16 error_code; - u16 num_args; - u32 arg[0]; -} spp_trace_log_t; - -#define DUMP_PKT_IDX 61 -#define OCTEON_SENSOR_READ 62 - -typedef enum { - CNAT_ERROR_SUCCESS, - CNAT_NO_CONFIG_ERROR, - CNAT_NO_VRF_RUN_ERROR, - CNAT_NO_POOL_FOR_ANY_ERROR, - CNAT_NO_PORT_FOR_ANY_ERROR, - CNAT_BAD_INUSE_ANY_ERROR, - CNAT_NOT_FOUND_ANY_ERROR, - CNAT_INV_PORT_FOR_DIRECT_ERROR, - CNAT_BAD_INUSE_DIRECT_ERROR, - CNAT_NOT_FOUND_DIRECT_ERROR, - CNAT_OUT_OF_PORT_LIMIT_ERROR, - CNAT_MAIN_DB_CREATE_ERROR, - CNAT_LOOKUP_ERROR, - CNAT_INDEX_MISMATCH_ERROR, - CNAT_PACKET_DROP_ERROR, - CNAT_INV_UNUSED_USR_INDEX, - CNAT_INVALID_VRFMAP_INDEX, - CNAT_USER_OUT_OF_PORTS, - CNAT_EXT_PORT_THRESH_EXCEEDED, - CNAT_EXT_PORT_THRESH_NORMAL, - CNAT_NO_EXT_PORT_AVAILABLE, - CNAT_SESSION_THRESH_EXCEEDED, - CNAT_SESSION_THRESH_NORMAL, - WQE_ALLOCATION_ERROR, - ERROR_PKT_DROPPED, - SYSMGR_PD_KEY_CREATION_ERROR, - SYSMGR_PD_SHMEM_ID_ERROR, - SYSMGR_PD_SHMEM_ATTACH_ERROR, - OCTEON_CKHUM_SKIPPED, - PK0_SEND_STATUS, - CMD_BUF_ALLOC_ERR, - SPP_CTX_ALLOC_FAILED, - SPP_MAX_DISPATCH_REACHED, - HA_SIGCHILD_RECV, - SIGACTION_ERR, - HA_INVALID_SEQ_OR_CONFIG_OR_TYPE, - NODE_CREATION_ERROR, - CNAT_CLI_INVALID_INPUT, /* new adds as part of CSCto04510, see sub codes below */ - CNAT_DUMMY_HANDLER_HIT, /* Has sub codes , see spp_dummy_handler_sub_cdes_t */ - CNAT_CONFIG_ERROR, /* has subcodes-see spp_config_error_sub_codes_t below */ - CNAT_NFV9_ERROR, /* Has sub codes see spp_nfv9_error_sub_codes_t below */ - CNAT_CMVX_TWSI_READ_WRITE_FAIL, /* Hassub codes see spp_cmvx_error_sub_codes_t */ - CNAT_TEMP_SENSOR_TIMEOUT, - CNAT_TEMP_SENSOR_DATA_MISMATCH, - CNAT_TEMP_SENSOR_CONFIG_FAILED, - HA_APP_NOT_RESPONDING, - HA_DATA_PATH_TEST_FAILED, - CNAT_WRONG_PORT_ALLOC_TYPE, - CNAT_NEW_PORT_ALLOC_ERROR, - CNAT_INVALID_INDEX_TO_FREE_PORT, - CNAT_DELETE_DB_ENTRY_NO_PORTMAP, - CNAT_MAIN_DB_LIMIT_ERROR, - CNAT_USER_DB_LIMIT_ERROR, - CNAT_FRAG_DB_ERROR, /* see spp_frag_db_error_sub_codes_t below */ - - DROP_PKT_DUMP, - CNAT_NAT64_SYSTEM_LIMIT_ERROR, - CNAT_ERROR_MAX -} spp_error_codes_t; - -typedef enum { - - TCP_MSS_INVALID_IVRF = 10, /* 1 param - vrf id */ - NFV9_LOG_INVALID_IP_OR_PORT = 20, /* 2 params - nfv9 server ip and port */ - NFV9_LOG_INVALID_PARAMS_OTHERS, /* 3 params, ref rate, time out, path mtu */ - NFV9_LOG_PATH_MTU_TOO_SMALL, /* 1 param, path mtu passed */ - NFV9_LOG_CANNOT_ADD_VRF_NOT_FOUND, /* 1 param, in vrf id */ - - VRF_MAP_ADDR_POOL_START_ADDR_GT_END_ADDR = 30, /* 2 params, start and end addr */ - VRF_MAP_ADDR_POOL_ADDR_POOL_TOO_LARGE, /* 2 params, start and end addr */ - VRF_MAP_ADDR_POOL_INVALID_IN_OR_OUT_VRF, /* 2 params, in vrf and out vrf */ - VRF_MAP_ADDR_POOL_TOO_LARGE_FOR_CORE, /* 2 params, pool size, core instance */ - VRF_MAP_DEL_POOL_START_ADDR_GT_END_ADDR, /* 2 params, start and end addr */ - VRF_MAP_DEL_POOL_ADDR_POOL_NOT_FOUND, /* 2 params, start and end addr */ - VRF_MAP_DEL_POOL_VRF_MAP_EMPTY, /* 2 params, start and end addr */ - - ADD_SVI_ADDR_INVALID_VRF = 40, /* 2 params, vrf passed and ipv4 addr */ - ADD_SVI_INDEX_INVALID_VRF, /* 2 params, vrf, uidb_index */ - - MAPPED_STAT_PORT_INVALID_OUTPUT_PARAMS = 50, - /* 3 params, out vrf, out ip, out port */ - MAPPED_STAT_PORT_UDP_PORT_POLARITY_MISMATCH, /* 2 params, in port and out port */ - MAPPED_STAT_PORT_IN_VRF_MAP_EMPTY, /* 1 param, in vrf id passed */ - MAPPED_STAT_PORT_VRF_MAP_NOT_IN_S_RUN, /* 1 param, vrf map status */ - MAPPED_STAT_PORT_INVALID_OUT_VRF_ID, /* 1 param, out vrf id passed */ - MAPPED_STAT_PORT_FAILED_TO_ADD_STAT_PORT, /* 4 params, in vrf, in ip, in port, error code */ - - STAT_PORT_INVALID_IN_PARAMS = 60, /* 4 params, in vrf, in ip, in port, proto */ - STAT_PORT_FAILED_TO_ADD_STAT_PORT, /* 4 params, in vrf, in ip, in port, error code */ - STAT_PORT_CONFIG_IN_USE, /* 4 params, in vrf, in ip, in port, proto */ - - DEL_STAT_PORT_IN_VRF_MAP_EMPTY = 70, /* 1 param, in vrf id passed */ - DEL_STAT_PORT_INVALID_IN_PARAMS, /* 4 params, in vrf, in ip, in port, proto */ - DEL_STAT_PORT_CANNOT_DELETE_NO_ENTRY, /* 4 params, in vrf, in ip, in port, proto */ - DEL_STAT_PORT_CANNOT_DELETE_NOT_STATIC_PORT, /* 4 params, in vrf, in ip, in port, proto*/ - - XLAT_SVI_CFG_INVALID_INDEX = 80, /* 1 param - uidb_index */ - XLAT_WRONG_V6_PREFIX_MASK, /* 1 param - v6 prefix mask */ - XLAT_INVALID_XLAT_ID_ERROR, /* 1 param - id */ - - V6RD_INVALID_6RD_ID_ERROR = 90, /*1 param - id */ - MAPE_INVALID_MAPE_ID_ERROR = 100 /* param - id */ -} spp_config_error_sub_codes_t; - -typedef enum { - CONFIG_DUMMY, - CONFIG_DUMMY_MAX, - SHOW_DUMMY, - SHOW_DUMMY_MAX, - DEBUG_DUMMY, - DEBUG_DUMMY_MAX -} spp_dummy_handler_sub_cdes_t; - -typedef enum { - CMVX_READ, - CMVX_WRITE -} spp_cmvx_error_sub_codes_t; - -typedef enum { - FRAG_DB_INVALID_BUCKET, - FRAG_DB_NO_ENTRY -} spp_frag_db_error_sub_codes_t; - -typedef enum { - CLI_INVALID_PAYLOAD_SIZE, - CLI_INVALID_MSG_ID -} spp_cli_error_sub_codes_t; - -typedef enum { - NFV9_DOWNSTREAM_CONGESTION, - NFV9_FAILED_TO_CREATE_CONTEXT -} spp_nfv9_error_sub_codes_t; - -typedef struct spp_cnat_logger_tbl_t_ { - u16 error_code; // The thread id stored by software - u16 num_args; - u16 rate_limit_time; // If we need to rate_limit logging - u8 param_name[7][32];// Parameter name for debug purposes -} spp_cnat_logger_tbl_t; - -extern spp_cnat_logger_tbl_t spp_cnat_logger_table[]; - -/* - * This corresponds to the length of the IMETRO SHIM Header for RODDICK - * For non-roddick cases, introduce an Ethernet header as well - */ -#if defined(RODDICK) -#define SPP_TRACE_LOG_SHIM_HDR_OFFSET 8 -#define SPP_TRACE_LOG_ENCAPS_OFFSET 0 -#else -#define SPP_TRACE_LOG_SHIM_HDR_OFFSET 0 -#define SPP_TRACE_LOG_ENCAPS_OFFSET 16 -#endif - -#define SPP_LOG_TRACE_HEADER_LENGTH \ - (sizeof(spp_trace_log_hdr_t)) - - -#define SPP_TRACE_LOG_IP_HDR_OFFSET \ - (SPP_TRACE_LOG_ENCAPS_OFFSET + \ - SPP_TRACE_LOG_SHIM_HDR_OFFSET) - - -#define SPP_TRACE_LOG_UDP_HDR_OFFSET \ - (SPP_TRACE_LOG_IP_HDR_OFFSET + sizeof(ipv4_header)) - -#define SPP_TRACE_LOG_HDR_OFFSET \ - (SPP_TRACE_LOG_UDP_HDR_OFFSET + sizeof(udp_hdr_type_t)) - -#define SPP_TRACE_LOG_RECORD_LENGTH 4 - -/* - * Let us put the maximum length of the log data to be 1400 - */ -#define SPP_TRACE_LOG_MAX_PKT_LENGTH 800 - -/* Structures and defines to store log info for MSC */ -#define SPP_TRACE_LOG_INVALID_LOGGING_INDEX 0xffffffff - -/* - * This structure stores the Logging information on per LOG TYPE - * basis. This structure is allocated from a pool and index - * to this structure based on log type - */ -typedef struct { - /* - * This field determines the maximum size of the Netflow V9 information - * that can be stored in a logging packet - */ - u16 max_length_minus_max_record_size; - - u32 sequence_num; /* Sequence number of the logging packet */ - u32 last_pkt_sent_count; - u16 pkt_length; /* Length of the currently NFv9 information */ - u16 log_record_length; /* Length of add record */ - u16 total_record_length; /* number of trace records */ - u16 total_record_count; - spp_log_type_t log_type; - /* - * current logging context - */ - spp_ctx_t *current_logging_context; - - /* - * Timestamp in UNIX seconds corresponding to when the current - * logging packet was created - */ - u32 current_logging_context_timestamp; - - /* - * Queued logging context waiting to be sent to the l3 infra node - */ - spp_ctx_t *queued_logging_context; - - /* - * Headers corresponding to various records in this - * current nfv9 logging context - */ - spp_trace_log_t *log_record; - spp_trace_log_hdr_t *log_header; - u8 *next_data_ptr; - -} spp_trace_log_info_t; - -typedef struct { - /* - * spp_ctx_alloc() call failed - */ - u64 spp_trace_log_context_creation_fail_count; - - /* - * Cannot send the existing logging pkt, so cannot create - * any additional packets for logging purposes - */ - u64 spp_trace_log_context_creation_deferred_count; - - /* - * Cannot send the existing logging pkt due to cnat_rewrite_output - * superframe being full. - */ - u64 spp_trace_log_downstream_constipation_count; -} spp_global_counters_t; - - -/* - * Global structure for SPP LOGS - */ -typedef struct { - /* A timer structure to periodically send log packets - * that have been waiting to be full for a long time. This will - * ensure event/error logs don't get delayed too much before they - * are sent to the MSC. - */ - spp_timer_t log_timer; - - /* - * Node index corresponding to the infra L3 output node - * to which the nfv9 logging node will send the packet - */ - u16 spp_trace_log_disp_node_index; - - /* - * Whether we have initialized the NFv9 information - */ - u8 spp_trace_log_init_done; - - /* - * pool index in global pool based on log type - */ - u32 spp_log_pool_index[SPP_LOG_MAX]; - -} spp_trace_log_global_info_t; - - -extern spp_timer_t sensor_timer; -extern spp_trace_log_info_t spp_default_trace_log_info; -extern spp_trace_log_info_t *spp_trace_log_info_pool; - -extern spp_trace_log_global_info_t spp_trace_log_global_info; - -void spp_trace_logger(u16 error_code, u16 num_args, u32 *arg); -void spp_trace_log_init(void); -void init_trace_log_buf_pool(void); -void spp_printf(u16 error_code, u16 num_args, u32 *arg); - -/* - * The following 2 functions are temporary hacks until - * we have RTC support from the PD nodes - */ -#if 0 -inline -u32 spp_trace_log_get_sys_up_time_in_ms (void); -#endif -extern -u32 spp_trace_log_get_unix_time_in_seconds (void); - -enum { - TEMPERATURE_SENSOR_TEST_MODE, - TEMPERATURE_SENSOR_QUIET_MODE, -}; - -extern int temperature_read_blocked; - -void read_octeon_sensors(u8 mode); -void Init_temperature_sensors(); -#endif /* __SPP_PLATFORM_TRACE_LOG_H__ */ diff --git a/plugins/vcgn-plugin/vcgn/spp_timers.h b/plugins/vcgn-plugin/vcgn/spp_timers.h deleted file mode 100644 index afb0147b..00000000 --- a/plugins/vcgn-plugin/vcgn/spp_timers.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - *------------------------------------------------------------------ - * spp_timers.h - * - * Copyright (c) 2008-2009 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ -#ifndef __SPP_TIMERS_H__ -#define __SPP_TIMERS_H__ - - -typedef struct d_list_el_ { - struct d_list_el_ *next; - struct d_list_el_ *prev; -} d_list_el_t; - -/* - * d_list_init - */ - -static inline void d_list_init (d_list_el_t *headp) -{ - headp->prev = headp->next = headp; -} - -/* - * d_list_init - add at head of list - */ - -static inline void d_list_add_head (d_list_el_t *headp, - d_list_el_t *elp) -{ - ASSERT(elp->prev == elp); /* multiple enqueue, BAD! */ - ASSERT(elp->next == elp); - - elp->next = headp->next; - headp->next = elp; - elp->prev = elp->next->prev; - elp->next->prev = elp; -} - -/* - * d_list_add_tail - add element at tail of list - */ -static inline void d_list_add_tail (d_list_el_t *headp, - d_list_el_t *elp) -{ - ASSERT(elp->prev == elp); /* multiple enqueue, BAD! */ - ASSERT(elp->next == elp); - - headp = headp->prev; - - elp->next = headp->next; - headp->next = elp; - elp->prev = elp->next->prev; - elp->next->prev = elp; -} - -/* - * d_list_rem_head - removes first element from list - */ -static inline d_list_el_t *d_list_rem_head (d_list_el_t *headp) -{ - d_list_el_t *elp; - - elp = headp->next; - if (elp == headp) - return (NULL); - headp->next = elp->next; - elp->next->prev = elp->prev; - - elp->next = elp->prev = elp; - return (elp); -} - -/* - * d_list_rem_elem - removes specific element from list. - */ -static inline void d_list_rem_elem (d_list_el_t *elp) -{ - d_list_el_t *headp; - - headp = elp->prev; - - headp->next = elp->next; - elp->next->prev = elp->prev; - elp->next = elp->prev = elp; -} - -#define TIMER_BKTS_PER_WHEEL 128 /* power of 2, please */ -#define TIMER_NWHEELS 4 - -typedef struct { - i32 curindex; /* current index for this wheel */ - d_list_el_t *bkts; /* vector of bucket listheads */ -} spp_timer_wheel_t; - - -typedef struct { - u64 next_run_ticks; /* Next time we expire timers */ - spp_timer_wheel_t **wheels; /* pointers to wheels */ -} spp_timer_axle_t; - - -typedef struct { - d_list_el_t el; - u16 cb_index; - u16 flags; - u64 expires; -} spp_timer_t; - -#define SPP_TIMER_RUNNING 0x0001 - - -/* - * prototypes - */ -void spp_timer_set_ticks_per_ms(u64); -void spp_timer_axle_init (spp_timer_axle_t *ta); -void spp_timer_expire(spp_timer_axle_t *ta, u64 now); -void spp_timer_final_init(void); - -void spp_timer_start(spp_timer_t *tp); -void spp_timer_start_axle(spp_timer_axle_t *ta, spp_timer_t *tp); -void spp_timer_stop(spp_timer_t *tp); -u16 spp_timer_register_callback (void (*fp)(spp_timer_t *)); - -#endif /* __SPP_TIMERS_H__ */ diff --git a/plugins/vcgn-plugin/vcgn/tcp_header_definitions.h b/plugins/vcgn-plugin/vcgn/tcp_header_definitions.h deleted file mode 100644 index 02920bcc..00000000 --- a/plugins/vcgn-plugin/vcgn/tcp_header_definitions.h +++ /dev/null @@ -1,1582 +0,0 @@ -/* - *----------------------------------------------------------------------------- - * - * Filename: tcp_header_definitions.h - * - * Description: Layer 2, 3, 4 definitions and header types - * - * Assumptions and Constraints: - * - * Copyright (c) 2012-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *----------------------------------------------------------------------------- - */ - -#ifndef __TCP_HEADER_DEFINITIONS_H__ -#define __TCP_HEADER_DEFINITIONS_H__ - -/* - * A general list of Layer 3 protocols, used by many Layer 2 encaps. - * - * formerly: - * TYPE_IP TYPE_IP10MB - * TYPE_ARP TYPE_RFC826_ARP - * TYPE_RARP TYPE_REVERSE_ARP - * TYPE_MPLS TYPE_TAGSWITCH - */ -#define TYPE_IP 0x0800 -#define TYPE_IP_V6 0x86DD -#define TYPE_ARP 0x0806 -#define TYPE_RARP 0x8035 -#define TYPE_MPLS 0x8847 -#define TYPE_CDP 0x2000 -#define TYPE_CGMP 0x2001 -#define TYPE_LACP 0x8808 /* 802.3ad */ -#define TYPE_CLNS 0xFEFE - -#define TYPE_PPPOE_SESSION 0x8864 /* PTA plus */ -#define TYPE_PPPOE_DISCOVERY 0x8863 /* PTA plus */ - -/* - * for atm arp handling - */ -#define IN_ATM_ARP_BIT 0x0008 - -/* - * The Layer 2 header structures. - */ - - -/* -** HDLC -*/ - -typedef struct hdlc_hdr_type { - u16 addr; - u16 type; - u8 data[0]; -} hdlc_hdr_type; - -#define HDLC_ADDR_CMD 0x0F00 -#define HDLC_HDR_LEN 4 -#define HDLC_BROADCAST_BIT 31 -#define TYPE_KEEP 0x8035 - -#define HDLC_CLNS (HDLC_ADDR_CMD<<16|TYPE_CLNS) -#define HDLC_CDP (HDLC_ADDR_CMD<<16|TYPE_CDP) -#define HDLC_MPLS (HDLC_ADDR_CMD<<16|TYPE_MPLS) -#define HDLC_IP (HDLC_ADDR_CMD<<16|TYPE_IP) -#define HDLC_IP_V6 (HDLC_ADDR_CMD<<16|TYPE_IP_V6) -#define HDLC_KEEPALIVE_CMD (HDLC_ADDR_CMD<<16|TYPE_KEEP) - -/* -** PPP -*/ - -typedef struct ppp_comp_hdr_type { - union { - u8 ppp_u8[4]; - u16 ppp_u16[2]; - u32 ppp_u32; - } ppp_comp_u; -} ppp_comp_hdr_type; - -#define PPP_STATION 0xFF03 -#define PPP_STATION_LEN 0x2 -#define PPP_ENDPROTO 0x01 -#define PPP_NOT_ENDPROTO 0xfffffffe -#define PPP_CONTROL_PROTOCOL_MASK 0x8000 -#define PPP_CONTROL_PROTOCOL_BIT 15 -#define PPP_CSCO_LEN 4 -#define PPP_RFC1661_LEN 2 -#define PPP_RFC1661_COMP_LEN 1 - -#define TYPE_PPP_IP 0x0021 -#define TYPE_PPP_IP_V6 0x0057 -#define TYPE_PPP_MPLS_UNICAST 0x0281 -#define TYPE_PPP_MPLS_CONTROL 0x8281 -#define TYPE_PPP_CLNS 0x0023 -#define TYPE_PPP_CDP 0x0207 - -#define TYPE_PPP_IPCP 0x8021 -#define TYPE_PPP_LCP 0xC021 -#define TYPE_PPP_PAP 0xC023 -#define TYPE_PPP_LQR 0xC025 -#define TYPE_PPP_CHAP 0xC223 - - -#define TYPE_PPP_LCP_ECHO_REQUEST 0x09 -/* -** MultiLink PPP -*/ - -#define MLPPP_FLAGS_FIELD_LEN 4 -#define MLPPP_BEGIN_MASK 0x80000000 -#define MLPPP_END_MASK 0x40000000 -#define MLPPP_BEGIN_END_MASK (MLPPP_BEGIN_MASK|MLPPP_END_MASK) -#define MLPPP_BEGIN_END_SHIFT 30 -#define MLPPP_SEQUENCE_NUM_MASK 0x00FFFFFF -#define MLPPP_MC_CLASS_ID_MASK 0x3C000000 -#define MLPPP_MC_CLASS_SHIFT 26 - -#define TYPE_PPP_MULTILINK 0x003D - -/* these are needed in the micro-code, for optimizations */ -#define TYPE_PPP_FULL_IP_4 0xff030021 -#define TYPE_PPP_FULL_IP_3 0xff0321 -#define TYPE_PPP_FULL_IP_2 0x0021 -#define TYPE_PPP_FULL_IP_1 0x21 - -#define MLPPP_BEGIN_END_MASK_BYTE 0xC0 -#define MLPPP_BEGIN_BIT 7 -#define MLPPP_END_BIT 6 -#define MLPPP_MC_CLASS_ID_MASK_BYTE 0x3C -#define MLPPP_MC_CLASS_ID_SHIFT_BYTE 2 - -#define MLPOA_BEGIN_END_SHIFT 24 - -/* -** Ethernet ARPA -*/ - - -typedef struct ethernet_arpa_hdr_type { - u8 daddr[6]; - u8 saddr[6]; - u16 type; - u8 data[0]; -} ethernet_arpa_hdr_type; - -typedef struct extension_802p3_type { - u16 type; - u8 ctl; - u8 data[0]; -} extension_802p3_type; - -typedef struct ethernet_802p3_hdr_type { - u8 daddr[6]; - u8 saddr[6]; - u16 length; - extension_802p3_type extension; -} ethernet_802p3_hdr_type; - - -typedef struct ethernet_vlan_802p3_hdr_type { - u8 daddr[6]; - u8 saddr[6]; - u16 type1; - u16 vlan_id; - u16 length; - extension_802p3_type extension; -} ethernet_vlan_802p3_hdr_type; - -#define MIN_ETHERNET_PKT_LEN 60 -#define MAX_ETHERNET_PKT_LEN 1500 -#define ETHERNET_ARPA_HDR_LEN 14 -#define ETHERNET_TYPE_FIELD_SIZE 2 - - -/* -** Ethernet 802.1q (VLAN) -*/ - -typedef struct ethernet_vlan_hdr_type { - u8 dest_addr[6]; - u8 src_addr[6]; - u16 type1; - u16 vlan_hdr; - u16 type2; - u8 data[0]; -} ethernet_vlan_hdr_type; - - -/* -** Ethernet 802.1.q-in-q (QinQ) -*/ - -typedef struct ethernet_qinq_hdr_type { - u8 dest_addr[6]; - u8 src_addr[6]; - u16 type1; - u16 vlan_hdr1; - u16 type2; - u16 vlan_hdr2; - u16 type3; - u8 data[0]; -} ethernet_qinq_hdr_type; - - -/* -** Ethernet 802.3ad EtherChannel control -*/ - -typedef struct ethernet_lacp_hdr_type { - u8 daddr[6]; - u8 saddr[6]; - u16 type; - u16 LAcmd; - u8 data[0]; -} ethernet_lacp_hdr_type; - - -/* -** Ethernet 802.1 Bridge (spanning tree) PDU -*/ - -typedef struct ethernet_bpdu_hdr_type { - u8 daddr[6]; - u8 saddr[6]; - u8 dsap; - u8 ssap; - u8 control; - u8 more[0]; -} ethernet_bpdu_hdr_type; - -#define ETH_BPDU_DSAP 0x42 -#define ETH_BPDU_SSAP 0x42 -#define ETH_BPDU_CONTROL 0x03 -#define ETH_BPDU_MATCH 0x424203 - - -/************************************************************/ -/* PTA PLUS ETHERNET ENCAPSULATIONS */ -/* - * PPPoEoARPA 20 bytes - */ -typedef struct ethernet_pppoe_arpa_hdr_type { - u8 daddr[6]; - u8 saddr[6]; - u16 type; - /* pppoe hdr at begining of enet payload */ - u16 vtc; /* version(4b), type(4b) and code(8b) fields */ - u16 sid; - u16 len; - u8 ppp_header[0]; /* PPP header start, no ff03 field present */ -} ethernet_pppoe_arpa_hdr_type; - -typedef struct pppoe_hdr_type { - /* pppoe hdr at begining of enet payload */ - u16 vtc; /* version(4b), type(4b) and code(8b) fields */ - u16 sid; - u16 len; - u8 ppp_header[0]; /* PPP header start, no ff03 field present */ -} pppoe_hdr_type; - -/* -** PPPoEoVLAN (802.1p or 802.1q) 24 bytes -*/ -typedef struct ethernet_pppoe_vlan_hdr_type { - u8 dest_addr[6]; - u8 src_addr[6]; - u16 type1; - u16 vlan_hdr; - u16 type2; - /* pppoe hdr at begining of enet payload */ - u16 vtc; /* version(4b), type(4b) and code(8b) fields */ - u16 sid; - u16 len; - u8 ppp_header[0]; /* PPP header start, no ff03 field present */ -} ethernet_pppoe_vlan_hdr_type; - -/* -** PPPoEoQinQ 28 bytes -*/ -typedef struct ethernet_pppoe_qinq_hdr_type { - u8 dest_addr[6]; - u8 src_addr[6]; - u16 type1; - u16 vlan_hdr1; - u16 type2; - u16 vlan_hdr2; - u16 type3; - /* pppoe hdr at begining of enet payload */ - u16 vtc; /* version(4b), type(4b) and code(8b) fields */ - u16 sid; - u16 len; - u8 ppp_header[0]; /* PPP header start, no ff03 field present */ -} ethernet_pppoe_qinq_hdr_type; - -#define ETH_PPPOE_ARPA_HDR_LEN sizeof(ethernet_pppoe_arpa_hdr_type) -#define ETH_PPPOE_VLAN_HDR_LEN sizeof(ethernet_pppoe_vlan_hdr_type) -#define ETH_PPPOE_QINQ_HDR_LEN sizeof(ethernet_pppoe_qinq_hdr_type) -#define PPPOE_HDR_LEN 6 -/* End PTA PLUS ETHERNET ENCAPSULATIONS */ -/****************************************************************/ - - - -#define TYPE_DOT1Q 0x8100 -#define DOT1Q_HDR_LEN 18 -#define DOT1Q_VLAN_ID_MASK 0x0FFF -#define DOT1Q_VLAN_ID_RES_0 0x0000 -#define DOT1Q_VLAN_ID_RES_4095 0x0FFF -#define DOT1Q_ARPA_INDEX DOT1Q_VLAN_ID_RES_0 - -#define TYPE_QINQ_91 0x9100 -#define TYPE_QINQ_92 0x9200 -#define TYPE_QINQ_88A8 0x88A8 -#define QINQ_HDR_LEN 22 - -/* - * 802.1p support - */ -#define DOT1P_VLAN_COS_MASK 0xE000 -#define DOT1P_VLAN_COS_SHIFT 13 -#define DOT1P_MAX_COS_VALUE 7 - -/* -** Frame Relay -*/ - -/* - * formerly: - * TYPE_FR_IETF_IPV4 ENCAPS_FR_IETF - * TYPE_FR_CISCO_IPV4 ENCAPS_FR_CISCO - * TYPE_FR_ISIS ENCAPS_FR_ISIS - * - * FR_LMI_DLCI_CISCO LMI_DLCI_CISCO - * FR_LMI_DLCI_IETF LMI_DLCI_ITUANSI - */ - -typedef struct frame_relay_hdr_type { - u16 address; - u16 control_nlpid; - u8 data[0]; -} frame_relay_hdr_type; - -typedef struct fr_snap_hdr_type { - u16 address; - u8 control; - u8 pad; - u8 nlpid; - u8 oui[3]; - u16 protocol_id; -} fr_snap_hdr_type; - -#define FR_ADDR_LEN 2 -#define FR_CTL_NLPID_LEN 2 -#define FR_HDR_LEN (FR_ADDR_LEN+FR_CTL_NLPID_LEN) - -/* - * These defines are for the FR-SNAP header. - * The SNAP header is set up solely so that we can - * identify ARP packets, which look like this: - * - * control pad nlpid oui protocol_id - * 03 00 80 00 00 00 0806 - */ -#define FR_ARP_CONTROL 0x03 -#define FR_ARP_PAD 0x00 -#define FR_ARP_NLPID 0x80 -#define FR_ARP_OUI_0 0x00 -#define FR_ARP_OUI_1 0x00 -#define FR_ARP_OUI_2 0x00 -/* - * these are used only in the tmc code - */ -#define FR_NLPID_OUI_LEN 4 -#define FR_ARP_CONTROL_PAD 0x0300 -#define FR_ARP_NLPID_OUI 0x80000000 - - -#define FR_DLCI_UPPER_MASK 0xFC00 -#define FR_DLCI_UPPER_SHIFT 6 -#define FR_DLCI_LOWER_MASK 0x00F0 -#define FR_DLCI_LOWER_SHIFT 4 - -/* - * Defines for converting a DLCI for insertion into a synthesized FR address - * field for FRoMPLS disposition. - - * bit 8 7 6 5 4 3 2 1 - * +-------------------------------+ - * | Flag | - * | 0 1 1 1 1 1 1 0 | - * +-------------------------------+ - * | Upper DLCI |C/R| 0 | - * +-------------------------------+ - * | Lower DLCI | F | B | DE| 1 | - * +-------------------------------+ - * | | - * :Frame relay information field : - * : (i.e.payload) : - * | | - * +-------------------------------+ - * | FCS (2 or 4 octets) | - * | | - * +-------------------------------+ - * | Flag | - * | 0 1 1 1 1 1 1 0 | - * +-------------------------------+ - * - * a-With 10 bits for the DLCI - */ -#define FR_DLCI_TO_HDR_UPPER_MASK 0x3f0 -#define FR_DLCI_TO_HDR_UPPER_SHIFT (10-4) -#define FR_DLCI_TO_HDR_LOWER_MASK 0xf -#define FR_DLCI_TO_HDR_LOWER_SHIFT 4 - -#define TYPE_FR_IETF_IP 0x03CC -#define TYPE_FR_IETF_IP_V6 0x038E -#define TYPE_FR_CISCO_IP 0x0800 -#define TYPE_FR_CISCO_IP_V6 0x86DD -#define TYPE_FR_ISIS 0x0383 -#define TYPE_FR_SNAP0PAD 0x0380 -#define TYPE_FR_SNAP1PAD 0x0300 -#define TYPE_FR_FRF12 0x03B1 -#define TYPE_FR_MLP 0x03CF -#define TYPE_FR_EEK 0x8037 - -#define FR_LMI_DLCI_CISCO 1023 -#define FR_LMI_DLCI_IETF 0 - -#define FR_NOT_NOT_NOT 0 -#define FR_NOT_NOT_DE 1 -#define FR_NOT_BECN_NOT 2 -#define FR_NOT_BECN_DE 3 -#define FR_FECN_NOT_NOT 4 -#define FR_FECN_NOT_DE 5 -#define FR_FECN_BECN_NOT 6 -#define FR_FECN_BECN_DE 7 - -#define FR_FECN_BECN_DE_MASK 0x000E -#define FR_FECN_BECN_DE_SHIFT 1 - -/* Address field extension bit for standard 2-byte FR address field */ -#define FR_EA1_MASK 0x0001 -#define FR_EA1_MASK_BIT 0 - -/* - * these are needed in the micro-code, for optimizations - */ - -/* the bit position (in the address field) of the LSB of the DLCI */ -#define FR_DLCI_LS_BIT 4 - - -/* -** -** MultiLink Frame Relay -** -*/ - -typedef struct mlfr_hdr_type { - u16 frag_hdr; - u16 address; - u16 control_nlpid; - u8 data[0]; -} mlfr_hdr_type; - -/* - * LIP frames have B, E and C set--the other - * bits in the frag_hdr field are irrelevant. - * - * NOTE: Injected LIP packets have a frag_hdr of 0xE100. - * - */ -#define MLFR_LIP_FRAME 0xE100 -#define MLFR_LIP_MASK 0xE000 -#define MLFR_FRAG_HDR_LEN 2 - -#define MLFR_BEGIN_MASK 0x8000 -#define MLFR_END_MASK 0x4000 -#define MLFR_BEGIN_END_MASK (MLFR_BEGIN_MASK|MLFR_END_MASK) -#define MLFR_BEGIN_END_SHIFT 14 - -#define MLFR_SEQ_NUM_HI_MASK 0x1E00 -#define MLFR_SEQ_NUM_HI_SHIFT 1 -#define MLFR_SEQ_NUM_LO_MASK 0x00FF - -/* - * these are needed in the micro-code, for optimizations - */ -#define MLFR_BEGIN_END_MASK_BYTE 0xC0 - - -/* - * FRF.12 definitions - */ -typedef struct frf12_hdr_type_ { - u16 address; - u16 control_nlpid; - u16 frag_hdr; - u8 data[0]; -} frf12_hdr_type; - -#define FRF12_FRAG_HDR_LEN sizeof(frf12_hdr_type) - -#define FRF12_BEGIN_MASK 0x8000 -#define FRF12_END_MASK 0x4000 -#define FRF12_BEGIN_END_MASK (FRF12_BEGIN_MASK|FRF12_END_MASK) -#define FRF12_BEGIN_END_SHIFT 8 - -#define FRF12_SEQ_NUM_HI_MASK 0x1E00 -#define FRF12_SEQ_NUM_HI_SHIFT 1 -#define FRF12_SEQ_NUM_LO_MASK 0x00FF -#define FRF12_BEGIN_END_MASK_BYTE 0xC0 - - - -/* -** -** MLP over Frame Relay -** The ppp hdr can be either a -** an MLP hdr or a PPP hdr -** -** MLP can be compressed or not: -** a) 0xff03003d -** b) 0x003d -** c) 0x3d -** followed by: -** 1 byte with begin/end bits -** 3 bytes of a sequence # -** -** PPP can be also be compressed or not. -** Only these will be fwded: -** a) 0xff030021 -** b) 0xff0321 -** c) 0x0021 -** d) 0x21 -** -** -*/ -typedef struct mlpofr_hdr_type { - u16 address; - u16 control_nlpid; - u8 ppp_header[0]; -} mlpofr_hdr_type; - -/* -** ATM - -*/ - -/* - * channel_handle is defined as follows: - * - * bits 15 = reserved (must be 0) - * bits 14 - 0 = channel handle - * - * - * flags is a bitfield defined as follows: - * - * bits 15 - 13 = proto (PPPoA RFC1661 = 0, - * PPPoE = 1, - * RBE = 2, - * PPPoA Cisco = 3, - * MLPoATM RFC1661 = 4, - * MLPoATM Cisco = 5, - * Reserved = 6-7) - * bit 12 = encap (MUX=0, - * SNAP=1) - * bits 11 - 6 = reserved (must be 0) - * bits 5 - 3 = pkt_type (AAL5 pkt = 0, - * Raw cell (includes F4 OAM) = 1, - * F5 segment OAM cell = 2 - * F5 end-to-end OAM cell = 3 - * Reserved = 4-7) - * bit 2 = EFCI (congestion indication) - * bit 1 = reserved (must be 0) - * bit 0 = CLP (cell loss priority) - */ - -typedef struct apollo_atm_generic_hdr_type { - u16 channel_handle; - u16 flags; -} apollo_atm_generic_hdr_type; - -typedef struct apollo_atm_aal5_snap_hdr_type { - u16 channel_handle; - u16 flags; - u8 dsap; - u8 ssap; - u8 control; - u8 oui[3]; - u16 type; - u8 data[0]; -} apollo_atm_aal5_snap_hdr_type; - -typedef struct atm_aal5_snap_hdr_type { - u8 dsap; - u8 ssap; - u8 control; - u8 oui[3]; - u16 pid; - u16 pad; - u8 data[0]; -} atm_aal5_snap_hdr_type; - - -typedef struct apollo_atm_aal5_snap_hdr1_type { - u16 channel_handle; - u16 flags; - u8 dsap; - u8 ssap; - u8 control; - u8 oui0; - u8 oui1; - u8 oui2; - u16 type; - u8 data[0]; -} apollo_atm_aal5_snap_hdr1_type; - -typedef struct apollo_atm_aal5_clns_hdr_type { - u16 channel_handle; - u16 flags; - u16 type; - u16 data; -} apollo_atm_aal5_clns_hdr_type; - -typedef struct apollo_atm_aal5_ilmi_hdr_type { - u16 channel_handle; - u16 flags; - u8 data[0]; -} apollo_atm_aal5_ilmi_hdr_type; - -typedef struct apollo_atm_aal5_mux_hdr_type { - u16 channel_handle; - u16 flags; - u8 data[0]; -} apollo_atm_aal5_mux_hdr_type; - -typedef struct apollo_atm_oam_f4_hdr_type { - u16 channel_handle; - u16 flags; - /* - * gcf_vpi_vci_pt_clp is a bitfield defined as follows: - * - * bits 31 - 28 = GCF - * bits 27 - 20 = VPI - * bits 19 - 4 = VCI - * bits 3 - 1 = PT - * bit 0 = CLP - */ - u32 gcf_vpi_vci_pt_clp; - u8 data[0]; -} apollo_atm_oam_f4_hdr_type; - -#define APOLLO_ATM_OAM_F4_HDR_PT_MASK 0xE -#define APOLLO_ATM_OAM_F4_HDR_PT_SHIFT 1 - -typedef struct apollo_atm_oam_f5_hdr_type { - u16 channel_handle; - u16 flags; - u8 data[0]; -} apollo_atm_oam_f5_hdr_type; - -#define APOLLO_IRONBUS_EXT_LESS_PROTO 0xFFFF0FFF -#define APOLLO_CHANNEL_HANDLE_MASK 0xFFFF -#define APOLLO_PKT_TYPE_MASK 0x0038 -#define APOLLO_PKT_TYPE_SHIFT 3 -#define APOLLO_FLAG_CLP_MASK 0x0001 -#define APOLLO_FLAG_CLP_BIT 0 - -#define APOLLO_CHANNEL_HANDLE_RES_0 0x0000 -/* - * The 1 byte HEC field is removed by the line card. - */ -#define APOLLO_F4_RX_CELL_SIZE 52 -#define APOLLO_F5_RX_CELL_SIZE 52 - -#define APOLLO_ATM_PACKET_TYPE_AAL5 0 -#define APOLLO_ATM_PACKET_TYPE_F4 1 -#define APOLLO_ATM_PACKET_TYPE_F5_SEG 2 -#define APOLLO_ATM_PACKET_TYPE_F5_E_TO_E 3 -#define APOLLO_ATM_PACKET_TYPE_4 4 -#define APOLLO_ATM_PACKET_TYPE_5 5 -#define APOLLO_ATM_PACKET_TYPE_6 6 -#define APOLLO_ATM_PACKET_RESERVED 7 - -#define APOLLO_AAL5_MUX_IP_HDR_LEN 4 -#define APOLLO_AAL5_SNAP_HDR_LEN 12 - -#define APOLLO_RCV_IRON_BUS_EXT_LEN 4 -#define APOLLO_TX_IRON_BUS_EXT_LEN 8 - -/* - * MLPoA type definitions - */ -#define MLPOA_CISCO_HDR 0xFF03 -#define MLPOA_SNAP_HDR_LEN 4 -#define MLPOA_CISCO_HDR_LEN 2 - -/************************************************************/ -/* PTA PLUS ATM ENCAPSULATIONS */ - -/* RBE header 28 bytes*/ -typedef struct apollo_atm_aal5_llcsnap_rbe_hdr_type { - u16 channel_handle; - u16 flags; - u8 dsap; - u8 ssap; - u8 control; - u8 oui[3]; - u16 pid; - u16 pad; - /* enet header within */ - u8 daddr[6]; - u8 saddr[6]; - u16 type; - u8 data[0]; /* start of IP */ -} apollo_atm_aal5_llcsnap_rbe_hdr_type; - -/* PPPoEoA header 34 bytes*/ -typedef struct apollo_atm_aal5_llcsnap_pppoe_hdr_type { - u16 channel_handle; - u16 flags; - u8 dsap; - u8 ssap; - u8 control; - u8 oui[3]; - u16 pid; - u16 pad; - /* enet header within */ - u8 daddr[6]; - u8 saddr[6]; - u16 type; - /* pppoe hdr at begining of enet payload */ - u16 vtc; /* version(4b), type(4b) and code(8b) fields */ - u16 sid; - u16 len; - u8 ppp_header[0]; /* PPP header start, no ff03 field present */ -} apollo_atm_aal5_llcsnap_pppoe_hdr_type; - - -/* PPPoA MUX 4 bytes*/ -typedef struct apollo_atm_aal5_mux_pppoa_hdr_type { - u16 channel_handle; - u16 flags; - u8 ppp_header[0]; -} apollo_atm_aal5_mux_pppoa_hdr_type; - - -/* PPPoA SNAP LLC 8 bytes */ -typedef struct apollo_atm_aal5_llcsnap_pppoa_hdr_type { - u16 channel_handle; - u16 flags; - u8 dsap; - u8 ssap; - u8 control; - u8 nlpid; - u8 ppp_header[0]; -} apollo_atm_aal5_llcsnap_pppoa_hdr_type; - -/* MLPoA MUX (generic) */ -typedef struct apollo_atm_aal5_mux_mlpoa_hdr_type { - u16 channel_handle; - u16 flags; - u8 ppp_header[0]; -} apollo_atm_aal5_mux_mlpoa_hdr_type; - -/* MLPoA SNAP LLC */ -typedef struct apollo_atm_aal5_llcsnap_mlpoa_hdr_type { - u16 channel_handle; - u16 flags; - u8 dsap; - u8 ssap; - u8 control; - u8 nlpid; - u8 ppp_header[0]; -} apollo_atm_aal5_llcsnap_mlpoa_hdr_type; - - -#define PPPOA_SNAPLLC_HDR_LEN sizeof(apollo_atm_aal5_llcsnap_pppoa_hdr_type) -#define PPPOA_MUX_HDR_LEN sizeof(apollo_atm_aal5_mux_pppoa_hdr_type) -#define PPPOE_SNAPLLC_HDR_LEN sizeof(apollo_atm_aal5_llcsnap_pppoe_hdr_type) -#define RBE_SNAPLLC_HDR_LEN sizeof(apollo_atm_aal5_llcsnap_rbe_hdr_type) - -/* End PTA PLUS ATM ENCAPSULATIONS */ -/****************************************************************/ - -#define LLCSNAP_PID_DOT3_NOFCS 0x0007 - -/* -** the SNAP header -*/ - -/* - * Note that some of these definitions are split - * up along certain word or half word boundaries - * to help expediate the TMC code. - */ -#define LLC_SNAP_HDR_DSAP 0xAA -#define LLC_SNAP_HDR_SSAP 0xAA -#define LLC_SNAP_HDR_CONTROL 0x03 -#define LLC_SNAP_HDR_OUI_0 0x00 -#define LLC_SNAP_HDR_OUI_1 0x00 -#define LLC_SNAP_HDR_OUI_2 0x00 -#define LLC_SNAP_HDR_OUI_2_CDP 0x0C - -#define LLC_SNAP_HDR_DSAP_SSAP 0xAAAA -#define LLC_SNAP_HDR_DSAP_SSAP_CTRL_OUI0 0xAAAA0300 -#define LLC_SNAP_HDR_CONTROL_OUI 0x03000000 -#define LLC_SNAP_HDR_OUI1_OUI2_CDP 0x000C2000 - - - -/* -** SRP -*/ - -/* - * The v2_gen_hdr is a 2-byte field that contains the following: - * - * [ ttl | ring_id | mode | priority | parity ] - * bits 8 1 3 3 1 - */ -typedef struct srp_hdr_type { - u16 v2_gen_hdr; - u8 dest_addr[6]; - u8 src_addr[6]; - u16 protocol; - u8 data[0]; -} srp_hdr_type; - -#define SRP_HDR_LEN 16 - -#define SRP_IB_CHANNEL_CONTROL 0x0000 -#define SRP_IB_CHANNEL_DATA_HI 0x0001 -#define SRP_IB_CHANNEL_DATA_LO 0x0002 - -#define SRP_RING_ID_MASK 0x0080 -#define SRP_RING_ID_BIT 7 - -#define SRP_MODE_BITS_MASK 0x0070 -#define SRP_MODE_BITS_SHIFT 4 -#define SRP_MODE_CONTROL_TOPOLOGY 4 -#define SRP_MODE_CONTROL_IPS 5 -#define SRP_MODE_DATA 7 - -#define SRP_PRIORITY_BITS_MASK 0x000E -#define SRP_PRIORITY_BITS_SHIFT 1 -#define SRP_PRIORITY_HIGH 7 -#define SRP_PRIORITY_PAK_PRIORITY 6 - -/* this is for the tmc code */ -#define SRP_INV_PRIORITY_BITS_MASK 0xFFF1 - -#define SRP_PROT_CONTROL_TOPOLOGY 0x2007 -#define SRP_PROT_CONTROL_IPS 0x2007 - -/* this is for the tmc code */ -#define SRP_TRUE 1 -#define SRP_FALSE 0 - -/* -** MPLS -*/ -#define MPLS_EOS_BIT 0x00000100 -#define MPLS_EOS_SHIFT 8 -#define MPLS_LABEL_SIZE 4 -#define MAX_MPLS_LABEL_STACK 6 -#define MPLS_LABEL_MASK 0xfffff000 -#define MPLS_LABEL_SHIFT 12 -#define MPLS_TTL_MASK 0x000000ff -#define MPLS_EXP_MASK 0x00000e00 -#define MPLS_EXP_SHIFT 9 -#define MPLS_EXP_TTL_MASK 0x00000eff - - - -typedef union _layer2 { - hdlc_hdr_type hdlc; - ppp_comp_hdr_type ppp; - ethernet_arpa_hdr_type eth_arpa; - ethernet_vlan_hdr_type eth_vlan; - ethernet_qinq_hdr_type eth_qinq; - ethernet_lacp_hdr_type eth_lacp; - ethernet_bpdu_hdr_type eth_bpdu; - ethernet_802p3_hdr_type eth_802p3; - ethernet_vlan_802p3_hdr_type eth_vlan_802p3; - ethernet_pppoe_arpa_hdr_type eth_pppoe_arpa; /* PTA plus */ - ethernet_pppoe_vlan_hdr_type eth_pppoe_vlan; /* PTA plus */ - ethernet_pppoe_qinq_hdr_type eth_pppoe_qinq; /* PTA plus */ - frame_relay_hdr_type frame_relay; - fr_snap_hdr_type fr_snap; - mlfr_hdr_type mlfr; - mlpofr_hdr_type mlpofr; - frf12_hdr_type frf12; - apollo_atm_generic_hdr_type atm_generic; - apollo_atm_aal5_snap_hdr_type atm_aal5_snap; - apollo_atm_aal5_snap_hdr1_type atm_aal5_snap1; - apollo_atm_aal5_clns_hdr_type atm_aal5_clns; - apollo_atm_aal5_ilmi_hdr_type atm_aal5_ilmi; - apollo_atm_aal5_mux_hdr_type atm_aal5_mux; - apollo_atm_oam_f4_hdr_type atm_oam_f4; - apollo_atm_oam_f5_hdr_type atm_oam_f5; - apollo_atm_aal5_llcsnap_rbe_hdr_type atm_aal5_rbe_snapllc; /* PTA plus */ - apollo_atm_aal5_llcsnap_pppoe_hdr_type atm_aal5_pppoe_snapllc; /* PTA plus */ - apollo_atm_aal5_mux_pppoa_hdr_type atm_aal5_pppoa_mux; /* PTA plus */ - apollo_atm_aal5_llcsnap_pppoa_hdr_type atm_aal5_pppoa_snapllc; /* PTA plus */ - apollo_atm_aal5_mux_mlpoa_hdr_type mlpoa_generic; - apollo_atm_aal5_llcsnap_mlpoa_hdr_type mlpoa_snapllc; - srp_hdr_type srp; -} layer2_t; - -/* - * Define the Common OAM cell format - F4 & F5 cells - * For F4 cells: - * VPI == User VPI - * VCI == (3 == Segment), (4 == End-to-End) - * - * For F5 cells: - * VPI == User VPI - * VCI == User VCI - * PT == (100 == Segment, 101 == End-to-End) - * - * OAM Cell Type & Function Type: - * - * OAM_TYPE = (0001 == Fault management) - * OAM_FUNC == (0000 == AIS, 0001 == RDI, 0100 == CC, - * 1000 == loopback) - * - * OAM_TYPE = (0010 == Performance management) - * OAM_FUNC == (0000 == Forward Monitoring(FM), - * 0001 == Backward monitoring(BR), - * 0010 == Monitoring & reporting (FM+BR)) - * - * OAM_TYPE = (1000 == Activation/Deactivation) - * OAM_FUNC == (0000 == Performance Monitoring, - * 0001 == Continuity Check) - * - * OAM_TYPE = (1111 == Sytem Management) - * OAM_FUNC == (0001 == Security - non-real-time, - * 0010 == Security - real-time) - * - */ -#define ATM_OAM_FAULT_MGMT 0x1 /* OAM Fault mgmt. code */ -#define ATM_OAM_PRFRM_MGMT 0x2 /* performance mgmt code */ -#define ATM_OAM_ACT_DEACT 0x8 /* OAM Activation/Deactivation - code */ -#define ATM_OAM_SYSTEM_MGMT 0xF /* System Management code */ - -#define ATM_OAM_AIS_FUNC 0x0 /* AIS function type */ -#define ATM_OAM_RDI_FUNC 0x1 /* RDI function type */ -#define ATM_OAM_CC_FUNC 0x4 /* OAM CC FM function code */ -#define ATM_OAM_LOOP_FUNC 0x8 /* Loopback function type */ - -#define ATM_OAM_F5_SEGMENT 0x4 /* Segment function */ -#define ATM_OAM_F5_ENDTOEND 0x5 /* End-to-End function */ -#define ATM_OAM_F4_SEGMENT 0x3 /* Segment function */ -#define ATM_OAM_F4_ENDTOEND 0x4 /* End-to-End function */ -#define ATM_OAM_F4_PTI_ZERO 0x0 /* PTI=0 for F4 OAM */ - -typedef struct atm_oam_hdr_t_ { - unsigned oam_gfc:4; /* GFC */ - unsigned oam_vpi:8; /* VPI */ - unsigned oam_vci_ms:4; /* VCI (Most Significant Bits) */ - - unsigned oam_vci_ls:12; /* VCI (Least Significant Bits) */ - unsigned oam_pt:3; /* Payload Type */ - unsigned oam_clp:1; /* Cell Loss Priority */ - u8 data[0]; -} atm_oam_hdr_t; - -typedef struct atm_oam_type_func_t_ { - u8 oam_type:4; - u8 oam_func:4; - u8 data[0]; -} atm_oam_type_func_t; - -/* -** IP Version 4 header -*/ - -/* - * version_hdr_len_words [7-4] IP Header Version - * [3-0] IP Header Length in 32-bit words - * tos Type of Service - * total_len_bytes Total IP datagram length in bytes - * (including IP header) - * identification Unique fragmentation identifier - * frag_flags_offset [15-13] Fragmentation flags - * [12-0] Fragmentation Offset - * ttl Time To Live - * protocol_id Protocol Identifier - * checksum 16-bit 1's complement IP Header checksum - * src_addr IP Source Address - * dest_addr IP Destination Address - */ -typedef struct ipv4_header { - u8 version_hdr_len_words; - u8 tos; - u16 total_len_bytes; - u16 identification; - u16 frag_flags_offset; - u8 ttl; - u8 protocol; - u16 checksum; - u32 src_addr; - u32 dest_addr; - u8 data[0]; -} ipv4_header; - -/*OPTIONS PACKET TYPE - * +-+-+-+-+-+-+-+-+ - * |C| CL| OP | - * +-+-+-+-+-+-+-+-+ - */ -typedef struct ipv4_options { - u8 copy :1 ; - u8 op_class :2 ; - u8 option :5 ; - u8 pad ; -}ipv4_options; - -#define LOOSE_SOURCE_ROUTE 131 -#define STRICT_SOURCE_ROUTE 137 -#define IPV4_NO_OPTIONS_HDR_LEN (sizeof(ipv4_header)) -#define IPV4_VERSION 4 -#define IPV4_HEADER_LENGTH_WORDS 5 -#define IPV4_VERSION_HDR_LEN_FIELD ((u8) 0x45) -#define IPV4_HEADER_LENGTH_WORDS 5 -#define IPV4_MIN_HEADER_LENGTH_BYTES 20 -#define IP_HDR_LEN sizeof(ipv4_header) -#define IPV4_VERSION_VALUE_SHIFT 4 - -#define IPV4_FRAG_OFFSET_MASK (0x1fff) -#define IPV4_FRAG_MF_MASK (0x2000) -#define IPV4_FRAG_MF_SHIFT (13) - -/* 0.0.0.0 */ -#define IP_BOOTP_SOURCE_ADDRESS 0 -/* 255.255.255.255 */ -#define IP_LIMITED_BROADCAST_ADDRESS 0xFFFFFFFF - -/* - * IPv4 header - version & length fields - */ -#define IP_VER_LEN 0x45 -#define IP_VER 0x4 -#define IP_MIN_LEN 0x5 -#define IP_VER_MASK 0xf0 -#define IP_LEN_MASK 0x0f - -/* - * IPv4 header - TOS field - */ -#define PS_IP_TOS_MASK 0xff -#define IP_PRECEDENCE_SHIFT 5 /* shift value up to precedence bits */ -#define IP_DSCP_SHIFT 2 /* shift value up to dscp bits */ - -#define IP_TOS_PRECEDENCE 0xe0 /* mask of precedence in tos byte */ -#define IP_TOS_NO_PRECEDENCE 0x1f -#define IP_TOS_LOW_DELAY 8 /* values must be shifted 1 bit */ -#define IP_TOS_HIGH_TPUT 4 /* before using */ -#define IP_TOS_HIGH_RELY 2 -#define IP_TOS_LOW_COST 1 -#define IP_TOS_NORMAL 0 -#define IP_TOS_MASK 0x1e /* mask of tos in tos byte */ -#define IP_TOS_MBZ_MASK 0x01 /* mask for MZB bit in tos byte */ -#define IP_TOS_DSCP 0xfc /* mask for dscp in tos byte */ -#define IP_TOS_NO_DSCP 0x03 - -#define IP_TOS_METRIC_TYPES 8 -#define IP_TOS_SHIFT 1 - -#define IP_TOS_PRECEDENCE_MASK (IP_TOS_PRECEDENCE | IP_TOS_MASK) - -/* - * IP TOS Precedence values (High order 3 bits) - */ -#define TOS_PREC_NET_CONTROL 0xe0 -#define TOS_PREC_INET_CONTROL 0xc0 -#define TOS_PREC_CRIT_ECP 0xa0 -#define TOS_PREC_FLASH_OVER 0x80 -#define TOS_PREC_FLASH 0x60 -#define TOS_PREC_IMMEDIATE 0x40 -#define TOS_PREC_PRIORITY 0x20 -#define TOS_PREC_ROUTINE 0x00 -#define TOS_PREC_ILLEGAL 0xff /* invalid precedence value */ - -#define TOS_PREC_NET_CONTROL_NUM 7 -#define TOS_PREC_INET_CONTROL_NUM 6 -#define TOS_PREC_CRIT_ECP_NUM 5 -#define TOS_PREC_FLASH_OVER_NUM 4 -#define TOS_PREC_FLASH_NUM 3 -#define TOS_PREC_IMMEDIATE_NUM 2 -#define TOS_PREC_PRIORITY_NUM 1 -#define TOS_PREC_ROUTINE_NUM 0 - - - -/* - * IPv4 header - flags and fragment offset fields - */ -#define IP_FRAG_OFFSET_MASK 0x1fff - - -#define IP_FRAG_MORE_MASK 0x2000 -#define IP_FRAG_DF_MASK 0x4000 -#define IP_FRAG_UNDEF_MASK 0x8000 -#define IP_FRAG_NO_DF_SET 0x0000 - -/* bit definitions for fragment flags */ -#define IP_FRAG_MORE_BIT 13 -#define IP_FRAG_DF_BIT 14 -#define IP_FRAG_UNDEF_BIT 15 - -/* - * IPv4 header - TTL field - */ -#define TTL_DEFAULT 255 -#define TTL_1 1 -#define TTL_2 2 -#define TTL_255 255 - - -/* - * IPv4 header - protocol field - * - * ICMP_PROT 1 ICMP - * IGMP_PROT 2 group management - * GGP_PROT 3 GGP - * IPINIP_PROT 4 IPv4 in IPv4 encapsulation - * TCP_PROT 6 TCP - * EGP_PROT 8 EGP - * IGRP_PROT 9 IGRP - * UDP_PROT 17 UDP - * HMP_PROT 20 HMP - * RDP_PROT 27 RDP - * IPV6_INIP_PROT 41 IPV6 in IPv4 encapsulation - * RSVP_PROT 46 RSVP - * GRE_PROT 47 GRE - * ESP_PROT 50 ESP - * AHP_PROT 51 AHP - * SDNS0_PROT 53 SNDS - * NHRP_PROT 54 NHRP - * SDNS1_PROT 55 SDNS1 - * HELLO_PROT 63 HELLO - * ND_PROT 77 ND - * EONIP_PROT 80 CLNS over IP - * VINES_PROT 83 Banyan Vines - * NEWIGRP_PROT 88 IGRP - * OSPF_PROT 89 OSPF - * FST_RSRB_PROT 90 RSRB - * FST_DLSW_PROT 91 DLSW - * NOSIP_PROT 94 KA9Q/NOS compatible IP over IP - * PIM_PROT 103 PIMv2 - * PCP_PROT 108 PCP - * PGM_PROT 113 PGM - * MAX_PROT 113 maximum protocol number in the above list, - * used in creating case registry - */ -#define ICMP_PROT 1 -#define IGMP_PROT 2 -#define GGP_PROT 3 -#define IPINIP_PROT 4 -#define TCP_PROT 6 -#define EGP_PROT 8 -#define IGRP_PROT 9 -#define UDP_PROT 17 -#define HMP_PROT 20 -#define RDP_PROT 27 -#define IPV6_INIP_PROT 41 -#define RSVP_PROT 46 -#define GRE_PROT 47 -#define ESP_PROT 50 -#define AHP_PROT 51 -#define SDNS0_PROT 53 -#define NHRP_PROT 54 -#define SDNS1_PROT 55 -#define HELLO_PROT 63 -#define ND_PROT 77 -#define EONIP_PROT 80 -#define VINES_PROT 83 -#define NEWIGRP_PROT 88 -#define OSPF_PROT 89 -#define FST_RSRB_PROT 90 -#define FST_DLSW_PROT 91 -#define NOSIP_PROT 94 -#define PIM_PROT 103 -#define PCP_PROT 108 -#define PGM_PROT 113 -#define MAX_PROT 113 - -/*Well Known Application ports */ -#define FTP_PORT 21 /* For control connection */ -/* - * TCP header - */ -typedef struct tcp_hdr_type { - u16 src_port; - u16 dest_port; - u32 seq_num; - u32 ack_num; - u8 hdr_len; - u8 flags; - u16 window_size; - u16 tcp_checksum; - u16 urgent_pointer; - u8 option_data[0]; -} tcp_hdr_type; - -#define TCP_FLAG_FIN 0x01 -#define TCP_FLAG_SYN 0x02 -#define TCP_FLAG_RST 0x04 -#define TCP_FLAG_PUSH 0x08 -#define TCP_FLAG_ACK 0x10 -#define TCP_FLAG_URG 0x20 -#define TCP_FLAG_ECE 0x40 -#define TCP_FLAG_CWR 0x80 - -/* - * TCP Option - */ -typedef struct tcp_option_s { - u8 kind; - u8 length; - u8 data[0]; -} tcp_option_t; - -#define TCP_END_OPTIONS_LIST 0 -#define TCP_OPTION_NOP 1 -#define TCP_OPTION_MSS 2 -#define TCP_OPTION_WINDOW_SCALE 3 -#define TCP_OPTION_SACK_PERMITTED 4 -#define TCP_OPTION_SACK_DATA 5 -#define TCP_OPTION_ECHO 6 -#define TCP_OPTION_ECHO_REPLY 7 -#define TCP_OPTION_TSOPT 8 -/* - 9 2 Partial Order Connection Permitted. RFC 1693 - 10 3 Partial Order Service Profile. RFC 1693 - 11 6 CC, Connection Count. RFC 1644 - 12 6 CC.NEW RFC 1644 - 13 6 CC.ECHO RFC 1644 - 14 3 TCP Alternate Checksum Request. RFC 1146 - 15 Variable. TCP Alternate Checksum Data. RFC 1146 - 16 Skeeter. - 17 Bubba. - 18 3 Trailer Checksum Option. -*/ -#define TCP_OPTION_MD5_SIGNATURE 19 -/* - 20 SCPS Capabilities. - 21 Selective Negative Acknowledgements. - 22 Record Boundaries. - 23 Corruption experienced. - 24 SNAP. - 25 - 26 TCP Compression Filter. -*/ -#define TCP_OPTION_QUICK_START 27 - -#define TCP_OPTION_NUM_MAX 27 - -#ifdef TARGET_CISCO -#define tcp_printf(format_str, params...) //printf(format_str, ## params) -#else -#define tcp_printf(format_str, params...) printf(format_str, ## params) -#endif - -typedef struct udp_hdr_type { - u16 src_port; - u16 dest_port; - u16 udp_length; - u16 udp_checksum; -} udp_hdr_type_t; - -#define TYPE_IPV6 0x86dd -#define TYPE_IPV4 0x0800 - -/* - * version_trafficclass_flowlabel [31:28] IP Header Version, - [27:20] traffic_class, - [19:0] flow_label[20] - * payload_length Length of packet in bytes excluding header size(s) - * next_header Identifies the type of header following the IPv6 header - * hop_limit Decremented by 1 by each forwarding node, packet discarded when zero - * src_addr IPv6 Source Address - * dst_addr IPv6 Destination Address - */ -typedef struct ipv6_header { - u32 version_trafficclass_flowlabel; - u16 payload_length; - u8 next_header; - u8 hop_limit; - u32 src_addr[4]; - u32 dst_addr[4]; - u8 data[0]; -} ipv6_header_t; - -#define IPV6_HDR_LEN 40 -#define IPV6_HDR_LEN_WORDS 10 -#define IPV6_FLABLE_MASK 0x000FFFFF -#define IPV6_MIN_PATH_MTU (1280) - -#define IPV6_GET_IP_VER(ih) ((clib_net_to_host_u32((ih) \ - ->version_trafficclass_flowlabel) >> 28) & 0xf) -#define IPV6_GET_TOS(ih) ((clib_net_to_host_u32((ih) \ - ->version_trafficclass_flowlabel) >> 20) & 0xff) -#define IPV6_GET_FLOW_LABEL(ih) ((clib_net_to_host_u32((ih) \ - ->version_trafficclass_flowlabel)) & 0xfffff) - -#define IPV6_VERSION_VALUE (6) -#define IPV6_VERSION_VALUE_SHIFT (28) -#define IPV6_TRAFFIC_CLASS_VALUE_SHIFT (20) -#define IPV6_TRAFFIC_CLASS_VALUE_MASK (0xff) - -#define IPV6_PROTO_HOPOPTS 0 -#define IPV6_PROTO_TCP 6 -#define IPV6_PROTO_UDP 17 -#define IPV6_PROTO_IPV6 41 -#define IPV6_PROTO_ROUTING 43 -#define IPV6_PROTO_FRAGMENT 44 -#define IPV6_PROTO_DESTOPTS 60 -#define IPV6_PROTO_ESP 50 -#define IPV6_PROTO_AH 51 -#define IPV6_PROTO_ICMPV6 58 -#define IPV6_PROTO_NONE 59 - -/* standard v6 extension header are 2 tytes - * one byte next header - * one byte header length - */ - -typedef struct ipv6_frag_header { - u8 next_header; - u8 reserved; - u16 frag_offset_res_m; - u32 identification; -} ipv6_frag_header_t; - -#define IPV6_FRAG_HDR_LEN (sizeof(ipv6_frag_header_t)) - -#define IPV6_FRAG_OFFSET_MASK (0xFFF8) -#define IPV6_FRAG_OFFSET_SHIFT (3) -#define IPV6_FRAG_MORE_FRAG_MASK (0x0001) - -#define IPV6_TOS_SHIFT 20 -#define IPV6_TOS_SHIFT_HLF_WD 4 -#define IPV6_NEXT_HDR_SHIFT 8 - -typedef struct ipv6_routing_header { - u8 next_header; - u8 hdr_ext_len; - u8 routing_type; - u8 segments_left; - u8 data[0]; -} ipv6_routing_header_t; -#define IPV6_ROUTING_HDR_LEN (sizeof(ipv6_routing_header_t)) - -typedef struct ipv6_hop_header { - u8 next_header; - u8 hdr_ext_len; - u8 options[0]; -} ipv6_hop_header_t; -#define IPV6_HOP_LEN (sizeof(ipv6_hop_header_t)) - -typedef struct ipv6_dest_opt_header { - u8 next_header; - u8 hdr_ext_len; - u8 options[0]; -} ipv6_dest_opt_header_t; -#define IPV6_DESTOPT_LEN (sizeof(ipv6_dest_opt_header_t)) - - -/* Definition of ICMP header */ -typedef struct icmp_v4_s { - u8 type; - u8 code; - u16 checksum; - u16 identifier; - u16 sequence; -} icmp_v4_t; - -#define ICMPV4_HDR_SIZE (sizeof(icmp_v4_t)) -#define ICMPV4_ECHOREPLY 0 /* Type: echo reply */ -#define ICMPV4_ECHO 8 /* Type: echo request */ - -#define ICMPV4_UNREACHABLE 3 /* Type: destination unreachable */ -#define ICMPV4_UNRNET 0 /* Code: Net unreachable */ -#define ICMPV4_UNRHOST 1 /* Code: host unreachable */ -#define ICMPV4_UNRPROT 2 /* Code: protocol unreachable */ -#define ICMPV4_UNRPORT 3 /* Code: port unreachable */ -#define ICMPV4_UNRFRAG 4 /* Code: frag req DF set */ -#define ICMPV4_UNRADMIN 13 /* Code: administratively prohib. */ -#define ICMPV4_SOURCEROUTE_FAILED 5 /* Code: administratively prohib. */ - -#define ICMPV4_SRC_ROUTE_FAIL 5 /* Code: Source Route Failed */ -#define ICMPV4_NO_ROUTE_DESTN_8 8 /* Code: No Route to Destn */ -#define ICMPV4_NO_ROUTE_DESTN_11 11 /* Code: No Route to Destn */ -#define ICMPV4_NO_ROUTE_DESTN_12 12 /* Code: No Route to Destn */ - -#define ICMPV4_ADMIN_PROH_9 9 /* Code: Administratively Prohibited */ -#define ICMPV4_ADMIN_PROH_10 10 /* Code: Administratively Prohibited */ -#define ICMPV4_PREC_CUTOFF 15 /* Code: Precedence Cutoff */ - - -#define ICMPV4_TIMEEXCEEDED 11 /* Type: time exceeded */ -#define ICMPV4_TIMTTL 0 /* Code: ttl in transit code */ - -#define ICMPV4_PARAMETER_PROBLEM 12 /* Type: Parameter Problem */ -#define ICMPV4_PARAM_ERROR 0 /* Code: Pointer to Error */ -#define ICMPV4_MISSING_OPTION_CODE 1 /* Code: Mission option */ -#define ICMPV4_PARAM_BAD_LEN 2 /* Code: Bad Length */ - -#define ICMPV4_CONVERSION_ERROR 31 -#define ICMPV4_SOURCE_QUENCH 4 -#define ICMPV4_REDIRECT 5 -#define ICMPV4_TIMESTAMP 13 -#define ICMPV4_TIMESTAMP_REPLY 14 -#define ICMPV4_INFO_REQUEST 15 -#define ICMPV4_INFO_REPLY 16 -#define ICMPV4_ADDR_MASK_REQUEST 17 -#define ICMPV4_ADDR_MASK_REPLY 18 - -typedef struct icmp_v6_s { - - u8 type; - u8 code; - u16 checksum; - - u32 data[0]; -} icmp_v6_t; - -typedef struct pseudo_v6_header { - u32 src_addr[4]; - u32 dst_addr[4]; - u16 payload_length; - u16 next_header; -} pseudo_v6_header_t; - - -#define ICMPV6_ECHO 128 -#define ICMPV6_ECHO_REPLY 129 -#define ICMPV6_PKT_TOO_BIG 2 -#define ICMPV6_TIMEEXCEEDED 3 -#define ICMPV6_TIMTTL 0 -#define ICMPV6_PARAMETER_PROBLEM 4 -#define ICMPV6_UNREACHABLE 1 -#define ICMPV6_NEIGHBOR_SOLICITAION 135 -#define ICMPV6_NEIGHBOR_ADVT 136 -/* ICMP V6 generated packet size */ -#define ICMPV6_ERR_SIZE 48 -#define ICMPV6_HDR_SIZE (sizeof(icmp_v6_t) +sizeof(u32)) - -/* Code for Type 1 */ -#define ICMPV6_UNRDESTN 0 /* Code: No route to Desnt */ -#define ICMPV6_ADM_PROH 1 /* Code: Adminitrative Prohibited */ -#define ICMPV6_SRC_ADD_SCOPE 2 /* Code: Source Address beyond scope */ -#define ICMPV6_UNRHOST 3 /* Code: Host Unreachable */ -#define ICMPV6_UNRPORT 4 /* Code: Port UnReachable */ - -#define ICMPV6_UNRPROT 1 /* type 4 - Code: No route to Desnt */ - -#define ICMPV6_PTB_CODE 0 /* Code: For PTB */ -#define ICMPV6_PARAM_CODE 0 /* Code: For Parameter Problem */ -#define ICMPV6_UNREC_HDR 1 /* Code: For Parameter Problem */ -#define ICMPV6_SRC_ADD_FAIL 5 /* Code: For Source address failed */ -#define ICMP_ECHO_REPLY_CODE 0 -#define DEFAULT_TTL_HOPLIMIT_VAL 64 - -typedef struct pptp_hdr_type { - - u16 flags_ver; - u16 proto_type; /* PPP = 0x880B */ - u16 payload_len; - u16 call_id; - u32 seq_no; - u32 ack_no; - -} pptp_hdr_type_t; - -/* - * NAME - * - * tcp_findoption - * - * SYNOPSIS - * u8* tcp_findoption (tcp_hdr_t *tcp, uchar option) - * - * PARAMETERS - * tcp - pointer to TCP header - * option - TCP option - * - * RETURNS - * This function returns a pointer to the option found, - * otherwise returns null. - * - * - * DESCRIPTION - * This function searches the option and returns a pointer to the - * matched option field containing option kind/length/data sub-fields. - * - */ -static inline u8* tcp_findoption (tcp_hdr_type *tcp, u8 option) -{ - u8*data; - u8 len, optlen; - - data = tcp->option_data; - len = ((tcp->hdr_len>>4) << 2) - sizeof(tcp_hdr_type); - -#define MAXTCPOPTIONBYTES 40 -#define MINTCPOPTIONLENGTH 2 - - while (len) { - if (PREDICT_TRUE(option == data[0])) { - return (data); - } else { - switch (data[0]) { - case TCP_END_OPTIONS_LIST: - return (NULL); - case TCP_OPTION_NOP: - len -= 1; - data += 1; - break; - default: - /* Sanity check the length. */ - optlen = data[1]; - if ((optlen < MINTCPOPTIONLENGTH) || - (optlen > MAXTCPOPTIONBYTES) || - (optlen > len)) { - return (NULL); - } - len -= optlen; - data += optlen; - break; - } - } - } - - return (NULL); -} - - -static inline u32 crc_calc (ipv4_header *ipv4) -{ - u16 *ipv4_word_ptr = (u16 *) ipv4; - u32 crc32; - /* - * Add all fields except the checksum field - */ - crc32 = (u32)clib_net_to_host_u16(*ipv4_word_ptr) + - (u32)clib_net_to_host_u16(*(ipv4_word_ptr + 1)) + - (u32)clib_net_to_host_u16(*(ipv4_word_ptr + 2)) + - (u32)clib_net_to_host_u16(*(ipv4_word_ptr + 3)) + - (u32)clib_net_to_host_u16(*(ipv4_word_ptr + 4)) + - (u32)clib_net_to_host_u16(*(ipv4_word_ptr + 6)) + - (u32)clib_net_to_host_u16(*(ipv4_word_ptr + 7)) + - (u32)clib_net_to_host_u16(*(ipv4_word_ptr + 8)) + - (u32)clib_net_to_host_u16(*(ipv4_word_ptr + 9)); - - /* Add in the carry of the original sum */ - crc32 = (crc32 & 0xFFFF) + (crc32 >> 16); - /* Add in the carry of the final sum */ - crc32 = (crc32 & 0xFFFF) + (crc32 >> 16); - - return crc32; -} - -#endif /* __TCP_HEADER_DEFINITIONS_H__ */ diff --git a/plugins/vcgn-plugin/vcgn/vcgn_classify.c b/plugins/vcgn-plugin/vcgn/vcgn_classify.c deleted file mode 100644 index b9917df6..00000000 --- a/plugins/vcgn-plugin/vcgn/vcgn_classify.c +++ /dev/null @@ -1,1508 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "cnat_db.h" -#include "cnat_global.h" -#include "cnat_cli.h" -#include "cnat_config.h" -#include "cnat_logging.h" -#include "cnat_config_api.h" -#include "cnat_show_api.h" -#include "cnat_show_response.h" -#include "cnat_ipv4_udp.h" -#include "cnat_common_api.h" - -#include - -typedef struct { - u32 cached_next_index; - - /* inside, outside interface handles */ - u32 * inside_sw_if_index_table; - u32 * outside_sw_if_index_table; - - /* convenience variables */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; - u8 cnat_db_initalized; -} vcgn_classify_main_t; - -typedef struct { - /* $$$$ fill in with per-pkt trace data */ - u32 next_index; - u32 sw_if_index; - u32 orig_dst_address; - u16 orig_dst_port; -} vcgn_classify_trace_t; - -#define FIND_MY_VRF_USING_I_VRF_ID \ - my_vrfmap_found = 0; \ - pool_foreach (my_vrfmap, cnat_map_by_vrf, ({ \ - if (my_vrfmap->i_vrf_id == i_vrf_id) { \ - my_vrfmap_found = 1; \ - my_vrfmap_temp = my_vrfmap; \ - break; \ - } \ - })); - - -/* packet trace format function */ -static u8 * format_swap_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 *); - vcgn_classify_trace_t * t = va_arg (*args, vcgn_classify_trace_t *); - - s = format (s, "VCGN_CLASSIFY: dst %U dst_port %d sw_if_index %d next %d", - format_ip4_address, (ip4_header_t *) &t->orig_dst_address, - clib_net_to_host_u16(t->orig_dst_port), - t->sw_if_index, t->next_index); - return s; -} - -vcgn_classify_main_t vcgn_classify_main; - -vlib_node_registration_t vcgn_classify_node; - -#define foreach_vcgn_classify_error \ -_(PACKETS_RECEIVED, "total packets received") \ -_(V4_PACKETS_PROCESSED, "ipv4 packets processed for vCGN") \ -_(V4_PACKETS_PUNTED, "ipv4 packets punted") \ -_(V6_PACKETS_PUNTED, "ipv6 packets punted") \ -_(MPLS_PACKETS_PUNTED, "mpls unicast packets punted") \ -_(ETH_PACKETS_PUNTED, "ethernet packets punted") - - -typedef enum { -#define _(sym,str) VCGN_CLASSIFY_ERROR_##sym, - foreach_vcgn_classify_error -#undef _ - VCGN_CLASSIFY_N_ERROR, -} vcgn_classify_error_t; - -static char * vcgn_classify_error_strings[] = { -#define _(sym,string) string, - foreach_vcgn_classify_error -#undef _ -}; - -/* - * To drop a pkt and increment one of the previous counters: - * - * set b0->error = error_node->errors[VCGN_CLASSIFY_ERROR_EXAMPLE]; - * set next0 to a disposition index bound to "error-drop". - * - * To manually increment the specific counter VCGN_CLASSIFY_ERROR_EXAMPLE: - * - * vlib_node_t *n = vlib_get_node (vm, vcgn_classify.index); - * u32 node_counter_base_index = n->error_heap_index; - * vlib_error_main_t * em = &vm->error_main; - * em->counters[node_counter_base_index + VCGN_CLASSIFY_ERROR_EXAMPLE] += 1; - * - */ - -typedef enum { - VCGN_CLASSIFY_NEXT_IP4_INPUT, - VCGN_CLASSIFY_NEXT_IP6_INPUT, - VCGN_CLASSIFY_NEXT_MPLS_INPUT, - VCGN_CLASSIFY_NEXT_ETHERNET_INPUT, - VCGN_CLASSIFY_NEXT_UDP_INSIDE, - VCGN_CLASSIFY_NEXT_UDP_OUTSIDE, - VCGN_CLASSIFY_NEXT_TCP_INSIDE, - VCGN_CLASSIFY_NEXT_TCP_OUTSIDE, - VCGN_CLASSIFY_NEXT_ICMP_Q_INSIDE, - VCGN_CLASSIFY_NEXT_ICMP_Q_OUTSIDE, - VCGN_CLASSIFY_NEXT_ICMP_E_INSIDE, - VCGN_CLASSIFY_NEXT_ICMP_E_OUTSIDE, - VCGN_CLASSIFY_N_NEXT, -} vcgn_classify_next_t; - -static uword -vcgn_classify_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - u32 n_left_from, * from, * to_next; - vcgn_classify_next_t next_index; - vcgn_classify_main_t * vcm = &vcgn_classify_main; - vlib_node_t *n = vlib_get_node (vm, vcgn_classify_node.index); - u32 node_counter_base_index = n->error_heap_index; - vlib_error_main_t * em = &vm->error_main; - u16 *l3_type; - int counter; - - 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); - - #if 0 - while (n_left_from >= 4 && n_left_to_next >= 2) - { - u32 bi0, bi1; - vlib_buffer_t * b0, * b1; - u32 next0, next1; - u32 sw_if_index0, sw_if_index1; - - /* 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); - - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - next0 = vcm->cached_next_index; - sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX]; - next1 = vcm->cached_next_index; - - /* $$$$ your message in this space. Process 2 x pkts */ - em->counters[node_counter_base_index + VCGN_CLASSIFY_ERROR_PACKETS_RECEIVED] += 2; - - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE))) - { - if (b0->flags & VLIB_BUFFER_IS_TRACED) - { - vcgn_classify_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) - { - vcgn_classify_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); - } - #endif /* if 0 */ - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t * b0; - u32 next0; - u32 sw_if_index0; - ip4_header_t * h0; - //ipv4_header *h0; - ethernet_header_t *eth0; - icmp_v4_t *icmp; - u8 icmp_type; - u8 ipv4_hdr_len; - - /* 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); - - eth0 = (ethernet_header_t *) vlib_buffer_get_current(b0); - u16 *etype = ð0->type; - - /* vlan tag 0x8100 */ - if (*etype == clib_host_to_net_u16(ETHERNET_TYPE_VLAN)) { - l3_type = (etype + 1); /* Skip 2 bytes of vlan id */ - vlib_buffer_advance(b0, 18); - } else { - l3_type = etype; - vlib_buffer_advance(b0, 14); - } - /* Handling v4 pkts 0x800 */ - if (*l3_type == clib_host_to_net_u16(ETHERNET_TYPE_IP4)) { - - h0 = vlib_buffer_get_current (b0); - - u8 protocol_type = h0->protocol; - - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - next0 = VCGN_CLASSIFY_NEXT_IP4_INPUT; - counter = VCGN_CLASSIFY_ERROR_V4_PACKETS_PROCESSED; - - if (protocol_type == 0x11) { /* UDP# 17 */ - next0 = (sw_if_index0 < vec_len(vcm->inside_sw_if_index_table) && - vcm->inside_sw_if_index_table[sw_if_index0] != EMPTY) ? - VCGN_CLASSIFY_NEXT_UDP_INSIDE : next0; - - next0 = (sw_if_index0 < vec_len(vcm->outside_sw_if_index_table) && - vcm->outside_sw_if_index_table[sw_if_index0] != EMPTY) ? - VCGN_CLASSIFY_NEXT_UDP_OUTSIDE : next0; - - } else if (protocol_type == 0x06) { /* TCP# 6 */ - next0 = (sw_if_index0 < vec_len(vcm->inside_sw_if_index_table) && - vcm->inside_sw_if_index_table[sw_if_index0] != EMPTY) ? - VCGN_CLASSIFY_NEXT_TCP_INSIDE : next0; - - next0 = (sw_if_index0 < vec_len(vcm->outside_sw_if_index_table) && - vcm->outside_sw_if_index_table[sw_if_index0] != EMPTY) ? - VCGN_CLASSIFY_NEXT_TCP_OUTSIDE : next0; - - } else if (protocol_type == 0x01) { /* ICMP # 1 */ - - ipv4_hdr_len = (h0->ip_version_and_header_length & 0xf) << 2; - icmp = (icmp_v4_t *)((u8*)h0 + ipv4_hdr_len); - icmp_type = icmp->type; - - if ((icmp_type == ICMPV4_ECHO) || - (icmp_type == ICMPV4_ECHOREPLY)) { - next0 = (sw_if_index0 < vec_len(vcm->inside_sw_if_index_table) && - vcm->inside_sw_if_index_table[sw_if_index0] != EMPTY) ? - VCGN_CLASSIFY_NEXT_ICMP_Q_INSIDE : next0; - - next0 = (sw_if_index0 < vec_len(vcm->outside_sw_if_index_table) && - vcm->outside_sw_if_index_table[sw_if_index0] != EMPTY) ? - VCGN_CLASSIFY_NEXT_ICMP_Q_OUTSIDE : next0; - - } else { - next0 = (sw_if_index0 < vec_len(vcm->inside_sw_if_index_table) && - vcm->inside_sw_if_index_table[sw_if_index0] != EMPTY) ? - VCGN_CLASSIFY_NEXT_ICMP_E_INSIDE : next0; - - next0 = (sw_if_index0 < vec_len(vcm->outside_sw_if_index_table) && - vcm->outside_sw_if_index_table[sw_if_index0] != EMPTY) ? - VCGN_CLASSIFY_NEXT_ICMP_E_OUTSIDE : next0; - } - } else { - /* cannot do NATting with this L4 protocol */ - counter = VCGN_CLASSIFY_ERROR_V4_PACKETS_PUNTED; - } - - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) { - udp_header_t * u0 = (udp_header_t *)(h0+1); - vcgn_classify_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - t->next_index = next0; - t->orig_dst_address = h0->dst_address.as_u32; - t->orig_dst_port = u0->dst_port; - } - - } else if (*l3_type == clib_host_to_net_u16(ETHERNET_TYPE_IP6)) { - - /* IPv6 0x86DD */ - next0 = VCGN_CLASSIFY_NEXT_IP6_INPUT; - counter = VCGN_CLASSIFY_ERROR_V6_PACKETS_PUNTED; - - } else if (*l3_type == - clib_host_to_net_u16(ETHERNET_TYPE_MPLS_UNICAST)) { - - /* MPLS unicast 0x8847 */ - next0 = VCGN_CLASSIFY_NEXT_MPLS_INPUT; - counter = VCGN_CLASSIFY_ERROR_MPLS_PACKETS_PUNTED; - } else { /* Remaining all should be pushed to "ethernet-input" */ - - next0 = VCGN_CLASSIFY_NEXT_ETHERNET_INPUT; - counter = VCGN_CLASSIFY_ERROR_ETH_PACKETS_PUNTED; - } - - em->counters[node_counter_base_index + counter] += 1; - em->counters[node_counter_base_index + - VCGN_CLASSIFY_ERROR_PACKETS_RECEIVED] += 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); - } - - return frame->n_vectors; -} - -VLIB_REGISTER_NODE (vcgn_classify_node) = { - .function = vcgn_classify_node_fn, - .name = "vcgn-classify", - .vector_size = sizeof (u32), - .format_trace = format_swap_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(vcgn_classify_error_strings), - .error_strings = vcgn_classify_error_strings, - - .n_next_nodes = VCGN_CLASSIFY_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [VCGN_CLASSIFY_NEXT_IP4_INPUT] = "ip4-input", - [VCGN_CLASSIFY_NEXT_IP6_INPUT] = "ip6-input", - [VCGN_CLASSIFY_NEXT_MPLS_INPUT] = "mpls-input", - [VCGN_CLASSIFY_NEXT_ETHERNET_INPUT] = "ethernet-input", - [VCGN_CLASSIFY_NEXT_UDP_INSIDE] = "vcgn-v4-udp-i2o", - [VCGN_CLASSIFY_NEXT_UDP_OUTSIDE] = "vcgn-v4-udp-o2i", - [VCGN_CLASSIFY_NEXT_TCP_INSIDE] = "vcgn-v4-tcp-i2o", - [VCGN_CLASSIFY_NEXT_TCP_OUTSIDE] = "vcgn-v4-tcp-o2i", - [VCGN_CLASSIFY_NEXT_ICMP_Q_INSIDE] = "vcgn-v4-icmp-q-i2o", - [VCGN_CLASSIFY_NEXT_ICMP_Q_OUTSIDE] = "vcgn-v4-icmp-q-o2i", - [VCGN_CLASSIFY_NEXT_ICMP_E_INSIDE] = "vcgn-v4-icmp-e-i2o", - [VCGN_CLASSIFY_NEXT_ICMP_E_OUTSIDE] = "vcgn-v4-icmp-e-o2i" - }, -}; - - -/* A test function to init the vrf map */ - -clib_error_t *vcgn_classify_init (vlib_main_t *vm) -{ - vcgn_classify_main_t * mp = &vcgn_classify_main; - - mp->vlib_main = vm; - mp->vnet_main = vnet_get_main(); - u32 inside_sw_if_index = 1; - u32 outside_sw_if_index = 0; - - vec_validate_init_empty (mp->inside_sw_if_index_table, - inside_sw_if_index + 1, EMPTY); - vec_validate_init_empty (mp->outside_sw_if_index_table, - outside_sw_if_index + 1, EMPTY); - - /* - * inside_sw_if_index cell of the table stores outside_sw_if_index - * and vice versa. This is ensurs pair of indices being remembered - * using one mem-location. - */ - mp->inside_sw_if_index_table[inside_sw_if_index] = outside_sw_if_index; - mp->outside_sw_if_index_table[outside_sw_if_index] = inside_sw_if_index; - -#if DPDK==1 - dpdk_set_next_node (DPDK_RX_NEXT_IP4_INPUT, "vcgn-classify"); -#endif - - { - pg_node_t * pn; - pn = pg_get_node (vcgn_classify_node.index); - pn->unformat_edit = unformat_pg_ip4_header; - } - return 0; -} - -VLIB_INIT_FUNCTION (vcgn_classify_init); - -/* Show command handlers */ -static clib_error_t * -show_vcgn_stats_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - if (cnat_db_init_done) { - cnat_nat44_handle_show_stats(vm); - } else { - vlib_cli_output(vm, "vCGN is not configured !!\n"); - } - return 0; -} - - -static clib_error_t * -show_vcgn_config_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - cnat_nat44_handle_show_config(vm); - return 0; -} - -static clib_error_t * -show_vcgn_inside_translation_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - vnet_main_t * vnm = vnet_get_main(); - vcgn_classify_main_t * vcm = &vcgn_classify_main; - spp_api_cnat_v4_show_inside_entry_req_t inside_req; - u8 *proto; - ip4_address_t inside_addr; - u32 start_port = 1; - u32 end_port = 65535; - u32 inside_sw_if_index = EMPTY; - - inside_req.start_port = start_port; - inside_req.end_port = end_port; - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { - if (unformat(input, "protocol %s", &proto)) { - if (!strncmp((char *) proto, "udp", 3)) { - inside_req.protocol = 1; - } else if (!strncmp((char *) proto, "tcp", 3)) { - inside_req.protocol = 2; - } else { - inside_req.protocol = 3; - } - } else if (unformat (input, "interface %U", - unformat_vnet_sw_interface, vnm, &inside_sw_if_index)) { - if (inside_sw_if_index > vec_len(vcm->inside_sw_if_index_table) || - vcm->inside_sw_if_index_table[inside_sw_if_index] == EMPTY) { - return clib_error_return (0, "Could not find the inside interface"); - } - } else if (unformat (input, "inside-addr %U", - unformat_ip4_address, &inside_addr)) { - inside_req.ipv4_addr = clib_net_to_host_u32(inside_addr.as_u32); - } else if (unformat(input, "start-port %u", &start_port)) { - inside_req.start_port = start_port; - } else if (unformat(input, "end-port %u", &end_port)) { - inside_req.end_port = end_port; - } else { break;} - } - inside_req.vrf_id = inside_sw_if_index; - inside_req.flags |= CNAT_TRANSLATION_ENTRY_DYNAMIC; /* as of now only dynamic */ - inside_req.all_entries = 0; /* we can see it later */ -#if DEBUG - vlib_cli_output(vm, "proto %d, inside-addr 0x%x, start_port %u, " - "end_port %u, vrf 0x%x\n", - inside_req.protocol, - inside_req.ipv4_addr, - inside_req.start_port, - inside_req.end_port, - inside_sw_if_index); -#endif - if (cnat_db_init_done) { - cnat_v4_show_inside_entry_req_t_handler(&inside_req, vm); - } else { - vlib_cli_output(vm, "vCGN is not configured !!\n"); - } - return 0; -} - - -static clib_error_t * -show_vcgn_outside_translation_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - void cnat_v4_show_outside_entry_req_t_handler - (spp_api_cnat_v4_show_outside_entry_req_t *mp, vlib_main_t *vm); - vnet_main_t * vnm = vnet_get_main(); - vcgn_classify_main_t * vcm = &vcgn_classify_main; - spp_api_cnat_v4_show_outside_entry_req_t outside_req; - u8 *proto; - ip4_address_t outside_addr; - u32 start_port = 1; - u32 end_port = 65535; - u32 outside_sw_if_index = EMPTY; - - - outside_req.start_port = start_port; - outside_req.end_port = end_port; - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { - if (unformat(input, "protocol %s", &proto)) { - if (!strncmp((char *) proto, "udp", 3)) { - outside_req.protocol = 1; - } else if (!strncmp((char *) proto, "tcp", 3)) { - outside_req.protocol = 2; - } else { - outside_req.protocol = 3; - } - } else if (unformat (input, "interface %U", - unformat_vnet_sw_interface, vnm, &outside_sw_if_index)) { - if (outside_sw_if_index > vec_len(vcm->outside_sw_if_index_table) || - vcm->outside_sw_if_index_table[outside_sw_if_index] == EMPTY) { - return clib_error_return (0, "Could not find the outside interface"); - } - } else if (unformat (input, "outside-addr %U", - unformat_ip4_address, &outside_addr)) { - outside_req.ipv4_addr = clib_net_to_host_u32(outside_addr.as_u32); - } else if (unformat(input, "start-port %u", &start_port)) { - outside_req.start_port = start_port; - } else if (unformat(input, "end-port %u", &end_port)) { - outside_req.end_port = end_port; - } else { break;} - } - outside_req.vrf_id = outside_sw_if_index; - outside_req.flags |= CNAT_TRANSLATION_ENTRY_DYNAMIC; /* as of now only dynamic */ -#if DEBUG - vlib_cli_output(vm, "proto %d, outside-addr 0x%x, start_port %u, " - "end_port %u, vrf 0x%x\n", - outside_req.protocol, - outside_req.ipv4_addr, - outside_req.start_port, - outside_req.end_port, - outside_sw_if_index); -#endif - if (cnat_db_init_done) { - cnat_v4_show_outside_entry_req_t_handler(&outside_req, vm); - } else { - vlib_cli_output(vm, "vCGN is not configured !!\n"); - } - return 0; -} - - -/* Config command handlers */ -static clib_error_t * -set_vcgn_inside_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - vnet_main_t * vnm = vnet_get_main(); - vcgn_classify_main_t * vcm = &vcgn_classify_main; - u32 inside_sw_if_index = 1; - u32 outside_sw_if_index = ~0; - void cnat_db_v2_init (void ); - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { - if (unformat(input, "%U", - unformat_vnet_sw_interface, vnm, &inside_sw_if_index)) - ; - else if (unformat(input, "outside %U", - unformat_vnet_sw_interface, vnm, &outside_sw_if_index)) - ; - else break; - } - if (inside_sw_if_index == ~0 || - outside_sw_if_index == ~0) - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); - - if (inside_sw_if_index == outside_sw_if_index) - return clib_error_return (0, "inside and outside interfaces can't be the same..."); - - /* - * Initialize in/out sw_if_index table. Could use - * non-indexed table to reduce memory. However, this - * is consulted in vcgn_classify for every packet. - * Therefore, table is indexed by sw_if_index. - */ - vec_validate_init_empty (vcm->inside_sw_if_index_table, - inside_sw_if_index + 1, EMPTY); - vec_validate_init_empty (vcm->outside_sw_if_index_table, - outside_sw_if_index + 1, EMPTY); - - /* - * inside_sw_if_index cell of the table stores outside_sw_if_index - * and vice versa. This is ensurs pair of indices being remembered - * using one mem-location. - */ - vcm->inside_sw_if_index_table[inside_sw_if_index] = outside_sw_if_index; - vcm->outside_sw_if_index_table[outside_sw_if_index] = inside_sw_if_index; - - if (! vcm->cnat_db_initalized) { - int i; - cnat_db_v2_init(); - - for (i = 0; i < CNAT_MAX_VRFMAP_ENTRIES; i++) { - vrf_map_array[i] = VRF_MAP_ENTRY_EMPTY; - } - /* Turn on the db scanner process */ - cnat_scanner_db_process_turn_on(vm); - vcm->cnat_db_initalized = 1; - } - return 0; -} - -static clib_error_t * -set_vcgn_map_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - vnet_main_t * vnm = vnet_get_main(); - vcgn_classify_main_t * vcm = &vcgn_classify_main; - ip4_address_t lo, hi; - spp_api_cnat_v4_add_vrf_map_t map; - u32 inside_sw_if_index = EMPTY; - u32 outside_sw_if_index; - - vnet_hw_interface_t *inside_hw_if_index = NULL; - vnet_hw_interface_t *outside_hw_if_index = NULL; - - if (! unformat(input, "inside %U", - unformat_vnet_sw_interface, vnm, &inside_sw_if_index)) - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); - - if (!unformat (input, "%U", unformat_ip4_address, &lo)) - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); - - if (unformat (input, "- %U", unformat_ip4_address, &hi)) - ; - - /* $$$$ remember to set i_vrf, i_vrf_id as needed */ - - /* Fill the structure spp_api_cnat_v4_add_vrf_map_t & let this API handle it */ - /* i_vrf_id & o_vrf_id are 32-bit & i_vrf, o_vrf are 16 bit */ - - if (inside_sw_if_index > vec_len(vcm->inside_sw_if_index_table) || - vcm->inside_sw_if_index_table[inside_sw_if_index] == EMPTY) { - return clib_error_return (0, "Could not find the inside interface"); - } - outside_sw_if_index = vcm->inside_sw_if_index_table[inside_sw_if_index]; - - map.i_vrf_id = inside_sw_if_index; - map.o_vrf_id = outside_sw_if_index; - map.i_vrf = inside_sw_if_index; - map.o_vrf = outside_sw_if_index; - - map.start_addr[0] = clib_net_to_host_u32(lo.as_u32); - map.end_addr[0] = clib_net_to_host_u32(hi.as_u32); - - cnat_nat44_add_vrf_map_t_handler(&map, vm); - -#if 1 - inside_hw_if_index = vnet_get_sup_hw_interface(vcm->vnet_main, inside_sw_if_index); - if (inside_hw_if_index) { - vnet_hw_interface_rx_redirect_to_node(vcm->vnet_main, - inside_hw_if_index->hw_if_index, vcgn_classify_node.index); - } - outside_hw_if_index = vnet_get_sup_hw_interface(vcm->vnet_main, outside_sw_if_index); - if (outside_hw_if_index) { - vnet_hw_interface_rx_redirect_to_node(vcm->vnet_main, - outside_hw_if_index->hw_if_index, vcgn_classify_node.index); - } -#endif - return 0; -} - -static clib_error_t * -set_vcgn_tcp_timeout_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - /* - vnet_main_t * vnm = vnet_get_main(); - vcgn_classify_main_t * vcm = &vcgn_classify_main; - */ - u32 act_timeout = 0; - u32 init_timeout = 0; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { - if (unformat(input, "active %u", &act_timeout)) - tcp_active_timeout = act_timeout; - else if (unformat(input, "init %u", &init_timeout)) - tcp_initial_setup_timeout = init_timeout; - else break; - } - return 0; -} - -static clib_error_t * -set_vcgn_udp_timeout_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - /* - vnet_main_t * vnm = vnet_get_main(); - vcgn_classify_main_t * vcm = &vcgn_classify_main; - */ - u32 act_timeout = 0; - u32 init_timeout = 0; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { - if (unformat(input, "active %u", &act_timeout)) - udp_act_session_timeout = act_timeout; - else if (unformat(input, "init %u", &init_timeout)) - udp_init_session_timeout = init_timeout; - else break; - } - return 0; -} - - -static clib_error_t * -set_vcgn_icmp_timeout_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - /* - * vnet_main_t * vnm = vnet_get_main(); - * vcgn_classify_main_t * vcm = &vcgn_classify_main; - */ - u32 timeout = 0; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { - if (unformat(input, "%u", &timeout)) - ; - else break; - } - icmp_session_timeout = timeout; - return 0; -} - - -static clib_error_t * -set_vcgn_protocol_default_timeout_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - /* - vnet_main_t * vnm = vnet_get_main(); - vcgn_classify_main_t * vcm = &vcgn_classify_main; - */ - u8 *protocol; - u8 reset = 1; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { - if (unformat(input, "%s", &protocol)) - ; - else break; - } - cnat_nat44_set_protocol_timeout_value(0, 0, protocol, reset, vm); - return 0; -} - -static clib_error_t * -set_vcgn_dynamic_port_start_range_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - /* - vnet_main_t * vnm = vnet_get_main(); - vcgn_classify_main_t * vcm = &vcgn_classify_main; - */ - u32 port = 0; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { - if (unformat(input, "%u", &port)) - ; - else break; - } - if (port != 0 && port > 65535) { - vlib_cli_output(vm, "Error !! Invalid port\n"); - } else { - cnat_static_port_range = port; - vlib_cli_output(vm, "Dynamic Port Range Config Successful !!\n"); - } - return 0; -} - -static clib_error_t * -set_vcgn_port_limit_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - /* - vnet_main_t * vnm = vnet_get_main(); - vcgn_classify_main_t * vcm = &vcgn_classify_main; - */ - u32 port = 0; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { - if (unformat(input, "%u", &port)) - ; - else break; - } - if (port != 0 && port > 65535) { - vlib_cli_output(vm, "Error !! Invalid port\n"); - } else { - cnat_main_db_max_ports_per_user = port; - vlib_cli_output(vm, "Port Limit Config Successful !!\n"); - } - return 0; -} - -static inline void nfv9_init_pkt_sent_data(cnat_nfv9_logging_info_t *nfv9_info) -{ - nfv9_server_info_t *server = nfv9_server_info_pool + - nfv9_info->server_index; - - /* - * Reset the pkts_since_last_template and sent_time - * so that template will be sent next time - */ - server->last_template_sent_time = 0; - server->pkts_since_last_template = 0xffffffff; -} - -static inline u16 nfv9_get_max_length_minus_max_record_size(u16 path_mtu) -{ - u16 max_length_minus_max_record_size; - if(!path_mtu) /* Use default */ - path_mtu = NFV9_DEF_PATH_MTU; - - max_length_minus_max_record_size = path_mtu - - CNAT_NFV9_DATAFLOW_RECORD_HEADER_LENGTH - - NFV9_PAD_VALUE - - CNAT_NFV9_MAX_SINGLE_RECORD_LENGTH; /* Note.. as of now this record - * requires max number of bytes. If you add more records, - * this needs to be re-checked */ - if (max_length_minus_max_record_size < CNAT_NFV9_MIN_RECORD_SIZE) { - max_length_minus_max_record_size = CNAT_NFV9_MIN_RECORD_SIZE; - } - return max_length_minus_max_record_size; -} - -/* This function finds if the netflow server indicated by - * new_server_info is already configured for some other instance - * if yes, it returns the same pointer so that, info sent to the - * server is consistent. If the server is not found, a new instance - * is created and returned. If an existing server is used, its refernce - * count is incrimented (indicating the number of instances using the - * same server - */ - /* #define DEBUG_NF_SERVER_CONFIG 1 */ -static u16 nfv9_get_server_instance( - cnat_nfv9_logging_info_t *nfv9_info, nfv9_server_info_t *new_server_info) -{ - - /* Check if the instance has a server already and if yes, does it match */ - nfv9_server_info_t *server; - if(nfv9_info->server_index != EMPTY) { - server = nfv9_server_info_pool + nfv9_info->server_index; - - if((server->ipv4_address == new_server_info->ipv4_address) && - (server->port == new_server_info->port)) { - /* Same server.. just check if refresh rate/timeouts are reduced */ -#ifdef DEBUG_NF_SERVER_CONFIG - if(my_instance_number == 1) { - printf("\n Server match for %x and port %d\n", - new_server_info->ipv4_address, new_server_info->port); - } -#endif /* #ifdef DEBUG_NF_SERVER_CONFIG */ - goto adjust_refresh_rate; - } else { /* The server is being changed */ - server->ref_count--; -#ifdef DEBUG_NF_SERVER_CONFIG - if(my_instance_number == 1) { - printf("\n Server change from %x, %d to %x, %d" - "Ref count %d\n", - server->ipv4_address, - server->port, - new_server_info->ipv4_address, new_server_info->port, - server->ref_count); - } -#endif /* #ifdef DEBUG_NF_SERVER_CONFIG */ - if(!server->ref_count) { - /* Return this server to pool */ -#ifdef DEBUG_NF_SERVER_CONFIG - if(my_instance_number == 1) { - PLATFORM_DEBUG_PRINT("Deleting Server %x, %d at %d\n", - server->ipv4_address, - server->port, - nfv9_info->server_index); - } -#endif /* #ifdef DEBUG_NF_SERVER_CONFIG */ - pool_put(nfv9_server_info_pool, server); - } - } - } - - /* Now check if the server is already present in the pool */ - u8 found = 0; - server = 0; - pool_foreach (server, nfv9_server_info_pool, ({ - if ((server->ipv4_address == new_server_info->ipv4_address) && - (server->port == new_server_info->port)) { - server->ref_count++; - nfv9_info->server_index = server - nfv9_server_info_pool; - found = 1; -#ifdef DEBUG_NF_SERVER_CONFIG - if(my_instance_number == 1) { - printf("Re-using server %x, %d Ref count %d\n", - server->ipv4_address, server->port, server->ref_count); - } -#endif /* #ifdef DEBUG_NF_SERVER_CONFIG */ - break; - } - })); - - if(!found) { - /* Create a new one, initialize and return */ - server = 0; - pool_get(nfv9_server_info_pool, server); - clib_memcpy(server, new_server_info, sizeof(nfv9_server_info_t)); - server->ref_count = 1; - nfv9_info->server_index = server - nfv9_server_info_pool; -#ifdef DEBUG_NF_SERVER_CONFIG - if(my_instance_number == 1) { - printf("Create new server for at %d %x and port %d\n", - nfv9_info->server_index, - new_server_info->ipv4_address, new_server_info->port); - } -#endif /* #ifdef DEBUG_NF_SERVER_CONFIG */ - return CNAT_SUCCESS; - } - -adjust_refresh_rate: - if(server->refresh_rate > - new_server_info->refresh_rate) { - server->refresh_rate = - new_server_info->refresh_rate; -#ifdef DEBUG_NF_SERVER_CONFIG - if(my_instance_number == 1) { - printf("Reset refresh rate to %d\n", - server->refresh_rate); - } -#endif /* #ifdef DEBUG_NF_SERVER_CONFIG */ - } - - if(server->timeout_rate > - new_server_info->timeout_rate) { - server->timeout_rate = - new_server_info->timeout_rate; -#ifdef DEBUG_NF_SERVER_CONFIG - if(my_instance_number == 1) { - printf("Reset timeout rate to %d\n", - server->timeout_rate); - } -#endif /* #ifdef DEBUG_NF_SERVER_CONFIG */ - } - - return CNAT_SUCCESS; -} -static clib_error_t * -set_vcgn_nfv9_logging_cofig_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - vcgn_classify_main_t * vcm = &vcgn_classify_main; - spp_api_cnat_v4_config_nfv9_logging_t nfv9_conf; - ip4_address_t server_addr; - u32 ip_addr = 0; - u32 port; - u32 refresh_rate = 0; - u32 timeout = 0; - u32 pmtu = 0; - u8 enable = 1; -/* vcgn changes start*/ - cnat_nfv9_logging_info_t *my_nfv9_logging_info = NULL; - cnat_nfv9_logging_info_t *my_nfv9_logging_info_tmp = NULL; - cnat_vrfmap_t *my_vrfmap = 0, *my_vrfmap_temp = 0; - u16 i_vrf = ~0; - u32 i_vrf_id = ~0; - u8 found; - u32 inside_sw_if_index = EMPTY; - /* - * Init NFv9 logging info as needed, this will be done only once - */ - cnat_nfv9_logging_init(); - - found = 0; - -/* vcgn changes end*/ - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { - if (unformat (input, "inside %U", - unformat_vnet_sw_interface, &inside_sw_if_index)) { - /* Do nothing */ - } else if (unformat (input, "server %U", unformat_ip4_address, &server_addr)) - ip_addr = clib_net_to_host_u32(server_addr.as_u32); - else if (unformat(input, "port %u", &port)) - ; - else if (unformat(input, "refresh-rate %u", &refresh_rate)) - ; - else if (unformat(input, "timeout %u", &timeout)) - ; - else if (unformat(input, "pmtu %u", &pmtu)) - ; - else if (unformat(input, "del")) - enable = 0; - else break; - } - - if (inside_sw_if_index > vec_len(vcm->inside_sw_if_index_table) || - vcm->inside_sw_if_index_table[inside_sw_if_index] == EMPTY) { - return clib_error_return (0, "Could not find the inside interface"); - } - i_vrf = inside_sw_if_index; - i_vrf_id = inside_sw_if_index; - - #if 0 - vlib_cli_output(vm, "ip 0x%x, port %u, refresh %u, " - "timeout %u, pmtu %u enable %u\n", - ip_addr, port, refresh_rate, - timeout, pmtu, enable); - #endif - if (refresh_rate == 0) refresh_rate = 500; /* num of pkts */ - if (timeout == 0) timeout = 30; /* in mins */ - - nfv9_conf.enable = enable; - nfv9_conf.ipv4_address = ip_addr; - nfv9_conf.i_vrf_id = inside_sw_if_index; - nfv9_conf.i_vrf = inside_sw_if_index; - nfv9_conf.port = port; - nfv9_conf.refresh_rate = refresh_rate; - nfv9_conf.timeout_rate = timeout; - nfv9_conf.path_mtu = pmtu; - nfv9_conf.nfv9_global_collector = 0; - nfv9_conf.session_logging = 0; - - /* - * At this point the NFv9 global information should already be - * inited as we have called cnat_nfv9_logging_init() - */ - - if (nfv9_conf.nfv9_global_collector) { - if (cnat_nfv9_global_info.cnat_nfv9_global_collector_index != EMPTY) { - found = 1; - my_nfv9_logging_info = cnat_nfv9_logging_info_pool + - cnat_nfv9_global_info.cnat_nfv9_global_collector_index; - } - } else { - /* Do we already have a map for this VRF? */ - pool_foreach (my_nfv9_logging_info, cnat_nfv9_logging_info_pool, ({ - if (my_nfv9_logging_info->i_vrf_id == i_vrf_id) { - nfv9_server_info_t *server = nfv9_server_info_pool + - my_nfv9_logging_info->server_index; - if((server->ipv4_address == (nfv9_conf.ipv4_address)) && (server->port == (nfv9_conf.port))) { - found = 1; - my_nfv9_logging_info_tmp = my_nfv9_logging_info; - break; - } - } - })); - } - - if ((nfv9_conf.ipv4_address == 0) || - (nfv9_conf.port == 0)) { - vlib_cli_output(vm, - "Add NFv9 ivrf %d Logging Invalid values [IPv4 0x%x, PORT %d]\n", - i_vrf, - (nfv9_conf.ipv4_address), - (nfv9_conf.port)); - goto done; - } - - if (nfv9_conf.enable) { - if ((nfv9_conf.ipv4_address == 0) || - (nfv9_conf.port == 0)) { - nfv9_conf.rc = CNAT_ERR_PARSER; - vlib_cli_output(vm, - "NFV9_logging i_vrf %d, Invalid [v4_addr 0x%x port %d]\n", - i_vrf, - (nfv9_conf.ipv4_address), - (nfv9_conf.port)); - goto done; - } - - nfv9_server_info_t new_server_info; - memset(&new_server_info, 0, sizeof(nfv9_server_info_t)); - new_server_info.ipv4_address = - nfv9_conf.ipv4_address; - new_server_info.port = - (nfv9_conf.port); - new_server_info.refresh_rate = - (nfv9_conf.refresh_rate); - /* - * Store the timeout in seconds. User configures it in minutes - */ - new_server_info.timeout_rate = - 60*(nfv9_conf.timeout_rate); - if (found && my_nfv9_logging_info) { - /* - * Entry already present, change it - */ - my_nfv9_logging_info->max_length_minus_max_record_size = - nfv9_get_max_length_minus_max_record_size( - ((nfv9_conf.path_mtu))); - } else { - pool_get(cnat_nfv9_logging_info_pool, my_nfv9_logging_info); - memset(my_nfv9_logging_info, 0, sizeof(*my_nfv9_logging_info)); - my_nfv9_logging_info->server_index = EMPTY; - my_nfv9_logging_info->nfv9_logging_next_index = EMPTY; - /* - * Make the current and head logging context indeices as EMPTY. - * When first logging happens, these get set correctly - */ - my_nfv9_logging_info->current_logging_context = NULL; - my_nfv9_logging_info->queued_logging_context = NULL; -#if 0 - my_nfv9_logging_info->f = NULL; - my_nfv9_logging_info->to_next = NULL; - output_node = vlib_get_node_by_name (vm, (u8 *) "ip4-input"); - my_nfv9_logging_info->ip4_input_node_index = output_node->index; - printf("ip4_input_node_index %d\n", my_nfv9_logging_info->ip4_input_node_index); -#endif - my_nfv9_logging_info->i_vrf = i_vrf; - my_nfv9_logging_info->i_vrf_id = i_vrf_id; - my_nfv9_logging_info->max_length_minus_max_record_size = - nfv9_get_max_length_minus_max_record_size( - nfv9_conf.path_mtu); - - /* my_nfv9_logging_info will have a copy of logging_policy - * because, it is quite possible that nfv9 config arrives before - * the corresponding vrfmap is initialized. In such cases - * this copy will be used to update the vrfmap entry - */ - my_nfv9_logging_info->logging_policy = nfv9_conf.session_logging; - - if (nfv9_conf.nfv9_global_collector) { - cnat_nfv9_global_info.cnat_nfv9_global_collector_index = - my_nfv9_logging_info - cnat_nfv9_logging_info_pool; - - pool_foreach (my_vrfmap, cnat_map_by_vrf, ({ - if (my_vrfmap->nfv9_logging_index == EMPTY) { - my_vrfmap->nfv9_logging_index = - cnat_nfv9_global_info.cnat_nfv9_global_collector_index; - } - })); - } else { - u32 my_vrfmap_found = 0; - - FIND_MY_VRF_USING_I_VRF_ID - my_vrfmap = my_vrfmap_temp; - if (my_vrfmap_found) { - if(my_vrfmap->nfv9_logging_index == EMPTY) { - my_vrfmap->nfv9_logging_index = - my_nfv9_logging_info - cnat_nfv9_logging_info_pool; - // my_vrfmap->nf_logging_policy = mp->session_logging; - } else { - cnat_nfv9_logging_info_t *my_nfv9_logging_info_temp = cnat_nfv9_logging_info_pool + my_vrfmap->nfv9_logging_index; - while(my_nfv9_logging_info_temp->nfv9_logging_next_index != EMPTY){ - my_nfv9_logging_info_temp = cnat_nfv9_logging_info_pool + my_nfv9_logging_info_temp->nfv9_logging_next_index; - } - my_nfv9_logging_info_temp->nfv9_logging_next_index = my_nfv9_logging_info - cnat_nfv9_logging_info_pool; - } - } - } - } - - /* Update logging policy */ - my_nfv9_logging_info->logging_policy = nfv9_conf.session_logging; - if (nfv9_conf.nfv9_global_collector) { - if(PLATFORM_DBL_SUPPORT) { - pool_foreach (my_vrfmap, cnat_map_by_vrf, ({ - if (my_vrfmap->nfv9_logging_index == - cnat_nfv9_global_info.cnat_nfv9_global_collector_index) { - my_vrfmap->nf_logging_policy = nfv9_conf.session_logging; - } - })); - } else { - nfv9_conf.rc = CNAT_ERR_NO_SESSION_DB; - } - } else { - if(PLATFORM_DBL_SUPPORT) { - u32 my_vrfmap_found = 0; - my_vrfmap_temp = NULL; - FIND_MY_VRF_USING_I_VRF_ID - my_vrfmap = my_vrfmap_temp; - if (my_vrfmap_found) { - // my_vrfmap->nf_logging_policy = mp->session_logging; - } - } else { - nfv9_conf.rc = CNAT_ERR_NO_SESSION_DB; - } - } - u8 nfv9_logging_policy = 0; - u32 my_vrfmap_found = 0; - my_vrfmap_temp = NULL; - FIND_MY_VRF_USING_I_VRF_ID - my_vrfmap = my_vrfmap_temp; - if (my_vrfmap_found) { - u32 index_curr = my_vrfmap->nfv9_logging_index; - cnat_nfv9_logging_info_t *my_nfv9_logging_info_temp; - while(index_curr != EMPTY) { - my_nfv9_logging_info_temp = cnat_nfv9_logging_info_pool + index_curr; - nfv9_logging_policy = nfv9_logging_policy || my_nfv9_logging_info_temp->logging_policy; - index_curr = (cnat_nfv9_logging_info_pool + index_curr)->nfv9_logging_next_index; - } - my_vrfmap->nf_logging_policy = nfv9_logging_policy; - } - //vlib_cli_output(vm,"Netflow logging policy = %d\n", my_vrfmap->nf_logging_policy); - if(nfv9_get_server_instance(my_nfv9_logging_info, &new_server_info) - != CNAT_SUCCESS) { - vlib_cli_output(vm, "Error to get server instance"); - nfv9_conf.rc = CNAT_ERR_PARSER; - goto done; - } - nfv9_init_pkt_sent_data(my_nfv9_logging_info); - - vlib_cli_output(vm,"Adding NFv9 Logging Succeeded\n"); - nfv9_configured = 1; - - } else { - /*Delete path*/ - if (found) { - /* if found entry then we need to overwrite the my_nfv9_logging_info_tmp - * to my_nfv9_logging_info - */ - my_nfv9_logging_info = my_nfv9_logging_info_tmp; - if (i_vrf == INVALID_UIDX) { - /* - * We are deleting a global collector. Mark the collectors - * in those VRFs using the global collector - */ - pool_foreach (my_vrfmap, cnat_map_by_vrf, ({ - if (my_vrfmap->nfv9_logging_index == - cnat_nfv9_global_info.cnat_nfv9_global_collector_index) { - my_vrfmap->nfv9_logging_index = EMPTY; - } - })); - - cnat_nfv9_global_info.cnat_nfv9_global_collector_index = EMPTY; - } else { - u32 my_vrfmap_found = 0; - my_vrfmap_temp = NULL; - FIND_MY_VRF_USING_I_VRF_ID - my_vrfmap = my_vrfmap_temp; - if (my_vrfmap_found) { - // my_vrfmap->nfv9_logging_index = cnat_nfv9_global_info.cnat_nfv9_global_collector_index; - } - } - if (my_nfv9_logging_info->queued_logging_context || - my_nfv9_logging_info->current_logging_context) { - /* - * If there is a pending context: - * Set the deleted flag to 1. This will ensure - * that the logging info structure gets freed after any - * pending packet get sent - */ - my_nfv9_logging_info->deleted = 1; - } else { - /* - * No pending context, just free the logging info structure - */ - u32 index = my_nfv9_logging_info - cnat_nfv9_logging_info_pool; - if(index == my_vrfmap->nfv9_logging_index) { - /* Deleting the first sever */ - my_vrfmap->nfv9_logging_index = my_nfv9_logging_info->nfv9_logging_next_index; - /* if(my_nfv9_logging_info->nfv9_logging_next_index != EMPTY){ - my_vrfmap->nf_logging_policy = (cnat_nfv9_logging_info_pool + my_nfv9_logging_info->nfv9_logging_next_index)->logging_policy; - } else { - my_vrfmap->nf_logging_policy = EMPTY; - }*/ - } else { - u32 index_curr = my_vrfmap->nfv9_logging_index; - u32 index_prev = EMPTY; - while(index_curr != EMPTY) { - index_prev = index_curr; - index_curr = (cnat_nfv9_logging_info_pool + index_curr)->nfv9_logging_next_index; - if(index == index_curr) - { - (cnat_nfv9_logging_info_pool + index_prev)->nfv9_logging_next_index = (cnat_nfv9_logging_info_pool + index_curr)->nfv9_logging_next_index; - break; - } - } - } - nfv9_delete_server_info(my_nfv9_logging_info); - pool_put(cnat_nfv9_logging_info_pool, my_nfv9_logging_info); - } - - vlib_cli_output(vm, "Deleting NFv9 Logging Succeeded\n"); - /* - * Search across all vrf and check if nfv9 logging is configured. - */ - nfv9_configured = 0; - pool_foreach (my_nfv9_logging_info, cnat_nfv9_logging_info_pool, ({ - nfv9_configured = 1; - break; - })); - } else { - nfv9_conf.rc = CNAT_NO_CONFIG; - vlib_cli_output(vm, "Add NFv9 Logging Failed (2) Non Existent vrf %d\n", - i_vrf); - - } - u8 nfv9_logging_policy = 0; - u32 my_vrfmap_found = 0; - my_vrfmap_temp = NULL; - FIND_MY_VRF_USING_I_VRF_ID - my_vrfmap = my_vrfmap_temp; - if (my_vrfmap_found) { - u32 index_curr = my_vrfmap->nfv9_logging_index; - cnat_nfv9_logging_info_t *my_nfv9_logging_info_temp; - while(index_curr != EMPTY) { - my_nfv9_logging_info_temp = cnat_nfv9_logging_info_pool + index_curr; - nfv9_logging_policy = nfv9_logging_policy || my_nfv9_logging_info_temp->logging_policy; - index_curr = (cnat_nfv9_logging_info_pool + index_curr)->nfv9_logging_next_index; - } - my_vrfmap->nf_logging_policy = nfv9_logging_policy; - } - } - -done: - return 0; -} - -/* config CLIs */ -VLIB_CLI_COMMAND (set_vcgn_map_command) = { - .path = "set vcgn map", - .short_help = "set vcgn map [- ]", - .function = set_vcgn_map_command_fn, -}; - -VLIB_CLI_COMMAND (set_vcgn_inside_command) = { - .path = "set vcgn inside", - .short_help = "set vcgn inside outside ", - .function = set_vcgn_inside_command_fn, -}; - -VLIB_CLI_COMMAND (set_vcgn_tcp_timeout_command) = { - .path = "set vcgn tcp timeout", - .short_help = "set vcgn tcp timeout active <1-65535> init <1-65535>", - .function = set_vcgn_tcp_timeout_command_fn, -}; - -VLIB_CLI_COMMAND (set_vcgn_udp_timeout_command) = { - .path = "set vcgn udp timeout", - .short_help = "set vcgn udp timeout active <1-65535> init <1-65535>", - .function = set_vcgn_udp_timeout_command_fn, -}; - -VLIB_CLI_COMMAND (set_vcgn_icmp_timeout_command) = { - .path = "set vcgn icmp timeout", - .short_help = "set vcgn icmp timeout <1-65535>", - .function = set_vcgn_icmp_timeout_command_fn, -}; - -VLIB_CLI_COMMAND (set_vcgn_protocol_default_timeout_command) = { - .path = "set vcgn default timeout", - .short_help = "set vcgn default timeout protocol ", - .function = set_vcgn_protocol_default_timeout_command_fn, -}; - -VLIB_CLI_COMMAND (set_vcgn_dynamic_port_start_range_command) = { - .path = "set vcgn dynamic port start", - .short_help = "set vcgn dynamic port start <1-65535>", - .function = set_vcgn_dynamic_port_start_range_command_fn, -}; - -VLIB_CLI_COMMAND (set_vcgn_port_limit_command) = { - .path = "set vcgn port limit", - .short_help = "set vcgn port limit <1-65535>", - .function = set_vcgn_port_limit_command_fn, -}; - -VLIB_CLI_COMMAND (set_vcgn_nfv9_logging_cofig_command) = { - .path = "set vcgn nfv9", - .short_help = "set vcgn nfv9 [del] inside " - "server port [refresh-rate ] " - "[timeout ] [pmtu ]", - .function = set_vcgn_nfv9_logging_cofig_command_fn, -}; - - -/* show CLIs */ -VLIB_CLI_COMMAND (show_vcgn_config_command) = { - .path = "show vcgn config", - .short_help = "show vcgn config", - .function = show_vcgn_config_command_fn, -}; - -VLIB_CLI_COMMAND (show_vcgn_stat_command) = { - .path = "show vcgn statistics", - .short_help = "show vcgn statistics", - .function = show_vcgn_stats_command_fn, -}; - -VLIB_CLI_COMMAND (show_vcgn_inside_translation_command) = { - .path = "show vcgn inside-translation", - .short_help = "show vcgn inside-translation protocol " - "interface inside-addr " - "[start-port ] [end-port ]", - .function = show_vcgn_inside_translation_command_fn, -}; - -VLIB_CLI_COMMAND (show_vcgn_outside_translation_command) = { - .path = "show vcgn outside-translation", - .short_help = "show vcgn outside-translation protocol " - "interface outside-addr " - "[start-port ] [end-port ]", - .function = show_vcgn_outside_translation_command_fn, -}; - -static clib_error_t * -vcgn_init (vlib_main_t * vm) -{ - clib_error_t * error = 0; - - if ((error = vlib_call_init_function - (vm, vcgn_classify_init))) - return error; - if ((error = vlib_call_init_function - (vm, cnat_ipv4_udp_inside_input_init))) - return error; - if ((error = vlib_call_init_function - (vm, cnat_ipv4_udp_outside_input_init))) - return error; - if ((error = vlib_call_init_function - (vm, cnat_ipv4_udp_inside_input_exc_init))) - return error; - if ((error = vlib_call_init_function - (vm, cnat_db_scanner_init))) - return error; - if ((error = vlib_call_init_function - (vm, cnat_ipv4_tcp_inside_input_init))) - return error; - if ((error = vlib_call_init_function - (vm, cnat_ipv4_tcp_inside_input_exc_init))) - return error; - if ((error = vlib_call_init_function - (vm, cnat_ipv4_tcp_outside_input_init))) - return error; - if ((error = vlib_call_init_function - (vm, cnat_ipv4_icmp_q_inside_input_init))) - return error; - if ((error = vlib_call_init_function - (vm, cnat_ipv4_icmp_q_inside_input_exc_init))) - return error; - if ((error = vlib_call_init_function - (vm, cnat_ipv4_icmp_q_outside_input_init))) - return error; - if ((error = vlib_call_init_function - (vm, cnat_ipv4_icmp_e_inside_input_init))) - return error; - if ((error = vlib_call_init_function - (vm, cnat_ipv4_icmp_e_outside_input_init))) - return error; - - return error; -} - -/* - * This routine exists to convince the vlib plugin framework that - * we haven't accidentally copied a random .dll into the plugin - * directory. This is used in lieu of VLIB_INIT_FUNCTION(vcgn_init). - * - * 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) -{ - return vcgn_init(vm); -} diff --git a/plugins/vcgn-plugin/vcgn/vcgn_db.h b/plugins/vcgn-plugin/vcgn/vcgn_db.h deleted file mode 100644 index cd7d835c..00000000 --- a/plugins/vcgn-plugin/vcgn/vcgn_db.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - *------------------------------------------------------------------ - * vcgn_db.h - translation database definitions - * - * Copyright (c) 2007-2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#ifndef __VCGN_DB_H__ -#define __VCGN_DB_H__ - -#include "index_list.h" - -/* - * The key structure. All fields are in NETWORK byte order! - */ -typedef struct { - u32 ipv4; - u16 port; - u16 vrf; //bit0-12:vrf, bit13:unused, bit14-15:protocol -} cnat_db_key_t; - -/* bit14-15:protocol in cnat_db_key_t */ -#define CNAT_INVALID_PROTO 0x0000 -#define CNAT_UDP 0x4000 -#define CNAT_TCP 0x8000 -#define CNAT_ICMP 0xc000 -#define CNAT_VRF_MASK 0x3fff -#define CNAT_PRO_MASK 0xc000 -#define CNAT_PRO_SHIFT 14 - -/* - * Maximum number of VRF entries supported - */ -#define CNAT_MAX_VRFMAP_ENTRIES (CNAT_VRF_MASK + 1) -/* - * for hashing purposes, fetch the key in one instr. - */ -typedef union { - cnat_db_key_t k; - u64 key64; -} cnat_key_t; - -/* - * Main translation database entries. Currently 0x50 = 80 bytes in length. - * Given 20,000,000 entries, it saves nearly 1gb of SDRAM to pack the entries - * and pay the extra prefetch. So, that's what we do. - */ - -typedef struct { - /* 0x00 */ - index_slist_t out2in_hash; /* hash-and-chain, x2 */ - index_slist_t in2out_hash; - - /* 0x08 */ - cnat_key_t out2in_key; /* network-to-user, outside-to-inside key */ - - /* 0x10 */ - cnat_key_t in2out_key; /* user-to-network, inside-to-outside key */ - - /* 0x18 */ - index_dlist_t user_ports; /* per-user translation list */ - - /* 0x20 */ - u32 user_index; /* index of user that owns this entry */ - - /* 0x24 */ - u16 vrfmap_index; /* index of vrfmap */ - - /* 0x26 */ - u16 flags; /* Always need flags... */ -#define CNAT_DB_FLAG_PORT_PAIR (1<<0) -#define CNAT_DB_FLAG_TCP_ACTIVE (1<<1) -#define CNAT_DB_FLAG_ENTRY_FREE (1<<2) -#define CNAT_DB_FLAG_UDP_ACTIVE (1<<3) -#define CNAT_DB_FLAG_STATIC_PORT (1<<4) -#define CNAT_DB_FLAG_ALG_ENTRY (1<<5) - - /* 0x28 */ - u32 dst_ipv4; /* pointer to ipv4 dst list, used in evil mode */ - - /* 0x2C */ - u32 out2in_pkts; /* pkt counters */ - - /* 0x30 */ - u32 in2out_pkts; - - /* 0x34 */ - u32 entry_expires; /* timestamp used to expire translations */ - - /* 0x38 */ - union { /* used by FTP ALG, pkt len delta due to FTP PORT cmd */ - u16 delta; - i8 alg_dlt[2]; /* two delta values, 0 for previous, 1 for current */ - u16 il; /* Used to indicate if interleaved mode is used - in case of RTSP ALG */ - } alg; - - /* 0x 48 */ - u32 tcp_seq_num; /* last tcp (FTP) seq # that has pkt len change due to PORT */ - - cnat_timeout_t destn_key; - - /* 0x4C... last byte -- 72 total */ -} cnat_main_db_entry_t; -#endif diff --git a/src/vnet/buffer.h b/src/vnet/buffer.h index 7935027f..45fc352a 100644 --- a/src/vnet/buffer.h +++ b/src/vnet/buffer.h @@ -229,72 +229,6 @@ typedef struct u32 sad_index; } ipsec; - /* vcgn udp inside input, only valid there */ - struct - { - /* This part forms context of the packet. The structure should be - * exactly same as spp_ctx_t. Also this should be the first - * element of this vcgn_uii structure. - */ - /****** BEGIN spp_ctx_t section ***********************/ - union - { /* Roddick specific */ - u32 roddick_info; - struct _tx_pkt_info - { /* Used by PI to PI communication for TX */ - u32 uidb_index:16; /* uidb_index to transmit */ - u32 packet_type:2; /* 1-IPv4, 2-Ipv6, - 0,3 - Unused */ - u32 ipv4_defrag:1; /* 0 - Normal, 1 - update first - * segment size - * (set by 6rd defrag node) - */ - - u32 dst_ip_port_idx:4; /* Index to dst_ip_port_table */ - u32 from_node:4; - u32 calc_chksum:1; - u32 reserved:4; - } tx; - struct _rx_pkt_info - { /* Used by PD / PI communication */ - u32 uidb_index:16; /* uidb_index received in packet */ - u32 packet_type:2; /* 1-IPv4, 2-Ipv6, - 0,3 - Unused */ - u32 icmp_type:1; /* 0-ICMP query type, 1-ICMP error type */ - u32 protocol_type:2; /* 1-TCP, 2-UDP, 3-ICMP, 0 - Unused */ - u32 ipv4_defrag:1; /* 0 - Normal, 1 - update first - * segment size - * (set by 6rd defrag node) - */ - - u32 direction:1; /* 0-Outside, 1-Inside */ - u32 frag:1; /*IP fragment-1, Otherwise-0 */ - u32 option:1; /* 0-No IP option (v4) present, non-fragHdr - * option hdr present (v6) - */ - u32 df_bit:1; /* IPv4 DF bit copied here */ - u32 reserved1:6; - } rx; - } ru; - /****** END spp_ctx_t section ***********************/ - - union - { - struct - { - u32 ipv4; - u16 port; - u16 vrf; //bit0-13:i/f, bit14-15:protocol - } k; - - u64 key64; - } key; - - u32 bucket; - - u16 ovrf; /* Exit interface */ - u8 frag_pkt; - u8 vcgn_unused1; - } vcgn_uii; - /* MAP */ struct { -- cgit 1.2.3-korg From 85bb9172894870f0c6c72e1555a0decf4d37213f Mon Sep 17 00:00:00 2001 From: Marco Varlese Date: Thu, 2 Feb 2017 21:33:09 +0100 Subject: Added support for openSUSE Change-Id: I64a0eeaa066adb70dfaeb33641d0336ddac18cf0 Signed-off-by: Marco Varlese --- doxygen/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'doxygen/Makefile') diff --git a/doxygen/Makefile b/doxygen/Makefile index 640acc26..069d97fb 100644 --- a/doxygen/Makefile +++ b/doxygen/Makefile @@ -35,6 +35,7 @@ OS_ID ?= $(shell grep '^ID=' /etc/os-release | cut -f2- -d= | sed -e 's/\"//g') # Package dependencies DOC_DEB_DEPENDS = doxygen graphviz python-pyparsing python-jinja2 DOC_RPM_DEPENDS = doxygen graphviz pyparsing python-jinja2 +DOC_SUSE_RPM_DEPENDS = doxygen graphviz python-pyparsing python-Jinja2 DOC_MAC_BIN_DEPENDS = doxygen dot git DOC_MAC_PY_DEPENDS = pyparsing jinja2 @@ -159,8 +160,10 @@ else ifeq ($(OS_ID),darwin) false; \ ); \ done +else ifeq ($(OS_ID),opensuse) + @sudo zypper install $(CONFIRM) $(DOC_SUSE_RPM_DEPENDS) else - $(error "Building documentation currently works only on Ubuntu, CentOS or MacOS systems.") + $(error "Building documentation currently works only on Ubuntu, CentOS, MacOS and OpenSUSE systems.") endif @touch $@ -- cgit 1.2.3-korg From c8c5335e3a1d1ba7ec1248b0ecbf00cc74ea57bb Mon Sep 17 00:00:00 2001 From: Dave Wallace Date: Fri, 17 Feb 2017 00:10:53 -0500 Subject: Add ref to test framework docs in doxygen output. Change-Id: If3081c4a9dde00cd522d1fc5a7daa9b1849684bf Signed-off-by: Dave Wallace --- README.md | 8 ++++++-- doxygen/Makefile | 6 +----- doxygen/test_framework_doc.md | 7 +++++++ 3 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 doxygen/test_framework_doc.md (limited to 'doxygen/Makefile') diff --git a/README.md b/README.md index 8520b395..b70103fb 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,6 @@ Directory name | Description build-root | Build output directory doxygen | Documentation generator configuration dpdk | DPDK patches and build infrastructure -@ref plugins | Not-yet-relocated VPP bundled plugins directory @ref src | VPP source code @ref src/plugins | VPP bundled plugins directory @ref src/svm | Shared virtual memory allocation library @@ -45,7 +44,7 @@ Directory name | Description @ref src/vpp-api | VPP application API bindings @ref src/vppinfra | VPP core library test | Unit tests -@ref vpp-api | Not-yet-relocated API bindings +@ref src/vpp/api | Not-yet-relocated API bindings ## Getting started @@ -100,3 +99,8 @@ information. Visit the [VPP wiki](https://wiki.fd.io/view/VPP) for details on more advanced building strategies and development notes. + + +## Test Framework + +There is PyDoc generated documentation available for the VPP test framework. See @subpage test_framework_doc for details. diff --git a/doxygen/Makefile b/doxygen/Makefile index 069d97fb..973ca07f 100644 --- a/doxygen/Makefile +++ b/doxygen/Makefile @@ -82,10 +82,6 @@ DOXY_EXCLUDE_REGEXP = ($(subst .,\.,$(shell echo '$(strip $(DOXY_EXCLUDE))' | se # Include all the normal source directories in the include file path DOXY_INCLUDE_PATH = $(DOXY_SRC_DIRECTORIES) -# Also include any plugin directories that exist -DOXY_INCLUDE_PATH += \ - $(shell find $(WS_ROOT)/plugins -maxdepth 1 -type d | sed -e 's@^$(WS_ROOT)/*@@') - # Find API header directories and include them in the header path. # This is only useful if VPP and plugins are already built; nothing # here depends on those targets. We don't build documentation for these @@ -140,7 +136,7 @@ ifeq ($(OS_ID),ubuntu) sudo apt-get $(CONFIRM) $(FORCE) install $$inst; \ fi @if [ ! -s /usr/lib/graphviz/config6a ]; then \ - echo "Rebuidlding system Graphviz configuration."; \ + echo "Rebuilding system Graphviz configuration."; \ sudo dot -c; \ fi else ifneq ("$(wildcard /etc/redhat-release)","") diff --git a/doxygen/test_framework_doc.md b/doxygen/test_framework_doc.md new file mode 100644 index 00000000..b2873c5f --- /dev/null +++ b/doxygen/test_framework_doc.md @@ -0,0 +1,7 @@ +Test Framework Documentation {#test_framework_doc} +============================ + +PyDoc generated documentation for the "make test" framework is available for the following releases + +- [Test framework documentation for VPP 17.04](https://docs.fd.io/vpp/17.04/vpp_make_test/html) +- [Test framework documentation for VPP 17.01](https://docs.fd.io/vpp/17.01/vpp_make_test/html) -- cgit 1.2.3-korg From 4521afa9a643983c789b6b3a77b14c0a95d5e0b2 Mon Sep 17 00:00:00 2001 From: Pablo Camarillo Date: Thu, 16 Mar 2017 10:43:05 +0100 Subject: Bugfixing and documentation for SRv6 - Fixed three coverity issues - Linked SRv6 docs - Moved sample plugin to examples folder - Fixed bug with hash. Now everything is using mhash. Potentially in the future we want to do bihash. Change-Id: Ie03a13c8fecb1e315e67d0596cbd23220779aaf2 Signed-off-by: Pablo Camarillo --- doxygen/Makefile | 6 +- doxygen/user_doc.md | 13 +- src/configure.ac | 1 - src/examples/srv6-sample-localsid/node.c | 200 +++++++++++++++++++++ .../srv6-sample-localsid/srv6_localsid_sample.c | 179 ++++++++++++++++++ .../srv6-sample-localsid/srv6_localsid_sample.h | 61 +++++++ .../srv6_sample_localsid_doc.md | 30 ++++ src/plugins/Makefile.am | 4 - src/plugins/sample_srv6_localsid.am | 23 --- src/plugins/srv6-localsid/node.c | 200 --------------------- src/plugins/srv6-localsid/srv6_localsid_sample.c | 179 ------------------ src/plugins/srv6-localsid/srv6_localsid_sample.h | 61 ------- .../srv6-localsid/srv6_sample_localsid_doc.md | 38 ---- src/vnet/sr/sr.h | 30 +--- src/vnet/sr/sr_doc.md | 132 ++------------ src/vnet/sr/sr_localsid.c | 18 +- src/vnet/sr/sr_localsid.md | 58 ++++++ src/vnet/sr/sr_policy.md | 56 ++++++ src/vnet/sr/sr_policy_rewrite.c | 28 ++- src/vnet/sr/sr_steering.c | 59 +++--- src/vnet/sr/sr_steering.md | 11 ++ 21 files changed, 672 insertions(+), 715 deletions(-) create mode 100644 src/examples/srv6-sample-localsid/node.c create mode 100755 src/examples/srv6-sample-localsid/srv6_localsid_sample.c create mode 100644 src/examples/srv6-sample-localsid/srv6_localsid_sample.h create mode 100644 src/examples/srv6-sample-localsid/srv6_sample_localsid_doc.md delete mode 100644 src/plugins/sample_srv6_localsid.am delete mode 100644 src/plugins/srv6-localsid/node.c delete mode 100755 src/plugins/srv6-localsid/srv6_localsid_sample.c delete mode 100644 src/plugins/srv6-localsid/srv6_localsid_sample.h delete mode 100644 src/plugins/srv6-localsid/srv6_sample_localsid_doc.md create mode 100644 src/vnet/sr/sr_localsid.md create mode 100644 src/vnet/sr/sr_policy.md create mode 100644 src/vnet/sr/sr_steering.md (limited to 'doxygen/Makefile') diff --git a/doxygen/Makefile b/doxygen/Makefile index 973ca07f..9caa4079 100644 --- a/doxygen/Makefile +++ b/doxygen/Makefile @@ -53,7 +53,8 @@ DOXY_SRC_DIRECTORIES = \ $(DOXY_SRC)/vlibsocket \ $(DOXY_SRC)/vnet \ $(DOXY_SRC)/vpp \ - $(DOXY_SRC)/vpp-api + $(DOXY_SRC)/vpp-api \ + $(DOXY_SRC)/examples # Input directories and files DOXY_INPUT ?= \ @@ -72,9 +73,8 @@ DOXY_INPUT := $(subst $(WS_ROOT)/,,$(DOXY_INPUT)) # These must be left-anchored paths for the regexp below to work. DOXY_EXCLUDE ?= \ $(DOXY_SRC)/vlib/vlib/buffer.c \ - $(DOXY_SRC)/vlib/example \ $(DOXY_SRC)/vpp-api/lua \ - plugins/sample-plugin + $(DOXY_SRC)/examples/sample-plugin # Generate a regexp for filenames to exclude DOXY_EXCLUDE_REGEXP = ($(subst .,\.,$(shell echo '$(strip $(DOXY_EXCLUDE))' | sed -e 's/ /|/g'))) diff --git a/doxygen/user_doc.md b/doxygen/user_doc.md index 40303439..29df6156 100644 --- a/doxygen/user_doc.md +++ b/doxygen/user_doc.md @@ -4,13 +4,14 @@ User Documentation {#user_doc} Several modules provide operational, dataplane-user focused documentation. - [GUI guided user demo](https://wiki.fd.io/view/VPP_Sandbox/vpp-userdemo) -- @subpage qos_doc -- @subpage ipsec_gre_doc -- @subpage dpdk_crypto_ipsec_doc -- @subpage map_doc -- @subpage lldp_doc +- @subpage bfd_doc - @subpage ioam_plugin_doc +- @subpage ipsec_gre_doc - @subpage lb_plugin_doc +- @subpage lldp_doc +- @subpage map_doc +- @subpage dpdk_crypto_ipsec_doc - @subpage flowperpkt_plugin_doc +- @subpage qos_doc - @subpage span_doc -- @subpage bfd_doc +- @subpage srv6_doc diff --git a/src/configure.ac b/src/configure.ac index 0ca1af11..581b0968 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -154,7 +154,6 @@ PLUGIN_ENABLED(lb) PLUGIN_ENABLED(memif) PLUGIN_ENABLED(sixrd) PLUGIN_ENABLED(snat) -PLUGIN_DISABLED(srv6sample) ############################################################################### # Dependency checks diff --git a/src/examples/srv6-sample-localsid/node.c b/src/examples/srv6-sample-localsid/node.c new file mode 100644 index 00000000..7bae9cd7 --- /dev/null +++ b/src/examples/srv6-sample-localsid/node.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include + +typedef struct { + u32 localsid_index; +} srv6_localsid_sample_trace_t; + +/* packet trace format function */ +static u8 * format_srv6_localsid_sample_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + srv6_localsid_sample_trace_t * t = va_arg (*args, srv6_localsid_sample_trace_t *); + s = format (s, "SRv6-sample-localsid: localsid_index %d\n", + t->localsid_index); + return s; +} + +vlib_node_registration_t srv6_localsid_sample_node; + +#define foreach_srv6_localsid_counter \ +_(PROCESSED, "srv6-sample-localsid processed packets") \ +_(NO_SRH, "(Error) No SRH.") + +typedef enum { +#define _(sym,str) SRV6_LOCALSID_COUNTER_##sym, + foreach_srv6_localsid_counter +#undef _ + SRV6_LOCALSID_N_COUNTERS, +} srv6_localsid_sample_counters; + +static char * srv6_localsid_counter_strings[] = { +#define _(sym,string) string, + foreach_srv6_localsid_counter +#undef _ +}; + +typedef enum { + SRV6_SAMPLE_LOCALSID_NEXT_ERROR, + SRV6_SAMPLE_LOCALSID_NEXT_IP6LOOKUP, + SRV6_SAMPLE_LOCALSID_N_NEXT, +} srv6_localsid_sample_next_t; + +/** + * @brief Function doing End processing. + */ +//Fixme: support OAM (hop-by-hop header) here! +static_always_inline void +end_srh_processing (vlib_node_runtime_t * node, + vlib_buffer_t * b0, + ip6_header_t * ip0, + ip6_sr_header_t * sr0, + u32 * next0) +{ + ip6_address_t *new_dst0; + + if(PREDICT_TRUE(ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)) + { + if(PREDICT_TRUE(sr0->type == ROUTING_HEADER_TYPE_SR)) + { + if(PREDICT_TRUE(sr0->segments_left != 0)) + { + sr0->segments_left -= 1; + new_dst0 = (ip6_address_t *)(sr0->segments); + new_dst0 += sr0->segments_left; + ip0->dst_address.as_u64[0] = new_dst0->as_u64[0]; + ip0->dst_address.as_u64[1] = new_dst0->as_u64[1]; + } + else + { + *next0 = SRV6_SAMPLE_LOCALSID_NEXT_ERROR; + b0->error = node->errors[SRV6_LOCALSID_COUNTER_NO_SRH]; + } + } + else + { + /* Error. Routing header of type != SR */ + *next0 = SRV6_SAMPLE_LOCALSID_NEXT_ERROR; + b0->error = node->errors[SRV6_LOCALSID_COUNTER_NO_SRH]; + } + } +} + +/* + * @brief SRv6 Sample Localsid graph node + * WARNING: YOU MUST DO THE DUAL LOOP + */ +static uword +srv6_localsid_sample_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, * from, * to_next; + u32 next_index; + u32 pkts_swapped = 0; + + ip6_sr_main_t * sm = &sr_main; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + u32 cpu_index = os_get_cpu_number (); + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame (vm, node, next_index, + to_next, n_left_to_next); + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t * b0; + ip6_header_t * ip0 = 0; + ip6_sr_header_t * sr0; + u32 next0 = SRV6_SAMPLE_LOCALSID_NEXT_IP6LOOKUP; + ip6_sr_localsid_t *ls0; + srv6_localsid_sample_per_sid_memory_t *ls0_mem; + + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + ip0 = vlib_buffer_get_current (b0); + sr0 = (ip6_sr_header_t *)(ip0+1); + + /* Lookup the SR End behavior based on IP DA (adj) */ + ls0 = pool_elt_at_index (sm->localsids, vnet_buffer(b0)->ip.adj_index[VLIB_TX]); + ls0_mem = ls0->plugin_mem; + + /* SRH processing */ + end_srh_processing (node, b0, ip0, sr0, &next0); + + /* ==================================================================== */ + /* INSERT CODE HERE */ + /* Example starts here */ + //In this example we are changing the next VRF table by the one in CLI + vnet_buffer(b0)->sw_if_index[VLIB_TX] = ls0_mem->fib_table; + /* Example finishes here */ + /* ==================================================================== */ + + if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) + { + srv6_localsid_sample_trace_t *tr = vlib_add_trace (vm, node, b0, sizeof (*tr)); + tr->localsid_index = ls0 - sm->localsids; + } + + /* This increments the SRv6 per LocalSID counters.*/ + vlib_increment_combined_counter + (((next0 == SRV6_SAMPLE_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) : &(sm->sr_ls_valid_counters)), + cpu_index, + ls0 - sm->localsids, + 1, vlib_buffer_length_in_chain (vm, b0)); + + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, + n_left_to_next, bi0, next0); + + pkts_swapped ++; + } + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + + } + + return frame->n_vectors; +} + +VLIB_REGISTER_NODE (srv6_localsid_sample_node) = { + .function = srv6_localsid_sample_fn, + .name = "srv6-localsid-sample", + .vector_size = sizeof (u32), + .format_trace = format_srv6_localsid_sample_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = SRV6_LOCALSID_N_COUNTERS, + .error_strings = srv6_localsid_counter_strings, + .n_next_nodes = SRV6_SAMPLE_LOCALSID_N_NEXT, + .next_nodes = { + [SRV6_SAMPLE_LOCALSID_NEXT_IP6LOOKUP] = "ip6-lookup", + [SRV6_SAMPLE_LOCALSID_NEXT_ERROR] = "error-drop", + }, +}; diff --git a/src/examples/srv6-sample-localsid/srv6_localsid_sample.c b/src/examples/srv6-sample-localsid/srv6_localsid_sample.c new file mode 100755 index 00000000..ec16547e --- /dev/null +++ b/src/examples/srv6-sample-localsid/srv6_localsid_sample.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + *------------------------------------------------------------------ + * srv6_localsid_sample.c - Simple SRv6 LocalSID + *------------------------------------------------------------------ + */ + +#include +#include +#include + +#include +#include +#include + +unsigned char srv6_localsid_name[32] = "Sample-SRv6-LocalSID-plugin"; +unsigned char keyword_str[32] = "new_srv6_localsid"; +unsigned char def_str[64] = "This is a definition of a sample new_srv6_localsid"; +unsigned char params_str[32] = ""; + +/*****************************************/ +/* SRv6 LocalSID instantiation and removal functions */ +static int +srv6_localsid_creation_fn (ip6_sr_localsid_t *localsid) +{ + /* + * Do you want to do anything fancy upon localsid instantiation? + * You can do it here + * (If return != 0 the localsid creation will be cancelled.) + */ + /* As an example Im going to do a +1 to the fib table inserted by the user */ + srv6_localsid_sample_per_sid_memory_t *ls_mem = localsid->plugin_mem; + ls_mem->fib_table += 1; + return 0; +} + +static int +srv6_localsid_removal_fn (ip6_sr_localsid_t *localsid) +{ + /* Do you want to do anything fancy upon localsid removal? + * You can do it here + * (If return != 0 the localsid removal will be cancelled.) + */ + /* + * BTW if you stored something in localsid->plugin_mem you should clean it now + */ + + //In this example we are only cleaning the memory allocated per localsid + clib_mem_free(localsid->plugin_mem); + return 0; +} + +/**********************************/ +/* SRv6 LocalSID format functions */ +/* + * Prints nicely the parameters of a localsid + * Example: print "Table 5" + */ +u8 * +format_srv6_localsid_sample (u8 * s, va_list * args) +{ + srv6_localsid_sample_per_sid_memory_t *ls_mem = va_arg (*args, void *); + return (format (s, "Table: %u", ls_mem->fib_table)); +} + +/* + * Process the parameters of a localsid + * Example: process from: + * sr localsid address cafe::1 behavior new_srv6_localsid 5 + * everything from behavior on... so in this case 'new_srv6_localsid 5' + * Notice that it MUST match the keyword_str and params_str defined above. + */ +uword +unformat_srv6_localsid_sample (unformat_input_t * input, va_list * args) +{ + void **plugin_mem = va_arg (*args, void **); + srv6_localsid_sample_per_sid_memory_t *ls_mem; + u32 table_id; + if (unformat (input, "new_srv6_localsid %u", &table_id)) + { + /* Allocate a portion of memory */ + ls_mem = clib_mem_alloc_aligned_at_offset ( + sizeof(srv6_localsid_sample_per_sid_memory_t), 0, 0, 1); + + /* Set to zero the memory */ + memset (ls_mem, 0, sizeof(srv6_localsid_sample_per_sid_memory_t)); + + /* Our brand-new car is ready */ + ls_mem->fib_table = table_id; + + /* Dont forget to add it to the localsid */ + *plugin_mem = ls_mem; + return 1; + } + return 0; +} + +/*************************/ +/* SRv6 LocalSID FIB DPO */ +static u8 * +format_srv6_localsid_sample_dpo (u8 * s, va_list * args) +{ + index_t index = va_arg (*args, index_t); + CLIB_UNUSED (u32 indent) = va_arg (*args, u32); + + return (format (s, "SR: localsid_sample_index:[%u]", index)); +} + +void +srv6_localsid_sample_dpo_lock (dpo_id_t * dpo) +{ +} + +void +srv6_localsid_sample_dpo_unlock (dpo_id_t * dpo) +{ +} + +const static dpo_vft_t srv6_localsid_sample_vft = { + .dv_lock = srv6_localsid_sample_dpo_lock, + .dv_unlock = srv6_localsid_sample_dpo_unlock, + .dv_format = format_srv6_localsid_sample_dpo, +}; + +const static char *const srv6_localsid_sample_ip6_nodes[] = { + "srv6-localsid-sample", + NULL, +}; + +const static char *const *const srv6_localsid_sample_nodes[DPO_PROTO_NUM] = { + [DPO_PROTO_IP6] = srv6_localsid_sample_ip6_nodes, +}; + +/**********************/ +static clib_error_t * srv6_localsid_sample_init (vlib_main_t * vm) +{ + srv6_localsid_sample_main_t * sm = &srv6_localsid_sample_main; + int rv = 0; + /* Create DPO */ + sm->srv6_localsid_sample_dpo_type = dpo_register_new_type ( + &srv6_localsid_sample_vft, srv6_localsid_sample_nodes); + + /* Register SRv6 LocalSID */ + rv = sr_localsid_register_function (vm, + srv6_localsid_name, + keyword_str, + def_str, + params_str, + &sm->srv6_localsid_sample_dpo_type, + format_srv6_localsid_sample, + unformat_srv6_localsid_sample, + srv6_localsid_creation_fn, + srv6_localsid_removal_fn); + if (rv < 0) + clib_error_return (0, "SRv6 LocalSID function could not be registered."); + else + sm->srv6_localsid_behavior_id = rv; + + return 0; +} + +VLIB_INIT_FUNCTION (srv6_localsid_sample_init); + +VLIB_PLUGIN_REGISTER () = { + .version = "1.0", +}; diff --git a/src/examples/srv6-sample-localsid/srv6_localsid_sample.h b/src/examples/srv6-sample-localsid/srv6_localsid_sample.h new file mode 100644 index 00000000..474b5de2 --- /dev/null +++ b/src/examples/srv6-sample-localsid/srv6_localsid_sample.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __included_srv6_localsid_sample_h__ +#define __included_srv6_localsid_sample_h__ + +#include +#include +#include +#include + +#include +#include +#include + +typedef struct { + /* API message ID base */ + u16 msg_id_base; + + /* convenience */ + vlib_main_t * vlib_main; + vnet_main_t * vnet_main; + + /* DPO type */ + dpo_type_t srv6_localsid_sample_dpo_type; + + /* SRv6 LocalSID behavior number */ + u32 srv6_localsid_behavior_id; + +} srv6_localsid_sample_main_t; + +/* + * This is the memory that will be stored per each localsid + * the user instantiates + */ +typedef struct { + u32 fib_table; /* Stupid index used as an example.. */ +} srv6_localsid_sample_per_sid_memory_t ; + +srv6_localsid_sample_main_t srv6_localsid_sample_main; + +format_function_t format_srv6_localsid_sample; +unformat_function_t unformat_srv6_localsid_sample; + +void srv6_localsid_sample_dpo_lock (dpo_id_t * dpo); +void srv6_localsid_sample_dpo_unlock (dpo_id_t * dpo); + +extern vlib_node_registration_t srv6_localsid_sample_node; + +#endif /* __included_sample_h__ */ diff --git a/src/examples/srv6-sample-localsid/srv6_sample_localsid_doc.md b/src/examples/srv6-sample-localsid/srv6_sample_localsid_doc.md new file mode 100644 index 00000000..78e91ab3 --- /dev/null +++ b/src/examples/srv6-sample-localsid/srv6_sample_localsid_doc.md @@ -0,0 +1,30 @@ +# Sample SRv6 LocalSID documentation {#srv6_plugin_doc} + +## Introduction + +This plugin is an example of how an user can create a new SRv6 LocalSID behavior by using VPP plugins with the appropiate API calls to the existing SR code. + +This **example** plugin registers a new localsid behavior, with cli keyword 'new_srv6_localsid' which only takes one parameter, a fib-table. Upon recival of a packet, this plugin will enforce the next IP6 lookup in the specific fib-table specified by the user. (Indeed it will do the lookup in the fib_table n+1 (since for the shake of the example we increment the fib-table.) + +Notice that the plugin only 'defines' a new SRv6 LocalSID behavior, but the existing SR code in VNET is the one actually instantiating new LocalSIDs. Notice that there are callback functions such that when you create or remove a LocalSID you can actually setup specific parameters through the functions in this plugin. + +## Variables to watch for + +* srv6_localsid_name: This variable is the name (used as a unique key) identifying this SR LocalSID plugin. +* keyword_str: This is the CLI keyword to be used for the plugin. In this example 'new_srv6_localsid'. (i.e. sr localsid address cafe::1 behavior new_srv6_localsid ) +* def_str: This is a definition of this SR behavior. This is printed when you do 'show sr localsid behaviors'. +* params_str: This is a definition of the parameters of this localsid. This is printed when you do 'show sr localsid behaviors'. + +## Functions to watch for + +* srv6_localsid_creation_fn: This function will be called every time a new SR LocalSID is instantiated with the behavior defined in this plugin. +* srv6_localsid_removal_fn: This function will be called every time a new SR LocalSID is removed with the behavior defined in this plugin. This function tends to be used for freeing up all the memory created in the previous function. +* format_srv6_localsid_sample: This function prints nicely the parameters of every SR LocalSID using this behavior. +* unformat_srv6_localsid_sample: This function parses the CLI command when initialising a new SR LocalSID using this behavior. It parses all the parameters and ensures that the parameters are correct. +* format_srv6_localsid_sample_dpo: This function formats the 'show ip6 fib' message for the SR LocalSIDs created with this plugin behavior. + +## Graph node + +The current graph node uses the function 'end_srh_processing' to do the Segment Routing Endpoint behavior. Notice that it does not allow the cleanup of a Segment Routing header (as per the SRv6 behavior specs). +This function is identical to the one found in /src/vnet/sr/sr_localsid.c +In case that by some other reason you want to do decapsulation, or SRH clean_up you can use the functions 'end_decaps_srh_processing' or 'end_psp_srh_processing' respectively. diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index 6713a9e2..623892e7 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -69,10 +69,6 @@ if ENABLE_SNAT_PLUGIN include snat.am endif -if ENABLE_SRV6SAMPLE_PLUGIN -include sample_srv6_localsid.am -endif - include ../suffix-rules.mk # Remove *.la files diff --git a/src/plugins/sample_srv6_localsid.am b/src/plugins/sample_srv6_localsid.am deleted file mode 100644 index a820ab25..00000000 --- a/src/plugins/sample_srv6_localsid.am +++ /dev/null @@ -1,23 +0,0 @@ - -# Copyright (c) -# 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. - -vppplugins_LTLIBRARIES += sample_srv6_localsid_plugin.la - -sample_srv6_localsid_plugin_la_SOURCES = \ - srv6-localsid/node.c \ - srv6-localsid/srv6_localsid_sample.c - -noinst_HEADERS += srv6-localsid/srv6_localsid_sample.h - -# vi:syntax=automake diff --git a/src/plugins/srv6-localsid/node.c b/src/plugins/srv6-localsid/node.c deleted file mode 100644 index 7bae9cd7..00000000 --- a/src/plugins/srv6-localsid/node.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include - -typedef struct { - u32 localsid_index; -} srv6_localsid_sample_trace_t; - -/* packet trace format function */ -static u8 * format_srv6_localsid_sample_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - srv6_localsid_sample_trace_t * t = va_arg (*args, srv6_localsid_sample_trace_t *); - s = format (s, "SRv6-sample-localsid: localsid_index %d\n", - t->localsid_index); - return s; -} - -vlib_node_registration_t srv6_localsid_sample_node; - -#define foreach_srv6_localsid_counter \ -_(PROCESSED, "srv6-sample-localsid processed packets") \ -_(NO_SRH, "(Error) No SRH.") - -typedef enum { -#define _(sym,str) SRV6_LOCALSID_COUNTER_##sym, - foreach_srv6_localsid_counter -#undef _ - SRV6_LOCALSID_N_COUNTERS, -} srv6_localsid_sample_counters; - -static char * srv6_localsid_counter_strings[] = { -#define _(sym,string) string, - foreach_srv6_localsid_counter -#undef _ -}; - -typedef enum { - SRV6_SAMPLE_LOCALSID_NEXT_ERROR, - SRV6_SAMPLE_LOCALSID_NEXT_IP6LOOKUP, - SRV6_SAMPLE_LOCALSID_N_NEXT, -} srv6_localsid_sample_next_t; - -/** - * @brief Function doing End processing. - */ -//Fixme: support OAM (hop-by-hop header) here! -static_always_inline void -end_srh_processing (vlib_node_runtime_t * node, - vlib_buffer_t * b0, - ip6_header_t * ip0, - ip6_sr_header_t * sr0, - u32 * next0) -{ - ip6_address_t *new_dst0; - - if(PREDICT_TRUE(ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)) - { - if(PREDICT_TRUE(sr0->type == ROUTING_HEADER_TYPE_SR)) - { - if(PREDICT_TRUE(sr0->segments_left != 0)) - { - sr0->segments_left -= 1; - new_dst0 = (ip6_address_t *)(sr0->segments); - new_dst0 += sr0->segments_left; - ip0->dst_address.as_u64[0] = new_dst0->as_u64[0]; - ip0->dst_address.as_u64[1] = new_dst0->as_u64[1]; - } - else - { - *next0 = SRV6_SAMPLE_LOCALSID_NEXT_ERROR; - b0->error = node->errors[SRV6_LOCALSID_COUNTER_NO_SRH]; - } - } - else - { - /* Error. Routing header of type != SR */ - *next0 = SRV6_SAMPLE_LOCALSID_NEXT_ERROR; - b0->error = node->errors[SRV6_LOCALSID_COUNTER_NO_SRH]; - } - } -} - -/* - * @brief SRv6 Sample Localsid graph node - * WARNING: YOU MUST DO THE DUAL LOOP - */ -static uword -srv6_localsid_sample_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) -{ - u32 n_left_from, * from, * to_next; - u32 next_index; - u32 pkts_swapped = 0; - - ip6_sr_main_t * sm = &sr_main; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - u32 cpu_index = os_get_cpu_number (); - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, - to_next, n_left_to_next); - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t * b0; - ip6_header_t * ip0 = 0; - ip6_sr_header_t * sr0; - u32 next0 = SRV6_SAMPLE_LOCALSID_NEXT_IP6LOOKUP; - ip6_sr_localsid_t *ls0; - srv6_localsid_sample_per_sid_memory_t *ls0_mem; - - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - ip0 = vlib_buffer_get_current (b0); - sr0 = (ip6_sr_header_t *)(ip0+1); - - /* Lookup the SR End behavior based on IP DA (adj) */ - ls0 = pool_elt_at_index (sm->localsids, vnet_buffer(b0)->ip.adj_index[VLIB_TX]); - ls0_mem = ls0->plugin_mem; - - /* SRH processing */ - end_srh_processing (node, b0, ip0, sr0, &next0); - - /* ==================================================================== */ - /* INSERT CODE HERE */ - /* Example starts here */ - //In this example we are changing the next VRF table by the one in CLI - vnet_buffer(b0)->sw_if_index[VLIB_TX] = ls0_mem->fib_table; - /* Example finishes here */ - /* ==================================================================== */ - - if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) - { - srv6_localsid_sample_trace_t *tr = vlib_add_trace (vm, node, b0, sizeof (*tr)); - tr->localsid_index = ls0 - sm->localsids; - } - - /* This increments the SRv6 per LocalSID counters.*/ - vlib_increment_combined_counter - (((next0 == SRV6_SAMPLE_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) : &(sm->sr_ls_valid_counters)), - cpu_index, - ls0 - sm->localsids, - 1, vlib_buffer_length_in_chain (vm, b0)); - - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, bi0, next0); - - pkts_swapped ++; - } - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - - } - - return frame->n_vectors; -} - -VLIB_REGISTER_NODE (srv6_localsid_sample_node) = { - .function = srv6_localsid_sample_fn, - .name = "srv6-localsid-sample", - .vector_size = sizeof (u32), - .format_trace = format_srv6_localsid_sample_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = SRV6_LOCALSID_N_COUNTERS, - .error_strings = srv6_localsid_counter_strings, - .n_next_nodes = SRV6_SAMPLE_LOCALSID_N_NEXT, - .next_nodes = { - [SRV6_SAMPLE_LOCALSID_NEXT_IP6LOOKUP] = "ip6-lookup", - [SRV6_SAMPLE_LOCALSID_NEXT_ERROR] = "error-drop", - }, -}; diff --git a/src/plugins/srv6-localsid/srv6_localsid_sample.c b/src/plugins/srv6-localsid/srv6_localsid_sample.c deleted file mode 100755 index ec16547e..00000000 --- a/src/plugins/srv6-localsid/srv6_localsid_sample.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - *------------------------------------------------------------------ - * srv6_localsid_sample.c - Simple SRv6 LocalSID - *------------------------------------------------------------------ - */ - -#include -#include -#include - -#include -#include -#include - -unsigned char srv6_localsid_name[32] = "Sample-SRv6-LocalSID-plugin"; -unsigned char keyword_str[32] = "new_srv6_localsid"; -unsigned char def_str[64] = "This is a definition of a sample new_srv6_localsid"; -unsigned char params_str[32] = ""; - -/*****************************************/ -/* SRv6 LocalSID instantiation and removal functions */ -static int -srv6_localsid_creation_fn (ip6_sr_localsid_t *localsid) -{ - /* - * Do you want to do anything fancy upon localsid instantiation? - * You can do it here - * (If return != 0 the localsid creation will be cancelled.) - */ - /* As an example Im going to do a +1 to the fib table inserted by the user */ - srv6_localsid_sample_per_sid_memory_t *ls_mem = localsid->plugin_mem; - ls_mem->fib_table += 1; - return 0; -} - -static int -srv6_localsid_removal_fn (ip6_sr_localsid_t *localsid) -{ - /* Do you want to do anything fancy upon localsid removal? - * You can do it here - * (If return != 0 the localsid removal will be cancelled.) - */ - /* - * BTW if you stored something in localsid->plugin_mem you should clean it now - */ - - //In this example we are only cleaning the memory allocated per localsid - clib_mem_free(localsid->plugin_mem); - return 0; -} - -/**********************************/ -/* SRv6 LocalSID format functions */ -/* - * Prints nicely the parameters of a localsid - * Example: print "Table 5" - */ -u8 * -format_srv6_localsid_sample (u8 * s, va_list * args) -{ - srv6_localsid_sample_per_sid_memory_t *ls_mem = va_arg (*args, void *); - return (format (s, "Table: %u", ls_mem->fib_table)); -} - -/* - * Process the parameters of a localsid - * Example: process from: - * sr localsid address cafe::1 behavior new_srv6_localsid 5 - * everything from behavior on... so in this case 'new_srv6_localsid 5' - * Notice that it MUST match the keyword_str and params_str defined above. - */ -uword -unformat_srv6_localsid_sample (unformat_input_t * input, va_list * args) -{ - void **plugin_mem = va_arg (*args, void **); - srv6_localsid_sample_per_sid_memory_t *ls_mem; - u32 table_id; - if (unformat (input, "new_srv6_localsid %u", &table_id)) - { - /* Allocate a portion of memory */ - ls_mem = clib_mem_alloc_aligned_at_offset ( - sizeof(srv6_localsid_sample_per_sid_memory_t), 0, 0, 1); - - /* Set to zero the memory */ - memset (ls_mem, 0, sizeof(srv6_localsid_sample_per_sid_memory_t)); - - /* Our brand-new car is ready */ - ls_mem->fib_table = table_id; - - /* Dont forget to add it to the localsid */ - *plugin_mem = ls_mem; - return 1; - } - return 0; -} - -/*************************/ -/* SRv6 LocalSID FIB DPO */ -static u8 * -format_srv6_localsid_sample_dpo (u8 * s, va_list * args) -{ - index_t index = va_arg (*args, index_t); - CLIB_UNUSED (u32 indent) = va_arg (*args, u32); - - return (format (s, "SR: localsid_sample_index:[%u]", index)); -} - -void -srv6_localsid_sample_dpo_lock (dpo_id_t * dpo) -{ -} - -void -srv6_localsid_sample_dpo_unlock (dpo_id_t * dpo) -{ -} - -const static dpo_vft_t srv6_localsid_sample_vft = { - .dv_lock = srv6_localsid_sample_dpo_lock, - .dv_unlock = srv6_localsid_sample_dpo_unlock, - .dv_format = format_srv6_localsid_sample_dpo, -}; - -const static char *const srv6_localsid_sample_ip6_nodes[] = { - "srv6-localsid-sample", - NULL, -}; - -const static char *const *const srv6_localsid_sample_nodes[DPO_PROTO_NUM] = { - [DPO_PROTO_IP6] = srv6_localsid_sample_ip6_nodes, -}; - -/**********************/ -static clib_error_t * srv6_localsid_sample_init (vlib_main_t * vm) -{ - srv6_localsid_sample_main_t * sm = &srv6_localsid_sample_main; - int rv = 0; - /* Create DPO */ - sm->srv6_localsid_sample_dpo_type = dpo_register_new_type ( - &srv6_localsid_sample_vft, srv6_localsid_sample_nodes); - - /* Register SRv6 LocalSID */ - rv = sr_localsid_register_function (vm, - srv6_localsid_name, - keyword_str, - def_str, - params_str, - &sm->srv6_localsid_sample_dpo_type, - format_srv6_localsid_sample, - unformat_srv6_localsid_sample, - srv6_localsid_creation_fn, - srv6_localsid_removal_fn); - if (rv < 0) - clib_error_return (0, "SRv6 LocalSID function could not be registered."); - else - sm->srv6_localsid_behavior_id = rv; - - return 0; -} - -VLIB_INIT_FUNCTION (srv6_localsid_sample_init); - -VLIB_PLUGIN_REGISTER () = { - .version = "1.0", -}; diff --git a/src/plugins/srv6-localsid/srv6_localsid_sample.h b/src/plugins/srv6-localsid/srv6_localsid_sample.h deleted file mode 100644 index 474b5de2..00000000 --- a/src/plugins/srv6-localsid/srv6_localsid_sample.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __included_srv6_localsid_sample_h__ -#define __included_srv6_localsid_sample_h__ - -#include -#include -#include -#include - -#include -#include -#include - -typedef struct { - /* API message ID base */ - u16 msg_id_base; - - /* convenience */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; - - /* DPO type */ - dpo_type_t srv6_localsid_sample_dpo_type; - - /* SRv6 LocalSID behavior number */ - u32 srv6_localsid_behavior_id; - -} srv6_localsid_sample_main_t; - -/* - * This is the memory that will be stored per each localsid - * the user instantiates - */ -typedef struct { - u32 fib_table; /* Stupid index used as an example.. */ -} srv6_localsid_sample_per_sid_memory_t ; - -srv6_localsid_sample_main_t srv6_localsid_sample_main; - -format_function_t format_srv6_localsid_sample; -unformat_function_t unformat_srv6_localsid_sample; - -void srv6_localsid_sample_dpo_lock (dpo_id_t * dpo); -void srv6_localsid_sample_dpo_unlock (dpo_id_t * dpo); - -extern vlib_node_registration_t srv6_localsid_sample_node; - -#endif /* __included_sample_h__ */ diff --git a/src/plugins/srv6-localsid/srv6_sample_localsid_doc.md b/src/plugins/srv6-localsid/srv6_sample_localsid_doc.md deleted file mode 100644 index b60ab5da..00000000 --- a/src/plugins/srv6-localsid/srv6_sample_localsid_doc.md +++ /dev/null @@ -1,38 +0,0 @@ -# SRv6 Sample LocalSID documentation {#srv6_plugin_doc} - -## Disclaimer - -This is a memo intended to contain documentation for the sample SRv6 LocalSID behavior plugin -Everything that is not directly obvious should come here. -For any feedback on content that should be explained please mailto:pcamaril@cisco.com - -This plugin refers to Segment Routing. Please read the SR documentation first. - -## Introduction - -This plugin is an example of how an user can create a new SRv6 LocalSID behavior by using VPP plugins with the appropiate API calls to the existing SR code. - -This **example** plugin registers a new localsid behavior, with cli keyword 'new_srv6_localsid' which only takes one parameter, a fib-table. Upon recival of a packet, this plugin will enforce the next IP6 lookup in the specific fib-table specified by the user. (Indeed it will do the lookup in the fib_table n+1 (since for the shake of the example we increment the fib-table.) - -Notice that the plugin only 'defines' a new SRv6 LocalSID behavior, but the existing SR code in VNET is the one actually instantiating new LocalSIDs. Notice that there are callback functions such that when you create or remove a LocalSID you can actually setup specific parameters through the functions in this plugin. - -## Variables to watch for - -* srv6_localsid_name: This variable is the name (used as a unique key) identifying this SR LocalSID plugin. -* keyword_str: This is the CLI keyword to be used for the plugin. In this example 'new_srv6_localsid'. (i.e. sr localsid address cafe::1 behavior new_srv6_localsid ) -* def_str: This is a definition of this SR behavior. This is printed when you do 'show sr localsid behaviors'. -* params_str: This is a definition of the parameters of this localsid. This is printed when you do 'show sr localsid behaviors'. - -## Functions to watch for - -* srv6_localsid_creation_fn: This function will be called every time a new SR LocalSID is instantiated with the behavior defined in this plugin. -* srv6_localsid_removal_fn: This function will be called every time a new SR LocalSID is removed with the behavior defined in this plugin. This function tends to be used for freeing up all the memory created in the previous function. -* format_srv6_localsid_sample: This function prints nicely the parameters of every SR LocalSID using this behavior. -* unformat_srv6_localsid_sample: This function parses the CLI command when initialising a new SR LocalSID using this behavior. It parses all the parameters and ensures that the parameters are correct. -* format_srv6_localsid_sample_dpo: This function formats the 'show ip6 fib' message for the SR LocalSIDs created with this plugin behavior. - -## Graph node - -The current graph node uses the function 'end_srh_processing' to do the Segment Routing Endpoint behavior. Notice that it does not allow the cleanup of a Segment Routing header (as per the SRv6 behavior specs). -This function is identical to the one found in /src/vnet/sr/sr_localsid.c -In case that by some other reason you want to do decapsulation, or SRH clean_up you can use the functions 'end_decaps_srh_processing' or 'end_psp_srh_processing' respectively. diff --git a/src/vnet/sr/sr.h b/src/vnet/sr/sr.h index 5efeb4dd..b832c0fc 100755 --- a/src/vnet/sr/sr.h +++ b/src/vnet/sr/sr.h @@ -173,6 +173,7 @@ typedef struct } l2; }; u8 traffic_type; /**< Traffic type (IPv4, IPv6, L2) */ + u8 padding[3]; } sr_steering_key_t; typedef struct @@ -186,46 +187,29 @@ typedef struct */ typedef struct { - /* ip6-lookup next index for imposition FIB entries */ - u32 ip6_lookup_sr_next_index; - - /* ip6-replicate next index for multicast tunnel */ - u32 ip6_lookup_sr_spray_index; - - /* IP4-lookup -> SR rewrite next index */ - u32 ip4_lookup_sr_policy_rewrite_encaps_index; - u32 ip4_lookup_sr_policy_rewrite_insert_index; - - /* IP6-lookup -> SR rewrite next index */ - u32 ip6_lookup_sr_policy_rewrite_encaps_index; - u32 ip6_lookup_sr_policy_rewrite_insert_index; - /* L2-input -> SR rewrite next index */ u32 l2_sr_policy_rewrite_index; - /* IP6-lookup -> SR LocalSID (SR End processing) index */ - u32 ip6_lookup_sr_localsid_index; - /* SR SID lists */ ip6_sr_sl_t *sid_lists; /* SR policies */ ip6_sr_policy_t *sr_policies; - /* Find an SR policy by its BindingSID */ - ip6_address_t *sr_policy_index_by_key; + /* Hash table mapping BindingSID to SR policy */ + mhash_t sr_policies_index_hash; /* Pool of SR localsid instances */ ip6_sr_localsid_t *localsids; - /* Find a SR localsid instance based on its functionID */ - ip6_address_t *localsids_index_by_key; + /* Hash table mapping LOC:FUNC to SR LocalSID instance */ + mhash_t sr_localsids_index_hash; /* Pool of SR steer policies instances */ ip6_sr_steering_policy_t *steer_policies; - /* Find a steer policy based on its classifier */ - sr_steering_key_t *steer_policies_index_by_key; + /* Hash table mapping steering rules to SR steer instance */ + mhash_t sr_steer_policies_hash; /* L2 steering ifaces - sr_policies */ u32 *sw_iface_sr_policies; diff --git a/src/vnet/sr/sr_doc.md b/src/vnet/sr/sr_doc.md index a7220630..fd92bdf2 100644 --- a/src/vnet/sr/sr_doc.md +++ b/src/vnet/sr/sr_doc.md @@ -1,6 +1,6 @@ -# SRv6: Segment Routing for IPv6 {#sr_doc} +# SRv6: Segment Routing for IPv6 {#srv6_doc} -This is a memo intended to contain documentation of the VPP SRv6 implementation +This is a memo intended to contain documentation of the VPP SRv6 implementation. Everything that is not directly obvious should come here. For any feedback on content that should be explained please mailto:pcamaril@cisco.com @@ -27,135 +27,29 @@ Segment routing can operate with either an MPLS or an IPv6 data plane. All the c * Local SID: is a SID associated with a processing function on the local node, which may go from advancing to the next SID in the SRH, to complex user-defined behaviors. When a FIB lookup, either in the main FIB or in a specific VRF, returns a match on a local SID, the associated function is performed. * BindingSID: a BindingSID is a SID (only one) associated one-one with an SR Policy. If a packet arrives with an IPv6 DA corresponding to a BindingSID, then the SR policy will be applied to such packet. -## Creating an SR LocalSID +## SRv6 Features in VPP -A local SID is associated to a Segment Routing behavior -or function- on the current node. +The SRv6 Network Programming (*draft-filsfils-spring-srv6-network-programming*) defines the SRv6 architecture. -The most basic behavior is called END. It simply activates the next SID in the current packet, by decrementing the Segments Left value and updating the IPv6 DA. +VPP supports the following SRv6 LocalSID functions: End, End.X, End.DX6, End.DT6, End.DX4, End.DT4, End.DX2, End.B6, End.B6.Encaps. -A local END SID is instantiated using the following CLI: +For further information and how to configure each specific function: @subpage srv6_localsid_doc - sr localsid (del) address XX::YY behavior end -This creates a new entry in the main FIB for IPv6 address XX::YY. All packets whose IPv6 DA matches this FIB entry are redirected to the sr-localsid node, where they are processed as described above. +The Segment Routing Policy (*draft-filsfils-spring-segment-routing-policy*) defines SR Policies. -Other examples of local SIDs are the following: +VPP supports SRv6 Policies with T.Insert and T.Encaps behaviors. - sr localsid (del) address XX::YY behavior end (psp) - sr localsid (del) address XX::YY behavior end.x GE0/1/0 2001::a (psp) - sr localsid (del) address XX::YY behavior end.dx6 GE0/1/0 2001::a - sr localsid (del) address XX::YY behavior end.dx4 GE0/1/0 10.0.0.1 - sr localsid (del) address XX::YY behavior end.dx2 GigabitE0/11/0 - sr localsid (del) address XX::YY behavior end.dt6 5 - sr localsid (del) address XX::YY behavior end.dt6 5 +For further information on how to create SR Policies: @subpage srv6_policy_doc -Note that all of these behaviors match the specifications in **TODO REF NET PGM**. Please refer to this document for a detailed description of each behavior. +For further information on how to steer traffic into SR Policies: @subpage srv6_steering_doc -Help on the available local SID behaviors and their usage can be obtained with: - - help sr localsid +## SRv6 LocalSID development framework -Alternatively they can be obtained using. - - show sr localsids behavior - -The difference in between those two commands is that the first one will only display the SR LocalSID behaviors that are built-in VPP, while the latter will display those behaviors plus the ones added with the SR LocalSID Development Framework. - - -VPP keeps a 'My LocalSID Table' where it stores all the SR local SIDs instantiated as well as their parameters. Every time a new local SID is instantiated, a new entry is added to this table. In addition, counters for correctly and incorrectly processed traffic are maintained for each local SID. The counters store both the number of packets and bytes. - -The contents of the 'My LocalSID Table' is shown with: - - vpp# show sr localsid - SRv6 - My LocalSID Table: - ========================= - Address: c3::1 - Behavior: DX6 (Endpoint with decapsulation and IPv6 cross-connect) - Iface: GigabitEthernet0/5/0 - Next hop: b:c3::b - Good traffic: [51277 packets : 5332808 bytes] - Bad traffic: [0 packets : 0 bytes] - -------------------- - -The traffic counters can be reset with: - - vpp# clear sr localsid counters - -## Creating a SR Policy - -An SR Policy is defined by a Binding SID and a weighted set of Segment Lists. - -A new SR policy is created with a first SID list using: - - sr policy add bsid 2001::1 next A1:: next B1:: next C1:: (weight 5) (fib-table 3) - -* The weight parameter is only used if more than one SID list is associated with the policy. -* The fib-table parameter specifies in which table (VRF) the Binding SID is to be installed. - -An SR policy is deleted with: - - sr policy del bsid 2001::1 - sr policy del index 1 - -The existing SR policies are listed with: - - show sr policies - -### Adding/Removing SID Lists from an SR policy - -An additional SID list is associated with an existing SR policy with: - - sr policy mod bsid 2001::1 add sl next A2:: next B2:: next C2:: (weight 3) - sr policy mod index 3 add sl next A2:: next B2:: next C2:: (weight 3) - -Conversely, a SID list can be removed from an SR policy with: - - sr policy mod bsid 2001::1 del sl index 1 - sr policy mod index 3 del sl index 1 - -Note that this cannot be used to remove the last SID list of a policy. - -The weight of a SID list can also be modified with: - - sr policy mod bsid 2001::1 mod sl index 1 weight 4 - sr policy mod index 3 mod sl index 1 weight 4 - -### SR Policies: Spray policies - -Spray policies are a specific type of SR policies where the packet is replicated on all the SID lists, rather than load-balanced among them. - -SID list weights are ignored with this type of policies. - -A Spray policy is instantiated by appending the keyword **spray** to a regular SR policy command, as in: - - sr policy add bsid 2001::1 next A1:: next B1:: next C1:: spray - -Spray policies are used for removing multicast state from a network core domain, and instead send a linear unicast copy to every access node. The last SID in each list accesses the multicast tree within the access node. - -### Encapsulation SR policies - -In case the user decides to create an SR policy an IPv6 Source Address must be specified for the encapsulated traffic. In order to do so the user might use the following command: - - set sr encaps source addr XXXX::YYYY - -## Steering packets into a SR Policy - -To steer packets in Transit into an SR policy (T.Insert, T.Encaps and T.Encaps.L2 behaviors), the user needs to create an 'sr steering policy'. - - sr steer l3 2001::/64 via sr policy index 1 - sr steer l3 2001::/64 via sr policy bsid cafe::1 - sr steer l3 2001::/64 via sr policy bsid cafe::1 fib-table 3 - sr steer l3 10.0.0.0/16 via sr policy bsid cafe::1 - sr steer l2 TenGE0/1/0 via sr policy bsid cafe::1 - -Disclaimer: The T.Encaps.L2 will steer L2 frames into an SR Policy. Notice that creating an SR steering policy for L2 frames will actually automatically *puts the interface into promiscous mode*. - -## SR LocalSID development framework - -One of the * 'key' * concepts about SRv6 is regarding network programmability. This is why an SRv6 LocalSID is associated with an specific function. +One of the *'key'* concepts about SRv6 is network programmability. This is why an SRv6 LocalSID is associated with an specific function. However, the trully way to enable network programmability is allowing any developer **easily** create his own SRv6 LocalSID function. That is the reason why we have added some API calls such that any developer can code his own SRv6 LocalSID behaviors as plugins an add them to the running SRv6 code. The principle is that the developer only codes the behavior -the graph node-. However all the FIB handling, SR LocalSID instantiation and so on are done by the VPP SRv6 code. -For more information please refer to the documentation *SRv6 Sample SR LocalSID plugin*. +For more information please refer to: @subpage srv6_plugin_doc diff --git a/src/vnet/sr/sr_localsid.c b/src/vnet/sr/sr_localsid.c index 610bb7ff..2e3d56de 100755 --- a/src/vnet/sr/sr_localsid.c +++ b/src/vnet/sr/sr_localsid.c @@ -72,18 +72,16 @@ sr_cli_localsid (char is_del, ip6_address_t * localsid_addr, int rv; ip6_sr_localsid_t *ls = 0; - ip6_address_t *key_copy; dpo_id_t dpo = DPO_INVALID; /* Search for the item */ - p = hash_get_mem (sm->localsids_index_by_key, localsid_addr); + p = mhash_get (&sm->sr_localsids_index_hash, localsid_addr); if (p) { if (is_del) { - hash_pair_t *hp; /* Retrieve localsid */ ls = pool_elt_at_index (sm->localsids, p[0]); /* Delete FIB entry */ @@ -116,10 +114,7 @@ sr_cli_localsid (char is_del, ip6_address_t * localsid_addr, /* Delete localsid registry */ pool_put (sm->localsids, ls); - hp = hash_get_pair (sm->localsids_index_by_key, localsid_addr); - key_copy = (void *) (hp->key); - hash_unset_mem (sm->localsids_index_by_key, localsid_addr); - vec_free (key_copy); + mhash_unset (&sm->sr_localsids_index_hash, localsid_addr, NULL); return 1; } else /* create with function already existing; complain */ @@ -232,9 +227,8 @@ sr_cli_localsid (char is_del, ip6_address_t * localsid_addr, } /* Set hash key for searching localsid by address */ - key_copy = vec_new (ip6_address_t, 1); - clib_memcpy (key_copy, localsid_addr, sizeof (ip6_address_t)); - hash_set_mem (sm->localsids_index_by_key, key_copy, ls - sm->localsids); + mhash_set (&sm->sr_localsids_index_hash, localsid_addr, ls - sm->localsids, + NULL); fib_table_entry_special_dpo_add (fib_index, &pfx, FIB_SOURCE_SR, FIB_ENTRY_FLAG_EXCLUSIVE, &dpo); @@ -1476,8 +1470,8 @@ sr_localsids_init (vlib_main_t * vm) { /* Init memory for function keys */ ip6_sr_main_t *sm = &sr_main; - sm->localsids_index_by_key = - hash_create_mem (0, sizeof (ip6_address_t), sizeof (uword)); + mhash_init (&sm->sr_localsids_index_hash, sizeof (uword), + sizeof (ip6_address_t)); /* Init SR behaviors DPO type */ sr_localsid_dpo_type = dpo_register_new_type (&sr_loc_vft, sr_loc_nodes); /* Init SR behaviors DPO type */ diff --git a/src/vnet/sr/sr_localsid.md b/src/vnet/sr/sr_localsid.md new file mode 100644 index 00000000..340af4a3 --- /dev/null +++ b/src/vnet/sr/sr_localsid.md @@ -0,0 +1,58 @@ +# SR LocalSIDs {#srv6_localsid_doc} + +A local SID is associated to a Segment Routing behavior -or function- on the current node. + +The most basic behavior is called END. It simply activates the next SID in the current packet, by decrementing the Segments Left value and updating the IPv6 DA. + +A local END SID is instantiated using the following CLI: + + sr localsid (del) address XX::YY behavior end + +This creates a new entry in the main FIB for IPv6 address XX::YY. All packets whose IPv6 DA matches this FIB entry are redirected to the sr-localsid node, where they are processed as described above. + +Other examples of local SIDs are the following: + + sr localsid (del) address XX::YY behavior end + sr localsid (del) address XX::YY behavior end.x GE0/1/0 2001::a + sr localsid (del) address XX::YY behavior end.dx6 GE0/1/0 2001::a + sr localsid (del) address XX::YY behavior end.dx4 GE0/1/0 10.0.0.1 + sr localsid (del) address XX::YY behavior end.dx2 GigabitE0/11/0 + sr localsid (del) address XX::YY behavior end.dt6 5 + sr localsid (del) address XX::YY behavior end.dt6 5 + +Note that all of these behaviors match the definitions of the SRv6 architecture (*draft-filsfils-spring-srv6-network-programming*). Please refer to this document for a detailed description of each behavior. + +Note also that you can configure the PSP flavor of the End and End.X behaviors by typing: + + sr localsid (del) address XX::YY behavior end psp + sr localsid (del) address XX::YY behavior end.x GE0/1/0 2001::a psp + +Help on the available local SID behaviors and their usage can be obtained with: + + help sr localsid + +Alternatively they can be obtained using. + + show sr localsids behavior + +The difference in between those two commands is that the first one will only display the SR LocalSID behaviors that are built-in VPP, while the latter will display those behaviors plus the ones added with the SR LocalSID Development Framework. + + +VPP keeps a 'My LocalSID Table' where it stores all the SR local SIDs instantiated as well as their parameters. Every time a new local SID is instantiated, a new entry is added to this table. In addition, counters for correctly and incorrectly processed traffic are maintained for each local SID. The counters store both the number of packets and bytes. + +The contents of the 'My LocalSID Table' is shown with: + + vpp# show sr localsid + SRv6 - My LocalSID Table: + ========================= + Address: c3::1 + Behavior: DX6 (Endpoint with decapsulation and IPv6 cross-connect) + Iface: GigabitEthernet0/5/0 + Next hop: b:c3::b + Good traffic: [51277 packets : 5332808 bytes] + Bad traffic: [0 packets : 0 bytes] + -------------------- + +The traffic counters can be reset with: + + vpp# clear sr localsid counters diff --git a/src/vnet/sr/sr_policy.md b/src/vnet/sr/sr_policy.md new file mode 100644 index 00000000..521b8461 --- /dev/null +++ b/src/vnet/sr/sr_policy.md @@ -0,0 +1,56 @@ +# Creating a SR Policy {#srv6_policy_doc} + +An SR Policy is defined by a Binding SID and a weighted set of Segment Lists. + +A new SR policy is created with a first SID list using: + + sr policy add bsid 2001::1 next A1:: next B1:: next C1:: (weight 5) (fib-table 3) + +* The weight parameter is only used if more than one SID list is associated with the policy. +* The fib-table parameter specifies in which table (VRF) the Binding SID is to be installed. + +An SR policy is deleted with: + + sr policy del bsid 2001::1 + sr policy del index 1 + +The existing SR policies are listed with: + + show sr policies + +## Adding/Removing SID Lists from an SR policy + +An additional SID list is associated with an existing SR policy with: + + sr policy mod bsid 2001::1 add sl next A2:: next B2:: next C2:: (weight 3) + sr policy mod index 3 add sl next A2:: next B2:: next C2:: (weight 3) + +Conversely, a SID list can be removed from an SR policy with: + + sr policy mod bsid 2001::1 del sl index 1 + sr policy mod index 3 del sl index 1 + +Note that this cannot be used to remove the last SID list of a policy. + +The weight of a SID list can also be modified with: + + sr policy mod bsid 2001::1 mod sl index 1 weight 4 + sr policy mod index 3 mod sl index 1 weight 4 + +## SR Policies: Spray policies + +Spray policies are a specific type of SR policies where the packet is replicated on all the SID lists, rather than load-balanced among them. + +SID list weights are ignored with this type of policies. + +A Spray policy is instantiated by appending the keyword **spray** to a regular SR policy command, as in: + + sr policy add bsid 2001::1 next A1:: next B1:: next C1:: spray + +Spray policies are used for removing multicast state from a network core domain, and instead send a linear unicast copy to every access node. The last SID in each list accesses the multicast tree within the access node. + +## Encapsulation SR policies + +In case the user decides to create an SR policy an IPv6 Source Address must be specified for the encapsulated traffic. In order to do so the user might use the following command: + + set sr encaps source addr XXXX::YYYY diff --git a/src/vnet/sr/sr_policy_rewrite.c b/src/vnet/sr/sr_policy_rewrite.c index dfdd7950..de6c1616 100755 --- a/src/vnet/sr/sr_policy_rewrite.c +++ b/src/vnet/sr/sr_policy_rewrite.c @@ -349,6 +349,7 @@ update_lb (ip6_sr_policy_t * sr_policy) ip6_sr_sl_t *segment_list; ip6_sr_main_t *sm = &sr_main; load_balance_path_t path; + path.path_index = FIB_NODE_INDEX_INVALID; load_balance_path_t *ip4_path_vector = 0; load_balance_path_t *ip6_path_vector = 0; load_balance_path_t *b_path_vector = 0; @@ -447,6 +448,7 @@ update_replicate (ip6_sr_policy_t * sr_policy) ip6_sr_sl_t *segment_list; ip6_sr_main_t *sm = &sr_main; load_balance_path_t path; + path.path_index = FIB_NODE_INDEX_INVALID; load_balance_path_t *b_path_vector = 0; load_balance_path_t *ip6_path_vector = 0; load_balance_path_t *ip4_path_vector = 0; @@ -548,11 +550,10 @@ sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments, { ip6_sr_main_t *sm = &sr_main; ip6_sr_policy_t *sr_policy = 0; - ip6_address_t *key_copy; uword *p; /* Search for existing keys (BSID) */ - p = hash_get_mem (sm->sr_policy_index_by_key, bsid); + p = mhash_get (&sm->sr_policies_index_hash, bsid); if (p) { /* Add SR policy that already exists; complain */ @@ -592,10 +593,8 @@ sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments, sr_policy->is_encap = is_encap; /* Copy the key */ - key_copy = vec_new (ip6_address_t, 1); - clib_memcpy (key_copy, bsid, sizeof (ip6_address_t)); - hash_set_mem (sm->sr_policy_index_by_key, key_copy, - sr_policy - sm->sr_policies); + mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies, + NULL); /* Create a segment list and add the index to the SR policy */ create_sl (sr_policy, segments, weight, is_encap); @@ -635,14 +634,12 @@ sr_policy_del (ip6_address_t * bsid, u32 index) ip6_sr_main_t *sm = &sr_main; ip6_sr_policy_t *sr_policy = 0; ip6_sr_sl_t *segment_list; - ip6_address_t *key_copy; u32 *sl_index; uword *p; - hash_pair_t *hp; if (bsid) { - p = hash_get_mem (sm->sr_policy_index_by_key, bsid); + p = mhash_get (&sm->sr_policies_index_hash, bsid); if (p) sr_policy = pool_elt_at_index (sm->sr_policies, p[0]); else @@ -692,14 +689,11 @@ sr_policy_del (ip6_address_t * bsid, u32 index) } /* Remove SR policy entry */ - hp = hash_get_pair (sm->sr_policy_index_by_key, &sr_policy->bsid); - key_copy = (void *) (hp->key); - hash_unset_mem (sm->sr_policy_index_by_key, &sr_policy->bsid); - vec_free (key_copy); + mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL); pool_put (sm->sr_policies, sr_policy); /* If FIB empty unlock it */ - if (!pool_elts (sm->sr_policies)) + if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies)) { fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6); fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6); @@ -741,7 +735,7 @@ sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table, if (bsid) { - p = hash_get_mem (sm->sr_policy_index_by_key, bsid); + p = mhash_get (&sm->sr_policies_index_hash, bsid); if (p) sr_policy = pool_elt_at_index (sm->sr_policies, p[0]); else @@ -3208,8 +3202,8 @@ sr_policy_rewrite_init (vlib_main_t * vm) ip6_sr_main_t *sm = &sr_main; /* Init memory for sr policy keys (bsid <-> ip6_address_t) */ - sm->sr_policy_index_by_key = hash_create_mem (0, sizeof (ip6_address_t), - sizeof (uword)); + mhash_init (&sm->sr_policies_index_hash, sizeof (uword), + sizeof (ip6_address_t)); /* Init SR VPO DPOs type */ sr_pr_encaps_dpo_type = diff --git a/src/vnet/sr/sr_steering.c b/src/vnet/sr/sr_steering.c index 86d6f27c..be1bb7ad 100755 --- a/src/vnet/sr/sr_steering.c +++ b/src/vnet/sr/sr_steering.c @@ -62,14 +62,14 @@ sr_steering_policy (int is_del, ip6_address_t * bsid, u32 sr_policy_index, u32 sw_if_index, u8 traffic_type) { ip6_sr_main_t *sm = &sr_main; - sr_steering_key_t key, *key_copy; + sr_steering_key_t key; ip6_sr_steering_policy_t *steer_pl; fib_prefix_t pfx = { 0 }; ip6_sr_policy_t *sr_policy = 0; uword *p = 0; - hash_pair_t *hp; + memset (&key, 0, sizeof (sr_steering_key_t)); /* Compute the steer policy key */ if (prefix) @@ -78,6 +78,8 @@ sr_steering_policy (int is_del, ip6_address_t * bsid, u32 sr_policy_index, key.l3.prefix.as_u64[1] = prefix->as_u64[1]; key.l3.mask_width = mask_width; key.l3.fib_table = (table_id != (u32) ~ 0 ? table_id : 0); + if (traffic_type != SR_STEER_IPV4 && traffic_type != SR_STEER_IPV6) + return -1; } else { @@ -92,12 +94,14 @@ sr_steering_policy (int is_del, ip6_address_t * bsid, u32 sr_policy_index, vnet_get_sw_interface (sm->vnet_main, sw_if_index); if (sw->type != VNET_SW_INTERFACE_TYPE_HARDWARE) return -3; + if (traffic_type != SR_STEER_L2) + return -1; } key.traffic_type = traffic_type; /* Search for the item */ - p = hash_get_mem (sm->steer_policies_index_by_key, &key); + p = mhash_get (&sm->sr_steer_policies_hash, &key); if (p) { @@ -152,10 +156,17 @@ sr_steering_policy (int is_del, ip6_address_t * bsid, u32 sr_policy_index, /* Delete SR steering policy entry */ pool_put (sm->steer_policies, steer_pl); - hp = hash_get_pair (sm->steer_policies_index_by_key, &key); - key_copy = (void *) (hp->key); - hash_unset_mem (sm->steer_policies_index_by_key, &key); - vec_free (key_copy); + mhash_unset (&sm->sr_steer_policies_hash, &key, NULL); + + /* If no more SR policies or steering policies */ + if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies)) + { + fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6); + fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6); + sm->fib_table_ip6 = (u32) ~ 0; + sm->fib_table_ip4 = (u32) ~ 0; + } + return 1; } else /* It means user requested to update an existing SR steering policy */ @@ -163,7 +174,7 @@ sr_steering_policy (int is_del, ip6_address_t * bsid, u32 sr_policy_index, /* Retrieve SR steering policy */ if (bsid) { - p = hash_get_mem (sm->sr_policy_index_by_key, bsid); + p = mhash_get (&sm->sr_policies_index_hash, bsid); if (p) sr_policy = pool_elt_at_index (sm->sr_policies, p[0]); else @@ -192,7 +203,6 @@ sr_steering_policy (int is_del, ip6_address_t * bsid, u32 sr_policy_index, /* Create a new one */ goto update_fib; - } else if (steer_pl->classify.traffic_type == SR_STEER_IPV4) { @@ -224,7 +234,7 @@ sr_steering_policy (int is_del, ip6_address_t * bsid, u32 sr_policy_index, /* Retrieve SR policy */ if (bsid) { - p = hash_get_mem (sm->sr_policy_index_by_key, bsid); + p = mhash_get (&sm->sr_policies_index_hash, bsid); if (p) sr_policy = pool_elt_at_index (sm->sr_policies, p[0]); else @@ -255,19 +265,14 @@ sr_steering_policy (int is_del, ip6_address_t * bsid, u32 sr_policy_index, { /* Incorrect API usage. Should never get here */ pool_put (sm->steer_policies, steer_pl); - hp = hash_get_pair (sm->steer_policies_index_by_key, &key); - key_copy = (void *) (hp->key); - hash_unset_mem (sm->steer_policies_index_by_key, &key); - vec_free (key_copy); + mhash_unset (&sm->sr_steer_policies_hash, &key, NULL); return -1; } steer_pl->sr_policy = sr_policy - sm->sr_policies; /* Create and store key */ - key_copy = vec_new (sr_steering_key_t, 1); - clib_memcpy (key_copy, &key, sizeof (sr_steering_key_t)); - hash_set_mem (sm->steer_policies_index_by_key, - key_copy, steer_pl - sm->steer_policies); + mhash_set (&sm->sr_steer_policies_hash, &key, steer_pl - sm->steer_policies, + NULL); if (traffic_type == SR_STEER_L2) { @@ -345,18 +350,12 @@ update_fib: cleanup_error_encap: pool_put (sm->steer_policies, steer_pl); - hp = hash_get_pair (sm->steer_policies_index_by_key, &key); - key_copy = (void *) (hp->key); - hash_unset_mem (sm->steer_policies_index_by_key, &key); - vec_free (key_copy); + mhash_unset (&sm->sr_steer_policies_hash, &key, NULL); return -5; cleanup_error_redirection: pool_put (sm->steer_policies, steer_pl); - hp = hash_get_pair (sm->steer_policies_index_by_key, &key); - key_copy = (void *) (hp->key); - hash_unset_mem (sm->steer_policies_index_by_key, &key); - vec_free (key_copy); + mhash_unset (&sm->sr_steer_policies_hash, &key, NULL); return -3; } @@ -379,6 +378,8 @@ sr_steer_policy_command_fn (vlib_main_t * vm, unformat_input_t * input, u8 sr_policy_set = 0; + memset (&prefix, 0, sizeof (ip46_address_t)); + int rv; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { @@ -450,7 +451,7 @@ sr_steer_policy_command_fn (vlib_main_t * vm, unformat_input_t * input, "Unable to do SW redirect. Incorrect interface."); case -4: return clib_error_return (0, - "The requested SR policy could not be deleted. Review the BSID/index."); + "The requested SR steering policy could not be deleted."); case -5: return clib_error_return (0, "The SR policy is not an encapsulation one."); @@ -541,8 +542,8 @@ sr_steering_init (vlib_main_t * vm) ip6_sr_main_t *sm = &sr_main; /* Init memory for function keys */ - sm->steer_policies_index_by_key = - hash_create_mem (0, sizeof (sr_steering_key_t), sizeof (uword)); + mhash_init (&sm->sr_steer_policies_hash, sizeof (uword), + sizeof (sr_steering_key_t)); sm->sw_iface_sr_policies = 0; diff --git a/src/vnet/sr/sr_steering.md b/src/vnet/sr/sr_steering.md new file mode 100644 index 00000000..cf446f81 --- /dev/null +++ b/src/vnet/sr/sr_steering.md @@ -0,0 +1,11 @@ +# Steering packets into a SR Policy {#srv6_steering_doc} + +To steer packets in Transit into an SR policy (T.Insert, T.Encaps and T.Encaps.L2 behaviors), the user needs to create an 'sr steering policy'. + + sr steer l3 2001::/64 via sr policy index 1 + sr steer l3 2001::/64 via sr policy bsid cafe::1 + sr steer l3 2001::/64 via sr policy bsid cafe::1 fib-table 3 + sr steer l3 10.0.0.0/16 via sr policy bsid cafe::1 + sr steer l2 TenGE0/1/0 via sr policy bsid cafe::1 + +Disclaimer: The T.Encaps.L2 will steer L2 frames into an SR Policy. Notice that creating an SR steering policy for L2 frames will actually automatically *put the interface into promiscous mode*. -- cgit 1.2.3-korg From 3335693cc1afe6742e9a5e726a682dd28b0ce4d4 Mon Sep 17 00:00:00 2001 From: Chris Luke Date: Wed, 10 May 2017 11:40:27 -0400 Subject: doxygen: Fix some paths - Add missing src dir. - Exclude 'src/examples' from siphon processing so that example cli commands don't end up in user documentation. Change-Id: I46a6ad759fa8220d305b007a9506956365fc79bd Signed-off-by: Chris Luke --- doxygen/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'doxygen/Makefile') diff --git a/doxygen/Makefile b/doxygen/Makefile index 9caa4079..abaca185 100644 --- a/doxygen/Makefile +++ b/doxygen/Makefile @@ -54,6 +54,7 @@ DOXY_SRC_DIRECTORIES = \ $(DOXY_SRC)/vnet \ $(DOXY_SRC)/vpp \ $(DOXY_SRC)/vpp-api \ + $(DOXY_SRC)/uri \ $(DOXY_SRC)/examples # Input directories and files @@ -72,7 +73,7 @@ DOXY_INPUT := $(subst $(WS_ROOT)/,,$(DOXY_INPUT)) # there's a DPDK equivalent that conflicts. # These must be left-anchored paths for the regexp below to work. DOXY_EXCLUDE ?= \ - $(DOXY_SRC)/vlib/vlib/buffer.c \ + $(DOXY_SRC)/vlib/buffer.c \ $(DOXY_SRC)/vpp-api/lua \ $(DOXY_SRC)/examples/sample-plugin @@ -204,6 +205,7 @@ $(SIPHON_FILES): $(BR)/.doxygen-bootstrap.ok \ cd "$(WS_ROOT)"; \ find "$$input" -type f \ \( -name '*.[ch]' -or -name '*.dox' \) -print \ + | grep -v -E '^src/examples/' \ | grep -v -E '^$(DOXY_EXCLUDE_REGEXP)' \ >> $(SIPHON_INPUT)/files; \ done -- cgit 1.2.3-korg From 583dc8d3e23a780c85ebe48ea59f0338aad4df17 Mon Sep 17 00:00:00 2001 From: Ray Kinsella Date: Thu, 8 Jun 2017 15:54:19 +0100 Subject: Sample plugin: Add sample plugin documentation Added some user documentation to sample plugin. Change-Id: I518910f80499307e8fcac8dcef7baaeab5ea8e35 Signed-off-by: Ray Kinsella --- README.md | 2 +- doxygen/Makefile | 3 +- doxygen/user_doc.md | 1 + src/examples/sample-plugin/sample/sample.c | 30 ++++++++--- src/examples/sample-plugin/sample_plugin_doc.md | 66 +++++++++++++++++++++++++ 5 files changed, 92 insertions(+), 10 deletions(-) create mode 100644 src/examples/sample-plugin/sample_plugin_doc.md (limited to 'doxygen/Makefile') diff --git a/README.md b/README.md index 7f429d12..596494b9 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Directory name | Description @ref src/vppinfra | VPP core library test | Unit tests @ref src/vpp/api | Not-yet-relocated API bindings - +@ref src/examples | VPP example code ## Getting started diff --git a/doxygen/Makefile b/doxygen/Makefile index abaca185..b6ba5887 100644 --- a/doxygen/Makefile +++ b/doxygen/Makefile @@ -74,8 +74,7 @@ DOXY_INPUT := $(subst $(WS_ROOT)/,,$(DOXY_INPUT)) # These must be left-anchored paths for the regexp below to work. DOXY_EXCLUDE ?= \ $(DOXY_SRC)/vlib/buffer.c \ - $(DOXY_SRC)/vpp-api/lua \ - $(DOXY_SRC)/examples/sample-plugin + $(DOXY_SRC)/vpp-api/lua # Generate a regexp for filenames to exclude DOXY_EXCLUDE_REGEXP = ($(subst .,\.,$(shell echo '$(strip $(DOXY_EXCLUDE))' | sed -e 's/ /|/g'))) diff --git a/doxygen/user_doc.md b/doxygen/user_doc.md index becc2e0a..c0a05bd9 100644 --- a/doxygen/user_doc.md +++ b/doxygen/user_doc.md @@ -16,3 +16,4 @@ Several modules provide operational, dataplane-user focused documentation. - @subpage span_doc - @subpage srv6_doc - @subpage srmpls_doc +- @subpage sample_plugin_doc diff --git a/src/examples/sample-plugin/sample/sample.c b/src/examples/sample-plugin/sample/sample.c index 2f8ac4c9..3929ac23 100644 --- a/src/examples/sample-plugin/sample/sample.c +++ b/src/examples/sample-plugin/sample/sample.c @@ -12,10 +12,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - *------------------------------------------------------------------ - * sample.c - simple MAC-swap API / debug CLI handling - *------------------------------------------------------------------ +/** + * @file + * @brief Sample Plugin, plugin API / trace / CLI handling. */ #include @@ -65,7 +64,11 @@ VLIB_PLUGIN_REGISTER () = { }; /* *INDENT-ON* */ -/* Action function shared between message handler and debug CLI */ +/** + * @brief Enable/disable the macswap plugin. + * + * Action function shared between message handler and debug CLI. + */ int sample_macswap_enable_disable (sample_main_t * sm, u32 sw_if_index, int enable_disable) @@ -135,6 +138,9 @@ macswap_enable_disable_command_fn (vlib_main_t * vm, return 0; } +/** + * @brief CLI command to enable/disable the sample macswap plugin. + */ VLIB_CLI_COMMAND (sr_content_command, static) = { .path = "sample macswap", .short_help = @@ -142,7 +148,9 @@ VLIB_CLI_COMMAND (sr_content_command, static) = { .function = macswap_enable_disable_command_fn, }; -/* API message handler */ +/** + * @brief Plugin API message handler. + */ static void vl_api_sample_macswap_enable_disable_t_handler (vl_api_sample_macswap_enable_disable_t * mp) { @@ -156,7 +164,9 @@ static void vl_api_sample_macswap_enable_disable_t_handler REPLY_MACRO(VL_API_SAMPLE_MACSWAP_ENABLE_DISABLE_REPLY); } -/* Set up the API message handling tables */ +/** + * @brief Set up the API message handling tables. + */ static clib_error_t * sample_plugin_api_hookup (vlib_main_t *vm) { @@ -188,6 +198,9 @@ setup_message_id_table (sample_main_t * sm, api_main_t *am) #undef _ } +/** + * @brief Initialize the sample plugin. + */ static clib_error_t * sample_init (vlib_main_t * vm) { sample_main_t * sm = &sample_main; @@ -214,6 +227,9 @@ static clib_error_t * sample_init (vlib_main_t * vm) VLIB_INIT_FUNCTION (sample_init); +/** + * @brief Hook the sample plugin into the VPP graph hierarchy. + */ VNET_FEATURE_INIT (sample, static) = { .arc_name = "device-input", diff --git a/src/examples/sample-plugin/sample_plugin_doc.md b/src/examples/sample-plugin/sample_plugin_doc.md new file mode 100644 index 00000000..9348094c --- /dev/null +++ b/src/examples/sample-plugin/sample_plugin_doc.md @@ -0,0 +1,66 @@ +# Sample plugin for VPP {#sample_plugin_doc} + +## Overview + +This is the VPP sample plugin demonstrates how to create a new plugin that integrates +with VPP. The sample code implements a trival macswap algorithim that demonstrates plugin +runtime integration with the VPP graph hierachy, api and cli. + +For deeper dive information see the annotations in the sample code itself. See [sample.c](@ref sample.c) + +## How to build and run the sample plugin. + +Now (re)build VPP. + + $ make wipe + +Define environmental variable 'VPP_WITH_SAMPLE_PLUGIN=yes' with a process scope + + $ VPP_WITH_SAMPLE_PLUGIN=yes make build + +or a session scope, and build VPP. + + $ export VPP_WITH_SAMPLE_PLUGIN=yes + & make build + +Now run VPP and make sure the plugin is loaded. + + $ make run + ... + load_one_plugin:184: Loaded plugin: memif_plugin.so (Packet Memory Interface (experimetal)) + load_one_plugin:184: Loaded plugin: sample_plugin.so (Sample of VPP Plugin) + load_one_plugin:184: Loaded plugin: snat_plugin.so (Network Address Translation) + ... + DBGvpp# + +## How to create a new plugin + +To create a new plugin based on the sample plugin, copy and rename the sample plugin directory and automake config. + + cp -r src/examples/sample-plugin/sample src/plugins/newplugin + cp src/examples/sample-plugin/sample.am src/plugins/newplugin.am + +Add the following entry to the plugins section of `src/configure.ac`. + + PLUGIN_ENABLED(newplugin) + +Add the following entry to the plugins section of `src/plugins/Makefile.am` + + if ENABLE_NEWPLUGIN + include newplugin.am + endif + +Now (re)build VPP. + + $ make wipe + $ make build + +## Configuration + +To enable the sample plugin + + sample macswap + +To disable the sample plugin + + sample macswap disable -- cgit 1.2.3-korg From d84f2ef54a457918f21bb0ee82392274b62611fe Mon Sep 17 00:00:00 2001 From: Chris Luke Date: Wed, 27 Sep 2017 15:09:48 -0400 Subject: General documentation updates - We now have several developer-focused docs, so create an index page for them. - Rework several docs to fit into the index structure. - Experiment with code highlighting; tweak the CSS slightly to make it slightly nicer to look at. Change-Id: I4185a18f84fa0764745ca7a3148276064a3155c6 Signed-off-by: Chris Luke (cherry picked from commit 64ebb5ff1338140d94c7f9ee72138fe84d89de2e) --- README.md | 15 +- doxygen/Makefile | 4 +- doxygen/assets/doxy-vpp.css | 6 + doxygen/dev_doc.md | 12 + doxygen/doxygen.cfg | 3 +- doxygen/test_framework_doc.md | 1 + doxygen/user_doc.md | 2 - extras/libmemif/README.md | 72 ------ extras/libmemif/docs/BuildInstructions.md | 54 ---- extras/libmemif/docs/GettingStarted.md | 215 ---------------- extras/libmemif/docs/buildinstructions_doc.md | 55 ++++ extras/libmemif/docs/gettingstarted_doc.md | 219 ++++++++++++++++ extras/libmemif/examples/ExampleSetup.md | 206 --------------- extras/libmemif/examples/README.md | 16 -- extras/libmemif/examples/example_setup_doc.md | 207 +++++++++++++++ extras/libmemif/examples/examples_doc.md | 18 ++ extras/libmemif/libmemif_doc.md | 74 ++++++ src/plugins/acl/acl-plugin.md | 347 ------------------------- src/plugins/acl/acl_hash_lookup_doc.md | 241 ++++++++++++++++++ src/plugins/acl/acl_multicore_doc.md | 349 ++++++++++++++++++++++++++ src/plugins/acl/hash_lookup.md | 241 ------------------ src/vlibapi/api_doc.md | 77 +++--- 22 files changed, 1234 insertions(+), 1200 deletions(-) create mode 100644 doxygen/dev_doc.md delete mode 100644 extras/libmemif/README.md delete mode 100644 extras/libmemif/docs/BuildInstructions.md delete mode 100644 extras/libmemif/docs/GettingStarted.md create mode 100644 extras/libmemif/docs/buildinstructions_doc.md create mode 100644 extras/libmemif/docs/gettingstarted_doc.md delete mode 100644 extras/libmemif/examples/ExampleSetup.md delete mode 100644 extras/libmemif/examples/README.md create mode 100644 extras/libmemif/examples/example_setup_doc.md create mode 100644 extras/libmemif/examples/examples_doc.md create mode 100644 extras/libmemif/libmemif_doc.md delete mode 100644 src/plugins/acl/acl-plugin.md create mode 100644 src/plugins/acl/acl_hash_lookup_doc.md create mode 100644 src/plugins/acl/acl_multicore_doc.md delete mode 100644 src/plugins/acl/hash_lookup.md (limited to 'doxygen/Makefile') diff --git a/README.md b/README.md index 596494b9..090dd35f 100644 --- a/README.md +++ b/README.md @@ -30,10 +30,11 @@ Directory name | Description build-root | Build output directory doxygen | Documentation generator configuration dpdk | DPDK patches and build infrastructure -@ref src | VPP source code +@ref extras/libmemif | Client library for memif +@ref src/examples | VPP example code @ref src/plugins | VPP bundled plugins directory @ref src/svm | Shared virtual memory allocation library - src/tests | Unit tests + src/tests | Standalone tests (not part of test harness) src/vat | VPP API test program @ref src/vlib | VPP application library @ref src/vlibapi | VPP API library @@ -43,9 +44,8 @@ Directory name | Description @ref src/vpp | VPP application @ref src/vpp-api | VPP application API bindings @ref src/vppinfra | VPP core library - test | Unit tests @ref src/vpp/api | Not-yet-relocated API bindings -@ref src/examples | VPP example code + test | Unit tests and Python test harness ## Getting started @@ -95,12 +95,13 @@ for this can be found [on the Setting up Vagrant wiki page] ## More information Several modules provide documentation, see @subpage user_doc for more -information. +end-user-oriented information. Also see @subpage dev_doc for developer notes. Visit the [VPP wiki](https://wiki.fd.io/view/VPP) for details on more -advanced building strategies and development notes. +advanced building strategies and other development notes. ## Test Framework -There is PyDoc generated documentation available for the VPP test framework. See @subpage test_framework_doc for details. +There is PyDoc generated documentation available for the VPP test framework. +See @ref test_framework_doc for details. diff --git a/doxygen/Makefile b/doxygen/Makefile index b6ba5887..5870530f 100644 --- a/doxygen/Makefile +++ b/doxygen/Makefile @@ -62,7 +62,8 @@ DOXY_INPUT ?= \ $(wildcard $(WS_ROOT)/*.md) \ $(wildcard $(DOXY_DIR)/*.md) \ $(DOXY_SRC_DIRECTORIES) \ - $(DOXY_SRC)/plugins + $(DOXY_SRC)/plugins \ + extras # Strip leading workspace path from input names DOXY_INPUT := $(subst $(WS_ROOT)/,,$(DOXY_INPUT)) @@ -73,7 +74,6 @@ DOXY_INPUT := $(subst $(WS_ROOT)/,,$(DOXY_INPUT)) # there's a DPDK equivalent that conflicts. # These must be left-anchored paths for the regexp below to work. DOXY_EXCLUDE ?= \ - $(DOXY_SRC)/vlib/buffer.c \ $(DOXY_SRC)/vpp-api/lua # Generate a regexp for filenames to exclude diff --git a/doxygen/assets/doxy-vpp.css b/doxygen/assets/doxy-vpp.css index 3b74eb6f..108600ac 100644 --- a/doxygen/assets/doxy-vpp.css +++ b/doxygen/assets/doxy-vpp.css @@ -45,3 +45,9 @@ pre { a.el { font-family: Consolas, Courier, monospace; } + +div.fragment { + padding: 2px; + margin-left: 8px; +} + diff --git a/doxygen/dev_doc.md b/doxygen/dev_doc.md new file mode 100644 index 00000000..d1d22f76 --- /dev/null +++ b/doxygen/dev_doc.md @@ -0,0 +1,12 @@ +Developer Documentation {#dev_doc} +======================= + +Programming notes for developers. + +- @subpage test_framework_doc +- @subpage sample_plugin_doc +- @subpage api_doc +- @subpage vapi_doc +- @subpage acl_hash_lookup +- @subpage acl_multicore +- @subpage libmemif_doc diff --git a/doxygen/doxygen.cfg b/doxygen/doxygen.cfg index 7675b693..f2d39112 100644 --- a/doxygen/doxygen.cfg +++ b/doxygen/doxygen.cfg @@ -882,7 +882,8 @@ EXAMPLE_RECURSIVE = NO # that contain images that are to be included in the documentation (see the # \image command). -IMAGE_PATH = $(ROOT)/doxygen/assets +IMAGE_PATH = $(ROOT)/doxygen/assets \ + $(ROOT)/extras/libmemif/docs # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program diff --git a/doxygen/test_framework_doc.md b/doxygen/test_framework_doc.md index b2873c5f..755a29e4 100644 --- a/doxygen/test_framework_doc.md +++ b/doxygen/test_framework_doc.md @@ -3,5 +3,6 @@ Test Framework Documentation {#test_framework_doc} PyDoc generated documentation for the "make test" framework is available for the following releases +- [Test framework documentation for VPP 17.10](https://docs.fd.io/vpp/17.10/vpp_make_test/html) - [Test framework documentation for VPP 17.04](https://docs.fd.io/vpp/17.04/vpp_make_test/html) - [Test framework documentation for VPP 17.01](https://docs.fd.io/vpp/17.01/vpp_make_test/html) diff --git a/doxygen/user_doc.md b/doxygen/user_doc.md index 65b09f98..f7d7936b 100644 --- a/doxygen/user_doc.md +++ b/doxygen/user_doc.md @@ -16,6 +16,4 @@ Several modules provide operational, dataplane-user focused documentation. - @subpage span_doc - @subpage srv6_doc - @subpage srmpls_doc -- @subpage sample_plugin_doc - @subpage nat64_doc -- @subpage api_doc diff --git a/extras/libmemif/README.md b/extras/libmemif/README.md deleted file mode 100644 index 0cccfb37..00000000 --- a/extras/libmemif/README.md +++ /dev/null @@ -1,72 +0,0 @@ -Shared Memory Packet Interface (memif) Library -============================================== -## Introduction - -Shared memory packet interface (memif) provides high performance packet transmit and receive between user application and Vector Packet Processing (VPP) or multiple user applications. Using libmemif, user application can create shared memory interface in master or slave mode and connect to VPP or another application using libmemif. Once the connection is established, user application can receive or transmit packets using libmemif API. - -![Architecture](docs/architecture.png) - -## Features - -- [x] Slave mode - - [x] Connect to VPP over memif - - [x] ICMP responder example app -- [x] Transmit/receive packets -- [x] Interrupt mode support -- [x] File descriptor event polling in libmemif (optional) - - [x] Simplify file descriptor event polling (one handler for control and interrupt channel) -- [x] Multiple connections -- [x] Multiple queues - - [x] Multi-thread support -- [x] Master mode - - [ ] Multiple regions (TODO) -- [ ] Performance testing (TODO) - -## Quickstart - -This setup will run libmemif ICMP responder example app in container. Install [docker](https://docs.docker.com/engine/installation) engine. -Useful link: [Docker documentation](https://docs.docker.com/get-started). - -Pull image: -``` -# docker pull ligato/libmemif-sample-service -``` - -Now you should be able to see ligato/libmemif-sample-service image on your local machine (IMAGE ID in this README may be outdated): -``` -# docker images -REPOSITORY TAG IMAGE ID CREATED SIZE -ligato/libmemif-sample-service latest 32ecc2f9d013 About a minute ago 468MB -... -``` - -Run container: -``` -# docker run -it --rm --name icmp-responder --hostname icmp-responder --privileged -v "/run/vpp/:/run/vpp/" ligato/libmemif-sample-service -``` -Example application will start in debug mode. Output should look like this: -``` -ICMP_Responder:add_epoll_fd:204: fd 0 added to epoll -MEMIF_DEBUG:src/main.c:memif_init:383: app name: ICMP_Responder -ICMP_Responder:add_epoll_fd:204: fd 4 added to epoll -LIBMEMIF EXAMPLE APP: ICMP_Responder (debug) -============================== -libmemif version: 1.0 (debug) -memif version: 256 -commands: - help - prints this help - exit - exit app - conn - create memif (slave-mode) - del - delete memif - show - show connection details - ip-set - set interface ip address - rx-mode - set queue rx mode -``` - -Continue with [Example setup](examples/ExampleSetup.md) which contains instructions on how to set up conenction between icmpr-epoll example app and VPP-memif. - -#### Next steps - -- [Build instructions](docs/BuildInstructions.md) Instructions on how to build/install libmemif. -- [Examples](examples/README.md) More example apps presenting different features. -- [Getting started](docs/GettingStarted.md) Introduction to libmemif API. Explaining library usage in custom app. diff --git a/extras/libmemif/docs/BuildInstructions.md b/extras/libmemif/docs/BuildInstructions.md deleted file mode 100644 index 9bb59b94..00000000 --- a/extras/libmemif/docs/BuildInstructions.md +++ /dev/null @@ -1,54 +0,0 @@ -## Build Instructions - -Install dependencies -``` -# sudo apt-get install -y git autoconf pkg_config libtool check -``` - -Clone repository to your local machine. -``` -# git clone https://github.com/JakubGrajciar/libmemif.git -``` - -From root directory execute: -For debug build: -``` -# ./bootstrap -# ./configure -# make -# make install -``` - -For release build: -``` -# ./bootstrap -# ./configure -# make release -# make install -``` -Verify installation: -``` -# ./.libs/icmpr-epoll -``` -> Make sure to run the binary file from ./.libs. File ./icmp\_responder in libmemif root directory is script that links the library, so it only verifies successful build. Default install path is /usr/lib. -Use _help_ command to display build information and commands: -``` -ICMP_Responder:add_epoll_fd:204: fd 0 added to epoll -MEMIF_DEBUG:src/main.c:memif_init:383: app name: ICMP_Responder -ICMP_Responder:add_epoll_fd:204: fd 4 added to epoll -LIBMEMIF EXAMPLE APP: ICMP_Responder (debug) -============================== -libmemif version: 1.0 (debug) -memif version: 256 -commands: - help - prints this help - exit - exit app - conn - create memif (slave-mode) - del - delete memif - show - show connection details - ip-set - set interface ip address - rx-mode - set queue rx mode -``` -#### Examples - -Once the library is build/installed, refer to [Examples](../examples/README.md) and [Getting started](GettingStarted.md) for additional information on basic use cases and API usage. diff --git a/extras/libmemif/docs/GettingStarted.md b/extras/libmemif/docs/GettingStarted.md deleted file mode 100644 index 3cc0ceb0..00000000 --- a/extras/libmemif/docs/GettingStarted.md +++ /dev/null @@ -1,215 +0,0 @@ -## Getting started - -#### Concept (Connecting to VPP) - -For detailed information on api calls and structures please refer to [libmemif.h](../src/libmemif.h) - -1. Initialize memif - - Declare callback function handling file descriptor event polling. -```C -int -control_fd_update (int fd, uint8_t events) -{ -... -} -``` - - Call memif initialization function. memif\_init -```C -err = memif_init (control_fd_update, APP_NAME); -``` - -> If event occurres on any file descriptor returned by this callback, call memif\_control\_fd\_handler function. -```C -memif_err = memif_control_fd_handler (evt.data.fd, events); -``` -> If callback function parameter for memif\_init function is set to NULL, libmemif will handle file descriptor event polling. - Api call memif\_poll\_event will call epoll\_pwait with user defined timeout to poll event on file descriptors opened by libmemif. -```C -/* main loop */ - while (1) - { - if (memif_poll_event (-1) < 0) - { - DBG ("poll_event error!"); - } - } -``` - -> Memif initialization function will initialize internal structures and create timer file descriptor, which will be used for sending periodic connection requests. Timer is disarmed if no memif interface is created. - -2. Creating interface - - Declare memif connction handle. -```C -memif_conn_handle_t c; -``` -> example app uses struct that contains connection handle, rx/tx buffers and other connection specific information. - - - Specify connection arguments. -```C -memif_conn_args_t args; -memset (&args, 0, sizeof (args)); -args.is_master = is_master; -args.log2_ring_size = 10; -args.buffer_size = 2048; -args.num_s2m_rings = 2; -args.num_m2s_rings = 2; -strncpy ((char *) args.interface_name, IF_NAME, strlen (IF_NAME)); -strncpy ((char *) args.instance_name, APP_NAME, strlen (APP_NAME)); -args.mode = 0; -args.interface_id = 0; -``` - - Declare callback functions called on connected/disconnected/interrupted status changed. -```C -int -on_connect (memif_conn_handle_t conn, void *private_ctx) -{ -... -} - -int -on_disconnect (memif_conn_handle_t conn, void *private_ctx) -{ - INFO ("memif connected!"); - return 0; -} -``` - - Call memif interface create function. memif\_create -```C -err = memif_create (&c->conn, - &args, on_connect, on_disconnect, on_interrupt, &ctx[index]); -``` -> If connection is in slave mode, arms timer file descriptor. -> If on interrupt callback is set to NULL, user will not be notified about interrupt. Use memif\_get\_queue\_efd call to get interrupt file descriptor for specific queue. -```C -int fd = -1; -err = memif_get_queue_efd (c->conn, data->qid, &fd); -``` - -3. Connection establishment - - User application will poll events on all file descriptors returned in memif\_control\_fd\_update\_t callback. - - On event call memif\_control\_fd\_handler. - - Everything else regarding connection establishment will be done internally. - - Once connection has been established, a callback will inform the user about connection status change. - -4. Interrupt packet receive - - If event is polled on interrupt file descriptor, libmemif will call memif\_interrupt\_t callback specified for every connection instance. -```C -int -on_interrupt (memif_conn_handle_t conn, void *private_ctx, uint16_t qid) -{ -... -} -``` - -6. Memif buffers - - Packet data are stored in memif\_buffer\_t. Pointer _data_ points to shared memory buffer, and unsigned integer *data\_len* contains packet data length. -```C -typedef struct -{ - uint16_t desc_index; - uint32_t buffer_len; - uint32_t data_len; - void *data; -} memif_buffer_t; -``` - -5. Packet receive - - Api call memif\_rx\_burst will set all required fields in memif buffers provided by user application. -```C -err = memif_rx_burst (c->conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &rx); -``` - - User application can then process packets. - - Api call memif\_buffer\_free will make supplied memif buffers ready for next receive and mark shared memory buffers as free. -```C -err = memif_buffer_free (c->conn, qid, c->rx_bufs, rx, &fb); -``` - -6. Packet transmit - - Api call memif\_buffer\_alloc will set all required fields in memif buffers provided by user application. -```C -err = memif_buffer_alloc (c->conn, qid, c->tx_bufs, n, &r); -``` - - User application can populate shared memory buffers with packets. - - Api call memif\_tx\_burst will inform peer interface (master memif on VPP) that there are packets ready to receive and mark memif buffers as free. -```C -err = memif_tx_burst (c->conn, qid, c->tx_bufs, c->tx_buf_num, &r); -``` - -7. Helper functions - - Memif details - - Api call memif\_get\_details will return details about connection. -```C -err = memif_get_details (c->conn, &md, buf, buflen); -``` - - Memif error messages - - Every api call returns error code (integer value) mapped to error string. - - Call memif\_strerror will return error message assigned to specific error code. -```C -if (err != MEMIF_ERR_SUCCESS) - INFO ("memif_get_details: %s", memif_strerror (err)); -``` - - Not all syscall errors are translated to memif error codes. If error code 1 (MEMIF\_ERR\_SYSCALL) is returned then libmemif needs to be compiled with -DMEMIF_DBG flag to print error message. Use _make -B_ to rebuild libmemif in debug mode. - -#### Example app (libmemif fd event polling): - -- [ICMP Responder](../examples/icmp_responder/main.c) -> Optional argument: transmit queue id. -``` -icmpr 1 -``` -> Set transmit queue id to 1. Default is 0. -> Application will create memif interface in slave mode and try to connect to VPP. Exit using Ctrl+C. Application will handle SIGINT signal, free allocated memory and exit with EXIT_SUCCESS. - -#### Example app: - -- [ICMP Responder custom fd event polling](../examples/icmp_responder-epoll/main.c) - -#### Example app (multi-thread queue polling) - -- [ICMP Responder multi-thread](../examples/icmp_responder-mt/main.c) - -> Simple example of libmemif multi-thread usage. Connection establishment is handled by main thread. There are two rx queues in this example. One in polling mode and second in interrupt mode. - -VPP config: -``` -# create memif id 0 master -# set int state memif0 up -# set int ip address memif0 192.168.1.1/24 -# ping 192.168.1.2 -``` -For multiple rings (queues) support run VPP with worker threads: -example startup.conf: -``` -unix { - interactive - nodaemon - full-coredump -} - -cpu { - workers 2 -} -``` -VPP config: -``` -# create memif id 0 master -# set int state memif0 up -# set int ip address memif0 192.168.1.1/24 -# ping 192.168.1.2 -``` -> Master mode queue number is limited by worker threads. Slave mode interface needs to specify number of queues. -``` -# create memif id 0 slave rx-queues 2 tx-queues 2 -``` -> Example applications use VPP default socket file for memif: /run/vpp/memif.sock -> For master mode, socket directory must exist prior to memif\_create call. - -#### Unit tests - -Unit tests use [Check](https://libcheck.github.io/check/index.html) framework. This framework must be installed in order to build *unit\_test* binary. -Ubuntu/Debian: -``` -sudo apt-get install check -``` -[More platforms](https://libcheck.github.io/check/web/install.html) - diff --git a/extras/libmemif/docs/buildinstructions_doc.md b/extras/libmemif/docs/buildinstructions_doc.md new file mode 100644 index 00000000..838e835a --- /dev/null +++ b/extras/libmemif/docs/buildinstructions_doc.md @@ -0,0 +1,55 @@ +## Build Instructions {#libmemif_build_doc} + +Install dependencies +``` +# sudo apt-get install -y git autoconf pkg_config libtool check +``` + +Clone repository to your local machine. +``` +# git clone https://github.com/JakubGrajciar/libmemif.git +``` + +From root directory execute: +For debug build: +``` +# ./bootstrap +# ./configure +# make +# make install +``` + +For release build: +``` +# ./bootstrap +# ./configure +# make release +# make install +``` +Verify installation: +``` +# ./.libs/icmpr-epoll +``` +> Make sure to run the binary file from ./.libs. File ./icmp\_responder in libmemif root directory is script that links the library, so it only verifies successful build. Default install path is /usr/lib. +Use _help_ command to display build information and commands: +``` +ICMP_Responder:add_epoll_fd:204: fd 0 added to epoll +MEMIF_DEBUG:src/main.c:memif_init:383: app name: ICMP_Responder +ICMP_Responder:add_epoll_fd:204: fd 4 added to epoll +LIBMEMIF EXAMPLE APP: ICMP_Responder (debug) +============================== +libmemif version: 1.0 (debug) +memif version: 256 +commands: + help - prints this help + exit - exit app + conn - create memif (slave-mode) + del - delete memif + show - show connection details + ip-set - set interface ip address + rx-mode - set queue rx mode +``` + +#### Examples + +Once the library is built/installed, refer to @ref libmemif_examples_doc and @ref libmemif_gettingstarted_doc for additional information on basic use cases and API usage. diff --git a/extras/libmemif/docs/gettingstarted_doc.md b/extras/libmemif/docs/gettingstarted_doc.md new file mode 100644 index 00000000..e3ae6e56 --- /dev/null +++ b/extras/libmemif/docs/gettingstarted_doc.md @@ -0,0 +1,219 @@ +## Getting started {#libmemif_gettingstarted_doc} + +#### Concept (Connecting to VPP) + +For detailed information on api calls and structures please refer to @ref libmemif.h. + +1. Initialize memif + - Declare callback function handling file descriptor event polling. +```C +int +control_fd_update (int fd, uint8_t events) +{ +... +} +``` + - Call memif initialization function. memif\_init +```C +err = memif_init (control_fd_update, APP_NAME); +``` + +> If event occurres on any file descriptor returned by this callback, call memif\_control\_fd\_handler function. +```C +memif_err = memif_control_fd_handler (evt.data.fd, events); +``` +> If callback function parameter for memif\_init function is set to NULL, libmemif will handle file descriptor event polling. + Api call memif\_poll\_event will call epoll\_pwait with user defined timeout to poll event on file descriptors opened by libmemif. +```C +/* main loop */ + while (1) + { + if (memif_poll_event (-1) < 0) + { + DBG ("poll_event error!"); + } + } +``` + +> Memif initialization function will initialize internal structures and create timer file descriptor, which will be used for sending periodic connection requests. Timer is disarmed if no memif interface is created. + +2. Creating interface + - Declare memif connction handle. +```C +memif_conn_handle_t c; +``` +> example app uses struct that contains connection handle, rx/tx buffers and other connection specific information. + + - Specify connection arguments. +```C +memif_conn_args_t args; +memset (&args, 0, sizeof (args)); +args.is_master = is_master; +args.log2_ring_size = 10; +args.buffer_size = 2048; +args.num_s2m_rings = 2; +args.num_m2s_rings = 2; +strncpy ((char *) args.interface_name, IF_NAME, strlen (IF_NAME)); +strncpy ((char *) args.instance_name, APP_NAME, strlen (APP_NAME)); +args.mode = 0; +args.interface_id = 0; +``` + - Declare callback functions called on connected/disconnected/interrupted status changed. +```C +int +on_connect (memif_conn_handle_t conn, void *private_ctx) +{ +... +} + +int +on_disconnect (memif_conn_handle_t conn, void *private_ctx) +{ + INFO ("memif connected!"); + return 0; +} +``` + - Call memif interface create function. memif\_create +```C +err = memif_create (&c->conn, + &args, on_connect, on_disconnect, on_interrupt, &ctx[index]); +``` +> If connection is in slave mode, arms timer file descriptor. +> If on interrupt callback is set to NULL, user will not be notified about interrupt. Use memif\_get\_queue\_efd call to get interrupt file descriptor for specific queue. +```C +int fd = -1; +err = memif_get_queue_efd (c->conn, data->qid, &fd); +``` + +3. Connection establishment + - User application will poll events on all file descriptors returned in memif\_control\_fd\_update\_t callback. + - On event call memif\_control\_fd\_handler. + - Everything else regarding connection establishment will be done internally. + - Once connection has been established, a callback will inform the user about connection status change. + +4. Interrupt packet receive + - If event is polled on interrupt file descriptor, libmemif will call memif\_interrupt\_t callback specified for every connection instance. +```C +int +on_interrupt (memif_conn_handle_t conn, void *private_ctx, uint16_t qid) +{ +... +} +``` + +6. Memif buffers + - Packet data are stored in memif\_buffer\_t. Pointer _data_ points to shared memory buffer, and unsigned integer *data\_len* contains packet data length. +```C +typedef struct +{ + uint16_t desc_index; + uint32_t buffer_len; + uint32_t data_len; + void *data; +} memif_buffer_t; +``` + +5. Packet receive + - Api call memif\_rx\_burst will set all required fields in memif buffers provided by user application. +```C +err = memif_rx_burst (c->conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &rx); +``` + - User application can then process packets. + - Api call memif\_buffer\_free will make supplied memif buffers ready for next receive and mark shared memory buffers as free. +```C +err = memif_buffer_free (c->conn, qid, c->rx_bufs, rx, &fb); +``` + +6. Packet transmit + - Api call memif\_buffer\_alloc will set all required fields in memif buffers provided by user application. +```C +err = memif_buffer_alloc (c->conn, qid, c->tx_bufs, n, &r); +``` + - User application can populate shared memory buffers with packets. + - Api call memif\_tx\_burst will inform peer interface (master memif on VPP) that there are packets ready to receive and mark memif buffers as free. +```C +err = memif_tx_burst (c->conn, qid, c->tx_bufs, c->tx_buf_num, &r); +``` + +7. Helper functions + - Memif details + - Api call memif\_get\_details will return details about connection. +```C +err = memif_get_details (c->conn, &md, buf, buflen); +``` + - Memif error messages + - Every api call returns error code (integer value) mapped to error string. + - Call memif\_strerror will return error message assigned to specific error code. +```C +if (err != MEMIF_ERR_SUCCESS) + INFO ("memif_get_details: %s", memif_strerror (err)); +``` + - Not all syscall errors are translated to memif error codes. If error code 1 (MEMIF\_ERR\_SYSCALL) is returned then libmemif needs to be compiled with -DMEMIF_DBG flag to print error message. Use _make -B_ to rebuild libmemif in debug mode. + +#### Example app (libmemif fd event polling): + +- @ref extras/libmemif/examples/icmp_responder + +> Optional argument: transmit queue id. +``` +icmpr 1 +``` +> Set transmit queue id to 1. Default is 0. +> Application will create memif interface in slave mode and try to connect to VPP. Exit using Ctrl+C. Application will handle SIGINT signal, free allocated memory and exit with EXIT_SUCCESS. + +#### Example app: + +ICMP Responder custom fd event polling. + +- @ref extras/libmemif/examples/icmp_responder-epoll + +#### Example app (multi-thread queue polling) + +ICMP Responder multi-thread. +- @ref extras/libmemif/examples/icmp_responder-mt + +> Simple example of libmemif multi-thread usage. Connection establishment is handled by main thread. There are two rx queues in this example. One in polling mode and second in interrupt mode. + +VPP config: +``` +# create memif id 0 master +# set int state memif0 up +# set int ip address memif0 192.168.1.1/24 +# ping 192.168.1.2 +``` +For multiple rings (queues) support run VPP with worker threads: +example startup.conf: +``` +unix { + interactive + nodaemon + full-coredump +} + +cpu { + workers 2 +} +``` +VPP config: +``` +# create memif id 0 master +# set int state memif0 up +# set int ip address memif0 192.168.1.1/24 +# ping 192.168.1.2 +``` +> Master mode queue number is limited by worker threads. Slave mode interface needs to specify number of queues. +``` +# create memif id 0 slave rx-queues 2 tx-queues 2 +``` +> Example applications use VPP default socket file for memif: /run/vpp/memif.sock +> For master mode, socket directory must exist prior to memif\_create call. + +#### Unit tests + +Unit tests use [Check](https://libcheck.github.io/check/index.html) framework. This framework must be installed in order to build *unit\_test* binary. +Ubuntu/Debian: +``` +sudo apt-get install check +``` +[More platforms](https://libcheck.github.io/check/web/install.html) + diff --git a/extras/libmemif/examples/ExampleSetup.md b/extras/libmemif/examples/ExampleSetup.md deleted file mode 100644 index a02506dd..00000000 --- a/extras/libmemif/examples/ExampleSetup.md +++ /dev/null @@ -1,206 +0,0 @@ -## Example setup - -#### VPP-memif master icmp_responder slave - -> Libmemif example app(s) use memif default socket file: /run/vpp/memif.sock. - -Run VPP and icmpr-epoll example (default example when running in container). -> Other examples work similar to icmpr-epoll. Brief explanation can be found in [Examples readme](README.md) file. - -VPP-side config: -``` -DBGvpp# create memif id 0 master -DBGvpp# set int state memif0/0 up -DBGvpp# set int ip address memif0/0 192.168.1.1/24 -``` -icmpr-epoll: -``` -conn 0 0 -``` -Memif in slave mode will try to connect every 2 seconds. If connection establishment is successfull, a message will show. -``` -INFO: memif connected! -``` -> Error messages like "unmatched interface id" are printed only in debug mode. - -Check connected status. -Use show command in icmpr-epoll: -``` -show -MEMIF DETAILS -============================== -interface index: 0 - interface ip: 192.168.1.2 - interface name: memif_connection - app name: ICMP_Responder - remote interface name: memif0/0 - remote app name: VPP 17.10-rc0~132-g62f9cdd - id: 0 - secret: - role: slave - mode: ethernet - socket filename: /run/vpp/memif.sock - rx queues: - queue id: 0 - ring size: 1024 - buffer size: 2048 - tx queues: - queue id: 0 - ring size: 1024 - buffer size: 2048 - link: up -interface index: 1 - no connection - -``` -Use sh memif command in VPP: -``` -DBGvpp# sh memif -interface memif0/0 - remote-name "ICMP_Responder" - remote-interface "memif_connection" - id 0 mode ethernet file /run/vpp/memif.sock - flags admin-up connected - listener-fd 12 conn-fd 13 - num-s2m-rings 1 num-m2s-rings 1 buffer-size 0 - master-to-slave ring 0: - region 0 offset 32896 ring-size 1024 int-fd 16 - head 0 tail 0 flags 0x0000 interrupts 0 - master-to-slave ring 0: - region 0 offset 0 ring-size 1024 int-fd 15 - head 0 tail 0 flags 0x0001 interrupts 0 -``` - -Send ping from VPP to icmpr-epoll: -``` -DBGvpp# ping 192.168.1.2 -64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=.1888 ms -64 bytes from 192.168.1.2: icmp_seq=3 ttl=64 time=.1985 ms -64 bytes from 192.168.1.2: icmp_seq=4 ttl=64 time=.1813 ms -64 bytes from 192.168.1.2: icmp_seq=5 ttl=64 time=.1929 ms - -Statistics: 5 sent, 4 received, 20% packet loss -``` -#### multiple queues VPP-memif slave icmp_responder master - -Run icmpr-epoll as in previous example setup. -Run VPP with startup conf, enabling 2 worker threads. -Example startup.conf: -``` -unix { - interactive - nodaemon - full-coredump -} - -cpu { - workers 2 -} -``` -VPP-side config: -``` -DBGvpp# create memif id 0 slave rx-queues 2 tx-queues 2 -DBGvpp# set int state memif0/0 up -DBGvpp# set int ip address memif0/0 192.168.1.1/24 -``` -icmpr-epoll: -``` -conn 0 1 -``` -When connection is established a message will print: -``` -INFO: memif connected! -``` -> Error messages like "unmatched interface id" are printed only in debug mode. - -Check connected status. -Use show command in icmpr-epoll: -``` -show -MEMIF DETAILS -============================== -interface index: 0 - interface ip: 192.168.1.2 - interface name: memif_connection - app name: ICMP_Responder - remote interface name: memif0/0 - remote app name: VPP 17.10-rc0~132-g62f9cdd - id: 0 - secret: - role: master - mode: ethernet - socket filename: /run/vpp/memif.sock - rx queues: - queue id: 0 - ring size: 1024 - buffer size: 2048 - queue id: 1 - ring size: 1024 - buffer size: 2048 - tx queues: - queue id: 0 - ring size: 1024 - buffer size: 2048 - queue id: 1 - ring size: 1024 - buffer size: 2048 - link: up -interface index: 1 - no connection - -``` -Use sh memif command in VPP: -``` -DBGvpp# sh memif -interface memif0/0 - remote-name "ICMP_Responder" - remote-interface "memif_connection" - id 0 mode ethernet file /run/vpp/memif.sock - flags admin-up slave connected - listener-fd -1 conn-fd 12 - num-s2m-rings 2 num-m2s-rings 2 buffer-size 2048 - slave-to-master ring 0: - region 0 offset 0 ring-size 1024 int-fd 14 - head 0 tail 0 flags 0x0000 interrupts 0 - slave-to-master ring 1: - region 0 offset 32896 ring-size 1024 int-fd 15 - head 0 tail 0 flags 0x0000 interrupts 0 - slave-to-master ring 0: - region 0 offset 65792 ring-size 1024 int-fd 16 - head 0 tail 0 flags 0x0001 interrupts 0 - slave-to-master ring 1: - region 0 offset 98688 ring-size 1024 int-fd 17 - head 0 tail 0 flags 0x0001 interrupts 0 - -``` -Send ping from VPP to icmpr-epoll: -``` -DBGvpp# ping 192.168.1.2 -64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=.1439 ms -64 bytes from 192.168.1.2: icmp_seq=3 ttl=64 time=.2184 ms -64 bytes from 192.168.1.2: icmp_seq=4 ttl=64 time=.1458 ms -64 bytes from 192.168.1.2: icmp_seq=5 ttl=64 time=.1687 ms - -Statistics: 5 sent, 4 received, 20% packet loss -``` - -#### icmp_responder master icmp_responder slave - -> Example apps can only repond to ping. This setup creates connection between two applications using libmemif. Traffic functionality is the same as when connection to VPP. App can receive ARP/ICMP request and transmit response, but can not send ARP/ICMP request. - -Run two instances of icmpr-epoll example. -> If not running in container, make sure folder /run/vpp/ exists before creating memif master. -Instance 1 will be in master mode, instance 2 in slave mode. -instance 1: -``` -conn 0 1 -``` -instance 2: -``` -conn 0 0 -``` -In 2 seconds, both instances should print connected! message: -``` -INFO: memif connected! -``` -Check peer interface names using show command. diff --git a/extras/libmemif/examples/README.md b/extras/libmemif/examples/README.md deleted file mode 100644 index 1375d27a..00000000 --- a/extras/libmemif/examples/README.md +++ /dev/null @@ -1,16 +0,0 @@ -## Examples - -After build, root folder will contain scripts linking binary examples with library (same name as example apps). These scripts can be executed to run example apps without installing the library. Example apps binaries can be found in _libs_ filder. To run binaries directly, make sure that libmemif library is installed. - -#### Run in container -ligato/libmemif-sample-service image contains built and installed libmemf. To run different examples, override docker CMD to start container in bash: -``` -# docker run -it --entrypoint=/bin/bash -i --rm --name icmp-responder --hostname icmp-responder --privileged -v "/run/vpp/:/run/vpp/" ligato/libmemif-sample-service -``` -Current WORKDIR is set to root repository directory. Example apps can be run from this directory (a script linking binary with library), or browse to ./.libs folder and execute binary directly. - -Example app | Description -------------|------------ -[icmpr](../examples/icmp_responder/main.c) | Simplest implementaion. Event polling is handled by libmemif. Single memif conenction in slave mode is created (id 0). Use Ctrl + C to exit app. Memif receive mode: interrupt. -[icmpr-epoll](../examples/icmp_responder-epoll/main.c) (run in container by default) | Supports multiple connections and master mode. User can create/delete connections, set ip addresses, print connection information. [Example setup](ExampleSetup.md) contains instructions on basic connection use cases setups. Memif receive mode: interrupt. App provides functionality to disable interrupts for specified queue/s for testing purposes. Polling mode is not implemented in this example. -[icmpr-mt](../examples/icmp_responder-mt/main.c) | Multi-thread example, very similar to icmpr-epoll. Packets are handled in threads assigned to specific queues. Slave mode only. Memif receive mode: polling (memif_rx_poll function), interrupt (memif_rx_interrupt function). Receive modes differ per queue. diff --git a/extras/libmemif/examples/example_setup_doc.md b/extras/libmemif/examples/example_setup_doc.md new file mode 100644 index 00000000..89a0b10e --- /dev/null +++ b/extras/libmemif/examples/example_setup_doc.md @@ -0,0 +1,207 @@ +## Example setup {#libmemif_example_setup_doc} + +#### VPP-memif master icmp_responder slave + +> Libmemif example app(s) use memif default socket file: `/run/vpp/memif.sock`. + +Run VPP and icmpr-epoll example (default example when running in container). + +> Other examples work similar to icmpr-epoll. Brief explanation can be found in @ref libmemif_examples_doc . + +VPP-side config: +``` +DBGvpp# create memif id 0 master +DBGvpp# set int state memif0/0 up +DBGvpp# set int ip address memif0/0 192.168.1.1/24 +``` +icmpr-epoll: +``` +conn 0 0 +``` +Memif in slave mode will try to connect every 2 seconds. If connection establishment is successfull, a message will show. +``` +INFO: memif connected! +``` +> Error messages like "unmatched interface id" are printed only in debug mode. + +Check connected status. +Use show command in icmpr-epoll: +``` +show +MEMIF DETAILS +============================== +interface index: 0 + interface ip: 192.168.1.2 + interface name: memif_connection + app name: ICMP_Responder + remote interface name: memif0/0 + remote app name: VPP 17.10-rc0~132-g62f9cdd + id: 0 + secret: + role: slave + mode: ethernet + socket filename: /run/vpp/memif.sock + rx queues: + queue id: 0 + ring size: 1024 + buffer size: 2048 + tx queues: + queue id: 0 + ring size: 1024 + buffer size: 2048 + link: up +interface index: 1 + no connection + +``` +Use sh memif command in VPP: +``` +DBGvpp# sh memif +interface memif0/0 + remote-name "ICMP_Responder" + remote-interface "memif_connection" + id 0 mode ethernet file /run/vpp/memif.sock + flags admin-up connected + listener-fd 12 conn-fd 13 + num-s2m-rings 1 num-m2s-rings 1 buffer-size 0 + master-to-slave ring 0: + region 0 offset 32896 ring-size 1024 int-fd 16 + head 0 tail 0 flags 0x0000 interrupts 0 + master-to-slave ring 0: + region 0 offset 0 ring-size 1024 int-fd 15 + head 0 tail 0 flags 0x0001 interrupts 0 +``` + +Send ping from VPP to icmpr-epoll: +``` +DBGvpp# ping 192.168.1.2 +64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=.1888 ms +64 bytes from 192.168.1.2: icmp_seq=3 ttl=64 time=.1985 ms +64 bytes from 192.168.1.2: icmp_seq=4 ttl=64 time=.1813 ms +64 bytes from 192.168.1.2: icmp_seq=5 ttl=64 time=.1929 ms + +Statistics: 5 sent, 4 received, 20% packet loss +``` +#### multiple queues VPP-memif slave icmp_responder master + +Run icmpr-epoll as in previous example setup. +Run VPP with startup conf, enabling 2 worker threads. +Example startup.conf: +``` +unix { + interactive + nodaemon + full-coredump +} + +cpu { + workers 2 +} +``` +VPP-side config: +``` +DBGvpp# create memif id 0 slave rx-queues 2 tx-queues 2 +DBGvpp# set int state memif0/0 up +DBGvpp# set int ip address memif0/0 192.168.1.1/24 +``` +icmpr-epoll: +``` +conn 0 1 +``` +When connection is established a message will print: +``` +INFO: memif connected! +``` +> Error messages like "unmatched interface id" are printed only in debug mode. + +Check connected status. +Use show command in icmpr-epoll: +``` +show +MEMIF DETAILS +============================== +interface index: 0 + interface ip: 192.168.1.2 + interface name: memif_connection + app name: ICMP_Responder + remote interface name: memif0/0 + remote app name: VPP 17.10-rc0~132-g62f9cdd + id: 0 + secret: + role: master + mode: ethernet + socket filename: /run/vpp/memif.sock + rx queues: + queue id: 0 + ring size: 1024 + buffer size: 2048 + queue id: 1 + ring size: 1024 + buffer size: 2048 + tx queues: + queue id: 0 + ring size: 1024 + buffer size: 2048 + queue id: 1 + ring size: 1024 + buffer size: 2048 + link: up +interface index: 1 + no connection + +``` +Use sh memif command in VPP: +``` +DBGvpp# sh memif +interface memif0/0 + remote-name "ICMP_Responder" + remote-interface "memif_connection" + id 0 mode ethernet file /run/vpp/memif.sock + flags admin-up slave connected + listener-fd -1 conn-fd 12 + num-s2m-rings 2 num-m2s-rings 2 buffer-size 2048 + slave-to-master ring 0: + region 0 offset 0 ring-size 1024 int-fd 14 + head 0 tail 0 flags 0x0000 interrupts 0 + slave-to-master ring 1: + region 0 offset 32896 ring-size 1024 int-fd 15 + head 0 tail 0 flags 0x0000 interrupts 0 + slave-to-master ring 0: + region 0 offset 65792 ring-size 1024 int-fd 16 + head 0 tail 0 flags 0x0001 interrupts 0 + slave-to-master ring 1: + region 0 offset 98688 ring-size 1024 int-fd 17 + head 0 tail 0 flags 0x0001 interrupts 0 + +``` +Send ping from VPP to icmpr-epoll: +``` +DBGvpp# ping 192.168.1.2 +64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=.1439 ms +64 bytes from 192.168.1.2: icmp_seq=3 ttl=64 time=.2184 ms +64 bytes from 192.168.1.2: icmp_seq=4 ttl=64 time=.1458 ms +64 bytes from 192.168.1.2: icmp_seq=5 ttl=64 time=.1687 ms + +Statistics: 5 sent, 4 received, 20% packet loss +``` + +#### icmp_responder master icmp_responder slave + +> Example apps can only repond to ping. This setup creates connection between two applications using libmemif. Traffic functionality is the same as when connection to VPP. App can receive ARP/ICMP request and transmit response, but can not send ARP/ICMP request. + +Run two instances of icmpr-epoll example. +> If not running in container, make sure folder /run/vpp/ exists before creating memif master. +Instance 1 will be in master mode, instance 2 in slave mode. +instance 1: +``` +conn 0 1 +``` +instance 2: +``` +conn 0 0 +``` +In 2 seconds, both instances should print connected! message: +``` +INFO: memif connected! +``` +Check peer interface names using show command. diff --git a/extras/libmemif/examples/examples_doc.md b/extras/libmemif/examples/examples_doc.md new file mode 100644 index 00000000..11937c57 --- /dev/null +++ b/extras/libmemif/examples/examples_doc.md @@ -0,0 +1,18 @@ +## Examples {#libmemif_examples_doc} + +After build, root folder will contain scripts linking binary examples with library (same name as example apps). These scripts can be executed to run example apps without installing the library. Example apps binaries can be found in _libs_ filder. To run binaries directly, make sure that libmemif library is installed. + +#### Run in container + +`ligato/libmemif-sample-service` image contains built and installed libmemf. To run different examples, override docker CMD to start container in bash: + +``` +# docker run -it --entrypoint=/bin/bash -i --rm --name icmp-responder --hostname icmp-responder --privileged -v "/run/vpp/:/run/vpp/" ligato/libmemif-sample-service +``` +Current WORKDIR is set to root repository directory. Example apps can be run from this directory (a script linking binary with library), or browse to `./.libs` folder and execute binary directly. + +Example app | Description +------------|------------ +@ref extras/libmemif/examples/icmp_responder | Simplest implementaion. Event polling is handled by libmemif. Single memif conenction in slave mode is created (id 0). Use Ctrl + C to exit app. Memif receive mode: interrupt. +@ref extras/libmemif/examples/icmp_responder-epoll (run in container by default) | Supports multiple connections and master mode. User can create/delete connections, set ip addresses, print connection information. @ref libmemif_example_setup_doc contains instructions on basic connection use cases setups. Memif receive mode: interrupt. App provides functionality to disable interrupts for specified queue/s for testing purposes. Polling mode is not implemented in this example. +@ref extras/libmemif/examples/icmp_responder-mt) | Multi-thread example, very similar to icmpr-epoll. Packets are handled in threads assigned to specific queues. Slave mode only. Memif receive mode: polling (memif_rx_poll function), interrupt (memif_rx_interrupt function). Receive modes differ per queue. diff --git a/extras/libmemif/libmemif_doc.md b/extras/libmemif/libmemif_doc.md new file mode 100644 index 00000000..fb4a18af --- /dev/null +++ b/extras/libmemif/libmemif_doc.md @@ -0,0 +1,74 @@ +Shared Memory Packet Interface (memif) Library {#libmemif_doc} +============================================== + +## Introduction + +Shared memory packet interface (memif) provides high performance packet transmit and receive between user application and Vector Packet Processing (VPP) or multiple user applications. Using libmemif, user application can create shared memory interface in master or slave mode and connect to VPP or another application using libmemif. Once the connection is established, user application can receive or transmit packets using libmemif API. + +![Architecture](docs/architecture.png) + +## Features + +- [x] Slave mode + - [x] Connect to VPP over memif + - [x] ICMP responder example app +- [x] Transmit/receive packets +- [x] Interrupt mode support +- [x] File descriptor event polling in libmemif (optional) + - [x] Simplify file descriptor event polling (one handler for control and interrupt channel) +- [x] Multiple connections +- [x] Multiple queues + - [x] Multi-thread support +- [x] Master mode + - [ ] Multiple regions (TODO) +- [ ] Performance testing (TODO) + +## Quickstart + +This setup will run libmemif ICMP responder example app in container. Install [docker](https://docs.docker.com/engine/installation) engine. +Useful link: [Docker documentation](https://docs.docker.com/get-started). + +Pull image: +``` +# docker pull ligato/libmemif-sample-service +``` + +Now you should be able to see ligato/libmemif-sample-service image on your local machine (IMAGE ID in this README may be outdated): +``` +# docker images +REPOSITORY TAG IMAGE ID CREATED SIZE +ligato/libmemif-sample-service latest 32ecc2f9d013 About a minute ago 468MB +... +``` + +Run container: +``` +# docker run -it --rm --name icmp-responder --hostname icmp-responder --privileged -v "/run/vpp/:/run/vpp/" ligato/libmemif-sample-service +``` +Example application will start in debug mode. Output should look like this: +``` +ICMP_Responder:add_epoll_fd:204: fd 0 added to epoll +MEMIF_DEBUG:src/main.c:memif_init:383: app name: ICMP_Responder +ICMP_Responder:add_epoll_fd:204: fd 4 added to epoll +LIBMEMIF EXAMPLE APP: ICMP_Responder (debug) +============================== +libmemif version: 1.0 (debug) +memif version: 256 +commands: + help - prints this help + exit - exit app + conn - create memif (slave-mode) + del - delete memif + show - show connection details + ip-set - set interface ip address + rx-mode - set queue rx mode +``` + +Continue with @ref libmemif_example_setup which contains instructions on how to set up conenction between icmpr-epoll example app and VPP-memif. + +#### Next steps + +- @subpage libmemif_build_doc +- @subpage libmemif_examples_doc +- @subpage libmemif_example_setup_doc +- @subpage libmemif_gettingstarted_doc diff --git a/src/plugins/acl/acl-plugin.md b/src/plugins/acl/acl-plugin.md deleted file mode 100644 index 1b44bca9..00000000 --- a/src/plugins/acl/acl-plugin.md +++ /dev/null @@ -1,347 +0,0 @@ -Multicore support for ACL plugin -================================ - -This captures some considerations and design decisions that I have made, -both for my own memory later on ("what the hell was I thinking?!?"), -and for anyone interested to criticize/improve/hack on this code. - -One of the factors taken into account while making these decisions, -was the relative emphasis on the multi-thread vs. single-thread -use cases: the latter is the vastly more prevalent. But, -one can not optimize the single-thread performance without -having a functioning code for multi-thread. - -stateless ACLs -============== - -The stateless trivially parallelizes, and the only potential for the -race between the different threads is during the reconfiguration, -at the time of replacing the old ACL being checked, with -the new ACL. - -In case an acl_add_replace is being used to replace the rules -within the existing entry, a reallocation of am->acls[X].rules -vector will happen and potentially a change in count. - -acl_match_5tuple() has the following code: - - a = am->acls + acl_index; - for (i = 0; i < a->count; i++) - { - r = a->rules + i; - . . . - -Ideally we should be immune from a->rules changing, -but the problem arises if the count changes in flight, -and the new ruleset is smaller - then we will attempt -to "match" against the free memory. - -This can(?) be solved by replacing the for() with while(), -so the comparison happens at each iteration. - -full_acl_match_5tuple(), which iterates over the list -of ACLs, is a bit less immune, since it takes the pointer -to the vector to iterate and keeps a local copy of -that pointer. - -This race can be solved by checking the -current pointer to the vector with the source pointer, -and seeing if there is an (unlikely) change, and if -there is, return the "deny" action, or, better, -restart the check. - -Since the check reloads the ACL list on a per-packet basis, -there is only a window of opportunity of one packet to -"match" packet against an incorrect rule set. -The workers also do not change anything, only read. -Therefore, it looks like building special structures -to ensure that it does not happen at all might be not -worth it. - -At least not until we have a unit-test able to -reliably catch this condition and test that -the measures applied are effective. Adding the code -which is not possible to exercise is worse than -not adding any code at all. - -So, I opt for "do-nothing" here for the moment. - -reflexive ACLs: single-thread -============================= - -Before we talk multi-thread, is worth revisiting the -design of the reflexive ACLs in the plugin, and -the history of their evolution. - -The very first version of the ACL plugin, shipped in -1701, mostly did the job using the existing components -and gluing them together. Because it needed to work -in bridged forwarding path only, using L2 classifier -as an insertion point appeared natural, also L2 classifier, -being a table with sessions, seemed like a good place -to hold the sessions. - -So, the original design had two conceptual nodes: -one, pointed by the next_miss from the L2 classifier table, -was checking the actual ACL, and inserting session into -the L2 classifier table, and the other one, pointed -to by the next_match within the specific session rule, -was checking the existing session. The timing out -of the existing connections was done in the datapath, -by periodically calling the aging function. - -This decision to use the existing components, -with its attrativeness, did bring a few limitations as well: - -* L2 classifier is a simple mask-and-value match, with -a fixed mask across the table. So, sanely supporting IPv6 -packets with extension headers in that framework was impossible. - -* There is no way to get a backpressure from L2 classifier -depending on memory usage. When it runs out of memory, -it simply crashes the box. When it runs out of memory ? -We don't really know. Depends on how it allocates it. - -* Since we need to match the *reflected* traffic, -we had to create *two* full session entries -in two different directions, which is quite wasteful memory-wise. - -* (showstopper): the L2 classifier runs only in -the bridged data path, so supporting routed data path -would require creating something else entirely different, -which would mean much more headaches support-wise going forward. - -Because of that, I have moved to a different model of -creating a session-5-tuple from the packet data - once, -and then doing all the matching just on that 5-tuple. - -This has allowed to add support for skipping IPv6 extension headers. - -Also, this new version started to store the sessions in a dedicated -bihash-per-interface, with the session key data being -aligned for the ingress packets, and being mirrored for the -egress packets. This allows of significant savings in memory, -because now we need to keep only one copy of the session table per -interface instead of two, and also to only have ONE node for all the lookups, -(L2/L3 path, in/out, IPv4/IPv6) - significantly reducing the code complexity. - -Unfortunately, bihash still has the "lack of backpressure" problem, -in a sense that if you try to insert too many entries and run out -of memory in the heap you supplied, you get a crash. - -To somewhat workaround against that, there is a "maximum tested number of sessions" -value, which tracks the currently inserted sessions in the bihash, -and if this number is being approached, a more aggressive cleanup -can happen. If this number is reached, two behaviors are possible: - -* attempt to do the stateless ACL matching and permit the packet - if it succeeds - -* deny the packet - -Currently I have opted for a second one, since it allows for -a better defined behavior, and if you have to permit -the traffic in both directions, why using stateful anyway ? - -In order to be able to do the cleanup, we need to discriminate between -the session types, with each session type having its own idle timeout. -In order to do that, we keep three lists, defined in enum acl_timeout_e: -ACL_TIMEOUT_UDP_IDLE, ACL_TIMEOUT_TCP_IDLE, ACL_TIMEOUT_TCP_TRANSIENT. - -The first one is hopefully obvious - it is just all UDP connections. -They have an idle timeout of 600 seconds. - -The second and third is a bit more subtle. TCP is a complicated protocol, -and we need to tread the fine line between doing too little and doing -too much, and triggering the potential compatibility issues because of -being a "middlebox". - -I decided to split the TCP connections into two classes: -established, and everything else. "Established", means we have seen -the SYN and ACK from both sides (with PUSH obviously masked out). -This is the "active" state of any TCP connection and we would like -to ensure we do not screw it up. So, the connections in this state -have the default idle timer of 24 hours. - -All the rest of the connections have the idle timeout of 2 minutes, -(inspired by an old value of MSL) and based on the observation -that the states this class represent are usually very short lived. - -Once we have these three baskets of connections, it is trivial to -imagine a simple cleanup mechanism to deal with this: take a -TCP transient connection that has been hanging around. - -It is debatable whether we want to do discrimination between the -different TCP transient connections. Assuming we do FIFO (and -the lists allow us to do just that), it means a given connection -on the head of the list has been hanging around for longest. -Thus, if we are short on resources, we might just go ahead and -reuse it within the datapath. - -This is where we are slowly approaching the question -"Why in the world have not you used timer wheel or such ?" - -The answer is simple: within the above constraints, it does -not buy me much. - -Also, timer wheel creates a leaky abstraction with a difficult -to manage corner case. Which corner case ? - -We have a set of objects (sessions) with an event that may -or may not happen (idle timeout timer firing), and a -necessity to reset the idle timeout when there is -activity on the session. - -In the worst case, where we had a 10000 of one-packet -UDP sessions just created 10 minutes ago, we would need -to deal with a spike of 10000 expired timers. - -Of course, if we have the active traffic on all -of these 10000 connections, then we will not have -to deal with that ? Right, but we will still have to deal -with canceling and requeueing the timers. - -In the best possible case, requeueing a timer is -going to be something along the lines of a linked-list -removal and reinsertion. - -However, keep in mind we already need to classify the -connections for reuse, so therefore we already have -the linked lists! - -And if we just check these linked lists periodically in -a FIFO fashion, we can get away with a very simple per-packet operation: -writing back the timestamp of "now" into the connection structure. - -Then rather than requeueing the list on a per-packet or per-frame -basis, we can defer this action until the time this session -appears on the head of the FIFO list, and the cleaning -routine makes the decision about whether to discard -the session (because the interval since last activity is bigger -than the idle timeout), or to requeue the session back to -the end of the list (because the last activity was less -than idle timeout ago). - -So, rather than using the timers, we can simply reuse our classification -FIFOs, with the following heuristic: do not look at the session that was -enqueued at time X until X+session_timeout. If we enqueue the sessions -in the order of their initial activity, then we can simply use enqueue -timestamp of the head session as a decision criterion for when we need -to get back at looking at it for the timeout purposes. - -Since the number of FIFOs is small, we get a slightly worse check -performance than with timers, but still O(1). - -We seemingly do quite a few "useless" operations of requeueing the items -back to the tail of the list - but, these are the operations we do not -have to do in the active data path, so overall it is a win. - -(Diversion: I believe this problem is congruent to poll vs. epoll or -events vs. threads, some reading on this subject: -http://web.archive.org/web/20120225022154/http://sheddingbikes.com/posts/1280829388.html) - -We can also can run a TCP-like scheme for adaptively changing -the wait period in the routine that deals with the connection timeouts: -we can attempt to check the connections a couple of times per second -(same as we would advance the timer wheel), and then if we have requeued -close to a max-per-quantum number of connections, we can half the waiting -interval, and if we did not requeue any, we can slowly increment the waiting -interval - which at a steady state should stabilize similar to what the TCP rate -does. - -reflexive ACLs: multi-thread -============================= - -The single-threaded implementation in 1704 used a separate "cleaner" process -to deal with the timing out of the connections. -It is all good and great when you know that there is only a single core -to run everything on, but the existence of the lists proves to be -a massive difficulty when it comes to operating from multiple threads. - -Initial study shows that with a few assumptions (e.g. that the cleaner running in main thread -and the worker have a demarcation point in time where either one or the other one touches -the session in the list) it might be possible to make it work, but the resulting -trickiness of doing it neatly with all the corner cases is quite large. - -So, for the multi-threaded scenario, we need to move the connection -aging back to the same CPU as its creation. - -Luckily we can do this with the help of the interrupts. - -So, the design is as follows: the aging thread (acl_fa_session_cleaner_process) -periodically fires the interrupts to the workers interrupt nodes (acl_fa_worker_session_cleaner_process_node.index), -using vlib_node_set_interrupt_pending(), and -the interrupt node acl_fa_worker_conn_cleaner_process() calls acl_fa_check_idle_sessions() -which does the actual job of advancing the lists. And within the actual datapath the only thing we will be -doing is putting the items onto FIFO, and updating the last active time on the existing connection. - -The one "delicate" part is that the worker for one leg of the connection might be different from -the worker of another leg of the connection - but, even if the "owner" tries to free the connection, -nothing terrible can happen - worst case the element of the pool (which is nominally free for a short period) -will get the timestamp updated - same thing about the TCP flags seen. - -A slightly trickier issue arises when the packet initially seen by one worker (thus owned by that worker), -and the return packet processed by another worker, and as a result changes the -the class of the connection (e.g. becomes TCP_ESTABLISHED from TCP_TRANSIENT or vice versa). -If the class changes from one with the shorter idle time to the one with the longer idle time, -then unless we are in the starvation mode where the transient connections are recycled, -we can simply do nothing and let the normal requeue mechanism kick in. If the class changes from the longer idle -timer to the shorter idle timer, then we risk keeping the connection around for longer than needed, which -will affect the resource usage. - -One solution to that is to have NxN ring buffers (where N is the number of workers), such that the non-owner -can signal to the owner the connection# that needs to be requeued out of order. - -A simpler solution though, is to ensure that each FIFO's period is equal to that of a shortest timer. -This way the resource starvation problem is taken care of, at an expense of some additional work. - -This all looks sufficiently nice and simple until a skeleton falls out of the closet: -sometimes we want to clean the connections en masse before they expire. - -There few potential scenarios: -1) removal of an ACL from the interface -2) removal of an interface -3) manual action of an operator (in the future). - -In order to tackle this, we need to modify the logic which decides whether to requeue the -connection on the end of the list, or to delete it due to idle timeout: - -We define a point in time, and have each worker thread fast-forward through its FIFO, -in the process looking for sessions that satisfy the criteria, and either keeping them or requeueing them. - -To keep the ease of appearance to the outside world, we still process this as an event -within the connection cleaner thread, but this event handler does as follows: -1) it creates the bitmap of the sw_if_index values requested to be cleared -2) for each worker, it waits to ensure there is no cleanup operation in progress (and if there is one, -it waits), and then makes a copy of the bitmap, sets the per-worker flag of a cleanup operation, and sends an interrupt. -3) wait until all cleanup operations have completed. - -Within the worker interrupt node, we check if the "cleanup in progress" is set, -and if it is, we check the "fast forward time" value. If unset, we initialize it to value now, and compare the -requested bitmap of sw_if_index values (pending_clear_sw_if_index_bitmap) with the bitmap of sw_if_index that this worker deals with. - -(we set the bit in the bitmap every time we enqueue the packet onto a FIFO - serviced_sw_if_index_bitmap in acl_fa_conn_list_add_session). - -If the result of this AND operation is zero - then we can clear the flag of cleanup in progress and return. -Else we kick off the quantum of cleanup, and make sure we get another interrupt ASAP if that cleanup operation returns non-zero, -meaning there is more work to do. -When that operation returns zero, everything has been processed, we can clear the "cleanup-in-progress" flag, and -zeroize the bitmap of sw_if_index-es requested to be cleaned. - -The interrupt node signals its wish to receive an interrupt ASAP by setting interrupt_is_needed -flag within the per-worker structure. The main thread, while waiting for the -cleanup operation to complete, checks if there is a request for interrupt, -and if there is - it sends one. - -This approach gives us a way to mass-clean the connections which is reusing the code of the regular idle -connection cleanup. - -One potential inefficiency is the bitmap values set by the session insertion -in the data path - there is nothing to clear them. - -So, if one rearranges the interface placement with the workers, then the cleanups will cause some unnecessary work. -For now, we consider it an acceptable limitation. It can be resolved by having another per-worker bitmap, which, when set, -would trigger the cleanup of the bits in the serviced_sw_if_index_bitmap). - -=== the end === - diff --git a/src/plugins/acl/acl_hash_lookup_doc.md b/src/plugins/acl/acl_hash_lookup_doc.md new file mode 100644 index 00000000..cb93df04 --- /dev/null +++ b/src/plugins/acl/acl_hash_lookup_doc.md @@ -0,0 +1,241 @@ +ACL plugin constant-time lookup design {#acl_hash_lookup} +====================================== + +The initial implementation of ACL plugin performs a trivial for() cycle, +going through the assigned ACLs on a per-packet basis. This is not very +efficient, even if for very short ACLs due to its simplicity it can beat +more advanced methods. + +However, to cover the case of longer ACLs with acceptable performance, +we need to have a better way of matching. This write-up proposes +a mechanism to make a lookup from O(M) where M is number of entries +to O(N) where N is number of different mask combinations. + +Preparation of ACL(s) +--------------------- + +The ACL plugin will maintain a global list of "mask types", i.e. the specific +configurations of "do not care" bits within the ACEs. +Upon the creation of a new ACL, a pass will be made through all the +ACEs, to assign and possibly allocate the "mask type number". + +Each ACL has a structure *hash_acl_info_t* representing the "hash-based" +parts of information related to that ACL, primarily the array of +*hash_ace_info_t* structures - each of the members of that array +corresponding to one of the rules (ACEs) in the original ACL, +for this they have a pair of *(acl_index, ace_index)* to keep track, +predominantly for the debugging. + +Why do we need a whole separate structure, and are not adding new fields +to the existing rile structure ? First, encapsulation, to minimize +the pollution of the main ACL code with the hash-based lookup artifacts. + +Second, one rule may correspond to more than one "hash-based" ACE. +In fact, most of the rules do correspond to two of those. Why ? + +Consider that the current ACL lookup logic is that if a packet +is not the initial fragment, and there is an L4 entry acting on the packet, +the comparison will be made only on the L4 protocol field value rather +than on the protocol and port values. This beaviour is governed by +*l4_match_nonfirst_fragment* flag in the *acl_main*, and was needed to +maintain the compatibility with the existing software switch implementation. + +While for the sequential check in *single_acl_match_5tuple()* +it is very easy to implement by just breaking out at the right moment, +in case of hash-based matching this cost us two checks: +one on full 5-tuple and the flag *pkt.is_nonfirst_fragment* being zero, +the second on 3-tuple and the flag *pkt.is_nonfirst_fragment* being one, +with the second check triggered by the *acl_main.l4_match_nonfirst_fragment* +setting being the default 1. This dictates the necessity of having a "match" +field in a given *hash_ace_info_t* element, which would reflect the value +we are supposed to match after applying the mask. + +There can be other circumstances when it might be beneficial to expand +the given rule in the original ACL into multiple - for example, as an +optimization within the port range handling for small port ranges +(this is not done as of the time of writing). + +Assigning ACLs to an interface +------------------------------ + +Once the ACL list is assigned to an interface, or, rather, a new ACL +is added to the list of the existing ACLs applied to the interface, +we need to update the bihash accelerating the lookup. + +All the entries for the lookups are stored within a single *48_8* bihash, +which captures the 5-tuple from the packet as well as the miscellaneous +per-packet information flags, e.g. *l4_valid*, *is_non_first_fragment*, +and so on. To facilitate the use of the single bihash by all the interfaces, +the *is_ip6*, *is_input*, *sw_if_index* are part of the key, +as well as *mask_type_index* - the latter being necessary because +there can be entries with the same value but different masks, e.g.: +`permit ::/0, permit::/128`. + +At the moment of an ACL being applied to an interface, we need to +walk the list of *hash_ace_info_t* entries corresponding to that ACL, +and update the bihash with the keys corresponding to the match +values in these entries. + +The value of the hash match contains the index into a per-*sw_if_index* vector +of *applied_ace_hash_entry_t* elements, as well as a couple of flags: +*shadowed* (optimization: if this flag on a matched entry is zero, means +we can stop the lookup early and declare a match - see below), +and *need_portrange_check* - meaning that what matched was a superset +of the actual match, and we need to perform an extra check. + +Also, upon insertion, we must keep in mind there can be +multiple *applied_ace_hash_entry_t* for the same key and must keep +a list of those. This is necessary to incrementally apply/unapply +the ACLs as part of the ACL vector: say, two ACLs have +"permit 2001:db8::1/128 any" - we should be able to retain the entry +for the second ACL even if we have deleted the first one. +Also, in case there are two entries with the same key but +different port ranges, say 0..42 and 142..65535 - we need +to be able to sequentially match on those if we decide not +to expand them into individual port-specific entries. + +Per-packet lookup +----------------- + +The simple single-packet lookup is defined in +*multi_acl_match_get_applied_ace_index*, which returns the index +of the applied hash ACE if there was a match, or ~0 if there wasn't. + +The future optimized per-packet lookup may be batched in three phases: + +1. Prepare the keys in the per-worker vector by doing logical AND of + original 5-tuple record with the elements of the mask vector. +2. Lookup the keys in the bihash in a batch manner, collecting the + result with lowest u64 (acl index within vector, ACE index) from + the hash lookup value, and performing the list walk if necessary + (for portranges) +3. Take the action from the ACL record as defined by (ACL#, ACE#) from the + resulting lookup winner, or, if no match found, then perform default deny. + +Shadowed/independent/redundant ACEs +------------------------------------ + +During the phase of combining multiple ACLs into one rulebase, when they +are applied to interface, we also can perform several optimizations. + +If a given ACE is a strict subset of another ACE located up in the linear +search order, we can ignore this ACE completely - because by definition +it will never match. We will call such an ACE *redundant*. Here is an example: + +``` +permit 2001:db8:1::/48 2001:db8:2::/48 (B) +deny 2001:d8b:1:1::/64 2001:db8:2:1::/64 (A) +``` + +A bit more formally, we can define this relationship of an ACE A to ACE B as: + +``` +redundant(aceA, aceB) := (contains(protoB, protoA) && contains(srcB, srcA) + && contains(dstB, dstA) && is_after(A, B)) +``` + +Here as "contains" we define an operation operating on the sets defined by +the protocol, (srcIP, srcPortDefinition) and (dstIP, dstPortDefinition) +respectively, and returning true if all the elements represented by +the second argument are represented by the first argument. The "is_after" +is true if A is located below B in the ruleset. + +If a given ACE does not intersect at all with any other ACE +in front of it, we can mark it as such. + +Then during the sequence of the lookups the successful hit on this ACE means +we do not need to look up other mask combinations - thus potentially +significantly speeding up the match process. Here is an example, +assuming we have the following ACL: + +``` +permit 2001:db8:1::/48 2001:db8:2::/48 (B) +deny 2001:db8:3::/48 2001:db8:2:1::/64 (A) +``` + +In this case if we match the second entry, we do not need to check whether +we have matched the first one - the source addresses are completely +different. We call such an ACE *independent* from another. + +We can define this as + +``` +independent(aceA, aceB) := (!intersect(protoA, protoB) || + !intersect(srcA, srcB) || + !intersect(dstA, dstB)) +``` + +where intersect is defined as operation returning true if there are +elements belonging to the sets of both arguments. + +If the entry A is neither redundant nor independent from B, and is below +B in the ruleset, we call such an entry *shadowed* by B, here is an example: + +``` +deny tcp 2001:db8:1::/48 2001:db8:2::/48 (B) +permit 2001:d8b:1:1::/64 2001:db8:2:1::/64 (A) +``` + +This means the earlier rule "carves out" a subset of A, thus leaving +a "shadow". (Evidently, the action needs to be different for the shadow +to have an effect, but for for the terminology sake we do not care). + +The more formal definition: + +``` +shadowed(aceA, aceB) := !redundante(aceA, aceB) && + !independent(aceA, aceB) && + is_after(aceA, aceB) +``` + +Using this terminology, any ruleset can be represented as +a DAG (Directed Acyclic Graph), with the bottom being the implicit +"deny any", pointing to the set of rules shadowing it or the ones +it is redundant for. + +These rules may in turn be shadowing each other. There is no cycles in +this graph because of the natural order of the rules - the rule located +closer to the end of the ruleset can never shadow or make redundant a rule +higher up. + +The optimization that enables can allow for is to skip matching certain +masks on a per-lookup basis - if a given rule has matched, +the only adjustments that can happen is the match with one of +the shadowing rules. + +Also, another avenue for the optimization can be starting the lookup process +with the mask type that maximizes the chances of the independent ACE match, +thus resulting in an ACE lookup being a single hash table hit. + + +Plumbing +-------- + +All the new routines are located in a separate file, +so we can cleanly experiment with a different approach if this +does not fit all of the use cases. + +The constant-time lookup within the data path has the API with +the same signature as: + +``` +u8 +multi_acl_match_5tuple (u32 sw_if_index, fa_5tuple_t * pkt_5tuple, int is_l2, + int is_ip6, int is_input, u32 * acl_match_p, + u32 * rule_match_p, u32 * trace_bitmap) +``` + +There should be a new upper-level function with the same signature, which +will make a decision whether to use a linear lookup, or to use the +constant-time lookup implemented by this work, or to add some other +optimizations (e.g. by keeping the cache of the last N lookups). + +The calls to the routine doing preparatory work should happen +in `acl_add_list()` after creating the linear-lookup structures, +and the routine doing the preparatory work populating the hashtable +should be called from `acl_interface_add_del_inout_acl()` or its callees. + +The initial implementation will be geared towards looking up a single +match at a time, with the subsequent optimizations possible to make +the lookup for more than one packet. + diff --git a/src/plugins/acl/acl_multicore_doc.md b/src/plugins/acl/acl_multicore_doc.md new file mode 100644 index 00000000..b2cf7b9c --- /dev/null +++ b/src/plugins/acl/acl_multicore_doc.md @@ -0,0 +1,349 @@ +Multicore support for ACL plugin {#acl_multicore} +================================ + +This captures some considerations and design decisions that I have made, +both for my own memory later on ("what the hell was I thinking?!?"), +and for anyone interested to criticize/improve/hack on this code. + +One of the factors taken into account while making these decisions, +was the relative emphasis on the multi-thread vs. single-thread +use cases: the latter is the vastly more prevalent. But, +one can not optimize the single-thread performance without +having a functioning code for multi-thread. + +stateless ACLs +============== + +The stateless trivially parallelizes, and the only potential for the +race between the different threads is during the reconfiguration, +at the time of replacing the old ACL being checked, with +the new ACL. + +In case an acl_add_replace is being used to replace the rules +within the existing entry, a reallocation of `am->acls[X].rules` +vector will happen and potentially a change in count. + +acl_match_5tuple() has the following code: + +```{.c} + a = am->acls + acl_index; + for (i = 0; i < a->count; i++) + { + r = a->rules + i; + . . . +``` + +Ideally we should be immune from a->rules changing, +but the problem arises if the count changes in flight, +and the new ruleset is smaller - then we will attempt +to "match" against the free memory. + +This can(?) be solved by replacing the for() with while(), +so the comparison happens at each iteration. + +full_acl_match_5tuple(), which iterates over the list +of ACLs, is a bit less immune, since it takes the pointer +to the vector to iterate and keeps a local copy of +that pointer. + +This race can be solved by checking the +current pointer to the vector with the source pointer, +and seeing if there is an (unlikely) change, and if +there is, return the "deny" action, or, better, +restart the check. + +Since the check reloads the ACL list on a per-packet basis, +there is only a window of opportunity of one packet to +"match" packet against an incorrect rule set. +The workers also do not change anything, only read. +Therefore, it looks like building special structures +to ensure that it does not happen at all might be not +worth it. + +At least not until we have a unit-test able to +reliably catch this condition and test that +the measures applied are effective. Adding the code +which is not possible to exercise is worse than +not adding any code at all. + +So, I opt for "do-nothing" here for the moment. + +reflexive ACLs: single-thread +============================= + +Before we talk multi-thread, is worth revisiting the +design of the reflexive ACLs in the plugin, and +the history of their evolution. + +The very first version of the ACL plugin, shipped in +1701, mostly did the job using the existing components +and gluing them together. Because it needed to work +in bridged forwarding path only, using L2 classifier +as an insertion point appeared natural, also L2 classifier, +being a table with sessions, seemed like a good place +to hold the sessions. + +So, the original design had two conceptual nodes: +one, pointed by the next_miss from the L2 classifier table, +was checking the actual ACL, and inserting session into +the L2 classifier table, and the other one, pointed +to by the next_match within the specific session rule, +was checking the existing session. The timing out +of the existing connections was done in the datapath, +by periodically calling the aging function. + +This decision to use the existing components, +with its attrativeness, did bring a few limitations as well: + +* L2 classifier is a simple mask-and-value match, with +a fixed mask across the table. So, sanely supporting IPv6 +packets with extension headers in that framework was impossible. + +* There is no way to get a backpressure from L2 classifier +depending on memory usage. When it runs out of memory, +it simply crashes the box. When it runs out of memory ? +We don't really know. Depends on how it allocates it. + +* Since we need to match the *reflected* traffic, +we had to create *two* full session entries +in two different directions, which is quite wasteful memory-wise. + +* (showstopper): the L2 classifier runs only in +the bridged data path, so supporting routed data path +would require creating something else entirely different, +which would mean much more headaches support-wise going forward. + +Because of that, I have moved to a different model of +creating a session-5-tuple from the packet data - once, +and then doing all the matching just on that 5-tuple. + +This has allowed to add support for skipping IPv6 extension headers. + +Also, this new version started to store the sessions in a dedicated +bihash-per-interface, with the session key data being +aligned for the ingress packets, and being mirrored for the +egress packets. This allows of significant savings in memory, +because now we need to keep only one copy of the session table per +interface instead of two, and also to only have ONE node for all the lookups, +(L2/L3 path, in/out, IPv4/IPv6) - significantly reducing the code complexity. + +Unfortunately, bihash still has the "lack of backpressure" problem, +in a sense that if you try to insert too many entries and run out +of memory in the heap you supplied, you get a crash. + +To somewhat workaround against that, there is a "maximum tested number of sessions" +value, which tracks the currently inserted sessions in the bihash, +and if this number is being approached, a more aggressive cleanup +can happen. If this number is reached, two behaviors are possible: + +* attempt to do the stateless ACL matching and permit the packet + if it succeeds + +* deny the packet + +Currently I have opted for a second one, since it allows for +a better defined behavior, and if you have to permit +the traffic in both directions, why using stateful anyway ? + +In order to be able to do the cleanup, we need to discriminate between +the session types, with each session type having its own idle timeout. +In order to do that, we keep three lists, defined in enum acl_timeout_e: +ACL_TIMEOUT_UDP_IDLE, ACL_TIMEOUT_TCP_IDLE, ACL_TIMEOUT_TCP_TRANSIENT. + +The first one is hopefully obvious - it is just all UDP connections. +They have an idle timeout of 600 seconds. + +The second and third is a bit more subtle. TCP is a complicated protocol, +and we need to tread the fine line between doing too little and doing +too much, and triggering the potential compatibility issues because of +being a "middlebox". + +I decided to split the TCP connections into two classes: +established, and everything else. "Established", means we have seen +the SYN and ACK from both sides (with PUSH obviously masked out). +This is the "active" state of any TCP connection and we would like +to ensure we do not screw it up. So, the connections in this state +have the default idle timer of 24 hours. + +All the rest of the connections have the idle timeout of 2 minutes, +(inspired by an old value of MSL) and based on the observation +that the states this class represent are usually very short lived. + +Once we have these three baskets of connections, it is trivial to +imagine a simple cleanup mechanism to deal with this: take a +TCP transient connection that has been hanging around. + +It is debatable whether we want to do discrimination between the +different TCP transient connections. Assuming we do FIFO (and +the lists allow us to do just that), it means a given connection +on the head of the list has been hanging around for longest. +Thus, if we are short on resources, we might just go ahead and +reuse it within the datapath. + +This is where we are slowly approaching the question +"Why in the world have not you used timer wheel or such ?" + +The answer is simple: within the above constraints, it does +not buy me much. + +Also, timer wheel creates a leaky abstraction with a difficult +to manage corner case. Which corner case ? + +We have a set of objects (sessions) with an event that may +or may not happen (idle timeout timer firing), and a +necessity to reset the idle timeout when there is +activity on the session. + +In the worst case, where we had a 10000 of one-packet +UDP sessions just created 10 minutes ago, we would need +to deal with a spike of 10000 expired timers. + +Of course, if we have the active traffic on all +of these 10000 connections, then we will not have +to deal with that ? Right, but we will still have to deal +with canceling and requeueing the timers. + +In the best possible case, requeueing a timer is +going to be something along the lines of a linked-list +removal and reinsertion. + +However, keep in mind we already need to classify the +connections for reuse, so therefore we already have +the linked lists! + +And if we just check these linked lists periodically in +a FIFO fashion, we can get away with a very simple per-packet operation: +writing back the timestamp of "now" into the connection structure. + +Then rather than requeueing the list on a per-packet or per-frame +basis, we can defer this action until the time this session +appears on the head of the FIFO list, and the cleaning +routine makes the decision about whether to discard +the session (because the interval since last activity is bigger +than the idle timeout), or to requeue the session back to +the end of the list (because the last activity was less +than idle timeout ago). + +So, rather than using the timers, we can simply reuse our classification +FIFOs, with the following heuristic: do not look at the session that was +enqueued at time X until X+session_timeout. If we enqueue the sessions +in the order of their initial activity, then we can simply use enqueue +timestamp of the head session as a decision criterion for when we need +to get back at looking at it for the timeout purposes. + +Since the number of FIFOs is small, we get a slightly worse check +performance than with timers, but still O(1). + +We seemingly do quite a few "useless" operations of requeueing the items +back to the tail of the list - but, these are the operations we do not +have to do in the active data path, so overall it is a win. + +(Diversion: I believe this problem is congruent to poll vs. epoll or +events vs. threads, some reading on this subject: +http://web.archive.org/web/20120225022154/http://sheddingbikes.com/posts/1280829388.html) + +We can also can run a TCP-like scheme for adaptively changing +the wait period in the routine that deals with the connection timeouts: +we can attempt to check the connections a couple of times per second +(same as we would advance the timer wheel), and then if we have requeued +close to a max-per-quantum number of connections, we can half the waiting +interval, and if we did not requeue any, we can slowly increment the waiting +interval - which at a steady state should stabilize similar to what the TCP rate +does. + +reflexive ACLs: multi-thread +============================= + +The single-threaded implementation in 1704 used a separate "cleaner" process +to deal with the timing out of the connections. +It is all good and great when you know that there is only a single core +to run everything on, but the existence of the lists proves to be +a massive difficulty when it comes to operating from multiple threads. + +Initial study shows that with a few assumptions (e.g. that the cleaner running in main thread +and the worker have a demarcation point in time where either one or the other one touches +the session in the list) it might be possible to make it work, but the resulting +trickiness of doing it neatly with all the corner cases is quite large. + +So, for the multi-threaded scenario, we need to move the connection +aging back to the same CPU as its creation. + +Luckily we can do this with the help of the interrupts. + +So, the design is as follows: the aging thread (acl_fa_session_cleaner_process) +periodically fires the interrupts to the workers interrupt nodes (acl_fa_worker_session_cleaner_process_node.index), +using vlib_node_set_interrupt_pending(), and +the interrupt node acl_fa_worker_conn_cleaner_process() calls acl_fa_check_idle_sessions() +which does the actual job of advancing the lists. And within the actual datapath the only thing we will be +doing is putting the items onto FIFO, and updating the last active time on the existing connection. + +The one "delicate" part is that the worker for one leg of the connection might be different from +the worker of another leg of the connection - but, even if the "owner" tries to free the connection, +nothing terrible can happen - worst case the element of the pool (which is nominally free for a short period) +will get the timestamp updated - same thing about the TCP flags seen. + +A slightly trickier issue arises when the packet initially seen by one worker (thus owned by that worker), +and the return packet processed by another worker, and as a result changes the +the class of the connection (e.g. becomes TCP_ESTABLISHED from TCP_TRANSIENT or vice versa). +If the class changes from one with the shorter idle time to the one with the longer idle time, +then unless we are in the starvation mode where the transient connections are recycled, +we can simply do nothing and let the normal requeue mechanism kick in. If the class changes from the longer idle +timer to the shorter idle timer, then we risk keeping the connection around for longer than needed, which +will affect the resource usage. + +One solution to that is to have NxN ring buffers (where N is the number of workers), such that the non-owner +can signal to the owner the connection# that needs to be requeued out of order. + +A simpler solution though, is to ensure that each FIFO's period is equal to that of a shortest timer. +This way the resource starvation problem is taken care of, at an expense of some additional work. + +This all looks sufficiently nice and simple until a skeleton falls out of the closet: +sometimes we want to clean the connections en masse before they expire. + +There few potential scenarios: +1) removal of an ACL from the interface +2) removal of an interface +3) manual action of an operator (in the future). + +In order to tackle this, we need to modify the logic which decides whether to requeue the +connection on the end of the list, or to delete it due to idle timeout: + +We define a point in time, and have each worker thread fast-forward through its FIFO, +in the process looking for sessions that satisfy the criteria, and either keeping them or requeueing them. + +To keep the ease of appearance to the outside world, we still process this as an event +within the connection cleaner thread, but this event handler does as follows: +1) it creates the bitmap of the sw_if_index values requested to be cleared +2) for each worker, it waits to ensure there is no cleanup operation in progress (and if there is one, +it waits), and then makes a copy of the bitmap, sets the per-worker flag of a cleanup operation, and sends an interrupt. +3) wait until all cleanup operations have completed. + +Within the worker interrupt node, we check if the "cleanup in progress" is set, +and if it is, we check the "fast forward time" value. If unset, we initialize it to value now, and compare the +requested bitmap of sw_if_index values (pending_clear_sw_if_index_bitmap) with the bitmap of sw_if_index that this worker deals with. + +(we set the bit in the bitmap every time we enqueue the packet onto a FIFO - serviced_sw_if_index_bitmap in acl_fa_conn_list_add_session). + +If the result of this AND operation is zero - then we can clear the flag of cleanup in progress and return. +Else we kick off the quantum of cleanup, and make sure we get another interrupt ASAP if that cleanup operation returns non-zero, +meaning there is more work to do. +When that operation returns zero, everything has been processed, we can clear the "cleanup-in-progress" flag, and +zeroize the bitmap of sw_if_index-es requested to be cleaned. + +The interrupt node signals its wish to receive an interrupt ASAP by setting interrupt_is_needed +flag within the per-worker structure. The main thread, while waiting for the +cleanup operation to complete, checks if there is a request for interrupt, +and if there is - it sends one. + +This approach gives us a way to mass-clean the connections which is reusing the code of the regular idle +connection cleanup. + +One potential inefficiency is the bitmap values set by the session insertion +in the data path - there is nothing to clear them. + +So, if one rearranges the interface placement with the workers, then the cleanups will cause some unnecessary work. +For now, we consider it an acceptable limitation. It can be resolved by having another per-worker bitmap, which, when set, +would trigger the cleanup of the bits in the serviced_sw_if_index_bitmap). + +=== the end === + diff --git a/src/plugins/acl/hash_lookup.md b/src/plugins/acl/hash_lookup.md deleted file mode 100644 index 95524643..00000000 --- a/src/plugins/acl/hash_lookup.md +++ /dev/null @@ -1,241 +0,0 @@ -ACL plugin constant-time lookup design -====================================== - -The initial implementation of ACL plugin performs a trivial for() cycle, -going through the assigned ACLs on a per-packet basis. This is not very -efficient, even if for very short ACLs due to its simplicity it can beat -more advanced methods. - -However, to cover the case of longer ACLs with acceptable performance, -we need to have a better way of matching. This write-up proposes -a mechanism to make a lookup from O(M) where M is number of entries -to O(N) where N is number of different mask combinations. - -Preparation of ACL(s) ---------------------- - -The ACL plugin will maintain a global list of "mask types", i.e. the specific -configurations of "do not care" bits within the ACEs. -Upon the creation of a new ACL, a pass will be made through all the -ACEs, to assign and possibly allocate the "mask type number". - -Each ACL has a structure *hash_acl_info_t* representing the "hash-based" -parts of information related to that ACL, primarily the array of -*hash_ace_info_t* structures - each of the members of that array -corresponding to one of the rules (ACEs) in the original ACL, -for this they have a pair of *(acl_index, ace_index)* to keep track, -predominantly for the debugging. - -Why do we need a whole separate structure, and are not adding new fields -to the existing rile structure ? First, encapsulation, to minimize -the pollution of the main ACL code with the hash-based lookup artifacts. - -Second, one rule may correspond to more than one "hash-based" ACE. -In fact, most of the rules do correspond to two of those. Why ? - -Consider that the current ACL lookup logic is that if a packet -is not the initial fragment, and there is an L4 entry acting on the packet, -the comparison will be made only on the L4 protocol field value rather -than on the protocol and port values. This beaviour is governed by -*l4_match_nonfirst_fragment* flag in the *acl_main*, and was needed to -maintain the compatibility with the existing software switch implementation. - -While for the sequential check in *single_acl_match_5tuple()* -it is very easy to implement by just breaking out at the right moment, -in case of hash-based matching this cost us two checks: -one on full 5-tuple and the flag *pkt.is_nonfirst_fragment* being zero, -the second on 3-tuple and the flag *pkt.is_nonfirst_fragment* being one, -with the second check triggered by the *acl_main.l4_match_nonfirst_fragment* -setting being the default 1. This dictates the necessity of having a "match" -field in a given *hash_ace_info_t* element, which would reflect the value -we are supposed to match after applying the mask. - -There can be other circumstances when it might be beneficial to expand -the given rule in the original ACL into multiple - for example, as an -optimization within the port range handling for small port ranges -(this is not done as of the time of writing). - -Assigning ACLs to an interface ------------------------------- - -Once the ACL list is assigned to an interface, or, rather, a new ACL -is added to the list of the existing ACLs applied to the interface, -we need to update the bihash accelerating the lookup. - -All the entries for the lookups are stored within a single *48_8* bihash, -which captures the 5-tuple from the packet as well as the miscellaneous -per-packet information flags, e.g. *l4_valid*, *is_non_first_fragment*, -and so on. To facilitate the use of the single bihash by all the interfaces, -the *is_ip6*, *is_input*, *sw_if_index* are part of the key, -as well as *mask_type_index* - the latter being necessary because -there can be entries with the same value but different masks, e.g.: -`permit ::/0, permit::/128`. - -At the moment of an ACL being applied to an interface, we need to -walk the list of *hash_ace_info_t* entries corresponding to that ACL, -and update the bihash with the keys corresponding to the match -values in these entries. - -The value of the hash match contains the index into a per-*sw_if_index* vector -of *applied_ace_hash_entry_t* elements, as well as a couple of flags: -*shadowed* (optimization: if this flag on a matched entry is zero, means -we can stop the lookup early and declare a match - see below), -and *need_portrange_check* - meaning that what matched was a superset -of the actual match, and we need to perform an extra check. - -Also, upon insertion, we must keep in mind there can be -multiple *applied_ace_hash_entry_t* for the same key and must keep -a list of those. This is necessary to incrementally apply/unapply -the ACLs as part of the ACL vector: say, two ACLs have -"permit 2001:db8::1/128 any" - we should be able to retain the entry -for the second ACL even if we have deleted the first one. -Also, in case there are two entries with the same key but -different port ranges, say 0..42 and 142..65535 - we need -to be able to sequentially match on those if we decide not -to expand them into individual port-specific entries. - -Per-packet lookup ------------------ - -The simple single-packet lookup is defined in -*multi_acl_match_get_applied_ace_index*, which returns the index -of the applied hash ACE if there was a match, or ~0 if there wasn't. - -The future optimized per-packet lookup may be batched in three phases: - -1. Prepare the keys in the per-worker vector by doing logical AND of - original 5-tuple record with the elements of the mask vector. -2. Lookup the keys in the bihash in a batch manner, collecting the - result with lowest u64 (acl index within vector, ACE index) from - the hash lookup value, and performing the list walk if necessary - (for portranges) -3. Take the action from the ACL record as defined by (ACL#, ACE#) from the - resulting lookup winner, or, if no match found, then perform default deny. - -Shadowed/independent/redundant ACEs ------------------------------------- - -During the phase of combining multiple ACLs into one rulebase, when they -are applied to interface, we also can perform several optimizations. - -If a given ACE is a strict subset of another ACE located up in the linear -search order, we can ignore this ACE completely - because by definition -it will never match. We will call such an ACE *redundant*. Here is an example: - -``` -permit 2001:db8:1::/48 2001:db8:2::/48 (B) -deny 2001:d8b:1:1::/64 2001:db8:2:1::/64 (A) -``` - -A bit more formally, we can define this relationship of an ACE A to ACE B as: - -``` -redundant(aceA, aceB) := (contains(protoB, protoA) && contains(srcB, srcA) - && contains(dstB, dstA) && is_after(A, B)) -``` - -Here as "contains" we define an operation operating on the sets defined by -the protocol, (srcIP, srcPortDefinition) and (dstIP, dstPortDefinition) -respectively, and returning true if all the elements represented by -the second argument are represented by the first argument. The "is_after" -is true if A is located below B in the ruleset. - -If a given ACE does not intersect at all with any other ACE -in front of it, we can mark it as such. - -Then during the sequence of the lookups the successful hit on this ACE means -we do not need to look up other mask combinations - thus potentially -significantly speeding up the match process. Here is an example, -assuming we have the following ACL: - -``` -permit 2001:db8:1::/48 2001:db8:2::/48 (B) -deny 2001:db8:3::/48 2001:db8:2:1::/64 (A) -``` - -In this case if we match the second entry, we do not need to check whether -we have matched the first one - the source addresses are completely -different. We call such an ACE *independent* from another. - -We can define this as - -``` -independent(aceA, aceB) := (!intersect(protoA, protoB) || - !intersect(srcA, srcB) || - !intersect(dstA, dstB)) -``` - -where intersect is defined as operation returning true if there are -elements belonging to the sets of both arguments. - -If the entry A is neither redundant nor independent from B, and is below -B in the ruleset, we call such an entry *shadowed* by B, here is an example: - -``` -deny tcp 2001:db8:1::/48 2001:db8:2::/48 (B) -permit 2001:d8b:1:1::/64 2001:db8:2:1::/64 (A) -``` - -This means the earlier rule "carves out" a subset of A, thus leaving -a "shadow". (Evidently, the action needs to be different for the shadow -to have an effect, but for for the terminology sake we do not care). - -The more formal definition: - -``` -shadowed(aceA, aceB) := !redundante(aceA, aceB) && - !independent(aceA, aceB) && - is_after(aceA, aceB) -``` - -Using this terminology, any ruleset can be represented as -a DAG (Directed Acyclic Graph), with the bottom being the implicit -"deny any", pointing to the set of rules shadowing it or the ones -it is redundant for. - -These rules may in turn be shadowing each other. There is no cycles in -this graph because of the natural order of the rules - the rule located -closer to the end of the ruleset can never shadow or make redundant a rule -higher up. - -The optimization that enables can allow for is to skip matching certain -masks on a per-lookup basis - if a given rule has matched, -the only adjustments that can happen is the match with one of -the shadowing rules. - -Also, another avenue for the optimization can be starting the lookup process -with the mask type that maximizes the chances of the independent ACE match, -thus resulting in an ACE lookup being a single hash table hit. - - -Plumbing --------- - -All the new routines are located in a separate file, -so we can cleanly experiment with a different approach if this -does not fit all of the use cases. - -The constant-time lookup within the data path has the API with -the same signature as: - -``` -u8 -multi_acl_match_5tuple (u32 sw_if_index, fa_5tuple_t * pkt_5tuple, int is_l2, - int is_ip6, int is_input, u32 * acl_match_p, - u32 * rule_match_p, u32 * trace_bitmap) -``` - -There should be a new upper-level function with the same signature, which -will make a decision whether to use a linear lookup, or to use the -constant-time lookup implemented by this work, or to add some other -optimizations (e.g. by keeping the cache of the last N lookups). - -The calls to the routine doing preparatory work should happen -in `acl_add_list()` after creating the linear-lookup structures, -and the routine doing the preparatory work populating the hashtable -should be called from `acl_interface_add_del_inout_acl()` or its callees. - -The initial implementation will be geared towards looking up a single -match at a time, with the subsequent optimizations possible to make -the lookup for more than one packet. - diff --git a/src/vlibapi/api_doc.md b/src/vlibapi/api_doc.md index e620ee12..2e7ae09a 100644 --- a/src/vlibapi/api_doc.md +++ b/src/vlibapi/api_doc.md @@ -6,12 +6,12 @@ APIs. Messages are defined in `*.api` files. Today, there are about 50 api files, with more arriving as folks add programmable features. The API file compiler -sources reside in @ref src/tools/vppapigen . +sources reside in @ref src/tools/vppapigen. -Here's a typical request/response message definition, from -@ref src/vnet/interface.api : +From @ref src/vnet/interface.api, here's a typical request/response message +definition: -``` +```{.c} autoreply define sw_interface_set_flags { u32 client_index; @@ -22,10 +22,10 @@ Here's a typical request/response message definition, from }; ``` -To a first approximation, the API compiler renders this definition as -follows: +To a first approximation, the API compiler renders this definition into +`build-root/.../vpp/include/vnet/interface.api.h` as follows: -``` +```{.c} /****** Message ID / handler enum ******/ #ifdef vl_msg_id vl_msg_id(VL_API_SW_INTERFACE_SET_FLAGS, vl_api_sw_interface_set_flags_t_handler) @@ -60,10 +60,13 @@ follows: u32 context; i32 retval; }) vl_api_sw_interface_set_flags_reply_t; + + ... + #endif /* vl_typedefs */ ``` To change the admin state of an interface, a binary api client sends a -@ref vl_api_sw_interface_set_flags_t to vpp, which will respond with a +@ref vl_api_sw_interface_set_flags_t to VPP, which will respond with a @ref vl_api_sw_interface_set_flags_reply_t message. Multiple layers of software, transport types, and shared libraries @@ -76,7 +79,7 @@ implement a variety of features: message handlers. Correctly-coded message handlers know nothing about the transport used to -deliver messages to/from vpp. It's reasonably straighforward to use multiple +deliver messages to/from VPP. It's reasonably straighforward to use multiple API message transport types simultaneously. For historical reasons, binary api messages are (putatively) sent in network @@ -90,12 +93,12 @@ Since binary API messages are always processed in order, we allocate messages using a ring allocator whenever possible. This scheme is extremely fast when compared with a traditional memory allocator, and doesn't cause heap fragmentation. See -@ref src/vlibmemory/memory_shared.c @ref vl_msg_api_alloc_internal() . +@ref src/vlibmemory/memory_shared.c @ref vl_msg_api_alloc_internal(). Regardless of transport, binary api messages always follow a @ref msgbuf_t header: -``` +```{.c} typedef struct msgbuf_ { unix_shared_memory_queue_t *q; @@ -109,7 +112,7 @@ This structure makes it easy to trace messages without having to decode them - simply save data_len bytes - and allows @ref vl_msg_api_free() to rapidly dispose of message buffers: -``` +```{.c} void vl_msg_api_free (void *a) { @@ -130,34 +133,34 @@ decode them - simply save data_len bytes - and allows return; } - } + } ``` ## Message Tracing and Replay -It's extremely important that vpp can capture and replay sizeable binary API +It's extremely important that VPP can capture and replay sizeable binary API traces. System-level issues involving hundreds of thousands of API transactions can be re-run in a second or less. Partial replay allows one to binary-search for the point where the wheels fall off. One can add scaffolding to the data plane, to trigger when complex conditions obtain. With binary API trace, print, and replay, system-level bug reports of the form -"after 300,000 API transactions, the vpp data-plane stopped forwarding +"after 300,000 API transactions, the VPP data-plane stopped forwarding traffic, FIX IT!" can be solved offline. More often than not, one discovers that a control-plane client misprograms the data plane after a long time or under complex circumstances. Without direct evidence, "it's a data-plane problem!" -See @ref src/vlibmemory/memory_vlib.c @ref vl_msg_api_process_file() , -and @ref src/vlibapi/api_shared.c . See also the debug CLI command "api trace" +See @ref src/vlibmemory/memory_vlib.c @ref vl_msg_api_process_file(), +and @ref src/vlibapi/api_shared.c. See also the debug CLI command "api trace" ## Client connection details -Establishing a binary API connection to vpp from a C-language client +Establishing a binary API connection to VPP from a C-language client is easy: -``` +```{.c} int connect_to_vpe (char *client_name, int client_message_queue_length) { @@ -176,9 +179,9 @@ is easy: } ``` -32 is a typical value for client_message_queue_length. Vpp cannot +32 is a typical value for client_message_queue_length. VPP cannot block when it needs to send an API message to a binary API client, and -the vpp-side binary API message handlers are very fast. When sending +the VPP-side binary API message handlers are very fast. When sending asynchronous messages, make sure to scrape the binary API rx ring with some enthusiasm. @@ -187,7 +190,7 @@ some enthusiasm. Calling @ref vl_client_connect_to_vlib spins up a binary API message RX pthread: -``` +```{.c} static void * rx_thread_fn (void *arg) { @@ -214,31 +217,31 @@ To handle the binary API message queue yourself, use @ref vl_client_connect_to_vlib_no_rx_pthread. In turn, vl_msg_api_queue_handler(...) uses mutex/condvar signalling -to wake up, process vpp -> client traffic, then sleep. Vpp supplies a -condvar broadcast when the vpp -> client API message queue transitions +to wake up, process VPP -> client traffic, then sleep. VPP supplies a +condvar broadcast when the VPP -> client API message queue transitions from empty to nonempty. -Vpp checks its own binary API input queue at a very high rate. Vpp +VPP checks its own binary API input queue at a very high rate. VPP invokes message handlers in "process" context [aka cooperative multitasking thread context] at a variable rate, depending on data-plane packet processing requirements. ## Client disconnection details -To disconnect from vpp, call @ref vl_client_disconnect_from_vlib -. Please arrange to call this function if the client application -terminates abnormally. Vpp makes every effort to hold a decent funeral -for dead clients, but vpp can't guarantee to free leaked memory in the +To disconnect from VPP, call @ref vl_client_disconnect_from_vlib. +Please arrange to call this function if the client application +terminates abnormally. VPP makes every effort to hold a decent funeral +for dead clients, but VPP can't guarantee to free leaked memory in the shared binary API segment. -## Sending binary API messages to vpp +## Sending binary API messages to VPP -The point of the exercise is to send binary API messages to vpp, and -to receive replies from vpp. Many vpp binary APIs comprise a client +The point of the exercise is to send binary API messages to VPP, and +to receive replies from VPP. Many VPP binary APIs comprise a client request message, and a simple status reply. For example, to set the admin status of an interface, one codes: -``` +```{.c} vl_api_sw_interface_set_flags_t *mp; mp = vl_msg_api_alloc (sizeof (*mp)); @@ -262,9 +265,9 @@ Key points: network byte order * The client-library global data structure @ref api_main keeps track - of sufficient pointers and handles used to communicate with vpp + of sufficient pointers and handles used to communicate with VPP -## Receiving binary API messages from vpp +## Receiving binary API messages from VPP Unless you've made other arrangements (see @ref vl_client_connect_to_vlib_no_rx_pthread), *messages are received on a @@ -273,7 +276,7 @@ thread is the responsibility of the application! Set up message handlers about as follows: -``` +```{.c} #define vl_typedefs /* define message structures */ #include #undef vl_typedefs @@ -319,7 +322,7 @@ vectors in the @ref api_main_t structure. As of this writing: not all vector element values can be set through the API. You'll see sporadic API message registrations followed by minor adjustments of this form: -``` +```{.c} /* * Thread-safe API messages */ -- cgit 1.2.3-korg