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 <chrisy@flirble.org>
This commit is contained in:
@ -16,14 +16,18 @@
|
|||||||
# Build the documentation
|
# Build the documentation
|
||||||
#
|
#
|
||||||
|
|
||||||
|
# Default target
|
||||||
|
.PHONY: all
|
||||||
|
all: doxygen
|
||||||
|
|
||||||
# These should be passed in by the root Makefile
|
# These should be passed in by the root Makefile
|
||||||
WS_ROOT ?= $(CURDIR)/..
|
WS_ROOT ?= $(CURDIR)/..
|
||||||
BR ?= $(WS_ROOT)/build-root
|
BR ?= $(WS_ROOT)/build-root
|
||||||
OS_ID ?= $(shell grep '^ID=' /etc/os-release | cut -f2- -d= | sed -e 's/\"//g')
|
OS_ID ?= $(shell grep '^ID=' /etc/os-release | cut -f2- -d= | sed -e 's/\"//g')
|
||||||
|
|
||||||
# Package dependencies
|
# Package dependencies
|
||||||
DOC_DEB_DEPENDS = doxygen graphviz python-pyparsing
|
DOC_DEB_DEPENDS = doxygen graphviz python-pyparsing python-jinja2
|
||||||
DOC_RPM_DEPENDS = doxygen graphviz pyparsing
|
DOC_RPM_DEPENDS = doxygen graphviz pyparsing python-jinja2
|
||||||
|
|
||||||
# Doxygen configuration and our utility scripts
|
# Doxygen configuration and our utility scripts
|
||||||
DOXY_DIR ?= $(WS_ROOT)/doxygen
|
DOXY_DIR ?= $(WS_ROOT)/doxygen
|
||||||
@ -104,19 +108,22 @@ SIPHON_OUTPUT ?= $(DOXY_OUTPUT)/siphon_docs
|
|||||||
EXTRA_DOXY_INPUT += $(SIPHON_OUTPUT)
|
EXTRA_DOXY_INPUT += $(SIPHON_OUTPUT)
|
||||||
|
|
||||||
# All the siphon types we know about
|
# All the siphon types we know about
|
||||||
SIPHONS ?= clicmd
|
SIPHONS ?= clicmd syscfg
|
||||||
|
|
||||||
SIPHON_FILES = $(addprefix $(SIPHON_INPUT)/,$(addsuffix .siphon,$(SIPHONS)))
|
SIPHON_FILES = $(addprefix $(SIPHON_INPUT)/,$(addsuffix .siphon,$(SIPHONS)))
|
||||||
SIPHON_DOCS = $(addprefix $(SIPHON_OUTPUT)/,$(addsuffix .md,$(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..."
|
@echo "Checking whether dependencies for Doxygen are installed..."
|
||||||
ifeq ($(OS_ID),ubuntu)
|
ifeq ($(OS_ID),ubuntu)
|
||||||
@set -e; inst=; \
|
@set -e; inst=; \
|
||||||
for i in $(DOC_DEB_DEPENDS); do \
|
for i in $(DOC_DEB_DEPENDS); do \
|
||||||
dpkg-query --show $$i >/dev/null 2>&1 || inst="$$inst $$i"; \
|
dpkg-query --show $$i >/dev/null 2>&1 || inst="$$inst $$i"; \
|
||||||
done; \
|
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 \
|
@if [ ! -s /usr/lib/graphviz/config6a ]; then \
|
||||||
echo "Rebuidlding system Graphviz configuration."; \
|
echo "Rebuidlding system Graphviz configuration."; \
|
||||||
sudo dot -c; \
|
sudo dot -c; \
|
||||||
@ -145,8 +152,12 @@ $(BR)/.doxygen-siphon.dep: Makefile
|
|||||||
# Include the source -> siphon dependencies
|
# Include the source -> siphon dependencies
|
||||||
-include $(BR)/.doxygen-siphon.dep
|
-include $(BR)/.doxygen-siphon.dep
|
||||||
|
|
||||||
|
# Generate .siphon files that contain fragments of source file that
|
||||||
|
# relate to the siphons we support.
|
||||||
.NOTPARALLEL: $(SIPHON_FILES)
|
.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)"
|
@rm -rf "$(SIPHON_INPUT)" "$(SIPHON_OUTPUT)"
|
||||||
@mkdir -p "$(SIPHON_INPUT)" "$(SIPHON_OUTPUT)"
|
@mkdir -p "$(SIPHON_INPUT)" "$(SIPHON_OUTPUT)"
|
||||||
@touch $(SIPHON_INPUT)/files
|
@touch $(SIPHON_INPUT)/files
|
||||||
@ -159,23 +170,33 @@ $(SIPHON_FILES): $(DOXY_DIR)/siphon_generate.py $(BR)/.doxygen-bootstrap.ok
|
|||||||
>> $(SIPHON_INPUT)/files; \
|
>> $(SIPHON_INPUT)/files; \
|
||||||
done
|
done
|
||||||
@echo "Generating siphons..."
|
@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)" \
|
--output="$(SIPHON_INPUT)" \
|
||||||
"@$(SIPHON_INPUT)/files"
|
"@$(SIPHON_INPUT)/files"
|
||||||
|
|
||||||
|
# Process the .siphon source fragments and render them into doxygen flavored
|
||||||
|
# markdown documentation
|
||||||
.DELETE_ON_ERROR: $(SIPHON_DOCS)
|
.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 $<)..."
|
@echo "Processing siphon from $(notdir $<)..."
|
||||||
@set -e; cd "$(WS_ROOT)"; \
|
@set -e; \
|
||||||
$(DOXY_DIR)/siphon_process.py --type=$(basename $(notdir $<)) \
|
cd "$(WS_ROOT)"; \
|
||||||
--output="$(SIPHON_OUTPUT)" $< > $@
|
$(DOXY_DIR)/siphon-process \
|
||||||
|
--type=$(basename $(notdir $<)) \
|
||||||
|
--output="$@" \
|
||||||
|
"$<"
|
||||||
|
|
||||||
# This target can be used just to generate the siphoned docs
|
# This target can be used just to generate the siphoned docs
|
||||||
.PHONY: doxygen-siphon
|
.PHONY: doxygen-siphon
|
||||||
doxygen-siphon: $(SIPHON_DOCS)
|
doxygen-siphon: $(SIPHON_DOCS)
|
||||||
|
|
||||||
# Generate the doxygen docs
|
# Generate the doxygen docs
|
||||||
|
.PHONY: doxygen
|
||||||
doxygen: $(SIPHON_DOCS)
|
doxygen: $(SIPHON_DOCS)
|
||||||
@mkdir -p "$(DOXY_OUTPUT)"
|
@mkdir -p "$(DOXY_OUTPUT)"
|
||||||
@echo "Running Doxygen..."
|
@echo "Running Doxygen..."
|
||||||
@ -189,6 +210,9 @@ doxygen: $(SIPHON_DOCS)
|
|||||||
VERSION="`git describe --tags --dirty`" \
|
VERSION="`git describe --tags --dirty`" \
|
||||||
doxygen $(DOXY_DIR)/doxygen.cfg
|
doxygen $(DOXY_DIR)/doxygen.cfg
|
||||||
|
|
||||||
|
.PHONY: wipe-doxygen
|
||||||
wipe-doxygen:
|
wipe-doxygen:
|
||||||
rm -rf "$(BR)/docs" "$(BR)/.doxygen-siphon.d"
|
rm -rf "$(BR)/docs" "$(BR)/.doxygen-siphon.d"
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean: wipe-doxygen
|
||||||
|
@ -27,3 +27,4 @@ This looks like a C file but it is not part of the build; it is purely
|
|||||||
for documentation.
|
for documentation.
|
||||||
*/
|
*/
|
||||||
/*? %%clicmd:group_label CLI section description%% ?*/
|
/*? %%clicmd:group_label CLI section description%% ?*/
|
||||||
|
/*? %%syscfg:group_label Startup config section description%% ?*/
|
||||||
|
@ -244,6 +244,9 @@ ALIASES += "cliexcmd{1}=@clistart<b>vpp# <em>\1</em></b>@cliend"
|
|||||||
ALIASES += "cliexstart{1}=@cliexcmd{\1}@clistart"
|
ALIASES += "cliexstart{1}=@cliexcmd{\1}@clistart"
|
||||||
ALIASES += "cliexend=@cliend"
|
ALIASES += "cliexend=@cliend"
|
||||||
|
|
||||||
|
## Formatting for config directives
|
||||||
|
ALIASES += "cfgcmd{2}=@par <code><pre>\1 \2</pre></code>"
|
||||||
|
ALIASES += "cfgcmd{1}=@par <code><pre>\1</pre></code>"
|
||||||
|
|
||||||
# This tag can be used to specify a number of word-keyword mappings (TCL only).
|
# 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"
|
# A mapping has the form "name=value". For example adding "class=itcl::class"
|
||||||
|
74
doxygen/siphon-generate
Executable file
74
doxygen/siphon-generate
Executable file
@ -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
|
67
doxygen/siphon-process
Executable file
67
doxygen/siphon-process
Executable file
@ -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
|
24
doxygen/siphon/__init__.py
Normal file
24
doxygen/siphon/__init__.py
Normal file
@ -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
|
304
doxygen/siphon/generate.py
Normal file
304
doxygen/siphon/generate.py
Normal file
File diff suppressed because it is too large
Load Diff
22
doxygen/siphon/generate_clicmd.py
Normal file
22
doxygen/siphon/generate_clicmd.py
Normal file
@ -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("(?P<m>VLIB_CLI_COMMAND)\s*"
|
||||||
|
"[(](?P<name>[a-zA-Z0-9_]+)(,[^)]*)?[)]"),
|
||||||
|
"clicmd"
|
||||||
|
))
|
22
doxygen/siphon/generate_syscfg.py
Normal file
22
doxygen/siphon/generate_syscfg.py
Normal file
@ -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("(?P<m>VLIB_CONFIG_FUNCTION)\s*"
|
||||||
|
'[(](?P<fn>[a-zA-Z0-9_]+)\s*,\s*"(?P<name>[^"]*)"[)]'),
|
||||||
|
"syscfg"
|
||||||
|
))
|
149
doxygen/siphon/parsers.py
Normal file
149
doxygen/siphon/parsers.py
Normal file
@ -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 <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
|
271
doxygen/siphon/process.py
Normal file
271
doxygen/siphon/process.py
Normal file
@ -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)
|
56
doxygen/siphon/process_clicmd.py
Normal file
56
doxygen/siphon/process_clicmd.py
Normal file
@ -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
|
30
doxygen/siphon/process_syscfg.py
Normal file
30
doxygen/siphon/process_syscfg.py
Normal file
@ -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
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
17
doxygen/siphon_templates/clicmd/index_entry.md
Normal file
17
doxygen/siphon_templates/clicmd/index_entry.md
Normal file
@ -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"]) }}
|
130
doxygen/siphon_templates/clicmd/index_header.md
Normal file
130
doxygen/siphon_templates/clicmd/index_header.md
Normal file
@ -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 <cli-command>
|
||||||
|
```
|
||||||
|
|
||||||
|
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]
|
59
doxygen/siphon_templates/clicmd/item_format.md
Normal file
59
doxygen/siphon_templates/clicmd/item_format.md
Normal file
@ -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 %}
|
||||||
|
|
16
doxygen/siphon_templates/default/index_entry.md
Normal file
16
doxygen/siphon_templates/default/index_entry.md
Normal file
@ -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"]) }}
|
18
doxygen/siphon_templates/default/index_section.md
Normal file
18
doxygen/siphon_templates/default/index_section.md
Normal file
@ -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) }}
|
||||||
|
|
16
doxygen/siphon_templates/default/item_format.md
Normal file
16
doxygen/siphon_templates/default/item_format.md
Normal file
@ -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 }}
|
18
doxygen/siphon_templates/default/item_header.md
Normal file
18
doxygen/siphon_templates/default/item_header.md
Normal file
@ -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)) }}
|
||||||
|
|
111
doxygen/siphon_templates/syscfg/index_header.md
Normal file
111
doxygen/siphon_templates/syscfg/index_header.md
Normal file
@ -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:
|
||||||
|
|
||||||
|
<startup diagnostic messages>
|
||||||
|
_______ _ _ _____ ___
|
||||||
|
__/ __/ _ \ (_)__ | | / / _ \/ _ \
|
||||||
|
_/ _// // / / / _ \ | |/ / ___/ ___/
|
||||||
|
/_/ /____(_)_/\___/ |___/_/ /_/
|
||||||
|
|
||||||
|
vpp# <start-typing>
|
||||||
|
|
||||||
|
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 <options>`. 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]
|
||||||
|
|
42
doxygen/siphon_templates/syscfg/item_format.md
Normal file
42
doxygen/siphon_templates/syscfg/item_format.md
Normal file
@ -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 %}
|
||||||
|
|
@ -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 <stdio.h>
|
#include <stdio.h>
|
||||||
#include <vlib/vlib.h>
|
#include <vlib/vlib.h>
|
||||||
|
|
||||||
@ -94,6 +104,18 @@ cj_config (vlib_main_t * vm, unformat_input_t * input)
|
|||||||
return 0;
|
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");
|
VLIB_CONFIG_FUNCTION (cj_config, "cj");
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -220,10 +242,21 @@ cj_command_fn (vlib_main_t * vm,
|
|||||||
return 0;
|
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 <code>unix interactive</code> mode
|
||||||
|
* this is typically the same place as the Debug CLI.
|
||||||
|
?*/
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
VLIB_CLI_COMMAND (cj_command,static) = {
|
VLIB_CLI_COMMAND (cj_command,static) = {
|
||||||
.path = "cj",
|
.path = "cj",
|
||||||
.short_help = "cj",
|
.short_help = "cj <enable | disable | dump>",
|
||||||
.function = cj_command_fn,
|
.function = cj_command_fn,
|
||||||
};
|
};
|
||||||
/* *INDENT-ON* */
|
/* *INDENT-ON* */
|
||||||
|
@ -42,7 +42,8 @@
|
|||||||
* Provides a command line interface so humans can interact with VPP.
|
* Provides a command line interface so humans can interact with VPP.
|
||||||
* This is predominantly a debugging and testing mechanism.
|
* 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 <vlib/vlib.h>
|
#include <vlib/vlib.h>
|
||||||
#include <vlib/unix/unix.h>
|
#include <vlib/unix/unix.h>
|
||||||
@ -2504,6 +2505,9 @@ unix_cli_config (vlib_main_t * vm, unformat_input_t * input)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*?
|
||||||
|
* This module has no configurable parameters.
|
||||||
|
?*/
|
||||||
VLIB_CONFIG_FUNCTION (unix_cli_config, "unix-cli");
|
VLIB_CONFIG_FUNCTION (unix_cli_config, "unix-cli");
|
||||||
|
|
||||||
/** Called when VPP is shutting down, this restores the system
|
/** Called when VPP is shutting down, this restores the system
|
||||||
|
@ -23,5 +23,6 @@
|
|||||||
VLIB application library Unix interface layer.
|
VLIB application library Unix interface layer.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
/*? %%clicmd:group_label VLIB Unix stuff%% ?*/
|
/*? %%clicmd:group_label Unix Interface %% ?*/
|
||||||
|
/*? %%syscfg:group_label Unix Interface %% ?*/
|
||||||
|
|
||||||
|
@ -407,6 +407,59 @@ unix_config (vlib_main_t * vm, unformat_input_t * input)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* unix { ... } configuration. */
|
/* 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 <code>startup-config <filename></code>
|
||||||
|
* 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 <tt>cli-listen localhost:5002</tt>,
|
||||||
|
* is typical.
|
||||||
|
*
|
||||||
|
* @cfgcmd{cli-line-mode}
|
||||||
|
* Disable character-by-character I/O on stdin. Useful when combined with,
|
||||||
|
* for example, <tt>emacs M-x gud-gdb</tt>.
|
||||||
|
*
|
||||||
|
* @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");
|
VLIB_CONFIG_FUNCTION (unix_config, "unix");
|
||||||
|
|
||||||
static clib_error_t *
|
static clib_error_t *
|
||||||
|
Reference in New Issue
Block a user