From cb9cadad578297ffd78fa8a33670bdf1ab669e7e Mon Sep 17 00:00:00 2001 From: Ed Warnicke Date: Tue, 8 Dec 2015 15:45:58 -0700 Subject: Initial commit of vpp code. Change-Id: Ib246f1fbfce93274020ee93ce461e3d8bd8b9f17 Signed-off-by: Ed Warnicke --- build-data/platforms.mk | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 build-data/platforms.mk (limited to 'build-data/platforms.mk') diff --git a/build-data/platforms.mk b/build-data/platforms.mk new file mode 100644 index 00000000..38f840e1 --- /dev/null +++ b/build-data/platforms.mk @@ -0,0 +1,71 @@ +# 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. + +# Pick up per-platform makefile fragments +$(foreach d,$(SOURCE_PATH_BUILD_DATA_DIRS), \ + $(eval -include $(d)/platforms/*.mk)) + +.PHONY: install-deb +install-deb: $(patsubst %,%-find-source,$(ROOT_PACKAGES)) + @$(BUILD_ENV) ; \ + set -eu$(BUILD_DEBUG) ; \ + $(MAKE) -C $(MU_BUILD_ROOT_DIR) \ + $(patsubst %,%-install, \ + $(ROOT_PACKAGES)) || exit 1; \ + \ + : generate file manifests ; \ + find $(INSTALL_PREFIX)$(ARCH)/*/bin -type f -print \ + | sed -e 's:.*:../& /usr/bin:' \ + > deb/debian/vpp.install ; \ + find $(INSTALL_PREFIX)$(ARCH)/*/lib* -type f -print \ + | egrep -e '*\.so\.*\.*\.*' \ + | sed -e 's:.*:../& /usr/lib/x86_64-linux-gnu:' \ + > deb/debian/vpp-lib.install ; \ + \ + : dev package ; \ + ./scripts/find-dev-contents $(INSTALL_PREFIX)$(ARCH) \ + deb/debian/vpp-dev.install ; \ + \ + : bin package needs startup config ; \ + echo ../../vpp/conf/startup.conf /etc/vpp \ + >> deb/debian/vpp.install ; \ + \ + : and sysctl config ; \ + echo ../../vpp/conf/80-vpp.conf /etc/sysctl.d \ + >> deb/debian/vpp.install ; \ + \ + : dev package needs a couple of additions ; \ + echo ../build-tool-native/vppapigen/vppapigen /usr/bin \ + >> deb/debian/vpp-dev.install ; \ + \ + : generate changelog; \ + ./scripts/generate-deb-changelog \ + \ + : Go fabricate the actual Debian packages ; \ + ( \ + cd deb && \ + dpkg-buildpackage -us -uc -b \ + ) + +.PHONY: install-rpm +install-rpm: $(patsubst %,%-find-source,$(ROOT_PACKAGES)) + @$(BUILD_ENV) ; \ + set -eu$(BUILD_DEBUG) ; \ + $(MAKE) -C $(MU_BUILD_ROOT_DIR) \ + $(patsubst %,%-install, \ + $(ROOT_PACKAGES)) || exit 1; \ + \ + cd rpm ; \ + rpmbuild -bb --define "_topdir $$PWD" vpp.spec ; \ + mv $$(find RPMS -name \*.rpm -type f) .. + -- cgit 1.2.3-korg From 74574228b0f63a3c8fd373321ed25f4d24308df0 Mon Sep 17 00:00:00 2001 From: Dave Barach Date: Mon, 1 Feb 2016 12:05:52 -0500 Subject: Add a vpp-dpdk-dev package, enable plugins to use dpdk APIs directly Change-Id: I69db06a0b5d5d556c2fd570ea0056bb59d7bc3d6 Signed-off-by: Dave Barach --- .gitignore | 1 + build-data/platforms.mk | 4 ++++ build-root/deb/debian/.gitignore | 1 + build-root/deb/debian/control | 16 ++++++++-------- build-root/scripts/find-dpdk-contents | 20 ++++++++++++++++++++ 5 files changed, 34 insertions(+), 8 deletions(-) create mode 100755 build-root/scripts/find-dpdk-contents (limited to 'build-data/platforms.mk') diff --git a/.gitignore b/.gitignore index 05d08a6b..f0b17c0d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ /build-root/build-*/ /build-root/install-*/ /build-root/tools +/build-root/dpdk-includes/ /build-root/packages-vpp/ /build-root/path_setup /build-root/build-config.mk diff --git a/build-data/platforms.mk b/build-data/platforms.mk index 38f840e1..988be14b 100644 --- a/build-data/platforms.mk +++ b/build-data/platforms.mk @@ -36,6 +36,10 @@ install-deb: $(patsubst %,%-find-source,$(ROOT_PACKAGES)) ./scripts/find-dev-contents $(INSTALL_PREFIX)$(ARCH) \ deb/debian/vpp-dev.install ; \ \ + : dpdk headers ; \ + ./scripts/find-dpdk-contents $(INSTALL_PREFIX)$(ARCH) \ + deb/debian/vpp-dpdk-dev.install ; \ + \ : bin package needs startup config ; \ echo ../../vpp/conf/startup.conf /etc/vpp \ >> deb/debian/vpp.install ; \ diff --git a/build-root/deb/debian/.gitignore b/build-root/deb/debian/.gitignore index 261ea486..e7868b4e 100644 --- a/build-root/deb/debian/.gitignore +++ b/build-root/deb/debian/.gitignore @@ -7,6 +7,7 @@ vpp-dpdk-dkms* vpp/ vpp-dev/ vpp-lib/ +vpp-dpdk-dev/ vpp-dpdk-dkms/ vpp-dbg/ vppctl/ diff --git a/build-root/deb/debian/control b/build-root/deb/debian/control index a90cea76..cf22fd02 100644 --- a/build-root/deb/debian/control +++ b/build-root/deb/debian/control @@ -23,16 +23,16 @@ Package: vpp-dev Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Vector Packet Processing--development support - This package contains development support files for the VPP libraries, including: + This package contains development support files for the VPP libraries . - Do we need to list those header files or just leave it blank ? - dynamic vectors (vec.c), dynamic bitmaps (bitmap.h), allocation heap of - objects (heap.c), allocation pool(pool.h), dynamic hash tables (hash.c), memory - allocator (mheap.c), extendable printf-like interface built on top of vectors - (format.c), formats for data structures (std-formats.c), and support for clock - time-based function calls (timer.c). + +Package: vpp-dpdk-dev +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Vector Packet Processing--development support + This package contains dpdk header files which match the dpdk version + compiled into the vpp executable . - TODO: reference and describe only the .h files Package: vpp-lib Architecture: any diff --git a/build-root/scripts/find-dpdk-contents b/build-root/scripts/find-dpdk-contents new file mode 100755 index 00000000..f8c80b5b --- /dev/null +++ b/build-root/scripts/find-dpdk-contents @@ -0,0 +1,20 @@ +#!/bin/bash + +# includes +rm -rf dpdk-includes +mkdir dpdk-includes +(cd $1/dpdk/include; tar cfh - . | (cd ../../../dpdk-includes; tar xf -)) + +paths=`cd dpdk-includes; find . -type f -print` +rm -f $2 + +for path in $paths +do + dir=`dirname $path` + if [ $dir = "." ] ; then + echo ../dpdk-includes/$path /usr/include/vpp-dpdk >> $2 + else + echo ../dpdk-includes/$path /usr/include/vpp-dpdk/$dir >> $2 + fi +done + -- cgit 1.2.3-korg From 1c11311b322ecf0b4bc88949f394922e9940ebb0 Mon Sep 17 00:00:00 2001 From: Dave Barach Date: Wed, 3 Feb 2016 12:59:38 -0500 Subject: Need to include symbolic links in the lib package: libXXX.so, libXXX.so.0 Otherwise, autotools can't find libXXX, -lXXX doesn't work, etc. Change-Id: I9c4c43f795ca872475f65bc0e4494674eaa00576 Signed-off-by: Dave Barach --- build-data/platforms.mk | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'build-data/platforms.mk') diff --git a/build-data/platforms.mk b/build-data/platforms.mk index 988be14b..8a18ec14 100644 --- a/build-data/platforms.mk +++ b/build-data/platforms.mk @@ -27,8 +27,10 @@ install-deb: $(patsubst %,%-find-source,$(ROOT_PACKAGES)) find $(INSTALL_PREFIX)$(ARCH)/*/bin -type f -print \ | sed -e 's:.*:../& /usr/bin:' \ > deb/debian/vpp.install ; \ - find $(INSTALL_PREFIX)$(ARCH)/*/lib* -type f -print \ - | egrep -e '*\.so\.*\.*\.*' \ + \ + : need symbolic links in the lib pkg ; \ + find $(INSTALL_PREFIX)$(ARCH)/*/lib* \( -type f -o -type l \) \ + -print | egrep -e '*\.so\.*\.*\.*' \ | sed -e 's:.*:../& /usr/lib/x86_64-linux-gnu:' \ > deb/debian/vpp-lib.install ; \ \ -- cgit 1.2.3-korg From 693b7026a8da00d4b325f1cde09959d88696b294 Mon Sep 17 00:00:00 2001 From: Sachin Date: Sat, 18 Jun 2016 15:28:08 +0530 Subject: Enhanced RPM build process to make rpm for any given platform - Currently default rpm.spec only look for "install-vpp-native" Change-Id: Iaa78c46ae62d2747bda6ffc1189cb8ac6d578bd8 Signed-off-by: Sachin --- build-data/platforms.mk | 3 ++- build-root/rpm/vpp.spec | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'build-data/platforms.mk') diff --git a/build-data/platforms.mk b/build-data/platforms.mk index 8a18ec14..625006b4 100644 --- a/build-data/platforms.mk +++ b/build-data/platforms.mk @@ -72,6 +72,7 @@ install-rpm: $(patsubst %,%-find-source,$(ROOT_PACKAGES)) $(ROOT_PACKAGES)) || exit 1; \ \ cd rpm ; \ - rpmbuild -bb --define "_topdir $$PWD" vpp.spec ; \ + rpmbuild -bb --define "_topdir $$PWD" --define \ + "_install_dir $(INSTALL_PREFIX)$(ARCH)" vpp.spec ; \ mv $$(find RPMS -name \*.rpm -type f) .. diff --git a/build-root/rpm/vpp.spec b/build-root/rpm/vpp.spec index b02b2bfe..4a666e68 100644 --- a/build-root/rpm/vpp.spec +++ b/build-root/rpm/vpp.spec @@ -1,4 +1,4 @@ -%define _vpp_install_dir ../install-vpp-native +%define _vpp_install_dir ../%{_install_dir} %define _vpp_build_dir ../build-tool-native %define _unitdir /lib/systemd/system %define _topdir %(pwd) -- cgit 1.2.3-korg From ad476c7861d0428766f9bee01f69cd00025a47c0 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Wed, 13 Jul 2016 13:42:33 +0200 Subject: Add plugins debian packaging New debian package "vpp-plugins" is created with enabled plugins. Change-Id: I8920178e8874f12e075858001ec44257dfaf497d Signed-off-by: Damjan Marion --- build-data/platforms.mk | 5 +++++ build-data/platforms/vpp.mk | 2 +- build-root/deb/debian/control | 7 +++++++ build-root/scripts/find-plugins-contents | 11 +++++++++++ 4 files changed, 24 insertions(+), 1 deletion(-) create mode 100755 build-root/scripts/find-plugins-contents (limited to 'build-data/platforms.mk') diff --git a/build-data/platforms.mk b/build-data/platforms.mk index 625006b4..65809ea6 100644 --- a/build-data/platforms.mk +++ b/build-data/platforms.mk @@ -31,6 +31,7 @@ install-deb: $(patsubst %,%-find-source,$(ROOT_PACKAGES)) : need symbolic links in the lib pkg ; \ find $(INSTALL_PREFIX)$(ARCH)/*/lib* \( -type f -o -type l \) \ -print | egrep -e '*\.so\.*\.*\.*' \ + | grep -v plugins\/ \ | sed -e 's:.*:../& /usr/lib/x86_64-linux-gnu:' \ > deb/debian/vpp-lib.install ; \ \ @@ -38,6 +39,10 @@ install-deb: $(patsubst %,%-find-source,$(ROOT_PACKAGES)) ./scripts/find-dev-contents $(INSTALL_PREFIX)$(ARCH) \ deb/debian/vpp-dev.install ; \ \ + : plugins package ; \ + ./scripts/find-plugins-contents $(INSTALL_PREFIX)$(ARCH) \ + deb/debian/vpp-plugins.install ; \ + \ : dpdk headers ; \ ./scripts/find-dpdk-contents $(INSTALL_PREFIX)$(ARCH) \ deb/debian/vpp-dpdk-dev.install ; \ diff --git a/build-data/platforms/vpp.mk b/build-data/platforms/vpp.mk index fb1867c7..977c4c32 100644 --- a/build-data/platforms/vpp.mk +++ b/build-data/platforms/vpp.mk @@ -30,7 +30,7 @@ vpp_uses_dpdk = yes # vpp_enable_tests = yes vpp_root_packages = vpp vlib vlib-api vnet svm vpp-api-test \ - vpp-api gmod + vpp-api gmod plugins vpp_configure_args_vpp = --with-dpdk vnet_configure_args_vpp = --with-dpdk diff --git a/build-root/deb/debian/control b/build-root/deb/debian/control index 97464e42..d1e7680e 100644 --- a/build-root/deb/debian/control +++ b/build-root/deb/debian/control @@ -47,6 +47,13 @@ Description: Vector Packet Processing--runtime libraries vlib-api - binary API library vnet - network stack library +Package: vpp-plugins +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Vector Packet Processing--runtime plugins + This package contains VPP plugins + . + Package: vpp-dpdk-dkms Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} diff --git a/build-root/scripts/find-plugins-contents b/build-root/scripts/find-plugins-contents new file mode 100755 index 00000000..8d1a4d5a --- /dev/null +++ b/build-root/scripts/find-plugins-contents @@ -0,0 +1,11 @@ +#!/bin/bash + +rm -f $2 + +for i in ${1}/plugins/lib64/vpp_plugins/*.so; do + echo ../${i} /usr/lib/vpp_plugins >> ${2} +done + +for i in ${1}/plugins/lib64/vpp_api_test_plugins/*.so; do + echo ../${i} /usr/lib/vpp_api_test_plugins >> ${2} +done -- cgit 1.2.3-korg From adeb749d13cbb750bcb25dac15314b80032fe024 Mon Sep 17 00:00:00 2001 From: Ed Warnicke Date: Mon, 11 Jul 2016 10:29:41 -0700 Subject: Create python package for jvpp generation. Change-Id: I2254f90b2c3e423563bb91bf70877979f1e86a6b Signed-off-by: Ed Warnicke Signed-off-by: Marek Gradzki --- .gitignore | 3 + build-data/platforms.mk | 10 +- vpp-api/java/jvpp/gen/callback_gen.py | 102 ---- vpp-api/java/jvpp/gen/dto_gen.py | 177 ------- vpp-api/java/jvpp/gen/jvpp_c_gen.py | 525 --------------------- vpp-api/java/jvpp/gen/jvpp_callback_facade_gen.py | 297 ------------ vpp-api/java/jvpp/gen/jvpp_future_facade_gen.py | 315 ------------- vpp-api/java/jvpp/gen/jvpp_gen.py | 30 +- vpp-api/java/jvpp/gen/jvpp_impl_gen.py | 173 ------- vpp-api/java/jvpp/gen/jvppgen/__init__.py | 0 vpp-api/java/jvpp/gen/jvppgen/callback_gen.py | 102 ++++ vpp-api/java/jvpp/gen/jvppgen/dto_gen.py | 177 +++++++ vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py | 525 +++++++++++++++++++++ .../jvpp/gen/jvppgen/jvpp_callback_facade_gen.py | 297 ++++++++++++ .../jvpp/gen/jvppgen/jvpp_future_facade_gen.py | 315 +++++++++++++ vpp-api/java/jvpp/gen/jvppgen/jvpp_impl_gen.py | 173 +++++++ vpp-api/java/jvpp/gen/jvppgen/notification_gen.py | 164 +++++++ vpp-api/java/jvpp/gen/jvppgen/util.py | 195 ++++++++ vpp-api/java/jvpp/gen/notification_gen.py | 164 ------- vpp-api/java/jvpp/gen/util.py | 195 -------- 20 files changed, 1978 insertions(+), 1961 deletions(-) delete mode 100644 vpp-api/java/jvpp/gen/callback_gen.py delete mode 100644 vpp-api/java/jvpp/gen/dto_gen.py delete mode 100644 vpp-api/java/jvpp/gen/jvpp_c_gen.py delete mode 100644 vpp-api/java/jvpp/gen/jvpp_callback_facade_gen.py delete mode 100644 vpp-api/java/jvpp/gen/jvpp_future_facade_gen.py delete mode 100644 vpp-api/java/jvpp/gen/jvpp_impl_gen.py create mode 100644 vpp-api/java/jvpp/gen/jvppgen/__init__.py create mode 100644 vpp-api/java/jvpp/gen/jvppgen/callback_gen.py create mode 100644 vpp-api/java/jvpp/gen/jvppgen/dto_gen.py create mode 100644 vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py create mode 100644 vpp-api/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py create mode 100644 vpp-api/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py create mode 100644 vpp-api/java/jvpp/gen/jvppgen/jvpp_impl_gen.py create mode 100644 vpp-api/java/jvpp/gen/jvppgen/notification_gen.py create mode 100644 vpp-api/java/jvpp/gen/jvppgen/util.py delete mode 100644 vpp-api/java/jvpp/gen/notification_gen.py delete mode 100644 vpp-api/java/jvpp/gen/util.py (limited to 'build-data/platforms.mk') diff --git a/.gitignore b/.gitignore index 250532aa..42526183 100644 --- a/.gitignore +++ b/.gitignore @@ -69,3 +69,6 @@ GTAGS # indent backup files *.BAK + +# Python bytecode +*.pyc diff --git a/build-data/platforms.mk b/build-data/platforms.mk index 65809ea6..cd65f67c 100644 --- a/build-data/platforms.mk +++ b/build-data/platforms.mk @@ -56,8 +56,14 @@ install-deb: $(patsubst %,%-find-source,$(ROOT_PACKAGES)) >> deb/debian/vpp.install ; \ \ : dev package needs a couple of additions ; \ - echo ../build-tool-native/vppapigen/vppapigen /usr/bin \ - >> deb/debian/vpp-dev.install ; \ + echo ../build-tool-native/vppapigen/vppapigen /usr/bin \ + >> deb/debian/vpp-dev.install ; \ + echo ../../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 \ + echo ../$${i} /usr/lib/python2.7/dist-packages/jvppgen \ + >> deb/debian/vpp-dev.install; \ + done; \ \ : generate changelog; \ ./scripts/generate-deb-changelog \ diff --git a/vpp-api/java/jvpp/gen/callback_gen.py b/vpp-api/java/jvpp/gen/callback_gen.py deleted file mode 100644 index eadf3b5c..00000000 --- a/vpp-api/java/jvpp/gen/callback_gen.py +++ /dev/null @@ -1,102 +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 $base_package.$callback_package; - -/** - *

Represents callback for vpe.api 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 $base_package.$callback_package; - -/** - *

Global aggregated callback interface. - *
It was generated by callback_gen.py based on $inputfile - *
(python representation of vpe.api generated by vppapigen). - */ -public interface JVppGlobalCallback extends $callbacks { -} -""") - - -def generate_callbacks(func_list, base_package, 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: - - if util.is_ignored(func['name']): - continue - - camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name']) - 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(base_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" % (base_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, - callback_package=callback_package, - callback_type=callback_type)) - callback_file.flush() - callback_file.close() - - callback_file = open(os.path.join(callback_package, "JVppGlobalCallback.java"), 'w') - callback_file.write(global_callback_template.substitute(inputfile=inputfile, - callbacks=", ".join(callbacks), - base_package=base_package, - callback_package=callback_package)) - callback_file.flush() - callback_file.close() diff --git a/vpp-api/java/jvpp/gen/dto_gen.py b/vpp-api/java/jvpp/gen/dto_gen.py deleted file mode 100644 index 426cd96b..00000000 --- a/vpp-api/java/jvpp/gen/dto_gen.py +++ /dev/null @@ -1,177 +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 $base_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 org.openvpp.jvpp.VppInvocationException { - return jvpp.$method_name($args); - }\n""") - - -def generate_dtos(func_list, base_package, 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']): - continue - - 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) - methods = "" - 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 = "vpe.api 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>" % (base_package, dto_package, request_dto_name + "Dump") - generate_dump_reply_dto(request_dto_name, base_package, dto_package, camel_case_dto_name, - camel_case_method_name, func) - else: - base_type += "JVppReply<%s.%s.%s>" % (base_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, - args=args) - if util.is_dump(camel_case_dto_name): - base_type += "JVppDump" - description = "vpe.api dump request DTO" - else: - base_type += "JVppRequest" - description = "vpe.api request DTO" - - write_dto_file(base_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 = "vpe.api notification DTO" - camel_case_dto_name = util.add_notification_suffix(camel_case_dto_name) - methods = "" - dto_path = os.path.join(dto_package, camel_case_dto_name + ".java") - write_dto_file(base_package, base_type, camel_case_dto_name, description, dto_package, dto_path, fields, func, - inputfile, methods) - - flush_dump_reply_dtos(inputfile) - - -def write_dto_file(base_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, - 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="vpe.api 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'], - 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, dto_package, camel_case_dto_name, camel_case_method_name, - func): - base_type = "JVppReplyDump<%s.%s.%s, %s.%s.%s>" % ( - base_package, dto_package, util.remove_reply_suffix(camel_case_dto_name) + "Dump", - base_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 - - # 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'] = \ - dump_reply_artificial_dtos[request_dto_name]['fields'] + '\n' + fields - else: - dump_reply_artificial_dtos[request_dto_name] = ({'docs': util.api_message_to_javadoc(func), - 'cls_name': cls_name, - 'fields': fields, - 'methods': "", - 'base_package': base_package, - 'base_type': base_type, - 'dto_package': dto_package, - }) diff --git a/vpp-api/java/jvpp/gen/jvpp_c_gen.py b/vpp-api/java/jvpp/gen/jvpp_c_gen.py deleted file mode 100644 index 1796ac17..00000000 --- a/vpp-api/java/jvpp/gen/jvpp_c_gen.py +++ /dev/null @@ -1,525 +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 - -def is_manually_generated(f_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, "org/openvpp/jvpp/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; - }""") - -class_cache_template = Template(""" -$class_references -static int cache_class_references(JNIEnv* env) { - $find_class_invocations - return 0; -}""") - -def generate_class_cache(func_list): - class_references = [] - find_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): - 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( - ref_name=ref_name, - class_name=class_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( - ref_name=util.add_notification_suffix(ref_name), - class_name=util.add_notification_suffix(class_name))) - - # add exception class to class cache - ref_name = 'callbackException' - class_name = 'org/openvpp/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)) - return class_cache_template.substitute( - class_references="".join(class_references), find_class_invocations="".join(find_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, "org/openvpp/jvpp/dto/${java_name_upper}");""") - -request_field_identifier_template = Template(""" - jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, requestClass, "${java_name}", "${jni_signature}"); - ${jni_type} ${java_name} = (*env)->Get${jni_getter}(env, request, ${java_name}FieldId); - """) - -u8_struct_setter_template = Template(""" - mp->${c_name} = ${java_name};""") - -u16_struct_setter_template = Template(""" - mp->${c_name} = clib_host_to_net_u16(${java_name});""") - -u32_struct_setter_template = Template(""" - mp->${c_name} = clib_host_to_net_u32(${java_name});""") - -i32_struct_setter_template = Template(""" - mp->${c_name} = clib_host_to_net_i32(${java_name});!""") - -u64_struct_setter_template = Template(""" - mp->${c_name} = clib_host_to_net_u64(${java_name});""") - -u8_array_struct_setter_template = Template(""" - if (${java_name}) { - jsize cnt = (*env)->GetArrayLength (env, ${java_name}); - size_t max_size = ${field_length}; - if (max_size != 0 && cnt > max_size) cnt = max_size; - (*env)->GetByteArrayRegion(env, ${java_name}, 0, cnt, (jbyte *)mp->${c_name}); - } -""") - -u16_array_struct_setter_template = Template(""" - jshort * ${java_name}ArrayElements = (*env)->GetShortArrayElements(env, ${java_name}, NULL); - if (${java_name}) { - size_t _i; - jsize cnt = (*env)->GetArrayLength (env, ${java_name}); - size_t max_size = ${field_length}; - if (max_size != 0 && cnt > max_size) cnt = max_size; - for (_i = 0; _i < cnt; _i++) { - mp->${c_name}[_i] = clib_host_to_net_u16(${java_name}ArrayElements[_i]); - } - } - (*env)->ReleaseShortArrayElements (env, ${java_name}, ${java_name}ArrayElements, 0); - """) - -u32_array_struct_setter_template = Template(""" - jint * ${java_name}ArrayElements = (*env)->GetIntArrayElements(env, ${java_name}, NULL); - if (${java_name}) { - size_t _i; - jsize cnt = (*env)->GetArrayLength (env, ${java_name}); - size_t max_size = ${field_length}; - if (max_size != 0 && cnt > max_size) cnt = max_size; - for (_i = 0; _i < cnt; _i++) { - mp->${c_name}[_i] = clib_host_to_net_u32(${java_name}ArrayElements[_i]); - } - } - (*env)->ReleaseIntArrayElements (env, ${java_name}, ${java_name}ArrayElements, 0); - """) - -u64_array_struct_setter_template = Template(""" - jlong * ${java_name}ArrayElements = (*env)->GetLongArrayElements(env, ${java_name}, NULL); - if (${java_name}) { - size_t _i; - jsize cnt = (*env)->GetArrayLength (env, ${java_name}); - size_t max_size = ${field_length}; - if (max_size != 0 && cnt > max_size) cnt = max_size; - for (_i = 0; _i < cnt; _i++) { - mp->${c_name}[_i] = clib_host_to_net_u64(${java_name}ArrayElements[_i]); - } - } - (*env)->ReleaseLongArrayElements (env, ${java_name}, ${java_name}ArrayElements, 0); - """) - -vl_api_ip4_fib_counter_t_array_struct_setter_template = Template(""" - // vl_api_ip4_fib_counter_t_array_field_setter_template FIXME""") - -vl_api_ip6_fib_counter_t_array_struct_setter_template = Template(""" - // vl_api_ip6_fib_counter_t_array_field_setter_template FIXME""") - -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, - 'vl_api_ip4_fib_counter_t[]': vl_api_ip4_fib_counter_t_array_struct_setter_template, - 'vl_api_ip6_fib_counter_t[]': vl_api_ip6_fib_counter_t_array_struct_setter_template - } - -jni_impl_template = Template(""" -/** - * JNI binding for sending ${c_name} vpe.api message. - * Generated based on $inputfile preparsed data: -$api_data - */ -JNIEXPORT jint JNICALL Java_org_openvpp_jvpp_JVppImpl_${java_name}0 -(JNIEnv * env, jclass clazz$args) { - vppjni_main_t *jm = &vppjni_main; - vl_api_${c_name}_t * mp; - u32 my_context_id; - int rv; - rv = vppjni_sanity_check (jm); - if (rv) return rv; - my_context_id = vppjni_get_context_id (jm); - $request_class - $field_identifiers - M(${c_name_uppercase}, ${c_name}); - mp->context = clib_host_to_net_u32 (my_context_id); - $struct_setters - S; - if ((*env)->ExceptionCheck(env)) { - return JNI_ERR; - } - return my_context_id; -}""") - -def generate_jni_impl(func_list, 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) 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 = '' - field_identifiers = '' - struct_setters = '' - 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) - - # field identifiers - for t in zip(f['types'], f['args']): - jni_type = t[0] - java_field_name = util.underscore_to_camelcase(t[1]) - jni_signature = util.jni_2_signature_mapping[jni_type] - jni_getter = util.jni_field_accessors[jni_type] - field_identifiers += request_field_identifier_template.substitute( - jni_type=jni_type, - java_name=java_field_name, - jni_signature=jni_signature, - jni_getter=jni_getter) - - # field setters - for t in zip(f['c_types'], f['args'], f['lengths']): - c_type = t[0] - c_name = t[1] - field_length = t[2][0] - - # check if we are processing variable length array: - if t[2][1]: - field_length = util.underscore_to_camelcase(t[2][0]) - - java_field_name = util.underscore_to_camelcase(c_name) - - struct_setter_template = struct_setter_templates[c_type] - - struct_setters += struct_setter_template.substitute( - c_name=c_name, - java_name=java_field_name, - field_length=field_length) - - jni_impl.append(jni_impl_template.substitute( - inputfile=inputfile, - api_data=util.api_message_to_javadoc(f), - java_name=camel_case_function_name, - c_name_uppercase=f_name_uppercase, - c_name=f_name, - request_class=request_class, - field_identifiers=field_identifiers, - struct_setters=struct_setters, - args=arguments)) - - return "\n".join(jni_impl) - - -dto_field_id_template = Template(""" - jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}");""") - -default_dto_field_setter_template = Template(""" - (*env)->Set${jni_setter}(env, dto, ${java_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, dto, ${java_name}FieldId, clib_net_to_host_u16(mp->${c_name})); -""") - -u32_dto_field_setter_template = Template(""" - (*env)->Set${jni_setter}(env, dto, ${java_name}FieldId, clib_net_to_host_u32(mp->${c_name})); -""") - -u64_dto_field_setter_template = Template(""" - (*env)->Set${jni_setter}(env, dto, ${java_name}FieldId, clib_net_to_host_u64(mp->${c_name})); -""") - -u8_array_dto_field_setter_template = Template(""" - jbyteArray ${java_name} = (*env)->NewByteArray(env, ${field_length}); - (*env)->SetByteArrayRegion(env, ${java_name}, 0, ${field_length}, (const jbyte*)mp->${c_name}); - (*env)->SetObjectField(env, dto, ${java_name}FieldId, ${java_name}); -""") - -u16_array_dto_field_setter_template = Template(""" - { - jshortArray ${java_name} = (*env)->NewShortArray(env, ${field_length}); - jshort * ${java_name}ArrayElements = (*env)->GetShortArrayElements(env, ${java_name}, NULL); - unsigned int _i; - for (_i = 0; _i < ${field_length}; _i++) { - ${java_name}ArrayElements[_i] = clib_net_to_host_u16(mp->${c_name}[_i]); - } - - (*env)->ReleaseShortArrayElements(env, ${java_name}, ${java_name}ArrayElements, 0); - (*env)->SetObjectField(env, dto, ${java_name}FieldId, ${java_name}); - } -""") - -u32_array_dto_field_setter_template = Template(""" - { - jintArray ${java_name} = (*env)->NewIntArray(env, ${field_length}); - jint * ${java_name}ArrayElements = (*env)->GetIntArrayElements(env, ${java_name}, NULL); - unsigned int _i; - for (_i = 0; _i < ${field_length}; _i++) { - ${java_name}ArrayElements[_i] = clib_net_to_host_u32(mp->${c_name}[_i]); - } - - (*env)->ReleaseIntArrayElements(env, ${java_name}, ${java_name}ArrayElements, 0); - (*env)->SetObjectField(env, dto, ${java_name}FieldId, ${java_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 ${java_name} = (*env)->NewLongArray(env, ${field_length}); - jlong * ${java_name}ArrayElements = (*env)->GetLongArrayElements(env, ${java_name}, NULL); - unsigned int _i; - for (_i = 0; _i < ${field_length}; _i++) { - ${java_name}ArrayElements[_i] = clib_net_to_host_u64(mp->${c_name}[_i]); - } - - (*env)->ReleaseLongArrayElements(env, ${java_name}, ${java_name}ArrayElements, 0); - (*env)->SetObjectField(env, dto, ${java_name}FieldId, ${java_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 - } - -# 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) { - CallOnError("${handler_name}",mp->context,mp->retval); - return; - } - if (mp->retval == VNET_API_ERROR_IN_PROGRESS) { - clib_warning("Result in progress"); - return; - } -""") - -msg_handler_template = Template(""" -/** - * Handler for ${handler_name} vpe.api message. - * Generated based on $inputfile preparsed data: -$api_data - */ -static void vl_api_${handler_name}_t_handler (vl_api_${handler_name}_t * mp) -{ - vppjni_main_t * jm = &vppjni_main; - JNIEnv *env = jm->jenv; - $err_handler - - jmethodID constructor = (*env)->GetMethodID(env, ${class_ref_name}Class, "", "()V"); - jmethodID callbackMethod = (*env)->GetMethodID(env, jm->callbackClass, "on${dto_name}", "(Lorg/openvpp/jvpp/dto/${dto_name};)V"); - - jobject dto = (*env)->NewObject(env, ${class_ref_name}Class, constructor); - $dto_setters - (*env)->CallVoidMethod(env, jm->callback, callbackMethod, dto); -}""") - -def generate_msg_handlers(func_list, 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) 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['c_types'], f['types'], f['args'], f['lengths']): - c_type = t[0] - jni_type = t[1] - c_name = t[2] - field_length = t[3][0] - - if jni_type.endswith('Array') and field_length == '0': - raise Exception('Variable array \'%s\' defined in message \'%s\' ' - 'should have defined length (e.g. \'%s[%s_length]\'' - % (c_name, handler_name, c_name, c_name)) - - # check if we are processing variable length array - if t[3][1]: - length_var_name = t[3][0] - length_field_type = f['c_types'][f['args'].index(length_var_name)] - 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 and generate retval check - if util.is_retval_field(c_name): - err_handler = callback_err_handler_template.substitute( - handler_name=handler_name - ) - continue - - java_field_name = util.underscore_to_camelcase(c_name) - jni_signature = util.jni_2_signature_mapping[jni_type] - jni_setter = util.jni_field_accessors[jni_type] - - dto_setters += dto_field_id_template.substitute( - java_name=java_field_name, - class_ref_name=ref_name, - jni_signature=jni_signature) - - dto_setter_template = dto_field_setter_templates[c_type] - - dto_setters += dto_setter_template.substitute( - java_name=java_field_name, - jni_signature=jni_signature, - c_name=c_name, - jni_setter=jni_setter, - field_length=field_length) - - handlers.append(msg_handler_template.substitute( - inputfile=inputfile, - api_data=util.api_message_to_javadoc(f), - handler_name=handler_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_vpe_api_msg \\\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): - 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 vpe.api generated by vppapigen). - */ - -void CallOnError(const char* call, int context, int retval); - -// 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, inputfile): - """ Generates jvpp C file """ - print "Generating jvpp C" - - class_cache = generate_class_cache(func_list) - jni_impl = generate_jni_impl(func_list, inputfile) - msg_handlers = generate_msg_handlers(func_list, inputfile) - handler_registration = generate_handler_registration(func_list) - - jvpp_c_file = open("jvpp_gen.h", '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/jvpp_callback_facade_gen.py b/vpp-api/java/jvpp/gen/jvpp_callback_facade_gen.py deleted file mode 100644 index 7df17486..00000000 --- a/vpp-api/java/jvpp/gen/jvpp_callback_facade_gen.py +++ /dev/null @@ -1,297 +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 $base_package.$callback_facade_package; - -/** - *

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

Default implementation of CallbackJVpp interface. - *
It was generated by jvpp_callback_facade_gen.py based on $inputfile - *
(python representation of vpe.api generated by vppapigen). - */ -public final class CallbackJVppFacade extends $base_package.$notification_package.NotificationRegistryProviderContext implements $base_package.$callback_facade_package.CallbackJVpp { - - private final $base_package.JVpp jvpp; - private final java.util.Map callbacks; - - /** - *

Create CallbackJVppFacade 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 CallbackJVppFacade(final $base_package.JVpp jvpp) throws java.io.IOException { - this.jvpp = java.util.Objects.requireNonNull(jvpp,"jvpp is null"); - this.callbacks = new java.util.HashMap<>(); - this.jvpp.connect(new CallbackJVppFacadeCallback(this.callbacks, getNotificationCallback())); - } - - @Override - public void close() { - } - - // TODO add send() - -$methods -} -""") - -method_template = Template( - """ void $name($base_package.$dto_package.$request request, $base_package.$callback_package.$callback callback) throws org.openvpp.jvpp.VppInvocationException;""") - -method_impl_template = Template(""" public final void $name($base_package.$dto_package.$request request, $base_package.$callback_package.$callback callback) throws org.openvpp.jvpp.VppInvocationException { - synchronized (callbacks) { - callbacks.put(jvpp.$name(request), callback); - } - } -""") - -no_arg_method_template = Template(""" void $name($base_package.$callback_package.$callback callback) throws org.openvpp.jvpp.VppInvocationException;""") -no_arg_method_impl_template = Template(""" public final void $name($base_package.$callback_package.$callback callback) throws org.openvpp.jvpp.VppInvocationException { - synchronized (callbacks) { - callbacks.put(jvpp.$name(), callback); - } - } -""") - - -def generate_jvpp(func_list, base_package, 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']): - # TODO handle notifications - 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 - - # 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, - 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, - 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, - 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, - dto_package=dto_package, - callback_package=callback_package, - callback=callback_type)) - - join = os.path.join(callback_facade_package, "CallbackJVpp.java") - jvpp_file = open(join, 'w') - jvpp_file.write( - jvpp_ifc_template.substitute(inputfile=inputfile, - methods="\n".join(methods), - base_package=base_package, - 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, "CallbackJVppFacade.java"), 'w') - jvpp_file.write(jvpp_impl_template.substitute(inputfile=inputfile, - methods="\n".join(methods_impl), - base_package=base_package, - 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, dto_package, callback_package, notification_package, callback_facade_package, inputfile) - - -jvpp_facade_callback_template = Template(""" -package $base_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 vpe.api generated by vppapigen). - */ -public final class CallbackJVppFacadeCallback implements $base_package.$callback_package.JVppGlobalCallback { - - private final java.util.Map requests; - private final $base_package.$notification_package.GlobalNotificationCallback notificationCallback; - private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(CallbackJVppFacadeCallback.class.getName()); - - public CallbackJVppFacadeCallback(final java.util.Map requestMap, - final $base_package.$notification_package.GlobalNotificationCallback notificationCallback) { - this.requests = requestMap; - this.notificationCallback = notificationCallback; - } - - @Override - public void onError(org.openvpp.jvpp.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); - } - } - } - -$methods -} -""") - -jvpp_facade_callback_method_template = Template(""" - @Override - @SuppressWarnings("unchecked") - public void on$callback_dto($base_package.$dto_package.$callback_dto reply) { - - $base_package.$callback_package.$callback callback; - synchronized(requests) { - callback = ($base_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($base_package.$dto_package.$callback_dto notification) { - notificationCallback.on$callback_dto(notification); - } -""") - - -def generate_callback(func_list, base_package, dto_package, callback_package, notification_package, callback_facade_package, inputfile): - callbacks = [] - for func in func_list: - - if util.is_ignored(func['name']): - continue - - camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name']) - - if util.is_reply(camel_case_name_with_suffix): - callbacks.append(jvpp_facade_callback_method_template.substitute(base_package=base_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(base_package=base_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, "CallbackJVppFacadeCallback.java"), 'w') - jvpp_file.write(jvpp_facade_callback_template.substitute(inputfile=inputfile, - base_package=base_package, - 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/jvpp_future_facade_gen.py b/vpp-api/java/jvpp/gen/jvpp_future_facade_gen.py deleted file mode 100644 index e1ca4d02..00000000 --- a/vpp-api/java/jvpp/gen/jvpp_future_facade_gen.py +++ /dev/null @@ -1,315 +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 $base_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 vpe.api generated by vppapigen). - */ -public final class FutureJVppFacadeCallback implements $base_package.$callback_package.JVppGlobalCallback { - - private final java.util.Map>> requests; - private final $base_package.$notification_package.GlobalNotificationCallback notificationCallback; - - public FutureJVppFacadeCallback(final java.util.Map>> requestMap, - final $base_package.$notification_package.GlobalNotificationCallback notificationCallback) { - this.requests = requestMap; - this.notificationCallback = notificationCallback; - } - - @Override - @SuppressWarnings("unchecked") - public void onError(org.openvpp.jvpp.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()); - } - } - } - -$methods -} -""") - -jvpp_facade_callback_method_template = Template(""" - @Override - @SuppressWarnings("unchecked") - public void on$callback_dto($base_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($base_package.$dto_package.$callback_dto notification) { - notificationCallback.on$callback_dto(notification); - } -""") - -# TODO reuse common parts with generic method callback -jvpp_facade_control_ping_method_template = Template(""" - @Override - @SuppressWarnings("unchecked") - public void on$callback_dto($base_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) { - // Finish dump call - if (completableFuture instanceof $base_package.$future_package.FutureJVppFacade.CompletableDumpFuture) { - completableFuture.complete((($base_package.$future_package.FutureJVppFacade.CompletableDumpFuture) completableFuture).getReplyDump()); - // Remove future mapped to dump call context id - synchronized(requests) { - requests.remove((($base_package.$future_package.FutureJVppFacade.CompletableDumpFuture) completableFuture).getContextId()); - } - } else { - completableFuture.complete(reply); - } - - synchronized(requests) { - requests.remove(reply.context); - } - } - } -""") - -jvpp_facade_details_callback_method_template = Template(""" - @Override - @SuppressWarnings("unchecked") - public void on$callback_dto($base_package.$dto_package.$callback_dto reply) { - final FutureJVppFacade.CompletableDumpFuture<$base_package.$dto_package.$callback_dto_reply_dump> completableFuture; - - synchronized(requests) { - completableFuture = ($base_package.$future_package.FutureJVppFacade.CompletableDumpFuture<$base_package.$dto_package.$callback_dto_reply_dump>) requests.get(reply.context); - } - - if(completableFuture != null) { - $base_package.$dto_package.$callback_dto_reply_dump replyDump = completableFuture.getReplyDump(); - if(replyDump == null) { - replyDump = new $base_package.$dto_package.$callback_dto_reply_dump(); - completableFuture.setReplyDump(replyDump); - } - - replyDump.$callback_dto_field.add(reply); - } - } -""") - - -def generate_jvpp(func_list, base_package, 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: - - if util.is_ignored(func['name']): - continue - - camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name']) - 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, - 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(base_package=base_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_method_impl_template.substitute(base_package=base_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(base_package=base_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(base_package=base_package, - dto_package=dto_package, - method_name=camel_case_request_method_name, - reply_name=camel_case_name_with_suffix, - request_name=request_name)) - - # Callback handler is a bit special and a different template has to be used - if util.is_control_ping(camel_case_name_with_suffix): - callbacks.append(jvpp_facade_control_ping_method_template.substitute(base_package=base_package, - dto_package=dto_package, - callback_dto=camel_case_name_with_suffix, - future_package=future_facade_package)) - else: - callbacks.append(jvpp_facade_callback_method_template.substitute(base_package=base_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(base_package=base_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, "FutureJVppFacadeCallback.java"), 'w') - jvpp_file.write(jvpp_facade_callback_template.substitute(inputfile=inputfile, - base_package=base_package, - 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.java"), 'w') - jvpp_file.write(future_jvpp_template.substitute(inputfile=inputfile, - base_package=base_package, - methods="".join(methods), - future_package=future_facade_package)) - jvpp_file.flush() - jvpp_file.close() - - jvpp_file = open(os.path.join(future_facade_package, "FutureJVppFacade.java"), 'w') - jvpp_file.write(future_jvpp_facade_template.substitute(inputfile=inputfile, - base_package=base_package, - dto_package=dto_package, - methods="".join(methods_impl), - future_package=future_facade_package)) - jvpp_file.flush() - jvpp_file.close() - - -future_jvpp_template = Template(''' -package $base_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 vpe.api generated by vppapigen). - */ -public interface FutureJVpp extends FutureJVppInvoker { -$methods -} -''') - -future_jvpp_method_template = Template(''' - java.util.concurrent.CompletionStage<$base_package.$dto_package.$reply_name> $method_name($base_package.$dto_package.$request_name request); -''') - - -future_jvpp_facade_template = Template(''' -package $base_package.$future_package; - -/** - *

Implementation of FutureJVpp based on FutureJVppInvokerFacade - *
It was generated by jvpp_future_facade_gen.py based on $inputfile - *
(python representation of vpe.api generated by vppapigen). - */ -public class FutureJVppFacade extends FutureJVppInvokerFacade implements FutureJVpp { - - /** - *

Create FutureJVppFacade 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 FutureJVppFacade(final $base_package.JVpp jvpp) throws java.io.IOException { - super(jvpp, new java.util.HashMap<>()); - jvpp.connect(new FutureJVppFacadeCallback(getRequests(), getNotificationCallback())); - } -$methods -} -''') - -future_jvpp_method_impl_template = Template(''' - @Override - public java.util.concurrent.CompletionStage<$base_package.$dto_package.$reply_name> $method_name($base_package.$dto_package.$request_name request) { - return send(request); - } -''') - -# 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/jvpp_gen.py b/vpp-api/java/jvpp/gen/jvpp_gen.py index 26bcea15..6f531def 100755 --- a/vpp-api/java/jvpp/gen/jvpp_gen.py +++ b/vpp-api/java/jvpp/gen/jvpp_gen.py @@ -17,15 +17,16 @@ import argparse import importlib import sys +import os -import callback_gen -import notification_gen -import dto_gen -import jvpp_callback_facade_gen -import jvpp_future_facade_gen -import jvpp_impl_gen -import jvpp_c_gen -import util +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 # Invocation: # ~/Projects/vpp/vpp-api/jvpp/gen$ mkdir -p java/org/openvpp/jvpp && cd java/org/openvpp/jvpp @@ -36,15 +37,23 @@ import util # # where # defs_api_vpp_papi.py - vpe.api in python format (generated by vppapigen) -from util import vpp_2_jni_type_mapping +from jvppgen.util import vpp_2_jni_type_mapping parser = argparse.ArgumentParser(description='VPP Java API generator') parser.add_argument('-i', action="store", dest="inputfile") +parser.add_argument('--base_package', action="store", dest="base_package", default='org.openvpp.jvpp') args = parser.parse_args() sys.path.append(".") -inputfile = args.inputfile.replace('.py', '') +print "args.inputfile %s" % args.inputfile +importdir = os.path.dirname(args.inputfile) +print "importdir %s" % importdir +inputfile = os.path.basename(args.inputfile) +inputfile = inputfile.replace('.py', '') +print "inputfile %s" % inputfile +base_package = args.base_package +sys.path.append(importdir) cfg = importlib.import_module(inputfile, package=None) @@ -124,7 +133,6 @@ def get_definitions(): func_list, func_name = get_definitions() -base_package = 'org.openvpp.jvpp' dto_package = 'dto' callback_package = 'callback' notification_package = 'notification' diff --git a/vpp-api/java/jvpp/gen/jvpp_impl_gen.py b/vpp-api/java/jvpp/gen/jvpp_impl_gen.py deleted file mode 100644 index 93ffd0fb..00000000 --- a/vpp-api/java/jvpp/gen/jvpp_impl_gen.py +++ /dev/null @@ -1,173 +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 $base_package; - - -/** - *

Java representation of vpe.api. - *
It was generated by jvpp_impl_gen.py based on $inputfile - *
(python representation of vpe.api generated by vppapigen). - */ -public interface JVpp extends java.lang.AutoCloseable { - - /** - * Generic connect with $base_package.callback.JVppCallback callback handler - * providing connecting to VPP - * - * @param callback JVppCallback instance providing callback handling - * - * @throws java.io.IOException if connection cannot be initiated - */ - void connect($base_package.callback.JVppCallback callback) throws java.io.IOException; - - /** - * Generic dispatch method for sending requests to VPP - * - * @throws org.openvpp.jvpp.VppInvocationException if send request had failed - */ - int send($base_package.$dto_package.JVppRequest request) throws org.openvpp.jvpp.VppInvocationException; - - @Override - void close(); - -$methods -} -""") - -jvpp_impl_template = Template(""" -package $base_package; - -/** - *

Default implementation of JVpp interface. - *
It was generated by jvpp_impl_gen.py based on $inputfile - *
(python representation of vpe.api generated by vppapigen). - */ -public final class JVppImpl implements $base_package.JVpp { - - private final $base_package.VppConnection connection; - - public JVppImpl(final $base_package.VppConnection connection) { - this.connection = java.util.Objects.requireNonNull(connection,"Connection is null"); - } - - @Override - public void connect($base_package.callback.JVppCallback callback) throws java.io.IOException { - connection.connect(callback); - } - - @Override - public void close() { - connection.close(); - } - - @Override - public int send($base_package.$dto_package.JVppRequest request) throws org.openvpp.jvpp.VppInvocationException { - return request.send(this); - } - -$methods -} -""") - -method_template = Template(""" int $name($base_package.$dto_package.$request request) throws org.openvpp.jvpp.VppInvocationException;""") -method_native_template = Template( - """ private static native int ${name}0($base_package.$dto_package.$request request);""") -method_impl_template = Template(""" public final int $name($base_package.$dto_package.$request request) throws org.openvpp.jvpp.VppInvocationException { - java.util.Objects.requireNonNull(request,"Null request object"); - connection.checkActive(); - int result=${name}0(request); - if(result<0){ - throw new org.openvpp.jvpp.VppInvocationException("${name}",result); - } - return result; - } -""") - -no_arg_method_template = Template(""" int $name() throws org.openvpp.jvpp.VppInvocationException;""") -no_arg_method_native_template = Template(""" private static native int ${name}0() throws org.openvpp.jvpp.VppInvocationException;""") -no_arg_method_impl_template = Template(""" public final int $name() throws org.openvpp.jvpp.VppInvocationException { - connection.checkActive(); - int result=${name}0(); - if(result<0){ - throw new org.openvpp.jvpp.VppInvocationException("${name}",result); - } - return result; - } -""") - - -def generate_jvpp(func_list, base_package, dto_package, inputfile): - """ Generates JVpp interface and JNI implementation """ - print "Generating JVpp" - - 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, - base_package=base_package, - dto_package=dto_package)) - methods_impl.append( - no_arg_method_native_template.substitute(name=camel_case_name, - base_package=base_package, - dto_package=dto_package)) - methods_impl.append(no_arg_method_impl_template.substitute(name=camel_case_name, - base_package=base_package, - dto_package=dto_package)) - else: - methods.append(method_template.substitute(name=camel_case_name, - request=camel_case_name_upper, - base_package=base_package, - dto_package=dto_package)) - methods_impl.append(method_native_template.substitute(name=camel_case_name, - request=camel_case_name_upper, - base_package=base_package, - dto_package=dto_package)) - methods_impl.append(method_impl_template.substitute(name=camel_case_name, - request=camel_case_name_upper, - base_package=base_package, - dto_package=dto_package)) - - jvpp_file = open("JVpp.java", 'w') - jvpp_file.write( - jvpp_ifc_template.substitute(inputfile=inputfile, - methods="\n".join(methods), - base_package=base_package, - dto_package=dto_package)) - jvpp_file.flush() - jvpp_file.close() - - jvpp_file = open("JVppImpl.java", 'w') - jvpp_file.write(jvpp_impl_template.substitute(inputfile=inputfile, - methods="\n".join(methods_impl), - base_package=base_package, - dto_package=dto_package)) - jvpp_file.flush() - jvpp_file.close() diff --git a/vpp-api/java/jvpp/gen/jvppgen/__init__.py b/vpp-api/java/jvpp/gen/jvppgen/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/vpp-api/java/jvpp/gen/jvppgen/callback_gen.py b/vpp-api/java/jvpp/gen/jvppgen/callback_gen.py new file mode 100644 index 00000000..eadf3b5c --- /dev/null +++ b/vpp-api/java/jvpp/gen/jvppgen/callback_gen.py @@ -0,0 +1,102 @@ +#!/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 $base_package.$callback_package; + +/** + *

Represents callback for vpe.api 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 $base_package.$callback_package; + +/** + *

Global aggregated callback interface. + *
It was generated by callback_gen.py based on $inputfile + *
(python representation of vpe.api generated by vppapigen). + */ +public interface JVppGlobalCallback extends $callbacks { +} +""") + + +def generate_callbacks(func_list, base_package, 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: + + if util.is_ignored(func['name']): + continue + + camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name']) + 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(base_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" % (base_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, + callback_package=callback_package, + callback_type=callback_type)) + callback_file.flush() + callback_file.close() + + callback_file = open(os.path.join(callback_package, "JVppGlobalCallback.java"), 'w') + callback_file.write(global_callback_template.substitute(inputfile=inputfile, + callbacks=", ".join(callbacks), + base_package=base_package, + 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 new file mode 100644 index 00000000..426cd96b --- /dev/null +++ b/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py @@ -0,0 +1,177 @@ +#!/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 $base_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 org.openvpp.jvpp.VppInvocationException { + return jvpp.$method_name($args); + }\n""") + + +def generate_dtos(func_list, base_package, 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']): + continue + + 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) + methods = "" + 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 = "vpe.api 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>" % (base_package, dto_package, request_dto_name + "Dump") + generate_dump_reply_dto(request_dto_name, base_package, dto_package, camel_case_dto_name, + camel_case_method_name, func) + else: + base_type += "JVppReply<%s.%s.%s>" % (base_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, + args=args) + if util.is_dump(camel_case_dto_name): + base_type += "JVppDump" + description = "vpe.api dump request DTO" + else: + base_type += "JVppRequest" + description = "vpe.api request DTO" + + write_dto_file(base_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 = "vpe.api notification DTO" + camel_case_dto_name = util.add_notification_suffix(camel_case_dto_name) + methods = "" + dto_path = os.path.join(dto_package, camel_case_dto_name + ".java") + write_dto_file(base_package, base_type, camel_case_dto_name, description, dto_package, dto_path, fields, func, + inputfile, methods) + + flush_dump_reply_dtos(inputfile) + + +def write_dto_file(base_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, + 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="vpe.api 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'], + 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, dto_package, camel_case_dto_name, camel_case_method_name, + func): + base_type = "JVppReplyDump<%s.%s.%s, %s.%s.%s>" % ( + base_package, dto_package, util.remove_reply_suffix(camel_case_dto_name) + "Dump", + base_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 + + # 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'] = \ + dump_reply_artificial_dtos[request_dto_name]['fields'] + '\n' + fields + else: + dump_reply_artificial_dtos[request_dto_name] = ({'docs': util.api_message_to_javadoc(func), + 'cls_name': cls_name, + 'fields': fields, + 'methods': "", + 'base_package': base_package, + 'base_type': base_type, + 'dto_package': dto_package, + }) diff --git a/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py b/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py new file mode 100644 index 00000000..1796ac17 --- /dev/null +++ b/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py @@ -0,0 +1,525 @@ +#!/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 + +def is_manually_generated(f_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, "org/openvpp/jvpp/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; + }""") + +class_cache_template = Template(""" +$class_references +static int cache_class_references(JNIEnv* env) { + $find_class_invocations + return 0; +}""") + +def generate_class_cache(func_list): + class_references = [] + find_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): + 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( + ref_name=ref_name, + class_name=class_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( + ref_name=util.add_notification_suffix(ref_name), + class_name=util.add_notification_suffix(class_name))) + + # add exception class to class cache + ref_name = 'callbackException' + class_name = 'org/openvpp/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)) + return class_cache_template.substitute( + class_references="".join(class_references), find_class_invocations="".join(find_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, "org/openvpp/jvpp/dto/${java_name_upper}");""") + +request_field_identifier_template = Template(""" + jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, requestClass, "${java_name}", "${jni_signature}"); + ${jni_type} ${java_name} = (*env)->Get${jni_getter}(env, request, ${java_name}FieldId); + """) + +u8_struct_setter_template = Template(""" + mp->${c_name} = ${java_name};""") + +u16_struct_setter_template = Template(""" + mp->${c_name} = clib_host_to_net_u16(${java_name});""") + +u32_struct_setter_template = Template(""" + mp->${c_name} = clib_host_to_net_u32(${java_name});""") + +i32_struct_setter_template = Template(""" + mp->${c_name} = clib_host_to_net_i32(${java_name});!""") + +u64_struct_setter_template = Template(""" + mp->${c_name} = clib_host_to_net_u64(${java_name});""") + +u8_array_struct_setter_template = Template(""" + if (${java_name}) { + jsize cnt = (*env)->GetArrayLength (env, ${java_name}); + size_t max_size = ${field_length}; + if (max_size != 0 && cnt > max_size) cnt = max_size; + (*env)->GetByteArrayRegion(env, ${java_name}, 0, cnt, (jbyte *)mp->${c_name}); + } +""") + +u16_array_struct_setter_template = Template(""" + jshort * ${java_name}ArrayElements = (*env)->GetShortArrayElements(env, ${java_name}, NULL); + if (${java_name}) { + size_t _i; + jsize cnt = (*env)->GetArrayLength (env, ${java_name}); + size_t max_size = ${field_length}; + if (max_size != 0 && cnt > max_size) cnt = max_size; + for (_i = 0; _i < cnt; _i++) { + mp->${c_name}[_i] = clib_host_to_net_u16(${java_name}ArrayElements[_i]); + } + } + (*env)->ReleaseShortArrayElements (env, ${java_name}, ${java_name}ArrayElements, 0); + """) + +u32_array_struct_setter_template = Template(""" + jint * ${java_name}ArrayElements = (*env)->GetIntArrayElements(env, ${java_name}, NULL); + if (${java_name}) { + size_t _i; + jsize cnt = (*env)->GetArrayLength (env, ${java_name}); + size_t max_size = ${field_length}; + if (max_size != 0 && cnt > max_size) cnt = max_size; + for (_i = 0; _i < cnt; _i++) { + mp->${c_name}[_i] = clib_host_to_net_u32(${java_name}ArrayElements[_i]); + } + } + (*env)->ReleaseIntArrayElements (env, ${java_name}, ${java_name}ArrayElements, 0); + """) + +u64_array_struct_setter_template = Template(""" + jlong * ${java_name}ArrayElements = (*env)->GetLongArrayElements(env, ${java_name}, NULL); + if (${java_name}) { + size_t _i; + jsize cnt = (*env)->GetArrayLength (env, ${java_name}); + size_t max_size = ${field_length}; + if (max_size != 0 && cnt > max_size) cnt = max_size; + for (_i = 0; _i < cnt; _i++) { + mp->${c_name}[_i] = clib_host_to_net_u64(${java_name}ArrayElements[_i]); + } + } + (*env)->ReleaseLongArrayElements (env, ${java_name}, ${java_name}ArrayElements, 0); + """) + +vl_api_ip4_fib_counter_t_array_struct_setter_template = Template(""" + // vl_api_ip4_fib_counter_t_array_field_setter_template FIXME""") + +vl_api_ip6_fib_counter_t_array_struct_setter_template = Template(""" + // vl_api_ip6_fib_counter_t_array_field_setter_template FIXME""") + +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, + 'vl_api_ip4_fib_counter_t[]': vl_api_ip4_fib_counter_t_array_struct_setter_template, + 'vl_api_ip6_fib_counter_t[]': vl_api_ip6_fib_counter_t_array_struct_setter_template + } + +jni_impl_template = Template(""" +/** + * JNI binding for sending ${c_name} vpe.api message. + * Generated based on $inputfile preparsed data: +$api_data + */ +JNIEXPORT jint JNICALL Java_org_openvpp_jvpp_JVppImpl_${java_name}0 +(JNIEnv * env, jclass clazz$args) { + vppjni_main_t *jm = &vppjni_main; + vl_api_${c_name}_t * mp; + u32 my_context_id; + int rv; + rv = vppjni_sanity_check (jm); + if (rv) return rv; + my_context_id = vppjni_get_context_id (jm); + $request_class + $field_identifiers + M(${c_name_uppercase}, ${c_name}); + mp->context = clib_host_to_net_u32 (my_context_id); + $struct_setters + S; + if ((*env)->ExceptionCheck(env)) { + return JNI_ERR; + } + return my_context_id; +}""") + +def generate_jni_impl(func_list, 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) 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 = '' + field_identifiers = '' + struct_setters = '' + 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) + + # field identifiers + for t in zip(f['types'], f['args']): + jni_type = t[0] + java_field_name = util.underscore_to_camelcase(t[1]) + jni_signature = util.jni_2_signature_mapping[jni_type] + jni_getter = util.jni_field_accessors[jni_type] + field_identifiers += request_field_identifier_template.substitute( + jni_type=jni_type, + java_name=java_field_name, + jni_signature=jni_signature, + jni_getter=jni_getter) + + # field setters + for t in zip(f['c_types'], f['args'], f['lengths']): + c_type = t[0] + c_name = t[1] + field_length = t[2][0] + + # check if we are processing variable length array: + if t[2][1]: + field_length = util.underscore_to_camelcase(t[2][0]) + + java_field_name = util.underscore_to_camelcase(c_name) + + struct_setter_template = struct_setter_templates[c_type] + + struct_setters += struct_setter_template.substitute( + c_name=c_name, + java_name=java_field_name, + field_length=field_length) + + jni_impl.append(jni_impl_template.substitute( + inputfile=inputfile, + api_data=util.api_message_to_javadoc(f), + java_name=camel_case_function_name, + c_name_uppercase=f_name_uppercase, + c_name=f_name, + request_class=request_class, + field_identifiers=field_identifiers, + struct_setters=struct_setters, + args=arguments)) + + return "\n".join(jni_impl) + + +dto_field_id_template = Template(""" + jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}");""") + +default_dto_field_setter_template = Template(""" + (*env)->Set${jni_setter}(env, dto, ${java_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, dto, ${java_name}FieldId, clib_net_to_host_u16(mp->${c_name})); +""") + +u32_dto_field_setter_template = Template(""" + (*env)->Set${jni_setter}(env, dto, ${java_name}FieldId, clib_net_to_host_u32(mp->${c_name})); +""") + +u64_dto_field_setter_template = Template(""" + (*env)->Set${jni_setter}(env, dto, ${java_name}FieldId, clib_net_to_host_u64(mp->${c_name})); +""") + +u8_array_dto_field_setter_template = Template(""" + jbyteArray ${java_name} = (*env)->NewByteArray(env, ${field_length}); + (*env)->SetByteArrayRegion(env, ${java_name}, 0, ${field_length}, (const jbyte*)mp->${c_name}); + (*env)->SetObjectField(env, dto, ${java_name}FieldId, ${java_name}); +""") + +u16_array_dto_field_setter_template = Template(""" + { + jshortArray ${java_name} = (*env)->NewShortArray(env, ${field_length}); + jshort * ${java_name}ArrayElements = (*env)->GetShortArrayElements(env, ${java_name}, NULL); + unsigned int _i; + for (_i = 0; _i < ${field_length}; _i++) { + ${java_name}ArrayElements[_i] = clib_net_to_host_u16(mp->${c_name}[_i]); + } + + (*env)->ReleaseShortArrayElements(env, ${java_name}, ${java_name}ArrayElements, 0); + (*env)->SetObjectField(env, dto, ${java_name}FieldId, ${java_name}); + } +""") + +u32_array_dto_field_setter_template = Template(""" + { + jintArray ${java_name} = (*env)->NewIntArray(env, ${field_length}); + jint * ${java_name}ArrayElements = (*env)->GetIntArrayElements(env, ${java_name}, NULL); + unsigned int _i; + for (_i = 0; _i < ${field_length}; _i++) { + ${java_name}ArrayElements[_i] = clib_net_to_host_u32(mp->${c_name}[_i]); + } + + (*env)->ReleaseIntArrayElements(env, ${java_name}, ${java_name}ArrayElements, 0); + (*env)->SetObjectField(env, dto, ${java_name}FieldId, ${java_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 ${java_name} = (*env)->NewLongArray(env, ${field_length}); + jlong * ${java_name}ArrayElements = (*env)->GetLongArrayElements(env, ${java_name}, NULL); + unsigned int _i; + for (_i = 0; _i < ${field_length}; _i++) { + ${java_name}ArrayElements[_i] = clib_net_to_host_u64(mp->${c_name}[_i]); + } + + (*env)->ReleaseLongArrayElements(env, ${java_name}, ${java_name}ArrayElements, 0); + (*env)->SetObjectField(env, dto, ${java_name}FieldId, ${java_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 + } + +# 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) { + CallOnError("${handler_name}",mp->context,mp->retval); + return; + } + if (mp->retval == VNET_API_ERROR_IN_PROGRESS) { + clib_warning("Result in progress"); + return; + } +""") + +msg_handler_template = Template(""" +/** + * Handler for ${handler_name} vpe.api message. + * Generated based on $inputfile preparsed data: +$api_data + */ +static void vl_api_${handler_name}_t_handler (vl_api_${handler_name}_t * mp) +{ + vppjni_main_t * jm = &vppjni_main; + JNIEnv *env = jm->jenv; + $err_handler + + jmethodID constructor = (*env)->GetMethodID(env, ${class_ref_name}Class, "", "()V"); + jmethodID callbackMethod = (*env)->GetMethodID(env, jm->callbackClass, "on${dto_name}", "(Lorg/openvpp/jvpp/dto/${dto_name};)V"); + + jobject dto = (*env)->NewObject(env, ${class_ref_name}Class, constructor); + $dto_setters + (*env)->CallVoidMethod(env, jm->callback, callbackMethod, dto); +}""") + +def generate_msg_handlers(func_list, 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) 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['c_types'], f['types'], f['args'], f['lengths']): + c_type = t[0] + jni_type = t[1] + c_name = t[2] + field_length = t[3][0] + + if jni_type.endswith('Array') and field_length == '0': + raise Exception('Variable array \'%s\' defined in message \'%s\' ' + 'should have defined length (e.g. \'%s[%s_length]\'' + % (c_name, handler_name, c_name, c_name)) + + # check if we are processing variable length array + if t[3][1]: + length_var_name = t[3][0] + length_field_type = f['c_types'][f['args'].index(length_var_name)] + 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 and generate retval check + if util.is_retval_field(c_name): + err_handler = callback_err_handler_template.substitute( + handler_name=handler_name + ) + continue + + java_field_name = util.underscore_to_camelcase(c_name) + jni_signature = util.jni_2_signature_mapping[jni_type] + jni_setter = util.jni_field_accessors[jni_type] + + dto_setters += dto_field_id_template.substitute( + java_name=java_field_name, + class_ref_name=ref_name, + jni_signature=jni_signature) + + dto_setter_template = dto_field_setter_templates[c_type] + + dto_setters += dto_setter_template.substitute( + java_name=java_field_name, + jni_signature=jni_signature, + c_name=c_name, + jni_setter=jni_setter, + field_length=field_length) + + handlers.append(msg_handler_template.substitute( + inputfile=inputfile, + api_data=util.api_message_to_javadoc(f), + handler_name=handler_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_vpe_api_msg \\\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): + 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 vpe.api generated by vppapigen). + */ + +void CallOnError(const char* call, int context, int retval); + +// 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, inputfile): + """ Generates jvpp C file """ + print "Generating jvpp C" + + class_cache = generate_class_cache(func_list) + jni_impl = generate_jni_impl(func_list, inputfile) + msg_handlers = generate_msg_handlers(func_list, inputfile) + handler_registration = generate_handler_registration(func_list) + + jvpp_c_file = open("jvpp_gen.h", '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 new file mode 100644 index 00000000..7df17486 --- /dev/null +++ b/vpp-api/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py @@ -0,0 +1,297 @@ +#!/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 $base_package.$callback_facade_package; + +/** + *

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

Default implementation of CallbackJVpp interface. + *
It was generated by jvpp_callback_facade_gen.py based on $inputfile + *
(python representation of vpe.api generated by vppapigen). + */ +public final class CallbackJVppFacade extends $base_package.$notification_package.NotificationRegistryProviderContext implements $base_package.$callback_facade_package.CallbackJVpp { + + private final $base_package.JVpp jvpp; + private final java.util.Map callbacks; + + /** + *

Create CallbackJVppFacade 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 CallbackJVppFacade(final $base_package.JVpp jvpp) throws java.io.IOException { + this.jvpp = java.util.Objects.requireNonNull(jvpp,"jvpp is null"); + this.callbacks = new java.util.HashMap<>(); + this.jvpp.connect(new CallbackJVppFacadeCallback(this.callbacks, getNotificationCallback())); + } + + @Override + public void close() { + } + + // TODO add send() + +$methods +} +""") + +method_template = Template( + """ void $name($base_package.$dto_package.$request request, $base_package.$callback_package.$callback callback) throws org.openvpp.jvpp.VppInvocationException;""") + +method_impl_template = Template(""" public final void $name($base_package.$dto_package.$request request, $base_package.$callback_package.$callback callback) throws org.openvpp.jvpp.VppInvocationException { + synchronized (callbacks) { + callbacks.put(jvpp.$name(request), callback); + } + } +""") + +no_arg_method_template = Template(""" void $name($base_package.$callback_package.$callback callback) throws org.openvpp.jvpp.VppInvocationException;""") +no_arg_method_impl_template = Template(""" public final void $name($base_package.$callback_package.$callback callback) throws org.openvpp.jvpp.VppInvocationException { + synchronized (callbacks) { + callbacks.put(jvpp.$name(), callback); + } + } +""") + + +def generate_jvpp(func_list, base_package, 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']): + # TODO handle notifications + 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 + + # 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, + 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, + 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, + 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, + dto_package=dto_package, + callback_package=callback_package, + callback=callback_type)) + + join = os.path.join(callback_facade_package, "CallbackJVpp.java") + jvpp_file = open(join, 'w') + jvpp_file.write( + jvpp_ifc_template.substitute(inputfile=inputfile, + methods="\n".join(methods), + base_package=base_package, + 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, "CallbackJVppFacade.java"), 'w') + jvpp_file.write(jvpp_impl_template.substitute(inputfile=inputfile, + methods="\n".join(methods_impl), + base_package=base_package, + 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, dto_package, callback_package, notification_package, callback_facade_package, inputfile) + + +jvpp_facade_callback_template = Template(""" +package $base_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 vpe.api generated by vppapigen). + */ +public final class CallbackJVppFacadeCallback implements $base_package.$callback_package.JVppGlobalCallback { + + private final java.util.Map requests; + private final $base_package.$notification_package.GlobalNotificationCallback notificationCallback; + private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(CallbackJVppFacadeCallback.class.getName()); + + public CallbackJVppFacadeCallback(final java.util.Map requestMap, + final $base_package.$notification_package.GlobalNotificationCallback notificationCallback) { + this.requests = requestMap; + this.notificationCallback = notificationCallback; + } + + @Override + public void onError(org.openvpp.jvpp.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); + } + } + } + +$methods +} +""") + +jvpp_facade_callback_method_template = Template(""" + @Override + @SuppressWarnings("unchecked") + public void on$callback_dto($base_package.$dto_package.$callback_dto reply) { + + $base_package.$callback_package.$callback callback; + synchronized(requests) { + callback = ($base_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($base_package.$dto_package.$callback_dto notification) { + notificationCallback.on$callback_dto(notification); + } +""") + + +def generate_callback(func_list, base_package, dto_package, callback_package, notification_package, callback_facade_package, inputfile): + callbacks = [] + for func in func_list: + + if util.is_ignored(func['name']): + continue + + camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name']) + + if util.is_reply(camel_case_name_with_suffix): + callbacks.append(jvpp_facade_callback_method_template.substitute(base_package=base_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(base_package=base_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, "CallbackJVppFacadeCallback.java"), 'w') + jvpp_file.write(jvpp_facade_callback_template.substitute(inputfile=inputfile, + base_package=base_package, + 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 new file mode 100644 index 00000000..e1ca4d02 --- /dev/null +++ b/vpp-api/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py @@ -0,0 +1,315 @@ +#!/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 $base_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 vpe.api generated by vppapigen). + */ +public final class FutureJVppFacadeCallback implements $base_package.$callback_package.JVppGlobalCallback { + + private final java.util.Map>> requests; + private final $base_package.$notification_package.GlobalNotificationCallback notificationCallback; + + public FutureJVppFacadeCallback(final java.util.Map>> requestMap, + final $base_package.$notification_package.GlobalNotificationCallback notificationCallback) { + this.requests = requestMap; + this.notificationCallback = notificationCallback; + } + + @Override + @SuppressWarnings("unchecked") + public void onError(org.openvpp.jvpp.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()); + } + } + } + +$methods +} +""") + +jvpp_facade_callback_method_template = Template(""" + @Override + @SuppressWarnings("unchecked") + public void on$callback_dto($base_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($base_package.$dto_package.$callback_dto notification) { + notificationCallback.on$callback_dto(notification); + } +""") + +# TODO reuse common parts with generic method callback +jvpp_facade_control_ping_method_template = Template(""" + @Override + @SuppressWarnings("unchecked") + public void on$callback_dto($base_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) { + // Finish dump call + if (completableFuture instanceof $base_package.$future_package.FutureJVppFacade.CompletableDumpFuture) { + completableFuture.complete((($base_package.$future_package.FutureJVppFacade.CompletableDumpFuture) completableFuture).getReplyDump()); + // Remove future mapped to dump call context id + synchronized(requests) { + requests.remove((($base_package.$future_package.FutureJVppFacade.CompletableDumpFuture) completableFuture).getContextId()); + } + } else { + completableFuture.complete(reply); + } + + synchronized(requests) { + requests.remove(reply.context); + } + } + } +""") + +jvpp_facade_details_callback_method_template = Template(""" + @Override + @SuppressWarnings("unchecked") + public void on$callback_dto($base_package.$dto_package.$callback_dto reply) { + final FutureJVppFacade.CompletableDumpFuture<$base_package.$dto_package.$callback_dto_reply_dump> completableFuture; + + synchronized(requests) { + completableFuture = ($base_package.$future_package.FutureJVppFacade.CompletableDumpFuture<$base_package.$dto_package.$callback_dto_reply_dump>) requests.get(reply.context); + } + + if(completableFuture != null) { + $base_package.$dto_package.$callback_dto_reply_dump replyDump = completableFuture.getReplyDump(); + if(replyDump == null) { + replyDump = new $base_package.$dto_package.$callback_dto_reply_dump(); + completableFuture.setReplyDump(replyDump); + } + + replyDump.$callback_dto_field.add(reply); + } + } +""") + + +def generate_jvpp(func_list, base_package, 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: + + if util.is_ignored(func['name']): + continue + + camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name']) + 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, + 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(base_package=base_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_method_impl_template.substitute(base_package=base_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(base_package=base_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(base_package=base_package, + dto_package=dto_package, + method_name=camel_case_request_method_name, + reply_name=camel_case_name_with_suffix, + request_name=request_name)) + + # Callback handler is a bit special and a different template has to be used + if util.is_control_ping(camel_case_name_with_suffix): + callbacks.append(jvpp_facade_control_ping_method_template.substitute(base_package=base_package, + dto_package=dto_package, + callback_dto=camel_case_name_with_suffix, + future_package=future_facade_package)) + else: + callbacks.append(jvpp_facade_callback_method_template.substitute(base_package=base_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(base_package=base_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, "FutureJVppFacadeCallback.java"), 'w') + jvpp_file.write(jvpp_facade_callback_template.substitute(inputfile=inputfile, + base_package=base_package, + 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.java"), 'w') + jvpp_file.write(future_jvpp_template.substitute(inputfile=inputfile, + base_package=base_package, + methods="".join(methods), + future_package=future_facade_package)) + jvpp_file.flush() + jvpp_file.close() + + jvpp_file = open(os.path.join(future_facade_package, "FutureJVppFacade.java"), 'w') + jvpp_file.write(future_jvpp_facade_template.substitute(inputfile=inputfile, + base_package=base_package, + dto_package=dto_package, + methods="".join(methods_impl), + future_package=future_facade_package)) + jvpp_file.flush() + jvpp_file.close() + + +future_jvpp_template = Template(''' +package $base_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 vpe.api generated by vppapigen). + */ +public interface FutureJVpp extends FutureJVppInvoker { +$methods +} +''') + +future_jvpp_method_template = Template(''' + java.util.concurrent.CompletionStage<$base_package.$dto_package.$reply_name> $method_name($base_package.$dto_package.$request_name request); +''') + + +future_jvpp_facade_template = Template(''' +package $base_package.$future_package; + +/** + *

Implementation of FutureJVpp based on FutureJVppInvokerFacade + *
It was generated by jvpp_future_facade_gen.py based on $inputfile + *
(python representation of vpe.api generated by vppapigen). + */ +public class FutureJVppFacade extends FutureJVppInvokerFacade implements FutureJVpp { + + /** + *

Create FutureJVppFacade 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 FutureJVppFacade(final $base_package.JVpp jvpp) throws java.io.IOException { + super(jvpp, new java.util.HashMap<>()); + jvpp.connect(new FutureJVppFacadeCallback(getRequests(), getNotificationCallback())); + } +$methods +} +''') + +future_jvpp_method_impl_template = Template(''' + @Override + public java.util.concurrent.CompletionStage<$base_package.$dto_package.$reply_name> $method_name($base_package.$dto_package.$request_name request) { + return send(request); + } +''') + +# 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 new file mode 100644 index 00000000..93ffd0fb --- /dev/null +++ b/vpp-api/java/jvpp/gen/jvppgen/jvpp_impl_gen.py @@ -0,0 +1,173 @@ +#!/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 $base_package; + + +/** + *

Java representation of vpe.api. + *
It was generated by jvpp_impl_gen.py based on $inputfile + *
(python representation of vpe.api generated by vppapigen). + */ +public interface JVpp extends java.lang.AutoCloseable { + + /** + * Generic connect with $base_package.callback.JVppCallback callback handler + * providing connecting to VPP + * + * @param callback JVppCallback instance providing callback handling + * + * @throws java.io.IOException if connection cannot be initiated + */ + void connect($base_package.callback.JVppCallback callback) throws java.io.IOException; + + /** + * Generic dispatch method for sending requests to VPP + * + * @throws org.openvpp.jvpp.VppInvocationException if send request had failed + */ + int send($base_package.$dto_package.JVppRequest request) throws org.openvpp.jvpp.VppInvocationException; + + @Override + void close(); + +$methods +} +""") + +jvpp_impl_template = Template(""" +package $base_package; + +/** + *

Default implementation of JVpp interface. + *
It was generated by jvpp_impl_gen.py based on $inputfile + *
(python representation of vpe.api generated by vppapigen). + */ +public final class JVppImpl implements $base_package.JVpp { + + private final $base_package.VppConnection connection; + + public JVppImpl(final $base_package.VppConnection connection) { + this.connection = java.util.Objects.requireNonNull(connection,"Connection is null"); + } + + @Override + public void connect($base_package.callback.JVppCallback callback) throws java.io.IOException { + connection.connect(callback); + } + + @Override + public void close() { + connection.close(); + } + + @Override + public int send($base_package.$dto_package.JVppRequest request) throws org.openvpp.jvpp.VppInvocationException { + return request.send(this); + } + +$methods +} +""") + +method_template = Template(""" int $name($base_package.$dto_package.$request request) throws org.openvpp.jvpp.VppInvocationException;""") +method_native_template = Template( + """ private static native int ${name}0($base_package.$dto_package.$request request);""") +method_impl_template = Template(""" public final int $name($base_package.$dto_package.$request request) throws org.openvpp.jvpp.VppInvocationException { + java.util.Objects.requireNonNull(request,"Null request object"); + connection.checkActive(); + int result=${name}0(request); + if(result<0){ + throw new org.openvpp.jvpp.VppInvocationException("${name}",result); + } + return result; + } +""") + +no_arg_method_template = Template(""" int $name() throws org.openvpp.jvpp.VppInvocationException;""") +no_arg_method_native_template = Template(""" private static native int ${name}0() throws org.openvpp.jvpp.VppInvocationException;""") +no_arg_method_impl_template = Template(""" public final int $name() throws org.openvpp.jvpp.VppInvocationException { + connection.checkActive(); + int result=${name}0(); + if(result<0){ + throw new org.openvpp.jvpp.VppInvocationException("${name}",result); + } + return result; + } +""") + + +def generate_jvpp(func_list, base_package, dto_package, inputfile): + """ Generates JVpp interface and JNI implementation """ + print "Generating JVpp" + + 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, + base_package=base_package, + dto_package=dto_package)) + methods_impl.append( + no_arg_method_native_template.substitute(name=camel_case_name, + base_package=base_package, + dto_package=dto_package)) + methods_impl.append(no_arg_method_impl_template.substitute(name=camel_case_name, + base_package=base_package, + dto_package=dto_package)) + else: + methods.append(method_template.substitute(name=camel_case_name, + request=camel_case_name_upper, + base_package=base_package, + dto_package=dto_package)) + methods_impl.append(method_native_template.substitute(name=camel_case_name, + request=camel_case_name_upper, + base_package=base_package, + dto_package=dto_package)) + methods_impl.append(method_impl_template.substitute(name=camel_case_name, + request=camel_case_name_upper, + base_package=base_package, + dto_package=dto_package)) + + jvpp_file = open("JVpp.java", 'w') + jvpp_file.write( + jvpp_ifc_template.substitute(inputfile=inputfile, + methods="\n".join(methods), + base_package=base_package, + dto_package=dto_package)) + jvpp_file.flush() + jvpp_file.close() + + jvpp_file = open("JVppImpl.java", 'w') + jvpp_file.write(jvpp_impl_template.substitute(inputfile=inputfile, + methods="\n".join(methods_impl), + base_package=base_package, + 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 new file mode 100644 index 00000000..df6407f8 --- /dev/null +++ b/vpp-api/java/jvpp/gen/jvppgen/notification_gen.py @@ -0,0 +1,164 @@ +#!/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 + +from util import remove_suffix + +notification_registry_template = Template(""" +package $base_package.$notification_package; + +/** + *

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

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

Notification registry delegating notification processing to registered callbacks. + *
It was generated by notification_gen.py based on $inputfile + *
(python representation of vpe.api generated by vppapigen). + */ +public final class NotificationRegistryImpl implements NotificationRegistry, GlobalNotificationCallback { + + // 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 $base_package.$callback_package.$callback callback){ + if(null != registeredCallbacks.putIfAbsent($base_package.$dto_package.$notification.class, callback)){ + throw new IllegalArgumentException("Callback for " + $base_package.$dto_package.$notification.class + + "notification already registered"); + } + return () -> registeredCallbacks.remove($base_package.$dto_package.$notification.class); + } +""") + +handler_impl_template = Template(""" + @Override + public void on$notification( + final $base_package.$dto_package.$notification notification) { + final $base_package.$callback_package.JVppNotificationCallback JVppNotificationCallback = registeredCallbacks.get($base_package.$dto_package.$notification.class); + if (null != JVppNotificationCallback) { + (($base_package.$callback_package.$callback) registeredCallbacks + .get($base_package.$dto_package.$notification.class)) + .on$notification(notification); + } + } +""") + + +def generate_notification_registry(func_list, base_package, 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(base_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(base_package=base_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, + callback_package=callback_package, + dto_package=dto_package, + notification=notification_dto, + callback=callback_ifc)) + if(callbacks): + callback_file = open(os.path.join(notification_package, "NotificationRegistry.java"), 'w') + callback_file.write(notification_registry_template.substitute(inputfile=inputfile, + register_callback_methods="\n ".join(register_callback_methods), + base_package=base_package, + notification_package=notification_package)) + callback_file.flush() + callback_file.close() + + callback_file = open(os.path.join(notification_package, "GlobalNotificationCallback.java"), 'w') + callback_file.write(global_notification_callback_template.substitute(inputfile=inputfile, + callbacks=", ".join(callbacks), + base_package=base_package, + notification_package=notification_package)) + callback_file.flush() + callback_file.close() + + callback_file = open(os.path.join(notification_package, "NotificationRegistryImpl.java"), '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, + notification_package=notification_package)) + callback_file.flush() + callback_file.close() diff --git a/vpp-api/java/jvpp/gen/jvppgen/util.py b/vpp-api/java/jvpp/gen/jvppgen/util.py new file mode 100644 index 00000000..f22132df --- /dev/null +++ b/vpp-api/java/jvpp/gen/jvppgen/util.py @@ -0,0 +1,195 @@ +#!/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 + +# http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html +jni_2_java_type_mapping = {'jbyte': 'byte', + 'jbyteArray': 'byte[]', + 'jchar': 'char', + 'jcharArray': 'char[]', + 'jshort': 'short', + 'jshortArray': 'short[]', + 'jint': 'int', + 'jintArray': 'int[]', + 'jlong': 'long', + 'jlongArray': 'long[]', + 'jdouble': 'double', + 'jdoubleArray': 'double[]', + 'jfloat': 'float', + 'jfloatArray': 'float[]', + 'void': 'void', + 'jstring': 'java.lang.String', + 'jobject': 'java.lang.Object', + 'jobjectArray': 'java.lang.Object[]' + } + +# https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/types.html#type_signatures +jni_2_signature_mapping = {'jbyte': 'B', + 'jbyteArray': '[B', + 'jchar': 'C', + 'jcharArray': '[C', + 'jshort': 'S', + 'jshortArray': '[S', + 'jint': 'I', + 'jintArray': '[I', + 'jlong': 'J', + 'jlongArray': '[J', + 'jdouble': 'D', + 'jdoubleArray': '[D', + 'jfloat': 'F', + 'jfloatArray': '[F' + } + +# https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#Get_type_Field_routines +jni_field_accessors = { + 'jbyte': 'ByteField', + 'jbyteArray': 'ObjectField', + 'jchar': 'CharField', + 'jcharArray': 'ObjectField', + 'jshort': 'ShortField', + 'jshortArray': 'ObjectField', + 'jint': 'IntField', + 'jintArray': 'ObjectField', + 'jlong': 'LongField', + 'jlongArray': 'ObjectField', + 'jdouble': 'DoubleField', + 'jdoubleArray': 'ObjectField', + 'jfloat': 'FloatField', + 'jfloatArray': 'ObjectField' +} + +# TODO watch out for unsigned types +# http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html +vpp_2_jni_type_mapping = {'u8': 'jbyte', # fixme + 'i8': 'jbyte', + 'u16': 'jshort', + 'i16': 'jshort', + 'u32': 'jint', # fixme + 'i32': 'jint', + 'u64': 'jlong', # fixme + 'i64': 'jlong', + 'f64': 'jdouble' + } + +# 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 "controlping" in camel_case_name_with_suffix.lower() + +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 diff --git a/vpp-api/java/jvpp/gen/notification_gen.py b/vpp-api/java/jvpp/gen/notification_gen.py deleted file mode 100644 index 4ca3c070..00000000 --- a/vpp-api/java/jvpp/gen/notification_gen.py +++ /dev/null @@ -1,164 +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 - -from util import remove_suffix - -notification_registry_template = Template(""" -package $base_package.$notification_package; - -/** - *

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

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

Notification registry delegating notification processing to registered callbacks. - *
It was generated by notification_gen.py based on $inputfile - *
(python representation of vpe.api generated by vppapigen). - */ -public final class NotificationRegistryImpl implements NotificationRegistry, GlobalNotificationCallback { - - // 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 $base_package.$callback_package.$callback callback){ - if(null != registeredCallbacks.putIfAbsent($base_package.$dto_package.$notification.class, callback)){ - throw new IllegalArgumentException("Callback for " + $base_package.$dto_package.$notification.class + - "notification already registered"); - } - return () -> registeredCallbacks.remove($base_package.$dto_package.$notification.class); - } -""") - -handler_impl_template = Template(""" - @Override - public void on$notification( - final $base_package.$dto_package.$notification notification) { - final $base_package.$callback_package.JVppNotificationCallback JVppNotificationCallback = registeredCallbacks.get($base_package.$dto_package.$notification.class); - if (null != JVppNotificationCallback) { - (($base_package.$callback_package.$callback) registeredCallbacks - .get($base_package.$dto_package.$notification.class)) - .on$notification(notification); - } - } -""") - - -def generate_notification_registry(func_list, base_package, 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(base_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(base_package=base_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, - callback_package=callback_package, - dto_package=dto_package, - notification=notification_dto, - callback=callback_ifc)) - - callback_file = open(os.path.join(notification_package, "NotificationRegistry.java"), 'w') - callback_file.write(notification_registry_template.substitute(inputfile=inputfile, - register_callback_methods="\n ".join(register_callback_methods), - base_package=base_package, - notification_package=notification_package)) - callback_file.flush() - callback_file.close() - - callback_file = open(os.path.join(notification_package, "GlobalNotificationCallback.java"), 'w') - callback_file.write(global_notification_callback_template.substitute(inputfile=inputfile, - callbacks=", ".join(callbacks), - base_package=base_package, - notification_package=notification_package)) - callback_file.flush() - callback_file.close() - - callback_file = open(os.path.join(notification_package, "NotificationRegistryImpl.java"), '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, - notification_package=notification_package)) - callback_file.flush() - callback_file.close() diff --git a/vpp-api/java/jvpp/gen/util.py b/vpp-api/java/jvpp/gen/util.py deleted file mode 100644 index f22132df..00000000 --- a/vpp-api/java/jvpp/gen/util.py +++ /dev/null @@ -1,195 +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 - -# http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html -jni_2_java_type_mapping = {'jbyte': 'byte', - 'jbyteArray': 'byte[]', - 'jchar': 'char', - 'jcharArray': 'char[]', - 'jshort': 'short', - 'jshortArray': 'short[]', - 'jint': 'int', - 'jintArray': 'int[]', - 'jlong': 'long', - 'jlongArray': 'long[]', - 'jdouble': 'double', - 'jdoubleArray': 'double[]', - 'jfloat': 'float', - 'jfloatArray': 'float[]', - 'void': 'void', - 'jstring': 'java.lang.String', - 'jobject': 'java.lang.Object', - 'jobjectArray': 'java.lang.Object[]' - } - -# https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/types.html#type_signatures -jni_2_signature_mapping = {'jbyte': 'B', - 'jbyteArray': '[B', - 'jchar': 'C', - 'jcharArray': '[C', - 'jshort': 'S', - 'jshortArray': '[S', - 'jint': 'I', - 'jintArray': '[I', - 'jlong': 'J', - 'jlongArray': '[J', - 'jdouble': 'D', - 'jdoubleArray': '[D', - 'jfloat': 'F', - 'jfloatArray': '[F' - } - -# https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#Get_type_Field_routines -jni_field_accessors = { - 'jbyte': 'ByteField', - 'jbyteArray': 'ObjectField', - 'jchar': 'CharField', - 'jcharArray': 'ObjectField', - 'jshort': 'ShortField', - 'jshortArray': 'ObjectField', - 'jint': 'IntField', - 'jintArray': 'ObjectField', - 'jlong': 'LongField', - 'jlongArray': 'ObjectField', - 'jdouble': 'DoubleField', - 'jdoubleArray': 'ObjectField', - 'jfloat': 'FloatField', - 'jfloatArray': 'ObjectField' -} - -# TODO watch out for unsigned types -# http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html -vpp_2_jni_type_mapping = {'u8': 'jbyte', # fixme - 'i8': 'jbyte', - 'u16': 'jshort', - 'i16': 'jshort', - 'u32': 'jint', # fixme - 'i32': 'jint', - 'u64': 'jlong', # fixme - 'i64': 'jlong', - 'f64': 'jdouble' - } - -# 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 "controlping" in camel_case_name_with_suffix.lower() - -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 -- cgit 1.2.3-korg From 5f9dcff39d5e25c6bef30d569e405635633f3c69 Mon Sep 17 00:00:00 2001 From: Ole Troan Date: Mon, 1 Aug 2016 04:59:13 +0200 Subject: VPP Python language binding - plugin support - Moved Python generator tool to tools directory - Added build-vpp-api Makefile target - Generator now only creates a Python representation of the .api the rest of the framework is in the vpp_papi script - Each plugin has its own namespace. - Plugin Python files are installed in vpp_papi_plugins for easy use inside the build tree. Change-Id: I272c83bb7e5d5e416bdbd8a790a3cc35c5a04e38 Signed-off-by: Ole Troan --- .gitignore | 4 +- Makefile | 6 +- build-data/platforms.mk | 18 ++- plugins/ioam-plugin/Makefile.am | 11 +- plugins/snat-plugin/Makefile.am | 11 +- vlib-api/Makefile.am | 4 + vpp-api/python/Makefile.am | 45 ++++-- vpp-api/python/pneum/pneum.c | 20 +-- vpp-api/python/pneum/pneum.h | 5 +- vpp-api/python/setup.cfg | 7 + vpp-api/python/setup.py | 19 +-- vpp-api/python/tests/test_base.py | 7 + vpp-api/python/tests/test_modules.py | 17 ++ vpp-api/python/tests/test_papi.py | 158 +++++++++---------- vpp-api/python/vpp_papi/__init__.py | 4 +- vpp-api/python/vpp_papi/pneum_wrap.c | 29 +++- vpp-api/python/vpp_papi/vpp_api_base.py | 97 ++++++++++++ vpp-api/python/vpp_papi/vpp_papi.py | 155 ++++++++++++++++++ vpp/vpp-api/api.c | 12 +- vppapigen/Makefile.am | 1 + vppapigen/lex.c | 8 +- vppapigen/node.c | 5 + vppapigen/pyvppapigen.py | 271 ++++++++++++++++++++++++++++++++ 23 files changed, 757 insertions(+), 157 deletions(-) create mode 100644 vpp-api/python/setup.cfg create mode 100644 vpp-api/python/tests/test_base.py create mode 100755 vpp-api/python/tests/test_modules.py create mode 100644 vpp-api/python/vpp_papi/vpp_api_base.py create mode 100644 vpp-api/python/vpp_papi/vpp_papi.py create mode 100755 vppapigen/pyvppapigen.py (limited to 'build-data/platforms.mk') diff --git a/.gitignore b/.gitignore index 42526183..8cbf1e61 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,6 @@ /build-root/*.rpm /build-root/*.changes /build-config.mk -/vpp-api/python/vpp_papi/vpp_papi.py /dpdk/*.tar.gz /dpdk/*.tar.xz /path_setup @@ -51,7 +50,7 @@ test-driver .settings # stop autotools ignore -# OSX and some IDE +# OSX and some IDE .DS_Store .idea/ .project @@ -63,6 +62,7 @@ test-driver GPATH GRTAGS GTAGS +TAGS # Generated documentation /build-root/docs diff --git a/Makefile b/Makefile index 4e3d65bc..39930651 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,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 doxygen wipe-doxygen plugins plugins-release +.PHONY: ctags cscope doxygen wipe-doxygen plugins plugins-release build-vpp-api help: @echo "Make Targets:" @@ -73,6 +73,7 @@ help: @echo " debug - run debug binary with debugger" @echo " debug-release - run release binary with debugger" @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" @@ -172,6 +173,9 @@ plugins: $(BR)/.bootstrap.ok plugins-release: $(BR)/.bootstrap.ok $(call make,$(PLATFORM),plugins-install) +build-vpp-api: $(BR)/.bootstrap.ok + $(call make,$(PLATFORM)_debug,vpp-api-install) + STARTUP_DIR ?= $(PWD) ifeq ("$(wildcard $(STARTUP_CONF))","") define run diff --git a/build-data/platforms.mk b/build-data/platforms.mk index cd65f67c..36cfc878 100644 --- a/build-data/platforms.mk +++ b/build-data/platforms.mk @@ -56,14 +56,16 @@ install-deb: $(patsubst %,%-find-source,$(ROOT_PACKAGES)) >> deb/debian/vpp.install ; \ \ : dev package needs a couple of additions ; \ - echo ../build-tool-native/vppapigen/vppapigen /usr/bin \ - >> deb/debian/vpp-dev.install ; \ - echo ../../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 \ - echo ../$${i} /usr/lib/python2.7/dist-packages/jvppgen \ - >> deb/debian/vpp-dev.install; \ - done; \ + echo ../build-tool-native/vppapigen/vppapigen /usr/bin \ + >> deb/debian/vpp-dev.install ; \ + echo ../../vppapigen/pyvppapigen.py /usr/bin \ + >> deb/debian/vpp-dev.install ; \ + echo ../../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 \ + echo ../$${i} /usr/lib/python2.7/dist-packages/jvppgen \ + >> deb/debian/vpp-dev.install; \ + done; \ \ : generate changelog; \ ./scripts/generate-deb-changelog \ diff --git a/plugins/ioam-plugin/Makefile.am b/plugins/ioam-plugin/Makefile.am index 2ea29e00..68e79248 100644 --- a/plugins/ioam-plugin/Makefile.am +++ b/plugins/ioam-plugin/Makefile.am @@ -28,7 +28,7 @@ ioam_pot_plugin_la_SOURCES = \ ioam/lib-pot/pot_api.c BUILT_SOURCES = \ - ioam/lib-pot/pot.api.h + ioam/lib-pot/pot.api.h ioam/lib-pot/pot.py SUFFIXES = .api.h .api @@ -37,6 +37,15 @@ SUFFIXES = .api.h .api $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ | vppapigen --input - --output $@ --show-name $@ +%.py: %.api + $(info Creating Python binding for $@) + $(CC) $(CPPFLAGS) -E -P -C -x c $< \ + | vppapigen --input - --python - \ + | pyvppapigen.py --input - > $@ + +pyapidir = ${prefix}/vpp_papi_plugins +pyapi_DATA = ioam/lib-pot/pot.py + noinst_HEADERS = \ ioam/lib-pot/pot_all_api_h.h \ ioam/lib-pot/pot_msg_enum.h \ diff --git a/plugins/snat-plugin/Makefile.am b/plugins/snat-plugin/Makefile.am index 0fe694cf..91fec414 100644 --- a/plugins/snat-plugin/Makefile.am +++ b/plugins/snat-plugin/Makefile.am @@ -28,7 +28,7 @@ snat_plugin_la_SOURCES = snat/snat.c \ snat/out2in.c \ snat/snat_plugin.api.h -BUILT_SOURCES = snat/snat.api.h +BUILT_SOURCES = snat/snat.api.h snat/snat.py SUFFIXES = .api.h .api @@ -37,6 +37,15 @@ SUFFIXES = .api.h .api $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ | vppapigen --input - --output $@ --show-name $@ +%.py: %.api + $(info Creating Python binding for $@) + $(CC) $(CPPFLAGS) -E -P -C -x c $< \ + | vppapigen --input - --python - \ + | pyvppapigen.py --input - > $@ + +pyapidir = ${prefix}/vpp_papi_plugins +pyapi_DATA = snat/snat.py + noinst_HEADERS = \ snat/snat_all_api_h.h \ snat/snat_msg_enum.h \ diff --git a/vlib-api/Makefile.am b/vlib-api/Makefile.am index 4b0129a3..5bc00e74 100644 --- a/vlib-api/Makefile.am +++ b/vlib-api/Makefile.am @@ -75,3 +75,7 @@ SUFFIXES = .api.h .api mkdir -p `dirname $@` ; \ $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ | vppapigen --input - --output $@ --show-name $@ + +# install the API definition, so we can produce java bindings, etc. +apidir = $(prefix)/vlibmemory +api_DATA = vlibmemory/memclnt.api diff --git a/vpp-api/python/Makefile.am b/vpp-api/python/Makefile.am index 4d2d221d..eb589335 100644 --- a/vpp-api/python/Makefile.am +++ b/vpp-api/python/Makefile.am @@ -13,33 +13,50 @@ AUTOMAKE_OPTIONS = foreign subdir-objects ACLOCAL_AMFLAGS = -I m4 -AM_CFLAGS = -Wall +AM_CFLAGS = -Wall BUILT_SOURCES = -bin_PROGRAMS = -CLEANFILES = -lib_LTLIBRARIES = +bin_PROGRAMS = +CLEANFILES = +lib_LTLIBRARIES = noinst_PROGRAMS = test_pneum nobase_include_HEADERS = pneum/pneum.h # -# Python binding +# Python / C extension # +lib_LTLIBRARIES += vpp_api.la +vpp_api_la_SOURCES = pneum/pneum.c vpp_papi/pneum_wrap.c +vpp_api_la_LIBADD = -lvlibmemoryclient -lvlibapi -lsvm -lvppinfra -lpthread -lm -lrt +vpp_api_la_LDFLAGS = -module $(shell python-config --ldflags) +vpp_api_la_CPPFLAGS = $(shell python-config --includes) + +# Kept around for setuptools based install. lib_LTLIBRARIES += libpneum.la -libpneum_la_SOURCES = pneum/pneum.c +libpneum_la_SOURCES = pneum/pneum.c setup.py libpneum_la_LIBADD = -lvlibmemoryclient -lvlibapi -lsvm -lvppinfra -lpthread -lm -lrt libpneum_la_LDFLAGS = -module libpneum_la_CPPFLAGS = -BUILT_SOURCES += vpp_papi.py +# +# Core VPP API +# +BUILT_SOURCES += \ + $(prefix)/../vpp/vpp-api/vpe.py \ + $(prefix)/../vlib-api/vlibmemory/memclnt.py -vpp_papi.py: $(prefix)/../vpp/vpp-api/vpe.api pneum/api-gen.py - @echo " PYTHON API"; \ - $(CC) $(CPPFLAGS) -E -P -C -x c $< \ - | vppapigen --input - --python defs_$@; \ - echo "#include " \ - | $(CC) $(CPPFLAGS) -E -P -x c - | grep VL_API \ - | @srcdir@/pneum/api-gen.py -i defs_$@ > @srcdir@/vpp_papi/$@ +%.py: %.api + $(info Creating Python binding for $@) + $(CC) $(CPPFLAGS) -E -P -C -x c $< \ + | vppapigen --input - --python - \ + | pyvppapigen.py --input - > $@ + +# +# TODO: Support both Python 2 and 3. +install-exec-local: + cd $(srcdir); \ + mkdir -p $(prefix)/lib/python2.7/site-packages; \ + PYTHONUSERBASE=$(prefix) python setup.py install --user # # Test client diff --git a/vpp-api/python/pneum/pneum.c b/vpp-api/python/pneum/pneum.c index ac518493..2637d43f 100644 --- a/vpp-api/python/pneum/pneum.c +++ b/vpp-api/python/pneum/pneum.c @@ -10,7 +10,7 @@ * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License. + * limitations under the License. */ #include #include @@ -36,11 +36,11 @@ #include "pneum.h" #define vl_typedefs /* define message structures */ -#include +#include #undef vl_typedefs #define vl_endianfun /* define message structures */ -#include +#include #undef vl_endianfun typedef struct { @@ -54,12 +54,12 @@ pneum_main_t pneum_main; extern int wrap_pneum_callback(char *data, int len); -/* +/* * Satisfy external references when -lvlib is not available. */ void vlib_cli_output (struct vlib_main_t * vm, char * fmt, ...) { - clib_warning ("vlib_cli_output callled..."); + clib_warning ("vlib_cli_output called..."); } #define vl_api_version(n,v) static u32 vpe_api_version = v; @@ -89,7 +89,7 @@ pneum_api_handler (void *msg) int l = ntohl(msgbuf->data_len); if (l == 0) clib_warning("Message ID %d has wrong length: %d\n", id, l); - + /* Call Python callback */ (void)wrap_pneum_callback(msg, l); vl_msg_api_free(msg); @@ -121,12 +121,6 @@ pneum_connect (char *name) int rv = 0; pneum_main_t *pm = &pneum_main; - /* - * Bail out now if we're not running as root - */ - if (geteuid() != 0) - return (-1); - if ((rv = vl_client_api_map("/vpe-api"))) { clib_warning ("vl_client_api map rv %d", rv); return rv; @@ -199,7 +193,7 @@ pneum_read (char **p, int *l) *p = (char *)msg; } else { printf("Read failed with %d\n", rv); - } + } return (rv); } diff --git a/vpp-api/python/pneum/pneum.h b/vpp-api/python/pneum/pneum.h index b99cbd4e..75fccf84 100644 --- a/vpp-api/python/pneum/pneum.h +++ b/vpp-api/python/pneum/pneum.h @@ -12,10 +12,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef __included_pneum_h__ -#define __included_pneum_h__ +#ifndef included_pneum_h +#define included_pneum_h -unsigned int vpe_client_index(void); int pneum_connect(char *name); int pneum_disconnect(void); int pneum_read(char **data, int *l); diff --git a/vpp-api/python/setup.cfg b/vpp-api/python/setup.cfg new file mode 100644 index 00000000..5e19e8c5 --- /dev/null +++ b/vpp-api/python/setup.cfg @@ -0,0 +1,7 @@ +[bdist_wheel] +# This flag says that the code is written to work on both Python 2 and Python +# 3. If at all possible, it is good practice to do this. If you cannot, you +# will need to generate wheels for each Python version that you support. +universal=0 + + diff --git a/vpp-api/python/setup.py b/vpp-api/python/setup.py index d890ba70..e369a0cb 100644 --- a/vpp-api/python/setup.py +++ b/vpp-api/python/setup.py @@ -1,21 +1,16 @@ -from distutils.core import setup, Extension - -module1 = Extension('vpp_api', - define_macros = [('MAJOR_VERSION', '1'), - ('MINOR_VERSION', '0')], - include_dirs = ['pneum'], - libraries = ['pneum'], - library_dirs = ['../../build-root/install-vpp_debug-native/vpp-api/lib64'], - sources = ['vpp_papi/pneum_wrap.c']) +try: + from setuptools import setup +except ImportError: + from distutils.core import setup setup (name = 'vpp_papi', - version = '1.0', + version = '1.1', description = 'VPP Python binding', author = 'Ole Troan', author_email = 'ot@cisco.com', #url = 'https://docs.python.org/extending/building', + test_suite = 'tests', packages=['vpp_papi'], long_description = ''' VPP Python language binding. -''', - ext_modules = [module1]) +''',) diff --git a/vpp-api/python/tests/test_base.py b/vpp-api/python/tests/test_base.py new file mode 100644 index 00000000..8ff5dd47 --- /dev/null +++ b/vpp-api/python/tests/test_base.py @@ -0,0 +1,7 @@ +# Manipulate sys.path to allow tests be run inside the build environment. +import os, sys, glob +scriptdir = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.dirname(glob.glob(scriptdir+'/../../../build-root/install*/vpp-api/lib64/vpp_api.so')[0])) +sys.path.append(os.path.dirname(glob.glob(scriptdir+'/../../../build-root/install*/vlib-api/vlibmemory/memclnt.py')[0])) +sys.path.append(os.path.dirname(glob.glob(scriptdir+'/../../../build-root/install*/vpp/vpp-api/vpe.py')[0])) +sys.path.append(glob.glob(scriptdir+'/../../../build-root/install*/plugins/vpp_papi_plugins')[0]) diff --git a/vpp-api/python/tests/test_modules.py b/vpp-api/python/tests/test_modules.py new file mode 100755 index 00000000..f3066b29 --- /dev/null +++ b/vpp-api/python/tests/test_modules.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +from __future__ import print_function +import unittest +import test_base +import vpp_papi +import pot, snat +print('Plugins:') +vpp_papi.plugin_show() +r = vpp_papi.connect('ole') + +r = vpp_papi.show_version() +print('R:', r) + +r = snat.snat_interface_add_del_feature(1, 1, 1) +print('R:', r) + +vpp_papi.disconnect() diff --git a/vpp-api/python/tests/test_papi.py b/vpp-api/python/tests/test_papi.py index bede7171..ab90eeaa 100755 --- a/vpp-api/python/tests/test_papi.py +++ b/vpp-api/python/tests/test_papi.py @@ -1,102 +1,104 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python -import vpp_papi +from __future__ import print_function import unittest, sys, time, threading, struct, logging +import test_base +import vpp_papi from ipaddress import * papi_event = threading.Event() +print(vpp_papi.VL_API_SW_INTERFACE_SET_FLAGS) def papi_event_handler(result): - if result.vl_msg_id == vpp_papi.VL_API_SW_INTERFACE_SET_FLAGS: - papi_event.set() + if result.vl_msg_id == vpp_papi.vpe.VL_API_SW_INTERFACE_SET_FLAGS: return - if result.vl_msg_id == vpp_papi.VL_API_VNET_INTERFACE_COUNTERS: - format = '>' + str(int(len(result.data) / 8)) + 'Q' - counters = struct.unpack(format, result.data) - print('Counters:', counters) + 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.VL_API_VNET_IP6_FIB_COUNTERS: - print('IP6 FIB Counters:', result.count, len(result.c), len(result)) - i = 0 - # FIB counters allocate a large (1000 bytes) block so message length does not match reality - for c in struct.iter_unpack('>16sBQQ', result.c): - # In Python 3.5 we can use a tuple for prefix, length - print(str(IPv6Address(c[0])) + '/' + str(c[1]), str(c[2]), str(c[3])) - i += 1 - if i >= result.count: - break + 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 TestPAPI(unittest.TestCase): + @classmethod + def setUpClass(cls): + # + # Start main VPP process + cls.vpp_bin = glob.glob(test_base.scriptdir+'/../../../build-root/install-vpp*-native/vpp/bin/vpp')[0] + print("VPP BIN:", cls.vpp_bin) + cls.vpp = subprocess.Popen([cls.vpp_bin, "unix", "nodaemon"], stderr=subprocess.PIPE) + print('Started VPP') + # For some reason unless we let VPP start up the API cannot connect. + time.sleep(0.3) + @classmethod + def tearDownClass(cls): + cls.vpp.terminate() 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) # - # Add a few MAP domains, then dump them later + # Details / Dump # - def test_map(self): - t = vpp_papi.map_summary_stats() - print(t) - ip6 = IPv6Address(u'2001:db8::1').packed - ip4 = IPv4Address(u'10.0.0.0').packed - ip6_src = IPv6Address(u'2001:db9::1').packed - t = vpp_papi.map_add_domain(ip6, ip4, ip6_src, 32, 24, 128, 0, 0, 6, 0, 0) - print(t) - self.assertEqual(t.retval, 0) + def test_details_dump(self): + t = vpp_papi.sw_interface_dump(0, b'') + print('Dump/details T', t) - ip4 = IPv4Address(u'10.0.1.0').packed - t = vpp_papi.map_add_domain(ip6, ip4, ip6_src, 32, 24, 128, 0, 0, 6, 0, 0) + # + # Arrays + # + def 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 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) - t = vpp_papi.map_summary_stats() + ifindex = t.sw_if_index + addr = str(IPv6Address('1::1').packed) + t = vpp_papi.sw_interface_add_del_address(ifindex, 1, 1, 0, 16, addr) print(t) - self.assertEqual(t.total_bindings, 2) - - t = vpp_papi.map_domain_dump() - print (t) - self.assertEqual(len(t), 2) - - def test_sw_interface_dump(self): - # - # Dump interfaces - # - t = vpp_papi.sw_interface_dump(0, b'ignored') - for interface in t: - if interface.vl_msg_id == vpp_papi.VL_API_SW_INTERFACE_DETAILS: - print(interface.interface_name.decode()) + self.assertEqual(t.retval, 0) - def test_want_interface_events(self): - pid = 123 - vpp_papi.register_event_callback(papi_event_handler) - papi_event.clear() - t = vpp_papi.want_interface_events(True, pid) - print (t) - print('Setting interface up') - t = vpp_papi.sw_interface_set_flags(0, 1, 1, 0) - print (t) - self.assertEqual(papi_event.wait(5), True) - t = vpp_papi.sw_interface_set_flags(0, 0, 0, 0) - print (t) - self.assertEqual(papi_event.wait(5), True) + # 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) - @unittest.skip("not quite ready yet") - def test_want_stats(self): - pid = 123 - vpp_papi.register_event_callback(papi_event_handler) - papi_event.clear() t = vpp_papi.want_stats(True, pid) print (t) @@ -104,33 +106,17 @@ class TestPAPI(unittest.TestCase): # # Wait for some stats # - self.assertEqual(papi_event.wait(30), True) + self.assertEqual(papi_event.wait(15), True) t = vpp_papi.want_stats(False, pid) print (t) - def test_tap(self): - pid = 123 - vpp_papi.register_event_callback(papi_event_handler) - papi_event.clear() - t = vpp_papi.want_stats(True, pid) - - print (t) - - t = vpp_papi.tap_connect(1, b'tap', b'foo', 1, 0) - print (t) - self.assertEqual(t.retval, 0) - swifindex = t.sw_if_index - - t = vpp_papi.sw_interface_set_flags(swifindex, 1, 1, 0) - print (t) - self.assertEqual(t.retval, 0) - - ip6 = IPv6Address(u'2001:db8::1').packed - t = vpp_papi.sw_interface_add_del_address(swifindex, 1, 1, 0, 16, ip6) - print (t) - time.sleep(40) + # + # Plugins? + # if __name__ == '__main__': #logging.basicConfig(level=logging.DEBUG) unittest.main() +def test_papi(): + print('test') diff --git a/vpp-api/python/vpp_papi/__init__.py b/vpp-api/python/vpp_papi/__init__.py index 8be644d7..19d78a3a 100644 --- a/vpp-api/python/vpp_papi/__init__.py +++ b/vpp-api/python/vpp_papi/__init__.py @@ -1,2 +1,4 @@ __import__('pkg_resources').declare_namespace(__name__) -from .vpp_papi import * +from . vpp_papi import * + + diff --git a/vpp-api/python/vpp_papi/pneum_wrap.c b/vpp-api/python/vpp_papi/pneum_wrap.c index d1795aa1..7a511974 100644 --- a/vpp-api/python/vpp_papi/pneum_wrap.c +++ b/vpp-api/python/vpp_papi/pneum_wrap.c @@ -1,5 +1,20 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 "pneum.h" +#include "../pneum/pneum.h" static PyObject *pneum_callback = NULL; @@ -35,7 +50,7 @@ wrap_connect (PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "sO:set_callback", &name, &temp)) return (NULL); - + if (!PyCallable_Check(temp)) { PyErr_SetString(PyExc_TypeError, "parameter must be callable"); return NULL; @@ -66,8 +81,8 @@ wrap_write (PyObject *self, PyObject *args) char *data; int len, rv; - if (!PyArg_ParseTuple(args, "s#", &data, &len)) - return NULL; + if (!PyArg_ParseTuple(args, "s#", &data, &len)) + return NULL; Py_BEGIN_ALLOW_THREADS rv = pneum_write(data, len); Py_END_ALLOW_THREADS @@ -117,16 +132,16 @@ initvpp_api (void) { #if PY_VERSION_HEX >= 0x03000000 static struct PyModuleDef vpp_api_module = { -# if PY_VERSION_HEX >= 0x03020000 +#if PY_VERSION_HEX >= 0x03020000 PyModuleDef_HEAD_INIT, -# else +#else { PyObject_HEAD_INIT(NULL) NULL, /* m_init */ 0, /* m_index */ NULL, /* m_copy */ }, -# endif +#endif (char *) "vpp_api", NULL, -1, diff --git a/vpp-api/python/vpp_papi/vpp_api_base.py b/vpp-api/python/vpp_papi/vpp_api_base.py new file mode 100644 index 00000000..a1ef87a3 --- /dev/null +++ b/vpp-api/python/vpp_papi/vpp_api_base.py @@ -0,0 +1,97 @@ +# +# Copyright (c) 2016 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# Module storing all global variables, shared between main module and plugins +# +import threading + +# +# Global variables +# +results = {} +waiting_for_reply = False +plugins = {} + +class ContextId(object): + def __init__(self): + self.context = 0 + def __call__(self, id): + self.context += 1 + return self.context +get_context = ContextId() + +def waiting_for_reply_clear(): + global waiting_for_reply + waiting_for_reply = False + +def waiting_for_reply_set(): + global waiting_for_reply + waiting_for_reply = True + +def is_waiting_for_reply(): + return waiting_for_reply + +def event_callback_set(callback): + global event_callback + event_callback = callback + +def event_callback_call(r): + global event_callback + event_callback(r) + +def results_event_set(context): + results[context]['e'].set() + +def results_event_clear(context): + results[context]['e'].clear() + +def results_event_wait(context, timeout): + results[context]['e'].wait(timeout) + +def results_set(context, r): + results[context]['r'] = r + +def results_append(context, r): + results[context]['r'].append(r) + +def is_results_context(context): + return context in results + +def is_results_more(context): + return 'm' in results[context] + +def results_more_set(context): + results[context]['m'] = True + +def results_prepare(context): + results[context] = {} + results[context]['e'] = threading.Event() + results[context]['e'].clear() + results[context]['r'] = [] + +def results_get(context): + return results[context]['r'] + +def plugin_register(name, func_table, name_to_id_table, version, msg_id_base_set): + plugins[name] = {} + p = plugins[name] + p['func_table'] = func_table + p['name_to_id_table'] = name_to_id_table + p['version'] = version + p['msg_id_base_set'] = msg_id_base_set + +def plugin_show(): + for p in plugins: + print(p) diff --git a/vpp-api/python/vpp_papi/vpp_papi.py b/vpp-api/python/vpp_papi/vpp_papi.py new file mode 100644 index 00000000..6a7a358f --- /dev/null +++ b/vpp-api/python/vpp_papi/vpp_papi.py @@ -0,0 +1,155 @@ +# +# Copyright (c) 2016 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT 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 C API shared object +# +from __future__ import print_function + +import signal, logging, os, sys +from struct import * + +scriptdir = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(scriptdir) +import vpp_api +from vpp_api_base import * + +# Import API definitions. The core VPE API is imported into main namespace +import memclnt +from vpe import * +vpe = sys.modules['vpe'] + +def msg_handler(msg): + if not msg: + logging.warning('vpp_api.read failed') + return + + id = unpack('>H', msg[0:2]) + logging.debug('Received message', id[0]) + if id[0] == memclnt.VL_API_RX_THREAD_EXIT: + logging.info("We got told to leave") + return; + + # + # Decode message and returns a tuple. + # + logging.debug('api_func', api_func_table[id[0]]) + r = api_func_table[id[0]](msg) + if not r: + logging.warning('Message decode failed', id[0]) + return + + if 'context' in r._asdict(): + if r.context > 0: + context = r.context + + # + # XXX: Call provided callback for event + # Are we guaranteed to not get an event during processing of other messages? + # How to differentiate what's a callback message and what not? Context = 0? + # + if not is_waiting_for_reply(): + event_callback_call(r) + return + + # + # Collect results until control ping + # + if id[0] == vpe.VL_API_CONTROL_PING_REPLY: + results_event_set(context) + waiting_for_reply_clear() + return + if not is_results_context(context): + logging.warning('Not expecting results for this context', context) + return + if is_results_more(context): + results_append(context, r) + return + + results_set(context, r) + results_event_set(context) + waiting_for_reply_clear() + +def connect(name): + signal.alarm(3) # 3 second + rv = vpp_api.connect(name, msg_handler) + signal.alarm(0) + logging.info("Connect:", rv) + + # + # Assign message id space for plugins + # + plugin_map_plugins() + + return rv + +def disconnect(): + rv = vpp_api.disconnect() + logging.info("Disconnected") + return rv + +def register_event_callback(callback): + event_callback_set(callback) + +def plugin_name_to_id(plugin, name_to_id_table, base): + try: + m = globals()[plugin] + except KeyError: + m = sys.modules[plugin] + for name in name_to_id_table: + setattr(m, name, name_to_id_table[name] + base) + +def plugin_map_plugins(): + for p in plugins: + if p == 'memclnt' or p == 'vpe': + continue + + # + # Find base + # Update api table + # + version = plugins[p]['version'] + name = p + '_' + format(version, '08x') + r = memclnt.get_first_msg_id(name.encode('ascii')) + + ## TODO: Add error handling + if r.retval != 0: + print('Failed getting first msg id for:', p) + continue + + # Set base + base = r.first_msg_id + msg_id_base_set = plugins[p]['msg_id_base_set'] + msg_id_base_set(base) + plugins[p]['base'] = base + func_table = plugins[p]['func_table'] + i = r.first_msg_id + for entry in func_table: + api_func_table.insert(i, entry) + i += 1 + plugin_name_to_id(p, plugins[p]['name_to_id_table'], base) + +# +# Set up core API +# +memclnt.msg_id_base_set(1) +plugins['memclnt']['base'] = 1 +msg_id_base_set(len(plugins['memclnt']['func_table']) + 1) +plugins['vpe']['base'] = len(plugins['memclnt']['func_table']) + 1 +api_func_table = [] +api_func_table.append(None) +api_func_table[1:] = plugins['memclnt']['func_table'] + plugins['vpe']['func_table'] +plugin_name_to_id('memclnt', plugins['memclnt']['name_to_id_table'], 1) +plugin_name_to_id('vpe', plugins['vpe']['name_to_id_table'], plugins['vpe']['base']) +#logging.basicConfig(level=logging.DEBUG) diff --git a/vpp/vpp-api/api.c b/vpp/vpp-api/api.c index 1de1b55f..2ba5ee40 100644 --- a/vpp/vpp-api/api.c +++ b/vpp/vpp-api/api.c @@ -2887,12 +2887,12 @@ vl_api_vnet_get_summary_stats_t_handler (vl_api_vnet_get_summary_stats_t * mp) } vnet_interface_counter_unlock (im); - /* Note: in HOST byte order! */ - rmp->total_pkts[VLIB_RX] = total_pkts[VLIB_RX]; - rmp->total_bytes[VLIB_RX] = total_bytes[VLIB_RX]; - rmp->total_pkts[VLIB_TX] = total_pkts[VLIB_TX]; - rmp->total_bytes[VLIB_TX] = total_bytes[VLIB_TX]; - rmp->vector_rate = vlib_last_vector_length_per_node (sm->vlib_main); + rmp->total_pkts[VLIB_RX] = clib_host_to_net_u64 (total_pkts[VLIB_RX]); + rmp->total_bytes[VLIB_RX] = clib_host_to_net_u64 (total_bytes[VLIB_RX]); + rmp->total_pkts[VLIB_TX] = clib_host_to_net_u64 (total_pkts[VLIB_TX]); + rmp->total_bytes[VLIB_TX] = clib_host_to_net_u64 (total_bytes[VLIB_TX]); + rmp->vector_rate = + clib_host_to_net_u64 (vlib_last_vector_length_per_node (sm->vlib_main)); vl_msg_api_send_shmem (q, (u8 *) & rmp); } diff --git a/vppapigen/Makefile.am b/vppapigen/Makefile.am index 42530015..066e1c30 100644 --- a/vppapigen/Makefile.am +++ b/vppapigen/Makefile.am @@ -14,6 +14,7 @@ AUTOMAKE_OPTIONS = foreign bin_PROGRAMS = vppapigen +bin_SCRIPTS = pyvppapigen.py BUILT_SOURCES = gram.h diff --git a/vppapigen/lex.c b/vppapigen/lex.c index 88744ff1..b011044d 100644 --- a/vppapigen/lex.c +++ b/vppapigen/lex.c @@ -331,13 +331,17 @@ int main (int argc, char **argv) if (!strncmp (argv [curarg], "--python", 8)) { curarg++; if (curarg < argc) { - pythonfp = fopen (argv[curarg], "w"); + if (!strcmp(argv[curarg], "-")) { + pythonfp = stdout; + } else { + pythonfp = fopen(argv[curarg], "w"); + pythonfile = argv[curarg]; + } if (pythonfp == NULL) { fprintf (stderr, "Couldn't open python output file %s\n", argv[curarg]); exit (1); } - pythonfile = argv[curarg]; curarg++; } else { fprintf(stderr, "Missing filename after --python\n"); diff --git a/vppapigen/node.c b/vppapigen/node.c index e66fdce8..420a128c 100644 --- a/vppapigen/node.c +++ b/vppapigen/node.c @@ -1339,6 +1339,11 @@ void generate_python (YYSTYPE a1, FILE *fp) np = np->peer; } fprintf (fp, "\n]\n"); + + /* + * API CRC signature + */ + fprintf (fp, "vl_api_version = 0x%08x\n\n", (unsigned int)input_crc); } void generate(YYSTYPE a1) diff --git a/vppapigen/pyvppapigen.py b/vppapigen/pyvppapigen.py new file mode 100755 index 00000000..e216169d --- /dev/null +++ b/vppapigen/pyvppapigen.py @@ -0,0 +1,271 @@ +#!/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 __future__ import print_function +import argparse, sys, os, importlib, pprint + +parser = argparse.ArgumentParser(description='VPP Python API generator') +parser.add_argument('-i', '--input', action="store", dest="inputfile", type=argparse.FileType('r')) +parser.add_argument('-c', '--cfile', action="store") +args = parser.parse_args() + +# +# Read API definitions file into vppapidefs +# +exec(args.inputfile.read()) + +# https://docs.python.org/3/library/struct.html +format_struct = {'u8': 'B', + 'u16' : 'H', + 'u32' : 'I', + 'i32' : 'i', + 'u64' : 'Q', + 'f64' : 'd', + 'vl_api_ip4_fib_counter_t' : 'IBQQ', + 'vl_api_ip6_fib_counter_t' : 'QQBQQ', + }; +# +# NB: If new types are introduced in vpe.api, these must be updated. +# +type_size = {'u8': 1, + 'u16' : 2, + 'u32' : 4, + 'i32' : 4, + 'u64' : 8, + 'f64' : 8, + 'vl_api_ip4_fib_counter_t' : 21, + 'vl_api_ip6_fib_counter_t' : 33, +}; + +def eprint(*args, **kwargs): + print(*args, file=sys.stderr, **kwargs) + +def get_args(t): + argslist = [] + for i in t: + if i[1][0] == '_': + argslist.append(i[1][1:]) + else: + argslist.append(i[1]) + + return argslist + +def get_pack(f): + zeroarray = False + bytecount = 0 + pack = '' + elements = 1 + if len(f) is 3 or len(f) is 4: # TODO: add support for variable length arrays (VPP-162) + size = type_size[f[0]] + bytecount += size * int(f[2]) + # Check if we have a zero length array + if f[2] == '0': + # If len 3 zero array + elements = 0; + pack += format_struct[f[0]] + bytecount = size + elif size == 1: + n = f[2] * size + pack += str(n) + 's' + else: + pack += format_struct[f[0]] * int(f[2]) + elements = int(f[2]) + else: + bytecount += type_size[f[0]] + pack += format_struct[f[0]] + return (pack, elements, bytecount) + + +''' +def get_reply_func(f): + if f['name']+'_reply' in func_name: + return func_name[f['name']+'_reply'] + if f['name'].find('_dump') > 0: + r = f['name'].replace('_dump','_details') + if r in func_name: + return func_name[r] + return None +''' + +def footer_print(): + print(''' +def msg_id_base_set(b): + global base + base = b + +import os +name = os.path.splitext(os.path.basename(__file__))[0] + ''') + print(u"plugin_register(name, api_func_table, api_name_to_id,", vl_api_version, ", msg_id_base_set)") + +def api_table_print(name, i): + msg_id_in = 'VL_API_' + name.upper() + fstr = name + '_decode' + print('api_func_table.append(' + fstr + ')') + print('api_name_to_id["' + msg_id_in + '"] =', i) + print('') + +def encode_print(name, id, t): + total = 0 + args = get_args(t) + pack = '>' + for i, f in enumerate(t): + p, elements, size = get_pack(f) + pack += p + total += size + + if name.find('_dump') > 0: + multipart = True + else: + multipart = False + + if len(args) < 4: + print(u"def", name + "(async = False):") + else: + print(u"def", name + "(" + ', '.join(args[3:]) + ", async = False):") + print(u" global base") + print(u" context = get_context(base + " + id + ")") + + print(''' + results_prepare(context) + waiting_for_reply_set() + ''') + if multipart == True: + print(u" results_more_set(context)") + + ### TODO deal with zeroarray!!! + #if zeroarray == True: + # print(u" vpp_api.write(pack('" + pack + "', " + id + ", 0, context, " + ', '.join(args[3:-1]) + ") + " + args[-1] + ")") + #else: + print(u" vpp_api.write(pack('" + pack + "', base + " + id + ", 0, context, " + ', '.join(args[3:]) + "))") + + if multipart == True: + print(u" vpp_api.write(pack('>HII', VL_API_CONTROL_PING, 0, context))") + + print(''' + if not async: + results_event_wait(context, 5) + return results_get(context) + return context + ''') + +def get_normal_pack(t, i, pack, offset): + while t: + f = t.pop(0) + i += 1 + if len(f) >= 3: + return t, i, pack, offset, f + p, elements, size = get_pack(f) + pack += p + offset += size + return t, i, pack, offset, None + +def decode_print(name, t): + # + # Generate code for each element + # + print(u'def ' + name + u'_decode(msg):') + total = 0 + args = get_args(t) + print(u" n = namedtuple('" + name + "', '" + ', '.join(args) + "')") + print(u" res = []") + + pack = '>' + start = 0 + end = 0 + offset = 0 + t = list(t) + i = 0 + while t: + t, i, pack, offset, array = get_normal_pack(t, i, pack, offset) + if array: + p, elements, size = get_pack(array) + + # Byte string + if elements > 0 and type_size[array[0]] == 1: + pack += p + offset += size * elements + continue + + # Dump current pack string + if pack != '>': + print(u" tr = unpack_from('" + pack + "', msg[" + str(start) + ":])") + print(u" res.extend(list(tr))") + start += offset + pack = '>' + + if elements == 0: + # This has to be the last element + if len(array) == 3: + print(u" res.append(msg[" + str(offset) + ":])") + if len(t) > 0: + eprint('WARNING: Variable length array must be last element in message', name, array) + + continue + if size == 1 or len(p) == 1: + # Do it as a bytestring. + if p == 'B': + p = 's' + # XXX: Assume that length parameter is the previous field. Add validation. + print(u" c = res[" + str(i - 2) + "]") + print(u" tr = unpack_from('>' + str(c) + '" + p + "', msg[" + str(start) + ":])") + print(u" res.append(tr)") + continue + print(u" tr2 = []") + print(u" offset = " + str(total)) + print(u" for j in range(res[" + str(i - 2) + "]):") + print(u" tr2.append(unpack_from('>" + p + "', msg[" + str(start) + ":], offset))") + print(u" offset += " + str(size)) + print(u" res.append(tr2)") + continue + + # Missing something!! + print(u" tr = unpack_from('>" + p + "', msg[" + str(start) + ":])") + start += size + + print(u" res.append(tr)") + + if pack != '>': + print(u" tr = unpack_from('" + pack + "', msg[" + str(start) + ":])") + print(u" res.extend(list(tr))") + print(u" return n._make(res)") + print('') + +# +# Generate the main Python file +# +def main(): + print(''' +# +# AUTO-GENERATED FILE. PLEASE DO NOT EDIT. +# +from vpp_api_base import * +from struct import * +from collections import namedtuple +import vpp_api +api_func_table = [] +api_name_to_id = {} + ''') + + for i, a in enumerate(vppapidef): + name = a[0] + encode_print(name, str(i), a[1:]) + decode_print(name, a[1:]) + api_table_print(name, i) + footer_print() + +if __name__ == "__main__": + main() -- cgit 1.2.3-korg From 822af5c95d080a58cda504228df4b5f3896e72b6 Mon Sep 17 00:00:00 2001 From: Miroslav Miklus Date: Tue, 27 Sep 2016 13:23:09 +0200 Subject: FIX sysctl configuration directory man sysctl.d: ... Packages should install their configuration files in /usr/lib/. Files in /etc/ are reserved for the local administrator, who may use this logic to override the configuration files installed by vendor packages. All configuration files are sorted by their filename in lexicographic order, regardless of which of the directories they reside in. If multiple files specify the same option, the entry in the file with the lexicographically latest name will take precedence. It is recommended to prefix all filenames with a two-digit number and a dash, to simplify the ordering of the files. If the administrator wants to disable a configuration file supplied by the vendor, the recommended way is to place a symlink to /dev/null in the configuration directory in /etc/, with the same filename as the vendor configuration file. ... Change-Id: I24b8b7fddf64ec287282ae195e07c9592c494ebe Signed-off-by: Miroslav Miklus --- build-data/platforms.mk | 2 +- build-root/rpm/vpp.spec | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'build-data/platforms.mk') diff --git a/build-data/platforms.mk b/build-data/platforms.mk index 36cfc878..59c28090 100644 --- a/build-data/platforms.mk +++ b/build-data/platforms.mk @@ -52,7 +52,7 @@ install-deb: $(patsubst %,%-find-source,$(ROOT_PACKAGES)) >> deb/debian/vpp.install ; \ \ : and sysctl config ; \ - echo ../../vpp/conf/80-vpp.conf /etc/sysctl.d \ + echo ../../vpp/conf/80-vpp.conf /usr/lib/sysctl.d \ >> deb/debian/vpp.install ; \ \ : dev package needs a couple of additions ; \ diff --git a/build-root/rpm/vpp.spec b/build-root/rpm/vpp.spec index 35964b6d..49590145 100644 --- a/build-root/rpm/vpp.spec +++ b/build-root/rpm/vpp.spec @@ -92,10 +92,10 @@ install -p -m 755 ../../vppapigen/pyvppapigen.py %{buildroot}%{_bindir} # configs # mkdir -p -m755 %{buildroot}/etc/vpp -mkdir -p -m755 %{buildroot}/etc/sysctl.d +mkdir -p -m755 %{buildroot}/usr/lib/sysctl.d install -p -m 644 vpp.service %{buildroot}%{_unitdir} install -p -m 644 ../../vpp/conf/startup.uiopcigeneric.conf %{buildroot}/etc/vpp/startup.conf -install -p -m 644 ../../vpp/conf/80-vpp.conf %{buildroot}/etc/sysctl.d +install -p -m 644 ../../vpp/conf/80-vpp.conf %{buildroot}/usr/lib/sysctl.d # # libraries # @@ -180,7 +180,7 @@ sysctl --system /usr/bin/vpp* /usr/bin/svm* /usr/bin/elftool -%config /etc/sysctl.d/80-vpp.conf +%config /usr/lib/sysctl.d/80-vpp.conf %config /etc/vpp/startup.conf %files lib -- cgit 1.2.3-korg From 8e08e74ce018f33ac0721fef729429b859d3bf0e Mon Sep 17 00:00:00 2001 From: Miroslav Miklus Date: Tue, 11 Oct 2016 13:35:26 +0200 Subject: VPP-474 Revert "FIX sysctl configuration directory" This reverts commit 822af5c95d080a58cda504228df4b5f3896e72b6. Reason for revert is a bug in procps upstart script. Change-Id: Ie9e501c9b52e65d8d0f31ce6600823021e89fb6f Signed-off-by: Miroslav Miklus --- build-data/platforms.mk | 2 +- build-root/rpm/vpp.spec | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'build-data/platforms.mk') diff --git a/build-data/platforms.mk b/build-data/platforms.mk index 59c28090..36cfc878 100644 --- a/build-data/platforms.mk +++ b/build-data/platforms.mk @@ -52,7 +52,7 @@ install-deb: $(patsubst %,%-find-source,$(ROOT_PACKAGES)) >> deb/debian/vpp.install ; \ \ : and sysctl config ; \ - echo ../../vpp/conf/80-vpp.conf /usr/lib/sysctl.d \ + echo ../../vpp/conf/80-vpp.conf /etc/sysctl.d \ >> deb/debian/vpp.install ; \ \ : dev package needs a couple of additions ; \ diff --git a/build-root/rpm/vpp.spec b/build-root/rpm/vpp.spec index b585579e..5fd9629d 100644 --- a/build-root/rpm/vpp.spec +++ b/build-root/rpm/vpp.spec @@ -95,10 +95,10 @@ install -p -m 755 ../../vppapigen/pyvppapigen.py %{buildroot}%{_bindir} # configs # mkdir -p -m755 %{buildroot}/etc/vpp -mkdir -p -m755 %{buildroot}/usr/lib/sysctl.d +mkdir -p -m755 %{buildroot}/etc/sysctl.d install -p -m 644 vpp.service %{buildroot}%{_unitdir} install -p -m 644 ../../vpp/conf/startup.uiopcigeneric.conf %{buildroot}/etc/vpp/startup.conf -install -p -m 644 ../../vpp/conf/80-vpp.conf %{buildroot}/usr/lib/sysctl.d +install -p -m 644 ../../vpp/conf/80-vpp.conf %{buildroot}/etc/sysctl.d # # libraries # @@ -204,7 +204,7 @@ fi /usr/bin/vpp* /usr/bin/svm* /usr/bin/elftool -%config /usr/lib/sysctl.d/80-vpp.conf +%config /etc/sysctl.d/80-vpp.conf %config /etc/vpp/startup.conf %files lib -- cgit 1.2.3-korg From 6ce685d79b1365588a92340e5c45cdbdea92d5db Mon Sep 17 00:00:00 2001 From: Ed Warnicke Date: Fri, 28 Oct 2016 22:52:36 +0000 Subject: Initial deb packaging of vpp-python-api Change-Id: I14d5180d6abd59b813906011718121a2bbc9bafd Signed-off-by: Ed Warnicke --- build-data/platforms.mk | 4 ++++ build-root/deb/debian/.gitignore | 1 + build-root/deb/debian/control | 7 +++++++ build-root/deb/debian/rules | 2 +- build-root/scripts/find-python-api-contents | 8 ++++++++ 5 files changed, 21 insertions(+), 1 deletion(-) create mode 100755 build-root/scripts/find-python-api-contents (limited to 'build-data/platforms.mk') diff --git a/build-data/platforms.mk b/build-data/platforms.mk index 36cfc878..9d878151 100644 --- a/build-data/platforms.mk +++ b/build-data/platforms.mk @@ -43,6 +43,10 @@ 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 ; \ + \ : dpdk headers ; \ ./scripts/find-dpdk-contents $(INSTALL_PREFIX)$(ARCH) \ deb/debian/vpp-dpdk-dev.install ; \ diff --git a/build-root/deb/debian/.gitignore b/build-root/deb/debian/.gitignore index e7868b4e..75d8fbbc 100644 --- a/build-root/deb/debian/.gitignore +++ b/build-root/deb/debian/.gitignore @@ -11,3 +11,4 @@ vpp-dpdk-dev/ vpp-dpdk-dkms/ vpp-dbg/ vppctl/ +vpp-python-api/ diff --git a/build-root/deb/debian/control b/build-root/deb/debian/control index 4be6c4aa..86383b14 100644 --- a/build-root/deb/debian/control +++ b/build-root/deb/debian/control @@ -59,3 +59,10 @@ Architecture: any 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 +Architecture: any +Depends: ${python:Depends}, ${misc:Depends}, vpp (= ${source:Version}) +Description: VPP Python API bindings + This package contains VPP python api bindings + . diff --git a/build-root/deb/debian/rules b/build-root/deb/debian/rules index b5afbdb6..4ecd38f7 100755 --- a/build-root/deb/debian/rules +++ b/build-root/deb/debian/rules @@ -18,7 +18,7 @@ include /usr/share/dpkg/default.mk # main packaging script based on dh7 syntax %: - dh $@ --with dkms --with systemd + dh $@ --with dkms --with systemd,python2 override_dh_install: dh_install --exclude .git diff --git a/build-root/scripts/find-python-api-contents b/build-root/scripts/find-python-api-contents new file mode 100755 index 00000000..9b390e75 --- /dev/null +++ b/build-root/scripts/find-python-api-contents @@ -0,0 +1,8 @@ +#!/bin/bash + +rm -f $2 + +for i in $(find ${1}/vpp-api/lib/python2.7/site-packages/ -type f -print); do + echo ../${i} /usr/lib/python2.7/site-packages/vpp_papi >> ${2} +done + -- cgit 1.2.3-korg From 20a29c7b4d1b5b68112498bee21ee7f3fe123b13 Mon Sep 17 00:00:00 2001 From: Thomas F Herbert Date: Thu, 13 Oct 2016 18:36:50 -0400 Subject: VPP-498: Prepare vpp RPM packaging for use by downstream distros. Change spec to add new macros to get rid of relative dir reference and use vpp version. Store version string in .version to store metadata in dist archive. New script to create dist archive. Add dist and wipedist targets to Makefile for builds of source RPMs. Change-Id: I7cf0164f0cb094ec70f3dc323ed7fa2ee82bd902 Signed-off-by: Thomas F Herbert --- Makefile | 21 ++++++++++++++++++-- build-data/platforms.mk | 6 +++++- build-root/rpm/vpp.spec | 48 ++++++++++++++++++++++++++++------------------ build-root/scripts/verdist | 31 ++++++++++++++++++++++++++++++ build-root/scripts/version | 45 ++++++++++++++++++++++++++++++++++--------- 5 files changed, 120 insertions(+), 31 deletions(-) create mode 100755 build-root/scripts/verdist (limited to 'build-data/platforms.mk') diff --git a/Makefile b/Makefile index 3a6c7834..98700864 100644 --- a/Makefile +++ b/Makefile @@ -167,10 +167,27 @@ define make @make -C $(BR) PLATFORM=$(PLATFORM) TAG=$(1) $(2) endef +$(BR)/scripts/.version: +ifneq ("$(wildcard /etc/redhat-release)","") + $(shell $(BR)/scripts/version rpm-string > $(BR)/scripts/.version) +else + $(shell $(BR)/scripts/version > $(BR)/scripts/.version) +endif + +dist: $(BR)/scripts/.version + $(MAKE) verstring=$(PLATFORM)-$(shell cat $(BR)/scripts/.version) prefix=$(PLATFORM) distversion + +distversion: $(BR)/scripts/.version + $(BR)/scripts/verdist ${BR} ${prefix}-$(shell $(BR)/scripts/version rpm-version) ${verstring} + mv $(verstring).tar.gz $(BR)/rpm + build: $(BR)/.bootstrap.ok $(call make,$(PLATFORM)_debug,vpp-install) -wipe: $(BR)/.bootstrap.ok +wipedist: + $(RM) $(BR)/scripts/.version $(BR)/rpm/*.tar.gz + +wipe: wipedist $(BR)/.bootstrap.ok $(call make,$(PLATFORM)_debug,vpp-wipe) rebuild: wipe build @@ -271,7 +288,7 @@ run-vat: pkg-deb: $(call make,$(PLATFORM),install-deb) -pkg-rpm: +pkg-rpm: dist $(call make,$(PLATFORM),install-rpm) ctags: ctags.files diff --git a/build-data/platforms.mk b/build-data/platforms.mk index 9d878151..16e61e3f 100644 --- a/build-data/platforms.mk +++ b/build-data/platforms.mk @@ -89,7 +89,11 @@ install-rpm: $(patsubst %,%-find-source,$(ROOT_PACKAGES)) $(ROOT_PACKAGES)) || exit 1; \ \ cd rpm ; \ + mkdir -p SOURCES ; \ + if test -f *.tar.gz ; then mv *.tar.gz SOURCES ; fi ; \ rpmbuild -bb --define "_topdir $$PWD" --define \ - "_install_dir $(INSTALL_PREFIX)$(ARCH)" vpp.spec ; \ + "_install_dir $(INSTALL_PREFIX)$(ARCH)" \ + --define "_mu_build_root_dir $(MU_BUILD_ROOT_DIR)" \ + vpp.spec ; \ mv $$(find RPMS -name \*.rpm -type f) .. diff --git a/build-root/rpm/vpp.spec b/build-root/rpm/vpp.spec index 8c4f4f05..7f0e2a34 100644 --- a/build-root/rpm/vpp.spec +++ b/build-root/rpm/vpp.spec @@ -1,5 +1,6 @@ -%define _vpp_install_dir ../%{_install_dir} -%define _vpp_build_dir ../build-tool-native +%define _mu_build_dir %{_mu_build_root_dir} +%define _vpp_install_dir %{_install_dir} +%define _vpp_build_dir build-tool-native %define _unitdir /lib/systemd/system %define _topdir %(pwd) %define _builddir %{_topdir} @@ -27,6 +28,8 @@ Release: %{_release} Requires: vpp-lib = %{_version}-%{_release}, net-tools, pciutils, python BuildRequires: systemd +Source: %{name}-%{_version}-%{_release}.tar.gz + %description This package provides VPP executables: vpp, vpp_api_test, vpp_json_test vpp - the vector packet engine @@ -76,6 +79,13 @@ Requires: vpp = %{_version}-%{_release}, vpp-lib = %{_version}-%{_release} %description python-api This package contains the python bindings for the vpp api +%prep +%setup -q -n %{name}-%{_version} + +%build +make bootstrap +make build-release + %pre # Add the vpp group groupadd -f -r vpp @@ -86,22 +96,22 @@ groupadd -f -r vpp # mkdir -p -m755 %{buildroot}%{_bindir} mkdir -p -m755 %{buildroot}%{_unitdir} -install -p -m 755 %{_vpp_install_dir}/*/bin/* %{buildroot}%{_bindir} -install -p -m 755 %{_vpp_build_dir}/vppapigen/vppapigen %{buildroot}%{_bindir} -install -p -m 755 ../../vppapigen/pyvppapigen.py %{buildroot}%{_bindir} +install -p -m 755 %{_mu_build_dir}/%{_vpp_install_dir}/*/bin/* %{buildroot}%{_bindir} +install -p -m 755 %{_mu_build_dir}/%{_vpp_build_dir}/vppapigen/vppapigen %{buildroot}%{_bindir} +install -p -m 755 %{_mu_build_dir}/../vppapigen/pyvppapigen.py %{buildroot}%{_bindir} # # configs # mkdir -p -m755 %{buildroot}/etc/vpp mkdir -p -m755 %{buildroot}/etc/sysctl.d -install -p -m 644 vpp.service %{buildroot}%{_unitdir} -install -p -m 644 ../../vpp/conf/startup.uiopcigeneric.conf %{buildroot}/etc/vpp/startup.conf -install -p -m 644 ../../vpp/conf/80-vpp.conf %{buildroot}/etc/sysctl.d +install -p -m 644 %{_mu_build_dir}/rpm/vpp.service %{buildroot}%{_unitdir} +install -p -m 644 %{_mu_build_dir}/../vpp/conf/startup.uiopcigeneric.conf %{buildroot}/etc/vpp/startup.conf +install -p -m 644 %{_mu_build_dir}/../vpp/conf/80-vpp.conf %{buildroot}/etc/sysctl.d # # libraries # mkdir -p -m755 %{buildroot}%{_libdir} -for file in $(find %{_vpp_install_dir}/*/lib* -type f -name '*.so.*.*.*' -print ) +for file in $(find %{_mu_build_dir}/%{_vpp_install_dir}/*/lib* -type f -name '*.so.*.*.*' -print ) do install -p -m 755 $file %{buildroot}%{_libdir} done @@ -116,7 +126,7 @@ done # Python bindings mkdir -p -m755 %{buildroot}%{python2_sitelib}/vpp_papi -for file in $(find %{_vpp_install_dir}/*/lib/python2.7/site-packages/ -type f -print | grep -v pyc | grep -v pyo) +for file in $(find %{_mu_build_dir}/%{_vpp_install_dir}/*/lib/python2.7/site-packages/ -type f -print | grep -v pyc | grep -v pyo) do install -p -m 666 $file %{buildroot}%{python2_sitelib}/vpp_papi/ done @@ -124,7 +134,7 @@ done # # devel # -for dir in $(find %{_vpp_install_dir}/*/include/ -maxdepth 0 -type d -print | grep -v dpdk) +for dir in $(find %{_mu_build_dir}/%{_vpp_install_dir}/*/include/ -maxdepth 0 -type d -print | grep -v dpdk) do for subdir in $(cd ${dir} && find . -type d -print) do @@ -137,16 +147,16 @@ do done mkdir -p -m755 %{buildroot}%{python2_sitelib}/jvppgen -install -p -m755 ../../vpp-api/java/jvpp/gen/jvpp_gen.py %{buildroot}/usr/bin -for i in $(ls ../../vpp-api/java/jvpp/gen/jvppgen/*.py); do +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 -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 %{_vpp_install_dir}/../../sample-plugin && find -type f -print) +for file in $(cd %{_mu_build_dir}/%{_vpp_install_dir}/../../sample-plugin && find -type f -print) do - install -p -m 644 %{_vpp_install_dir}/../../sample-plugin/$file \ + install -p -m 644 %{_mu_build_dir}/%{_vpp_install_dir}/../../sample-plugin/$file \ %{buildroot}/usr/share/doc/vpp/examples/sample-plugin/$file done @@ -156,15 +166,15 @@ done # mkdir -p -m755 %{buildroot}/usr/lib/vpp_plugins mkdir -p -m755 %{buildroot}/usr/lib/vpp_api_test_plugins -for file in $(cd %{_vpp_install_dir}/plugins/lib64/vpp_plugins && find -type f -print) +for file in $(cd %{_mu_build_dir}/%{_vpp_install_dir}/plugins/lib64/vpp_plugins && find -type f -print) do - install -p -m 644 %{_vpp_install_dir}/plugins/lib64/vpp_plugins/$file \ + 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 %{_vpp_install_dir}/plugins/lib64/vpp_api_test_plugins && find -type f -print) +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 %{_vpp_install_dir}/plugins/lib64/vpp_api_test_plugins/$file \ + 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 diff --git a/build-root/scripts/verdist b/build-root/scripts/verdist new file mode 100755 index 00000000..9d1f1b5a --- /dev/null +++ b/build-root/scripts/verdist @@ -0,0 +1,31 @@ +#!/bin/bash + +# +# Add version to dist tarball. +# +BR=$1 +prefix=$2 +verstring=$3 +BASE=`pwd` + +git rev-parse 2> /dev/null +if [ $? == 0 ]; then + git archive --prefix=${prefix}/ HEAD | gzip -9 > ${verstring}.tar.gz +else + cd .. + tar -c ${prefix} | gzip -9 > ${verstring}.tar.gz + cp ${verstring}.tar.gz $BASE + cd $BASE +fi + +mkdir ${BASE}/tmp +cd ${BASE}/tmp +tar -xzf ${BASE}/${verstring}.tar.gz +rm ${BASE}/${verstring}.tar.gz + +cp ${BR}/scripts/.version ${BASE}/tmp/${prefix}/build-root/scripts +tar -c ${prefix} | gzip -9 > ${verstring}.tar.gz +mv ${verstring}.tar.gz ${BASE} + +cd ${BASE} +rm -rf tmp diff --git a/build-root/scripts/version b/build-root/scripts/version index 84ee5dbe..af447286 100755 --- a/build-root/scripts/version +++ b/build-root/scripts/version @@ -1,8 +1,32 @@ #!/bin/bash -TAG=$(git describe | cut -d- -f1 | sed -e 's/^v//') -ADD=$(git describe | cut -s -d- -f2) -CMT=$(git describe --dirty --match 'v*'| cut -s -d- -f3,4) +path=$( cd "$(dirname "${BASH_SOURCE}")" ; pwd -P ) + +cd "$path" + +git rev-parse 2> /dev/null +if [ $? == 0 ]; then + vstring=$(git describe) +elif [ -f .version ]; then + vstring=$(cat .version) +else + if [ -f ../rpm/*.gz ]; then + vstring=$(ls ../rpm/*.gz) + else + exit 1 + fi +fi + +TAG=$(echo ${vstring} | cut -d- -f1 | sed -e 's/^v//') +ADD=$(echo ${vstring} | cut -s -d- -f2) + +git rev-parse 2> /dev/null +if [ $? == 0 ]; then + CMT=$(git describe --dirty --match 'v*'| cut -s -d- -f3,4) +else + CMT=$(echo ${vstring} | cut -s -d- -f3,4) +fi +CMTR=$(echo $CMT | sed 's/-/_/') if [ -n "${BUILD_NUMBER}" ]; then BLD="~b${BUILD_NUMBER}" @@ -15,13 +39,16 @@ fi if [ "$1" = "rpm-release" ]; then [ -z "${ADD}" ] && echo release && exit - CMT=$(git describe --dirty --match 'v*'| cut -s -d- -f3,4 | sed 's/-/_/') - echo ${ADD}${CMT:+~${CMT}}${BLD} + echo ${ADD}${CMTR:+~${CMTR}}${BLD} exit fi -if [ -n "${ADD}" ]; then - echo ${TAG}-${ADD}${CMT:+~${CMT}}${BLD} -else - echo ${TAG} + if [ -n "${ADD}" ]; then + if [ "$1" = "rpm-string" ]; then + echo ${TAG}-${ADD}${CMTR:+~${CMTR}}${BLD} + else + echo ${TAG}-${ADD}${CMT:+~${CMT}}${BLD} + fi + else + echo ${TAG} fi -- cgit 1.2.3-korg From f14e3bf7b297f3b9eea87af412929bb8f277b315 Mon Sep 17 00:00:00 2001 From: Ole Troan Date: Thu, 1 Dec 2016 21:49:03 +0100 Subject: API: Packaging of JSON files. Change-Id: If041b6faf1a091d4758b514f0a8cd800ee0e6a89 Signed-off-by: Ole Troan Signed-off-by: Ole Troan Signed-off-by: Ole Troan --- build-data/platforms.mk | 10 +- build-data/suffix-rules.mk | 6 +- build-root/rpm/vpp.spec | 20 +- build-root/scripts/find-api-core-contents | 9 + build-root/scripts/find-api-lib-contents | 6 + build-root/scripts/find-plugins-contents | 4 + plugins/flowperpkt-plugin/Makefile.am | 15 +- plugins/ioam-plugin/Makefile.am | 31 ++-- plugins/lb-plugin/Makefile.am | 15 +- plugins/sample-plugin/Makefile.am | 11 +- plugins/snat-plugin/Makefile.am | 18 +- vlib-api/Makefile.am | 9 +- vnet/Makefile.am | 8 +- vpp-api/Makefile.am | 15 -- vpp-api/java/Makefile.am | 6 +- vpp-api/python/Makefile.am | 17 +- vpp/Makefile.am | 6 +- vppapigen/Makefile.am | 2 +- vppapigen/pyvppapigen.py | 291 ------------------------------ 19 files changed, 132 insertions(+), 367 deletions(-) create mode 100755 build-root/scripts/find-api-core-contents create mode 100755 build-root/scripts/find-api-lib-contents delete mode 100755 vppapigen/pyvppapigen.py (limited to 'build-data/platforms.mk') diff --git a/build-data/platforms.mk b/build-data/platforms.mk index 16e61e3f..a568c7a0 100644 --- a/build-data/platforms.mk +++ b/build-data/platforms.mk @@ -28,6 +28,10 @@ install-deb: $(patsubst %,%-find-source,$(ROOT_PACKAGES)) | sed -e 's:.*:../& /usr/bin:' \ > deb/debian/vpp.install ; \ \ + : core api definitions ; \ + ./scripts/find-api-core-contents $(INSTALL_PREFIX)$(ARCH) \ + deb/debian/vpp.install ; \ + \ : need symbolic links in the lib pkg ; \ find $(INSTALL_PREFIX)$(ARCH)/*/lib* \( -type f -o -type l \) \ -print | egrep -e '*\.so\.*\.*\.*' \ @@ -35,6 +39,10 @@ install-deb: $(patsubst %,%-find-source,$(ROOT_PACKAGES)) | sed -e 's:.*:../& /usr/lib/x86_64-linux-gnu:' \ > deb/debian/vpp-lib.install ; \ \ + : vnet api definitions ; \ + ./scripts/find-api-lib-contents $(INSTALL_PREFIX)$(ARCH) \ + deb/debian/vpp-lib.install ; \ + \ : dev package ; \ ./scripts/find-dev-contents $(INSTALL_PREFIX)$(ARCH) \ deb/debian/vpp-dev.install ; \ @@ -62,8 +70,6 @@ install-deb: $(patsubst %,%-find-source,$(ROOT_PACKAGES)) : dev package needs a couple of additions ; \ echo ../build-tool-native/vppapigen/vppapigen /usr/bin \ >> deb/debian/vpp-dev.install ; \ - echo ../../vppapigen/pyvppapigen.py /usr/bin \ - >> deb/debian/vpp-dev.install ; \ echo ../../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 \ diff --git a/build-data/suffix-rules.mk b/build-data/suffix-rules.mk index 95069297..e3eeb922 100644 --- a/build-data/suffix-rules.mk +++ b/build-data/suffix-rules.mk @@ -20,4 +20,8 @@ $(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 $@ diff --git a/build-root/rpm/vpp.spec b/build-root/rpm/vpp.spec index 0620234d..5db0c4bd 100644 --- a/build-root/rpm/vpp.spec +++ b/build-root/rpm/vpp.spec @@ -98,7 +98,12 @@ mkdir -p -m755 %{buildroot}%{_bindir} mkdir -p -m755 %{buildroot}%{_unitdir} install -p -m 755 %{_mu_build_dir}/%{_vpp_install_dir}/*/bin/* %{buildroot}%{_bindir} install -p -m 755 %{_mu_build_dir}/%{_vpp_build_dir}/vppapigen/vppapigen %{buildroot}%{_bindir} -install -p -m 755 %{_mu_build_dir}/../vppapigen/pyvppapigen.py %{buildroot}%{_bindir} + +# core api +mkdir -p -m755 %{buildroot}/usr/share/vpp/api +install -p -m 755 %{_mu_build_dir}/%{_vpp_install_dir}/vpp/vpp-api/vpe.api.json %{buildroot}/usr/share/vpp/api +install -p -m 755 %{_mu_build_dir}/%{_vpp_install_dir}/vlib-api/vlibmemory/memclnt.api.json %{buildroot}/usr/share/vpp/api + # # configs # @@ -123,6 +128,10 @@ do ( cd %{buildroot}%{_libdir} && ln -fs $file $(echo $file | sed -e 's/\(\.so\)\.[0-9]\+.*/\1/') ) done +for file in $(find %{_mu_build_dir}/%{_vpp_install_dir}/vnet -type f -name '*.api.json' -print ) +do + install -p -m 644 $file %{buildroot}/usr/share/vpp/api +done # Python bindings mkdir -p -m755 %{buildroot}%{python2_sitelib}/vpp_papi @@ -178,6 +187,11 @@ do %{buildroot}/usr/lib/vpp_api_test_plugins/$file done +for file in $(find %{_mu_build_dir}/%{_vpp_install_dir}/plugins -type f -name '*.api.json' -print ) +do + install -p -m 644 $file %{buildroot}/usr/share/vpp/api +done + %post sysctl --system %systemd_post vpp.service @@ -214,12 +228,14 @@ fi /usr/bin/elftool %config /etc/sysctl.d/80-vpp.conf %config /etc/vpp/startup.conf +/usr/share/vpp/api/* %files lib %defattr(-,bin,bin) %exclude %{_libdir}/vpp_plugins %exclude %{_libdir}/vpp_api_test_plugins %{_libdir}/* +/usr/share/vpp/api/* %files python-api %defattr(644,root,root) @@ -229,7 +245,6 @@ fi %defattr(-,bin,bin) /usr/bin/vppapigen /usr/bin/jvpp_gen.py -/usr/bin/pyvppapigen.py %{_includedir}/* %{python2_sitelib}/jvppgen/* /usr/share/doc/vpp/examples/sample-plugin @@ -238,3 +253,4 @@ fi %defattr(-,bin,bin) /usr/lib/vpp_plugins/* /usr/lib/vpp_api_test_plugins/* +/usr/share/vpp/api/* diff --git a/build-root/scripts/find-api-core-contents b/build-root/scripts/find-api-core-contents new file mode 100755 index 00000000..f1f96f1f --- /dev/null +++ b/build-root/scripts/find-api-core-contents @@ -0,0 +1,9 @@ +#!/bin/bash + +for i in $(find ${1}/vpp -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 + echo ../${i} /usr/share/vpp/api/ >> ${2} +done + diff --git a/build-root/scripts/find-api-lib-contents b/build-root/scripts/find-api-lib-contents new file mode 100755 index 00000000..562db7b8 --- /dev/null +++ b/build-root/scripts/find-api-lib-contents @@ -0,0 +1,6 @@ +#!/bin/bash + +for i in $(find ${1}/vnet -name *.api.json -type f -print); do + echo ../${i} /usr/share/vpp/api/ >> ${2} +done + diff --git a/build-root/scripts/find-plugins-contents b/build-root/scripts/find-plugins-contents index 8d1a4d5a..a5a52acf 100755 --- a/build-root/scripts/find-plugins-contents +++ b/build-root/scripts/find-plugins-contents @@ -9,3 +9,7 @@ done for i in ${1}/plugins/lib64/vpp_api_test_plugins/*.so; do echo ../${i} /usr/lib/vpp_api_test_plugins >> ${2} done + +for i in $(find ${1}/plugins -name *.api.json -type f -print); do + echo ../${i} /usr/share/vpp/api/ >> ${2} +done diff --git a/plugins/flowperpkt-plugin/Makefile.am b/plugins/flowperpkt-plugin/Makefile.am index fe0d8b27..1df758ed 100644 --- a/plugins/flowperpkt-plugin/Makefile.am +++ b/plugins/flowperpkt-plugin/Makefile.am @@ -28,15 +28,26 @@ flowperpkt_plugin_la_SOURCES = flowperpkt/flowperpkt.c \ flowperpkt/flowperpkt_plugin.api.h flowperpkt_plugin_la_LDFLAGS = -module -BUILT_SOURCES = flowperpkt/flowperpkt.api.h +BUILT_SOURCES = \ + flowperpkt/flowperpkt.api.h \ + flowperpkt/flowperpkt.api.json -SUFFIXES = .api.h .api +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)/flowperpkt/ +api_DATA = flowperpkt/flowperpkt.api.json + noinst_HEADERS = \ flowperpkt/flowperpkt_all_api_h.h \ flowperpkt/flowperpkt_msg_enum.h \ diff --git a/plugins/ioam-plugin/Makefile.am b/plugins/ioam-plugin/Makefile.am index c66c6cd5..a9ed4ab4 100644 --- a/plugins/ioam-plugin/Makefile.am +++ b/plugins/ioam-plugin/Makefile.am @@ -28,7 +28,8 @@ ioam_pot_plugin_la_SOURCES = \ ioam/lib-pot/pot_api.c BUILT_SOURCES = \ - ioam/lib-pot/pot.api.h ioam/lib-pot/pot.py + ioam/lib-pot/pot.api.h \ + ioam/lib-pot/pot.api.json SUFFIXES = .api.h .api @@ -37,14 +38,17 @@ SUFFIXES = .api.h .api $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ | vppapigen --input - --output $@ --show-name $@ -%.py: %.api - $(info Creating Python binding for $@) - $(CC) $(CPPFLAGS) -E -P -C -x c $< \ - | vppapigen --input - --python - \ - | pyvppapigen.py --input - > $@ +%.api.json: %.api + @echo " JSON APIGEN " $@ ; \ + mkdir -p `dirname $@` ; \ + $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ + | vppapigen --input - --json $@ -pyapidir = ${prefix}/vpp_papi_plugins -pyapi_DATA = ioam/lib-pot/pot.py +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 \ @@ -73,7 +77,9 @@ ioam/export/node.c \ ioam/export/ioam_export.api.h \ ioam/export/ioam_export_thread.c -BUILT_SOURCES += ioam/export/ioam_export.api.h +BUILT_SOURCES += \ + ioam/export/ioam_export.api.h \ + ioam/export/ioam_export.api.json noinst_HEADERS += \ ioam/export/ioam_export_all_api_h.h \ @@ -96,10 +102,9 @@ ioam_trace_plugin_la_SOURCES = \ ioam/lib-trace/trace_util.h \ ioam/lib-trace/trace_api.c -BUILT_SOURCES += \ - ioam/lib-trace/trace.api.h ioam/lib-trace/trace.py - -pyapi_DATA += ioam/lib-trace/trace.py +BUILT_SOURCES += \ + ioam/lib-trace/trace.api.h \ + ioam/lib-trace/trace.api.json noinst_HEADERS += \ ioam/export/ioam_export_all_api_h.h \ diff --git a/plugins/lb-plugin/Makefile.am b/plugins/lb-plugin/Makefile.am index 8d92ff1d..8e360279 100644 --- a/plugins/lb-plugin/Makefile.am +++ b/plugins/lb-plugin/Makefile.am @@ -24,13 +24,26 @@ 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 -SUFFIXES = .api.h .api +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 = \ diff --git a/plugins/sample-plugin/Makefile.am b/plugins/sample-plugin/Makefile.am index 0b213791..e221f8c1 100644 --- a/plugins/sample-plugin/Makefile.am +++ b/plugins/sample-plugin/Makefile.am @@ -25,7 +25,7 @@ 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 +BUILT_SOURCES = sample/sample.api.h sample/sample.api.json SUFFIXES = .api.h .api @@ -34,6 +34,15 @@ SUFFIXES = .api.h .api $(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 \ diff --git a/plugins/snat-plugin/Makefile.am b/plugins/snat-plugin/Makefile.am index cdf7e356..f10ba25e 100644 --- a/plugins/snat-plugin/Makefile.am +++ b/plugins/snat-plugin/Makefile.am @@ -28,7 +28,7 @@ snat_plugin_la_SOURCES = snat/snat.c \ snat/out2in.c \ snat/snat_plugin.api.h -BUILT_SOURCES = snat/snat.api.h snat/snat.py +BUILT_SOURCES = snat/snat.api.h snat/snat.api.json SUFFIXES = .api.h .api @@ -37,14 +37,14 @@ SUFFIXES = .api.h .api $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ | vppapigen --input - --output $@ --show-name $@ -%.py: %.api - $(info Creating Python binding for $@) - $(CC) $(CPPFLAGS) -E -P -C -x c $< \ - | vppapigen --input - --python - \ - | pyvppapigen.py --input - > $@ +%.api.json: %.api + @echo " JSON APIGEN " $@ ; \ + mkdir -p `dirname $@` ; \ + $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ + | vppapigen --input - --json $@ -pyapidir = ${prefix}/vpp_papi_plugins -pyapi_DATA = snat/snat.py +apidir = $(prefix)/snat/ +api_DATA = snat.api.json noinst_HEADERS = \ snat/snat_all_api_h.h \ @@ -60,7 +60,7 @@ install-data-hook: @(cd $(vppapitestpluginsdir) && $(RM) $(vppapitestplugins_LTLIBRARIES)) apidir = $(prefix)/snat -api_DATA = snat/snat.api +api_DATA = snat/snat.api.json # # Java code generation diff --git a/vlib-api/Makefile.am b/vlib-api/Makefile.am index 087d56ee..d9f4a27b 100644 --- a/vlib-api/Makefile.am +++ b/vlib-api/Makefile.am @@ -67,9 +67,12 @@ nobase_include_HEADERS += \ vlibsocket/vl_socket_msg_enum.h \ vlibsocket/sockclnt.api.h -BUILT_SOURCES = vlibsocket/sockclnt.api.h vlibmemory/memclnt.api.h +BUILT_SOURCES = \ + vlibsocket/sockclnt.api.h \ + vlibmemory/memclnt.api.h \ + vlibmemory/memclnt.api.json -SUFFIXES = .api.h .api +SUFFIXES = .api.h .api .api.json # The actual %.api.h rule is in .../build-data/packages/suffix-rules.mk # and requires a symbolic link at the top of the vnet source tree @@ -78,4 +81,4 @@ include $(top_srcdir)/suffix-rules.mk # install the API definition, so we can produce java bindings, etc. apidir = $(prefix)/vlibmemory -api_DATA = vlibmemory/memclnt.api +api_DATA = vlibmemory/memclnt.api.json diff --git a/vnet/Makefile.am b/vnet/Makefile.am index a9481d11..0ba07bac 100644 --- a/vnet/Makefile.am +++ b/vnet/Makefile.am @@ -15,7 +15,7 @@ AUTOMAKE_OPTIONS = foreign subdir-objects AM_CFLAGS = -Wall -Werror @DPDK@ @DPDK_CRYPTO@ @IPSEC@ @IPV6SR@ -BUILT_SOURCES = vnet/interface.api.h +BUILT_SOURCES = vnet/interface.api.h vnet/interface.api.json libvnet_la_SOURCES = libvnetplugin_la_SOURCES = @@ -884,12 +884,12 @@ pcap2pg_LDADD = libvnet.la -l:libvppinfra.a -lpthread -lm -ldl noinst_PROGRAMS += pcap2pg # Set the suffix list -SUFFIXES = .api.h .api +SUFFIXES = .api.h .api .api.json # install the API definition, so we can produce java bindings, etc. -apidir = $(prefix)/vpp-api -api_DATA = vnet/interface.api +apidir = $(prefix)/vnet +api_DATA = vnet/interface.api.json # The actual %.api.h rule is in .../build-data/packages/suffix-rules.mk # and requires a symbolic link at the top of the vnet source tree diff --git a/vpp-api/Makefile.am b/vpp-api/Makefile.am index 310bd232..1812b637 100644 --- a/vpp-api/Makefile.am +++ b/vpp-api/Makefile.am @@ -1,17 +1,2 @@ AUTOMAKE_OPTIONS = foreign SUBDIRS = python java - -api_json_dir = $(abs_builddir)/vpp-api -api_srcs:=$(shell find $(prefix)/../ -name '*.api') -api_json:=$(patsubst %.api,$(api_json_dir)/%.api.json,$(notdir $(api_srcs))) - -define define_compile_rules -$(api_json_dir)/%.api.json: $(1)%.api - @echo " + Generating '$$<'" - @mkdir -p $$(@D) - $(CC) $$(CPPFLAGS) -E -P -C -x c $$< | vppapigen --input - --json $$@ -endef - -$(foreach directory,$(dir $(api_srcs)),$(eval $(call define_compile_rules,$(directory)))) - -BUILT_SOURCES = $(api_json) diff --git a/vpp-api/java/Makefile.am b/vpp-api/java/Makefile.am index af4c3f31..f2f5fbe5 100644 --- a/vpp-api/java/Makefile.am +++ b/vpp-api/java/Makefile.am @@ -83,14 +83,14 @@ packagedir_jvpp_core = io/fd/vpp/jvpp/core BUILT_SOURCES += jvpp-core/io_fd_vpp_jvpp_core_JVppCoreImpl.h -jvpp-core/io_fd_vpp_jvpp_core_JVppCoreImpl.h: jvpp-registry/io_fd_vpp_jvpp_VppJNIConnection.h $(abs_builddir)/../vpp-api/vpe.api.json +jvpp-core/io_fd_vpp_jvpp_core_JVppCoreImpl.h: jvpp-registry/io_fd_vpp_jvpp_VppJNIConnection.h $(prefix)/../vpp/vpp-api/vpe.api.json 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 $(abs_builddir)/../vpp-api/vpe.api.json \ - $(abs_builddir)/../vpp-api/interface.api.json \ + -i $(prefix)/../vpp/vpp-api/vpe.api.json \ + $(prefix)/../vnet/vnet/interface.api.json \ && cp -rf types dto future callfacade callback notification *.java -t $(packagedir_jvpp_core) \ && rm -rf types dto future callfacade callback notification *.java diff --git a/vpp-api/python/Makefile.am b/vpp-api/python/Makefile.am index d2c3fb5d..2a578464 100644 --- a/vpp-api/python/Makefile.am +++ b/vpp-api/python/Makefile.am @@ -32,23 +32,8 @@ libpneum_la_LIBADD = -lvlibmemoryclient -lvlibapi -lsvm -lvppinfra -lpthread \ libpneum_la_LDFLAGS = -module libpneum_la_CPPFLAGS = -# -# Core VPP API -# -$(srcdir)/vpp_papi/vpe.py: $(prefix)/../vpp/vpp-api/vpe.api - $(info Creating Python binding for $@) - $(CC) $(CPPFLAGS) -E -P -C -x c $< \ - | vppapigen --input - --python - \ - | pyvppapigen.py --input - > $(srcdir)/vpp_papi/$(notdir $@) - -$(srcdir)/vpp_papi/memclnt.py: $(prefix)/../vlib-api/vlibmemory/memclnt.api - $(info Creating Python binding for $@) - $(CC) $(CPPFLAGS) -E -P -C -x c $< \ - | vppapigen --input - --python - \ - | pyvppapigen.py --input - > $(srcdir)/vpp_papi/$(notdir $@) - # TODO: Support both Python 2 and 3. -install-exec-local: $(srcdir)/vpp_papi/vpe.py $(srcdir)/vpp_papi/memclnt.py +install-exec-local: cd $(srcdir); \ mkdir -p $(prefix)/lib/python2.7/site-packages; \ PYTHONUSERBASE=$(prefix) \ diff --git a/vpp/Makefile.am b/vpp/Makefile.am index 1c40ed3d..9ae06055 100644 --- a/vpp/Makefile.am +++ b/vpp/Makefile.am @@ -46,9 +46,9 @@ nobase_include_HEADERS = \ # install the API definition, so we can produce java bindings, etc. apidir = $(prefix)/vpp-api -api_DATA = vpp-api/vpe.api +api_DATA = vpp-api/vpe.api.json -BUILT_SOURCES += vpp-api/vpe.api.h app/version.h +BUILT_SOURCES += vpp-api/vpe.api.h app/version.h vpp-api/vpe.api.json app/version.o: app/version.h @@ -122,7 +122,7 @@ if WITH_IPV6SR endif # Set the suffix list -SUFFIXES = .api.h .api +SUFFIXES = .api.h .api .api.json # The actual %.api.h rule is in .../build-data/packages/suffix-rules.mk # and requires a symbolic link at the top of the vpp source tree diff --git a/vppapigen/Makefile.am b/vppapigen/Makefile.am index 066e1c30..16a48736 100644 --- a/vppapigen/Makefile.am +++ b/vppapigen/Makefile.am @@ -14,7 +14,7 @@ AUTOMAKE_OPTIONS = foreign bin_PROGRAMS = vppapigen -bin_SCRIPTS = pyvppapigen.py +bin_SCRIPTS = BUILT_SOURCES = gram.h diff --git a/vppapigen/pyvppapigen.py b/vppapigen/pyvppapigen.py deleted file mode 100755 index ea669517..00000000 --- a/vppapigen/pyvppapigen.py +++ /dev/null @@ -1,291 +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 __future__ import print_function -import argparse, sys, os, importlib, pprint - -parser = argparse.ArgumentParser(description='VPP Python API generator') -parser.add_argument('-i', '--input', action="store", dest="inputfile", type=argparse.FileType('r')) -parser.add_argument('-c', '--cfile', action="store") -args = parser.parse_args() - -# -# Read API definitions file into vppapidefs -# -exec(args.inputfile.read()) - -# https://docs.python.org/3/library/struct.html -format_struct = {'u8': 'B', - 'u16' : 'H', - 'u32' : 'I', - 'i32' : 'i', - 'u64' : 'Q', - 'f64' : 'd', - 'vl_api_fib_path_t' : 'IIBBBBBBBBBBBBBBBBBBBBB', - 'vl_api_ip4_fib_counter_t' : 'IBQQ', - 'vl_api_ip6_fib_counter_t' : 'QQBQQ', - 'vl_api_lisp_adjacency_t' : 'B' * 35 - }; -# -# NB: If new types are introduced in vpe.api, these must be updated. -# -type_size = {'u8': 1, - 'u16' : 2, - 'u32' : 4, - 'i32' : 4, - 'u64' : 8, - 'f64' : 8, - 'vl_api_fib_path_t' : 29, - 'vl_api_ip4_fib_counter_t' : 21, - 'vl_api_ip6_fib_counter_t' : 33, - 'vl_api_lisp_adjacency_t' : 35 -}; - -def eprint(*args, **kwargs): - print(*args, file=sys.stderr, **kwargs) - -def get_args(t): - argslist = [] - for i in t: - if i[1][0] == '_': - argslist.append(i[1][1:]) - else: - argslist.append(i[1]) - - return argslist - -def get_pack(f): - zeroarray = False - bytecount = 0 - pack = '' - elements = 1 - if len(f) is 3 or len(f) is 4: - size = type_size[f[0]] - bytecount += size * int(f[2]) - # Check if we have a zero length array - if f[2] == '0': - # If len 3 zero array - elements = 0; - pack += format_struct[f[0]] - bytecount = size - elif size == 1: - n = f[2] * size - pack += str(n) + 's' - else: - pack += format_struct[f[0]] * int(f[2]) - elements = int(f[2]) - else: - bytecount += type_size[f[0]] - pack += format_struct[f[0]] - return (pack, elements, bytecount) - - -''' -def get_reply_func(f): - if f['name']+'_reply' in func_name: - return func_name[f['name']+'_reply'] - if f['name'].find('_dump') > 0: - r = f['name'].replace('_dump','_details') - if r in func_name: - return func_name[r] - return None -''' - -def footer_print(): - print(''' -def msg_id_base_set(b): - global base - base = b - -import os -name = os.path.splitext(os.path.basename(__file__))[0] - ''') - print(u"plugin_register(name, api_func_table, api_name_to_id,", vl_api_version, ", msg_id_base_set)") - -def api_table_print(name, i): - msg_id_in = 'VL_API_' + name.upper() - fstr = name + '_decode' - print('api_func_table.append(' + fstr + ')') - print('api_name_to_id["' + msg_id_in + '"] =', i) - print('') - - -def encode_print(name, id, t): - args = get_args(t) - - if name.find('_dump') > 0: - multipart = True - else: - multipart = False - - if len(args) < 4: - print(u"def", name + "(async = False):") - else: - print(u"def", name + "(" + ', '.join(args[3:]) + ", async = False):") - print(u" global base") - print(u" context = get_context(base + " + id + ")") - - print(''' - results_prepare(context) - waiting_for_reply_set() - ''') - if multipart == True: - print(u" results_more_set(context)") - - t = list(t) - - # only the last field can be a variable-length-array - # it can either be 0, or a string - # first, deal with all the other fields - pack = '>' + ''.join([get_pack(f)[0] for f in t[:-1]]) - - # named variable-length-array - if len(t[-1]) == 4 and t[-1][2] == '0' and t[-1][3] == t[-2][1]: - print(u" vpp_api.write(pack('" + pack + "', base + " - + id + ", 0, context, " + ', '.join(args[3:-2] + ["len(" + args[-1] + ")"]) - + ") + " + args[-1] + ")") - - # unnamed variable-length-array - elif len(t[-1]) >= 3 and t[-1][2] == '0': - print(u" vpp_api.write(pack('" + pack + "', base + " + - id + ", 0, context, " + ', '.join(args[3:-1]) + ") + " - + args[-1] + ")") - - - # not a variable-length-array - else: - pack += get_pack(t[-1])[0] - print(u" vpp_api.write(pack('" + pack + "', base + " + id + - ", 0, context, " + ', '.join(args[3:]) + "))") - - if multipart == True: - print( - u" vpp_api.write(pack('>HII', VL_API_CONTROL_PING, 0, context))") - - print(''' - if not async: - results_event_wait(context, 5) - return results_get(context) - return context - ''') - -def get_normal_pack(t, i, pack, offset): - while t: - f = t.pop(0) - i += 1 - if len(f) >= 3: - return t, i, pack, offset, f - p, elements, size = get_pack(f) - pack += p - offset += size - return t, i, pack, offset, None - -def decode_print(name, t): - # - # Generate code for each element - # - print(u'def ' + name + u'_decode(msg):') - total = 0 - args = get_args(t) - print(u" n = namedtuple('" + name + "', '" + ', '.join(args) + "')") - print(u" res = []") - - pack = '>' - start = 0 - end = 0 - offset = 0 - t = list(t) - i = 0 - while t: - t, i, pack, offset, array = get_normal_pack(t, i, pack, offset) - if array: - p, elements, size = get_pack(array) - - # Byte string - if elements > 0 and type_size[array[0]] == 1: - pack += p - offset += size * elements - continue - - # Dump current pack string - if pack != '>': - print(u" tr = unpack_from('" + pack + "', msg[" + str(start) + ":])") - print(u" res.extend(list(tr))") - start += offset - pack = '>' - - if elements == 0: - # This has to be the last element - if len(array) == 3: - print(u" res.append(msg[" + str(offset) + ":])") - if len(t) > 0: - eprint('WARNING: Variable length array must be last element in message', name, array) - - continue - if size == 1 or len(p) == 1: - # Do it as a bytestring. - if p == 'B': - p = 's' - # XXX: Assume that length parameter is the previous field. Add validation. - print(u" c = res[" + str(i - 2) + "]") - print(u" tr = unpack_from('>' + str(c) + '" + p + "', msg[" + str(start) + ":])") - print(u" res.append(tr)") - continue - print(u" tr2 = []") - print(u" offset = " + str(total)) - print(u" for j in range(res[" + str(i - 2) + "]):") - print(u" tr2.append(unpack_from('>" + p + "', msg[" + str(start) + ":], offset))") - print(u" offset += " + str(size)) - print(u" res.append(tr2)") - continue - - # Missing something!! - print(u" tr = unpack_from('>" + p + "', msg[" + str(start) + ":])") - start += size - - print(u" res.append(tr)") - - if pack != '>': - print(u" tr = unpack_from('" + pack + "', msg[" + str(start) + ":])") - print(u" res.extend(list(tr))") - print(u" return n._make(res)") - print('') - -# -# Generate the main Python file -# -def main(): - print(''' -# -# AUTO-GENERATED FILE. PLEASE DO NOT EDIT. -# -from vpp_api_base import * -from struct import * -from collections import namedtuple -import vpp_api -api_func_table = [] -api_name_to_id = {} - ''') - - for i, a in enumerate(messages): - name = a[0] - encode_print(name, str(i), a[1:]) - decode_print(name, a[1:]) - api_table_print(name, i) - footer_print() - -if __name__ == "__main__": - main() -- cgit 1.2.3-korg From 7cd468a3d7dee7d6c92f69a0bb7061ae208ec727 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Mon, 19 Dec 2016 23:05:39 +0100 Subject: Reorganize source tree to use single autotools instance Change-Id: I7b51f88292e057c6443b12224486f2d0c9f8ae23 Signed-off-by: Damjan Marion --- Makefile | 4 +- build-data/packages/cavium-dpdk.mk | 55 - build-data/packages/g2.mk | 6 +- build-data/packages/gmod.mk | 6 +- build-data/packages/perftool.mk | 5 +- build-data/packages/plugins.mk | 25 +- build-data/packages/src.mk | 0 build-data/packages/svm.mk | 5 - build-data/packages/vlib-api-cavium-dpdk.mk | 6 - build-data/packages/vlib-api.mk | 4 - build-data/packages/vlib-cavium-dpdk.mk | 7 - build-data/packages/vlib.mk | 16 - build-data/packages/vnet-cavium-dpdk.mk | 29 - build-data/packages/vpp-api-test-cavium-dpdk.mk | 32 - build-data/packages/vpp-api-test.mk | 39 - build-data/packages/vpp-api.mk | 16 +- build-data/packages/vpp-cavium-dpdk.mk | 30 - build-data/packages/vpp.mk | 29 +- build-data/packages/vppinfra.mk | 5 - build-data/platforms.mk | 6 +- build-data/platforms/vpp.mk | 4 +- build-data/platforms/vpp_lite.mk | 3 +- build-data/suffix-rules.mk | 27 - build-root/bootstrap.sh | 2 +- build-root/packages/src.mk | 4 + build-root/packages/tools.mk | 3 + build-root/packages/vppapigen.mk | 5 - build-root/rpm/vpp.spec | 24 +- build-root/scripts/find-plugins-contents | 6 +- build-root/scripts/find-python-api-contents | 2 +- g2/Makefile.am | 34 - g2/clib.c | 154 - g2/configure.ac | 12 - g2/cpel.c | 470 - g2/cpel.h | 83 - g2/events.c | 475 - g2/g2.h | 195 - g2/g2version.c | 19 - g2/main.c | 196 - g2/menu1.c | 565 - g2/mkversion.c | 77 - g2/pointsel.c | 854 - g2/props.c | 279 - g2/props.h | 21 - g2/view1.c | 3077 ---- gmod/gmod/mod_vpp.c | 2 +- perftool/Makefile.am | 44 - perftool/c2cpel.c | 248 - perftool/configure.ac | 12 - perftool/cpel.h | 83 - perftool/cpel_util.c | 456 - perftool/cpel_util.h | 68 - perftool/cpelatency.c | 927 - perftool/cpeldump.c | 638 - perftool/cpelinreg.c | 892 - perftool/cpelstate.c | 822 - perftool/delsvec.c | 315 - perftool/linreg.c | 78 - perftool/new.cpel | Bin 1672 -> 0 bytes perftool/new.elog | Bin 4525 -> 0 bytes perftool/props.c | 280 - plugins/Makefile.am | 12 - plugins/configure.ac | 3 - plugins/flowperpkt-plugin/Makefile.am | 64 - plugins/flowperpkt-plugin/configure.ac | 9 - .../flowperpkt-plugin/flowperpkt/flowperpkt.api | 42 - plugins/flowperpkt-plugin/flowperpkt/flowperpkt.c | 671 - plugins/flowperpkt-plugin/flowperpkt/flowperpkt.h | 90 - .../flowperpkt/flowperpkt_all_api_h.h | 18 - .../flowperpkt/flowperpkt_msg_enum.h | 31 - .../flowperpkt-plugin/flowperpkt/flowperpkt_test.c | 234 - plugins/flowperpkt-plugin/flowperpkt/l2_node.c | 561 - plugins/flowperpkt-plugin/flowperpkt/node.c | 574 - plugins/flowperpkt-plugin/flowperpkt_plugin_doc.md | 13 - plugins/ila-plugin/Makefile.am | 29 - plugins/ila-plugin/configure.ac | 9 - plugins/ila-plugin/ila/ila.c | 1070 -- plugins/ila-plugin/ila/ila.h | 116 - plugins/sixrd-plugin/Makefile.am | 38 - plugins/sixrd-plugin/configure.ac | 9 - plugins/sixrd-plugin/sixrd/ip4_sixrd.c | 127 - plugins/sixrd-plugin/sixrd/ip6_sixrd.c | 129 - plugins/sixrd-plugin/sixrd/sixrd.c | 369 - plugins/sixrd-plugin/sixrd/sixrd.h | 141 - plugins/sixrd-plugin/sixrd/sixrd_dpo.c | 132 - plugins/sixrd-plugin/sixrd/sixrd_dpo.h | 61 - src/Makefile.am | 101 + src/configure.ac | 195 + src/examples/vlib/dir.dox | 22 + src/examples/vlib/main_stub.c | 418 + src/examples/vlib/mc_test.c | 384 + src/examples/vlib/plex_test.c | 527 + src/g2.am | 32 + src/perftool.am | 41 + src/plugins/Makefile.am | 60 + src/plugins/flowperpkt.am | 38 + src/plugins/flowperpkt/flowperpkt.api | 42 + src/plugins/flowperpkt/flowperpkt.c | 671 + src/plugins/flowperpkt/flowperpkt.h | 90 + src/plugins/flowperpkt/flowperpkt_all_api_h.h | 18 + src/plugins/flowperpkt/flowperpkt_msg_enum.h | 31 + src/plugins/flowperpkt/flowperpkt_plugin_doc.md | 13 + src/plugins/flowperpkt/flowperpkt_test.c | 234 + src/plugins/flowperpkt/l2_node.c | 561 + src/plugins/flowperpkt/node.c | 574 + src/plugins/ila.am | 20 + src/plugins/ila/ila.c | 1070 ++ src/plugins/ila/ila.h | 116 + src/plugins/sixrd.am | 26 + src/plugins/sixrd/ip4_sixrd.c | 127 + src/plugins/sixrd/ip6_sixrd.c | 129 + src/plugins/sixrd/sixrd.c | 369 + src/plugins/sixrd/sixrd.h | 141 + src/plugins/sixrd/sixrd_dpo.c | 132 + src/plugins/sixrd/sixrd_dpo.h | 61 + src/scripts/vnet/arp4 | 21 + src/scripts/vnet/arp4-mpls | 24 + src/scripts/vnet/arp6 | 21 + src/scripts/vnet/bvi | 76 + src/scripts/vnet/dhcp/dhcpd.conf | 8 + src/scripts/vnet/dhcp/left-ping-target.sh | 4 + src/scripts/vnet/dhcp/leftpeer.conf | 17 + src/scripts/vnet/icmp | 16 + src/scripts/vnet/icmp6 | 16 + src/scripts/vnet/ige | 19 + src/scripts/vnet/ip6 | 15 + src/scripts/vnet/ip6-hbh | 84 + src/scripts/vnet/ixge | 15 + src/scripts/vnet/l2efpfilter | 83 + src/scripts/vnet/l2efpfilter_perf | 58 + src/scripts/vnet/l2fib | 46 + src/scripts/vnet/l2fib_perf | 29 + src/scripts/vnet/l2fib_xc | 31 + src/scripts/vnet/l2flood | 42 + src/scripts/vnet/l2tp | 134 + src/scripts/vnet/leftpeer/leftpeer-classify | 8 + src/scripts/vnet/leftpeer/leftpeer-classify6 | 5 + src/scripts/vnet/leftpeer/leftpeer-classifyl2 | 8 + src/scripts/vnet/leftpeer/leftpeer-dhcp | 23 + src/scripts/vnet/leftpeer/leftpeer-ioam.conf | 15 + src/scripts/vnet/leftpeer/leftpeer-l3vxlan.conf | 12 + src/scripts/vnet/leftpeer/leftpeer-lisp.conf | 18 + src/scripts/vnet/leftpeer/leftpeer-mpls.conf | 17 + src/scripts/vnet/leftpeer/leftpeer-sr.conf | 24 + src/scripts/vnet/leftpeer/leftpeer-vxlan.conf | 17 + src/scripts/vnet/leftpeer/leftpeer.script | 9 + src/scripts/vnet/lfib/ip4-to-mpls | 26 + src/scripts/vnet/lfib/mpls-pop-to-mpls | 28 + src/scripts/vnet/lfib/mpls-to-ip4 | 27 + src/scripts/vnet/lfib/mpls-to-mpls | 26 + src/scripts/vnet/mpls-o-ethernet/leftpeer.conf | 17 + src/scripts/vnet/mpls-o-ethernet/pg | 10 + src/scripts/vnet/mpls-o-ethernet/rightpeer.conf | 15 + src/scripts/vnet/mpls-o-ethernet/single.conf | 17 + src/scripts/vnet/mpls-o-gre/dhcpd.conf | 116 + src/scripts/vnet/mpls-o-gre/leftpeer.conf | 14 + src/scripts/vnet/mpls-o-gre/rightpeer.conf | 14 + src/scripts/vnet/mpls-tunnel | 87 + src/scripts/vnet/pcap | 18 + src/scripts/vnet/probe4 | 11 + src/scripts/vnet/probe6 | 7 + src/scripts/vnet/rewrite | 62 + src/scripts/vnet/rightpeer/rightpeer-ioam.conf | 14 + src/scripts/vnet/rightpeer/rightpeer-l3vxlan.conf | 9 + src/scripts/vnet/rightpeer/rightpeer-lisp.conf | 16 + src/scripts/vnet/rightpeer/rightpeer-mpls-l2.conf | 24 + src/scripts/vnet/rightpeer/rightpeer-mpls.conf | 17 + src/scripts/vnet/rightpeer/rightpeer-sr.conf | 28 + src/scripts/vnet/rightpeer/rightpeer-vxlan.conf | 16 + src/scripts/vnet/rightpeer/rightpeer.script | 9 + src/scripts/vnet/rpf | 18 + src/scripts/vnet/rtt-test | 31 + src/scripts/vnet/snat | 34 + src/scripts/vnet/snat_static | 44 + src/scripts/vnet/snat_static_with_port | 44 + src/scripts/vnet/source_and_port_range_check | 63 + src/scripts/vnet/speed | 14 + src/scripts/vnet/sr/left-linux-ping.sh | 3 + src/scripts/vnet/sr/leftpeer.conf | 27 + src/scripts/vnet/sr/right-linux-ping.sh | 4 + src/scripts/vnet/sr/rightpeer.conf | 22 + src/scripts/vnet/sr/srlocal.sh | 4 + src/scripts/vnet/srp | 27 + src/scripts/vnet/tcp | 16 + src/scripts/vnet/tcp-test | 6 + src/scripts/vnet/tf-ucs-1 | 16 + src/scripts/vnet/urpf | 86 + src/scripts/vnet/virl/ip6sr.virl | 874 + src/scripts/vnet/virl/ip6sr_notes.txt | 38 + src/scripts/vnet/virl/mplsogre.virl | 319 + src/scripts/vnet/virl/simple.virl | 389 + src/scripts/vnet/vlan | 23 + src/scripts/vppctl | 121 + src/suffix-rules.mk | 27 + src/svm.am | 31 + src/svm/dir.dox | 21 + src/svm/persist.c | 258 + src/svm/ssvm.c | 178 + src/svm/ssvm.h | 155 + src/svm/svm.c | 1237 ++ src/svm/svm.h | 207 + src/svm/svm_test.c | 79 + src/svm/svmdb.c | 671 + src/svm/svmdb.h | 135 + src/svm/svmdbtool.c | 537 + src/svm/svmtool.c | 528 + src/tests/vnet/README | 10 + src/tests/vnet/lisp-cp/test_cp_serdes.c | 639 + src/tests/vnet/lisp-cp/test_lisp_types.c | 565 + src/tests/vnet/lisp-gpe/test.c | 18 + src/tools/elftool/dir.dox | 19 + src/tools/elftool/elftool.c | 464 + src/tools/g2/clib.c | 154 + src/tools/g2/configure.ac | 12 + src/tools/g2/cpel.c | 470 + src/tools/g2/cpel.h | 83 + src/tools/g2/events.c | 475 + src/tools/g2/g2.h | 195 + src/tools/g2/g2version.c | 19 + src/tools/g2/main.c | 196 + src/tools/g2/menu1.c | 565 + src/tools/g2/mkversion.c | 77 + src/tools/g2/pointsel.c | 854 + src/tools/g2/props.c | 279 + src/tools/g2/props.h | 21 + src/tools/g2/view1.c | 3077 ++++ src/tools/perftool/c2cpel.c | 248 + src/tools/perftool/configure.ac | 12 + src/tools/perftool/cpel.h | 83 + src/tools/perftool/cpel_util.c | 456 + src/tools/perftool/cpel_util.h | 68 + src/tools/perftool/cpelatency.c | 927 + src/tools/perftool/cpeldump.c | 638 + src/tools/perftool/cpelinreg.c | 892 + src/tools/perftool/cpelstate.c | 822 + src/tools/perftool/delsvec.c | 315 + src/tools/perftool/linreg.c | 78 + src/tools/perftool/new.cpel | Bin 0 -> 1672 bytes src/tools/perftool/new.elog | Bin 0 -> 4525 bytes src/tools/perftool/props.c | 280 + src/tools/vppapigen/configure.ac | 14 + src/tools/vppapigen/gram.y | 90 + src/tools/vppapigen/lex.c | 1067 ++ src/tools/vppapigen/lex.h | 50 + src/tools/vppapigen/node.c | 1527 ++ src/tools/vppapigen/node.h | 94 + src/vat/api_format.c | 17829 +++++++++++++++++++ src/vat/json_format.c | 304 + src/vat/json_format.h | 254 + src/vat/json_test.c | 75 + src/vat/main.c | 421 + src/vat/plugin.c | 201 + src/vat/plugin.h | 61 + src/vat/plugin_api.c | 216 + src/vat/restart.c | 246 + src/vat/vat.h | 257 + src/vlib-api.am | 73 + src/vlib.am | 103 + src/vlib/buffer.c | 1987 +++ src/vlib/buffer.h | 417 + src/vlib/buffer_funcs.h | 755 + src/vlib/buffer_node.h | 337 + src/vlib/cli.c | 1173 ++ src/vlib/cli.h | 192 + src/vlib/cli_funcs.h | 58 + src/vlib/counter.c | 151 + src/vlib/counter.h | 379 + src/vlib/defs.h | 82 + src/vlib/dir.dox | 23 + src/vlib/elog_samples.c | 122 + src/vlib/error.c | 338 + src/vlib/error.h | 101 + src/vlib/error_funcs.h | 88 + src/vlib/format.c | 196 + src/vlib/format_funcs.h | 75 + src/vlib/global_funcs.h | 45 + src/vlib/i2c.c | 231 + src/vlib/i2c.h | 67 + src/vlib/init.c | 168 + src/vlib/init.h | 238 + src/vlib/lex.c | 271 + src/vlib/lex.h | 145 + src/vlib/main.c | 1703 ++ src/vlib/main.h | 333 + src/vlib/mc.c | 2609 +++ src/vlib/mc.h | 687 + src/vlib/node.c | 631 + src/vlib/node.h | 725 + src/vlib/node_cli.c | 466 + src/vlib/node_format.c | 187 + src/vlib/node_funcs.h | 1130 ++ src/vlib/parse.c | 1007 ++ src/vlib/parse.h | 221 + src/vlib/parse_builtin.c | 150 + src/vlib/pci/linux_pci.c | 642 + src/vlib/pci/pci.c | 264 + src/vlib/pci/pci.h | 251 + src/vlib/pci/pci_config.h | 731 + src/vlib/physmem.h | 108 + src/vlib/threads.c | 1492 ++ src/vlib/threads.h | 470 + src/vlib/threads_cli.c | 579 + src/vlib/trace.c | 545 + src/vlib/trace.h | 100 + src/vlib/trace_funcs.h | 185 + src/vlib/unix/cj.c | 271 + src/vlib/unix/cj.h | 79 + src/vlib/unix/cli.c | 2989 ++++ src/vlib/unix/dir.dox | 28 + src/vlib/unix/input.c | 265 + src/vlib/unix/main.c | 557 + src/vlib/unix/mc_socket.c | 1049 ++ src/vlib/unix/mc_socket.h | 137 + src/vlib/unix/physmem.c | 470 + src/vlib/unix/physmem.h | 65 + src/vlib/unix/plugin.c | 260 + src/vlib/unix/plugin.h | 98 + src/vlib/unix/unix.h | 232 + src/vlib/unix/util.c | 231 + src/vlib/vlib.h | 86 + src/vlib/vlib_process_doc.h | 147 + src/vlibapi/api.h | 281 + src/vlibapi/api_helper_macros.h | 243 + src/vlibapi/api_shared.c | 1375 ++ src/vlibapi/node_serialize.c | 399 + src/vlibmemory/api.h | 163 + src/vlibmemory/memclnt.api | 91 + src/vlibmemory/memory_client.c | 283 + src/vlibmemory/memory_shared.c | 852 + src/vlibmemory/memory_vlib.c | 1346 ++ src/vlibmemory/unix_shared_memory_queue.c | 324 + src/vlibmemory/unix_shared_memory_queue.h | 69 + src/vlibmemory/vl_memory_api_h.h | 32 + src/vlibmemory/vl_memory_msg_enum.h | 42 + src/vlibsocket/api.h | 87 + src/vlibsocket/sock_test.c | 155 + src/vlibsocket/sockclnt.api | 50 + src/vlibsocket/sockclnt_vlib.c | 209 + src/vlibsocket/socksvr_vlib.c | 706 + src/vlibsocket/vl_socket_api_h.h | 33 + src/vlibsocket/vl_socket_msg_enum.h | 42 + src/vnet.am | 972 + src/vnet/adj/adj.c | 454 + src/vnet/adj/adj.h | 122 + src/vnet/adj/adj_glean.c | 285 + src/vnet/adj/adj_glean.h | 61 + src/vnet/adj/adj_internal.h | 104 + src/vnet/adj/adj_l2.c | 194 + src/vnet/adj/adj_l2.h | 24 + src/vnet/adj/adj_midchain.c | 559 + src/vnet/adj/adj_midchain.h | 102 + src/vnet/adj/adj_nbr.c | 1087 ++ src/vnet/adj/adj_nbr.h | 176 + src/vnet/adj/adj_rewrite.c | 53 + src/vnet/adj/adj_rewrite.h | 49 + src/vnet/adj/adj_types.h | 53 + src/vnet/api_errno.h | 113 + src/vnet/bfd/bfd.api | 205 + src/vnet/bfd/bfd_api.c | 262 + src/vnet/bfd/bfd_api.h | 46 + src/vnet/bfd/bfd_debug.h | 79 + src/vnet/bfd/bfd_doc.md | 1 + src/vnet/bfd/bfd_main.c | 969 + src/vnet/bfd/bfd_main.h | 220 + src/vnet/bfd/bfd_protocol.c | 74 + src/vnet/bfd/bfd_protocol.h | 154 + src/vnet/bfd/bfd_udp.c | 639 + src/vnet/bfd/bfd_udp.h | 56 + src/vnet/bfd/dir.dox | 18 + src/vnet/buffer.h | 381 + src/vnet/cdp/cdp.pg | 7 + src/vnet/cdp/cdp_input.c | 506 + src/vnet/cdp/cdp_node.c | 208 + src/vnet/cdp/cdp_node.h | 147 + src/vnet/cdp/cdp_periodic.c | 512 + src/vnet/cdp/cdp_protocol.h | 186 + src/vnet/classify/README | 180 + src/vnet/classify/flow_classify.c | 212 + src/vnet/classify/flow_classify.h | 51 + src/vnet/classify/flow_classify_node.c | 338 + src/vnet/classify/input_acl.c | 283 + src/vnet/classify/input_acl.h | 54 + src/vnet/classify/ip_classify.c | 365 + src/vnet/classify/policer_classify.c | 227 + src/vnet/classify/policer_classify.h | 55 + src/vnet/classify/vnet_classify.c | 2436 +++ src/vnet/classify/vnet_classify.h | 523 + src/vnet/config.c | 361 + src/vnet/config.h | 176 + src/vnet/cop/cop.c | 387 + src/vnet/cop/cop.h | 89 + src/vnet/cop/ip4_whitelist.c | 356 + src/vnet/cop/ip6_whitelist.c | 298 + src/vnet/cop/node1.c | 319 + src/vnet/devices/af_packet/af_packet.api | 71 + src/vnet/devices/af_packet/af_packet.c | 366 + src/vnet/devices/af_packet/af_packet.h | 69 + src/vnet/devices/af_packet/af_packet_api.c | 143 + src/vnet/devices/af_packet/cli.c | 144 + src/vnet/devices/af_packet/device.c | 250 + src/vnet/devices/af_packet/node.c | 288 + src/vnet/devices/devices.c | 91 + src/vnet/devices/devices.h | 53 + src/vnet/devices/dpdk/cli.c | 1296 ++ src/vnet/devices/dpdk/device.c | 840 + src/vnet/devices/dpdk/dpdk.h | 534 + src/vnet/devices/dpdk/dpdk_priv.h | 132 + src/vnet/devices/dpdk/format.c | 763 + src/vnet/devices/dpdk/hqos.c | 775 + src/vnet/devices/dpdk/init.c | 1803 ++ src/vnet/devices/dpdk/ipsec/cli.c | 141 + src/vnet/devices/dpdk/ipsec/crypto_node.c | 210 + src/vnet/devices/dpdk/ipsec/dir.dox | 18 + .../devices/dpdk/ipsec/dpdk_crypto_ipsec_doc.md | 73 + src/vnet/devices/dpdk/ipsec/esp.h | 295 + src/vnet/devices/dpdk/ipsec/esp_decrypt.c | 583 + src/vnet/devices/dpdk/ipsec/esp_encrypt.c | 598 + src/vnet/devices/dpdk/ipsec/ipsec.c | 313 + src/vnet/devices/dpdk/ipsec/ipsec.h | 227 + src/vnet/devices/dpdk/node.c | 687 + src/vnet/devices/dpdk/qos_doc.md | 404 + src/vnet/devices/netmap/cli.c | 146 + src/vnet/devices/netmap/device.c | 261 + src/vnet/devices/netmap/net_netmap.h | 650 + src/vnet/devices/netmap/netmap.api | 74 + src/vnet/devices/netmap/netmap.c | 316 + src/vnet/devices/netmap/netmap.h | 164 + src/vnet/devices/netmap/netmap_api.c | 137 + src/vnet/devices/netmap/node.c | 300 + src/vnet/devices/nic/ixge.c | 2938 +++ src/vnet/devices/nic/ixge.h | 1293 ++ src/vnet/devices/nic/sfp.c | 117 + src/vnet/devices/nic/sfp.h | 117 + src/vnet/devices/ssvm/node.c | 343 + src/vnet/devices/ssvm/ssvm_eth.c | 491 + src/vnet/devices/ssvm/ssvm_eth.h | 141 + src/vnet/devices/virtio/dir.dox | 27 + src/vnet/devices/virtio/vhost-user.c | 3314 ++++ src/vnet/devices/virtio/vhost-user.h | 350 + src/vnet/devices/virtio/vhost_user.api | 125 + src/vnet/devices/virtio/vhost_user_api.c | 262 + src/vnet/dhcp/client.c | 1031 ++ src/vnet/dhcp/client.h | 118 + src/vnet/dhcp/packet.h | 61 + src/vnet/dhcp/proxy.h | 92 + src/vnet/dhcp/proxy_error.def | 30 + src/vnet/dhcp/proxy_node.c | 1114 ++ src/vnet/dhcpv6/packet.h | 183 + src/vnet/dhcpv6/proxy.h | 95 + src/vnet/dhcpv6/proxy_error.def | 29 + src/vnet/dhcpv6/proxy_node.c | 1191 ++ src/vnet/dpo/classify_dpo.c | 131 + src/vnet/dpo/classify_dpo.h | 56 + src/vnet/dpo/dpo.c | 500 + src/vnet/dpo/dpo.h | 381 + src/vnet/dpo/drop_dpo.c | 106 + src/vnet/dpo/drop_dpo.h | 31 + src/vnet/dpo/ip_null_dpo.c | 408 + src/vnet/dpo/ip_null_dpo.h | 56 + src/vnet/dpo/load_balance.c | 993 ++ src/vnet/dpo/load_balance.h | 211 + src/vnet/dpo/load_balance_map.c | 575 + src/vnet/dpo/load_balance_map.h | 79 + src/vnet/dpo/lookup_dpo.c | 1185 ++ src/vnet/dpo/lookup_dpo.h | 108 + src/vnet/dpo/mpls_label_dpo.c | 570 + src/vnet/dpo/mpls_label_dpo.h | 101 + src/vnet/dpo/punt_dpo.c | 100 + src/vnet/dpo/punt_dpo.h | 30 + src/vnet/dpo/receive_dpo.c | 165 + src/vnet/dpo/receive_dpo.h | 62 + src/vnet/ethernet/arp.c | 2355 +++ src/vnet/ethernet/arp_packet.h | 173 + src/vnet/ethernet/dir.dox | 24 + src/vnet/ethernet/error.def | 46 + src/vnet/ethernet/ethernet.h | 561 + src/vnet/ethernet/format.c | 366 + src/vnet/ethernet/init.c | 128 + src/vnet/ethernet/interface.c | 730 + src/vnet/ethernet/mac_swap.c | 397 + src/vnet/ethernet/node.c | 1368 ++ src/vnet/ethernet/packet.h | 152 + src/vnet/ethernet/pg.c | 183 + src/vnet/ethernet/types.def | 113 + src/vnet/feature/feature.c | 463 + src/vnet/feature/feature.h | 382 + src/vnet/feature/registration.c | 301 + src/vnet/fib/fib.c | 41 + src/vnet/fib/fib.h | 652 + src/vnet/fib/fib_api.h | 54 + src/vnet/fib/fib_attached_export.c | 572 + src/vnet/fib/fib_attached_export.h | 57 + src/vnet/fib/fib_entry.c | 1503 ++ src/vnet/fib/fib_entry.h | 530 + src/vnet/fib/fib_entry_cover.c | 225 + src/vnet/fib/fib_entry_cover.h | 47 + src/vnet/fib/fib_entry_delegate.c | 149 + src/vnet/fib/fib_entry_delegate.h | 124 + src/vnet/fib/fib_entry_src.c | 1456 ++ src/vnet/fib/fib_entry_src.h | 296 + src/vnet/fib/fib_entry_src_adj.c | 207 + src/vnet/fib/fib_entry_src_api.c | 119 + src/vnet/fib/fib_entry_src_default.c | 121 + src/vnet/fib/fib_entry_src_default_route.c | 58 + src/vnet/fib/fib_entry_src_interface.c | 195 + src/vnet/fib/fib_entry_src_lisp.c | 133 + src/vnet/fib/fib_entry_src_mpls.c | 196 + src/vnet/fib/fib_entry_src_rr.c | 293 + src/vnet/fib/fib_entry_src_special.c | 71 + src/vnet/fib/fib_internal.h | 69 + src/vnet/fib/fib_node.c | 277 + src/vnet/fib/fib_node.h | 371 + src/vnet/fib/fib_node_list.c | 390 + src/vnet/fib/fib_node_list.h | 64 + src/vnet/fib/fib_path.c | 2001 +++ src/vnet/fib/fib_path.h | 158 + src/vnet/fib/fib_path_ext.c | 231 + src/vnet/fib/fib_path_ext.h | 69 + src/vnet/fib/fib_path_list.c | 1223 ++ src/vnet/fib/fib_path_list.h | 158 + src/vnet/fib/fib_table.c | 1104 ++ src/vnet/fib/fib_table.h | 732 + src/vnet/fib/fib_test.c | 7112 ++++++++ src/vnet/fib/fib_types.c | 326 + src/vnet/fib/fib_types.h | 340 + src/vnet/fib/fib_urpf_list.c | 260 + src/vnet/fib/fib_urpf_list.h | 146 + src/vnet/fib/fib_walk.c | 1108 ++ src/vnet/fib/fib_walk.h | 58 + src/vnet/fib/ip4_fib.c | 664 + src/vnet/fib/ip4_fib.h | 141 + src/vnet/fib/ip6_fib.c | 784 + src/vnet/fib/ip6_fib.h | 130 + src/vnet/fib/mpls_fib.c | 439 + src/vnet/fib/mpls_fib.h | 106 + src/vnet/flow/flow_report.c | 502 + src/vnet/flow/flow_report.h | 145 + src/vnet/flow/flow_report_classify.c | 529 + src/vnet/flow/flow_report_classify.h | 122 + src/vnet/flow/ipfix_info_elements.h | 429 + src/vnet/flow/ipfix_packet.h | 188 + src/vnet/global_funcs.h | 32 + src/vnet/gre/error.def | 23 + src/vnet/gre/gre.api | 57 + src/vnet/gre/gre.c | 455 + src/vnet/gre/gre.h | 235 + src/vnet/gre/gre_api.c | 204 + src/vnet/gre/interface.c | 606 + src/vnet/gre/node.c | 531 + src/vnet/gre/packet.h | 55 + src/vnet/gre/pg.c | 77 + src/vnet/handoff.c | 594 + src/vnet/handoff.h | 259 + src/vnet/hdlc/error.def | 42 + src/vnet/hdlc/hdlc.c | 249 + src/vnet/hdlc/hdlc.h | 127 + src/vnet/hdlc/node.c | 351 + src/vnet/hdlc/packet.h | 72 + src/vnet/hdlc/pg.c | 105 + src/vnet/interface.api | 339 + src/vnet/interface.c | 1398 ++ src/vnet/interface.h | 658 + src/vnet/interface_api.c | 725 + src/vnet/interface_cli.c | 1165 ++ src/vnet/interface_format.c | 401 + src/vnet/interface_funcs.h | 318 + src/vnet/interface_output.c | 1404 ++ src/vnet/ip/dir.dox | 26 + src/vnet/ip/format.c | 121 + src/vnet/ip/format.h | 114 + src/vnet/ip/icmp4.c | 784 + src/vnet/ip/icmp4.h | 60 + src/vnet/ip/icmp46_packet.h | 398 + src/vnet/ip/icmp6.c | 882 + src/vnet/ip/icmp6.h | 86 + src/vnet/ip/igmp_packet.h | 155 + src/vnet/ip/ip.api | 434 + src/vnet/ip/ip.h | 195 + src/vnet/ip/ip4.h | 322 + src/vnet/ip/ip46_cli.c | 236 + src/vnet/ip/ip4_error.h | 95 + src/vnet/ip/ip4_format.c | 256 + src/vnet/ip/ip4_forward.c | 3345 ++++ src/vnet/ip/ip4_input.c | 507 + src/vnet/ip/ip4_mtrie.c | 568 + src/vnet/ip/ip4_mtrie.h | 188 + src/vnet/ip/ip4_packet.h | 384 + src/vnet/ip/ip4_pg.c | 387 + src/vnet/ip/ip4_source_and_port_range_check.c | 1415 ++ src/vnet/ip/ip4_source_check.c | 573 + src/vnet/ip/ip4_test.c | 340 + src/vnet/ip/ip6.h | 476 + src/vnet/ip/ip6_error.h | 92 + src/vnet/ip/ip6_format.c | 383 + src/vnet/ip/ip6_forward.c | 3402 ++++ src/vnet/ip/ip6_hop_by_hop.c | 1194 ++ src/vnet/ip/ip6_hop_by_hop.h | 217 + src/vnet/ip/ip6_hop_by_hop_packet.h | 66 + src/vnet/ip/ip6_input.c | 353 + src/vnet/ip/ip6_neighbor.c | 4088 +++++ src/vnet/ip/ip6_neighbor.h | 52 + src/vnet/ip/ip6_packet.h | 499 + src/vnet/ip/ip6_pg.c | 231 + src/vnet/ip/ip_api.c | 1196 ++ src/vnet/ip/ip_checksum.c | 228 + src/vnet/ip/ip_frag.c | 581 + src/vnet/ip/ip_frag.h | 96 + src/vnet/ip/ip_init.c | 152 + src/vnet/ip/ip_input_acl.c | 450 + src/vnet/ip/ip_packet.h | 180 + src/vnet/ip/ip_source_and_port_range_check.h | 148 + src/vnet/ip/lookup.c | 967 + src/vnet/ip/lookup.h | 498 + src/vnet/ip/ping.c | 888 + src/vnet/ip/ping.h | 108 + src/vnet/ip/ports.def | 757 + src/vnet/ip/protocols.def | 162 + src/vnet/ip/punt.c | 323 + src/vnet/ip/punt.h | 43 + src/vnet/ip/punt_error.def | 19 + src/vnet/ip/tcp_packet.h | 138 + src/vnet/ip/udp.h | 313 + src/vnet/ip/udp_error.def | 21 + src/vnet/ip/udp_format.c | 91 + src/vnet/ip/udp_init.c | 71 + src/vnet/ip/udp_local.c | 645 + src/vnet/ip/udp_packet.h | 65 + src/vnet/ip/udp_pg.c | 237 + src/vnet/ipsec-gre/dir.dox | 18 + src/vnet/ipsec-gre/error.def | 26 + src/vnet/ipsec-gre/interface.c | 311 + src/vnet/ipsec-gre/ipsec_gre.api | 79 + src/vnet/ipsec-gre/ipsec_gre.c | 407 + src/vnet/ipsec-gre/ipsec_gre.h | 114 + src/vnet/ipsec-gre/ipsec_gre_api.c | 190 + src/vnet/ipsec-gre/ipsec_gre_doc.md | 74 + src/vnet/ipsec-gre/node.c | 433 + src/vnet/ipsec/esp.h | 320 + src/vnet/ipsec/esp_decrypt.c | 430 + src/vnet/ipsec/esp_encrypt.c | 425 + src/vnet/ipsec/ikev2.c | 2186 +++ src/vnet/ipsec/ikev2.h | 410 + src/vnet/ipsec/ikev2_cli.c | 479 + src/vnet/ipsec/ikev2_crypto.c | 765 + src/vnet/ipsec/ikev2_format.c | 155 + src/vnet/ipsec/ikev2_payload.c | 535 + src/vnet/ipsec/ikev2_priv.h | 321 + src/vnet/ipsec/ipsec.api | 457 + src/vnet/ipsec/ipsec.c | 581 + src/vnet/ipsec/ipsec.h | 344 + src/vnet/ipsec/ipsec_api.c | 537 + src/vnet/ipsec/ipsec_cli.c | 807 + src/vnet/ipsec/ipsec_format.c | 141 + src/vnet/ipsec/ipsec_if.c | 372 + src/vnet/ipsec/ipsec_if_in.c | 175 + src/vnet/ipsec/ipsec_if_out.c | 161 + src/vnet/ipsec/ipsec_input.c | 455 + src/vnet/ipsec/ipsec_output.c | 478 + src/vnet/l2/dir.dox | 24 + src/vnet/l2/feat_bitmap.c | 185 + src/vnet/l2/feat_bitmap.h | 96 + src/vnet/l2/l2.api | 38 + src/vnet/l2/l2_api.c | 140 + src/vnet/l2/l2_bd.c | 1079 ++ src/vnet/l2/l2_bd.h | 150 + src/vnet/l2/l2_bvi.c | 40 + src/vnet/l2/l2_bvi.h | 117 + src/vnet/l2/l2_classify.h | 116 + src/vnet/l2/l2_efp_filter.c | 614 + src/vnet/l2/l2_efp_filter.h | 33 + src/vnet/l2/l2_fib.c | 857 + src/vnet/l2/l2_fib.h | 341 + src/vnet/l2/l2_flood.c | 568 + src/vnet/l2/l2_flood.h | 35 + src/vnet/l2/l2_fwd.c | 544 + src/vnet/l2/l2_fwd.h | 36 + src/vnet/l2/l2_input.c | 1116 ++ src/vnet/l2/l2_input.h | 266 + src/vnet/l2/l2_input_acl.c | 434 + src/vnet/l2/l2_input_classify.c | 655 + src/vnet/l2/l2_input_vtr.c | 401 + src/vnet/l2/l2_input_vtr.h | 54 + src/vnet/l2/l2_learn.c | 597 + src/vnet/l2/l2_learn.h | 64 + src/vnet/l2/l2_output.c | 708 + src/vnet/l2/l2_output.h | 285 + src/vnet/l2/l2_output_acl.c | 358 + src/vnet/l2/l2_output_classify.c | 657 + src/vnet/l2/l2_patch.c | 452 + src/vnet/l2/l2_rw.c | 719 + src/vnet/l2/l2_rw.h | 95 + src/vnet/l2/l2_vtr.c | 770 + src/vnet/l2/l2_vtr.h | 270 + src/vnet/l2/l2_xcrw.c | 591 + src/vnet/l2/l2_xcrw.h | 91 + src/vnet/l2tp/decap.c | 309 + src/vnet/l2tp/encap.c | 238 + src/vnet/l2tp/l2tp.api | 126 + src/vnet/l2tp/l2tp.c | 739 + src/vnet/l2tp/l2tp.h | 147 + src/vnet/l2tp/l2tp_api.c | 267 + src/vnet/l2tp/packet.h | 44 + src/vnet/l2tp/pg.c | 106 + src/vnet/l3_types.h | 59 + src/vnet/lawful-intercept/lawful_intercept.c | 112 + src/vnet/lawful-intercept/lawful_intercept.h | 45 + src/vnet/lawful-intercept/node.c | 275 + src/vnet/lisp-cp/control.c | 4950 +++++ src/vnet/lisp-cp/control.h | 314 + src/vnet/lisp-cp/gid_dictionary.c | 865 + src/vnet/lisp-cp/gid_dictionary.h | 120 + src/vnet/lisp-cp/lisp.api | 835 + src/vnet/lisp-cp/lisp_api.c | 1257 ++ src/vnet/lisp-cp/lisp_cp_dpo.c | 117 + src/vnet/lisp-cp/lisp_cp_dpo.h | 45 + src/vnet/lisp-cp/lisp_cp_messages.h | 613 + src/vnet/lisp-cp/lisp_msg_serdes.c | 372 + src/vnet/lisp-cp/lisp_msg_serdes.h | 58 + src/vnet/lisp-cp/lisp_types.c | 1574 ++ src/vnet/lisp-cp/lisp_types.h | 354 + src/vnet/lisp-cp/packets.c | 269 + src/vnet/lisp-cp/packets.h | 82 + src/vnet/lisp-gpe/decap.c | 501 + src/vnet/lisp-gpe/dir.dox | 26 + src/vnet/lisp-gpe/interface.c | 709 + src/vnet/lisp-gpe/lisp_gpe.api | 143 + src/vnet/lisp-gpe/lisp_gpe.c | 327 + src/vnet/lisp-gpe/lisp_gpe.h | 257 + src/vnet/lisp-gpe/lisp_gpe_adjacency.c | 542 + src/vnet/lisp-gpe/lisp_gpe_adjacency.h | 136 + src/vnet/lisp-gpe/lisp_gpe_api.c | 304 + src/vnet/lisp-gpe/lisp_gpe_error.def | 18 + src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c | 1053 ++ src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h | 188 + src/vnet/lisp-gpe/lisp_gpe_packet.h | 149 + src/vnet/lisp-gpe/lisp_gpe_sub_interface.c | 278 + src/vnet/lisp-gpe/lisp_gpe_sub_interface.h | 157 + src/vnet/lisp-gpe/lisp_gpe_tenant.c | 330 + src/vnet/lisp-gpe/lisp_gpe_tenant.h | 88 + src/vnet/lisp-gpe/lisp_gpe_tunnel.c | 289 + src/vnet/lisp-gpe/lisp_gpe_tunnel.h | 89 + src/vnet/lisp-gpe/rfc.txt | 826 + src/vnet/llc/llc.c | 241 + src/vnet/llc/llc.h | 194 + src/vnet/llc/node.c | 331 + src/vnet/llc/pg.c | 113 + src/vnet/lldp/dir.dox | 18 + src/vnet/lldp/lldp_cli.c | 646 + src/vnet/lldp/lldp_doc.md | 84 + src/vnet/lldp/lldp_input.c | 302 + src/vnet/lldp/lldp_node.c | 341 + src/vnet/lldp/lldp_node.h | 145 + src/vnet/lldp/lldp_output.c | 216 + src/vnet/lldp/lldp_protocol.h | 142 + src/vnet/map/examples/gen-rules.py | 186 + src/vnet/map/examples/health_check.c | 109 + src/vnet/map/examples/test_map.py | 141 + src/vnet/map/gen-rules.py | 107 + src/vnet/map/ip4_map.c | 813 + src/vnet/map/ip4_map_t.c | 1363 ++ src/vnet/map/ip6_map.c | 1269 ++ src/vnet/map/ip6_map_t.c | 1517 ++ src/vnet/map/map.api | 178 + src/vnet/map/map.c | 2166 +++ src/vnet/map/map.h | 591 + src/vnet/map/map_api.c | 295 + src/vnet/map/map_doc.md | 69 + src/vnet/map/map_dpo.c | 191 + src/vnet/map/map_dpo.h | 67 + src/vnet/map/test.c | 205 + src/vnet/mcast/mcast.c | 565 + src/vnet/mcast/mcast.h | 50 + src/vnet/mcast/mcast_test.c | 149 + src/vnet/misc.c | 124 + src/vnet/mpls/error.def | 31 + src/vnet/mpls/interface.c | 121 + src/vnet/mpls/mpls.c | 511 + src/vnet/mpls/mpls.h | 172 + src/vnet/mpls/mpls_features.c | 156 + src/vnet/mpls/mpls_lookup.c | 531 + src/vnet/mpls/mpls_output.c | 479 + src/vnet/mpls/mpls_tunnel.c | 787 + src/vnet/mpls/mpls_tunnel.h | 98 + src/vnet/mpls/mpls_types.h | 39 + src/vnet/mpls/node.c | 303 + src/vnet/mpls/packet.h | 125 + src/vnet/mpls/pg.c | 71 + src/vnet/osi/node.c | 326 + src/vnet/osi/osi.c | 201 + src/vnet/osi/osi.h | 171 + src/vnet/osi/pg.c | 106 + src/vnet/pg/cli.c | 636 + src/vnet/pg/edit.c | 186 + src/vnet/pg/edit.h | 210 + src/vnet/pg/example.script | 6 + src/vnet/pg/init.c | 72 + src/vnet/pg/input.c | 1667 ++ src/vnet/pg/output.c | 85 + src/vnet/pg/pg.h | 383 + src/vnet/pg/stream.c | 497 + src/vnet/pipeline.h | 456 + src/vnet/plugin/p1.c | 52 + src/vnet/plugin/plugin.h | 32 + src/vnet/policer/node_funcs.c | 938 + src/vnet/policer/police.h | 214 + src/vnet/policer/policer.c | 528 + src/vnet/policer/policer.h | 107 + src/vnet/policer/xlate.c | 1505 ++ src/vnet/policer/xlate.h | 186 + src/vnet/ppp/error.def | 42 + src/vnet/ppp/node.c | 368 + src/vnet/ppp/packet.h | 199 + src/vnet/ppp/pg.c | 114 + src/vnet/ppp/ppp.c | 261 + src/vnet/ppp/ppp.h | 135 + src/vnet/replication.c | 293 + src/vnet/replication.h | 136 + src/vnet/rewrite.c | 329 + src/vnet/rewrite.h | 305 + src/vnet/snap/node.c | 353 + src/vnet/snap/pg.c | 116 + src/vnet/snap/snap.c | 204 + src/vnet/snap/snap.h | 209 + src/vnet/span/node.c | 286 + src/vnet/span/span.api | 60 + src/vnet/span/span.c | 197 + src/vnet/span/span.h | 62 + src/vnet/span/span.md | 65 + src/vnet/span/span_api.c | 153 + src/vnet/sr/dir.dox | 25 + src/vnet/sr/examples/sr_multicastmap.script | 4 + src/vnet/sr/rfc_draft_05.txt | 1265 ++ src/vnet/sr/sr.c | 3333 ++++ src/vnet/sr/sr.h | 262 + src/vnet/sr/sr_error.def | 20 + src/vnet/sr/sr_fix_dst_error.def | 17 + src/vnet/sr/sr_packet.h | 251 + src/vnet/sr/sr_replicate.c | 490 + src/vnet/srp/format.c | 147 + src/vnet/srp/interface.c | 458 + src/vnet/srp/node.c | 932 + src/vnet/srp/packet.h | 204 + src/vnet/srp/pg.c | 157 + src/vnet/srp/srp.h | 222 + src/vnet/unix/gdb_funcs.c | 171 + src/vnet/unix/pcap.c | 241 + src/vnet/unix/pcap.h | 230 + src/vnet/unix/pcap2pg.c | 182 + src/vnet/unix/tap.api | 123 + src/vnet/unix/tap_api.c | 257 + src/vnet/unix/tapcli.c | 1328 ++ src/vnet/unix/tapcli.h | 52 + src/vnet/unix/tuntap.c | 1000 ++ src/vnet/unix/tuntap.h | 36 + src/vnet/vnet.h | 96 + src/vnet/vnet_all_api_h.h | 57 + src/vnet/vnet_msg_enum.h | 37 + src/vnet/vxlan-gpe/decap.c | 733 + src/vnet/vxlan-gpe/dir.dox | 32 + src/vnet/vxlan-gpe/encap.c | 388 + src/vnet/vxlan-gpe/vxlan-gpe-rfc.txt | 868 + src/vnet/vxlan-gpe/vxlan_gpe.api | 61 + src/vnet/vxlan-gpe/vxlan_gpe.c | 659 + src/vnet/vxlan-gpe/vxlan_gpe.h | 221 + src/vnet/vxlan-gpe/vxlan_gpe_api.c | 249 + src/vnet/vxlan-gpe/vxlan_gpe_error.def | 16 + src/vnet/vxlan-gpe/vxlan_gpe_packet.h | 110 + src/vnet/vxlan/decap.c | 1130 ++ src/vnet/vxlan/dir.dox | 24 + src/vnet/vxlan/encap.c | 553 + src/vnet/vxlan/vxlan.api | 81 + src/vnet/vxlan/vxlan.c | 899 + src/vnet/vxlan/vxlan.h | 199 + src/vnet/vxlan/vxlan_api.c | 253 + src/vnet/vxlan/vxlan_error.def | 17 + src/vnet/vxlan/vxlan_packet.h | 69 + src/vpp-api-test.am | 64 + src/vpp-api/python/Makefile.am | 60 + src/vpp-api/python/README.rst | 0 src/vpp-api/python/pneum/pneum.c | 259 + src/vpp-api/python/pneum/pneum.h | 31 + src/vpp-api/python/pneum/test_pneum.c | 143 + src/vpp-api/python/setup.cfg | 5 + src/vpp-api/python/setup.py | 34 + src/vpp-api/python/tests/test_cli.py | 52 + src/vpp-api/python/tests/test_modules.py | 18 + src/vpp-api/python/tests/test_papi.py | 119 + src/vpp-api/python/tests/test_version.py | 35 + src/vpp-api/python/tests/test_vpp_papi2.py | 487 + src/vpp-api/python/vpp_papi/__init__.py | 3 + src/vpp-api/python/vpp_papi/pneum_wrap.c | 200 + src/vpp-api/python/vpp_papi/vpp_papi.py | 450 + src/vpp.am | 159 + src/vpp/api/api.c | 4922 +++++ src/vpp/api/api_format.c | 1 + src/vpp/api/api_main.c | 192 + src/vpp/api/custom_dump.c | 3139 ++++ src/vpp/api/gmon.c | 319 + src/vpp/api/json_format.c | 304 + src/vpp/api/json_format.h | 254 + src/vpp/api/summary_stats_client.c | 302 + src/vpp/api/test_client.c | 1531 ++ src/vpp/api/test_ha.c | 249 + src/vpp/api/vat.h | 1 + src/vpp/api/vpe.api | 2782 +++ src/vpp/api/vpe_all_api_h.h | 37 + src/vpp/api/vpe_msg_enum.h | 37 + src/vpp/api/vpp_get_metrics.c | 253 + src/vpp/app/l2t.c | 557 + src/vpp/app/l2t_l2.c | 267 + src/vpp/app/sticky_hash.c | 581 + src/vpp/app/version.c | 102 + src/vpp/app/vpe_cli.c | 123 + src/vpp/conf/80-vpp.conf | 15 + src/vpp/conf/startup.conf | 99 + src/vpp/conf/startup.uiopcigeneric.conf | 18 + src/vpp/oam/oam.c | 648 + src/vpp/oam/oam.h | 96 + src/vpp/stats/stats.c | 987 + src/vpp/stats/stats.h | 76 + src/vpp/vnet/main.c | 415 + src/vppapigen.am | 27 + src/vppinfra.am | 276 + src/vppinfra/README | 43 + src/vppinfra/anneal.c | 172 + src/vppinfra/anneal.h | 89 + src/vppinfra/asm_mips.h | 351 + src/vppinfra/asm_x86.c | 1947 ++ src/vppinfra/asm_x86.h | 125 + src/vppinfra/backtrace.c | 267 + src/vppinfra/bihash_24_8.h | 85 + src/vppinfra/bihash_8_8.h | 98 + src/vppinfra/bihash_doc.h | 149 + src/vppinfra/bihash_template.c | 455 + src/vppinfra/bihash_template.h | 214 + src/vppinfra/bitmap.h | 774 + src/vppinfra/bitops.h | 179 + src/vppinfra/byte_order.h | 202 + src/vppinfra/cache.h | 104 + src/vppinfra/clib.h | 359 + src/vppinfra/cpu.c | 133 + src/vppinfra/cpu.h | 112 + src/vppinfra/dir.dox | 19 + src/vppinfra/dlist.h | 156 + src/vppinfra/elf.c | 2040 +++ src/vppinfra/elf.h | 1062 ++ src/vppinfra/elf_clib.c | 377 + src/vppinfra/elf_clib.h | 144 + src/vppinfra/elog.c | 1061 ++ src/vppinfra/elog.h | 460 + src/vppinfra/error.c | 292 + src/vppinfra/error.h | 201 + src/vppinfra/error_bootstrap.h | 106 + src/vppinfra/fheap.c | 473 + src/vppinfra/fheap.h | 140 + src/vppinfra/fifo.c | 137 + src/vppinfra/fifo.h | 304 + src/vppinfra/format.c | 814 + src/vppinfra/format.h | 331 + src/vppinfra/graph.c | 182 + src/vppinfra/graph.h | 127 + src/vppinfra/hash.c | 1095 ++ src/vppinfra/hash.h | 699 + src/vppinfra/heap.c | 828 + src/vppinfra/heap.h | 357 + src/vppinfra/longjmp.S | 690 + src/vppinfra/longjmp.h | 124 + src/vppinfra/macros.c | 266 + src/vppinfra/macros.h | 54 + src/vppinfra/math.h | 63 + src/vppinfra/md5.c | 317 + src/vppinfra/md5.h | 57 + src/vppinfra/mem.h | 291 + src/vppinfra/mem_mheap.c | 165 + src/vppinfra/memcheck.h | 317 + src/vppinfra/memcpy_avx.h | 293 + src/vppinfra/memcpy_sse3.h | 355 + src/vppinfra/mhash.c | 408 + src/vppinfra/mhash.h | 179 + src/vppinfra/mheap.c | 1649 ++ src/vppinfra/mheap.h | 94 + src/vppinfra/mheap_bootstrap.h | 374 + src/vppinfra/mod_test_hash.c | 27 + src/vppinfra/os.h | 72 + src/vppinfra/pfhash.c | 689 + src/vppinfra/pfhash.h | 276 + src/vppinfra/phash.c | 1017 ++ src/vppinfra/phash.h | 194 + src/vppinfra/pipeline.h | 176 + src/vppinfra/pool.h | 405 + src/vppinfra/ptclosure.c | 125 + src/vppinfra/ptclosure.h | 40 + src/vppinfra/qhash.c | 858 + src/vppinfra/qhash.h | 169 + src/vppinfra/qsort.c | 269 + src/vppinfra/random.c | 51 + src/vppinfra/random.h | 178 + src/vppinfra/random_buffer.c | 86 + src/vppinfra/random_buffer.h | 118 + src/vppinfra/random_isaac.c | 434 + src/vppinfra/random_isaac.h | 81 + src/vppinfra/serialize.c | 1254 ++ src/vppinfra/serialize.h | 443 + src/vppinfra/slist.c | 336 + src/vppinfra/slist.h | 145 + src/vppinfra/smp.c | 325 + src/vppinfra/smp.h | 81 + src/vppinfra/smp_fifo.c | 91 + src/vppinfra/smp_fifo.h | 313 + src/vppinfra/socket.c | 422 + src/vppinfra/socket.h | 160 + src/vppinfra/sparse_vec.h | 244 + src/vppinfra/std-formats.c | 330 + src/vppinfra/string.c | 94 + src/vppinfra/string.h | 83 + src/vppinfra/test_bihash_template.c | 297 + src/vppinfra/test_dlist.c | 193 + src/vppinfra/test_elf.c | 217 + src/vppinfra/test_elog.c | 262 + src/vppinfra/test_fifo.c | 144 + src/vppinfra/test_format.c | 199 + src/vppinfra/test_hash.c | 458 + src/vppinfra/test_heap.c | 198 + src/vppinfra/test_longjmp.c | 129 + src/vppinfra/test_macros.c | 64 + src/vppinfra/test_md5.c | 141 + src/vppinfra/test_mheap.c | 242 + src/vppinfra/test_pfhash.c | 322 + src/vppinfra/test_phash.c | 149 + src/vppinfra/test_pool.c | 86 + src/vppinfra/test_pool_iterate.c | 59 + src/vppinfra/test_ptclosure.c | 212 + src/vppinfra/test_qhash.c | 333 + src/vppinfra/test_random.c | 148 + src/vppinfra/test_random_isaac.c | 142 + src/vppinfra/test_serialize.c | 274 + src/vppinfra/test_slist.c | 228 + src/vppinfra/test_socket.c | 134 + src/vppinfra/test_time.c | 104 + src/vppinfra/test_timing_wheel.c | 389 + src/vppinfra/test_vec.c | 1159 ++ src/vppinfra/test_vec.h | 243 + src/vppinfra/test_vhash.c | 757 + src/vppinfra/test_zvec.c | 117 + src/vppinfra/time.c | 226 + src/vppinfra/time.h | 298 + src/vppinfra/timer.c | 322 + src/vppinfra/timer.h | 46 + src/vppinfra/timing_wheel.c | 750 + src/vppinfra/timing_wheel.h | 155 + src/vppinfra/types.h | 174 + src/vppinfra/unformat.c | 1077 ++ src/vppinfra/unix-formats.c | 918 + src/vppinfra/unix-kelog.c | 415 + src/vppinfra/unix-misc.c | 242 + src/vppinfra/unix.h | 64 + src/vppinfra/unix_error.def | 145 + src/vppinfra/valgrind.h | 4030 +++++ src/vppinfra/vec.c | 171 + src/vppinfra/vec.h | 973 + src/vppinfra/vec_bootstrap.h | 201 + src/vppinfra/vector.c | 54 + src/vppinfra/vector.h | 268 + src/vppinfra/vector_altivec.h | 178 + src/vppinfra/vector_funcs.h | 334 + src/vppinfra/vector_iwmmxt.h | 149 + src/vppinfra/vector_neon.h | 71 + src/vppinfra/vector_sse2.h | 711 + src/vppinfra/vhash.c | 772 + src/vppinfra/vhash.h | 850 + src/vppinfra/vm_linux_kernel.h | 78 + src/vppinfra/vm_standalone.h | 74 + src/vppinfra/vm_unix.h | 106 + src/vppinfra/xxhash.h | 86 + src/vppinfra/xy.h | 56 + src/vppinfra/zvec.c | 442 + src/vppinfra/zvec.h | 166 + svm/Makefile.am | 30 - svm/configure.ac | 7 - svm/dir.dox | 21 - svm/persist.c | 258 - svm/ssvm.c | 178 - svm/ssvm.h | 155 - svm/svm.c | 1237 -- svm/svm.h | 207 - svm/svm_test.c | 79 - svm/svmdb.c | 671 - svm/svmdb.h | 135 - svm/svmdbtool.c | 537 - svm/svmtool.c | 528 - vlib-api/Makefile.am | 84 - vlib-api/configure.ac | 9 - vlib-api/suffix-rules.mk | 1 - vlib-api/vlibapi/api.h | 281 - vlib-api/vlibapi/api_helper_macros.h | 243 - vlib-api/vlibapi/api_shared.c | 1375 -- vlib-api/vlibapi/node_serialize.c | 399 - vlib-api/vlibmemory/api.h | 163 - vlib-api/vlibmemory/memclnt.api | 91 - vlib-api/vlibmemory/memory_client.c | 283 - vlib-api/vlibmemory/memory_shared.c | 852 - vlib-api/vlibmemory/memory_vlib.c | 1346 -- vlib-api/vlibmemory/unix_shared_memory_queue.c | 324 - vlib-api/vlibmemory/unix_shared_memory_queue.h | 69 - vlib-api/vlibmemory/vl_memory_api_h.h | 32 - vlib-api/vlibmemory/vl_memory_msg_enum.h | 42 - vlib-api/vlibsocket/api.h | 87 - vlib-api/vlibsocket/sock_test.c | 155 - vlib-api/vlibsocket/sockclnt.api | 50 - vlib-api/vlibsocket/sockclnt_vlib.c | 209 - vlib-api/vlibsocket/socksvr_vlib.c | 706 - vlib-api/vlibsocket/vl_socket_api_h.h | 33 - vlib-api/vlibsocket/vl_socket_msg_enum.h | 42 - vlib/.gitignore | 1 - vlib/Makefile.am | 104 - vlib/configure.ac | 25 - vlib/dir.dox | 21 - vlib/example/dir.dox | 22 - vlib/example/main_stub.c | 418 - vlib/example/mc_test.c | 384 - vlib/example/plex_test.c | 527 - vlib/vlib/buffer.c | 1987 --- vlib/vlib/buffer.h | 417 - vlib/vlib/buffer_funcs.h | 755 - vlib/vlib/buffer_node.h | 337 - vlib/vlib/cli.c | 1173 -- vlib/vlib/cli.h | 192 - vlib/vlib/cli_funcs.h | 58 - vlib/vlib/counter.c | 151 - vlib/vlib/counter.h | 379 - vlib/vlib/defs.h | 82 - vlib/vlib/dir.dox | 23 - vlib/vlib/elog_samples.c | 122 - vlib/vlib/error.c | 338 - vlib/vlib/error.h | 101 - vlib/vlib/error_funcs.h | 88 - vlib/vlib/format.c | 196 - vlib/vlib/format_funcs.h | 75 - vlib/vlib/global_funcs.h | 45 - vlib/vlib/i2c.c | 231 - vlib/vlib/i2c.h | 67 - vlib/vlib/init.c | 168 - vlib/vlib/init.h | 238 - vlib/vlib/lex.c | 271 - vlib/vlib/lex.h | 145 - vlib/vlib/main.c | 1703 -- vlib/vlib/main.h | 333 - vlib/vlib/mc.c | 2609 --- vlib/vlib/mc.h | 687 - vlib/vlib/node.c | 631 - vlib/vlib/node.h | 725 - vlib/vlib/node_cli.c | 466 - vlib/vlib/node_format.c | 187 - vlib/vlib/node_funcs.h | 1130 -- vlib/vlib/parse.c | 1007 -- vlib/vlib/parse.h | 221 - vlib/vlib/parse_builtin.c | 150 - vlib/vlib/pci/linux_pci.c | 642 - vlib/vlib/pci/pci.c | 264 - vlib/vlib/pci/pci.h | 251 - vlib/vlib/pci/pci_config.h | 731 - vlib/vlib/physmem.h | 108 - vlib/vlib/threads.c | 1492 -- vlib/vlib/threads.h | 470 - vlib/vlib/threads_cli.c | 579 - vlib/vlib/trace.c | 545 - vlib/vlib/trace.h | 100 - vlib/vlib/trace_funcs.h | 185 - vlib/vlib/unix/cj.c | 271 - vlib/vlib/unix/cj.h | 79 - vlib/vlib/unix/cli.c | 2989 ---- vlib/vlib/unix/dir.dox | 28 - vlib/vlib/unix/input.c | 265 - vlib/vlib/unix/main.c | 557 - vlib/vlib/unix/mc_socket.c | 1049 -- vlib/vlib/unix/mc_socket.h | 137 - vlib/vlib/unix/physmem.c | 470 - vlib/vlib/unix/physmem.h | 65 - vlib/vlib/unix/plugin.c | 260 - vlib/vlib/unix/plugin.h | 98 - vlib/vlib/unix/unix.h | 232 - vlib/vlib/unix/util.c | 231 - vlib/vlib/vlib.h | 86 - vlib/vlib/vlib_process_doc.h | 147 - vnet/.gitignore | 1 - vnet/Makefile.am | 993 -- vnet/configure.ac | 49 - vnet/etc/scripts/arp4 | 21 - vnet/etc/scripts/arp4-mpls | 24 - vnet/etc/scripts/arp6 | 21 - vnet/etc/scripts/bvi | 76 - vnet/etc/scripts/dhcp/dhcpd.conf | 8 - vnet/etc/scripts/dhcp/left-ping-target.sh | 4 - vnet/etc/scripts/dhcp/leftpeer.conf | 17 - vnet/etc/scripts/icmp | 16 - vnet/etc/scripts/icmp6 | 16 - vnet/etc/scripts/ige | 19 - vnet/etc/scripts/ip6 | 15 - vnet/etc/scripts/ip6-hbh | 84 - vnet/etc/scripts/ixge | 15 - vnet/etc/scripts/l2efpfilter | 83 - vnet/etc/scripts/l2efpfilter_perf | 58 - vnet/etc/scripts/l2fib | 46 - vnet/etc/scripts/l2fib_perf | 29 - vnet/etc/scripts/l2fib_xc | 31 - vnet/etc/scripts/l2flood | 42 - vnet/etc/scripts/l2tp | 134 - vnet/etc/scripts/leftpeer/leftpeer-classify | 8 - vnet/etc/scripts/leftpeer/leftpeer-classify6 | 5 - vnet/etc/scripts/leftpeer/leftpeer-classifyl2 | 8 - vnet/etc/scripts/leftpeer/leftpeer-dhcp | 23 - vnet/etc/scripts/leftpeer/leftpeer-ioam.conf | 15 - vnet/etc/scripts/leftpeer/leftpeer-l3vxlan.conf | 12 - vnet/etc/scripts/leftpeer/leftpeer-lisp.conf | 18 - vnet/etc/scripts/leftpeer/leftpeer-mpls.conf | 17 - vnet/etc/scripts/leftpeer/leftpeer-sr.conf | 24 - vnet/etc/scripts/leftpeer/leftpeer-vxlan.conf | 17 - vnet/etc/scripts/leftpeer/leftpeer.script | 9 - vnet/etc/scripts/lfib/ip4-to-mpls | 26 - vnet/etc/scripts/lfib/mpls-pop-to-mpls | 28 - vnet/etc/scripts/lfib/mpls-to-ip4 | 27 - vnet/etc/scripts/lfib/mpls-to-mpls | 26 - vnet/etc/scripts/mpls-o-ethernet/leftpeer.conf | 17 - vnet/etc/scripts/mpls-o-ethernet/pg | 10 - vnet/etc/scripts/mpls-o-ethernet/rightpeer.conf | 15 - vnet/etc/scripts/mpls-o-ethernet/single.conf | 17 - vnet/etc/scripts/mpls-o-gre/dhcpd.conf | 116 - vnet/etc/scripts/mpls-o-gre/leftpeer.conf | 14 - vnet/etc/scripts/mpls-o-gre/rightpeer.conf | 14 - vnet/etc/scripts/mpls-tunnel | 87 - vnet/etc/scripts/pcap | 18 - vnet/etc/scripts/probe4 | 11 - vnet/etc/scripts/probe6 | 7 - vnet/etc/scripts/rewrite | 62 - vnet/etc/scripts/rightpeer/rightpeer-ioam.conf | 14 - vnet/etc/scripts/rightpeer/rightpeer-l3vxlan.conf | 9 - vnet/etc/scripts/rightpeer/rightpeer-lisp.conf | 16 - vnet/etc/scripts/rightpeer/rightpeer-mpls-l2.conf | 24 - vnet/etc/scripts/rightpeer/rightpeer-mpls.conf | 17 - vnet/etc/scripts/rightpeer/rightpeer-sr.conf | 28 - vnet/etc/scripts/rightpeer/rightpeer-vxlan.conf | 16 - vnet/etc/scripts/rightpeer/rightpeer.script | 9 - vnet/etc/scripts/rpf | 18 - vnet/etc/scripts/rtt-test | 31 - vnet/etc/scripts/snat | 34 - vnet/etc/scripts/snat_static | 44 - vnet/etc/scripts/snat_static_with_port | 44 - vnet/etc/scripts/source_and_port_range_check | 63 - vnet/etc/scripts/speed | 14 - vnet/etc/scripts/sr/left-linux-ping.sh | 3 - vnet/etc/scripts/sr/leftpeer.conf | 27 - vnet/etc/scripts/sr/right-linux-ping.sh | 4 - vnet/etc/scripts/sr/rightpeer.conf | 22 - vnet/etc/scripts/sr/srlocal.sh | 4 - vnet/etc/scripts/srp | 27 - vnet/etc/scripts/tcp | 16 - vnet/etc/scripts/tcp-test | 6 - vnet/etc/scripts/tf-ucs-1 | 16 - vnet/etc/scripts/urpf | 86 - vnet/etc/scripts/virl/ip6sr.virl | 874 - vnet/etc/scripts/virl/ip6sr_notes.txt | 38 - vnet/etc/scripts/virl/mplsogre.virl | 319 - vnet/etc/scripts/virl/simple.virl | 389 - vnet/etc/scripts/vlan | 23 - vnet/suffix-rules.mk | 1 - vnet/test/README | 10 - vnet/test/lisp-cp/test_cp_serdes.c | 635 - vnet/test/lisp-cp/test_lisp_types.c | 561 - vnet/test/lisp-gpe/test.c | 18 - vnet/vnet/adj/adj.c | 454 - vnet/vnet/adj/adj.h | 122 - vnet/vnet/adj/adj_glean.c | 285 - vnet/vnet/adj/adj_glean.h | 61 - vnet/vnet/adj/adj_internal.h | 104 - vnet/vnet/adj/adj_l2.c | 194 - vnet/vnet/adj/adj_l2.h | 24 - vnet/vnet/adj/adj_midchain.c | 559 - vnet/vnet/adj/adj_midchain.h | 102 - vnet/vnet/adj/adj_nbr.c | 1087 -- vnet/vnet/adj/adj_nbr.h | 176 - vnet/vnet/adj/adj_rewrite.c | 53 - vnet/vnet/adj/adj_rewrite.h | 49 - vnet/vnet/adj/adj_types.h | 53 - vnet/vnet/api_errno.h | 113 - vnet/vnet/bfd/bfd.api | 205 - vnet/vnet/bfd/bfd_api.c | 262 - vnet/vnet/bfd/bfd_api.h | 46 - vnet/vnet/bfd/bfd_debug.h | 79 - vnet/vnet/bfd/bfd_doc.md | 1 - vnet/vnet/bfd/bfd_main.c | 969 - vnet/vnet/bfd/bfd_main.h | 220 - vnet/vnet/bfd/bfd_protocol.c | 74 - vnet/vnet/bfd/bfd_protocol.h | 154 - vnet/vnet/bfd/bfd_udp.c | 639 - vnet/vnet/bfd/bfd_udp.h | 56 - vnet/vnet/bfd/dir.dox | 18 - vnet/vnet/buffer.h | 381 - vnet/vnet/cdp/cdp.pg | 7 - vnet/vnet/cdp/cdp_input.c | 506 - vnet/vnet/cdp/cdp_node.c | 208 - vnet/vnet/cdp/cdp_node.h | 147 - vnet/vnet/cdp/cdp_periodic.c | 512 - vnet/vnet/cdp/cdp_protocol.h | 186 - vnet/vnet/classify/README | 180 - vnet/vnet/classify/flow_classify.c | 212 - vnet/vnet/classify/flow_classify.h | 51 - vnet/vnet/classify/flow_classify_node.c | 338 - vnet/vnet/classify/input_acl.c | 283 - vnet/vnet/classify/input_acl.h | 54 - vnet/vnet/classify/ip_classify.c | 365 - vnet/vnet/classify/policer_classify.c | 227 - vnet/vnet/classify/policer_classify.h | 55 - vnet/vnet/classify/vnet_classify.c | 2436 --- vnet/vnet/classify/vnet_classify.h | 523 - vnet/vnet/config.c | 361 - vnet/vnet/config.h | 176 - vnet/vnet/cop/cop.c | 387 - vnet/vnet/cop/cop.h | 89 - vnet/vnet/cop/ip4_whitelist.c | 356 - vnet/vnet/cop/ip6_whitelist.c | 298 - vnet/vnet/cop/node1.c | 319 - vnet/vnet/devices/af_packet/af_packet.api | 71 - vnet/vnet/devices/af_packet/af_packet.c | 366 - vnet/vnet/devices/af_packet/af_packet.h | 69 - vnet/vnet/devices/af_packet/af_packet_api.c | 143 - vnet/vnet/devices/af_packet/cli.c | 144 - vnet/vnet/devices/af_packet/device.c | 250 - vnet/vnet/devices/af_packet/node.c | 288 - vnet/vnet/devices/devices.c | 91 - vnet/vnet/devices/devices.h | 53 - vnet/vnet/devices/dpdk/cli.c | 1296 -- vnet/vnet/devices/dpdk/device.c | 840 - vnet/vnet/devices/dpdk/dpdk.h | 534 - vnet/vnet/devices/dpdk/dpdk_priv.h | 132 - vnet/vnet/devices/dpdk/format.c | 763 - vnet/vnet/devices/dpdk/hqos.c | 775 - vnet/vnet/devices/dpdk/init.c | 1803 -- vnet/vnet/devices/dpdk/ipsec/cli.c | 141 - vnet/vnet/devices/dpdk/ipsec/crypto_node.c | 210 - vnet/vnet/devices/dpdk/ipsec/dir.dox | 18 - .../devices/dpdk/ipsec/dpdk_crypto_ipsec_doc.md | 73 - vnet/vnet/devices/dpdk/ipsec/esp.h | 295 - vnet/vnet/devices/dpdk/ipsec/esp_decrypt.c | 583 - vnet/vnet/devices/dpdk/ipsec/esp_encrypt.c | 598 - vnet/vnet/devices/dpdk/ipsec/ipsec.c | 313 - vnet/vnet/devices/dpdk/ipsec/ipsec.h | 227 - vnet/vnet/devices/dpdk/node.c | 687 - vnet/vnet/devices/dpdk/qos_doc.md | 404 - vnet/vnet/devices/netmap/cli.c | 146 - vnet/vnet/devices/netmap/device.c | 261 - vnet/vnet/devices/netmap/net_netmap.h | 650 - vnet/vnet/devices/netmap/netmap.api | 74 - vnet/vnet/devices/netmap/netmap.c | 316 - vnet/vnet/devices/netmap/netmap.h | 164 - vnet/vnet/devices/netmap/netmap_api.c | 137 - vnet/vnet/devices/netmap/node.c | 300 - vnet/vnet/devices/nic/ixge.c | 2938 --- vnet/vnet/devices/nic/ixge.h | 1293 -- vnet/vnet/devices/nic/sfp.c | 117 - vnet/vnet/devices/nic/sfp.h | 117 - vnet/vnet/devices/ssvm/node.c | 343 - vnet/vnet/devices/ssvm/ssvm_eth.c | 491 - vnet/vnet/devices/ssvm/ssvm_eth.h | 141 - vnet/vnet/devices/virtio/dir.dox | 27 - vnet/vnet/devices/virtio/vhost-user.c | 3314 ---- vnet/vnet/devices/virtio/vhost-user.h | 350 - vnet/vnet/devices/virtio/vhost_user.api | 125 - vnet/vnet/devices/virtio/vhost_user_api.c | 262 - vnet/vnet/dhcp/client.c | 1031 -- vnet/vnet/dhcp/client.h | 118 - vnet/vnet/dhcp/packet.h | 61 - vnet/vnet/dhcp/proxy.h | 92 - vnet/vnet/dhcp/proxy_error.def | 30 - vnet/vnet/dhcp/proxy_node.c | 1114 -- vnet/vnet/dhcpv6/packet.h | 183 - vnet/vnet/dhcpv6/proxy.h | 95 - vnet/vnet/dhcpv6/proxy_error.def | 29 - vnet/vnet/dhcpv6/proxy_node.c | 1191 -- vnet/vnet/dpo/classify_dpo.c | 131 - vnet/vnet/dpo/classify_dpo.h | 56 - vnet/vnet/dpo/dpo.c | 500 - vnet/vnet/dpo/dpo.h | 381 - vnet/vnet/dpo/drop_dpo.c | 106 - vnet/vnet/dpo/drop_dpo.h | 31 - vnet/vnet/dpo/ip_null_dpo.c | 408 - vnet/vnet/dpo/ip_null_dpo.h | 56 - vnet/vnet/dpo/load_balance.c | 993 -- vnet/vnet/dpo/load_balance.h | 211 - vnet/vnet/dpo/load_balance_map.c | 575 - vnet/vnet/dpo/load_balance_map.h | 79 - vnet/vnet/dpo/lookup_dpo.c | 1185 -- vnet/vnet/dpo/lookup_dpo.h | 108 - vnet/vnet/dpo/mpls_label_dpo.c | 570 - vnet/vnet/dpo/mpls_label_dpo.h | 101 - vnet/vnet/dpo/punt_dpo.c | 100 - vnet/vnet/dpo/punt_dpo.h | 30 - vnet/vnet/dpo/receive_dpo.c | 165 - vnet/vnet/dpo/receive_dpo.h | 62 - vnet/vnet/ethernet/arp.c | 2355 --- vnet/vnet/ethernet/arp_packet.h | 173 - vnet/vnet/ethernet/dir.dox | 24 - vnet/vnet/ethernet/error.def | 46 - vnet/vnet/ethernet/ethernet.h | 561 - vnet/vnet/ethernet/format.c | 366 - vnet/vnet/ethernet/init.c | 128 - vnet/vnet/ethernet/interface.c | 730 - vnet/vnet/ethernet/mac_swap.c | 397 - vnet/vnet/ethernet/node.c | 1368 -- vnet/vnet/ethernet/packet.h | 152 - vnet/vnet/ethernet/pg.c | 183 - vnet/vnet/ethernet/types.def | 113 - vnet/vnet/feature/feature.c | 463 - vnet/vnet/feature/feature.h | 382 - vnet/vnet/feature/registration.c | 301 - vnet/vnet/fib/fib.c | 41 - vnet/vnet/fib/fib.h | 652 - vnet/vnet/fib/fib_api.h | 54 - vnet/vnet/fib/fib_attached_export.c | 572 - vnet/vnet/fib/fib_attached_export.h | 57 - vnet/vnet/fib/fib_entry.c | 1503 -- vnet/vnet/fib/fib_entry.h | 530 - vnet/vnet/fib/fib_entry_cover.c | 225 - vnet/vnet/fib/fib_entry_cover.h | 47 - vnet/vnet/fib/fib_entry_delegate.c | 149 - vnet/vnet/fib/fib_entry_delegate.h | 124 - vnet/vnet/fib/fib_entry_src.c | 1456 -- vnet/vnet/fib/fib_entry_src.h | 296 - vnet/vnet/fib/fib_entry_src_adj.c | 207 - vnet/vnet/fib/fib_entry_src_api.c | 119 - vnet/vnet/fib/fib_entry_src_default.c | 121 - vnet/vnet/fib/fib_entry_src_default_route.c | 58 - vnet/vnet/fib/fib_entry_src_interface.c | 195 - vnet/vnet/fib/fib_entry_src_lisp.c | 133 - vnet/vnet/fib/fib_entry_src_mpls.c | 196 - vnet/vnet/fib/fib_entry_src_rr.c | 293 - vnet/vnet/fib/fib_entry_src_special.c | 71 - vnet/vnet/fib/fib_internal.h | 69 - vnet/vnet/fib/fib_node.c | 277 - vnet/vnet/fib/fib_node.h | 371 - vnet/vnet/fib/fib_node_list.c | 390 - vnet/vnet/fib/fib_node_list.h | 64 - vnet/vnet/fib/fib_path.c | 2001 --- vnet/vnet/fib/fib_path.h | 158 - vnet/vnet/fib/fib_path_ext.c | 231 - vnet/vnet/fib/fib_path_ext.h | 69 - vnet/vnet/fib/fib_path_list.c | 1223 -- vnet/vnet/fib/fib_path_list.h | 158 - vnet/vnet/fib/fib_table.c | 1104 -- vnet/vnet/fib/fib_table.h | 732 - vnet/vnet/fib/fib_test.c | 7112 -------- vnet/vnet/fib/fib_types.c | 326 - vnet/vnet/fib/fib_types.h | 340 - vnet/vnet/fib/fib_urpf_list.c | 260 - vnet/vnet/fib/fib_urpf_list.h | 146 - vnet/vnet/fib/fib_walk.c | 1108 -- vnet/vnet/fib/fib_walk.h | 58 - vnet/vnet/fib/ip4_fib.c | 664 - vnet/vnet/fib/ip4_fib.h | 141 - vnet/vnet/fib/ip6_fib.c | 784 - vnet/vnet/fib/ip6_fib.h | 130 - vnet/vnet/fib/mpls_fib.c | 439 - vnet/vnet/fib/mpls_fib.h | 106 - vnet/vnet/flow/flow_report.c | 502 - vnet/vnet/flow/flow_report.h | 145 - vnet/vnet/flow/flow_report_classify.c | 529 - vnet/vnet/flow/flow_report_classify.h | 122 - vnet/vnet/flow/ipfix_info_elements.h | 429 - vnet/vnet/flow/ipfix_packet.h | 188 - vnet/vnet/global_funcs.h | 32 - vnet/vnet/gre/error.def | 23 - vnet/vnet/gre/gre.api | 57 - vnet/vnet/gre/gre.c | 455 - vnet/vnet/gre/gre.h | 235 - vnet/vnet/gre/gre_api.c | 204 - vnet/vnet/gre/interface.c | 606 - vnet/vnet/gre/node.c | 531 - vnet/vnet/gre/packet.h | 55 - vnet/vnet/gre/pg.c | 77 - vnet/vnet/handoff.c | 594 - vnet/vnet/handoff.h | 259 - vnet/vnet/hdlc/error.def | 42 - vnet/vnet/hdlc/hdlc.c | 249 - vnet/vnet/hdlc/hdlc.h | 127 - vnet/vnet/hdlc/node.c | 351 - vnet/vnet/hdlc/packet.h | 72 - vnet/vnet/hdlc/pg.c | 105 - vnet/vnet/interface.api | 339 - vnet/vnet/interface.c | 1398 -- vnet/vnet/interface.h | 658 - vnet/vnet/interface_api.c | 725 - vnet/vnet/interface_cli.c | 1165 -- vnet/vnet/interface_format.c | 401 - vnet/vnet/interface_funcs.h | 318 - vnet/vnet/interface_output.c | 1404 -- vnet/vnet/ip/dir.dox | 26 - vnet/vnet/ip/format.c | 121 - vnet/vnet/ip/format.h | 114 - vnet/vnet/ip/icmp4.c | 784 - vnet/vnet/ip/icmp4.h | 60 - vnet/vnet/ip/icmp46_packet.h | 398 - vnet/vnet/ip/icmp6.c | 882 - vnet/vnet/ip/icmp6.h | 86 - vnet/vnet/ip/igmp_packet.h | 155 - vnet/vnet/ip/ip.api | 434 - vnet/vnet/ip/ip.h | 195 - vnet/vnet/ip/ip4.h | 322 - vnet/vnet/ip/ip46_cli.c | 236 - vnet/vnet/ip/ip4_error.h | 95 - vnet/vnet/ip/ip4_format.c | 256 - vnet/vnet/ip/ip4_forward.c | 3345 ---- vnet/vnet/ip/ip4_input.c | 507 - vnet/vnet/ip/ip4_mtrie.c | 568 - vnet/vnet/ip/ip4_mtrie.h | 188 - vnet/vnet/ip/ip4_packet.h | 384 - vnet/vnet/ip/ip4_pg.c | 387 - vnet/vnet/ip/ip4_source_and_port_range_check.c | 1415 -- vnet/vnet/ip/ip4_source_check.c | 573 - vnet/vnet/ip/ip4_test.c | 340 - vnet/vnet/ip/ip6.h | 476 - vnet/vnet/ip/ip6_error.h | 92 - vnet/vnet/ip/ip6_format.c | 383 - vnet/vnet/ip/ip6_forward.c | 3402 ---- vnet/vnet/ip/ip6_hop_by_hop.c | 1194 -- vnet/vnet/ip/ip6_hop_by_hop.h | 217 - vnet/vnet/ip/ip6_hop_by_hop_packet.h | 66 - vnet/vnet/ip/ip6_input.c | 353 - vnet/vnet/ip/ip6_neighbor.c | 4088 ----- vnet/vnet/ip/ip6_neighbor.h | 52 - vnet/vnet/ip/ip6_packet.h | 499 - vnet/vnet/ip/ip6_pg.c | 231 - vnet/vnet/ip/ip_api.c | 1196 -- vnet/vnet/ip/ip_checksum.c | 228 - vnet/vnet/ip/ip_frag.c | 581 - vnet/vnet/ip/ip_frag.h | 96 - vnet/vnet/ip/ip_init.c | 152 - vnet/vnet/ip/ip_input_acl.c | 450 - vnet/vnet/ip/ip_packet.h | 180 - vnet/vnet/ip/ip_source_and_port_range_check.h | 148 - vnet/vnet/ip/lookup.c | 967 - vnet/vnet/ip/lookup.h | 498 - vnet/vnet/ip/ping.c | 888 - vnet/vnet/ip/ping.h | 108 - vnet/vnet/ip/ports.def | 757 - vnet/vnet/ip/protocols.def | 162 - vnet/vnet/ip/punt.c | 323 - vnet/vnet/ip/punt.h | 43 - vnet/vnet/ip/punt_error.def | 19 - vnet/vnet/ip/tcp_packet.h | 138 - vnet/vnet/ip/udp.h | 313 - vnet/vnet/ip/udp_error.def | 21 - vnet/vnet/ip/udp_format.c | 91 - vnet/vnet/ip/udp_init.c | 71 - vnet/vnet/ip/udp_local.c | 645 - vnet/vnet/ip/udp_packet.h | 65 - vnet/vnet/ip/udp_pg.c | 237 - vnet/vnet/ipsec-gre/dir.dox | 18 - vnet/vnet/ipsec-gre/error.def | 26 - vnet/vnet/ipsec-gre/interface.c | 311 - vnet/vnet/ipsec-gre/ipsec_gre.api | 79 - vnet/vnet/ipsec-gre/ipsec_gre.c | 407 - vnet/vnet/ipsec-gre/ipsec_gre.h | 114 - vnet/vnet/ipsec-gre/ipsec_gre_api.c | 190 - vnet/vnet/ipsec-gre/ipsec_gre_doc.md | 74 - vnet/vnet/ipsec-gre/node.c | 433 - vnet/vnet/ipsec/esp.h | 320 - vnet/vnet/ipsec/esp_decrypt.c | 430 - vnet/vnet/ipsec/esp_encrypt.c | 425 - vnet/vnet/ipsec/ikev2.c | 2186 --- vnet/vnet/ipsec/ikev2.h | 410 - vnet/vnet/ipsec/ikev2_cli.c | 479 - vnet/vnet/ipsec/ikev2_crypto.c | 765 - vnet/vnet/ipsec/ikev2_format.c | 155 - vnet/vnet/ipsec/ikev2_payload.c | 535 - vnet/vnet/ipsec/ikev2_priv.h | 321 - vnet/vnet/ipsec/ipsec.api | 457 - vnet/vnet/ipsec/ipsec.c | 581 - vnet/vnet/ipsec/ipsec.h | 344 - vnet/vnet/ipsec/ipsec_api.c | 537 - vnet/vnet/ipsec/ipsec_cli.c | 807 - vnet/vnet/ipsec/ipsec_format.c | 141 - vnet/vnet/ipsec/ipsec_if.c | 372 - vnet/vnet/ipsec/ipsec_if_in.c | 175 - vnet/vnet/ipsec/ipsec_if_out.c | 161 - vnet/vnet/ipsec/ipsec_input.c | 455 - vnet/vnet/ipsec/ipsec_output.c | 478 - vnet/vnet/l2/dir.dox | 24 - vnet/vnet/l2/feat_bitmap.c | 185 - vnet/vnet/l2/feat_bitmap.h | 96 - vnet/vnet/l2/l2.api | 38 - vnet/vnet/l2/l2_api.c | 140 - vnet/vnet/l2/l2_bd.c | 1079 -- vnet/vnet/l2/l2_bd.h | 150 - vnet/vnet/l2/l2_bvi.c | 40 - vnet/vnet/l2/l2_bvi.h | 117 - vnet/vnet/l2/l2_classify.h | 116 - vnet/vnet/l2/l2_efp_filter.c | 614 - vnet/vnet/l2/l2_efp_filter.h | 33 - vnet/vnet/l2/l2_fib.c | 857 - vnet/vnet/l2/l2_fib.h | 341 - vnet/vnet/l2/l2_flood.c | 568 - vnet/vnet/l2/l2_flood.h | 35 - vnet/vnet/l2/l2_fwd.c | 544 - vnet/vnet/l2/l2_fwd.h | 36 - vnet/vnet/l2/l2_input.c | 1116 -- vnet/vnet/l2/l2_input.h | 266 - vnet/vnet/l2/l2_input_acl.c | 434 - vnet/vnet/l2/l2_input_classify.c | 655 - vnet/vnet/l2/l2_input_vtr.c | 401 - vnet/vnet/l2/l2_input_vtr.h | 54 - vnet/vnet/l2/l2_learn.c | 597 - vnet/vnet/l2/l2_learn.h | 64 - vnet/vnet/l2/l2_output.c | 708 - vnet/vnet/l2/l2_output.h | 285 - vnet/vnet/l2/l2_output_acl.c | 358 - vnet/vnet/l2/l2_output_classify.c | 657 - vnet/vnet/l2/l2_patch.c | 452 - vnet/vnet/l2/l2_rw.c | 719 - vnet/vnet/l2/l2_rw.h | 95 - vnet/vnet/l2/l2_vtr.c | 770 - vnet/vnet/l2/l2_vtr.h | 270 - vnet/vnet/l2/l2_xcrw.c | 591 - vnet/vnet/l2/l2_xcrw.h | 91 - vnet/vnet/l2tp/decap.c | 309 - vnet/vnet/l2tp/encap.c | 238 - vnet/vnet/l2tp/l2tp.api | 126 - vnet/vnet/l2tp/l2tp.c | 739 - vnet/vnet/l2tp/l2tp.h | 147 - vnet/vnet/l2tp/l2tp_api.c | 267 - vnet/vnet/l2tp/packet.h | 44 - vnet/vnet/l2tp/pg.c | 106 - vnet/vnet/l3_types.h | 59 - vnet/vnet/lawful-intercept/lawful_intercept.c | 112 - vnet/vnet/lawful-intercept/lawful_intercept.h | 45 - vnet/vnet/lawful-intercept/node.c | 275 - vnet/vnet/lisp-cp/control.c | 4950 ----- vnet/vnet/lisp-cp/control.h | 314 - vnet/vnet/lisp-cp/gid_dictionary.c | 865 - vnet/vnet/lisp-cp/gid_dictionary.h | 120 - vnet/vnet/lisp-cp/lisp.api | 835 - vnet/vnet/lisp-cp/lisp_api.c | 1257 -- vnet/vnet/lisp-cp/lisp_cp_dpo.c | 117 - vnet/vnet/lisp-cp/lisp_cp_dpo.h | 45 - vnet/vnet/lisp-cp/lisp_cp_messages.h | 613 - vnet/vnet/lisp-cp/lisp_msg_serdes.c | 372 - vnet/vnet/lisp-cp/lisp_msg_serdes.h | 58 - vnet/vnet/lisp-cp/lisp_types.c | 1574 -- vnet/vnet/lisp-cp/lisp_types.h | 354 - vnet/vnet/lisp-cp/packets.c | 269 - vnet/vnet/lisp-cp/packets.h | 82 - vnet/vnet/lisp-gpe/decap.c | 501 - vnet/vnet/lisp-gpe/dir.dox | 26 - vnet/vnet/lisp-gpe/interface.c | 709 - vnet/vnet/lisp-gpe/lisp_gpe.api | 143 - vnet/vnet/lisp-gpe/lisp_gpe.c | 327 - vnet/vnet/lisp-gpe/lisp_gpe.h | 257 - vnet/vnet/lisp-gpe/lisp_gpe_adjacency.c | 542 - vnet/vnet/lisp-gpe/lisp_gpe_adjacency.h | 136 - vnet/vnet/lisp-gpe/lisp_gpe_api.c | 304 - vnet/vnet/lisp-gpe/lisp_gpe_error.def | 18 - vnet/vnet/lisp-gpe/lisp_gpe_fwd_entry.c | 1053 -- vnet/vnet/lisp-gpe/lisp_gpe_fwd_entry.h | 188 - vnet/vnet/lisp-gpe/lisp_gpe_packet.h | 149 - vnet/vnet/lisp-gpe/lisp_gpe_sub_interface.c | 278 - vnet/vnet/lisp-gpe/lisp_gpe_sub_interface.h | 157 - vnet/vnet/lisp-gpe/lisp_gpe_tenant.c | 330 - vnet/vnet/lisp-gpe/lisp_gpe_tenant.h | 88 - vnet/vnet/lisp-gpe/lisp_gpe_tunnel.c | 289 - vnet/vnet/lisp-gpe/lisp_gpe_tunnel.h | 89 - vnet/vnet/lisp-gpe/rfc.txt | 826 - vnet/vnet/llc/llc.c | 241 - vnet/vnet/llc/llc.h | 194 - vnet/vnet/llc/node.c | 331 - vnet/vnet/llc/pg.c | 113 - vnet/vnet/lldp/dir.dox | 18 - vnet/vnet/lldp/lldp_cli.c | 646 - vnet/vnet/lldp/lldp_doc.md | 84 - vnet/vnet/lldp/lldp_input.c | 302 - vnet/vnet/lldp/lldp_node.c | 341 - vnet/vnet/lldp/lldp_node.h | 145 - vnet/vnet/lldp/lldp_output.c | 216 - vnet/vnet/lldp/lldp_protocol.h | 142 - vnet/vnet/map/examples/gen-rules.py | 186 - vnet/vnet/map/examples/health_check.c | 109 - vnet/vnet/map/examples/test_map.py | 141 - vnet/vnet/map/gen-rules.py | 107 - vnet/vnet/map/ip4_map.c | 813 - vnet/vnet/map/ip4_map_t.c | 1363 -- vnet/vnet/map/ip6_map.c | 1269 -- vnet/vnet/map/ip6_map_t.c | 1517 -- vnet/vnet/map/map.api | 178 - vnet/vnet/map/map.c | 2166 --- vnet/vnet/map/map.h | 591 - vnet/vnet/map/map_api.c | 295 - vnet/vnet/map/map_doc.md | 69 - vnet/vnet/map/map_dpo.c | 191 - vnet/vnet/map/map_dpo.h | 67 - vnet/vnet/map/test.c | 205 - vnet/vnet/mcast/mcast.c | 565 - vnet/vnet/mcast/mcast.h | 50 - vnet/vnet/mcast/mcast_test.c | 149 - vnet/vnet/misc.c | 124 - vnet/vnet/mpls/error.def | 31 - vnet/vnet/mpls/interface.c | 121 - vnet/vnet/mpls/mpls.c | 511 - vnet/vnet/mpls/mpls.h | 172 - vnet/vnet/mpls/mpls_features.c | 156 - vnet/vnet/mpls/mpls_lookup.c | 531 - vnet/vnet/mpls/mpls_output.c | 479 - vnet/vnet/mpls/mpls_tunnel.c | 787 - vnet/vnet/mpls/mpls_tunnel.h | 98 - vnet/vnet/mpls/mpls_types.h | 39 - vnet/vnet/mpls/node.c | 303 - vnet/vnet/mpls/packet.h | 125 - vnet/vnet/mpls/pg.c | 71 - vnet/vnet/osi/node.c | 326 - vnet/vnet/osi/osi.c | 201 - vnet/vnet/osi/osi.h | 171 - vnet/vnet/osi/pg.c | 106 - vnet/vnet/pg/cli.c | 636 - vnet/vnet/pg/edit.c | 186 - vnet/vnet/pg/edit.h | 210 - vnet/vnet/pg/example.script | 6 - vnet/vnet/pg/init.c | 72 - vnet/vnet/pg/input.c | 1667 -- vnet/vnet/pg/output.c | 85 - vnet/vnet/pg/pg.h | 383 - vnet/vnet/pg/stream.c | 497 - vnet/vnet/pipeline.h | 456 - vnet/vnet/plugin/p1.c | 52 - vnet/vnet/plugin/plugin.h | 32 - vnet/vnet/policer/node_funcs.c | 938 - vnet/vnet/policer/police.h | 214 - vnet/vnet/policer/policer.c | 528 - vnet/vnet/policer/policer.h | 107 - vnet/vnet/policer/xlate.c | 1505 -- vnet/vnet/policer/xlate.h | 186 - vnet/vnet/ppp/error.def | 42 - vnet/vnet/ppp/node.c | 368 - vnet/vnet/ppp/packet.h | 199 - vnet/vnet/ppp/pg.c | 114 - vnet/vnet/ppp/ppp.c | 261 - vnet/vnet/ppp/ppp.h | 135 - vnet/vnet/replication.c | 293 - vnet/vnet/replication.h | 136 - vnet/vnet/rewrite.c | 329 - vnet/vnet/rewrite.h | 305 - vnet/vnet/snap/node.c | 353 - vnet/vnet/snap/pg.c | 116 - vnet/vnet/snap/snap.c | 204 - vnet/vnet/snap/snap.h | 209 - vnet/vnet/span/node.c | 286 - vnet/vnet/span/span.api | 60 - vnet/vnet/span/span.c | 197 - vnet/vnet/span/span.h | 62 - vnet/vnet/span/span.md | 65 - vnet/vnet/span/span_api.c | 153 - vnet/vnet/sr/dir.dox | 25 - vnet/vnet/sr/examples/sr_multicastmap.script | 4 - vnet/vnet/sr/rfc_draft_05.txt | 1265 -- vnet/vnet/sr/sr.c | 3333 ---- vnet/vnet/sr/sr.h | 262 - vnet/vnet/sr/sr_error.def | 20 - vnet/vnet/sr/sr_fix_dst_error.def | 17 - vnet/vnet/sr/sr_packet.h | 251 - vnet/vnet/sr/sr_replicate.c | 490 - vnet/vnet/srp/format.c | 147 - vnet/vnet/srp/interface.c | 458 - vnet/vnet/srp/node.c | 932 - vnet/vnet/srp/packet.h | 204 - vnet/vnet/srp/pg.c | 157 - vnet/vnet/srp/srp.h | 222 - vnet/vnet/unix/gdb_funcs.c | 171 - vnet/vnet/unix/pcap.c | 241 - vnet/vnet/unix/pcap.h | 230 - vnet/vnet/unix/pcap2pg.c | 182 - vnet/vnet/unix/tap.api | 123 - vnet/vnet/unix/tap_api.c | 257 - vnet/vnet/unix/tapcli.c | 1328 -- vnet/vnet/unix/tapcli.h | 52 - vnet/vnet/unix/tuntap.c | 1000 -- vnet/vnet/unix/tuntap.h | 36 - vnet/vnet/vnet.h | 96 - vnet/vnet/vnet_all_api_h.h | 57 - vnet/vnet/vnet_msg_enum.h | 37 - vnet/vnet/vxlan-gpe/decap.c | 733 - vnet/vnet/vxlan-gpe/dir.dox | 32 - vnet/vnet/vxlan-gpe/encap.c | 388 - vnet/vnet/vxlan-gpe/vxlan-gpe-rfc.txt | 868 - vnet/vnet/vxlan-gpe/vxlan_gpe.api | 61 - vnet/vnet/vxlan-gpe/vxlan_gpe.c | 659 - vnet/vnet/vxlan-gpe/vxlan_gpe.h | 221 - vnet/vnet/vxlan-gpe/vxlan_gpe_api.c | 249 - vnet/vnet/vxlan-gpe/vxlan_gpe_error.def | 16 - vnet/vnet/vxlan-gpe/vxlan_gpe_packet.h | 110 - vnet/vnet/vxlan/decap.c | 1130 -- vnet/vnet/vxlan/dir.dox | 24 - vnet/vnet/vxlan/encap.c | 553 - vnet/vnet/vxlan/vxlan.api | 81 - vnet/vnet/vxlan/vxlan.c | 899 - vnet/vnet/vxlan/vxlan.h | 199 - vnet/vnet/vxlan/vxlan_api.c | 253 - vnet/vnet/vxlan/vxlan_error.def | 17 - vnet/vnet/vxlan/vxlan_packet.h | 69 - vpp-api-test/Makefile.am | 37 - vpp-api-test/configure.ac | 40 - vpp-api-test/scripts/vppctl | 121 - vpp-api-test/vat/api_format.c | 17827 ------------------ vpp-api-test/vat/json_format.c | 304 - vpp-api-test/vat/json_format.h | 254 - vpp-api-test/vat/json_test.c | 75 - vpp-api-test/vat/main.c | 418 - vpp-api-test/vat/plugin.c | 201 - vpp-api-test/vat/plugin.h | 61 - vpp-api-test/vat/plugin_api.c | 216 - vpp-api-test/vat/restart.c | 246 - vpp-api-test/vat/vat.h | 257 - vpp-api/Makefile.am | 4 +- vpp-api/configure.ac | 1 - vpp-api/java/Makefile.am | 3 +- vpp-api/java/jvpp-core/jvpp_core.c | 8 +- vpp-api/java/jvpp-registry/jvpp_registry.c | 10 +- vpp-api/java/jvpp/gen/jvpp_gen.py | 5 + vpp-api/python/Makefile.am | 51 - vpp-api/python/README.rst | 0 vpp-api/python/pneum/pneum.c | 259 - vpp-api/python/pneum/pneum.h | 31 - vpp-api/python/pneum/test_pneum.c | 143 - vpp-api/python/setup.cfg | 5 - vpp-api/python/setup.py | 34 - vpp-api/python/tests/test_cli.py | 52 - vpp-api/python/tests/test_modules.py | 18 - vpp-api/python/tests/test_papi.py | 119 - vpp-api/python/tests/test_version.py | 35 - vpp-api/python/tests/test_vpp_papi2.py | 487 - vpp-api/python/vpp_papi/__init__.py | 3 - vpp-api/python/vpp_papi/pneum_wrap.c | 200 - vpp-api/python/vpp_papi/vpp_papi.py | 450 - vpp/Makefile.am | 166 - vpp/app/l2t.c | 557 - vpp/app/l2t_l2.c | 267 - vpp/app/sticky_hash.c | 581 - vpp/app/version.c | 102 - vpp/app/vpe_cli.c | 123 - vpp/conf/80-vpp.conf | 15 - vpp/conf/startup.conf | 99 - vpp/conf/startup.uiopcigeneric.conf | 18 - vpp/configure.ac | 80 - vpp/oam/oam.c | 648 - vpp/oam/oam.h | 96 - vpp/stats/stats.c | 987 - vpp/stats/stats.h | 76 - vpp/suffix-rules.mk | 1 - vpp/vnet/main.c | 414 - vpp/vpp-api/api.c | 4921 ----- vpp/vpp-api/api_format.c | 1 - vpp/vpp-api/api_main.c | 192 - vpp/vpp-api/custom_dump.c | 3139 ---- vpp/vpp-api/gmon.c | 319 - vpp/vpp-api/json_format.c | 304 - vpp/vpp-api/json_format.h | 254 - vpp/vpp-api/summary_stats_client.c | 302 - vpp/vpp-api/test_client.c | 1531 -- vpp/vpp-api/test_ha.c | 249 - vpp/vpp-api/vat.h | 1 - vpp/vpp-api/vpe.api | 2782 --- vpp/vpp-api/vpe_all_api_h.h | 37 - vpp/vpp-api/vpe_msg_enum.h | 37 - vpp/vpp-api/vpp_get_metrics.c | 253 - vppapigen/Makefile.am | 29 - vppapigen/configure.ac | 14 - vppapigen/gram.y | 90 - vppapigen/lex.c | 1067 -- vppapigen/lex.h | 50 - vppapigen/node.c | 1531 -- vppapigen/node.h | 94 - vppinfra/.gitignore | 1 - vppinfra/INSTALL | 236 - vppinfra/Make.defs | 129 - vppinfra/Makefile.am | 275 - vppinfra/README | 43 - vppinfra/configure.ac | 52 - vppinfra/dir.dox | 19 - vppinfra/mkinstalldirs | 111 - vppinfra/tools/dir.dox | 19 - vppinfra/tools/elftool.c | 464 - vppinfra/unix_error.def | 145 - vppinfra/vppinfra/anneal.c | 172 - vppinfra/vppinfra/anneal.h | 89 - vppinfra/vppinfra/asm_mips.h | 351 - vppinfra/vppinfra/asm_x86.c | 1947 -- vppinfra/vppinfra/asm_x86.h | 125 - vppinfra/vppinfra/backtrace.c | 267 - vppinfra/vppinfra/bihash_24_8.h | 85 - vppinfra/vppinfra/bihash_8_8.h | 98 - vppinfra/vppinfra/bihash_doc.h | 149 - vppinfra/vppinfra/bihash_template.c | 455 - vppinfra/vppinfra/bihash_template.h | 214 - vppinfra/vppinfra/bitmap.h | 774 - vppinfra/vppinfra/bitops.h | 179 - vppinfra/vppinfra/byte_order.h | 202 - vppinfra/vppinfra/cache.h | 104 - vppinfra/vppinfra/clib.h | 359 - vppinfra/vppinfra/cpu.c | 133 - vppinfra/vppinfra/cpu.h | 112 - vppinfra/vppinfra/dir.dox | 19 - vppinfra/vppinfra/dlist.h | 156 - vppinfra/vppinfra/elf.c | 2040 --- vppinfra/vppinfra/elf.h | 1062 -- vppinfra/vppinfra/elf_clib.c | 377 - vppinfra/vppinfra/elf_clib.h | 144 - vppinfra/vppinfra/elog.c | 1061 -- vppinfra/vppinfra/elog.h | 460 - vppinfra/vppinfra/error.c | 292 - vppinfra/vppinfra/error.h | 201 - vppinfra/vppinfra/error_bootstrap.h | 106 - vppinfra/vppinfra/fheap.c | 473 - vppinfra/vppinfra/fheap.h | 140 - vppinfra/vppinfra/fifo.c | 137 - vppinfra/vppinfra/fifo.h | 304 - vppinfra/vppinfra/format.c | 814 - vppinfra/vppinfra/format.h | 331 - vppinfra/vppinfra/graph.c | 182 - vppinfra/vppinfra/graph.h | 127 - vppinfra/vppinfra/hash.c | 1095 -- vppinfra/vppinfra/hash.h | 699 - vppinfra/vppinfra/heap.c | 828 - vppinfra/vppinfra/heap.h | 357 - vppinfra/vppinfra/longjmp.S | 690 - vppinfra/vppinfra/longjmp.h | 124 - vppinfra/vppinfra/macros.c | 266 - vppinfra/vppinfra/macros.h | 54 - vppinfra/vppinfra/math.h | 63 - vppinfra/vppinfra/md5.c | 317 - vppinfra/vppinfra/md5.h | 57 - vppinfra/vppinfra/mem.h | 291 - vppinfra/vppinfra/mem_mheap.c | 165 - vppinfra/vppinfra/memcheck.h | 317 - vppinfra/vppinfra/memcpy_avx.h | 293 - vppinfra/vppinfra/memcpy_sse3.h | 355 - vppinfra/vppinfra/mhash.c | 408 - vppinfra/vppinfra/mhash.h | 179 - vppinfra/vppinfra/mheap.c | 1649 -- vppinfra/vppinfra/mheap.h | 94 - vppinfra/vppinfra/mheap_bootstrap.h | 374 - vppinfra/vppinfra/mod_test_hash.c | 27 - vppinfra/vppinfra/os.h | 72 - vppinfra/vppinfra/pfhash.c | 689 - vppinfra/vppinfra/pfhash.h | 276 - vppinfra/vppinfra/phash.c | 1017 -- vppinfra/vppinfra/phash.h | 194 - vppinfra/vppinfra/pipeline.h | 176 - vppinfra/vppinfra/pool.h | 405 - vppinfra/vppinfra/ptclosure.c | 125 - vppinfra/vppinfra/ptclosure.h | 40 - vppinfra/vppinfra/qhash.c | 858 - vppinfra/vppinfra/qhash.h | 169 - vppinfra/vppinfra/qsort.c | 269 - vppinfra/vppinfra/random.c | 51 - vppinfra/vppinfra/random.h | 178 - vppinfra/vppinfra/random_buffer.c | 86 - vppinfra/vppinfra/random_buffer.h | 118 - vppinfra/vppinfra/random_isaac.c | 434 - vppinfra/vppinfra/random_isaac.h | 81 - vppinfra/vppinfra/serialize.c | 1254 -- vppinfra/vppinfra/serialize.h | 443 - vppinfra/vppinfra/slist.c | 336 - vppinfra/vppinfra/slist.h | 145 - vppinfra/vppinfra/smp.c | 325 - vppinfra/vppinfra/smp.h | 81 - vppinfra/vppinfra/smp_fifo.c | 91 - vppinfra/vppinfra/smp_fifo.h | 313 - vppinfra/vppinfra/socket.c | 422 - vppinfra/vppinfra/socket.h | 160 - vppinfra/vppinfra/sparse_vec.h | 244 - vppinfra/vppinfra/std-formats.c | 330 - vppinfra/vppinfra/string.c | 94 - vppinfra/vppinfra/string.h | 83 - vppinfra/vppinfra/test_bihash_template.c | 297 - vppinfra/vppinfra/test_dlist.c | 193 - vppinfra/vppinfra/test_elf.c | 217 - vppinfra/vppinfra/test_elog.c | 262 - vppinfra/vppinfra/test_fifo.c | 144 - vppinfra/vppinfra/test_format.c | 199 - vppinfra/vppinfra/test_hash.c | 458 - vppinfra/vppinfra/test_heap.c | 198 - vppinfra/vppinfra/test_longjmp.c | 129 - vppinfra/vppinfra/test_macros.c | 64 - vppinfra/vppinfra/test_md5.c | 141 - vppinfra/vppinfra/test_mheap.c | 242 - vppinfra/vppinfra/test_pfhash.c | 322 - vppinfra/vppinfra/test_phash.c | 149 - vppinfra/vppinfra/test_pool.c | 86 - vppinfra/vppinfra/test_pool_iterate.c | 59 - vppinfra/vppinfra/test_ptclosure.c | 212 - vppinfra/vppinfra/test_qhash.c | 333 - vppinfra/vppinfra/test_random.c | 148 - vppinfra/vppinfra/test_random_isaac.c | 142 - vppinfra/vppinfra/test_serialize.c | 274 - vppinfra/vppinfra/test_slist.c | 228 - vppinfra/vppinfra/test_socket.c | 134 - vppinfra/vppinfra/test_time.c | 104 - vppinfra/vppinfra/test_timing_wheel.c | 389 - vppinfra/vppinfra/test_vec.c | 1159 -- vppinfra/vppinfra/test_vec.h | 243 - vppinfra/vppinfra/test_vhash.c | 757 - vppinfra/vppinfra/test_zvec.c | 117 - vppinfra/vppinfra/time.c | 226 - vppinfra/vppinfra/time.h | 298 - vppinfra/vppinfra/timer.c | 322 - vppinfra/vppinfra/timer.h | 46 - vppinfra/vppinfra/timing_wheel.c | 750 - vppinfra/vppinfra/timing_wheel.h | 155 - vppinfra/vppinfra/types.h | 174 - vppinfra/vppinfra/unformat.c | 1077 -- vppinfra/vppinfra/unix-formats.c | 918 - vppinfra/vppinfra/unix-kelog.c | 415 - vppinfra/vppinfra/unix-misc.c | 242 - vppinfra/vppinfra/unix.h | 64 - vppinfra/vppinfra/valgrind.h | 4030 ----- vppinfra/vppinfra/vec.c | 171 - vppinfra/vppinfra/vec.h | 973 - vppinfra/vppinfra/vec_bootstrap.h | 201 - vppinfra/vppinfra/vector.c | 54 - vppinfra/vppinfra/vector.h | 268 - vppinfra/vppinfra/vector_altivec.h | 178 - vppinfra/vppinfra/vector_funcs.h | 334 - vppinfra/vppinfra/vector_iwmmxt.h | 149 - vppinfra/vppinfra/vector_neon.h | 71 - vppinfra/vppinfra/vector_sse2.h | 711 - vppinfra/vppinfra/vhash.c | 772 - vppinfra/vppinfra/vhash.h | 850 - vppinfra/vppinfra/vm_linux_kernel.h | 78 - vppinfra/vppinfra/vm_standalone.h | 74 - vppinfra/vppinfra/vm_unix.h | 106 - vppinfra/vppinfra/xxhash.h | 86 - vppinfra/vppinfra/xy.h | 56 - vppinfra/vppinfra/zvec.c | 442 - vppinfra/vppinfra/zvec.h | 166 - 2038 files changed, 380675 insertions(+), 381455 deletions(-) delete mode 100644 build-data/packages/cavium-dpdk.mk create mode 100644 build-data/packages/src.mk delete mode 100644 build-data/packages/svm.mk delete mode 100644 build-data/packages/vlib-api-cavium-dpdk.mk delete mode 100644 build-data/packages/vlib-api.mk delete mode 100644 build-data/packages/vlib-cavium-dpdk.mk delete mode 100644 build-data/packages/vlib.mk delete mode 100644 build-data/packages/vnet-cavium-dpdk.mk delete mode 100644 build-data/packages/vpp-api-test-cavium-dpdk.mk delete mode 100644 build-data/packages/vpp-api-test.mk delete mode 100644 build-data/packages/vpp-cavium-dpdk.mk delete mode 100644 build-data/packages/vppinfra.mk delete mode 100644 build-data/suffix-rules.mk create mode 100644 build-root/packages/src.mk create mode 100644 build-root/packages/tools.mk delete mode 100644 build-root/packages/vppapigen.mk delete mode 100644 g2/Makefile.am delete mode 100644 g2/clib.c delete mode 100644 g2/configure.ac delete mode 100644 g2/cpel.c delete mode 100644 g2/cpel.h delete mode 100644 g2/events.c delete mode 100644 g2/g2.h delete mode 100644 g2/g2version.c delete mode 100644 g2/main.c delete mode 100644 g2/menu1.c delete mode 100644 g2/mkversion.c delete mode 100644 g2/pointsel.c delete mode 100644 g2/props.c delete mode 100644 g2/props.h delete mode 100644 g2/view1.c delete mode 100644 perftool/Makefile.am delete mode 100644 perftool/c2cpel.c delete mode 100644 perftool/configure.ac delete mode 100644 perftool/cpel.h delete mode 100644 perftool/cpel_util.c delete mode 100644 perftool/cpel_util.h delete mode 100644 perftool/cpelatency.c delete mode 100644 perftool/cpeldump.c delete mode 100644 perftool/cpelinreg.c delete mode 100644 perftool/cpelstate.c delete mode 100644 perftool/delsvec.c delete mode 100644 perftool/linreg.c delete mode 100644 perftool/new.cpel delete mode 100644 perftool/new.elog delete mode 100644 perftool/props.c delete mode 100644 plugins/flowperpkt-plugin/Makefile.am delete mode 100644 plugins/flowperpkt-plugin/configure.ac delete mode 100644 plugins/flowperpkt-plugin/flowperpkt/flowperpkt.api delete mode 100644 plugins/flowperpkt-plugin/flowperpkt/flowperpkt.c delete mode 100644 plugins/flowperpkt-plugin/flowperpkt/flowperpkt.h delete mode 100644 plugins/flowperpkt-plugin/flowperpkt/flowperpkt_all_api_h.h delete mode 100644 plugins/flowperpkt-plugin/flowperpkt/flowperpkt_msg_enum.h delete mode 100644 plugins/flowperpkt-plugin/flowperpkt/flowperpkt_test.c delete mode 100644 plugins/flowperpkt-plugin/flowperpkt/l2_node.c delete mode 100644 plugins/flowperpkt-plugin/flowperpkt/node.c delete mode 100644 plugins/flowperpkt-plugin/flowperpkt_plugin_doc.md delete mode 100644 plugins/ila-plugin/Makefile.am delete mode 100644 plugins/ila-plugin/configure.ac delete mode 100644 plugins/ila-plugin/ila/ila.c delete mode 100644 plugins/ila-plugin/ila/ila.h delete mode 100644 plugins/sixrd-plugin/Makefile.am delete mode 100644 plugins/sixrd-plugin/configure.ac delete mode 100644 plugins/sixrd-plugin/sixrd/ip4_sixrd.c delete mode 100644 plugins/sixrd-plugin/sixrd/ip6_sixrd.c delete mode 100644 plugins/sixrd-plugin/sixrd/sixrd.c delete mode 100644 plugins/sixrd-plugin/sixrd/sixrd.h delete mode 100644 plugins/sixrd-plugin/sixrd/sixrd_dpo.c delete mode 100644 plugins/sixrd-plugin/sixrd/sixrd_dpo.h create mode 100644 src/Makefile.am create mode 100644 src/configure.ac create mode 100644 src/examples/vlib/dir.dox create mode 100644 src/examples/vlib/main_stub.c create mode 100644 src/examples/vlib/mc_test.c create mode 100644 src/examples/vlib/plex_test.c create mode 100644 src/g2.am create mode 100644 src/perftool.am create mode 100644 src/plugins/Makefile.am create mode 100644 src/plugins/flowperpkt.am create mode 100644 src/plugins/flowperpkt/flowperpkt.api create mode 100644 src/plugins/flowperpkt/flowperpkt.c create mode 100644 src/plugins/flowperpkt/flowperpkt.h create mode 100644 src/plugins/flowperpkt/flowperpkt_all_api_h.h create mode 100644 src/plugins/flowperpkt/flowperpkt_msg_enum.h create mode 100644 src/plugins/flowperpkt/flowperpkt_plugin_doc.md create mode 100644 src/plugins/flowperpkt/flowperpkt_test.c create mode 100644 src/plugins/flowperpkt/l2_node.c create mode 100644 src/plugins/flowperpkt/node.c create mode 100644 src/plugins/ila.am create mode 100644 src/plugins/ila/ila.c create mode 100644 src/plugins/ila/ila.h create mode 100644 src/plugins/sixrd.am create mode 100644 src/plugins/sixrd/ip4_sixrd.c create mode 100644 src/plugins/sixrd/ip6_sixrd.c create mode 100644 src/plugins/sixrd/sixrd.c create mode 100644 src/plugins/sixrd/sixrd.h create mode 100644 src/plugins/sixrd/sixrd_dpo.c create mode 100644 src/plugins/sixrd/sixrd_dpo.h create mode 100644 src/scripts/vnet/arp4 create mode 100644 src/scripts/vnet/arp4-mpls create mode 100644 src/scripts/vnet/arp6 create mode 100644 src/scripts/vnet/bvi create mode 100644 src/scripts/vnet/dhcp/dhcpd.conf create mode 100644 src/scripts/vnet/dhcp/left-ping-target.sh create mode 100644 src/scripts/vnet/dhcp/leftpeer.conf create mode 100644 src/scripts/vnet/icmp create mode 100644 src/scripts/vnet/icmp6 create mode 100644 src/scripts/vnet/ige create mode 100644 src/scripts/vnet/ip6 create mode 100644 src/scripts/vnet/ip6-hbh create mode 100644 src/scripts/vnet/ixge create mode 100644 src/scripts/vnet/l2efpfilter create mode 100644 src/scripts/vnet/l2efpfilter_perf create mode 100644 src/scripts/vnet/l2fib create mode 100644 src/scripts/vnet/l2fib_perf create mode 100644 src/scripts/vnet/l2fib_xc create mode 100644 src/scripts/vnet/l2flood create mode 100644 src/scripts/vnet/l2tp create mode 100755 src/scripts/vnet/leftpeer/leftpeer-classify create mode 100644 src/scripts/vnet/leftpeer/leftpeer-classify6 create mode 100644 src/scripts/vnet/leftpeer/leftpeer-classifyl2 create mode 100644 src/scripts/vnet/leftpeer/leftpeer-dhcp create mode 100644 src/scripts/vnet/leftpeer/leftpeer-ioam.conf create mode 100644 src/scripts/vnet/leftpeer/leftpeer-l3vxlan.conf create mode 100644 src/scripts/vnet/leftpeer/leftpeer-lisp.conf create mode 100644 src/scripts/vnet/leftpeer/leftpeer-mpls.conf create mode 100644 src/scripts/vnet/leftpeer/leftpeer-sr.conf create mode 100644 src/scripts/vnet/leftpeer/leftpeer-vxlan.conf create mode 100644 src/scripts/vnet/leftpeer/leftpeer.script create mode 100644 src/scripts/vnet/lfib/ip4-to-mpls create mode 100644 src/scripts/vnet/lfib/mpls-pop-to-mpls create mode 100644 src/scripts/vnet/lfib/mpls-to-ip4 create mode 100644 src/scripts/vnet/lfib/mpls-to-mpls create mode 100644 src/scripts/vnet/mpls-o-ethernet/leftpeer.conf create mode 100644 src/scripts/vnet/mpls-o-ethernet/pg create mode 100644 src/scripts/vnet/mpls-o-ethernet/rightpeer.conf create mode 100644 src/scripts/vnet/mpls-o-ethernet/single.conf create mode 100644 src/scripts/vnet/mpls-o-gre/dhcpd.conf create mode 100644 src/scripts/vnet/mpls-o-gre/leftpeer.conf create mode 100644 src/scripts/vnet/mpls-o-gre/rightpeer.conf create mode 100644 src/scripts/vnet/mpls-tunnel create mode 100644 src/scripts/vnet/pcap create mode 100644 src/scripts/vnet/probe4 create mode 100644 src/scripts/vnet/probe6 create mode 100644 src/scripts/vnet/rewrite create mode 100644 src/scripts/vnet/rightpeer/rightpeer-ioam.conf create mode 100644 src/scripts/vnet/rightpeer/rightpeer-l3vxlan.conf create mode 100644 src/scripts/vnet/rightpeer/rightpeer-lisp.conf create mode 100644 src/scripts/vnet/rightpeer/rightpeer-mpls-l2.conf create mode 100644 src/scripts/vnet/rightpeer/rightpeer-mpls.conf create mode 100644 src/scripts/vnet/rightpeer/rightpeer-sr.conf create mode 100644 src/scripts/vnet/rightpeer/rightpeer-vxlan.conf create mode 100644 src/scripts/vnet/rightpeer/rightpeer.script create mode 100644 src/scripts/vnet/rpf create mode 100644 src/scripts/vnet/rtt-test create mode 100644 src/scripts/vnet/snat create mode 100644 src/scripts/vnet/snat_static create mode 100644 src/scripts/vnet/snat_static_with_port create mode 100644 src/scripts/vnet/source_and_port_range_check create mode 100644 src/scripts/vnet/speed create mode 100755 src/scripts/vnet/sr/left-linux-ping.sh create mode 100644 src/scripts/vnet/sr/leftpeer.conf create mode 100755 src/scripts/vnet/sr/right-linux-ping.sh create mode 100644 src/scripts/vnet/sr/rightpeer.conf create mode 100755 src/scripts/vnet/sr/srlocal.sh create mode 100644 src/scripts/vnet/srp create mode 100644 src/scripts/vnet/tcp create mode 100644 src/scripts/vnet/tcp-test create mode 100644 src/scripts/vnet/tf-ucs-1 create mode 100644 src/scripts/vnet/urpf create mode 100644 src/scripts/vnet/virl/ip6sr.virl create mode 100644 src/scripts/vnet/virl/ip6sr_notes.txt create mode 100644 src/scripts/vnet/virl/mplsogre.virl create mode 100644 src/scripts/vnet/virl/simple.virl create mode 100644 src/scripts/vnet/vlan create mode 100755 src/scripts/vppctl create mode 100644 src/suffix-rules.mk create mode 100644 src/svm.am create mode 100644 src/svm/dir.dox create mode 100644 src/svm/persist.c create mode 100644 src/svm/ssvm.c create mode 100644 src/svm/ssvm.h create mode 100644 src/svm/svm.c create mode 100644 src/svm/svm.h create mode 100644 src/svm/svm_test.c create mode 100644 src/svm/svmdb.c create mode 100644 src/svm/svmdb.h create mode 100644 src/svm/svmdbtool.c create mode 100644 src/svm/svmtool.c create mode 100644 src/tests/vnet/README create mode 100644 src/tests/vnet/lisp-cp/test_cp_serdes.c create mode 100644 src/tests/vnet/lisp-cp/test_lisp_types.c create mode 100644 src/tests/vnet/lisp-gpe/test.c create mode 100644 src/tools/elftool/dir.dox create mode 100644 src/tools/elftool/elftool.c create mode 100644 src/tools/g2/clib.c create mode 100644 src/tools/g2/configure.ac create mode 100644 src/tools/g2/cpel.c create mode 100644 src/tools/g2/cpel.h create mode 100644 src/tools/g2/events.c create mode 100644 src/tools/g2/g2.h create mode 100644 src/tools/g2/g2version.c create mode 100644 src/tools/g2/main.c create mode 100644 src/tools/g2/menu1.c create mode 100644 src/tools/g2/mkversion.c create mode 100644 src/tools/g2/pointsel.c create mode 100644 src/tools/g2/props.c create mode 100644 src/tools/g2/props.h create mode 100644 src/tools/g2/view1.c create mode 100644 src/tools/perftool/c2cpel.c create mode 100644 src/tools/perftool/configure.ac create mode 100644 src/tools/perftool/cpel.h create mode 100644 src/tools/perftool/cpel_util.c create mode 100644 src/tools/perftool/cpel_util.h create mode 100644 src/tools/perftool/cpelatency.c create mode 100644 src/tools/perftool/cpeldump.c create mode 100644 src/tools/perftool/cpelinreg.c create mode 100644 src/tools/perftool/cpelstate.c create mode 100644 src/tools/perftool/delsvec.c create mode 100644 src/tools/perftool/linreg.c create mode 100644 src/tools/perftool/new.cpel create mode 100644 src/tools/perftool/new.elog create mode 100644 src/tools/perftool/props.c create mode 100644 src/tools/vppapigen/configure.ac create mode 100644 src/tools/vppapigen/gram.y create mode 100644 src/tools/vppapigen/lex.c create mode 100644 src/tools/vppapigen/lex.h create mode 100644 src/tools/vppapigen/node.c create mode 100644 src/tools/vppapigen/node.h create mode 100644 src/vat/api_format.c create mode 100644 src/vat/json_format.c create mode 100644 src/vat/json_format.h create mode 100644 src/vat/json_test.c create mode 100644 src/vat/main.c create mode 100644 src/vat/plugin.c create mode 100644 src/vat/plugin.h create mode 100644 src/vat/plugin_api.c create mode 100644 src/vat/restart.c create mode 100644 src/vat/vat.h create mode 100644 src/vlib-api.am create mode 100644 src/vlib.am create mode 100644 src/vlib/buffer.c create mode 100644 src/vlib/buffer.h create mode 100644 src/vlib/buffer_funcs.h create mode 100644 src/vlib/buffer_node.h create mode 100644 src/vlib/cli.c create mode 100644 src/vlib/cli.h create mode 100644 src/vlib/cli_funcs.h create mode 100644 src/vlib/counter.c create mode 100644 src/vlib/counter.h create mode 100644 src/vlib/defs.h create mode 100644 src/vlib/dir.dox create mode 100644 src/vlib/elog_samples.c create mode 100644 src/vlib/error.c create mode 100644 src/vlib/error.h create mode 100644 src/vlib/error_funcs.h create mode 100644 src/vlib/format.c create mode 100644 src/vlib/format_funcs.h create mode 100644 src/vlib/global_funcs.h create mode 100644 src/vlib/i2c.c create mode 100644 src/vlib/i2c.h create mode 100644 src/vlib/init.c create mode 100644 src/vlib/init.h create mode 100644 src/vlib/lex.c create mode 100644 src/vlib/lex.h create mode 100644 src/vlib/main.c create mode 100644 src/vlib/main.h create mode 100644 src/vlib/mc.c create mode 100644 src/vlib/mc.h create mode 100644 src/vlib/node.c create mode 100644 src/vlib/node.h create mode 100644 src/vlib/node_cli.c create mode 100644 src/vlib/node_format.c create mode 100644 src/vlib/node_funcs.h create mode 100644 src/vlib/parse.c create mode 100644 src/vlib/parse.h create mode 100644 src/vlib/parse_builtin.c create mode 100644 src/vlib/pci/linux_pci.c create mode 100644 src/vlib/pci/pci.c create mode 100644 src/vlib/pci/pci.h create mode 100644 src/vlib/pci/pci_config.h create mode 100644 src/vlib/physmem.h create mode 100644 src/vlib/threads.c create mode 100644 src/vlib/threads.h create mode 100644 src/vlib/threads_cli.c create mode 100644 src/vlib/trace.c create mode 100644 src/vlib/trace.h create mode 100644 src/vlib/trace_funcs.h create mode 100644 src/vlib/unix/cj.c create mode 100644 src/vlib/unix/cj.h create mode 100644 src/vlib/unix/cli.c create mode 100644 src/vlib/unix/dir.dox create mode 100644 src/vlib/unix/input.c create mode 100644 src/vlib/unix/main.c create mode 100644 src/vlib/unix/mc_socket.c create mode 100644 src/vlib/unix/mc_socket.h create mode 100644 src/vlib/unix/physmem.c create mode 100644 src/vlib/unix/physmem.h create mode 100644 src/vlib/unix/plugin.c create mode 100644 src/vlib/unix/plugin.h create mode 100644 src/vlib/unix/unix.h create mode 100644 src/vlib/unix/util.c create mode 100644 src/vlib/vlib.h create mode 100644 src/vlib/vlib_process_doc.h create mode 100644 src/vlibapi/api.h create mode 100644 src/vlibapi/api_helper_macros.h create mode 100644 src/vlibapi/api_shared.c create mode 100644 src/vlibapi/node_serialize.c create mode 100644 src/vlibmemory/api.h create mode 100644 src/vlibmemory/memclnt.api create mode 100644 src/vlibmemory/memory_client.c create mode 100644 src/vlibmemory/memory_shared.c create mode 100644 src/vlibmemory/memory_vlib.c create mode 100644 src/vlibmemory/unix_shared_memory_queue.c create mode 100644 src/vlibmemory/unix_shared_memory_queue.h create mode 100644 src/vlibmemory/vl_memory_api_h.h create mode 100644 src/vlibmemory/vl_memory_msg_enum.h create mode 100644 src/vlibsocket/api.h create mode 100644 src/vlibsocket/sock_test.c create mode 100644 src/vlibsocket/sockclnt.api create mode 100644 src/vlibsocket/sockclnt_vlib.c create mode 100644 src/vlibsocket/socksvr_vlib.c create mode 100644 src/vlibsocket/vl_socket_api_h.h create mode 100644 src/vlibsocket/vl_socket_msg_enum.h create mode 100644 src/vnet.am create mode 100644 src/vnet/adj/adj.c create mode 100644 src/vnet/adj/adj.h create mode 100644 src/vnet/adj/adj_glean.c create mode 100644 src/vnet/adj/adj_glean.h create mode 100644 src/vnet/adj/adj_internal.h create mode 100644 src/vnet/adj/adj_l2.c create mode 100644 src/vnet/adj/adj_l2.h create mode 100644 src/vnet/adj/adj_midchain.c create mode 100644 src/vnet/adj/adj_midchain.h create mode 100644 src/vnet/adj/adj_nbr.c create mode 100644 src/vnet/adj/adj_nbr.h create mode 100644 src/vnet/adj/adj_rewrite.c create mode 100644 src/vnet/adj/adj_rewrite.h create mode 100644 src/vnet/adj/adj_types.h create mode 100644 src/vnet/api_errno.h create mode 100644 src/vnet/bfd/bfd.api create mode 100644 src/vnet/bfd/bfd_api.c create mode 100644 src/vnet/bfd/bfd_api.h create mode 100644 src/vnet/bfd/bfd_debug.h create mode 100644 src/vnet/bfd/bfd_doc.md create mode 100644 src/vnet/bfd/bfd_main.c create mode 100644 src/vnet/bfd/bfd_main.h create mode 100644 src/vnet/bfd/bfd_protocol.c create mode 100644 src/vnet/bfd/bfd_protocol.h create mode 100644 src/vnet/bfd/bfd_udp.c create mode 100644 src/vnet/bfd/bfd_udp.h create mode 100644 src/vnet/bfd/dir.dox create mode 100644 src/vnet/buffer.h create mode 100644 src/vnet/cdp/cdp.pg create mode 100644 src/vnet/cdp/cdp_input.c create mode 100644 src/vnet/cdp/cdp_node.c create mode 100644 src/vnet/cdp/cdp_node.h create mode 100644 src/vnet/cdp/cdp_periodic.c create mode 100644 src/vnet/cdp/cdp_protocol.h create mode 100644 src/vnet/classify/README create mode 100644 src/vnet/classify/flow_classify.c create mode 100644 src/vnet/classify/flow_classify.h create mode 100644 src/vnet/classify/flow_classify_node.c create mode 100644 src/vnet/classify/input_acl.c create mode 100644 src/vnet/classify/input_acl.h create mode 100644 src/vnet/classify/ip_classify.c create mode 100644 src/vnet/classify/policer_classify.c create mode 100644 src/vnet/classify/policer_classify.h create mode 100644 src/vnet/classify/vnet_classify.c create mode 100644 src/vnet/classify/vnet_classify.h create mode 100644 src/vnet/config.c create mode 100644 src/vnet/config.h create mode 100644 src/vnet/cop/cop.c create mode 100644 src/vnet/cop/cop.h create mode 100644 src/vnet/cop/ip4_whitelist.c create mode 100644 src/vnet/cop/ip6_whitelist.c create mode 100644 src/vnet/cop/node1.c create mode 100644 src/vnet/devices/af_packet/af_packet.api create mode 100644 src/vnet/devices/af_packet/af_packet.c create mode 100644 src/vnet/devices/af_packet/af_packet.h create mode 100644 src/vnet/devices/af_packet/af_packet_api.c create mode 100644 src/vnet/devices/af_packet/cli.c create mode 100644 src/vnet/devices/af_packet/device.c create mode 100644 src/vnet/devices/af_packet/node.c create mode 100644 src/vnet/devices/devices.c create mode 100644 src/vnet/devices/devices.h create mode 100644 src/vnet/devices/dpdk/cli.c create mode 100644 src/vnet/devices/dpdk/device.c create mode 100644 src/vnet/devices/dpdk/dpdk.h create mode 100644 src/vnet/devices/dpdk/dpdk_priv.h create mode 100644 src/vnet/devices/dpdk/format.c create mode 100644 src/vnet/devices/dpdk/hqos.c create mode 100755 src/vnet/devices/dpdk/init.c create mode 100644 src/vnet/devices/dpdk/ipsec/cli.c create mode 100644 src/vnet/devices/dpdk/ipsec/crypto_node.c create mode 100644 src/vnet/devices/dpdk/ipsec/dir.dox create mode 100644 src/vnet/devices/dpdk/ipsec/dpdk_crypto_ipsec_doc.md create mode 100644 src/vnet/devices/dpdk/ipsec/esp.h create mode 100644 src/vnet/devices/dpdk/ipsec/esp_decrypt.c create mode 100644 src/vnet/devices/dpdk/ipsec/esp_encrypt.c create mode 100644 src/vnet/devices/dpdk/ipsec/ipsec.c create mode 100644 src/vnet/devices/dpdk/ipsec/ipsec.h create mode 100644 src/vnet/devices/dpdk/node.c create mode 100644 src/vnet/devices/dpdk/qos_doc.md create mode 100644 src/vnet/devices/netmap/cli.c create mode 100644 src/vnet/devices/netmap/device.c create mode 100644 src/vnet/devices/netmap/net_netmap.h create mode 100644 src/vnet/devices/netmap/netmap.api create mode 100644 src/vnet/devices/netmap/netmap.c create mode 100644 src/vnet/devices/netmap/netmap.h create mode 100644 src/vnet/devices/netmap/netmap_api.c create mode 100644 src/vnet/devices/netmap/node.c create mode 100644 src/vnet/devices/nic/ixge.c create mode 100644 src/vnet/devices/nic/ixge.h create mode 100644 src/vnet/devices/nic/sfp.c create mode 100644 src/vnet/devices/nic/sfp.h create mode 100644 src/vnet/devices/ssvm/node.c create mode 100644 src/vnet/devices/ssvm/ssvm_eth.c create mode 100644 src/vnet/devices/ssvm/ssvm_eth.h create mode 100644 src/vnet/devices/virtio/dir.dox create mode 100644 src/vnet/devices/virtio/vhost-user.c create mode 100644 src/vnet/devices/virtio/vhost-user.h create mode 100644 src/vnet/devices/virtio/vhost_user.api create mode 100644 src/vnet/devices/virtio/vhost_user_api.c create mode 100644 src/vnet/dhcp/client.c create mode 100644 src/vnet/dhcp/client.h create mode 100644 src/vnet/dhcp/packet.h create mode 100644 src/vnet/dhcp/proxy.h create mode 100644 src/vnet/dhcp/proxy_error.def create mode 100644 src/vnet/dhcp/proxy_node.c create mode 100644 src/vnet/dhcpv6/packet.h create mode 100644 src/vnet/dhcpv6/proxy.h create mode 100644 src/vnet/dhcpv6/proxy_error.def create mode 100644 src/vnet/dhcpv6/proxy_node.c create mode 100644 src/vnet/dpo/classify_dpo.c create mode 100644 src/vnet/dpo/classify_dpo.h create mode 100644 src/vnet/dpo/dpo.c create mode 100644 src/vnet/dpo/dpo.h create mode 100644 src/vnet/dpo/drop_dpo.c create mode 100644 src/vnet/dpo/drop_dpo.h create mode 100644 src/vnet/dpo/ip_null_dpo.c create mode 100644 src/vnet/dpo/ip_null_dpo.h create mode 100644 src/vnet/dpo/load_balance.c create mode 100644 src/vnet/dpo/load_balance.h create mode 100644 src/vnet/dpo/load_balance_map.c create mode 100644 src/vnet/dpo/load_balance_map.h create mode 100644 src/vnet/dpo/lookup_dpo.c create mode 100644 src/vnet/dpo/lookup_dpo.h create mode 100644 src/vnet/dpo/mpls_label_dpo.c create mode 100644 src/vnet/dpo/mpls_label_dpo.h create mode 100644 src/vnet/dpo/punt_dpo.c create mode 100644 src/vnet/dpo/punt_dpo.h create mode 100644 src/vnet/dpo/receive_dpo.c create mode 100644 src/vnet/dpo/receive_dpo.h create mode 100644 src/vnet/ethernet/arp.c create mode 100644 src/vnet/ethernet/arp_packet.h create mode 100644 src/vnet/ethernet/dir.dox create mode 100644 src/vnet/ethernet/error.def create mode 100644 src/vnet/ethernet/ethernet.h create mode 100644 src/vnet/ethernet/format.c create mode 100644 src/vnet/ethernet/init.c create mode 100644 src/vnet/ethernet/interface.c create mode 100644 src/vnet/ethernet/mac_swap.c create mode 100755 src/vnet/ethernet/node.c create mode 100644 src/vnet/ethernet/packet.h create mode 100644 src/vnet/ethernet/pg.c create mode 100644 src/vnet/ethernet/types.def create mode 100644 src/vnet/feature/feature.c create mode 100644 src/vnet/feature/feature.h create mode 100644 src/vnet/feature/registration.c create mode 100644 src/vnet/fib/fib.c create mode 100644 src/vnet/fib/fib.h create mode 100644 src/vnet/fib/fib_api.h create mode 100644 src/vnet/fib/fib_attached_export.c create mode 100644 src/vnet/fib/fib_attached_export.h create mode 100644 src/vnet/fib/fib_entry.c create mode 100644 src/vnet/fib/fib_entry.h create mode 100644 src/vnet/fib/fib_entry_cover.c create mode 100644 src/vnet/fib/fib_entry_cover.h create mode 100644 src/vnet/fib/fib_entry_delegate.c create mode 100644 src/vnet/fib/fib_entry_delegate.h create mode 100644 src/vnet/fib/fib_entry_src.c create mode 100644 src/vnet/fib/fib_entry_src.h create mode 100644 src/vnet/fib/fib_entry_src_adj.c create mode 100644 src/vnet/fib/fib_entry_src_api.c create mode 100644 src/vnet/fib/fib_entry_src_default.c create mode 100644 src/vnet/fib/fib_entry_src_default_route.c create mode 100644 src/vnet/fib/fib_entry_src_interface.c create mode 100644 src/vnet/fib/fib_entry_src_lisp.c create mode 100644 src/vnet/fib/fib_entry_src_mpls.c create mode 100644 src/vnet/fib/fib_entry_src_rr.c create mode 100644 src/vnet/fib/fib_entry_src_special.c create mode 100644 src/vnet/fib/fib_internal.h create mode 100644 src/vnet/fib/fib_node.c create mode 100644 src/vnet/fib/fib_node.h create mode 100644 src/vnet/fib/fib_node_list.c create mode 100644 src/vnet/fib/fib_node_list.h create mode 100644 src/vnet/fib/fib_path.c create mode 100644 src/vnet/fib/fib_path.h create mode 100644 src/vnet/fib/fib_path_ext.c create mode 100644 src/vnet/fib/fib_path_ext.h create mode 100644 src/vnet/fib/fib_path_list.c create mode 100644 src/vnet/fib/fib_path_list.h create mode 100644 src/vnet/fib/fib_table.c create mode 100644 src/vnet/fib/fib_table.h create mode 100644 src/vnet/fib/fib_test.c create mode 100644 src/vnet/fib/fib_types.c create mode 100644 src/vnet/fib/fib_types.h create mode 100644 src/vnet/fib/fib_urpf_list.c create mode 100644 src/vnet/fib/fib_urpf_list.h create mode 100644 src/vnet/fib/fib_walk.c create mode 100644 src/vnet/fib/fib_walk.h create mode 100644 src/vnet/fib/ip4_fib.c create mode 100644 src/vnet/fib/ip4_fib.h create mode 100644 src/vnet/fib/ip6_fib.c create mode 100644 src/vnet/fib/ip6_fib.h create mode 100644 src/vnet/fib/mpls_fib.c create mode 100644 src/vnet/fib/mpls_fib.h create mode 100644 src/vnet/flow/flow_report.c create mode 100644 src/vnet/flow/flow_report.h create mode 100644 src/vnet/flow/flow_report_classify.c create mode 100644 src/vnet/flow/flow_report_classify.h create mode 100644 src/vnet/flow/ipfix_info_elements.h create mode 100644 src/vnet/flow/ipfix_packet.h create mode 100644 src/vnet/global_funcs.h create mode 100644 src/vnet/gre/error.def create mode 100644 src/vnet/gre/gre.api create mode 100644 src/vnet/gre/gre.c create mode 100644 src/vnet/gre/gre.h create mode 100644 src/vnet/gre/gre_api.c create mode 100644 src/vnet/gre/interface.c create mode 100644 src/vnet/gre/node.c create mode 100644 src/vnet/gre/packet.h create mode 100644 src/vnet/gre/pg.c create mode 100644 src/vnet/handoff.c create mode 100644 src/vnet/handoff.h create mode 100644 src/vnet/hdlc/error.def create mode 100644 src/vnet/hdlc/hdlc.c create mode 100644 src/vnet/hdlc/hdlc.h create mode 100644 src/vnet/hdlc/node.c create mode 100644 src/vnet/hdlc/packet.h create mode 100644 src/vnet/hdlc/pg.c create mode 100644 src/vnet/interface.api create mode 100644 src/vnet/interface.c create mode 100644 src/vnet/interface.h create mode 100644 src/vnet/interface_api.c create mode 100644 src/vnet/interface_cli.c create mode 100644 src/vnet/interface_format.c create mode 100644 src/vnet/interface_funcs.h create mode 100644 src/vnet/interface_output.c create mode 100644 src/vnet/ip/dir.dox create mode 100644 src/vnet/ip/format.c create mode 100644 src/vnet/ip/format.h create mode 100644 src/vnet/ip/icmp4.c create mode 100644 src/vnet/ip/icmp4.h create mode 100644 src/vnet/ip/icmp46_packet.h create mode 100644 src/vnet/ip/icmp6.c create mode 100644 src/vnet/ip/icmp6.h create mode 100644 src/vnet/ip/igmp_packet.h create mode 100644 src/vnet/ip/ip.api create mode 100644 src/vnet/ip/ip.h create mode 100644 src/vnet/ip/ip4.h create mode 100644 src/vnet/ip/ip46_cli.c create mode 100644 src/vnet/ip/ip4_error.h create mode 100644 src/vnet/ip/ip4_format.c create mode 100644 src/vnet/ip/ip4_forward.c create mode 100644 src/vnet/ip/ip4_input.c create mode 100644 src/vnet/ip/ip4_mtrie.c create mode 100644 src/vnet/ip/ip4_mtrie.h create mode 100644 src/vnet/ip/ip4_packet.h create mode 100644 src/vnet/ip/ip4_pg.c create mode 100644 src/vnet/ip/ip4_source_and_port_range_check.c create mode 100644 src/vnet/ip/ip4_source_check.c create mode 100644 src/vnet/ip/ip4_test.c create mode 100644 src/vnet/ip/ip6.h create mode 100644 src/vnet/ip/ip6_error.h create mode 100644 src/vnet/ip/ip6_format.c create mode 100644 src/vnet/ip/ip6_forward.c create mode 100644 src/vnet/ip/ip6_hop_by_hop.c create mode 100644 src/vnet/ip/ip6_hop_by_hop.h create mode 100644 src/vnet/ip/ip6_hop_by_hop_packet.h create mode 100644 src/vnet/ip/ip6_input.c create mode 100644 src/vnet/ip/ip6_neighbor.c create mode 100644 src/vnet/ip/ip6_neighbor.h create mode 100644 src/vnet/ip/ip6_packet.h create mode 100644 src/vnet/ip/ip6_pg.c create mode 100644 src/vnet/ip/ip_api.c create mode 100644 src/vnet/ip/ip_checksum.c create mode 100644 src/vnet/ip/ip_frag.c create mode 100644 src/vnet/ip/ip_frag.h create mode 100644 src/vnet/ip/ip_init.c create mode 100644 src/vnet/ip/ip_input_acl.c create mode 100644 src/vnet/ip/ip_packet.h create mode 100644 src/vnet/ip/ip_source_and_port_range_check.h create mode 100644 src/vnet/ip/lookup.c create mode 100644 src/vnet/ip/lookup.h create mode 100644 src/vnet/ip/ping.c create mode 100644 src/vnet/ip/ping.h create mode 100644 src/vnet/ip/ports.def create mode 100644 src/vnet/ip/protocols.def create mode 100644 src/vnet/ip/punt.c create mode 100644 src/vnet/ip/punt.h create mode 100644 src/vnet/ip/punt_error.def create mode 100644 src/vnet/ip/tcp_packet.h create mode 100644 src/vnet/ip/udp.h create mode 100644 src/vnet/ip/udp_error.def create mode 100644 src/vnet/ip/udp_format.c create mode 100644 src/vnet/ip/udp_init.c create mode 100644 src/vnet/ip/udp_local.c create mode 100644 src/vnet/ip/udp_packet.h create mode 100644 src/vnet/ip/udp_pg.c create mode 100644 src/vnet/ipsec-gre/dir.dox create mode 100644 src/vnet/ipsec-gre/error.def create mode 100644 src/vnet/ipsec-gre/interface.c create mode 100644 src/vnet/ipsec-gre/ipsec_gre.api create mode 100644 src/vnet/ipsec-gre/ipsec_gre.c create mode 100644 src/vnet/ipsec-gre/ipsec_gre.h create mode 100644 src/vnet/ipsec-gre/ipsec_gre_api.c create mode 100644 src/vnet/ipsec-gre/ipsec_gre_doc.md create mode 100644 src/vnet/ipsec-gre/node.c create mode 100644 src/vnet/ipsec/esp.h create mode 100644 src/vnet/ipsec/esp_decrypt.c create mode 100644 src/vnet/ipsec/esp_encrypt.c create mode 100644 src/vnet/ipsec/ikev2.c create mode 100644 src/vnet/ipsec/ikev2.h create mode 100644 src/vnet/ipsec/ikev2_cli.c create mode 100644 src/vnet/ipsec/ikev2_crypto.c create mode 100644 src/vnet/ipsec/ikev2_format.c create mode 100644 src/vnet/ipsec/ikev2_payload.c create mode 100644 src/vnet/ipsec/ikev2_priv.h create mode 100644 src/vnet/ipsec/ipsec.api create mode 100644 src/vnet/ipsec/ipsec.c create mode 100644 src/vnet/ipsec/ipsec.h create mode 100644 src/vnet/ipsec/ipsec_api.c create mode 100644 src/vnet/ipsec/ipsec_cli.c create mode 100644 src/vnet/ipsec/ipsec_format.c create mode 100644 src/vnet/ipsec/ipsec_if.c create mode 100644 src/vnet/ipsec/ipsec_if_in.c create mode 100644 src/vnet/ipsec/ipsec_if_out.c create mode 100644 src/vnet/ipsec/ipsec_input.c create mode 100644 src/vnet/ipsec/ipsec_output.c create mode 100644 src/vnet/l2/dir.dox create mode 100644 src/vnet/l2/feat_bitmap.c create mode 100644 src/vnet/l2/feat_bitmap.h create mode 100644 src/vnet/l2/l2.api create mode 100644 src/vnet/l2/l2_api.c create mode 100644 src/vnet/l2/l2_bd.c create mode 100644 src/vnet/l2/l2_bd.h create mode 100644 src/vnet/l2/l2_bvi.c create mode 100644 src/vnet/l2/l2_bvi.h create mode 100644 src/vnet/l2/l2_classify.h create mode 100644 src/vnet/l2/l2_efp_filter.c create mode 100644 src/vnet/l2/l2_efp_filter.h create mode 100644 src/vnet/l2/l2_fib.c create mode 100644 src/vnet/l2/l2_fib.h create mode 100644 src/vnet/l2/l2_flood.c create mode 100644 src/vnet/l2/l2_flood.h create mode 100644 src/vnet/l2/l2_fwd.c create mode 100644 src/vnet/l2/l2_fwd.h create mode 100644 src/vnet/l2/l2_input.c create mode 100644 src/vnet/l2/l2_input.h create mode 100644 src/vnet/l2/l2_input_acl.c create mode 100644 src/vnet/l2/l2_input_classify.c create mode 100644 src/vnet/l2/l2_input_vtr.c create mode 100644 src/vnet/l2/l2_input_vtr.h create mode 100644 src/vnet/l2/l2_learn.c create mode 100644 src/vnet/l2/l2_learn.h create mode 100644 src/vnet/l2/l2_output.c create mode 100644 src/vnet/l2/l2_output.h create mode 100644 src/vnet/l2/l2_output_acl.c create mode 100644 src/vnet/l2/l2_output_classify.c create mode 100644 src/vnet/l2/l2_patch.c create mode 100644 src/vnet/l2/l2_rw.c create mode 100644 src/vnet/l2/l2_rw.h create mode 100644 src/vnet/l2/l2_vtr.c create mode 100644 src/vnet/l2/l2_vtr.h create mode 100644 src/vnet/l2/l2_xcrw.c create mode 100644 src/vnet/l2/l2_xcrw.h create mode 100644 src/vnet/l2tp/decap.c create mode 100644 src/vnet/l2tp/encap.c create mode 100644 src/vnet/l2tp/l2tp.api create mode 100644 src/vnet/l2tp/l2tp.c create mode 100644 src/vnet/l2tp/l2tp.h create mode 100644 src/vnet/l2tp/l2tp_api.c create mode 100644 src/vnet/l2tp/packet.h create mode 100644 src/vnet/l2tp/pg.c create mode 100644 src/vnet/l3_types.h create mode 100644 src/vnet/lawful-intercept/lawful_intercept.c create mode 100644 src/vnet/lawful-intercept/lawful_intercept.h create mode 100644 src/vnet/lawful-intercept/node.c create mode 100644 src/vnet/lisp-cp/control.c create mode 100644 src/vnet/lisp-cp/control.h create mode 100644 src/vnet/lisp-cp/gid_dictionary.c create mode 100644 src/vnet/lisp-cp/gid_dictionary.h create mode 100644 src/vnet/lisp-cp/lisp.api create mode 100644 src/vnet/lisp-cp/lisp_api.c create mode 100644 src/vnet/lisp-cp/lisp_cp_dpo.c create mode 100644 src/vnet/lisp-cp/lisp_cp_dpo.h create mode 100644 src/vnet/lisp-cp/lisp_cp_messages.h create mode 100644 src/vnet/lisp-cp/lisp_msg_serdes.c create mode 100644 src/vnet/lisp-cp/lisp_msg_serdes.h create mode 100644 src/vnet/lisp-cp/lisp_types.c create mode 100644 src/vnet/lisp-cp/lisp_types.h create mode 100644 src/vnet/lisp-cp/packets.c create mode 100644 src/vnet/lisp-cp/packets.h create mode 100644 src/vnet/lisp-gpe/decap.c create mode 100644 src/vnet/lisp-gpe/dir.dox create mode 100644 src/vnet/lisp-gpe/interface.c create mode 100644 src/vnet/lisp-gpe/lisp_gpe.api create mode 100644 src/vnet/lisp-gpe/lisp_gpe.c create mode 100644 src/vnet/lisp-gpe/lisp_gpe.h create mode 100644 src/vnet/lisp-gpe/lisp_gpe_adjacency.c create mode 100644 src/vnet/lisp-gpe/lisp_gpe_adjacency.h create mode 100644 src/vnet/lisp-gpe/lisp_gpe_api.c create mode 100644 src/vnet/lisp-gpe/lisp_gpe_error.def create mode 100644 src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c create mode 100644 src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h create mode 100644 src/vnet/lisp-gpe/lisp_gpe_packet.h create mode 100644 src/vnet/lisp-gpe/lisp_gpe_sub_interface.c create mode 100644 src/vnet/lisp-gpe/lisp_gpe_sub_interface.h create mode 100644 src/vnet/lisp-gpe/lisp_gpe_tenant.c create mode 100644 src/vnet/lisp-gpe/lisp_gpe_tenant.h create mode 100644 src/vnet/lisp-gpe/lisp_gpe_tunnel.c create mode 100644 src/vnet/lisp-gpe/lisp_gpe_tunnel.h create mode 100644 src/vnet/lisp-gpe/rfc.txt create mode 100644 src/vnet/llc/llc.c create mode 100644 src/vnet/llc/llc.h create mode 100644 src/vnet/llc/node.c create mode 100644 src/vnet/llc/pg.c create mode 100644 src/vnet/lldp/dir.dox create mode 100644 src/vnet/lldp/lldp_cli.c create mode 100644 src/vnet/lldp/lldp_doc.md create mode 100644 src/vnet/lldp/lldp_input.c create mode 100644 src/vnet/lldp/lldp_node.c create mode 100644 src/vnet/lldp/lldp_node.h create mode 100644 src/vnet/lldp/lldp_output.c create mode 100644 src/vnet/lldp/lldp_protocol.h create mode 100755 src/vnet/map/examples/gen-rules.py create mode 100644 src/vnet/map/examples/health_check.c create mode 100755 src/vnet/map/examples/test_map.py create mode 100755 src/vnet/map/gen-rules.py create mode 100644 src/vnet/map/ip4_map.c create mode 100644 src/vnet/map/ip4_map_t.c create mode 100644 src/vnet/map/ip6_map.c create mode 100644 src/vnet/map/ip6_map_t.c create mode 100644 src/vnet/map/map.api create mode 100644 src/vnet/map/map.c create mode 100644 src/vnet/map/map.h create mode 100644 src/vnet/map/map_api.c create mode 100644 src/vnet/map/map_doc.md create mode 100644 src/vnet/map/map_dpo.c create mode 100644 src/vnet/map/map_dpo.h create mode 100644 src/vnet/map/test.c create mode 100644 src/vnet/mcast/mcast.c create mode 100644 src/vnet/mcast/mcast.h create mode 100644 src/vnet/mcast/mcast_test.c create mode 100644 src/vnet/misc.c create mode 100644 src/vnet/mpls/error.def create mode 100644 src/vnet/mpls/interface.c create mode 100644 src/vnet/mpls/mpls.c create mode 100644 src/vnet/mpls/mpls.h create mode 100644 src/vnet/mpls/mpls_features.c create mode 100644 src/vnet/mpls/mpls_lookup.c create mode 100644 src/vnet/mpls/mpls_output.c create mode 100644 src/vnet/mpls/mpls_tunnel.c create mode 100644 src/vnet/mpls/mpls_tunnel.h create mode 100644 src/vnet/mpls/mpls_types.h create mode 100644 src/vnet/mpls/node.c create mode 100644 src/vnet/mpls/packet.h create mode 100644 src/vnet/mpls/pg.c create mode 100644 src/vnet/osi/node.c create mode 100644 src/vnet/osi/osi.c create mode 100644 src/vnet/osi/osi.h create mode 100644 src/vnet/osi/pg.c create mode 100644 src/vnet/pg/cli.c create mode 100644 src/vnet/pg/edit.c create mode 100644 src/vnet/pg/edit.h create mode 100644 src/vnet/pg/example.script create mode 100644 src/vnet/pg/init.c create mode 100644 src/vnet/pg/input.c create mode 100644 src/vnet/pg/output.c create mode 100644 src/vnet/pg/pg.h create mode 100644 src/vnet/pg/stream.c create mode 100644 src/vnet/pipeline.h create mode 100644 src/vnet/plugin/p1.c create mode 100644 src/vnet/plugin/plugin.h create mode 100644 src/vnet/policer/node_funcs.c create mode 100644 src/vnet/policer/police.h create mode 100644 src/vnet/policer/policer.c create mode 100644 src/vnet/policer/policer.h create mode 100644 src/vnet/policer/xlate.c create mode 100644 src/vnet/policer/xlate.h create mode 100644 src/vnet/ppp/error.def create mode 100644 src/vnet/ppp/node.c create mode 100644 src/vnet/ppp/packet.h create mode 100644 src/vnet/ppp/pg.c create mode 100644 src/vnet/ppp/ppp.c create mode 100644 src/vnet/ppp/ppp.h create mode 100644 src/vnet/replication.c create mode 100644 src/vnet/replication.h create mode 100644 src/vnet/rewrite.c create mode 100644 src/vnet/rewrite.h create mode 100644 src/vnet/snap/node.c create mode 100644 src/vnet/snap/pg.c create mode 100644 src/vnet/snap/snap.c create mode 100644 src/vnet/snap/snap.h create mode 100644 src/vnet/span/node.c create mode 100644 src/vnet/span/span.api create mode 100644 src/vnet/span/span.c create mode 100644 src/vnet/span/span.h create mode 100644 src/vnet/span/span.md create mode 100644 src/vnet/span/span_api.c create mode 100644 src/vnet/sr/dir.dox create mode 100644 src/vnet/sr/examples/sr_multicastmap.script create mode 100644 src/vnet/sr/rfc_draft_05.txt create mode 100644 src/vnet/sr/sr.c create mode 100644 src/vnet/sr/sr.h create mode 100644 src/vnet/sr/sr_error.def create mode 100644 src/vnet/sr/sr_fix_dst_error.def create mode 100644 src/vnet/sr/sr_packet.h create mode 100644 src/vnet/sr/sr_replicate.c create mode 100644 src/vnet/srp/format.c create mode 100644 src/vnet/srp/interface.c create mode 100644 src/vnet/srp/node.c create mode 100644 src/vnet/srp/packet.h create mode 100644 src/vnet/srp/pg.c create mode 100644 src/vnet/srp/srp.h create mode 100644 src/vnet/unix/gdb_funcs.c create mode 100644 src/vnet/unix/pcap.c create mode 100644 src/vnet/unix/pcap.h create mode 100644 src/vnet/unix/pcap2pg.c create mode 100644 src/vnet/unix/tap.api create mode 100644 src/vnet/unix/tap_api.c create mode 100644 src/vnet/unix/tapcli.c create mode 100644 src/vnet/unix/tapcli.h create mode 100644 src/vnet/unix/tuntap.c create mode 100644 src/vnet/unix/tuntap.h create mode 100644 src/vnet/vnet.h create mode 100644 src/vnet/vnet_all_api_h.h create mode 100644 src/vnet/vnet_msg_enum.h create mode 100644 src/vnet/vxlan-gpe/decap.c create mode 100644 src/vnet/vxlan-gpe/dir.dox create mode 100644 src/vnet/vxlan-gpe/encap.c create mode 100644 src/vnet/vxlan-gpe/vxlan-gpe-rfc.txt create mode 100644 src/vnet/vxlan-gpe/vxlan_gpe.api create mode 100644 src/vnet/vxlan-gpe/vxlan_gpe.c create mode 100644 src/vnet/vxlan-gpe/vxlan_gpe.h create mode 100644 src/vnet/vxlan-gpe/vxlan_gpe_api.c create mode 100644 src/vnet/vxlan-gpe/vxlan_gpe_error.def create mode 100644 src/vnet/vxlan-gpe/vxlan_gpe_packet.h create mode 100644 src/vnet/vxlan/decap.c create mode 100644 src/vnet/vxlan/dir.dox create mode 100644 src/vnet/vxlan/encap.c create mode 100644 src/vnet/vxlan/vxlan.api create mode 100644 src/vnet/vxlan/vxlan.c create mode 100644 src/vnet/vxlan/vxlan.h create mode 100644 src/vnet/vxlan/vxlan_api.c create mode 100644 src/vnet/vxlan/vxlan_error.def create mode 100644 src/vnet/vxlan/vxlan_packet.h create mode 100644 src/vpp-api-test.am create mode 100644 src/vpp-api/python/Makefile.am create mode 100644 src/vpp-api/python/README.rst create mode 100644 src/vpp-api/python/pneum/pneum.c create mode 100644 src/vpp-api/python/pneum/pneum.h create mode 100644 src/vpp-api/python/pneum/test_pneum.c create mode 100644 src/vpp-api/python/setup.cfg create mode 100644 src/vpp-api/python/setup.py create mode 100755 src/vpp-api/python/tests/test_cli.py create mode 100755 src/vpp-api/python/tests/test_modules.py create mode 100755 src/vpp-api/python/tests/test_papi.py create mode 100755 src/vpp-api/python/tests/test_version.py create mode 100755 src/vpp-api/python/tests/test_vpp_papi2.py create mode 100644 src/vpp-api/python/vpp_papi/__init__.py create mode 100644 src/vpp-api/python/vpp_papi/pneum_wrap.c create mode 100644 src/vpp-api/python/vpp_papi/vpp_papi.py create mode 100644 src/vpp.am create mode 100644 src/vpp/api/api.c create mode 120000 src/vpp/api/api_format.c create mode 100644 src/vpp/api/api_main.c create mode 100644 src/vpp/api/custom_dump.c create mode 100644 src/vpp/api/gmon.c create mode 100644 src/vpp/api/json_format.c create mode 100644 src/vpp/api/json_format.h create mode 100644 src/vpp/api/summary_stats_client.c create mode 100644 src/vpp/api/test_client.c create mode 100644 src/vpp/api/test_ha.c create mode 120000 src/vpp/api/vat.h create mode 100644 src/vpp/api/vpe.api create mode 100644 src/vpp/api/vpe_all_api_h.h create mode 100644 src/vpp/api/vpe_msg_enum.h create mode 100644 src/vpp/api/vpp_get_metrics.c create mode 100644 src/vpp/app/l2t.c create mode 100644 src/vpp/app/l2t_l2.c create mode 100644 src/vpp/app/sticky_hash.c create mode 100644 src/vpp/app/version.c create mode 100644 src/vpp/app/vpe_cli.c create mode 100644 src/vpp/conf/80-vpp.conf create mode 100644 src/vpp/conf/startup.conf create mode 100644 src/vpp/conf/startup.uiopcigeneric.conf create mode 100644 src/vpp/oam/oam.c create mode 100644 src/vpp/oam/oam.h create mode 100644 src/vpp/stats/stats.c create mode 100644 src/vpp/stats/stats.h create mode 100644 src/vpp/vnet/main.c create mode 100644 src/vppapigen.am create mode 100644 src/vppinfra.am create mode 100644 src/vppinfra/README create mode 100644 src/vppinfra/anneal.c create mode 100644 src/vppinfra/anneal.h create mode 100644 src/vppinfra/asm_mips.h create mode 100644 src/vppinfra/asm_x86.c create mode 100644 src/vppinfra/asm_x86.h create mode 100644 src/vppinfra/backtrace.c create mode 100644 src/vppinfra/bihash_24_8.h create mode 100644 src/vppinfra/bihash_8_8.h create mode 100644 src/vppinfra/bihash_doc.h create mode 100644 src/vppinfra/bihash_template.c create mode 100644 src/vppinfra/bihash_template.h create mode 100644 src/vppinfra/bitmap.h create mode 100644 src/vppinfra/bitops.h create mode 100644 src/vppinfra/byte_order.h create mode 100644 src/vppinfra/cache.h create mode 100644 src/vppinfra/clib.h create mode 100644 src/vppinfra/cpu.c create mode 100644 src/vppinfra/cpu.h create mode 100644 src/vppinfra/dir.dox create mode 100644 src/vppinfra/dlist.h create mode 100644 src/vppinfra/elf.c create mode 100644 src/vppinfra/elf.h create mode 100644 src/vppinfra/elf_clib.c create mode 100644 src/vppinfra/elf_clib.h create mode 100644 src/vppinfra/elog.c create mode 100644 src/vppinfra/elog.h create mode 100644 src/vppinfra/error.c create mode 100644 src/vppinfra/error.h create mode 100644 src/vppinfra/error_bootstrap.h create mode 100644 src/vppinfra/fheap.c create mode 100644 src/vppinfra/fheap.h create mode 100644 src/vppinfra/fifo.c create mode 100644 src/vppinfra/fifo.h create mode 100644 src/vppinfra/format.c create mode 100644 src/vppinfra/format.h create mode 100644 src/vppinfra/graph.c create mode 100644 src/vppinfra/graph.h create mode 100644 src/vppinfra/hash.c create mode 100644 src/vppinfra/hash.h create mode 100644 src/vppinfra/heap.c create mode 100644 src/vppinfra/heap.h create mode 100644 src/vppinfra/longjmp.S create mode 100644 src/vppinfra/longjmp.h create mode 100644 src/vppinfra/macros.c create mode 100644 src/vppinfra/macros.h create mode 100644 src/vppinfra/math.h create mode 100644 src/vppinfra/md5.c create mode 100644 src/vppinfra/md5.h create mode 100644 src/vppinfra/mem.h create mode 100644 src/vppinfra/mem_mheap.c create mode 100644 src/vppinfra/memcheck.h create mode 100644 src/vppinfra/memcpy_avx.h create mode 100644 src/vppinfra/memcpy_sse3.h create mode 100644 src/vppinfra/mhash.c create mode 100644 src/vppinfra/mhash.h create mode 100644 src/vppinfra/mheap.c create mode 100644 src/vppinfra/mheap.h create mode 100644 src/vppinfra/mheap_bootstrap.h create mode 100644 src/vppinfra/mod_test_hash.c create mode 100644 src/vppinfra/os.h create mode 100644 src/vppinfra/pfhash.c create mode 100644 src/vppinfra/pfhash.h create mode 100644 src/vppinfra/phash.c create mode 100644 src/vppinfra/phash.h create mode 100644 src/vppinfra/pipeline.h create mode 100644 src/vppinfra/pool.h create mode 100644 src/vppinfra/ptclosure.c create mode 100644 src/vppinfra/ptclosure.h create mode 100644 src/vppinfra/qhash.c create mode 100644 src/vppinfra/qhash.h create mode 100644 src/vppinfra/qsort.c create mode 100644 src/vppinfra/random.c create mode 100644 src/vppinfra/random.h create mode 100644 src/vppinfra/random_buffer.c create mode 100644 src/vppinfra/random_buffer.h create mode 100644 src/vppinfra/random_isaac.c create mode 100644 src/vppinfra/random_isaac.h create mode 100644 src/vppinfra/serialize.c create mode 100644 src/vppinfra/serialize.h create mode 100644 src/vppinfra/slist.c create mode 100644 src/vppinfra/slist.h create mode 100644 src/vppinfra/smp.c create mode 100644 src/vppinfra/smp.h create mode 100644 src/vppinfra/smp_fifo.c create mode 100644 src/vppinfra/smp_fifo.h create mode 100644 src/vppinfra/socket.c create mode 100644 src/vppinfra/socket.h create mode 100644 src/vppinfra/sparse_vec.h create mode 100644 src/vppinfra/std-formats.c create mode 100644 src/vppinfra/string.c create mode 100644 src/vppinfra/string.h create mode 100644 src/vppinfra/test_bihash_template.c create mode 100644 src/vppinfra/test_dlist.c create mode 100644 src/vppinfra/test_elf.c create mode 100644 src/vppinfra/test_elog.c create mode 100644 src/vppinfra/test_fifo.c create mode 100644 src/vppinfra/test_format.c create mode 100644 src/vppinfra/test_hash.c create mode 100644 src/vppinfra/test_heap.c create mode 100644 src/vppinfra/test_longjmp.c create mode 100644 src/vppinfra/test_macros.c create mode 100644 src/vppinfra/test_md5.c create mode 100644 src/vppinfra/test_mheap.c create mode 100644 src/vppinfra/test_pfhash.c create mode 100644 src/vppinfra/test_phash.c create mode 100644 src/vppinfra/test_pool.c create mode 100644 src/vppinfra/test_pool_iterate.c create mode 100644 src/vppinfra/test_ptclosure.c create mode 100644 src/vppinfra/test_qhash.c create mode 100644 src/vppinfra/test_random.c create mode 100644 src/vppinfra/test_random_isaac.c create mode 100644 src/vppinfra/test_serialize.c create mode 100644 src/vppinfra/test_slist.c create mode 100644 src/vppinfra/test_socket.c create mode 100644 src/vppinfra/test_time.c create mode 100644 src/vppinfra/test_timing_wheel.c create mode 100644 src/vppinfra/test_vec.c create mode 100644 src/vppinfra/test_vec.h create mode 100644 src/vppinfra/test_vhash.c create mode 100644 src/vppinfra/test_zvec.c create mode 100644 src/vppinfra/time.c create mode 100644 src/vppinfra/time.h create mode 100644 src/vppinfra/timer.c create mode 100644 src/vppinfra/timer.h create mode 100644 src/vppinfra/timing_wheel.c create mode 100644 src/vppinfra/timing_wheel.h create mode 100644 src/vppinfra/types.h create mode 100644 src/vppinfra/unformat.c create mode 100644 src/vppinfra/unix-formats.c create mode 100644 src/vppinfra/unix-kelog.c create mode 100644 src/vppinfra/unix-misc.c create mode 100644 src/vppinfra/unix.h create mode 100644 src/vppinfra/unix_error.def create mode 100644 src/vppinfra/valgrind.h create mode 100644 src/vppinfra/vec.c create mode 100644 src/vppinfra/vec.h create mode 100644 src/vppinfra/vec_bootstrap.h create mode 100644 src/vppinfra/vector.c create mode 100644 src/vppinfra/vector.h create mode 100644 src/vppinfra/vector_altivec.h create mode 100644 src/vppinfra/vector_funcs.h create mode 100644 src/vppinfra/vector_iwmmxt.h create mode 100644 src/vppinfra/vector_neon.h create mode 100644 src/vppinfra/vector_sse2.h create mode 100644 src/vppinfra/vhash.c create mode 100644 src/vppinfra/vhash.h create mode 100644 src/vppinfra/vm_linux_kernel.h create mode 100644 src/vppinfra/vm_standalone.h create mode 100644 src/vppinfra/vm_unix.h create mode 100644 src/vppinfra/xxhash.h create mode 100644 src/vppinfra/xy.h create mode 100644 src/vppinfra/zvec.c create mode 100644 src/vppinfra/zvec.h delete mode 100644 svm/Makefile.am delete mode 100644 svm/configure.ac delete mode 100644 svm/dir.dox delete mode 100644 svm/persist.c delete mode 100644 svm/ssvm.c delete mode 100644 svm/ssvm.h delete mode 100644 svm/svm.c delete mode 100644 svm/svm.h delete mode 100644 svm/svm_test.c delete mode 100644 svm/svmdb.c delete mode 100644 svm/svmdb.h delete mode 100644 svm/svmdbtool.c delete mode 100644 svm/svmtool.c delete mode 100644 vlib-api/Makefile.am delete mode 100644 vlib-api/configure.ac delete mode 120000 vlib-api/suffix-rules.mk delete mode 100644 vlib-api/vlibapi/api.h delete mode 100644 vlib-api/vlibapi/api_helper_macros.h delete mode 100644 vlib-api/vlibapi/api_shared.c delete mode 100644 vlib-api/vlibapi/node_serialize.c delete mode 100644 vlib-api/vlibmemory/api.h delete mode 100644 vlib-api/vlibmemory/memclnt.api delete mode 100644 vlib-api/vlibmemory/memory_client.c delete mode 100644 vlib-api/vlibmemory/memory_shared.c delete mode 100644 vlib-api/vlibmemory/memory_vlib.c delete mode 100644 vlib-api/vlibmemory/unix_shared_memory_queue.c delete mode 100644 vlib-api/vlibmemory/unix_shared_memory_queue.h delete mode 100644 vlib-api/vlibmemory/vl_memory_api_h.h delete mode 100644 vlib-api/vlibmemory/vl_memory_msg_enum.h delete mode 100644 vlib-api/vlibsocket/api.h delete mode 100644 vlib-api/vlibsocket/sock_test.c delete mode 100644 vlib-api/vlibsocket/sockclnt.api delete mode 100644 vlib-api/vlibsocket/sockclnt_vlib.c delete mode 100644 vlib-api/vlibsocket/socksvr_vlib.c delete mode 100644 vlib-api/vlibsocket/vl_socket_api_h.h delete mode 100644 vlib-api/vlibsocket/vl_socket_msg_enum.h delete mode 100644 vlib/.gitignore delete mode 100644 vlib/Makefile.am delete mode 100644 vlib/configure.ac delete mode 100644 vlib/dir.dox delete mode 100644 vlib/example/dir.dox delete mode 100644 vlib/example/main_stub.c delete mode 100644 vlib/example/mc_test.c delete mode 100644 vlib/example/plex_test.c delete mode 100644 vlib/vlib/buffer.c delete mode 100644 vlib/vlib/buffer.h delete mode 100644 vlib/vlib/buffer_funcs.h delete mode 100644 vlib/vlib/buffer_node.h delete mode 100644 vlib/vlib/cli.c delete mode 100644 vlib/vlib/cli.h delete mode 100644 vlib/vlib/cli_funcs.h delete mode 100644 vlib/vlib/counter.c delete mode 100644 vlib/vlib/counter.h delete mode 100644 vlib/vlib/defs.h delete mode 100644 vlib/vlib/dir.dox delete mode 100644 vlib/vlib/elog_samples.c delete mode 100644 vlib/vlib/error.c delete mode 100644 vlib/vlib/error.h delete mode 100644 vlib/vlib/error_funcs.h delete mode 100644 vlib/vlib/format.c delete mode 100644 vlib/vlib/format_funcs.h delete mode 100644 vlib/vlib/global_funcs.h delete mode 100644 vlib/vlib/i2c.c delete mode 100644 vlib/vlib/i2c.h delete mode 100644 vlib/vlib/init.c delete mode 100644 vlib/vlib/init.h delete mode 100644 vlib/vlib/lex.c delete mode 100644 vlib/vlib/lex.h delete mode 100644 vlib/vlib/main.c delete mode 100644 vlib/vlib/main.h delete mode 100644 vlib/vlib/mc.c delete mode 100644 vlib/vlib/mc.h delete mode 100644 vlib/vlib/node.c delete mode 100644 vlib/vlib/node.h delete mode 100644 vlib/vlib/node_cli.c delete mode 100644 vlib/vlib/node_format.c delete mode 100644 vlib/vlib/node_funcs.h delete mode 100644 vlib/vlib/parse.c delete mode 100644 vlib/vlib/parse.h delete mode 100644 vlib/vlib/parse_builtin.c delete mode 100644 vlib/vlib/pci/linux_pci.c delete mode 100644 vlib/vlib/pci/pci.c delete mode 100644 vlib/vlib/pci/pci.h delete mode 100644 vlib/vlib/pci/pci_config.h delete mode 100644 vlib/vlib/physmem.h delete mode 100644 vlib/vlib/threads.c delete mode 100644 vlib/vlib/threads.h delete mode 100644 vlib/vlib/threads_cli.c delete mode 100644 vlib/vlib/trace.c delete mode 100644 vlib/vlib/trace.h delete mode 100644 vlib/vlib/trace_funcs.h delete mode 100644 vlib/vlib/unix/cj.c delete mode 100644 vlib/vlib/unix/cj.h delete mode 100644 vlib/vlib/unix/cli.c delete mode 100644 vlib/vlib/unix/dir.dox delete mode 100644 vlib/vlib/unix/input.c delete mode 100644 vlib/vlib/unix/main.c delete mode 100644 vlib/vlib/unix/mc_socket.c delete mode 100644 vlib/vlib/unix/mc_socket.h delete mode 100644 vlib/vlib/unix/physmem.c delete mode 100644 vlib/vlib/unix/physmem.h delete mode 100644 vlib/vlib/unix/plugin.c delete mode 100644 vlib/vlib/unix/plugin.h delete mode 100644 vlib/vlib/unix/unix.h delete mode 100644 vlib/vlib/unix/util.c delete mode 100644 vlib/vlib/vlib.h delete mode 100644 vlib/vlib/vlib_process_doc.h delete mode 100644 vnet/.gitignore delete mode 100644 vnet/Makefile.am delete mode 100644 vnet/configure.ac delete mode 100644 vnet/etc/scripts/arp4 delete mode 100644 vnet/etc/scripts/arp4-mpls delete mode 100644 vnet/etc/scripts/arp6 delete mode 100644 vnet/etc/scripts/bvi delete mode 100644 vnet/etc/scripts/dhcp/dhcpd.conf delete mode 100644 vnet/etc/scripts/dhcp/left-ping-target.sh delete mode 100644 vnet/etc/scripts/dhcp/leftpeer.conf delete mode 100644 vnet/etc/scripts/icmp delete mode 100644 vnet/etc/scripts/icmp6 delete mode 100644 vnet/etc/scripts/ige delete mode 100644 vnet/etc/scripts/ip6 delete mode 100644 vnet/etc/scripts/ip6-hbh delete mode 100644 vnet/etc/scripts/ixge delete mode 100644 vnet/etc/scripts/l2efpfilter delete mode 100644 vnet/etc/scripts/l2efpfilter_perf delete mode 100644 vnet/etc/scripts/l2fib delete mode 100644 vnet/etc/scripts/l2fib_perf delete mode 100644 vnet/etc/scripts/l2fib_xc delete mode 100644 vnet/etc/scripts/l2flood delete mode 100644 vnet/etc/scripts/l2tp delete mode 100755 vnet/etc/scripts/leftpeer/leftpeer-classify delete mode 100644 vnet/etc/scripts/leftpeer/leftpeer-classify6 delete mode 100644 vnet/etc/scripts/leftpeer/leftpeer-classifyl2 delete mode 100644 vnet/etc/scripts/leftpeer/leftpeer-dhcp delete mode 100644 vnet/etc/scripts/leftpeer/leftpeer-ioam.conf delete mode 100644 vnet/etc/scripts/leftpeer/leftpeer-l3vxlan.conf delete mode 100644 vnet/etc/scripts/leftpeer/leftpeer-lisp.conf delete mode 100644 vnet/etc/scripts/leftpeer/leftpeer-mpls.conf delete mode 100644 vnet/etc/scripts/leftpeer/leftpeer-sr.conf delete mode 100644 vnet/etc/scripts/leftpeer/leftpeer-vxlan.conf delete mode 100644 vnet/etc/scripts/leftpeer/leftpeer.script delete mode 100644 vnet/etc/scripts/lfib/ip4-to-mpls delete mode 100644 vnet/etc/scripts/lfib/mpls-pop-to-mpls delete mode 100644 vnet/etc/scripts/lfib/mpls-to-ip4 delete mode 100644 vnet/etc/scripts/lfib/mpls-to-mpls delete mode 100644 vnet/etc/scripts/mpls-o-ethernet/leftpeer.conf delete mode 100644 vnet/etc/scripts/mpls-o-ethernet/pg delete mode 100644 vnet/etc/scripts/mpls-o-ethernet/rightpeer.conf delete mode 100644 vnet/etc/scripts/mpls-o-ethernet/single.conf delete mode 100644 vnet/etc/scripts/mpls-o-gre/dhcpd.conf delete mode 100644 vnet/etc/scripts/mpls-o-gre/leftpeer.conf delete mode 100644 vnet/etc/scripts/mpls-o-gre/rightpeer.conf delete mode 100644 vnet/etc/scripts/mpls-tunnel delete mode 100644 vnet/etc/scripts/pcap delete mode 100644 vnet/etc/scripts/probe4 delete mode 100644 vnet/etc/scripts/probe6 delete mode 100644 vnet/etc/scripts/rewrite delete mode 100644 vnet/etc/scripts/rightpeer/rightpeer-ioam.conf delete mode 100644 vnet/etc/scripts/rightpeer/rightpeer-l3vxlan.conf delete mode 100644 vnet/etc/scripts/rightpeer/rightpeer-lisp.conf delete mode 100644 vnet/etc/scripts/rightpeer/rightpeer-mpls-l2.conf delete mode 100644 vnet/etc/scripts/rightpeer/rightpeer-mpls.conf delete mode 100644 vnet/etc/scripts/rightpeer/rightpeer-sr.conf delete mode 100644 vnet/etc/scripts/rightpeer/rightpeer-vxlan.conf delete mode 100644 vnet/etc/scripts/rightpeer/rightpeer.script delete mode 100644 vnet/etc/scripts/rpf delete mode 100644 vnet/etc/scripts/rtt-test delete mode 100644 vnet/etc/scripts/snat delete mode 100644 vnet/etc/scripts/snat_static delete mode 100644 vnet/etc/scripts/snat_static_with_port delete mode 100644 vnet/etc/scripts/source_and_port_range_check delete mode 100644 vnet/etc/scripts/speed delete mode 100755 vnet/etc/scripts/sr/left-linux-ping.sh delete mode 100644 vnet/etc/scripts/sr/leftpeer.conf delete mode 100755 vnet/etc/scripts/sr/right-linux-ping.sh delete mode 100644 vnet/etc/scripts/sr/rightpeer.conf delete mode 100755 vnet/etc/scripts/sr/srlocal.sh delete mode 100644 vnet/etc/scripts/srp delete mode 100644 vnet/etc/scripts/tcp delete mode 100644 vnet/etc/scripts/tcp-test delete mode 100644 vnet/etc/scripts/tf-ucs-1 delete mode 100644 vnet/etc/scripts/urpf delete mode 100644 vnet/etc/scripts/virl/ip6sr.virl delete mode 100644 vnet/etc/scripts/virl/ip6sr_notes.txt delete mode 100644 vnet/etc/scripts/virl/mplsogre.virl delete mode 100644 vnet/etc/scripts/virl/simple.virl delete mode 100644 vnet/etc/scripts/vlan delete mode 120000 vnet/suffix-rules.mk delete mode 100644 vnet/test/README delete mode 100644 vnet/test/lisp-cp/test_cp_serdes.c delete mode 100644 vnet/test/lisp-cp/test_lisp_types.c delete mode 100644 vnet/test/lisp-gpe/test.c delete mode 100644 vnet/vnet/adj/adj.c delete mode 100644 vnet/vnet/adj/adj.h delete mode 100644 vnet/vnet/adj/adj_glean.c delete mode 100644 vnet/vnet/adj/adj_glean.h delete mode 100644 vnet/vnet/adj/adj_internal.h delete mode 100644 vnet/vnet/adj/adj_l2.c delete mode 100644 vnet/vnet/adj/adj_l2.h delete mode 100644 vnet/vnet/adj/adj_midchain.c delete mode 100644 vnet/vnet/adj/adj_midchain.h delete mode 100644 vnet/vnet/adj/adj_nbr.c delete mode 100644 vnet/vnet/adj/adj_nbr.h delete mode 100644 vnet/vnet/adj/adj_rewrite.c delete mode 100644 vnet/vnet/adj/adj_rewrite.h delete mode 100644 vnet/vnet/adj/adj_types.h delete mode 100644 vnet/vnet/api_errno.h delete mode 100644 vnet/vnet/bfd/bfd.api delete mode 100644 vnet/vnet/bfd/bfd_api.c delete mode 100644 vnet/vnet/bfd/bfd_api.h delete mode 100644 vnet/vnet/bfd/bfd_debug.h delete mode 100644 vnet/vnet/bfd/bfd_doc.md delete mode 100644 vnet/vnet/bfd/bfd_main.c delete mode 100644 vnet/vnet/bfd/bfd_main.h delete mode 100644 vnet/vnet/bfd/bfd_protocol.c delete mode 100644 vnet/vnet/bfd/bfd_protocol.h delete mode 100644 vnet/vnet/bfd/bfd_udp.c delete mode 100644 vnet/vnet/bfd/bfd_udp.h delete mode 100644 vnet/vnet/bfd/dir.dox delete mode 100644 vnet/vnet/buffer.h delete mode 100644 vnet/vnet/cdp/cdp.pg delete mode 100644 vnet/vnet/cdp/cdp_input.c delete mode 100644 vnet/vnet/cdp/cdp_node.c delete mode 100644 vnet/vnet/cdp/cdp_node.h delete mode 100644 vnet/vnet/cdp/cdp_periodic.c delete mode 100644 vnet/vnet/cdp/cdp_protocol.h delete mode 100644 vnet/vnet/classify/README delete mode 100644 vnet/vnet/classify/flow_classify.c delete mode 100644 vnet/vnet/classify/flow_classify.h delete mode 100644 vnet/vnet/classify/flow_classify_node.c delete mode 100644 vnet/vnet/classify/input_acl.c delete mode 100644 vnet/vnet/classify/input_acl.h delete mode 100644 vnet/vnet/classify/ip_classify.c delete mode 100644 vnet/vnet/classify/policer_classify.c delete mode 100644 vnet/vnet/classify/policer_classify.h delete mode 100644 vnet/vnet/classify/vnet_classify.c delete mode 100644 vnet/vnet/classify/vnet_classify.h delete mode 100644 vnet/vnet/config.c delete mode 100644 vnet/vnet/config.h delete mode 100644 vnet/vnet/cop/cop.c delete mode 100644 vnet/vnet/cop/cop.h delete mode 100644 vnet/vnet/cop/ip4_whitelist.c delete mode 100644 vnet/vnet/cop/ip6_whitelist.c delete mode 100644 vnet/vnet/cop/node1.c delete mode 100644 vnet/vnet/devices/af_packet/af_packet.api delete mode 100644 vnet/vnet/devices/af_packet/af_packet.c delete mode 100644 vnet/vnet/devices/af_packet/af_packet.h delete mode 100644 vnet/vnet/devices/af_packet/af_packet_api.c delete mode 100644 vnet/vnet/devices/af_packet/cli.c delete mode 100644 vnet/vnet/devices/af_packet/device.c delete mode 100644 vnet/vnet/devices/af_packet/node.c delete mode 100644 vnet/vnet/devices/devices.c delete mode 100644 vnet/vnet/devices/devices.h delete mode 100644 vnet/vnet/devices/dpdk/cli.c delete mode 100644 vnet/vnet/devices/dpdk/device.c delete mode 100644 vnet/vnet/devices/dpdk/dpdk.h delete mode 100644 vnet/vnet/devices/dpdk/dpdk_priv.h delete mode 100644 vnet/vnet/devices/dpdk/format.c delete mode 100644 vnet/vnet/devices/dpdk/hqos.c delete mode 100755 vnet/vnet/devices/dpdk/init.c delete mode 100644 vnet/vnet/devices/dpdk/ipsec/cli.c delete mode 100644 vnet/vnet/devices/dpdk/ipsec/crypto_node.c delete mode 100644 vnet/vnet/devices/dpdk/ipsec/dir.dox delete mode 100644 vnet/vnet/devices/dpdk/ipsec/dpdk_crypto_ipsec_doc.md delete mode 100644 vnet/vnet/devices/dpdk/ipsec/esp.h delete mode 100644 vnet/vnet/devices/dpdk/ipsec/esp_decrypt.c delete mode 100644 vnet/vnet/devices/dpdk/ipsec/esp_encrypt.c delete mode 100644 vnet/vnet/devices/dpdk/ipsec/ipsec.c delete mode 100644 vnet/vnet/devices/dpdk/ipsec/ipsec.h delete mode 100644 vnet/vnet/devices/dpdk/node.c delete mode 100644 vnet/vnet/devices/dpdk/qos_doc.md delete mode 100644 vnet/vnet/devices/netmap/cli.c delete mode 100644 vnet/vnet/devices/netmap/device.c delete mode 100644 vnet/vnet/devices/netmap/net_netmap.h delete mode 100644 vnet/vnet/devices/netmap/netmap.api delete mode 100644 vnet/vnet/devices/netmap/netmap.c delete mode 100644 vnet/vnet/devices/netmap/netmap.h delete mode 100644 vnet/vnet/devices/netmap/netmap_api.c delete mode 100644 vnet/vnet/devices/netmap/node.c delete mode 100644 vnet/vnet/devices/nic/ixge.c delete mode 100644 vnet/vnet/devices/nic/ixge.h delete mode 100644 vnet/vnet/devices/nic/sfp.c delete mode 100644 vnet/vnet/devices/nic/sfp.h delete mode 100644 vnet/vnet/devices/ssvm/node.c delete mode 100644 vnet/vnet/devices/ssvm/ssvm_eth.c delete mode 100644 vnet/vnet/devices/ssvm/ssvm_eth.h delete mode 100644 vnet/vnet/devices/virtio/dir.dox delete mode 100644 vnet/vnet/devices/virtio/vhost-user.c delete mode 100644 vnet/vnet/devices/virtio/vhost-user.h delete mode 100644 vnet/vnet/devices/virtio/vhost_user.api delete mode 100644 vnet/vnet/devices/virtio/vhost_user_api.c delete mode 100644 vnet/vnet/dhcp/client.c delete mode 100644 vnet/vnet/dhcp/client.h delete mode 100644 vnet/vnet/dhcp/packet.h delete mode 100644 vnet/vnet/dhcp/proxy.h delete mode 100644 vnet/vnet/dhcp/proxy_error.def delete mode 100644 vnet/vnet/dhcp/proxy_node.c delete mode 100644 vnet/vnet/dhcpv6/packet.h delete mode 100644 vnet/vnet/dhcpv6/proxy.h delete mode 100644 vnet/vnet/dhcpv6/proxy_error.def delete mode 100644 vnet/vnet/dhcpv6/proxy_node.c delete mode 100644 vnet/vnet/dpo/classify_dpo.c delete mode 100644 vnet/vnet/dpo/classify_dpo.h delete mode 100644 vnet/vnet/dpo/dpo.c delete mode 100644 vnet/vnet/dpo/dpo.h delete mode 100644 vnet/vnet/dpo/drop_dpo.c delete mode 100644 vnet/vnet/dpo/drop_dpo.h delete mode 100644 vnet/vnet/dpo/ip_null_dpo.c delete mode 100644 vnet/vnet/dpo/ip_null_dpo.h delete mode 100644 vnet/vnet/dpo/load_balance.c delete mode 100644 vnet/vnet/dpo/load_balance.h delete mode 100644 vnet/vnet/dpo/load_balance_map.c delete mode 100644 vnet/vnet/dpo/load_balance_map.h delete mode 100644 vnet/vnet/dpo/lookup_dpo.c delete mode 100644 vnet/vnet/dpo/lookup_dpo.h delete mode 100644 vnet/vnet/dpo/mpls_label_dpo.c delete mode 100644 vnet/vnet/dpo/mpls_label_dpo.h delete mode 100644 vnet/vnet/dpo/punt_dpo.c delete mode 100644 vnet/vnet/dpo/punt_dpo.h delete mode 100644 vnet/vnet/dpo/receive_dpo.c delete mode 100644 vnet/vnet/dpo/receive_dpo.h delete mode 100644 vnet/vnet/ethernet/arp.c delete mode 100644 vnet/vnet/ethernet/arp_packet.h delete mode 100644 vnet/vnet/ethernet/dir.dox delete mode 100644 vnet/vnet/ethernet/error.def delete mode 100644 vnet/vnet/ethernet/ethernet.h delete mode 100644 vnet/vnet/ethernet/format.c delete mode 100644 vnet/vnet/ethernet/init.c delete mode 100644 vnet/vnet/ethernet/interface.c delete mode 100644 vnet/vnet/ethernet/mac_swap.c delete mode 100755 vnet/vnet/ethernet/node.c delete mode 100644 vnet/vnet/ethernet/packet.h delete mode 100644 vnet/vnet/ethernet/pg.c delete mode 100644 vnet/vnet/ethernet/types.def delete mode 100644 vnet/vnet/feature/feature.c delete mode 100644 vnet/vnet/feature/feature.h delete mode 100644 vnet/vnet/feature/registration.c delete mode 100644 vnet/vnet/fib/fib.c delete mode 100644 vnet/vnet/fib/fib.h delete mode 100644 vnet/vnet/fib/fib_api.h delete mode 100644 vnet/vnet/fib/fib_attached_export.c delete mode 100644 vnet/vnet/fib/fib_attached_export.h delete mode 100644 vnet/vnet/fib/fib_entry.c delete mode 100644 vnet/vnet/fib/fib_entry.h delete mode 100644 vnet/vnet/fib/fib_entry_cover.c delete mode 100644 vnet/vnet/fib/fib_entry_cover.h delete mode 100644 vnet/vnet/fib/fib_entry_delegate.c delete mode 100644 vnet/vnet/fib/fib_entry_delegate.h delete mode 100644 vnet/vnet/fib/fib_entry_src.c delete mode 100644 vnet/vnet/fib/fib_entry_src.h delete mode 100644 vnet/vnet/fib/fib_entry_src_adj.c delete mode 100644 vnet/vnet/fib/fib_entry_src_api.c delete mode 100644 vnet/vnet/fib/fib_entry_src_default.c delete mode 100644 vnet/vnet/fib/fib_entry_src_default_route.c delete mode 100644 vnet/vnet/fib/fib_entry_src_interface.c delete mode 100644 vnet/vnet/fib/fib_entry_src_lisp.c delete mode 100644 vnet/vnet/fib/fib_entry_src_mpls.c delete mode 100644 vnet/vnet/fib/fib_entry_src_rr.c delete mode 100644 vnet/vnet/fib/fib_entry_src_special.c delete mode 100644 vnet/vnet/fib/fib_internal.h delete mode 100644 vnet/vnet/fib/fib_node.c delete mode 100644 vnet/vnet/fib/fib_node.h delete mode 100644 vnet/vnet/fib/fib_node_list.c delete mode 100644 vnet/vnet/fib/fib_node_list.h delete mode 100644 vnet/vnet/fib/fib_path.c delete mode 100644 vnet/vnet/fib/fib_path.h delete mode 100644 vnet/vnet/fib/fib_path_ext.c delete mode 100644 vnet/vnet/fib/fib_path_ext.h delete mode 100644 vnet/vnet/fib/fib_path_list.c delete mode 100644 vnet/vnet/fib/fib_path_list.h delete mode 100644 vnet/vnet/fib/fib_table.c delete mode 100644 vnet/vnet/fib/fib_table.h delete mode 100644 vnet/vnet/fib/fib_test.c delete mode 100644 vnet/vnet/fib/fib_types.c delete mode 100644 vnet/vnet/fib/fib_types.h delete mode 100644 vnet/vnet/fib/fib_urpf_list.c delete mode 100644 vnet/vnet/fib/fib_urpf_list.h delete mode 100644 vnet/vnet/fib/fib_walk.c delete mode 100644 vnet/vnet/fib/fib_walk.h delete mode 100644 vnet/vnet/fib/ip4_fib.c delete mode 100644 vnet/vnet/fib/ip4_fib.h delete mode 100644 vnet/vnet/fib/ip6_fib.c delete mode 100644 vnet/vnet/fib/ip6_fib.h delete mode 100644 vnet/vnet/fib/mpls_fib.c delete mode 100644 vnet/vnet/fib/mpls_fib.h delete mode 100644 vnet/vnet/flow/flow_report.c delete mode 100644 vnet/vnet/flow/flow_report.h delete mode 100644 vnet/vnet/flow/flow_report_classify.c delete mode 100644 vnet/vnet/flow/flow_report_classify.h delete mode 100644 vnet/vnet/flow/ipfix_info_elements.h delete mode 100644 vnet/vnet/flow/ipfix_packet.h delete mode 100644 vnet/vnet/global_funcs.h delete mode 100644 vnet/vnet/gre/error.def delete mode 100644 vnet/vnet/gre/gre.api delete mode 100644 vnet/vnet/gre/gre.c delete mode 100644 vnet/vnet/gre/gre.h delete mode 100644 vnet/vnet/gre/gre_api.c delete mode 100644 vnet/vnet/gre/interface.c delete mode 100644 vnet/vnet/gre/node.c delete mode 100644 vnet/vnet/gre/packet.h delete mode 100644 vnet/vnet/gre/pg.c delete mode 100644 vnet/vnet/handoff.c delete mode 100644 vnet/vnet/handoff.h delete mode 100644 vnet/vnet/hdlc/error.def delete mode 100644 vnet/vnet/hdlc/hdlc.c delete mode 100644 vnet/vnet/hdlc/hdlc.h delete mode 100644 vnet/vnet/hdlc/node.c delete mode 100644 vnet/vnet/hdlc/packet.h delete mode 100644 vnet/vnet/hdlc/pg.c delete mode 100644 vnet/vnet/interface.api delete mode 100644 vnet/vnet/interface.c delete mode 100644 vnet/vnet/interface.h delete mode 100644 vnet/vnet/interface_api.c delete mode 100644 vnet/vnet/interface_cli.c delete mode 100644 vnet/vnet/interface_format.c delete mode 100644 vnet/vnet/interface_funcs.h delete mode 100644 vnet/vnet/interface_output.c delete mode 100644 vnet/vnet/ip/dir.dox delete mode 100644 vnet/vnet/ip/format.c delete mode 100644 vnet/vnet/ip/format.h delete mode 100644 vnet/vnet/ip/icmp4.c delete mode 100644 vnet/vnet/ip/icmp4.h delete mode 100644 vnet/vnet/ip/icmp46_packet.h delete mode 100644 vnet/vnet/ip/icmp6.c delete mode 100644 vnet/vnet/ip/icmp6.h delete mode 100644 vnet/vnet/ip/igmp_packet.h delete mode 100644 vnet/vnet/ip/ip.api delete mode 100644 vnet/vnet/ip/ip.h delete mode 100644 vnet/vnet/ip/ip4.h delete mode 100644 vnet/vnet/ip/ip46_cli.c delete mode 100644 vnet/vnet/ip/ip4_error.h delete mode 100644 vnet/vnet/ip/ip4_format.c delete mode 100644 vnet/vnet/ip/ip4_forward.c delete mode 100644 vnet/vnet/ip/ip4_input.c delete mode 100644 vnet/vnet/ip/ip4_mtrie.c delete mode 100644 vnet/vnet/ip/ip4_mtrie.h delete mode 100644 vnet/vnet/ip/ip4_packet.h delete mode 100644 vnet/vnet/ip/ip4_pg.c delete mode 100644 vnet/vnet/ip/ip4_source_and_port_range_check.c delete mode 100644 vnet/vnet/ip/ip4_source_check.c delete mode 100644 vnet/vnet/ip/ip4_test.c delete mode 100644 vnet/vnet/ip/ip6.h delete mode 100644 vnet/vnet/ip/ip6_error.h delete mode 100644 vnet/vnet/ip/ip6_format.c delete mode 100644 vnet/vnet/ip/ip6_forward.c delete mode 100644 vnet/vnet/ip/ip6_hop_by_hop.c delete mode 100644 vnet/vnet/ip/ip6_hop_by_hop.h delete mode 100644 vnet/vnet/ip/ip6_hop_by_hop_packet.h delete mode 100644 vnet/vnet/ip/ip6_input.c delete mode 100644 vnet/vnet/ip/ip6_neighbor.c delete mode 100644 vnet/vnet/ip/ip6_neighbor.h delete mode 100644 vnet/vnet/ip/ip6_packet.h delete mode 100644 vnet/vnet/ip/ip6_pg.c delete mode 100644 vnet/vnet/ip/ip_api.c delete mode 100644 vnet/vnet/ip/ip_checksum.c delete mode 100644 vnet/vnet/ip/ip_frag.c delete mode 100644 vnet/vnet/ip/ip_frag.h delete mode 100644 vnet/vnet/ip/ip_init.c delete mode 100644 vnet/vnet/ip/ip_input_acl.c delete mode 100644 vnet/vnet/ip/ip_packet.h delete mode 100644 vnet/vnet/ip/ip_source_and_port_range_check.h delete mode 100644 vnet/vnet/ip/lookup.c delete mode 100644 vnet/vnet/ip/lookup.h delete mode 100644 vnet/vnet/ip/ping.c delete mode 100644 vnet/vnet/ip/ping.h delete mode 100644 vnet/vnet/ip/ports.def delete mode 100644 vnet/vnet/ip/protocols.def delete mode 100644 vnet/vnet/ip/punt.c delete mode 100644 vnet/vnet/ip/punt.h delete mode 100644 vnet/vnet/ip/punt_error.def delete mode 100644 vnet/vnet/ip/tcp_packet.h delete mode 100644 vnet/vnet/ip/udp.h delete mode 100644 vnet/vnet/ip/udp_error.def delete mode 100644 vnet/vnet/ip/udp_format.c delete mode 100644 vnet/vnet/ip/udp_init.c delete mode 100644 vnet/vnet/ip/udp_local.c delete mode 100644 vnet/vnet/ip/udp_packet.h delete mode 100644 vnet/vnet/ip/udp_pg.c delete mode 100644 vnet/vnet/ipsec-gre/dir.dox delete mode 100644 vnet/vnet/ipsec-gre/error.def delete mode 100644 vnet/vnet/ipsec-gre/interface.c delete mode 100644 vnet/vnet/ipsec-gre/ipsec_gre.api delete mode 100644 vnet/vnet/ipsec-gre/ipsec_gre.c delete mode 100644 vnet/vnet/ipsec-gre/ipsec_gre.h delete mode 100644 vnet/vnet/ipsec-gre/ipsec_gre_api.c delete mode 100644 vnet/vnet/ipsec-gre/ipsec_gre_doc.md delete mode 100644 vnet/vnet/ipsec-gre/node.c delete mode 100644 vnet/vnet/ipsec/esp.h delete mode 100644 vnet/vnet/ipsec/esp_decrypt.c delete mode 100644 vnet/vnet/ipsec/esp_encrypt.c delete mode 100644 vnet/vnet/ipsec/ikev2.c delete mode 100644 vnet/vnet/ipsec/ikev2.h delete mode 100644 vnet/vnet/ipsec/ikev2_cli.c delete mode 100644 vnet/vnet/ipsec/ikev2_crypto.c delete mode 100644 vnet/vnet/ipsec/ikev2_format.c delete mode 100644 vnet/vnet/ipsec/ikev2_payload.c delete mode 100644 vnet/vnet/ipsec/ikev2_priv.h delete mode 100644 vnet/vnet/ipsec/ipsec.api delete mode 100644 vnet/vnet/ipsec/ipsec.c delete mode 100644 vnet/vnet/ipsec/ipsec.h delete mode 100644 vnet/vnet/ipsec/ipsec_api.c delete mode 100644 vnet/vnet/ipsec/ipsec_cli.c delete mode 100644 vnet/vnet/ipsec/ipsec_format.c delete mode 100644 vnet/vnet/ipsec/ipsec_if.c delete mode 100644 vnet/vnet/ipsec/ipsec_if_in.c delete mode 100644 vnet/vnet/ipsec/ipsec_if_out.c delete mode 100644 vnet/vnet/ipsec/ipsec_input.c delete mode 100644 vnet/vnet/ipsec/ipsec_output.c delete mode 100644 vnet/vnet/l2/dir.dox delete mode 100644 vnet/vnet/l2/feat_bitmap.c delete mode 100644 vnet/vnet/l2/feat_bitmap.h delete mode 100644 vnet/vnet/l2/l2.api delete mode 100644 vnet/vnet/l2/l2_api.c delete mode 100644 vnet/vnet/l2/l2_bd.c delete mode 100644 vnet/vnet/l2/l2_bd.h delete mode 100644 vnet/vnet/l2/l2_bvi.c delete mode 100644 vnet/vnet/l2/l2_bvi.h delete mode 100644 vnet/vnet/l2/l2_classify.h delete mode 100644 vnet/vnet/l2/l2_efp_filter.c delete mode 100644 vnet/vnet/l2/l2_efp_filter.h delete mode 100644 vnet/vnet/l2/l2_fib.c delete mode 100644 vnet/vnet/l2/l2_fib.h delete mode 100644 vnet/vnet/l2/l2_flood.c delete mode 100644 vnet/vnet/l2/l2_flood.h delete mode 100644 vnet/vnet/l2/l2_fwd.c delete mode 100644 vnet/vnet/l2/l2_fwd.h delete mode 100644 vnet/vnet/l2/l2_input.c delete mode 100644 vnet/vnet/l2/l2_input.h delete mode 100644 vnet/vnet/l2/l2_input_acl.c delete mode 100644 vnet/vnet/l2/l2_input_classify.c delete mode 100644 vnet/vnet/l2/l2_input_vtr.c delete mode 100644 vnet/vnet/l2/l2_input_vtr.h delete mode 100644 vnet/vnet/l2/l2_learn.c delete mode 100644 vnet/vnet/l2/l2_learn.h delete mode 100644 vnet/vnet/l2/l2_output.c delete mode 100644 vnet/vnet/l2/l2_output.h delete mode 100644 vnet/vnet/l2/l2_output_acl.c delete mode 100644 vnet/vnet/l2/l2_output_classify.c delete mode 100644 vnet/vnet/l2/l2_patch.c delete mode 100644 vnet/vnet/l2/l2_rw.c delete mode 100644 vnet/vnet/l2/l2_rw.h delete mode 100644 vnet/vnet/l2/l2_vtr.c delete mode 100644 vnet/vnet/l2/l2_vtr.h delete mode 100644 vnet/vnet/l2/l2_xcrw.c delete mode 100644 vnet/vnet/l2/l2_xcrw.h delete mode 100644 vnet/vnet/l2tp/decap.c delete mode 100644 vnet/vnet/l2tp/encap.c delete mode 100644 vnet/vnet/l2tp/l2tp.api delete mode 100644 vnet/vnet/l2tp/l2tp.c delete mode 100644 vnet/vnet/l2tp/l2tp.h delete mode 100644 vnet/vnet/l2tp/l2tp_api.c delete mode 100644 vnet/vnet/l2tp/packet.h delete mode 100644 vnet/vnet/l2tp/pg.c delete mode 100644 vnet/vnet/l3_types.h delete mode 100644 vnet/vnet/lawful-intercept/lawful_intercept.c delete mode 100644 vnet/vnet/lawful-intercept/lawful_intercept.h delete mode 100644 vnet/vnet/lawful-intercept/node.c delete mode 100644 vnet/vnet/lisp-cp/control.c delete mode 100644 vnet/vnet/lisp-cp/control.h delete mode 100644 vnet/vnet/lisp-cp/gid_dictionary.c delete mode 100644 vnet/vnet/lisp-cp/gid_dictionary.h delete mode 100644 vnet/vnet/lisp-cp/lisp.api delete mode 100644 vnet/vnet/lisp-cp/lisp_api.c delete mode 100644 vnet/vnet/lisp-cp/lisp_cp_dpo.c delete mode 100644 vnet/vnet/lisp-cp/lisp_cp_dpo.h delete mode 100644 vnet/vnet/lisp-cp/lisp_cp_messages.h delete mode 100644 vnet/vnet/lisp-cp/lisp_msg_serdes.c delete mode 100644 vnet/vnet/lisp-cp/lisp_msg_serdes.h delete mode 100644 vnet/vnet/lisp-cp/lisp_types.c delete mode 100644 vnet/vnet/lisp-cp/lisp_types.h delete mode 100644 vnet/vnet/lisp-cp/packets.c delete mode 100644 vnet/vnet/lisp-cp/packets.h delete mode 100644 vnet/vnet/lisp-gpe/decap.c delete mode 100644 vnet/vnet/lisp-gpe/dir.dox delete mode 100644 vnet/vnet/lisp-gpe/interface.c delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe.api delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe.c delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe.h delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_adjacency.c delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_adjacency.h delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_api.c delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_error.def delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_fwd_entry.c delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_fwd_entry.h delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_packet.h delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_sub_interface.c delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_sub_interface.h delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_tenant.c delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_tenant.h delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_tunnel.c delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_tunnel.h delete mode 100644 vnet/vnet/lisp-gpe/rfc.txt delete mode 100644 vnet/vnet/llc/llc.c delete mode 100644 vnet/vnet/llc/llc.h delete mode 100644 vnet/vnet/llc/node.c delete mode 100644 vnet/vnet/llc/pg.c delete mode 100644 vnet/vnet/lldp/dir.dox delete mode 100644 vnet/vnet/lldp/lldp_cli.c delete mode 100644 vnet/vnet/lldp/lldp_doc.md delete mode 100644 vnet/vnet/lldp/lldp_input.c delete mode 100644 vnet/vnet/lldp/lldp_node.c delete mode 100644 vnet/vnet/lldp/lldp_node.h delete mode 100644 vnet/vnet/lldp/lldp_output.c delete mode 100644 vnet/vnet/lldp/lldp_protocol.h delete mode 100755 vnet/vnet/map/examples/gen-rules.py delete mode 100644 vnet/vnet/map/examples/health_check.c delete mode 100755 vnet/vnet/map/examples/test_map.py delete mode 100755 vnet/vnet/map/gen-rules.py delete mode 100644 vnet/vnet/map/ip4_map.c delete mode 100644 vnet/vnet/map/ip4_map_t.c delete mode 100644 vnet/vnet/map/ip6_map.c delete mode 100644 vnet/vnet/map/ip6_map_t.c delete mode 100644 vnet/vnet/map/map.api delete mode 100644 vnet/vnet/map/map.c delete mode 100644 vnet/vnet/map/map.h delete mode 100644 vnet/vnet/map/map_api.c delete mode 100644 vnet/vnet/map/map_doc.md delete mode 100644 vnet/vnet/map/map_dpo.c delete mode 100644 vnet/vnet/map/map_dpo.h delete mode 100644 vnet/vnet/map/test.c delete mode 100644 vnet/vnet/mcast/mcast.c delete mode 100644 vnet/vnet/mcast/mcast.h delete mode 100644 vnet/vnet/mcast/mcast_test.c delete mode 100644 vnet/vnet/misc.c delete mode 100644 vnet/vnet/mpls/error.def delete mode 100644 vnet/vnet/mpls/interface.c delete mode 100644 vnet/vnet/mpls/mpls.c delete mode 100644 vnet/vnet/mpls/mpls.h delete mode 100644 vnet/vnet/mpls/mpls_features.c delete mode 100644 vnet/vnet/mpls/mpls_lookup.c delete mode 100644 vnet/vnet/mpls/mpls_output.c delete mode 100644 vnet/vnet/mpls/mpls_tunnel.c delete mode 100644 vnet/vnet/mpls/mpls_tunnel.h delete mode 100644 vnet/vnet/mpls/mpls_types.h delete mode 100644 vnet/vnet/mpls/node.c delete mode 100644 vnet/vnet/mpls/packet.h delete mode 100644 vnet/vnet/mpls/pg.c delete mode 100644 vnet/vnet/osi/node.c delete mode 100644 vnet/vnet/osi/osi.c delete mode 100644 vnet/vnet/osi/osi.h delete mode 100644 vnet/vnet/osi/pg.c delete mode 100644 vnet/vnet/pg/cli.c delete mode 100644 vnet/vnet/pg/edit.c delete mode 100644 vnet/vnet/pg/edit.h delete mode 100644 vnet/vnet/pg/example.script delete mode 100644 vnet/vnet/pg/init.c delete mode 100644 vnet/vnet/pg/input.c delete mode 100644 vnet/vnet/pg/output.c delete mode 100644 vnet/vnet/pg/pg.h delete mode 100644 vnet/vnet/pg/stream.c delete mode 100644 vnet/vnet/pipeline.h delete mode 100644 vnet/vnet/plugin/p1.c delete mode 100644 vnet/vnet/plugin/plugin.h delete mode 100644 vnet/vnet/policer/node_funcs.c delete mode 100644 vnet/vnet/policer/police.h delete mode 100644 vnet/vnet/policer/policer.c delete mode 100644 vnet/vnet/policer/policer.h delete mode 100644 vnet/vnet/policer/xlate.c delete mode 100644 vnet/vnet/policer/xlate.h delete mode 100644 vnet/vnet/ppp/error.def delete mode 100644 vnet/vnet/ppp/node.c delete mode 100644 vnet/vnet/ppp/packet.h delete mode 100644 vnet/vnet/ppp/pg.c delete mode 100644 vnet/vnet/ppp/ppp.c delete mode 100644 vnet/vnet/ppp/ppp.h delete mode 100644 vnet/vnet/replication.c delete mode 100644 vnet/vnet/replication.h delete mode 100644 vnet/vnet/rewrite.c delete mode 100644 vnet/vnet/rewrite.h delete mode 100644 vnet/vnet/snap/node.c delete mode 100644 vnet/vnet/snap/pg.c delete mode 100644 vnet/vnet/snap/snap.c delete mode 100644 vnet/vnet/snap/snap.h delete mode 100644 vnet/vnet/span/node.c delete mode 100644 vnet/vnet/span/span.api delete mode 100644 vnet/vnet/span/span.c delete mode 100644 vnet/vnet/span/span.h delete mode 100644 vnet/vnet/span/span.md delete mode 100644 vnet/vnet/span/span_api.c delete mode 100644 vnet/vnet/sr/dir.dox delete mode 100644 vnet/vnet/sr/examples/sr_multicastmap.script delete mode 100644 vnet/vnet/sr/rfc_draft_05.txt delete mode 100644 vnet/vnet/sr/sr.c delete mode 100644 vnet/vnet/sr/sr.h delete mode 100644 vnet/vnet/sr/sr_error.def delete mode 100644 vnet/vnet/sr/sr_fix_dst_error.def delete mode 100644 vnet/vnet/sr/sr_packet.h delete mode 100644 vnet/vnet/sr/sr_replicate.c delete mode 100644 vnet/vnet/srp/format.c delete mode 100644 vnet/vnet/srp/interface.c delete mode 100644 vnet/vnet/srp/node.c delete mode 100644 vnet/vnet/srp/packet.h delete mode 100644 vnet/vnet/srp/pg.c delete mode 100644 vnet/vnet/srp/srp.h delete mode 100644 vnet/vnet/unix/gdb_funcs.c delete mode 100644 vnet/vnet/unix/pcap.c delete mode 100644 vnet/vnet/unix/pcap.h delete mode 100644 vnet/vnet/unix/pcap2pg.c delete mode 100644 vnet/vnet/unix/tap.api delete mode 100644 vnet/vnet/unix/tap_api.c delete mode 100644 vnet/vnet/unix/tapcli.c delete mode 100644 vnet/vnet/unix/tapcli.h delete mode 100644 vnet/vnet/unix/tuntap.c delete mode 100644 vnet/vnet/unix/tuntap.h delete mode 100644 vnet/vnet/vnet.h delete mode 100644 vnet/vnet/vnet_all_api_h.h delete mode 100644 vnet/vnet/vnet_msg_enum.h delete mode 100644 vnet/vnet/vxlan-gpe/decap.c delete mode 100644 vnet/vnet/vxlan-gpe/dir.dox delete mode 100644 vnet/vnet/vxlan-gpe/encap.c delete mode 100644 vnet/vnet/vxlan-gpe/vxlan-gpe-rfc.txt delete mode 100644 vnet/vnet/vxlan-gpe/vxlan_gpe.api delete mode 100644 vnet/vnet/vxlan-gpe/vxlan_gpe.c delete mode 100644 vnet/vnet/vxlan-gpe/vxlan_gpe.h delete mode 100644 vnet/vnet/vxlan-gpe/vxlan_gpe_api.c delete mode 100644 vnet/vnet/vxlan-gpe/vxlan_gpe_error.def delete mode 100644 vnet/vnet/vxlan-gpe/vxlan_gpe_packet.h delete mode 100644 vnet/vnet/vxlan/decap.c delete mode 100644 vnet/vnet/vxlan/dir.dox delete mode 100644 vnet/vnet/vxlan/encap.c delete mode 100644 vnet/vnet/vxlan/vxlan.api delete mode 100644 vnet/vnet/vxlan/vxlan.c delete mode 100644 vnet/vnet/vxlan/vxlan.h delete mode 100644 vnet/vnet/vxlan/vxlan_api.c delete mode 100644 vnet/vnet/vxlan/vxlan_error.def delete mode 100644 vnet/vnet/vxlan/vxlan_packet.h delete mode 100644 vpp-api-test/Makefile.am delete mode 100644 vpp-api-test/configure.ac delete mode 100755 vpp-api-test/scripts/vppctl delete mode 100644 vpp-api-test/vat/api_format.c delete mode 100644 vpp-api-test/vat/json_format.c delete mode 100644 vpp-api-test/vat/json_format.h delete mode 100644 vpp-api-test/vat/json_test.c delete mode 100644 vpp-api-test/vat/main.c delete mode 100644 vpp-api-test/vat/plugin.c delete mode 100644 vpp-api-test/vat/plugin.h delete mode 100644 vpp-api-test/vat/plugin_api.c delete mode 100644 vpp-api-test/vat/restart.c delete mode 100644 vpp-api-test/vat/vat.h delete mode 100644 vpp-api/python/Makefile.am delete mode 100644 vpp-api/python/README.rst delete mode 100644 vpp-api/python/pneum/pneum.c delete mode 100644 vpp-api/python/pneum/pneum.h delete mode 100644 vpp-api/python/pneum/test_pneum.c delete mode 100644 vpp-api/python/setup.cfg delete mode 100644 vpp-api/python/setup.py delete mode 100755 vpp-api/python/tests/test_cli.py delete mode 100755 vpp-api/python/tests/test_modules.py delete mode 100755 vpp-api/python/tests/test_papi.py delete mode 100755 vpp-api/python/tests/test_version.py delete mode 100755 vpp-api/python/tests/test_vpp_papi2.py delete mode 100644 vpp-api/python/vpp_papi/__init__.py delete mode 100644 vpp-api/python/vpp_papi/pneum_wrap.c delete mode 100644 vpp-api/python/vpp_papi/vpp_papi.py delete mode 100644 vpp/Makefile.am delete mode 100644 vpp/app/l2t.c delete mode 100644 vpp/app/l2t_l2.c delete mode 100644 vpp/app/sticky_hash.c delete mode 100644 vpp/app/version.c delete mode 100644 vpp/app/vpe_cli.c delete mode 100644 vpp/conf/80-vpp.conf delete mode 100644 vpp/conf/startup.conf delete mode 100644 vpp/conf/startup.uiopcigeneric.conf delete mode 100644 vpp/configure.ac delete mode 100644 vpp/oam/oam.c delete mode 100644 vpp/oam/oam.h delete mode 100644 vpp/stats/stats.c delete mode 100644 vpp/stats/stats.h delete mode 120000 vpp/suffix-rules.mk delete mode 100644 vpp/vnet/main.c delete mode 100644 vpp/vpp-api/api.c delete mode 120000 vpp/vpp-api/api_format.c delete mode 100644 vpp/vpp-api/api_main.c delete mode 100644 vpp/vpp-api/custom_dump.c delete mode 100644 vpp/vpp-api/gmon.c delete mode 100644 vpp/vpp-api/json_format.c delete mode 100644 vpp/vpp-api/json_format.h delete mode 100644 vpp/vpp-api/summary_stats_client.c delete mode 100644 vpp/vpp-api/test_client.c delete mode 100644 vpp/vpp-api/test_ha.c delete mode 120000 vpp/vpp-api/vat.h delete mode 100644 vpp/vpp-api/vpe.api delete mode 100644 vpp/vpp-api/vpe_all_api_h.h delete mode 100644 vpp/vpp-api/vpe_msg_enum.h delete mode 100644 vpp/vpp-api/vpp_get_metrics.c delete mode 100644 vppapigen/Makefile.am delete mode 100644 vppapigen/configure.ac delete mode 100644 vppapigen/gram.y delete mode 100644 vppapigen/lex.c delete mode 100644 vppapigen/lex.h delete mode 100644 vppapigen/node.c delete mode 100644 vppapigen/node.h delete mode 100644 vppinfra/.gitignore delete mode 100644 vppinfra/INSTALL delete mode 100644 vppinfra/Make.defs delete mode 100644 vppinfra/Makefile.am delete mode 100644 vppinfra/README delete mode 100644 vppinfra/configure.ac delete mode 100644 vppinfra/dir.dox delete mode 100755 vppinfra/mkinstalldirs delete mode 100644 vppinfra/tools/dir.dox delete mode 100644 vppinfra/tools/elftool.c delete mode 100644 vppinfra/unix_error.def delete mode 100644 vppinfra/vppinfra/anneal.c delete mode 100644 vppinfra/vppinfra/anneal.h delete mode 100644 vppinfra/vppinfra/asm_mips.h delete mode 100644 vppinfra/vppinfra/asm_x86.c delete mode 100644 vppinfra/vppinfra/asm_x86.h delete mode 100644 vppinfra/vppinfra/backtrace.c delete mode 100644 vppinfra/vppinfra/bihash_24_8.h delete mode 100644 vppinfra/vppinfra/bihash_8_8.h delete mode 100644 vppinfra/vppinfra/bihash_doc.h delete mode 100644 vppinfra/vppinfra/bihash_template.c delete mode 100644 vppinfra/vppinfra/bihash_template.h delete mode 100644 vppinfra/vppinfra/bitmap.h delete mode 100644 vppinfra/vppinfra/bitops.h delete mode 100644 vppinfra/vppinfra/byte_order.h delete mode 100644 vppinfra/vppinfra/cache.h delete mode 100644 vppinfra/vppinfra/clib.h delete mode 100644 vppinfra/vppinfra/cpu.c delete mode 100644 vppinfra/vppinfra/cpu.h delete mode 100644 vppinfra/vppinfra/dir.dox delete mode 100644 vppinfra/vppinfra/dlist.h delete mode 100644 vppinfra/vppinfra/elf.c delete mode 100644 vppinfra/vppinfra/elf.h delete mode 100644 vppinfra/vppinfra/elf_clib.c delete mode 100644 vppinfra/vppinfra/elf_clib.h delete mode 100644 vppinfra/vppinfra/elog.c delete mode 100644 vppinfra/vppinfra/elog.h delete mode 100644 vppinfra/vppinfra/error.c delete mode 100644 vppinfra/vppinfra/error.h delete mode 100644 vppinfra/vppinfra/error_bootstrap.h delete mode 100644 vppinfra/vppinfra/fheap.c delete mode 100644 vppinfra/vppinfra/fheap.h delete mode 100644 vppinfra/vppinfra/fifo.c delete mode 100644 vppinfra/vppinfra/fifo.h delete mode 100644 vppinfra/vppinfra/format.c delete mode 100644 vppinfra/vppinfra/format.h delete mode 100644 vppinfra/vppinfra/graph.c delete mode 100644 vppinfra/vppinfra/graph.h delete mode 100644 vppinfra/vppinfra/hash.c delete mode 100644 vppinfra/vppinfra/hash.h delete mode 100644 vppinfra/vppinfra/heap.c delete mode 100644 vppinfra/vppinfra/heap.h delete mode 100644 vppinfra/vppinfra/longjmp.S delete mode 100644 vppinfra/vppinfra/longjmp.h delete mode 100644 vppinfra/vppinfra/macros.c delete mode 100644 vppinfra/vppinfra/macros.h delete mode 100644 vppinfra/vppinfra/math.h delete mode 100644 vppinfra/vppinfra/md5.c delete mode 100644 vppinfra/vppinfra/md5.h delete mode 100644 vppinfra/vppinfra/mem.h delete mode 100644 vppinfra/vppinfra/mem_mheap.c delete mode 100644 vppinfra/vppinfra/memcheck.h delete mode 100644 vppinfra/vppinfra/memcpy_avx.h delete mode 100644 vppinfra/vppinfra/memcpy_sse3.h delete mode 100644 vppinfra/vppinfra/mhash.c delete mode 100644 vppinfra/vppinfra/mhash.h delete mode 100644 vppinfra/vppinfra/mheap.c delete mode 100644 vppinfra/vppinfra/mheap.h delete mode 100644 vppinfra/vppinfra/mheap_bootstrap.h delete mode 100644 vppinfra/vppinfra/mod_test_hash.c delete mode 100644 vppinfra/vppinfra/os.h delete mode 100644 vppinfra/vppinfra/pfhash.c delete mode 100644 vppinfra/vppinfra/pfhash.h delete mode 100644 vppinfra/vppinfra/phash.c delete mode 100644 vppinfra/vppinfra/phash.h delete mode 100644 vppinfra/vppinfra/pipeline.h delete mode 100644 vppinfra/vppinfra/pool.h delete mode 100644 vppinfra/vppinfra/ptclosure.c delete mode 100644 vppinfra/vppinfra/ptclosure.h delete mode 100644 vppinfra/vppinfra/qhash.c delete mode 100644 vppinfra/vppinfra/qhash.h delete mode 100644 vppinfra/vppinfra/qsort.c delete mode 100644 vppinfra/vppinfra/random.c delete mode 100644 vppinfra/vppinfra/random.h delete mode 100644 vppinfra/vppinfra/random_buffer.c delete mode 100644 vppinfra/vppinfra/random_buffer.h delete mode 100644 vppinfra/vppinfra/random_isaac.c delete mode 100644 vppinfra/vppinfra/random_isaac.h delete mode 100644 vppinfra/vppinfra/serialize.c delete mode 100644 vppinfra/vppinfra/serialize.h delete mode 100644 vppinfra/vppinfra/slist.c delete mode 100644 vppinfra/vppinfra/slist.h delete mode 100644 vppinfra/vppinfra/smp.c delete mode 100644 vppinfra/vppinfra/smp.h delete mode 100644 vppinfra/vppinfra/smp_fifo.c delete mode 100644 vppinfra/vppinfra/smp_fifo.h delete mode 100644 vppinfra/vppinfra/socket.c delete mode 100644 vppinfra/vppinfra/socket.h delete mode 100644 vppinfra/vppinfra/sparse_vec.h delete mode 100644 vppinfra/vppinfra/std-formats.c delete mode 100644 vppinfra/vppinfra/string.c delete mode 100644 vppinfra/vppinfra/string.h delete mode 100644 vppinfra/vppinfra/test_bihash_template.c delete mode 100644 vppinfra/vppinfra/test_dlist.c delete mode 100644 vppinfra/vppinfra/test_elf.c delete mode 100644 vppinfra/vppinfra/test_elog.c delete mode 100644 vppinfra/vppinfra/test_fifo.c delete mode 100644 vppinfra/vppinfra/test_format.c delete mode 100644 vppinfra/vppinfra/test_hash.c delete mode 100644 vppinfra/vppinfra/test_heap.c delete mode 100644 vppinfra/vppinfra/test_longjmp.c delete mode 100644 vppinfra/vppinfra/test_macros.c delete mode 100644 vppinfra/vppinfra/test_md5.c delete mode 100644 vppinfra/vppinfra/test_mheap.c delete mode 100644 vppinfra/vppinfra/test_pfhash.c delete mode 100644 vppinfra/vppinfra/test_phash.c delete mode 100644 vppinfra/vppinfra/test_pool.c delete mode 100644 vppinfra/vppinfra/test_pool_iterate.c delete mode 100644 vppinfra/vppinfra/test_ptclosure.c delete mode 100644 vppinfra/vppinfra/test_qhash.c delete mode 100644 vppinfra/vppinfra/test_random.c delete mode 100644 vppinfra/vppinfra/test_random_isaac.c delete mode 100644 vppinfra/vppinfra/test_serialize.c delete mode 100644 vppinfra/vppinfra/test_slist.c delete mode 100644 vppinfra/vppinfra/test_socket.c delete mode 100644 vppinfra/vppinfra/test_time.c delete mode 100644 vppinfra/vppinfra/test_timing_wheel.c delete mode 100644 vppinfra/vppinfra/test_vec.c delete mode 100644 vppinfra/vppinfra/test_vec.h delete mode 100644 vppinfra/vppinfra/test_vhash.c delete mode 100644 vppinfra/vppinfra/test_zvec.c delete mode 100644 vppinfra/vppinfra/time.c delete mode 100644 vppinfra/vppinfra/time.h delete mode 100644 vppinfra/vppinfra/timer.c delete mode 100644 vppinfra/vppinfra/timer.h delete mode 100644 vppinfra/vppinfra/timing_wheel.c delete mode 100644 vppinfra/vppinfra/timing_wheel.h delete mode 100644 vppinfra/vppinfra/types.h delete mode 100644 vppinfra/vppinfra/unformat.c delete mode 100644 vppinfra/vppinfra/unix-formats.c delete mode 100644 vppinfra/vppinfra/unix-kelog.c delete mode 100644 vppinfra/vppinfra/unix-misc.c delete mode 100644 vppinfra/vppinfra/unix.h delete mode 100644 vppinfra/vppinfra/valgrind.h delete mode 100644 vppinfra/vppinfra/vec.c delete mode 100644 vppinfra/vppinfra/vec.h delete mode 100644 vppinfra/vppinfra/vec_bootstrap.h delete mode 100644 vppinfra/vppinfra/vector.c delete mode 100644 vppinfra/vppinfra/vector.h delete mode 100644 vppinfra/vppinfra/vector_altivec.h delete mode 100644 vppinfra/vppinfra/vector_funcs.h delete mode 100644 vppinfra/vppinfra/vector_iwmmxt.h delete mode 100644 vppinfra/vppinfra/vector_neon.h delete mode 100644 vppinfra/vppinfra/vector_sse2.h delete mode 100644 vppinfra/vppinfra/vhash.c delete mode 100644 vppinfra/vppinfra/vhash.h delete mode 100644 vppinfra/vppinfra/vm_linux_kernel.h delete mode 100644 vppinfra/vppinfra/vm_standalone.h delete mode 100644 vppinfra/vppinfra/vm_unix.h delete mode 100644 vppinfra/vppinfra/xxhash.h delete mode 100644 vppinfra/vppinfra/xy.h delete mode 100644 vppinfra/vppinfra/zvec.c delete mode 100644 vppinfra/vppinfra/zvec.h (limited to 'build-data/platforms.mk') diff --git a/Makefile b/Makefile index 292b0d28..1b75779a 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ 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 +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 @@ -147,7 +147,7 @@ else @ln -s /usr/bin/ccache $(BR)/tools/ccache-bin/gcc @ln -s /usr/bin/ccache $(BR)/tools/ccache-bin/g++ endif - @make -C $(BR) V=$(V) is_build_tool=yes vppapigen-install + @make -C $(BR) V=$(V) is_build_tool=yes tools-install @touch $@ bootstrap: $(BR)/.bootstrap.ok diff --git a/build-data/packages/cavium-dpdk.mk b/build-data/packages/cavium-dpdk.mk deleted file mode 100644 index ce8ee228..00000000 --- a/build-data/packages/cavium-dpdk.mk +++ /dev/null @@ -1,55 +0,0 @@ -# Temporary until Cavium upstreams their work - -cavium-dpdk_configure = \ - src_dir=$(call find_source_fn,$(PACKAGE_SOURCE)) ; \ - dst_dir=$(PACKAGE_BUILD_DIR) ; \ - tar -C $${src_dir} -cf - . | tar -C $${dst_dir} -xf - ; \ - cd $${dst_dir} ; \ - : colossal hemorrhoid to configure headroom ; \ - if [ x$($(PACKAGE)_configure_args_$(PLATFORM)) = "x" ] ; then \ - HR=256 ; \ - else \ - dpdk_configure_args=$($(PACKAGE)_configure_args_$(PLATFORM)) ; \ - if [ $$dpdk_configure_args = "--with-headroom=256" ] ; then \ - HR=256 ; \ - elif [ $$dpdk_configure_args = "--with-headroom=384" ] ; then \ - HR=384 ; \ - else \ - HR=256 ; \ - fi ; \ - fi ; \ - env HR=$$HR \ - spp -o \ - $(PACKAGE_BUILD_DIR)/config/common_linuxapp \ - $(PACKAGE_BUILD_DIR)/config/common_linuxapp.spp \ - ; \ - env $(CONFIGURE_ENV) \ - make config T=arm64-thunderx-linuxapp-gcc RTE_ARCH=arm64 \ - CC=aarch64-thunderx-linux-gnu-gcc V=0 \ - RTE_SDK=$(PACKAGE_BUILD_DIR) \ - RTE_TARGET=arm-default-linuxapp-gcc - -# Note: add e.g. "-O0" to EXTRA_CFLAGS if desired: EXTRA_CFLAGS='-g -O0' - -cavium-dpdk_make_args = install T=arm64-thunderx-linuxapp-gcc RTE_ARCH=arm64 \ - CC=aarch64-thunderx-linux-gnu-gcc V=0 \ - RTE_SDK=$(PACKAGE_BUILD_DIR) \ - RTE_TARGET=arm-default-linuxapp-gcc - -cavium-dpdk_install = \ - src_dir=$(PACKAGE_BUILD_DIR) ; \ - dst_dir=$(PACKAGE_INSTALL_DIR) ; \ - tar -h -C $${src_dir}/arm64-thunderx-linuxapp-gcc -cf - . \ - | tar -C $${dst_dir} -xf - - -# dpdk libraries end up in .../lib not .../lib64. Fix it. -cavium-dpdk_post_install = \ - if [ "$(arch_lib_dir)" != "lib" ] ; then \ - mkdir -p $(PACKAGE_INSTALL_DIR)/$(arch_lib_dir) ; \ - cd $(PACKAGE_INSTALL_DIR)/lib ; \ - tar cf - . | ( cd $(PACKAGE_INSTALL_DIR)/$(arch_lib_dir); tar xf - ) ; \ - fi - -# nothing to install, all static libraries -cavium-dpdk_image_include = echo - diff --git a/build-data/packages/g2.mk b/build-data/packages/g2.mk index 258eff1d..9b760e63 100644 --- a/build-data/packages/g2.mk +++ b/build-data/packages/g2.mk @@ -1,5 +1,3 @@ -g2_configure_depend = vppinfra-install +g2_source = src -g2_CPPFLAGS = $(call installed_includes_fn, vppinfra) - -g2_LDFLAGS = $(call installed_libs_fn, vppinfra) +g2_configure_args = --disable-vlib --disable-svm --enable-g2 diff --git a/build-data/packages/gmod.mk b/build-data/packages/gmod.mk index a6ba42d0..6fa7e0f1 100644 --- a/build-data/packages/gmod.mk +++ b/build-data/packages/gmod.mk @@ -1,9 +1,9 @@ -gmod_configure_depend = vppinfra-install svm-install +gmod_configure_depend = vpp-install gmod_configure_args = --libdir=$(PACKAGE_INSTALL_DIR)/$(arch_lib_dir)/ganglia -gmod_CPPFLAGS = $(call installed_includes_fn, vppinfra svm) +gmod_CPPFLAGS = $(call installed_includes_fn, vpp) gmod_CPPFLAGS += -I/usr/include/apr-1.0 -I/usr/include/apr-1 -I/usr/include -gmod_LDFLAGS = $(call installed_libs_fn, vppinfra svm) +gmod_LDFLAGS = $(call installed_libs_fn, vpp) gmod_image_include = echo $(arch_lib_dir)/ganglia/libgmodvpp.so etc diff --git a/build-data/packages/perftool.mk b/build-data/packages/perftool.mk index 300f902b..e582c316 100644 --- a/build-data/packages/perftool.mk +++ b/build-data/packages/perftool.mk @@ -1,5 +1,4 @@ -perftool_configure_depend = vppinfra-install +perftool_source = src -perftool_CPPFLAGS = $(call installed_includes_fn, vppinfra) +perftool_configure_args = --disable-vlib --disable-svm --enable-perftool -perftool_LDFLAGS = $(call installed_libs_fn, vppinfra) diff --git a/build-data/packages/plugins.mk b/build-data/packages/plugins.mk index 44a8e2bd..b4d67a28 100644 --- a/build-data/packages/plugins.mk +++ b/build-data/packages/plugins.mk @@ -1,24 +1,13 @@ plugins_configure_depend = \ - vppinfra-install \ - vlib-api-install \ - vpp-api-test-install \ - vnet-install \ - vlib-install \ - vpp-api-install + vpp-api-install \ + vpp-install -plugins_CPPFLAGS = $(call installed_includes_fn, \ - vppinfra \ - vlib \ - vnet \ - svm \ - vpp-api-test \ - vlib-api \ - vpp-api) +plugins_CPPFLAGS = $(call installed_includes_fn, \ + vpp \ + vpp-api) -plugins_LDFLAGS = $(call installed_libs_fn, \ - vppinfra \ - vlib \ - vlib-api) +plugins_LDFLAGS = $(call installed_libs_fn, \ + vpp) ifeq ($($(PLATFORM)_enable_tests),yes) plugins_configure_args += --enable-tests diff --git a/build-data/packages/src.mk b/build-data/packages/src.mk new file mode 100644 index 00000000..e69de29b diff --git a/build-data/packages/svm.mk b/build-data/packages/svm.mk deleted file mode 100644 index 3971fe82..00000000 --- a/build-data/packages/svm.mk +++ /dev/null @@ -1,5 +0,0 @@ -svm_top_srcdir = $(call find_source_fn,svm) -svm_configure_depend = vppinfra-install - -svm_CPPFLAGS = $(call installed_includes_fn, vppinfra) -svm_LDFLAGS = $(call installed_libs_fn, vppinfra) diff --git a/build-data/packages/vlib-api-cavium-dpdk.mk b/build-data/packages/vlib-api-cavium-dpdk.mk deleted file mode 100644 index 7a4fe2cd..00000000 --- a/build-data/packages/vlib-api-cavium-dpdk.mk +++ /dev/null @@ -1,6 +0,0 @@ -vlib-api-cavium-dpdk_source = vlib-api - -vlib-api-cavium-dpdk_configure_depend = vppinfra-install svm-install vlib-cavium-dpdk-install - -vlib-api-cavium-dpdk_CPPFLAGS = $(call installed_includes_fn, vppinfra svm vlib-cavium-dpdk) -vlib-api-cavium-dpdk_LDFLAGS = $(call installed_libs_fn, vppinfra svm vlib-cavium-dpdk) diff --git a/build-data/packages/vlib-api.mk b/build-data/packages/vlib-api.mk deleted file mode 100644 index 29b0d17d..00000000 --- a/build-data/packages/vlib-api.mk +++ /dev/null @@ -1,4 +0,0 @@ -vlib-api_configure_depend = vppinfra-install svm-install vlib-install - -vlib-api_CPPFLAGS = $(call installed_includes_fn, vppinfra svm vlib) -vlib-api_LDFLAGS = $(call installed_libs_fn, vppinfra svm vlib) diff --git a/build-data/packages/vlib-cavium-dpdk.mk b/build-data/packages/vlib-cavium-dpdk.mk deleted file mode 100644 index 0f2f132d..00000000 --- a/build-data/packages/vlib-cavium-dpdk.mk +++ /dev/null @@ -1,7 +0,0 @@ -vlib-cavium-dpdk_source = vlib -vlib-cavium-dpdk_configure_depend = vppinfra-install cavium-dpdk-install - -vlib-cavium-dpdk_configure_args += --with-dpdk - -vlib-cavium-dpdk_CPPFLAGS = $(call installed_includes_fn, vppinfra cavium-dpdk) -vlib-cavium-dpdk_LDFLAGS = $(call installed_libs_fn, vppinfra cavium-dpdk) diff --git a/build-data/packages/vlib.mk b/build-data/packages/vlib.mk deleted file mode 100644 index 2172708d..00000000 --- a/build-data/packages/vlib.mk +++ /dev/null @@ -1,16 +0,0 @@ -vlib_configure_depend = vppinfra-install - -vlib_CPPFLAGS = $(call installed_includes_fn, vppinfra) -vlib_LDFLAGS = $(call installed_libs_fn, vppinfra) - -ifneq ($($(PLATFORM)_uses_dpdk),no) -vlib_configure_args += --with-dpdk -ifeq ($($(PLATFORM)_uses_external_dpdk),yes) -vlib_CPPFLAGS += -I$($(PLATFORM)_dpdk_inc_dir) -vlib_LDFLAGS += -L$($(PLATFORM)_dpdk_lib_dir) -else -vlib_configure_depend += dpdk-install -vlib_CPPFLAGS += $(call installed_includes_fn, dpdk) -vlib_LDFLAGS += $(call installed_libs_fn, dpdk) -endif -endif diff --git a/build-data/packages/vnet-cavium-dpdk.mk b/build-data/packages/vnet-cavium-dpdk.mk deleted file mode 100644 index 4c35b04d..00000000 --- a/build-data/packages/vnet-cavium-dpdk.mk +++ /dev/null @@ -1,29 +0,0 @@ -vnet-cavium-dpdk_source = vnet - -vnet-cavium-dpdk_configure_depend = \ - vppinfra-install \ - cavium-dpdk-install \ - svm-install \ - vlib-api-cavium-dpdk-install \ - vlib-cavium-dpdk-install - - -vnet-cavium-dpdk_CPPFLAGS = $(call installed_includes_fn, \ - vppinfra \ - cavium-dpdk \ - openssl \ - svm \ - vlib-cavium-dpdk \ - vlib-api-cavium-dpdk) - -vnet-cavium-dpdk_LDFLAGS = $(call installed_libs_fn, \ - vppinfra \ - cavium-dpdk \ - openssl \ - svm \ - vlib-cavium-dpdk \ - vlib-api-cavium-dpdk) - -# Platform dependent configure flags -vnet-cavium-dpdk_configure_args += $(vnet-cavium-dpdk_configure_args_$(PLATFORM)) - diff --git a/build-data/packages/vpp-api-test-cavium-dpdk.mk b/build-data/packages/vpp-api-test-cavium-dpdk.mk deleted file mode 100644 index e352317f..00000000 --- a/build-data/packages/vpp-api-test-cavium-dpdk.mk +++ /dev/null @@ -1,32 +0,0 @@ -vpp-api-test-cavium-dpdk_source = vpp-api-test - -vpp-api-test-cavium-dpdk_configure_depend = \ - vppinfra-install \ - cavium-dpdk-install \ - svm-install \ - vlib-api-cavium-dpdk-install \ - vlib-cavium-dpdk-install \ - vnet-cavium-dpdk-install \ - vpp-cavium-dpdk-install - -# -vpp-api-test-cavium-dpdk_configure_args = --with-dpdk - -vpp-api-test-cavium-dpdk_CPPFLAGS = $(call installed_includes_fn, \ - vppinfra \ - cavium-dpdk \ - svm \ - vlib-cavium-dpdk \ - vlib-api-cavium-dpdk \ - vnet-cavium-dpdk \ - vpp-cavium-dpdk) - -vpp-api-test-cavium-dpdk_LDFLAGS = $(call installed_libs_fn, \ - vppinfra \ - cavium-dpdk \ - svm \ - vlib-cavium-dpdk \ - vlib-api-cavium-dpdk \ - vnet-cavium-dpdk \ - vpp-cavium-dpdk) - diff --git a/build-data/packages/vpp-api-test.mk b/build-data/packages/vpp-api-test.mk deleted file mode 100644 index c9eae367..00000000 --- a/build-data/packages/vpp-api-test.mk +++ /dev/null @@ -1,39 +0,0 @@ -vpp-api-test_configure_depend = \ - vppinfra-install \ - svm-install \ - vlib-api-install \ - vlib-install \ - vnet-install \ - vpp-install - -vpp-api-test_CPPFLAGS = $(call installed_includes_fn, \ - vppinfra \ - svm \ - vlib \ - vlib-api \ - vnet \ - vpp) - -vpp-api-test_LDFLAGS = $(call installed_libs_fn, \ - vppinfra \ - svm \ - vlib \ - vlib-api \ - vnet \ - vpp) - -ifneq ($($(PLATFORM)_uses_dpdk),no) -vpp-api-test_configure_args = --with-dpdk -ifeq ($($(PLATFORM)_uses_external_dpdk),yes) -vpp-api-test_CPPFLAGS += -I$($(PLATFORM)_dpdk_inc_dir) -vpp-api-test_LDFLAGS += -L$($(PLATFORM)_dpdk_lib_dir) -else -vpp-api-test_configure_depend += dpdk-install -vpp-api-test_CPPFLAGS += $(call installed_includes_fn, dpdk) -vpp-api-test_LDFLAGS += $(call installed_libs_fn, dpdk) -endif -endif -ifeq ($($(PLATFORM)_uses_dpdk_cryptodev),yes) -vpp-api-test_configure_args += --with-dpdk-crypto -endif - diff --git a/build-data/packages/vpp-api.mk b/build-data/packages/vpp-api.mk index 4937023a..d9e8d72e 100644 --- a/build-data/packages/vpp-api.mk +++ b/build-data/packages/vpp-api.mk @@ -1,23 +1,9 @@ vpp-api_configure_depend = \ - vppinfra-install \ - svm-install \ - vlib-api-install \ - vlib-install \ - vnet-install \ vpp-install vpp-api_CPPFLAGS = $(call installed_includes_fn, \ - vppinfra \ - svm \ - vlib \ - vlib-api \ - vnet \ vpp) -vpp-api_LDFLAGS = $(call installed_libs_fn, \ - vppinfra \ - svm \ - vlib \ - vlib-api) +vpp-api_LDFLAGS = vpp-api_CPPFLAGS += -I/usr/lib/jvm/java-8-openjdk-amd64/include diff --git a/build-data/packages/vpp-cavium-dpdk.mk b/build-data/packages/vpp-cavium-dpdk.mk deleted file mode 100644 index 704e3a95..00000000 --- a/build-data/packages/vpp-cavium-dpdk.mk +++ /dev/null @@ -1,30 +0,0 @@ -vpp-cavium-dpdk_source = vpp - -vpp-cavium-dpdk_configure_depend = \ - vppinfra-install \ - cavium-dpdk-install \ - svm-install \ - vlib-api-cavium-dpdk-install \ - vlib-cavium-dpdk-install \ - vnet-cavium-dpdk-install - -# Platform dependent configure flags -vpp-cavium-dpdk_configure_args += $(vpp-cavium-dpdk_configure_args_$(PLATFORM)) - -vpp-cavium-dpdk_CPPFLAGS = $(call installed_includes_fn, \ - vppinfra \ - cavium-dpdk \ - openssl \ - svm \ - vlib-cavium-dpdk \ - vlib-api-cavium-dpdk \ - vnet-cavium-dpdk) - -vpp-cavium-dpdk_LDFLAGS = $(call installed_libs_fn, \ - vppinfra \ - cavium-dpdk \ - openssl \ - svm \ - vlib-cavium-dpdk \ - vlib-api-cavium-dpdk \ - vnet-cavium-dpdk) diff --git a/build-data/packages/vpp.mk b/build-data/packages/vpp.mk index a3d60528..fe68cd82 100644 --- a/build-data/packages/vpp.mk +++ b/build-data/packages/vpp.mk @@ -1,11 +1,5 @@ -vpp_configure_depend = \ - vppinfra-install \ - svm-install \ - vlib-api-install \ - vlib-install \ - vnet-install \ +vpp_source = src -# ifeq ($($(PLATFORM)_dpdk_shared_lib),yes) vpp_configure_args = --enable-dpdk-shared else @@ -16,25 +10,8 @@ endif vpp_configure_args += $(vpp_configure_args_$(PLATFORM)) -vpp_CPPFLAGS = $(call installed_includes_fn, \ - vppinfra \ - svm \ - vlib \ - vlib-api \ - vnet) - -vpp_LDFLAGS = $(call installed_libs_fn, \ - vppinfra \ - svm \ - vlib \ - vlib-api \ - vnet) - -# include & link with openssl only if needed -ifneq ($($(PLATFORM)_uses_openssl),no) -vpp_CPPFLAGS += $(call installed_includes_fn, openssl) -vpp_LDFLAGS += $(call installed_libs_fn, openssl) -endif +vpp_CPPFLAGS = +vpp_LDFLAGS = ifneq ($($(PLATFORM)_uses_dpdk),no) ifeq ($($(PLATFORM)_uses_external_dpdk),yes) diff --git a/build-data/packages/vppinfra.mk b/build-data/packages/vppinfra.mk deleted file mode 100644 index 6ca6eb24..00000000 --- a/build-data/packages/vppinfra.mk +++ /dev/null @@ -1,5 +0,0 @@ - -ifeq ($($(PLATFORM)_enable_tests),yes) -vppinfra_configure_args += --enable-tests -endif - diff --git a/build-data/platforms.mk b/build-data/platforms.mk index a568c7a0..88dd3ed8 100644 --- a/build-data/platforms.mk +++ b/build-data/platforms.mk @@ -60,15 +60,15 @@ install-deb: $(patsubst %,%-find-source,$(ROOT_PACKAGES)) deb/debian/vpp-dpdk-dev.install ; \ \ : bin package needs startup config ; \ - echo ../../vpp/conf/startup.conf /etc/vpp \ + echo ../../src/vpp/conf/startup.conf /etc/vpp \ >> deb/debian/vpp.install ; \ \ : and sysctl config ; \ - echo ../../vpp/conf/80-vpp.conf /etc/sysctl.d \ + echo ../../src/vpp/conf/80-vpp.conf /etc/sysctl.d \ >> deb/debian/vpp.install ; \ \ : dev package needs a couple of additions ; \ - echo ../build-tool-native/vppapigen/vppapigen /usr/bin \ + echo ../build-tool-native/tools/vppapigen /usr/bin \ >> deb/debian/vpp-dev.install ; \ echo ../../vpp-api/java/jvpp/gen/jvpp_gen.py /usr/bin \ >> deb/debian/vpp-dev.install ; \ diff --git a/build-data/platforms/vpp.mk b/build-data/platforms/vpp.mk index 97ddc57d..513a4db4 100644 --- a/build-data/platforms/vpp.mk +++ b/build-data/platforms/vpp.mk @@ -29,11 +29,9 @@ vpp_uses_dpdk = yes # Uncoment to enable building unit tests # vpp_enable_tests = yes -vpp_root_packages = vpp vlib vlib-api vnet svm vpp-api-test \ - vpp-api gmod plugins +vpp_root_packages = vpp vpp-api gmod plugins vpp_configure_args_vpp = --with-dpdk -vnet_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 diff --git a/build-data/platforms/vpp_lite.mk b/build-data/platforms/vpp_lite.mk index ef2ec444..55805d10 100644 --- a/build-data/platforms/vpp_lite.mk +++ b/build-data/platforms/vpp_lite.mk @@ -27,8 +27,7 @@ vpp_lite_uses_dpdk = no # Uncoment to enable building unit tests #vpp_lite_enable_tests = yes -vpp_lite_root_packages = vpp vlib vlib-api vnet svm vpp-api-test \ - vpp-api gmod +vpp_lite_root_packages = vpp vpp-api gmod vlib_configure_args_vpp_lite = --with-pre-data=128 diff --git a/build-data/suffix-rules.mk b/build-data/suffix-rules.mk deleted file mode 100644 index e3eeb922..00000000 --- a/build-data/suffix-rules.mk +++ /dev/null @@ -1,27 +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. - -# Shared suffix rules -# Please do not set "SUFFIXES = .api.h .api" here - -%.api.h: %.api - @echo " APIGEN " $@ ; \ - 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 $@ diff --git a/build-root/bootstrap.sh b/build-root/bootstrap.sh index f83734fd..2949c180 100755 --- a/build-root/bootstrap.sh +++ b/build-root/bootstrap.sh @@ -45,7 +45,7 @@ cd $wsroot cd $build_root echo Compile native tools -for tool in vppapigen +for tool in tools do make V=0 is_build_tool=yes $tool-install done diff --git a/build-root/packages/src.mk b/build-root/packages/src.mk new file mode 100644 index 00000000..db48ed58 --- /dev/null +++ b/build-root/packages/src.mk @@ -0,0 +1,4 @@ +# nothing + + + diff --git a/build-root/packages/tools.mk b/build-root/packages/tools.mk new file mode 100644 index 00000000..506e024b --- /dev/null +++ b/build-root/packages/tools.mk @@ -0,0 +1,3 @@ +tools_source = src +tools_configure_args = --disable-vlib + diff --git a/build-root/packages/vppapigen.mk b/build-root/packages/vppapigen.mk deleted file mode 100644 index 0d284631..00000000 --- a/build-root/packages/vppapigen.mk +++ /dev/null @@ -1,5 +0,0 @@ -vppapigen_configure_depend = vppinfra-install - -vppapigen_CPPFLAGS = $(call installed_includes_fn, vppinfra) - -vppapigen_LDFLAGS = $(call installed_libs_fn, vppinfra) diff --git a/build-root/rpm/vpp.spec b/build-root/rpm/vpp.spec index 194d205f..654424c0 100644 --- a/build-root/rpm/vpp.spec +++ b/build-root/rpm/vpp.spec @@ -97,12 +97,10 @@ groupadd -f -r vpp mkdir -p -m755 %{buildroot}%{_bindir} mkdir -p -m755 %{buildroot}%{_unitdir} install -p -m 755 %{_mu_build_dir}/%{_vpp_install_dir}/*/bin/* %{buildroot}%{_bindir} -install -p -m 755 %{_mu_build_dir}/%{_vpp_build_dir}/vppapigen/vppapigen %{buildroot}%{_bindir} +install -p -m 755 %{_mu_build_dir}/%{_vpp_build_dir}/tools/vppapigen %{buildroot}%{_bindir} -# core api +# api mkdir -p -m755 %{buildroot}/usr/share/vpp/api -install -p -m 644 %{_mu_build_dir}/%{_vpp_install_dir}/vpp/vpp-api/vpe.api.json %{buildroot}/usr/share/vpp/api -install -p -m 644 %{_mu_build_dir}/%{_vpp_install_dir}/vlib-api/vlibmemory/memclnt.api.json %{buildroot}/usr/share/vpp/api # # configs @@ -110,8 +108,8 @@ install -p -m 644 %{_mu_build_dir}/%{_vpp_install_dir}/vlib-api/vlibmemory/memcl mkdir -p -m755 %{buildroot}/etc/vpp mkdir -p -m755 %{buildroot}/etc/sysctl.d install -p -m 644 %{_mu_build_dir}/rpm/vpp.service %{buildroot}%{_unitdir} -install -p -m 644 %{_mu_build_dir}/../vpp/conf/startup.uiopcigeneric.conf %{buildroot}/etc/vpp/startup.conf -install -p -m 644 %{_mu_build_dir}/../vpp/conf/80-vpp.conf %{buildroot}/etc/sysctl.d +install -p -m 644 %{_mu_build_dir}/../src/vpp/conf/startup.uiopcigeneric.conf %{buildroot}/etc/vpp/startup.conf +install -p -m 644 %{_mu_build_dir}/../src/vpp/conf/80-vpp.conf %{buildroot}/etc/sysctl.d # # libraries # @@ -128,7 +126,7 @@ do ( cd %{buildroot}%{_libdir} && ln -fs $file $(echo $file | sed -e 's/\(\.so\)\.[0-9]\+.*/\1/') ) done -for file in $(find %{_mu_build_dir}/%{_vpp_install_dir}/vnet -type f -name '*.api.json' -print ) +for file in $(find %{_mu_build_dir}/%{_vpp_install_dir}/vpp/share/vpp/api -type f -name '*.api.json' -print ) do install -p -m 644 $file %{buildroot}/usr/share/vpp/api done @@ -178,12 +176,24 @@ do %{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 \ + %{buildroot}/usr/lib/vpp_api_test_plugins/$file +done + for file in $(find %{_mu_build_dir}/%{_vpp_install_dir}/plugins -type f -name '*.api.json' -print ) do install -p -m 644 $file %{buildroot}/usr/share/vpp/api diff --git a/build-root/scripts/find-plugins-contents b/build-root/scripts/find-plugins-contents index a5a52acf..4108f790 100755 --- a/build-root/scripts/find-plugins-contents +++ b/build-root/scripts/find-plugins-contents @@ -2,14 +2,14 @@ rm -f $2 -for i in ${1}/plugins/lib64/vpp_plugins/*.so; do +for i in ${1}/{plugins,vpp}/lib64/vpp_plugins/*.so; do echo ../${i} /usr/lib/vpp_plugins >> ${2} done -for i in ${1}/plugins/lib64/vpp_api_test_plugins/*.so; do +for i in ${1}/{plugins,vpp}/lib64/vpp_api_test_plugins/*.so; do echo ../${i} /usr/lib/vpp_api_test_plugins >> ${2} done -for i in $(find ${1}/plugins -name *.api.json -type f -print); do +for i in $(find ${1}/plugins ${1}/vpp/share/vpp/api/plugins/ -name *.api.json -type f -print); do echo ../${i} /usr/share/vpp/api/ >> ${2} done diff --git a/build-root/scripts/find-python-api-contents b/build-root/scripts/find-python-api-contents index 9b390e75..24e8532c 100755 --- a/build-root/scripts/find-python-api-contents +++ b/build-root/scripts/find-python-api-contents @@ -2,7 +2,7 @@ rm -f $2 -for i in $(find ${1}/vpp-api/lib/python2.7/site-packages/ -type f -print); do +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/g2/Makefile.am b/g2/Makefile.am deleted file mode 100644 index 8457c272..00000000 --- a/g2/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 - -bin_PROGRAMS = g2 - -AM_CFLAGS = -Wall - -g2_SOURCES = \ - clib.c \ - cpel.c \ - cpel.h \ - events.c \ - g2.h \ - main.c \ - menu1.c \ - pointsel.c \ - props.c \ - props.h \ - g2version.c \ - view1.c - -g2_LDADD = $(g2_LIBS) -lvppinfra -lpthread -lm diff --git a/g2/clib.c b/g2/clib.c deleted file mode 100644 index d0cd6195..00000000 --- a/g2/clib.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2009-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 -#include -#include "cpel.h" -#include "g2.h" - -int widest_track_format; - -typedef struct bound_track_ { - u32 track; - u8 *track_str; -} bound_track_t; - -bound_track_t *bound_tracks; - -uword *the_evtdef_hash; /* (event-id, event-definition) hash */ -uword *the_trackdef_hash; /* (track-id, track-definition) hash */ - -elog_main_t elog_main; - -void *get_clib_event (unsigned int datum) -{ - elog_event_t *ep = vec_elt_at_index (elog_main.events, datum); - return (void *)ep; -} - -/* - * read_clib_file - */ -int read_clib_file(char *clib_file) -{ - static FILE *ofp; - clib_error_t *error = 0; - int i; - elog_main_t *em = &elog_main; - double starttime, delta; - - vec_free(em->events); - vec_free(em->event_types); - if (the_trackdef_hash) - hash_free(the_trackdef_hash); - - the_trackdef_hash = hash_create (0, sizeof (uword)); - - error = elog_read_file (&elog_main, clib_file); - - if (error) { - fformat(stderr, "%U", format_clib_error, error); - return (1); - } - - if (ofp == NULL) { - ofp = fdopen(2, "w"); - if (ofp == NULL) { - fprintf(stderr, "Couldn't fdopen(2)?\n"); - exit(1); - } - } - - em = &elog_main; - - for (i = 0; i < vec_len (em->tracks); i++) { - u32 track_code; - bound_track_t * btp; - elog_track_t * t; - uword * p; - int track_strlen; - - t = &em->tracks[i]; - track_code = i; - p = hash_get(the_trackdef_hash, track_code); - if (p) { - fprintf(ofp, "track %d redefined, retain first definition\n", - track_code); - continue; - } - vec_add2(bound_tracks, btp, 1); - btp->track = track_code; - btp->track_str = t->name; - hash_set(the_trackdef_hash, track_code, btp - bound_tracks); - - track_strlen = strlen((char *)btp->track_str); - if (track_strlen > widest_track_format) - widest_track_format = track_strlen; - } - - initialize_events(); - - for (i = 0; i < vec_len (em->event_types); i++) { - elog_event_type_t *ep; - u8 *tmp; - - ep = vec_elt_at_index(em->event_types, i); - tmp = (u8 *) vec_dup(ep->format); - vec_add1(tmp,0); - add_event_from_clib_file (ep->type_index_plus_one, (char *) tmp, i); - vec_free(tmp); - } - - finalize_events(); - - em->events = elog_get_events (em); - - cpel_event_init(vec_len(em->events)); - - starttime = em->events[0].time; - - for (i = 0; i < vec_len (em->events); i++) { - elog_event_t *ep; - - ep = vec_elt_at_index(em->events, i); - - delta = ep->time - starttime; - - add_clib_event (delta, ep->track, ep->type + 1, i); - } - - cpel_event_finalize(); - - set_pid_ax_width(8*widest_track_format); - - return(0); -} diff --git a/g2/configure.ac b/g2/configure.ac deleted file mode 100644 index c8af7747..00000000 --- a/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/g2/cpel.c b/g2/cpel.c deleted file mode 100644 index 8bcc91e6..00000000 --- a/g2/cpel.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2005-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 -#include "cpel.h" -#include "g2.h" - -typedef struct bound_event_ { - u32 event_code; - u8 *event_str; - u8 *datum_str; -} bound_event_t; - -bound_event_t *bound_events; - -int widest_track_format=8; - -typedef struct bound_track_ { - u32 track; - u8 *track_str; -} bound_track_t; - -bound_track_t *bound_tracks; - -uword *the_strtab_hash; /* (name, base-VA) hash of all string tables */ -uword *the_evtdef_hash; /* (event-id, event-definition) hash */ -uword *the_trackdef_hash; /* (track-id, track-definition) hash */ -u8 *event_strtab; /* event string-table */ - -void fatal(char *s) -{ - fprintf(stderr, "%s", s); - exit(1); -} - -typedef enum { - PASS1=1, - PASS2=2, -} pass_t; - -typedef struct { - int (*pass1)(cpel_section_header_t *, int, FILE *); - int (*pass2)(cpel_section_header_t *, int, FILE *); -} section_processor_t; - -int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - fprintf(ofp, "Bad (type 0) section, skipped...\n"); - return(0); -} - -int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - return(0); -} - -int strtab_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - uword *p; - u8 *strtab_data_area = (u8 *)(sh+1); - - /* Multiple string tables with the same name are Bad... */ - p = hash_get_mem(the_strtab_hash, strtab_data_area); - if (p) { - fprintf(ofp, "Duplicate string table name %s", strtab_data_area); - } - /* - * Looks funny, but we really do want key = first string in the - * table, value = address(first string in the table) - */ - hash_set_mem(the_strtab_hash, strtab_data_area, strtab_data_area); - if (verbose) { - fprintf(ofp, "String Table %s\n", strtab_data_area); - } - return(0); -} - -int evtdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - int i, nevents; - event_definition_section_header_t *edh; - event_definition_t *ep; - u8 *this_strtab; - u32 event_code; - uword *p; - bound_event_t *bp; - - edh = (event_definition_section_header_t *)(sh+1); - nevents = ntohl(edh->number_of_event_definitions); - - if (verbose) { - fprintf(ofp, "Event Definition Section: %d definitions\n", - nevents); - } - - p = hash_get_mem(the_strtab_hash, edh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - this_strtab = (u8 *)p[0]; - - initialize_events(); - - ep = (event_definition_t *)(edh+1); - - for (i = 0; i < nevents; i++) { - event_code = ntohl(ep->event); - p = hash_get(the_evtdef_hash, event_code); - if (p) { - fprintf(ofp, "Event %d redefined, retain first definition\n", - event_code); - continue; - } - vec_add2(bound_events, bp, 1); - bp->event_code = event_code; - bp->event_str = this_strtab + ntohl(ep->event_format); - bp->datum_str = this_strtab + ntohl(ep->datum_format); - hash_set(the_evtdef_hash, event_code, bp - bound_events); - - add_event_from_cpel_file(event_code, (char *) bp->event_str, - (char *)bp->datum_str); - - ep++; - } - - finalize_events(); - return (0); -} - -int trackdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - int i, nevents; - track_definition_section_header_t *tdh; - track_definition_t *tp; - u8 *this_strtab; - u32 track_code; - uword *p; - bound_track_t *btp; - int track_strlen; - - tdh = (track_definition_section_header_t *)(sh+1); - nevents = ntohl(tdh->number_of_track_definitions); - - if (verbose) { - fprintf(ofp, "Track Definition Section: %d definitions\n", - nevents); - } - - p = hash_get_mem(the_strtab_hash, tdh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - this_strtab = (u8 *)p[0]; - - tp = (track_definition_t *)(tdh+1); - - for (i = 0; i < nevents; i++) { - track_code = ntohl(tp->track); - p = hash_get(the_trackdef_hash, track_code); - if (p) { - fprintf(ofp, "track %d redefined, retain first definition\n", - track_code); - continue; - } - vec_add2(bound_tracks, btp, 1); - btp->track = track_code; - btp->track_str = this_strtab + ntohl(tp->track_format); - hash_set(the_trackdef_hash, track_code, btp - bound_tracks); - - track_strlen = strlen((char *)btp->track_str); - if (track_strlen > widest_track_format) - widest_track_format = track_strlen; - tp++; - } - return (0); -} - -int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - if (verbose) { - fprintf(ofp, "Unsupported type %d section\n", - ntohl(sh->section_type)); - } - return(0); -} - -int event_pass2(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - event_section_header_t *eh; - u32 event_code, track_code, datum; - u64 starttime = ~0ULL; - int nevents; - int i; - event_entry_t *ep; - u64 now; - u64 delta; - u32 time0, time1; - double d; - uword *p; - - eh = (event_section_header_t *)(sh+1); - nevents = ntohl(eh->number_of_events); - ticks_per_ns = ntohl(eh->clock_ticks_per_second)/1e9; - ep = (event_entry_t *)(eh+1); - - p = hash_get_mem(the_strtab_hash, eh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - event_strtab = (u8 *)p[0]; - - cpel_event_init(nevents); - - for (i = 0; i < nevents; i++) { - time0 = ntohl (ep->time[0]); - time1 = ntohl (ep->time[1]); - - now = (((u64) time0)<<32) | time1; - - /* Convert from bus ticks to usec */ - d = now; - d /= ticks_per_ns; - - now = d; - - if (starttime == ~0ULL) - starttime = now; - - delta = now - starttime; - - /* Delta = time since first event, in usec */ - event_code = ntohl(ep->event_code); - track_code = ntohl(ep->track); - datum = ntohl(ep->event_datum); - - add_cpel_event(delta, track_code, event_code, datum); - - ep++; - } - cpel_event_finalize(); - return(0); -} - -char *strtab_ref(unsigned long datum) -{ - return ((char *)(event_strtab + datum)); -} - -/* - * Note: If necessary, add passes / columns to this table to - * handle section order dependencies. - */ - -section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] = -{ - {bad_section, noop_pass}, /* type 0 -- f**ked */ - {strtab_pass1, noop_pass}, /* type 1 -- STRTAB */ - {unsupported_pass, noop_pass}, /* type 2 -- SYMTAB */ - {evtdef_pass1, noop_pass}, /* type 3 -- EVTDEF */ - {trackdef_pass1, noop_pass}, /* type 4 -- TRACKDEF */ - {noop_pass, event_pass2}, /* type 5 -- EVENTS */ -}; - - -int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp, - pass_t pass) -{ - u32 type; - type = ntohl(sh->section_type); - int rv; - int (*fp)(cpel_section_header_t *, int, FILE *); - - if (type > CPEL_NUM_SECTION_TYPES) { - fprintf(stderr, "Unknown section type %d\n", type); - return(1); - } - switch(pass) { - case PASS1: - fp = processors[type].pass1; - break; - - case PASS2: - fp = processors[type].pass2; - break; - - default: - fprintf(stderr, "Unknown pass %d\n", pass); - return(1); - } - - rv = (*fp)(sh, verbose, ofp); - - return(rv); -} - -int cpel_dump_file_header(cpel_file_header_t *fh, int verbose, FILE *ofp) -{ - time_t file_time; - - if (verbose) { - fprintf(ofp, "CPEL file: %s-endian, version %d\n", - ((fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) ? - "little" : "big"), - fh->endian_version & CPEL_FILE_VERSION_MASK); - - file_time = ntohl(fh->file_date); - - fprintf(ofp, "File created %s", ctime(&file_time)); - } - - return(0); -} - - -int cpel_process(u8 *cpel, int verbose, FILE *ofp) -{ - cpel_file_header_t *fh; - cpel_section_header_t *sh; - u16 nsections; - u32 section_size; - int i; - - /* First, the file header */ - fh = (cpel_file_header_t *)cpel; - if (fh->endian_version != CPEL_FILE_VERSION) { - if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) { - fprintf(stderr, "Little endian data format not supported\n"); - return(1); - } - fprintf(stderr, "Unsupported file version 0x%x\n", - fh->endian_version); - return(1); - } - cpel_dump_file_header(fh, verbose, ofp); - nsections = ntohs(fh->nsections); - - /* - * Take two passes through the file. PASS1 builds - * data structures, PASS2 actually dumps the file. - * Just in case the sections are in an unobvious order. - */ - sh = (cpel_section_header_t *)(fh+1); - for (i = 0; i < nsections; i++) { - section_size = ntohl(sh->data_length); - - if(verbose) { - fprintf(ofp, "Section type %d, size %d\n", ntohl(sh->section_type), - section_size); - } - - if(process_section(sh, verbose, ofp, PASS1)) - return(1); - - sh++; - sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); - } - - sh = (cpel_section_header_t *)(fh+1); - for (i = 0; i < nsections; i++) { - if(process_section(sh, verbose, ofp, PASS2)) - return(1); - section_size = ntohl(sh->data_length); - sh++; - sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); - } - - - return(0); -} - -/* - * read_cpel_file - */ -int read_cpel_file(char *cpel_file) -{ - int verbose = 0; - int rv; - static u8 *cpel; - static unsigned long size; - static FILE *ofp; - - if (cpel) { - unmapfile((char *)cpel, size); - hash_free(the_strtab_hash); - the_strtab_hash = 0; - hash_free(the_evtdef_hash); - the_evtdef_hash = 0; - hash_free(the_trackdef_hash); - the_trackdef_hash = 0; - } - - cpel = (u8 *)mapfile((char *)cpel_file, &size); - if (cpel == 0) { - fprintf(stderr, "Couldn't map %s...\n", cpel_file); - exit(1); - } - - if (ofp == NULL) { - ofp = fdopen(2, "w"); - if (ofp == NULL) { - fprintf(stderr, "Couldn't fdopen(2)?\n"); - exit(1); - } - } - - the_strtab_hash = hash_create_string (0, sizeof (uword)); - the_evtdef_hash = hash_create (0, sizeof (uword)); - the_trackdef_hash = hash_create (0, sizeof (uword)); - - rv = cpel_process(cpel, verbose, ofp); - - set_pid_ax_width(8*widest_track_format); - - return(rv); -} - -static bound_track_t generic_hex_track = {0, (u8 *) "0x%08x"}; -static bound_track_t generic_decimal_track = {0, (u8 *) "%8ld"}; - -/* - * get_track_label - */ -char *get_track_label(unsigned long track) -{ - uword *p; - bound_track_t *tp; - - p = hash_get(the_trackdef_hash, track); - if (p) { - tp = &bound_tracks[p[0]]; - } else { - if (track > 65535) - tp = &generic_hex_track; - else - tp = &generic_decimal_track; - } - return((char *)tp->track_str); -} diff --git a/g2/cpel.h b/g2/cpel.h deleted file mode 100644 index 73e4aea5..00000000 --- a/g2/cpel.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2005-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 _CPEL_H_ -#define _CPEL_H_ 1 - -typedef struct cpel_file_header_ { - unsigned char endian_version; - unsigned char pad; - unsigned short nsections; - unsigned file_date; -} cpel_file_header_t; - -#define CPEL_FILE_LITTLE_ENDIAN 0x80 -#define CPEL_FILE_VERSION 0x01 -#define CPEL_FILE_VERSION_MASK 0x7F - -typedef struct cpel_section_header_ { - unsigned int section_type; - unsigned int data_length; /* does NOT include type and itself */ -} cpel_section_header_t; - -#define CPEL_SECTION_STRTAB 1 -/* string at offset 0 is the name of the table */ - -#define CPEL_SECTION_SYMTAB 2 -#define CPEL_SECTION_EVTDEF 3 - -typedef struct event_definition_section_header_ { - char string_table_name[64]; - unsigned int number_of_event_definitions; -} event_definition_section_header_t; - -typedef struct event_definition_ { - unsigned int event; - unsigned int event_format; - unsigned int datum_format; -} event_definition_t; - -#define CPEL_SECTION_TRACKDEF 4 - -typedef struct track_definition_section_header_ { - char string_table_name[64]; - unsigned int number_of_track_definitions; -} track_definition_section_header_t; - -typedef struct track_definition_ { - unsigned int track; - unsigned int track_format; -} track_definition_t; - -#define CPEL_SECTION_EVENT 5 - -typedef struct event_section_header_ { - char string_table_name[64]; - unsigned int number_of_events; - unsigned int clock_ticks_per_second; -} event_section_header_t; - -typedef struct event_entry_ { - unsigned int time[2]; - unsigned int track; - unsigned int event_code; - unsigned int event_datum; -} event_entry_t; - -#define CPEL_NUM_SECTION_TYPES 5 - -#endif /* _CPEL_H_ */ - diff --git a/g2/events.c b/g2/events.c deleted file mode 100644 index d4333bb0..00000000 --- a/g2/events.c +++ /dev/null @@ -1,475 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2005-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 "g2.h" -#include -#include -#include -#include - -/* - * globals - */ -boolean g_little_endian; -event_t *g_events; -ulong g_nevents; -pid_sort_t *g_pids; -pid_sort_t *g_original_pids; -int g_npids; -pid_data_t *g_pid_data_list; - -/* - * locals - */ -pid_data_t **s_pidhash; - -/* - * config parameters - */ - -double ticks_per_ns=1000.0; -boolean ticks_per_ns_set; - -/**************************************************************************** -* event_init -****************************************************************************/ - -void event_init(void) -{ - ulong endian; - char *ep; - char *askstr; - int tmp; - - ep = (char *)&endian; - endian = 0x12345678; - if (*ep != 0x12) - g_little_endian = TRUE; - else - g_little_endian = FALSE; - - askstr = getprop("dont_ask_ticks_per_ns_initially"); - - if (askstr && (*askstr == 't' || *askstr == 'T')) { - tmp = atol(getprop_default("ticks_per_ns", 0)); - if (tmp > 0) { - ticks_per_ns = tmp; - ticks_per_ns_set = TRUE; - } - } -} - -/**************************************************************************** -* find_or_add_pid -****************************************************************************/ - -pid_data_t *find_or_add_pid (ulong pid) -{ - pid_data_t *pp; - ulong bucket; - - bucket = pid % PIDHASH_NBUCKETS; - - pp = s_pidhash[bucket]; - - if (pp == 0) { - pp = g_malloc0(sizeof(pid_data_t)); - pp->pid_value = pid; - s_pidhash[bucket] = pp; - g_npids++; - return(pp); - } - while (pp) { - if (pp->pid_value == pid) - return(pp); - pp = pp->next; - } - - pp = g_malloc0(sizeof(pid_data_t)); - pp->pid_value = pid; - pp->next = s_pidhash[bucket]; - s_pidhash[bucket] = pp; - g_npids++; - return(pp); -} - -/**************************************************************************** -* pid_cmp -****************************************************************************/ - -int pid_cmp(const void *a1, const void *a2) -{ - pid_sort_t *p1 = (pid_sort_t *)a1; - pid_sort_t *p2 = (pid_sort_t *)a2; - - if (p1->pid_value < p2->pid_value) - return(-1); - else if (p1->pid_value == p2->pid_value) - return(0); - else - return(1); -} - -/**************************************************************************** -* make_sorted_pid_vector -****************************************************************************/ - -static void make_sorted_pid_vector(void) -{ - pid_data_t *pp; - pid_data_t **p_previous; - pid_sort_t *psp; - int i; - - psp = g_pids = g_malloc(sizeof(pid_sort_t)*g_npids); - - for (i = 0; i < PIDHASH_NBUCKETS; i++) { - pp = s_pidhash[i]; - while(pp) { - psp->pid = pp; - psp->pid_value = pp->pid_value; - psp++; - pp = pp->next; - } - } - - qsort(&g_pids[0], g_npids, sizeof(pid_sort_t), pid_cmp); - - /* put the sort order into the pid objects */ - psp = g_pids; - - /* - * This is rather gross. - * - * We happen to know that whenever this function is called, the hash table - * structure itself is immediately torn down. So the "next" pointers in the - * pid_data_t elements are about to become useless. - * - * So we re-use them, to link all the pid_data_t elements together into a - * single unified linked list, with g_pid_data_list pointing to the head. - * This means we can walk all the pid_data_t objects if we really want to. - * Reading snapshots from disk is one example. - * - * Alternatively we could just leave the hash table in place; this is - * far nicer, but as it happens, trading O(n) lookups for O(1) lookups - * isn't actually a problem for the restricted post-tear-down usage. So for - * now we take the memory savings and swap our hash table for a list. - */ - p_previous = &g_pid_data_list; - for (i = 0; i < g_npids; i++) { - pp = psp->pid; - pp->pid_index = i; - *p_previous = pp; - p_previous = &pp->next; - psp++; - } - *p_previous = NULL; - - /* - * Squirrel away original (sorted) vector, so we can - * toggle between "chase" mode, snapshots, and the original - * display method on short notice - */ - g_original_pids = g_malloc(sizeof(pid_sort_t)*g_npids); - memcpy (g_original_pids, g_pids, sizeof(pid_sort_t)*g_npids); -} - -/**************************************************************************** -* read_events -****************************************************************************/ - -void read_events(char *filename) -{ - ulong *ulp; - ulong size; - event_t *ep; - raw_event_t *rep; - ulonglong start_time=0ULL; - ulonglong low_time; - boolean once=TRUE; - int i; - char tmpbuf [128]; - - ulp = (ulong *)mapfile(filename, &size); - - if (ulp == NULL) { - sprintf(tmpbuf, "Couldn't open %s\n", filename); - infobox("Read Event Log Failure", tmpbuf); - return; - } - - g_nevents = ntohl(*ulp); - - if (size != (g_nevents*sizeof(raw_event_t) + sizeof(g_nevents))) { - sprintf(tmpbuf, "%s was damaged, or isn't an event log.\n", filename); - infobox("Bad Input File", tmpbuf); - g_nevents = 0; - unmapfile((char *)ulp, size); - return; - } - - rep = (raw_event_t *)(ulp+1); - - if (g_events) - g_free(g_events); - - g_events = (event_t *)g_malloc(g_nevents * sizeof(event_t)); - ep = g_events; - - while (g_npids > 0) { - g_free((g_pids + g_npids-1)->pid); - g_npids--; - } - if (g_pids) { - g_free(g_pids); - g_free(g_original_pids); - g_pids = 0; - g_original_pids = 0; - } - - s_pidhash = (pid_data_t **)g_malloc0( - PIDHASH_NBUCKETS*sizeof(pid_data_t *)); - - /* $$$ add a SEGV handler... */ - for (i = 0; i < g_nevents; i++) { - if (once) { - once = FALSE; - start_time = ((ulonglong)ntohl(rep->time[0])); - start_time <<= 32; - low_time = ntohl(rep->time[1]); - low_time &= 0xFFFFFFFF; - start_time |= low_time; - ep->time = 0LL; - } else { - ep->time = ((ulonglong)ntohl(rep->time[0])); - ep->time <<= 32; - low_time = ntohl(rep->time[1]); - low_time &= 0xFFFFFFFF; - ep->time |= low_time; - ep->time -= start_time; - ep->time /= ticks_per_ns; - } - ep->code = ntohl(rep->code); - ep->pid = find_or_add_pid(ntohl(rep->pid)); - ep->datum = ntohl(rep->datum); - ep->flags = 0; - ep++; - rep++; - } - - unmapfile((char *)ulp, size); - - make_sorted_pid_vector(); - g_free(s_pidhash); - s_pidhash = 0; - - /* Give the view-1 world a chance to reset a few things... */ - view1_read_events_callback(); -} - -static event_t *add_ep; - -/**************************************************************************** -* cpel_event_init -****************************************************************************/ -void cpel_event_init (ulong nevents) -{ - g_nevents = nevents; - if (g_events) - g_free(g_events); - add_ep = g_events = (event_t *)g_malloc(g_nevents * sizeof(event_t)); - while (g_npids > 0) { - g_free((g_pids + g_npids-1)->pid); - g_npids--; - } - if (g_pids) { - g_free(g_pids); - g_free(g_original_pids); - g_pids = 0; - g_original_pids = 0; - } - s_pidhash = (pid_data_t **)g_malloc0( - PIDHASH_NBUCKETS*sizeof(pid_data_t *)); -} - -/**************************************************************************** -* add_cpel_event -****************************************************************************/ - -void add_cpel_event(ulonglong delta, ulong track, ulong event, ulong datum) -{ - event_t *ep; - - ep = add_ep++; - ep->time = delta; - ep->pid = find_or_add_pid(track); - ep->code = event; - ep->datum = datum; - ep->flags = 0; -} - -/**************************************************************************** -* add_clib_event -****************************************************************************/ - -void add_clib_event(double delta, unsigned short track, - unsigned short event, unsigned int index) -{ - event_t *ep; - - ep = add_ep++; - ep->time = (ulonglong) (delta * 1e9); /* time in intger nanoseconds */ - ep->pid = find_or_add_pid(track); - ep->code = event; - ep->datum = index; - ep->flags = EVENT_FLAG_CLIB; -} - -/**************************************************************************** -* cpel_event_finalize -****************************************************************************/ - -void cpel_event_finalize(void) -{ - make_sorted_pid_vector(); - g_free(s_pidhash); - s_pidhash = 0; - - /* Give the view-1 world a chance to reset a few things... */ - view1_read_events_callback(); -} - -/**************************************************************************** -* mapfile -****************************************************************************/ - -char *mapfile (char *file, ulong *sizep) -{ - struct stat statb; - char *rv; - int maphfile; - size_t mapfsize; - - maphfile = open (file, O_RDONLY); - - if (maphfile < 0) - return (NULL); - - if (fstat (maphfile, &statb) < 0) { - return (NULL); - } - - /* Don't try to mmap directories, FIFOs, semaphores, etc. */ - if (! (statb.st_mode & S_IFREG)) { - return (NULL); - } - - mapfsize = statb.st_size; - - if (mapfsize < 3) { - close (maphfile); - return (NULL); - } - - rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0); - - if (rv == 0) { - g_error ("%s mapping problem, I quit...\n", file); - } - - close (maphfile); - - if (madvise (rv, mapfsize, MADV_SEQUENTIAL) < 0) { - return (rv); - } - - if (sizep) { - *sizep = mapfsize; - } - return (rv); -} - -/**************************************************************************** -* unmapfile -****************************************************************************/ - -boolean unmapfile (char *addr, ulong size) -{ - if (munmap (addr, size) < 0) { - g_warning("Unmap error, addr 0x%lx size 0x%x\n", - (unsigned long) addr, (unsigned int)size); - return(FALSE); - } - return(TRUE); -} - -/**************************************************************************** -* find_event_index -* Binary search for first event whose time is >= t -****************************************************************************/ - -int find_event_index (ulonglong t) -{ - int index, bottom, top; - event_t *ep; - - bottom = g_nevents-1; - top = 0; - - while (1) { - index = (bottom + top) / 2; - - ep = (g_events + index); - - if (ep->time == t) - return(index); - - if (top >= bottom) { - while (index > 0 && ep->time > t) { - ep--; - index--; - } - while (index < g_nevents && ep->time < t) { - ep++; - index++; - } - return(index); - } - - if (ep->time < t) - top = index + 1; - else - bottom = index - 1; - } -} - -/**************************************************************************** -* events_about -****************************************************************************/ - -void events_about (char *tmpbuf) -{ - sprintf(tmpbuf+strlen(tmpbuf), "%d total events, %.3f ticks per us\n", - (int)g_nevents, ticks_per_ns); -} diff --git a/g2/g2.h b/g2/g2.h deleted file mode 100644 index 1ab42191..00000000 --- a/g2/g2.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2005-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * typedefs and so forth - */ -#include -#include -#include -#include "props.h" - -typedef char boolean; -typedef unsigned long long ulonglong; - -/* - * main.c - */ - -GtkWidget *g_mainwindow; -GtkWidget *g_mainvbox; -GtkWidget *g_mainhbox; - -/* - * pointsel.c - */ -void point_selector_init(void); -boolean read_event_definitions (char *filename); -char *sxerox(char *); -void pointsel_about(char *); -void pointsel_next_snapshot(void); -void initialize_events(void); -void finalize_events(void); - -#define NEVENTS 100000 - -typedef struct event_def_ { - ulong event; - char *name; - char *format; - boolean selected; - boolean is_clib; - char pad[2]; -} event_def_t; - -event_def_t *find_event_definition (ulong code); - -event_def_t g_eventdefs[NEVENTS]; - -/* - * config params - */ -int c_maxpointsel; /* max # points shown in selector dlg */ -gint c_view1_draw_width; -gint c_view1_draw_height; - -/* - * menu1.c - */ - -void menu1_init(void); -void modal_dialog (char *label_text, char *retry_text, char *default_value, - boolean (*cb)(char *)); -void infobox(char *label_text, char *text); -/* - * view1.c - */ -GdkFont *g_font; -GdkColor fg_black, bg_white; -void view1_init(void); -void view1_display(void); -void view1_read_events_callback(void); -void view1_display_when_idle(void); -void view1_print_callback(GtkToggleButton *item, gpointer data); -void view1_about(char *); -void set_pid_ax_width(int width); -void set_window_title(const char *filename); - -enum view1_tbox_fn { - TBOX_DRAW_BOXED = 1, /* note: order counts */ - TBOX_DRAW_EVENT, - TBOX_DRAW_PLAIN, - TBOX_PRINT_BOXED, - TBOX_PRINT_EVENT, - TBOX_PRINT_PLAIN, /* end restriction */ - TBOX_GETRECT_BOXED, - TBOX_GETRECT_EVENT, - TBOX_GETRECT_PLAIN, -}; - -enum view1_line_fn { - LINE_DRAW_BLACK = 1, - LINE_DRAW_WHITE, - LINE_PRINT, -}; - -GdkRectangle *tbox (char *s, int x, int y, enum view1_tbox_fn function); -void line (int x1, int y1, int x2, int y2, enum view1_line_fn function); -gint view1_handle_key_press_event (GtkWidget *widget, GdkEventKey *event); - -/* - * events.c - */ - -void events_about (char *); - -typedef struct raw_event { - unsigned long time[2]; - unsigned long pid; - unsigned long code; - unsigned long datum; -} raw_event_t; - -void event_init(void); -char *mapfile (char *file, ulong *sizep); -boolean unmapfile (char *addr, ulong size); -void read_events (char *); -int find_event_index (ulonglong t); -int read_cpel_file(char *file); -int read_clib_file(char *file); -void cpel_event_init(ulong); -void add_event_from_cpel_file(ulong, char * , char *); -void add_event_from_clib_file(unsigned int event, char *name, - unsigned int vec_index); -void add_cpel_event(ulonglong delta, ulong, ulong, ulong); -void add_clib_event(double delta, unsigned short track, - unsigned short event, unsigned int index); -void cpel_event_finalize(void); -void *get_clib_event (unsigned int datum); - -typedef struct pid_data { - struct pid_data *next; - ulong pid_value; /* The actual pid value */ - ulong pid_index; /* Index in pid sort order */ -} pid_data_t; - -#define EVENT_FLAG_SELECT 0x00000001 /* This event is selected */ -#define EVENT_FLAG_SEARCHRSLT 0x00000002 /* This event is the search rslt */ -#define EVENT_FLAG_CLIB 0x00000004 /* clib event */ - -typedef struct pid_sort { - struct pid_data *pid; - ulong pid_value; - /* - * This is a bit of a hack, since this is used only by the view: - */ - unsigned color_index; -} pid_sort_t; - -typedef struct event { - ulonglong time; - ulong code; - pid_data_t *pid; - ulong datum; - ulong flags; -} event_t; - - -boolean g_little_endian; -event_t *g_events; -ulong g_nevents; -pid_sort_t *g_pids; -pid_sort_t *g_original_pids; -int g_npids; -pid_data_t *g_pid_data_list; - -#define PIDHASH_NBUCKETS 20021 /* Should be prime */ - -boolean ticks_per_ns_set; -double ticks_per_ns; - -/* - * version.c - */ -const char *version_string; -const char *minor_v_string; - -/* - * cpel.c - */ -char *get_track_label(unsigned long); -int widest_track_format; -char *strtab_ref(unsigned long); diff --git a/g2/g2version.c b/g2/g2version.c deleted file mode 100644 index 4b6f9313..00000000 --- a/g2/g2version.c +++ /dev/null @@ -1,19 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2005-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -const char *version_string = "G2 (x86_64 GNU/Linux) major version 3.0"; -const char *minor_v_string = - "Built Wed Feb 3 10:58:12 EST 2016"; diff --git a/g2/main.c b/g2/main.c deleted file mode 100644 index a782e17f..00000000 --- a/g2/main.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2005-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 "g2.h" -#include "props.h" -#include -#include -#include -#include -#include - -/* - * globals - */ - -GtkWidget *g_mainwindow; /* The main window */ - -/* Graphical object heirarchy - * - * [main window] - * [main vbox] - * [main (e.g. file) menubar] - * [view hbox] - * [view bottom menu] - */ - -GtkWidget *g_mainvbox; -GtkWidget *g_mainhbox; - -gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) -{ - /* Allow window to be destroyed */ - return(FALSE); -} - -void destroy(GtkWidget *widget, gpointer data) -{ - gtk_main_quit(); -} - -int main (int argc, char **argv) -{ - char tmpbuf [128]; - struct passwd *pw; - char *event_file = 0; - char *cpel_file = 0; - char *clib_file =0; - char *title = "none"; - int curarg=1; - char *homedir; - - gtk_init(&argc, &argv); - - homedir = getenv ("HOME"); - tmpbuf[0] = 0; - - if (homedir) { - sprintf(tmpbuf, "%s/.g2", homedir); - } else { - pw = getpwuid(geteuid()); - if (pw) { - sprintf(tmpbuf, "%s/.g2", pw->pw_dir); - } - } - if (tmpbuf[0]) - readprops(tmpbuf); - - g_mainwindow = gtk_window_new (GTK_WINDOW_TOPLEVEL); - - gtk_signal_connect (GTK_OBJECT(g_mainwindow), "delete_event", - GTK_SIGNAL_FUNC (delete_event), NULL); - - gtk_signal_connect (GTK_OBJECT(g_mainwindow), "destroy", - GTK_SIGNAL_FUNC (destroy), NULL); - - gtk_container_set_border_width(GTK_CONTAINER(g_mainwindow), 5); - - g_mainvbox = gtk_vbox_new(FALSE, 0); - g_mainhbox = gtk_hbox_new(FALSE, 0); - - /* - * init routines - */ - - menu1_init(); - point_selector_init(); - view1_init(); - event_init(); - - /* - * Now that we're ready to rock 'n roll, see if we've been asked to - * press a few buttons... - */ - - while (curarg < argc) { - if (!strncmp(argv[curarg], "--cpel-input", 4)) { - curarg++; - if (curarg < argc) { - cpel_file = argv[curarg]; - curarg++; - break; - } - g_error("Missing filename after --cpel-input"); - } - if (!strncmp(argv[curarg], "--clib-input", 4)) { - curarg++; - if (curarg < argc) { - clib_file = argv[curarg]; - curarg++; - break; - } - g_error("Missing filename after --cpel-input"); - } - - if (!strncmp(argv[curarg], "--pointdefs", 3)) { - curarg++; - if (curarg < argc) { - read_event_definitions(argv[curarg]); - curarg++; - continue; - } - g_error ("Missing filename after --pointdefs\n"); - } - if (!strncmp(argv[curarg], "--event-log", 3)) { - curarg++; - if (curarg < argc) { - event_file = argv[curarg]; - curarg++; - continue; - } - g_error ("Missing filename after --event-log\n"); - } - - if (!strncmp(argv[curarg], "--ticks-per-us", 3)) { - curarg++; - if (curarg < argc) { - ticks_per_ns = 0.0; - ticks_per_ns = atof(argv[curarg]); - if (ticks_per_ns == 0.0) { - g_error("ticks-per-ns (%s) didn't convert properly\n", - argv[curarg]); - } - ticks_per_ns_set = TRUE; - curarg++; - continue; - } - g_error ("Missing filename after --event-log\n"); - } - - fprintf(stderr, - "g2 [--pointdefs ] [--event-log ]\n"); - fprintf(stderr, " [--ticks-per-us ]\n"); - fprintf(stderr, - " [--cpel-input ] [--clib-input \n"); - fprintf(stderr, - "%s\n%s\n", version_string, minor_v_string); - exit(0); - } - - if (clib_file) { - read_clib_file (clib_file); - title = clib_file; - } else if (cpel_file) { - read_cpel_file(cpel_file); - title = cpel_file; - } else if (event_file) { - read_events(event_file); - title = event_file; - } - - set_window_title(title); - - gtk_signal_connect (GTK_OBJECT (g_mainwindow), "key_press_event", - (GtkSignalFunc) view1_handle_key_press_event, NULL); - gtk_container_add(GTK_CONTAINER(g_mainvbox), g_mainhbox); - gtk_widget_show(g_mainhbox); - gtk_container_add(GTK_CONTAINER(g_mainwindow), g_mainvbox); - gtk_widget_show(g_mainvbox); - gtk_widget_show(g_mainwindow); - - gtk_main(); - return(0); -} diff --git a/g2/menu1.c b/g2/menu1.c deleted file mode 100644 index fce81fa6..00000000 --- a/g2/menu1.c +++ /dev/null @@ -1,565 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2006-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 GTK_ENABLE_BROKEN // DGMS -#include -#include -#include "g2.h" -#include - -/* - * locals - */ -static GtkWidget *s_mainmenubar; -static GtkWidget *s_filemenu; -static GtkWidget *s_readdefs; -static GtkWidget *s_readevents; -static GtkWidget *s_readeventsclock; -static GtkWidget *s_readcpel; -static GtkWidget *s_readclib; -static GtkWidget *s_print; -static GtkWidget *s_quit; - -static GtkWidget *s_mainfilemenu; -static GtkWidget *s_help_general; -static GtkWidget *s_help_about; -static GtkWidget *s_mainhelpmenu; -static GtkWidget *s_helpmenu; - -static GtkWidget *s_filesel; -static GtkWidget *s_eventsel; - -typedef struct md_ { - GtkWidget *entry; - GtkWidget *label; - GtkWidget *dialog; - boolean (*callback)(char *); - char *retry_text; -} md_t; - -char *general_help = "\n" -"G2 is a performance event visualization tool.\n" -"\n" -"To view CPEL-format event data:\n" -"g2 --cpel \n" -"or use the File Menu->Read CPEL file option.\n" -"\n" -"To view vppinfra-format (.../open-repo/vppinfra/vppinfra/elog.h) event data:\n" -"g2 --clib \n" -"or use the File Menu->Read clib file option.\n" -"\n" -"To toggle event detail boxes, left-mouse-click on an event.\n" -"\n" -"To zoom to an area, depress the left mouse button. Move the\n" -"mouse. Release the mouse.\n" -"\n" -"To use the time ruler, depress the right mouse button. Move the\n" -"mouse. Release when done.\n" -"\n" -"To push a track to the bottom, \n" -"\n" -"To pull a track to the top, \n" -"\n" -"To selectively color/uncolor a track, \n" -"\n" -"To make the mouse scrollwheel faster, press \n" -"\n" -"Hotkeys, supposedly Quake-like:\n" -" w - zoom-in\n" -" s - zoom-out\n" -" a - pan-left\n" -" d - pan-right\n" -" r - pan-up\n" -" f - pan-down\n" -" t - less traces\n" -" g - more traces\n" -"\n" -" e - toggle summary-mode\n" -" c - toggle color-mode\n" -"\n" -" x - take snapshot\n" -" z - go to next snapshot\n" -" p - put snapshots to snapshots.g2 \n" -" l - load snapshots from snapshots.g2\n" -"\n" -"q - quit\n" -"Send comments / bug reports to the \"fd.io\" mailing list.\n"; - -/**************************************************************************** -* debug_dialog_callback -****************************************************************************/ - -boolean debug_dialog_callback (char *s) -{ - g_print("Dialog result: %s", s); - return (TRUE); -} - -/**************************************************************************** -* get_dialog_value -****************************************************************************/ - -static void get_dialog_value (GtkWidget *dialog, gpointer user_data) -{ - md_t *md = (md_t *)user_data; - char * cb_arg; - - cb_arg = (char *) gtk_entry_get_text(GTK_ENTRY(md->entry)); - - if ((*md->callback)(cb_arg)) { - gtk_grab_remove(md->dialog); - gtk_widget_destroy(md->dialog); - } else { - gtk_label_set_text (GTK_LABEL(md->label), md->retry_text); - } -} - -/**************************************************************************** -* modal_dialog -****************************************************************************/ - -void modal_dialog (char *label_text, char *retry_text, char *default_value, - boolean (*cb)(char *)) -{ - GtkWidget *dialog, *label, *ok_button, *entry; - static md_t dlg; - md_t *md = &dlg; - - dialog = gtk_dialog_new(); - label = gtk_label_new(label_text); - - entry = gtk_entry_new(); - if (default_value) - gtk_entry_set_text(GTK_ENTRY(entry), default_value); - - ok_button = gtk_button_new_with_label("OK"); - - md->entry = entry; - md->label = label; - md->retry_text = retry_text; - md->dialog = dialog; - if (cb) - md->callback = cb; - else - md->callback = debug_dialog_callback; - - gtk_signal_connect (GTK_OBJECT (ok_button), "clicked", - GTK_SIGNAL_FUNC(get_dialog_value), (gpointer) md); - - gtk_signal_connect (GTK_OBJECT (entry), "activate", - GTK_SIGNAL_FUNC(get_dialog_value), (gpointer) md); - - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), - entry); - - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), - ok_button); - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); - gtk_widget_show_all(dialog); - gtk_widget_grab_focus(entry); - gtk_grab_add(dialog); -} - -/**************************************************************************** -* get_eventdef_name -****************************************************************************/ - -static void get_eventdef_name (GtkFileSelection *sel, gpointer user_data) -{ - char *filename = (char *) gtk_file_selection_get_filename ( - GTK_FILE_SELECTION(s_filesel)); - read_event_definitions(filename); - set_window_title(filename); -} - -/**************************************************************************** -* read_eventdef_callback -****************************************************************************/ - -static void read_eventdef_callback(GtkToggleButton *item, gpointer data) -{ - - s_filesel = gtk_file_selection_new("Read Event Definitions From..."); - - gtk_file_selection_set_filename(GTK_FILE_SELECTION(s_filesel), - "../h/elog.h"); - - gtk_signal_connect (GTK_OBJECT ( - GTK_FILE_SELECTION(s_filesel)->ok_button), - "clicked", - GTK_SIGNAL_FUNC(get_eventdef_name), NULL); - - gtk_signal_connect_object (GTK_OBJECT ( - GTK_FILE_SELECTION(s_filesel)->ok_button), - "clicked", - GTK_SIGNAL_FUNC (gtk_widget_destroy), - (gpointer) s_filesel); - - gtk_signal_connect_object (GTK_OBJECT ( - GTK_FILE_SELECTION(s_filesel)->cancel_button), - "clicked", - GTK_SIGNAL_FUNC (gtk_widget_destroy), - (gpointer) s_filesel); - gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(s_filesel)); - gtk_widget_show (s_filesel); -} - -/**************************************************************************** -* get_events_name -****************************************************************************/ - -static void get_events_name (GtkFileSelection *sel, gpointer user_data) -{ - char *filename = (char *) gtk_file_selection_get_filename ( - GTK_FILE_SELECTION(s_eventsel)); - read_events(filename); - view1_display_when_idle(); -} - - -/**************************************************************************** -* get_ticks_per_ns -****************************************************************************/ - -static boolean get_ticks_per_ns (char *value) -{ - double rv; - - rv = atof (value); - - if (rv == 0.0 || rv > 100000) - return(FALSE); - - ticks_per_ns = rv; - ticks_per_ns_set = TRUE; - - gtk_widget_show(s_eventsel); - return(TRUE); -} - -/**************************************************************************** -* read_events_callback -****************************************************************************/ - -static void read_events_callback(GtkToggleButton *item, gpointer data) -{ - char tmpbuf [32]; - - s_eventsel = gtk_file_selection_new("Read Events From..."); - - gtk_signal_connect (GTK_OBJECT ( - GTK_FILE_SELECTION(s_eventsel)->ok_button), - "clicked", - GTK_SIGNAL_FUNC(get_events_name), NULL); - - gtk_signal_connect_object (GTK_OBJECT ( - GTK_FILE_SELECTION(s_eventsel)->ok_button), - "clicked", - GTK_SIGNAL_FUNC (gtk_widget_destroy), - (gpointer) s_eventsel); - - gtk_signal_connect_object (GTK_OBJECT ( - GTK_FILE_SELECTION(s_eventsel)->cancel_button), - "clicked", - GTK_SIGNAL_FUNC (gtk_widget_destroy), - (gpointer) s_eventsel); - gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(s_eventsel)); - - if (ticks_per_ns_set) - gtk_widget_show (s_eventsel); - else { - sprintf(tmpbuf, "%.3f", ticks_per_ns); - modal_dialog ("Please enter clock ticks per nanosecond", - "Invalid: Please enter clock ticks per nanosecond", - tmpbuf, get_ticks_per_ns); - } -} - -/**************************************************************************** -* read_eventclock_callback -****************************************************************************/ - -static void read_eventsclock_callback(GtkToggleButton *item, gpointer data) -{ - ticks_per_ns_set = FALSE; - read_events_callback(item, data); -} - -/**************************************************************************** -* infobox_size_request -****************************************************************************/ - -void infobox_size_request (GtkWidget *widget, GtkRequisition *req, - gpointer user_data) -{ - char *text = (char *)user_data; - char *cp; - int widest_line_in_chars; - int w; - int nlines; - - /* - * You'd think that the string extent function would work here. - * You'd be wrong. - */ - nlines = w = widest_line_in_chars = 0; - for (cp = text; *cp; cp++) { - if (*cp == '\n') { - if (w > widest_line_in_chars) { - widest_line_in_chars = w; - } - w = 0; - nlines++; - } - w++; - } - - nlines++; - - req->width = (widest_line_in_chars * 8) + 20; - req->height = (nlines * 13) + 10; -} - -/**************************************************************************** -* infobox -****************************************************************************/ - -void infobox(char *label_text, char *text) -{ - GtkWidget *dialog, *label, *ok_button, *entry; - GtkWidget *box; - - dialog = gtk_dialog_new(); - label = gtk_label_new(label_text); - - entry = gtk_text_new(NULL, NULL); - - gtk_signal_connect (GTK_OBJECT (entry), "size-request", - GTK_SIGNAL_FUNC(infobox_size_request), - (gpointer) text); - - gtk_text_insert(GTK_TEXT(entry), g_font, &fg_black, &bg_white, - text, -1); - - gtk_text_set_editable(GTK_TEXT(entry), FALSE); - - ok_button = gtk_button_new_with_label("OK"); - - gtk_signal_connect_object (GTK_OBJECT (ok_button), "clicked", - GTK_SIGNAL_FUNC(gtk_widget_destroy), - (gpointer) GTK_OBJECT(dialog)); - - box = gtk_vbox_new(FALSE, 5); - - - gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(box), ok_button, FALSE, FALSE, 0); - - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), - box); - - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); - gtk_widget_show_all(dialog); -} - -/**************************************************************************** -* help_general_callback -****************************************************************************/ - -static void help_general_callback(GtkToggleButton *item, gpointer data) -{ - infobox("General Help", general_help); -} - -/**************************************************************************** -* help_about_callback -****************************************************************************/ - -static void help_about_callback(GtkToggleButton *item, gpointer data) -{ - char tmpbuf [1024]; - sprintf (tmpbuf, "G2 -- Graphical Event Viewer\n\n"); - view1_about(tmpbuf); - pointsel_about(tmpbuf); - events_about(tmpbuf); - sprintf (tmpbuf+strlen(tmpbuf), "\n%s\n", version_string); - sprintf (tmpbuf+strlen(tmpbuf), "%s\n", minor_v_string); - infobox("About", tmpbuf); -} - - -/**************************************************************************** -* get_cpel_name -****************************************************************************/ - -static void get_cpel_name (GtkFileSelection *sel, gpointer user_data) -{ - char *filename = (char *)gtk_file_selection_get_filename ( - GTK_FILE_SELECTION(s_filesel)); - read_cpel_file(filename); - set_window_title(filename); -} - -/**************************************************************************** -* get_clib_name -****************************************************************************/ - -static void get_clib_name (GtkFileSelection *sel, gpointer user_data) -{ - char *filename = (char *) gtk_file_selection_get_filename ( - GTK_FILE_SELECTION(s_filesel)); - read_clib_file(filename); - set_window_title(filename); -} - -/**************************************************************************** -* read_cpel_callback -****************************************************************************/ - -static void read_cpel_callback(GtkToggleButton *item, gpointer data) -{ - - s_filesel = gtk_file_selection_new("Read CPEL data from..."); - - gtk_file_selection_set_filename(GTK_FILE_SELECTION(s_filesel), - "cpel.out"); - - gtk_signal_connect (GTK_OBJECT ( - GTK_FILE_SELECTION(s_filesel)->ok_button), - "clicked", - GTK_SIGNAL_FUNC(get_cpel_name), NULL); - - gtk_signal_connect_object (GTK_OBJECT ( - GTK_FILE_SELECTION(s_filesel)->ok_button), - "clicked", - GTK_SIGNAL_FUNC (gtk_widget_destroy), - (gpointer) s_filesel); - - gtk_signal_connect_object (GTK_OBJECT ( - GTK_FILE_SELECTION(s_filesel)->cancel_button), - "clicked", - GTK_SIGNAL_FUNC (gtk_widget_destroy), - (gpointer) s_filesel); - gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(s_filesel)); - gtk_widget_show (s_filesel); -} - -/**************************************************************************** -* read_clib_callback -****************************************************************************/ - -static void read_clib_callback(GtkToggleButton *item, gpointer data) -{ - - s_filesel = gtk_file_selection_new("Read clib data From..."); - - gtk_file_selection_set_filename(GTK_FILE_SELECTION(s_filesel), - "clib.out"); - - gtk_signal_connect (GTK_OBJECT ( - GTK_FILE_SELECTION(s_filesel)->ok_button), - "clicked", - GTK_SIGNAL_FUNC(get_clib_name), NULL); - - gtk_signal_connect_object (GTK_OBJECT ( - GTK_FILE_SELECTION(s_filesel)->ok_button), - "clicked", - GTK_SIGNAL_FUNC (gtk_widget_destroy), - (gpointer) s_filesel); - - gtk_signal_connect_object (GTK_OBJECT ( - GTK_FILE_SELECTION(s_filesel)->cancel_button), - "clicked", - GTK_SIGNAL_FUNC (gtk_widget_destroy), - (gpointer) s_filesel); - gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(s_filesel)); - gtk_widget_show (s_filesel); -} - -/**************************************************************************** -* menu1_init -****************************************************************************/ - -void menu1_init(void) -{ - - s_filemenu = gtk_menu_new(); - - s_readcpel = gtk_menu_item_new_with_label - ("Read CPEL file"); - gtk_menu_append(GTK_MENU(s_filemenu), s_readcpel); - gtk_signal_connect(GTK_OBJECT(s_readcpel), "activate", - GTK_SIGNAL_FUNC(read_cpel_callback), 0); - - s_readclib = gtk_menu_item_new_with_label - ("Read CLIB file"); - gtk_menu_append(GTK_MENU(s_filemenu), s_readclib); - gtk_signal_connect(GTK_OBJECT(s_readclib), "activate", - GTK_SIGNAL_FUNC(read_clib_callback), 0); - - s_readdefs = gtk_menu_item_new_with_label ("Read Event Definitions"); - gtk_menu_append(GTK_MENU(s_filemenu), s_readdefs); - gtk_signal_connect(GTK_OBJECT(s_readdefs), "activate", - GTK_SIGNAL_FUNC(read_eventdef_callback), 0); - - s_readevents = gtk_menu_item_new_with_label ("Read Event Log"); - gtk_menu_append(GTK_MENU(s_filemenu), s_readevents); - gtk_signal_connect(GTK_OBJECT(s_readevents), "activate", - GTK_SIGNAL_FUNC(read_events_callback), 0); - - s_readeventsclock = gtk_menu_item_new_with_label - ("Read Event Log with Different Clock Rate"); - gtk_menu_append(GTK_MENU(s_filemenu), s_readeventsclock); - gtk_signal_connect(GTK_OBJECT(s_readeventsclock), "activate", - GTK_SIGNAL_FUNC(read_eventsclock_callback), 0); - - s_print = gtk_menu_item_new_with_label ("Print"); - gtk_menu_append(GTK_MENU(s_filemenu), s_print); - gtk_signal_connect(GTK_OBJECT(s_print), "activate", - GTK_SIGNAL_FUNC(view1_print_callback), 0); - - s_quit = gtk_menu_item_new_with_label ("Exit"); - gtk_menu_append(GTK_MENU(s_filemenu), s_quit); - gtk_signal_connect(GTK_OBJECT(s_quit), "activate", - GTK_SIGNAL_FUNC(gtk_main_quit), 0); - - s_mainfilemenu = gtk_menu_item_new_with_label("File"); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(s_mainfilemenu), s_filemenu); - - s_helpmenu = gtk_menu_new(); - - s_help_general = gtk_menu_item_new_with_label ("General"); - gtk_menu_append(GTK_MENU(s_helpmenu), s_help_general); - gtk_signal_connect(GTK_OBJECT(s_help_general), "activate", - GTK_SIGNAL_FUNC(help_general_callback), 0); - - s_help_about = gtk_menu_item_new_with_label ("About"); - gtk_menu_append(GTK_MENU(s_helpmenu), s_help_about); - gtk_signal_connect(GTK_OBJECT(s_help_about), "activate", - GTK_SIGNAL_FUNC(help_about_callback), 0); - - s_mainhelpmenu = gtk_menu_item_new_with_label("Help"); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(s_mainhelpmenu), s_helpmenu); - - s_mainmenubar = gtk_menu_bar_new(); - gtk_menu_bar_append(GTK_MENU_BAR(s_mainmenubar), s_mainfilemenu); - gtk_menu_bar_append(GTK_MENU_BAR(s_mainmenubar), s_mainhelpmenu); - gtk_widget_show_all(s_mainmenubar); - - gtk_box_pack_start(GTK_BOX(g_mainvbox), s_mainmenubar, FALSE, FALSE, 0); -} diff --git a/g2/mkversion.c b/g2/mkversion.c deleted file mode 100644 index 3523fbe6..00000000 --- a/g2/mkversion.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 1997-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 - -int main (int argc, char **argv) -{ - time_t now; - FILE *ofp; - char *dateval; - char *username; - char *userstr; - char *datestr; - int i; - char propname[32]; - char *propvalue; - char timestr[64]; - char *cp; - - if (argc < 4) { - printf ("usage: mkversion ostype version outputfile\n"); - exit (1); - } - - ofp = fopen (argv[3], "w"); - if (ofp == NULL) { - printf ("Couldn't create %s\n", argv[3]); - exit (1); - } - - now = time (0); - - fprintf (ofp, "/*\n"); - fprintf (ofp, " * G2 Version Stamp, %s", - ctime (&now)); - fprintf (ofp, " * Automatically generated, hand edits are pointless.\n"); - fprintf (ofp, " */\n\n"); - - fprintf (ofp, - "const char *version_string = \"G2 (%s) major version %s\";\n", - argv[1], argv[2]); - - username = (char *) cuserid (0); - - strcpy(timestr, ctime(&now)); - - cp = timestr; - - while (*cp) { - cp++; - } - if (*--cp == '\n') - *cp = 0; - - fprintf (ofp, - "const char *minor_v_string = \"Built by %s at %s\";\n", - username, timestr); - - exit (0); -} - - diff --git a/g2/pointsel.c b/g2/pointsel.c deleted file mode 100644 index 018dc213..00000000 --- a/g2/pointsel.c +++ /dev/null @@ -1,854 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2005-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 "g2.h" - -/* - * globals - */ -event_def_t g_eventdefs[NEVENTS]; - -/* - * locals - */ -static GtkWidget *s_pointselbox; -static FILE *s_hfp; -static FILE *s_elog_hfp; -static int s_basenum; -static GtkWidget *s_event_buttons[NEVENTS]; -static int s_min_shown_pointsel; -static int s_max_shown_pointsel; -static GtkWidget *s_allbutton; -static GtkWidget *s_nonebutton; -static GtkWidget *s_pointselbuttons; -static GtkWidget *s_ps_vscroll; -static GtkObject *s_ps_vsadj; -static int g_neventdefs; - -enum button_click { - ALL_BUTTON=1, - NONE_BUTTON, -}; - -/* - * config params - */ -int c_maxpointsel; - -/**************************************************************************** -* recompute_vscrollbar -****************************************************************************/ - -static void recompute_ps_vscrollbar (void) -{ - GtkAdjustment *adj; - ulong limit; - - adj = GTK_ADJUSTMENT(s_ps_vsadj); - -#ifdef NOTDEF - /* This seems like the right calculation, but seems not to work */ - if (g_neventdefs > c_maxpointsel) - limit = g_neventdefs - c_maxpointsel; - else - limit = g_neventdefs; -#else - limit = g_neventdefs-1; -#endif - - adj->lower = (gfloat)0.00; - adj->upper = (gfloat)limit; - adj->value = (gfloat)0.00; - adj->step_increment = (gfloat)1.00; - adj->page_increment = (gfloat)(c_maxpointsel / 3); - adj->page_size = (gfloat)c_maxpointsel; - gtk_adjustment_changed(adj); - gtk_adjustment_value_changed(adj); - gtk_widget_show(s_ps_vscroll); -} - -/**************************************************************************** -* point_select_callback -****************************************************************************/ - -static void point_select_callback(GtkToggleButton *item, gpointer data) -{ - int i = (int) (unsigned long long) data; - - g_eventdefs[i].selected = gtk_toggle_button_get_active( - GTK_TOGGLE_BUTTON(s_event_buttons[i])); - view1_display_when_idle(); -} - -/**************************************************************************** -* up_button -****************************************************************************/ - -static void up_button(void) -{ - int i; - int increment = c_maxpointsel/4; - - if (s_min_shown_pointsel == 0) - return; - - s_min_shown_pointsel -= increment; - - if (s_min_shown_pointsel < 0) - s_min_shown_pointsel = 0; - - s_max_shown_pointsel = s_min_shown_pointsel + c_maxpointsel; - - for (i = 0; i < g_neventdefs; i++) { - if (i >= s_min_shown_pointsel && - i <= s_max_shown_pointsel) - gtk_widget_show(s_event_buttons[i]); - else - gtk_widget_hide(s_event_buttons[i]); - } - -} - -#ifdef NOTDEF -/**************************************************************************** -* down_button -****************************************************************************/ - -static void down_button(void) -{ - int i; - int increment = c_maxpointsel/4; - - if (s_max_shown_pointsel == g_neventdefs) - return; - - s_max_shown_pointsel += increment; - - if (s_max_shown_pointsel >= g_neventdefs) - s_max_shown_pointsel = (g_neventdefs-1); - - s_min_shown_pointsel = s_max_shown_pointsel - c_maxpointsel; - - if (s_min_shown_pointsel < 0) - s_min_shown_pointsel = 0; - - for (i = 0; i < g_neventdefs; i++) { - if (i >= s_min_shown_pointsel && - i <= s_max_shown_pointsel) - gtk_widget_show(s_event_buttons[i]); - else - gtk_widget_hide(s_event_buttons[i]); - } - -} -#endif - -/**************************************************************************** -* button_click_callback -****************************************************************************/ - -static void button_click_callback(GtkButton *item, gpointer data) -{ - int i; - enum button_click click = (enum button_click)data; - - switch (click) { - case ALL_BUTTON: - for (i = 0; i < g_neventdefs; i++) { - gtk_toggle_button_set_active ( - GTK_TOGGLE_BUTTON(s_event_buttons[i]), TRUE); - g_eventdefs[i].selected = TRUE; - } - break; - - case NONE_BUTTON: - for (i = 0; i < g_neventdefs; i++) { - gtk_toggle_button_set_active ( - GTK_TOGGLE_BUTTON(s_event_buttons[i]), FALSE); - g_eventdefs[i].selected = FALSE; - } - break; - } -} - -/**************************************************************************** -* scroll_callback -****************************************************************************/ - -static void scroll_callback (GtkAdjustment *adj, GtkWidget *notused) -{ - int i; - - s_min_shown_pointsel = (int)adj->value; - s_max_shown_pointsel = s_min_shown_pointsel + c_maxpointsel; - - for (i = 0; i < g_neventdefs; i++) { - if (i >= s_min_shown_pointsel && - i <= s_max_shown_pointsel) - gtk_widget_show(s_event_buttons[i]); - else - gtk_widget_hide(s_event_buttons[i]); - } -} - -/**************************************************************************** -* point_selector_init -****************************************************************************/ - -void point_selector_init(void) -{ - - c_maxpointsel = atol(getprop_default("event_selector_lines", "20")); - - s_pointselbox = gtk_vbox_new(FALSE,5); - - s_pointselbuttons = gtk_hbox_new(FALSE,5); - - s_allbutton = gtk_button_new_with_label("ALL"); - gtk_widget_show(s_allbutton); - s_nonebutton = gtk_button_new_with_label("NONE"); - gtk_widget_show(s_nonebutton); - - gtk_signal_connect (GTK_OBJECT(s_allbutton), "clicked", - GTK_SIGNAL_FUNC(button_click_callback), - (gpointer) ALL_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_nonebutton), "clicked", - GTK_SIGNAL_FUNC(button_click_callback), - (gpointer) NONE_BUTTON); - - gtk_box_pack_start(GTK_BOX(s_pointselbuttons), s_allbutton, FALSE, - FALSE, 0); - gtk_box_pack_start(GTK_BOX(s_pointselbuttons), s_nonebutton, FALSE, - FALSE, 0); - - gtk_widget_show(s_pointselbuttons); - gtk_widget_ref(s_pointselbuttons); - - gtk_box_pack_start(GTK_BOX(s_pointselbox), s_pointselbuttons, FALSE, - FALSE, 0); - - gtk_box_pack_end (GTK_BOX(g_mainhbox), s_pointselbox, - FALSE, FALSE, 0); - - s_ps_vsadj = gtk_adjustment_new(0.0 /* initial value */, - 0.0 /* minimum value */, - 2000.0 /* maximum value */, - 0.1 /* step increment */, - 10.0/* page increment */, - 10.0/* page size */); - - s_ps_vscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT(s_ps_vsadj)); - gtk_signal_connect (GTK_OBJECT (s_ps_vsadj), "value-changed", - GTK_SIGNAL_FUNC (scroll_callback), - (gpointer)s_ps_vscroll); - gtk_box_pack_end(GTK_BOX(g_mainhbox), s_ps_vscroll, FALSE, FALSE, 0); -} - -/**************************************************************************** -* sxerox -****************************************************************************/ - -char *sxerox (char *s) -{ - char *rv; - - /* Note: g_malloc does or dies... */ - rv = (char *)g_malloc(strlen(s)+1); - strcpy (rv, s); - return (rv); -} - -/**************************************************************************** -* reset_point_selector -****************************************************************************/ - -static void reset_point_selector(void) -{ - int i; - - gtk_widget_hide(s_pointselbox); - gtk_widget_hide(s_pointselbuttons); - gtk_widget_hide(s_ps_vscroll); - gtk_container_remove(GTK_CONTAINER(s_pointselbox), - s_pointselbuttons); - - for (i = 0; i < g_neventdefs; i++) { - if (s_event_buttons[i]) { - gtk_container_remove(GTK_CONTAINER(s_pointselbox), - s_event_buttons[i]); - s_event_buttons[i] = 0; - } - } -} - -/**************************************************************************** -* create_point_selector -****************************************************************************/ - -static void create_point_selector(void) -{ - int i; - char tmpbuf [1024]; - event_def_t *ep; - GtkWidget *wp; - - for (i = 0; i < g_neventdefs; i++) { - ep = &g_eventdefs[i]; - sprintf(tmpbuf, "[%lu] %s", ep->event, - ep->name ? ep->name : "(none)"); - /* Hack to reduce width of point selectors */ - if (strlen(tmpbuf) > 50) { - tmpbuf[50] = 0; - } - - wp = gtk_check_button_new_with_label (tmpbuf); - s_event_buttons[i] = wp; - gtk_signal_connect (GTK_OBJECT(wp), "toggled", - GTK_SIGNAL_FUNC(point_select_callback), - (gpointer) (unsigned long long) i); - gtk_toggle_button_set_active ( - GTK_TOGGLE_BUTTON(wp), TRUE); - gtk_box_pack_start(GTK_BOX(s_pointselbox), wp, FALSE, FALSE, 0); - } - - /* set up scroll parameters by faking an up-button */ - s_min_shown_pointsel = 1; - up_button(); - - gtk_box_pack_start(GTK_BOX(s_pointselbox), s_pointselbuttons, FALSE, - FALSE, 0); - gtk_widget_show(s_pointselbuttons); - gtk_widget_show(s_pointselbox); - gtk_widget_show(s_ps_vscroll); -} - -/**************************************************************************** -* remove_all_events -****************************************************************************/ - -static void remove_all_events(void) -{ - event_def_t *ep; - int i; - - for (i = 0; i < g_neventdefs; i++) { - ep = &g_eventdefs[i]; - if (!ep->is_clib) { - if (ep->name) - g_free(ep->name); - if(ep->format) - g_free(ep->format); - } - } - g_neventdefs = 0; -} - -/**************************************************************************** -* add_event -****************************************************************************/ - -static void add_event(ulong event, char *name, char *format) -{ - int i; - event_def_t *ep; - - if (g_neventdefs >= NEVENTS) { - g_error("Too many event definitions, increase NEVENTS!"); - /*NOTREACHED*/ - } - - /* Simple dup check, probably not needed very often */ - for (i = 0; i < g_neventdefs; i++) { - if (g_eventdefs[i].event == event) { - g_warning("Duplicate def event %lu: first definition retained\n", - event); - return; - } - } - - ep = &g_eventdefs[g_neventdefs++]; - - ep->event = event; - ep->name = sxerox(name); - ep->format = sxerox(format); - ep->selected = TRUE; -} - -/**************************************************************************** -* add_event_from_cpel_file -****************************************************************************/ - -void add_event_from_cpel_file(ulong event, char *event_format, - char *datum_format) -{ - event_def_t *ep; - - if (g_neventdefs >= NEVENTS) { - g_error("Too many event definitions, increase NEVENTS!"); - /*NOTREACHED*/ - } - - ep = &g_eventdefs[g_neventdefs++]; - - ep->event = event; - /* - * Duplicate the strings for backward compatibility. Otherwise, - * the g_free above will barf because the name/format strings are - * actually in mmap'ed memory - */ - ep->name = sxerox(event_format); - ep->format = sxerox(datum_format); - ep->selected = TRUE; -} - -/**************************************************************************** -* add_event_from_clib_file -****************************************************************************/ - -void add_event_from_clib_file(unsigned int event, char *name, - unsigned int vec_index) -{ - event_def_t *ep; - - if (g_neventdefs >= NEVENTS) { - g_error("Too many event definitions, increase NEVENTS!"); - /*NOTREACHED*/ - } - - ep = &g_eventdefs[g_neventdefs++]; - - ep->event = event; - - ep->name = sxerox(name); - ep->format = (void *)(unsigned long long) vec_index; - ep->selected = TRUE; - ep->is_clib = TRUE; -} - -/**************************************************************************** -* read_header_file - eats header file lines of the form -* -* #define EVENT_FOO 123 / * name: %d * / -* -****************************************************************************/ - -static void read_header_file (void) -{ - char tmpbuf [1024]; - char *name, *format; - char *cp; - unsigned long event; - int ev_num_flag; - - while (fgets (tmpbuf, sizeof (tmpbuf), s_hfp)) - { - cp = tmpbuf; - ev_num_flag = 0; - - if (strncmp (cp, "#define", 7)) - continue; - - /* skip #define */ - while (*cp && !(isspace ((int)*cp))) - cp++; - - if (*cp == 0) - continue; - - /* skip ws after #define */ - while (*cp && isspace ((int)*cp)) - cp++; - - if (*cp == 0) - continue; - - /* skip symbolic name */ - while (*cp && !(isspace ((int)*cp))) - cp++; - - if (*cp == 0) - continue; - - /* skip ws after symbolic name */ - while (*cp && isspace ((int)*cp)) - cp++; - - if (*cp == 0) - continue; - - event = 0; - - if (!strncmp(cp, "EV_NUM", 6)) { - cp += 6; - ev_num_flag = 1; - - while (*cp && *cp != '(') - cp++; - - if (*cp == 0) - continue; - - cp++; - - while (*cp && isspace ((int)*cp)) - cp++; - - } - - /* eat event code. */ - while (*cp && isdigit ((int)*cp)) - { - event = event * 10 + (*cp - '0'); - cp++; - } - - if (*cp == 0) - continue; - - if (ev_num_flag) { - while (*cp && *cp != ')') - cp++; - if (*cp == 0) - continue; - cp++; - event += s_basenum; - } - - /* skip ws after event code */ - while (*cp && isspace ((int)*cp)) - cp++; - - if (*cp != '/') - continue; - - cp++; - - if (*cp != '*') - continue; - - cp++; - - /* skip ws after comment start */ - while (*cp && isspace ((int)*cp)) - cp++; - - if (*cp == 0) - continue; - - name = cp; - - /* accumulate name */ - while (*cp && *cp != ':' && *cp != '*') - cp++; - - if (*cp == 0) - continue; - - *cp++ = 0; - - /* skip ws after name: */ - while (*cp && isspace ((int)*cp)) - cp++; - - if (*cp == 0 || *cp == '/') - { - format = " "; - goto write_it; - } - - format = cp; - - /* accumulate format string */ - while (*cp && !isspace ((int)*cp)) - cp++; - - *cp = 0; - - write_it: - - add_event (event, name, format); - } -} - -/**************************************************************************** -* read_header_files - eats header file lines of the form -* -* #define FILE1_BASE 100 / * pointdefs: ../vpn/vpn_points.h * / -* -****************************************************************************/ - -static boolean read_header_files (void) -{ - char *cp, *name; - char tmpbuf [1024]; - int basenum; - boolean rv=FALSE; - - while (fgets (tmpbuf, sizeof (tmpbuf), s_elog_hfp)) - { - cp = tmpbuf; - - if (strncmp (cp, "#define", 7)) - continue; - - cp += 7; - - /* skip ws after #define */ - while (*cp && isspace ((int)*cp)) - cp++; - - if (*cp == 0) - continue; - - /* skip EV_COMPxxx_START */ - while (*cp && !isspace((int)*cp)) - cp++; - - if (*cp == 0) - continue; - - /* skip ws after EV_COMPxxx_START */ - while (*cp && isspace ((int)*cp)) - cp++; - - if (*cp == 0) - continue; - - basenum = atol (cp); - - /* skip #define */ - while (*cp && (*cp != '/')) - cp++; - - if (*cp == 0) - continue; - - cp++; - if (*cp != '*') - continue; - - cp++; - - /* skip ws after comment start */ - while (*cp && isspace ((int)*cp)) - cp++; - - if (*cp == 0) - continue; - - if (strncmp (cp, "pointdefs:", 10)) - continue; - - cp += 10; - - /* skip ws after comment start */ - while (*cp && isspace ((int)*cp)) - cp++; - - name = cp; - - while (*cp && !isspace ((int)*cp)) - cp++; - - *cp = 0; - - s_hfp = fopen (name, "rt"); - - if (s_hfp == NULL) { - g_warning ("Couldn't open header file %s\n", name); - continue; - } - rv = TRUE; - - s_basenum = basenum; - - read_header_file(); - - fclose (s_hfp); - } - return(rv); -} - -/**************************************************************************** -* event_def_cmp -****************************************************************************/ - -int event_def_cmp(const void *a1, const void *a2) -{ - event_def_t *e1 = (event_def_t *)a1; - event_def_t *e2 = (event_def_t *)a2; - - if (e1->event < e2->event) - return(-1); - else if (e1->event == e2->event) - return(0); - else - return(1); -} - -/**************************************************************************** -* sort_event_definitions -****************************************************************************/ - -void sort_event_definitions(void) -{ - qsort(&g_eventdefs[0], g_neventdefs, sizeof(event_def_t), event_def_cmp); -} - -static boolean remove_needed=TRUE; - -void finalize_events(void) -{ - sort_event_definitions(); - create_point_selector(); - recompute_ps_vscrollbar(); - view1_display_when_idle(); - remove_needed = TRUE; -} - -void initialize_events(void) -{ - if (remove_needed) { - reset_point_selector(); - remove_all_events(); - remove_needed = FALSE; - } -} - -/**************************************************************************** -* read_event_definitions -****************************************************************************/ - -boolean read_event_definitions (char *filename) -{ - char tmpbuf [128]; - - initialize_events(); - - s_elog_hfp = fopen (filename, "rt"); - if (s_elog_hfp == NULL) { - sprintf (tmpbuf, "Couldn't open %s\n", filename); - infobox ("Open Failed", tmpbuf); - return(FALSE); - } - /* Presume "elog.h". Note fallthrough... */ - if (read_header_files()) { - sort_event_definitions(); - create_point_selector(); - recompute_ps_vscrollbar(); - fclose(s_elog_hfp); - view1_display_when_idle(); - remove_needed = TRUE; - return(TRUE); - } - fclose(s_elog_hfp); - - s_hfp = fopen (filename, "rt"); - if (s_hfp == NULL) { - sprintf (tmpbuf, "Couldn't open %s\n", filename); - infobox ("Read Event Definition Failure", tmpbuf); - return(FALSE); - } - - read_header_file(); - - /* Happens if the user feeds us the wrong file, for example */ - if (g_neventdefs == 0) { - sprintf (tmpbuf, "No event definitions found in %s\n", filename); - infobox ("No Event Definitions?", tmpbuf); - return(FALSE); - } - finalize_events(); - return(TRUE); -} - -static event_def_t dummy_event; -static char dummy_string[32]; - -/**************************************************************************** -* find_event_definition -* Binary search for first event whose time is >= t -****************************************************************************/ - -event_def_t *find_event_definition (ulong code) -{ - int index, bottom, top; - event_def_t *edp; - - if (g_neventdefs == 0) - goto use_dummy; - - bottom = g_neventdefs-1; - top = 0; - - while (1) { - index = (bottom + top) / 2; - - edp = (g_eventdefs + index); - - if (edp->event == code) - return(edp); - - if (top >= bottom) { - use_dummy: - edp = &dummy_event; - edp->selected = TRUE; - edp->event = code; - edp->format = "0x%x"; - sprintf (dummy_string, "E%lu", code); - edp->name = &dummy_string[0]; - return(edp); - } - - if (edp->event < code) - top = index + 1; - else - bottom = index - 1; - } -} - -/**************************************************************************** -* pointsel_next_snapshot -* Set dialog buttons from snapshot -****************************************************************************/ - -void pointsel_next_snapshot(void) -{ - int i; - - for (i = 0; i < g_neventdefs; i++) { - gtk_toggle_button_set_active ( - GTK_TOGGLE_BUTTON(s_event_buttons[i]), - g_eventdefs[i].selected); - } -} - -/**************************************************************************** -* pointsel_about -****************************************************************************/ - -void pointsel_about (char *tmpbuf) -{ - sprintf (tmpbuf+strlen(tmpbuf), "%d event definitions\n", - g_neventdefs); -} diff --git a/g2/props.c b/g2/props.c deleted file mode 100644 index a23dc050..00000000 --- a/g2/props.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 1997-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 - -static char *sxerox (char *s); -void exit(int); - -#define NBUCKETS 97 - -typedef struct prop_ { - struct prop_ *next; - char *name; - char *value; -} prop_t; - -static prop_t *buckets [NBUCKETS]; -static int hash_shifts[4] = {24, 16, 8, 0}; - -/* - * getprop - */ - -char *getprop (char *name) -{ - unsigned char *cp; - unsigned long hash=0; - prop_t *bp; - int i=0; - - for (cp = (unsigned char *) name; *cp; cp++) - hash ^= (*cp)<<(hash_shifts[(i++)&0x3]); - - bp = buckets [hash%NBUCKETS]; - - while (bp && strcmp (bp->name, name)) { - bp = bp->next; - } - - if (bp == NULL) - return (0); - else - return (bp->value); -} - -/* - * getprop_default - */ - -char *getprop_default (char *name, char *def) -{ - char *rv; - rv = getprop (name); - if (rv) - return (rv); - else - return (def); -} - -/* - * addprop - */ - -void addprop (char *name, char *value) -{ - unsigned char *cp; - unsigned long hash=0; - prop_t **bpp; - prop_t *bp; - int i=0; - - bp = (prop_t *)g_malloc (sizeof (prop_t)); - - bp->next = 0; - bp->name = sxerox (name); - bp->value = sxerox (value); - - for (cp = (unsigned char *)name; *cp; cp++) - hash ^= (*cp)<<(hash_shifts[(i++)&0x3]); - - bpp = &buckets [hash%NBUCKETS]; - - if (*bpp == NULL) - *bpp = bp; - else { - bp->next = *bpp; - *bpp = bp; - } -} - -/* - * sxerox - */ - -static char *sxerox (char *s) -{ - char *rv = (char *) g_malloc (strlen (s) + 1); - strcpy (rv, s); - return rv; -} - -/* - * readprops - */ - -#define START 0 -#define READNAME 1 -#define READVALUE 2 -#define C_COMMENT 3 -#define CPP_COMMENT 4 - -int readprops (char *filename) -{ - FILE *ifp; - unsigned char c; - int state=START; - int linenum=1; - char namebuf [128]; - char valbuf [512]; - int i; - - ifp = fopen (filename, "r"); - - if (ifp == NULL) - return (-1); - - while (1) { - - readchar: - c = getc (ifp); - - again: - switch (state) { - case START: - if (feof (ifp)) { - fclose (ifp); - return (0); - } - - if (c == ' ' || c == '\t') - goto readchar; - - if (c == '\n') { - linenum++; - goto readchar; - } - if (isalpha (c) || (c == '_')) { - state = READNAME; - goto again; - } - if (c == '/') { - c = getc (ifp); - if (c == '/') { - state = CPP_COMMENT; - goto readchar; - } else if (c == '*') { - state = C_COMMENT; - goto readchar; - } else { - fprintf (stderr, "unknown token '/' line %d\n", - linenum); - exit (1); - } - } - fprintf (stderr, "unknown token '%c' line %d\n", - c, linenum); - exit (1); - break; - - case CPP_COMMENT: - while (1) { - c = getc (ifp); - if (feof (ifp)) - return (0); - if (c == '\n') { - linenum++; - state = START; - goto readchar; - } - } - break; - - case C_COMMENT: - while (1) { - c = getc (ifp); - if (feof (ifp)) { - fprintf (stderr, "unterminated comment, line %d\n", - linenum); - exit (1); - } - if (c == '*') { - staragain: - c = getc (ifp); - if (c == '/') { - state = START; - goto readchar; - } - if (c == '*') - goto staragain; - } - } - break; - - case READNAME: - i = 0; - namebuf[i++] = c; - while (1) { - c = getc (ifp); - if (feof (ifp)) { - fprintf (stderr, "EOF while reading a name, line %d\n", - linenum); - exit (1); - } - if ((!isalnum (c)) && (c != '_')) { - namebuf [i] = 0; - state = READVALUE; - goto again; - } - namebuf [i++] = c; - } - break; - - case READVALUE: - i = 0; - while ((c == ' ') || (c == '\t') || (c == '=')) { - c = getc (ifp); - if (feof (ifp)) { - fprintf (stderr, "EOF while reading a value, line %d\n", - linenum); - exit (1); - } - } - goto firsttime; - while (1) { - c = getc (ifp); - - firsttime: - if (c == '\\') { - c = getc (ifp); - if (feof (ifp)) { - fprintf (stderr, "EOF after '\\', line %d\n", - linenum); - exit (1); - } - valbuf[i++] = c; - continue; - } - if (c == '\n') { - linenum++; - while (valbuf [i-1] == ' ' || valbuf[i-1] == '\t') - i--; - valbuf[i] = 0; - addprop (namebuf, valbuf); - state = START; - goto readchar; - } - valbuf[i++] = c; - } - - } - } -} diff --git a/g2/props.h b/g2/props.h deleted file mode 100644 index 6289941d..00000000 --- a/g2/props.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 1997-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -extern char *getprop (char *name); -extern char *getprop_default (char *name, char *def); -extern void addprop (char *name, char *value); -extern int readprops (char *filename); -extern int writeprops (char *filename); diff --git a/g2/view1.c b/g2/view1.c deleted file mode 100644 index ec394cc3..00000000 --- a/g2/view1.c +++ /dev/null @@ -1,3077 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2005-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 "g2.h" -#include -#include -#include -#include - -/* - * The main event display view. - * - * Important variables: - * - * "da" -- the drawing area, aka the screen representation of the - * event view. - * - * "pm" -- the backing pixmap for the drawing area. Note that - * all graphics operations target this backing - * store, then call gtk_widget_draw to copy a rectangle from - * the backing store onto the screen. - * - * "s_v1" -- pointer to the current v1_geometry_t object. - * - * Box heirarchy: - * s_view1_vbox - * s_view1_hbox - * da s_view1_vmenubox - * s_view1_topbutton("Top") - * s_view1_vscroll (vertical scrollbar) - * s_view1_bottombutton("Bottom") - * s_view1_hmenubox - * s_view1_startbutton("Start"); - * s_view1_hscroll(horizontal scrollbar) - * s_view1_endbutton("End") - * s_view1_zoominbutton("Zoomin") - * s_view1_searchbutton("Search") - * s_view1_searchagainbutton("Search Again") - * s_view1_zoomoutbutton("Zoomout") - * s_view1_label - */ - -/* - * Globals - */ - -GdkFont *g_font; /* a fixed-width font to use */ -GdkColor fg_black = {0, 0, 0, 0}; -GdkColor bg_white = {0, 65535, 65535, 65535}; -static boolean summary_mode = TRUE; /* start out in summary mode */ -static boolean color_mode = FALSE; /* start out in color mode */ - -/* - * Locals - */ - -/* - * user_data values passed to view1_button_click_callback, - * which is used by the various action buttons noted above - */ -enum view1_button_click { - TOP_BUTTON=1, - BOTTOM_BUTTON, - START_BUTTON, - ZOOMIN_BUTTON, - SEARCH_BUTTON, - SEARCH_AGAIN_BUTTON, - ZOOMOUT_BUTTON, - END_BUTTON, - MORE_TRACES_BUTTON, - LESS_TRACES_BUTTON, - SNAP_BUTTON, - NEXT_BUTTON, - DEL_BUTTON, - CHASE_EVENT_BUTTON, - CHASE_DATUM_BUTTON, - CHASE_TRACK_BUTTON, - UNCHASE_BUTTON, - FORWARD_BUTTON, - BACKWARD_BUTTON, - SUMMARY_BUTTON, - NOSUMMARY_BUTTON, -}; - -enum chase_mode { - CHASE_EVENT=1, - CHASE_DATUM, - CHASE_TRACK, -}; - -enum sc_dir { - SRCH_CHASE_FORWARD = 0, - SRCH_CHASE_BACKWARD = 1, -}; - -static GtkWidget *s_view1_hbox; /* see box heirarchy chart */ -static GtkWidget *s_view1_vbox; /* see box heirarchy chart */ -static GtkWidget *da; /* main drawing area */ -static GdkPixmap *pm; /* and its backing pixmap */ -static GdkCursor *norm_cursor; /* the "normal" cursor */ - -/* - * view geometry parameters - * - * Remember: - * Y increases down the page. - * Strip origin is at the top - * Payday is Friday - * Don't put your fingers in your mouth. - * - * Most of these values are in pixels - */ - -typedef struct v1_geometry { - int pid_ax_width; /* Width of the PID axis */ - int time_ax_height; /* Height of the time axis */ - int time_ax_spacing; /* TimeAxis: Space between tick-marks */ - int strip_height; /* Height of a regular PID trace */ - int pop_offset; /* Vertical offset of the detail box */ - int pid_ax_offset; /* Vertical offset of the PID axis */ - int event_offset; /* Vertical offset of the event boxes */ - int total_height; /* total height of da, see configure_event */ - int total_width; /* ditto, for width */ - - /* Derived values */ - int first_pid_index; /* Index of first displayed PID */ - int npids; /* Max number of displayed pids */ - ulonglong minvistime; /* in usec */ - ulonglong maxvistime; /* in usec */ -} v1_geometry_t; - - -/* The active geometry object */ -static v1_geometry_t s_v1record; -static v1_geometry_t *s_v1 = &s_v1record; - -/* The color array */ -static GdkColor *s_color; - -/* Snapshot ring */ -typedef struct snapshot { - struct snapshot *next; - /* Screen geometry */ - v1_geometry_t geometry; - boolean show_event[NEVENTS]; - pid_sort_t *pidvec; - /* - * Note: not worth recomputing the vertical scrollbar, just save - * its value here - */ - gfloat vscroll_value; - boolean summary_mode; - boolean color_mode; -} snapshot_t; - -static snapshot_t *s_snapshots; -static snapshot_t *s_cursnap; -static event_t *s_last_selected_event; - -/* - * various widgets, see the box heirarchy chart above - * The toolkit keeps track of these things, we could lose many of - * these pointers. - */ -static GtkWidget *s_view1_vmenubox; -static GtkWidget *s_view1_topbutton; -static GtkWidget *s_view1_bottombutton; -static GtkWidget *s_view1_more_traces_button; -static GtkWidget *s_view1_less_traces_button; - -static GtkWidget *s_view1_hmenubox; -static GtkWidget *s_view1_hmenubox2; -static GtkWidget *s_view1_startbutton; -static GtkWidget *s_view1_zoominbutton; -static GtkWidget *s_view1_searchbutton; -static GtkWidget *s_view1_srchagainbutton; -static GtkWidget *s_view1_zoomoutbutton; -static GtkWidget *s_view1_endbutton; - -static GtkWidget *s_view1_snapbutton; -static GtkWidget *s_view1_nextbutton; -static GtkWidget *s_view1_delbutton; - -static GtkWidget *s_view1_chase_event_button; -static GtkWidget *s_view1_chase_datum_button; -static GtkWidget *s_view1_chase_track_button; -static GtkWidget *s_view1_unchasebutton; - -static GtkWidget *s_view1_forward_button; -static GtkWidget *s_view1_backward_button; - -static GtkWidget *s_view1_summary_button; -static GtkWidget *s_view1_nosummary_button; - -static GtkWidget *s_view1_hscroll; -static GtkObject *s_view1_hsadj; - -static GtkWidget *s_view1_vscroll; -static GtkObject *s_view1_vsadj; - -static GtkWidget *s_view1_label; - -/* - * Search context - */ -static ulong s_srchcode; /* search event code */ -static int s_srchindex; /* last hit was at this event index */ -static boolean s_result_up; /* The SEARCH RESULT dongle is displayed */ -static boolean s_srchfail_up; /* The status line "Search Failed" is up */ -static int srch_chase_dir; /* search/chase dir, 0=>forward */ - - -/* - * Print context - */ -static int s_print_offset; /* Magic offset added to line, tbox fn codes */ -static FILE *s_printfp; - -/* - * Forward reference prototypes - */ -static void display_pid_axis(v1_geometry_t *vp); -static void display_event_data(v1_geometry_t *vp); -static void display_time_axis(v1_geometry_t *vp); -static void view1_button_click_callback(GtkButton *item, gpointer data); - -/* - * config params - */ - -gint c_view1_draw_width; -gint c_view1_draw_height; - -/* - * Zoom-In / Time Ruler cursor - */ - -#define zi_width 32 -#define zi_height 32 -#define zi_x_hot 22 -#define zi_y_hot 14 -static unsigned char zi_bits[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x88, 0x00, - 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xc0, 0x00, - 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xa0, 0x00, - 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x84, 0x00, - 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -static unsigned char zi_bkgd[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x88, 0x00, - 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xc0, 0x00, - 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xa0, 0x00, - 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x84, 0x00, - 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -static GdkCursor *zi_cursor; -static GdkPixmap *zi_source, *zi_mask; - -/* - * Frequently-used small computations, best - * done correctly once and instantiated. - */ - -/**************************************************************************** -* dtime_per_pixel -****************************************************************************/ - -static inline double dtime_per_pixel(v1_geometry_t *vp) -{ - return ((double)(vp->maxvistime - vp->minvistime)) / - ((double)(vp->total_width - vp->pid_ax_width)); -} - -/**************************************************************************** -* message_line -* Changes the status line. Pass "" to clear the status line. -****************************************************************************/ - -void message_line (char *s) -{ - gtk_label_set_text (GTK_LABEL(s_view1_label), s); -} - -/**************************************************************************** -* set_window_title -* Changes the window title to include the specified filename. -****************************************************************************/ - -void set_window_title (const char *filename) -{ - char title[128]; - snprintf(title, sizeof(title), "g2 (%s)", filename); - gtk_window_set_title(GTK_WINDOW(g_mainwindow), title); -} - -/**************************************************************************** -* recompute_hscrollbar -* Adjust the horizontal scrollbar's adjustment object. -* -* GtkAdjustments are really cool, but have to be set up exactly -* right or the various client objects screw up completely. -* -* Note: this function is *not* called when the user clicks the scrollbar. -****************************************************************************/ - -static void recompute_hscrollbar (void) -{ - ulonglong current_width; - ulonglong event_incdec; - GtkAdjustment *adj; - event_t *ep; - - if (g_nevents == 0) - return; - - ep = (g_events + (g_nevents-1)); - current_width = s_v1->maxvistime - s_v1->minvistime; - event_incdec = (current_width) / 6; - - adj = GTK_ADJUSTMENT(s_view1_hsadj); - - /* - * Structure member decoder ring - * ----------------------------- - * lower the minimum possible value - * value the current value - * upper the maximum possible value - * step_increment end button click increment - * page_increment click in trough increment - * page_size size of currently visible area - */ - - adj->lower = (gfloat)0.00; - adj->value = (gfloat)s_v1->minvistime; - - /* Minor click: move about 1/6 of a page */ - adj->step_increment = (gfloat)event_incdec; - - /* Major click: move about 1/3 of a page. */ - adj->page_increment = (gfloat)(2*event_incdec); - - /* allow the user to go a bit past the end */ - adj->upper = adj->page_increment/3 + (gfloat)(ep->time); - adj->page_size = (gfloat)(current_width); - - /* - * Tell all clients (e.g. the visible scrollbar) to - * make themselves look right - */ - gtk_adjustment_changed(adj); - gtk_adjustment_value_changed(adj); -} - -/**************************************************************************** -* recompute_vscrollbar -* Ditto, for the vertical scrollbar -****************************************************************************/ - -static void recompute_vscrollbar (void) -{ - GtkAdjustment *adj; - - adj = GTK_ADJUSTMENT(s_view1_vsadj); - - adj->lower = (gfloat)0.00; - adj->upper = (gfloat)g_npids; - adj->value = (gfloat)0.00; - adj->step_increment = 1.00; - adj->page_increment = (gfloat)(s_v1->npids / 3); - adj->page_size = (gfloat)s_v1->npids; - gtk_adjustment_changed(adj); - gtk_adjustment_value_changed(adj); -} - -/**************************************************************************** -* format_popbox_string -****************************************************************************/ - -elog_main_t elog_main; - -void format_popbox_string (char *tmpbuf, int len, event_t *ep, event_def_t *edp) -{ - char *fp; - -#ifdef NOTDEF - sprintf(tmpbuf,"%d:", ep->code); -#endif - if (ep->flags & EVENT_FLAG_CLIB) { - elog_event_t *eep; - u8 *s; - - eep = get_clib_event (ep->datum); - - s = format (0, "%U", format_elog_event, &elog_main, eep); - memcpy (tmpbuf, s, vec_len(s)); - tmpbuf[vec_len(s)] = 0; - vec_free(s); - return; - } - - snprintf(tmpbuf, len, "%s", edp->name); - fp = edp->format; - /* Make sure there's a real format string. If so, add it */ - while (fp && *fp) { - if (*fp != ' ') { - snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf), ": "); - /* %s only supported for cpel files */ - if (fp[1] == 's') { - snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf), - edp->format, strtab_ref(ep->datum)); - } else { - snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf), - edp->format, ep->datum); - } - return; - } - fp++; - } -} - -/**************************************************************************** - * add_snapshot - ****************************************************************************/ - -static void add_snapshot(void) -{ - int i; - snapshot_t *new = g_malloc(sizeof(snapshot_t)); - - memcpy(&new->geometry, s_v1, sizeof(new->geometry)); - for (i = 0; i < NEVENTS; i++) { - new->show_event[i] = g_eventdefs[i].selected; - } - new->pidvec = g_malloc(sizeof(pid_sort_t)*g_npids); - memcpy(new->pidvec, g_pids, sizeof(pid_sort_t)*g_npids); - new->vscroll_value = GTK_ADJUSTMENT(s_view1_vsadj)->value; - new->summary_mode = summary_mode; - new->color_mode = color_mode; - - if (s_snapshots) { - new->next = s_snapshots; - s_snapshots = new; - } else { - new->next = 0; - s_snapshots = new; - } - s_cursnap = new; -} - -/**************************************************************************** - * next_snapshot - ****************************************************************************/ - -static void next_snapshot(void) -{ - snapshot_t *next; - int i; - pid_sort_t *psp; - pid_data_t *pp; - - if (!s_snapshots) { - infobox("No snapshots", "\nNo snapshots in the ring...\n"); - return; - } - - next = s_cursnap->next; - if (next == 0) - next = s_snapshots; - - s_cursnap = next; - - memcpy(s_v1, &next->geometry, sizeof(next->geometry)); - for (i = 0; i < NEVENTS; i++) { - g_eventdefs[i].selected = next->show_event[i]; - } - memcpy(g_pids, next->pidvec, sizeof(pid_sort_t)*g_npids); - color_mode = next->color_mode; - /* - * Update summary mode via a button push so that the button state is - * updated accordingly. (Should ideally clean up the view/controller - * separation properly one day.) - */ - if (summary_mode != next->summary_mode) { - view1_button_click_callback - (NULL, (gpointer)(unsigned long long) - (summary_mode ? NOSUMMARY_BUTTON : SUMMARY_BUTTON)); - } - - /* Fix the pid structure index mappings */ - psp = g_pids; - - for (i = 0; i < g_npids; i++) { - pp = psp->pid; - pp->pid_index = i; - psp++; - } - GTK_ADJUSTMENT(s_view1_vsadj)->value = next->vscroll_value; - gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); - recompute_hscrollbar(); - pointsel_next_snapshot(); - view1_display_when_idle(); -} - - -/**************************************************************************** - * del_snapshot - ****************************************************************************/ - -static void del_snapshot(void) -{ - snapshot_t *prev; - snapshot_t *this; - - if (!s_snapshots) { - infobox("No snapshots", "\nNo snapshots to delete...\n"); - return; - } - - prev = NULL; - this = s_snapshots; - - while (this && this != s_cursnap) { - prev = this; - this = this->next; - } - - if (this != s_cursnap) { - infobox("BUG", "\nSnapshot AWOL!\n"); - return; - } - - s_cursnap = this->next; - - /* middle of the list? */ - if (prev) { - prev->next = this->next; - g_free(this->pidvec); - g_free(this); - } else { /* start of the list */ - s_snapshots = this->next; - g_free(this->pidvec); - g_free(this); - } - - /* Note: both will be NULL after last delete */ - if (s_cursnap == NULL) - s_cursnap = s_snapshots; -} - -/**************************************************************************** - * write_snapshot - * - * VERY primitive right now - not endian or version independent, and only - * writes to "snapshots.g2" in the current directory - ****************************************************************************/ -static void write_snapshot(void) -{ - FILE *file = NULL; - snapshot_t *snap; - char *error = NULL; - int records = 0; - - if (s_snapshots == NULL) { - error = "No snapshots defined"; - errno = 0; - } - - if (!error) { - file = fopen("snapshots.g2", "w"); - if (file == NULL) { - error = "Unable to open snapshots.g2"; - } - } - - /* - * Simply serialize the arch-dependent binary data, without a care in the - * world. Don't come running to me if you try to read it and crash. - */ - for (snap = s_snapshots; !error && snap != NULL; snap = snap->next) { - if (fwrite(&snap->geometry, - sizeof(snap->geometry), 1, file) != 1 || - fwrite(&snap->show_event, - sizeof(snap->show_event), 1, file) != 1 || - fwrite(snap->pidvec, - sizeof(pid_sort_t) * g_npids, 1, file) != 1 || - fwrite(&snap->vscroll_value, - sizeof(snap->vscroll_value), 1, file) != 1 || - fwrite(&snap->summary_mode, - sizeof(snap->summary_mode), 1, file) != 1 || - fwrite(&snap->color_mode, - sizeof(snap->color_mode), 1, file) != 1) { - error = "Error writing data"; - } - records++; - } - - if (!error) { - if (fclose(file)) { - error = "Unable to close file"; - } - } - - if (error) { - infobox(error, strerror(errno)); - } else { - char buf[64]; - snprintf(buf, sizeof(buf), "Wrote %d snapshots to snapshots.g2", - records); - message_line(buf); - } -} - -/**************************************************************************** - * read_snapshot - * - * VERY primitive right now - not endian or version independent, and only reads - * from "snapshots.g2" in the current directory - ****************************************************************************/ -static void read_snapshot(void) -{ - FILE *file; - snapshot_t *snap, *next_snap; - snapshot_t *new_snaps = NULL; - char *error = NULL; - int len, i, records = 0; - pid_data_t *pp; - - file = fopen("snapshots.g2", "r"); - if (file == NULL) { - error = "Unable to open snapshots.g2"; - } - - /* - * Read in the snapshots and link them together. We insert them backwards, - * but that's tolerable. If the data is in anyway not what we expect, we'll - * probably crash. Sorry. - */ - while (!error && !feof(file)) { - snap = g_malloc(sizeof(*snap)); - snap->pidvec = NULL; /* so we can free this if there's an error */ - - len = fread(&snap->geometry, sizeof(snap->geometry), 1, file); - if (len == 0) { - /* EOF */ - g_free(snap); - break; - } else { - /* insert into list straight away */ - snap->next = new_snaps; - new_snaps = snap; - } - if (len != 1) { - error = "Problem reading first item from file"; - break; - } - if (fread(&snap->show_event, sizeof(snap->show_event), 1, file) != 1) { - error = "Problem reading second item from file"; - break; - } - len = sizeof(pid_sort_t) * g_npids; - snap->pidvec = g_malloc(len); - if (fread(snap->pidvec, len, 1, file) != 1) { - error = "Problem reading third item from file"; - break; - } - if (fread(&snap->vscroll_value, - sizeof(snap->vscroll_value), 1, file) != 1 || - fread(&snap->summary_mode, - sizeof(snap->summary_mode), 1, file) != 1 || - fread(&snap->color_mode, - sizeof(snap->color_mode), 1, file) != 1) { - error = "Problem reading final items from file"; - break; - } - - /* - * Fix up the pointers from the sorted pid vector back into our pid - * data objects, by walking the linked list of pid_data_t objects for - * every one looking for a match. This is O(n^2) grossness, but in real - * life there aren't that many pids, and it seems zippy enough. - */ - for (i = 0; i < g_npids; i++) { - for (pp = g_pid_data_list; pp != NULL; pp = pp->next) { - if (pp->pid_value == snap->pidvec[i].pid_value) { - break; - } - } - if (pp != NULL) { - snap->pidvec[i].pid = pp; - } else { - error = "Snapshot file referenced unknown pids"; - break; - } - } - - records++; - } - - if (!error) { - if (fclose(file)) { - error = "Unable to close file"; - } - } - - if (error) { - /* - * Problem - clear up any detritus - */ - infobox(error, strerror(errno)); - for (snap = new_snaps; snap != NULL; snap = next_snap) { - next_snap = snap->next; - g_free(snap); - g_free(snap->pidvec); - } - } else { - /* - * Success! trash the old snapshots and replace with the new - */ - for (snap = s_snapshots; snap != NULL; snap = next_snap) { - next_snap = snap->next; - g_free(snap->pidvec); - g_free(snap); - } - - s_cursnap = s_snapshots = new_snaps; - } - - if (error) { - infobox(error, strerror(errno)); - } else { - char buf[64]; - snprintf(buf, sizeof(buf), - "Read %d snapshots from snapshots.g2", records); - message_line(buf); - } -} - -/**************************************************************************** -* set_color -* -* Set the color for the specified pid_index, or COLOR_DEFAULT to return it -* to the usual black. -****************************************************************************/ -#define COLOR_DEFAULT (-1) -static void set_color(int pid_index) -{ - if (pid_index == COLOR_DEFAULT || !color_mode) { - gdk_gc_set_foreground(da->style->black_gc, &fg_black); - } else { - gdk_gc_set_foreground(da->style->black_gc, - &s_color[g_pids[pid_index].color_index]); - } -} - -/**************************************************************************** -* toggle_event_select -****************************************************************************/ - -static void toggle_event_select(GdkEventButton *event, v1_geometry_t *vp) -{ - int pid_index, start_index; - int x, y; - GdkRectangle *rp; - GdkRectangle hit_rect; - GdkRectangle dummy; - event_t *ep; - event_def_t *edp; - char tmpbuf [1024]; - double time_per_pixel; - - if (g_nevents == 0) - return; - - time_per_pixel = dtime_per_pixel(vp); - - start_index = find_event_index (vp->minvistime); - - /* Too far right? */ - if (start_index >= g_nevents) - return; - - /* - * To see if the mouse hit a visible event, use a variant - * of the event display loop. - */ - - hit_rect.x = (int)event->x; - hit_rect.y = (int)event->y; - hit_rect.width = 1; - hit_rect.height = 1; - - ep = (g_events + start_index); - - while ((ep->time < vp->maxvistime) && - (ep < (g_events + g_nevents))) { - pid_index = ep->pid->pid_index; - - /* First filter: pid out of range */ - if ((pid_index < vp->first_pid_index) || - (pid_index >= vp->first_pid_index + vp->npids)) { - ep++; - continue; - } - - /* Second filter: event hidden */ - edp = find_event_definition (ep->code); - if (!edp->selected) { - ep++; - continue; - } - - /* - * At this point, we know that the point is at least on the - * screen. See if the mouse hit within the bounding box - */ - - /* - * $$$$ maybe keep looping until off the edge, - * maintain a "best hit", then declare that one the winner? - */ - - pid_index -= vp->first_pid_index; - - y = pid_index*vp->strip_height + vp->event_offset; - - x = vp->pid_ax_width + - (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel); - - /* Perhaps we're trying to toggle the detail box? */ - if (ep->flags & EVENT_FLAG_SELECT) { - /* Figure out the dimensions of the detail box */ - format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp); - rp = tbox(tmpbuf, x, y - vp->pop_offset, TBOX_GETRECT_BOXED); - if (gdk_rectangle_intersect(rp, &hit_rect, &dummy)) { - ep->flags &= ~EVENT_FLAG_SELECT; - view1_display_when_idle(); - break; - } - } - - sprintf(tmpbuf, "%ld", ep->code); - - /* Figure out the dimensions of the regular box */ - rp = tbox(tmpbuf, x, y, TBOX_GETRECT_EVENT); - - if (gdk_rectangle_intersect(rp, &hit_rect, &dummy)) { - /* we hit the rectangle. */ - if (ep->flags & EVENT_FLAG_SELECT) { - ep->flags &= ~EVENT_FLAG_SELECT; - view1_display_when_idle(); - break; - } else { - set_color(ep->pid->pid_index); - - /* It wasn't selected, so put up the detail box */ - format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp); - tbox(tmpbuf, x, y - vp->pop_offset, TBOX_DRAW_BOXED); - line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK); - ep->flags |= EVENT_FLAG_SELECT; - ep->flags &= ~EVENT_FLAG_SEARCHRSLT; - s_last_selected_event = ep; - } - break; - } - ep++; - } -} - -/**************************************************************************** -* move_current_track -****************************************************************************/ - -typedef enum { MOVE_TOP, MOVE_BOTTOM } move_type; - -static void move_current_track(GdkEventButton *event, - v1_geometry_t *vp, - move_type type) -{ - int i; - int pid_index; - int y, delta_y; - pid_sort_t *new_pidvec; - pid_sort_t *psp; - pid_sort_t *pold, *pnew; - pid_data_t *pp; - - if (g_nevents == 0) - return; - - /* Scan pid/track axis locations, looking for a match */ - for (i = 0; i < vp->npids; i++) { - y = i*vp->strip_height + vp->pid_ax_offset; - delta_y = y - event->y; - if (delta_y < 0) - delta_y = -delta_y; - if (delta_y < 10) { - goto found; - } - - } - infobox("NOTE", "\nNo PID/Track In Range\nPlease Try Again"); - return; - - found: - pid_index = i + vp->first_pid_index; - - new_pidvec = g_malloc(sizeof(pid_sort_t)*g_npids); - pold = g_pids; - pnew = new_pidvec; - - if (type == MOVE_TOP) { - /* move to top */ - *pnew++ = g_pids[pid_index]; - for (i = 0; i < pid_index; i++) - *pnew++ = *pold++; - pold++; - i++; - for (; i < g_npids; i++) - *pnew++ = *pold++; - } else { - /* move to bottom */ - for (i = 0; i < pid_index; i++) - *pnew++ = *pold++; - pold++; - i++; - for (; i < g_npids; i++) - *pnew++ = *pold++; - *pnew = g_pids[pid_index]; - } - - g_free(g_pids); - g_pids = new_pidvec; - - /* - * Revert the pid_index mapping to an identity map, - */ - psp = g_pids; - - for (i = 0; i < g_npids; i++) { - pp = psp->pid; - pp->pid_index = i; - psp++; - } - view1_display_when_idle(); -} - -/**************************************************************************** -* zoom_event -* Process a zoom gesture. The use of doubles is required to avoid -* truncating the various variable values, which in turn would lead to -* some pretty random-looking zoom responses. -****************************************************************************/ - -void zoom_event(GdkEventButton *e1, GdkEventButton *e2, v1_geometry_t *vp) -{ - double xrange; - double time_per_pixel; - double width_in_pixels; - double center_on_time, width_in_time; - double center_on_pixel; - - /* - * Clip the zoom area to the event display area. - * Otherwise, center_on_time - width_in_time is in hyperspace - * to the left of zero - */ - - if (e1->x < vp->pid_ax_width) - e1->x = vp->pid_ax_width; - - if (e2->x < vp->pid_ax_width) - e2->x = vp->pid_ax_width; - - if (e2->x == e1->x) - goto loser_zoom_repaint; - - xrange = (double) (e2->x - e1->x); - if (xrange < 0.00) - xrange = -xrange; - - /* Actually, width in pixels of half the zoom area */ - width_in_pixels = xrange / 2.00; - time_per_pixel = dtime_per_pixel(vp); - width_in_time = width_in_pixels * time_per_pixel; - - /* Center the screen on the center of the zoom area */ - center_on_pixel = (double)((e2->x + e1->x) / 2.00) - - (double)vp->pid_ax_width; - center_on_time = center_on_pixel*time_per_pixel + (double)vp->minvistime; - - /* - * Transform back to 64-bit integer microseconds, reset the - * scrollbar, schedule a repaint. - */ - vp->minvistime = (ulonglong)(center_on_time - width_in_time); - vp->maxvistime = (ulonglong)(center_on_time + width_in_time); - -loser_zoom_repaint: - recompute_hscrollbar(); - - view1_display_when_idle(); -} - -/**************************************************************************** -* scroll_y -* -* Scroll up or down by the specified delta -* -****************************************************************************/ -static void scroll_y(int delta) -{ - int new_index = s_v1->first_pid_index + delta; - if (new_index + s_v1->npids > g_npids) - new_index = g_npids - s_v1->npids; - if (new_index < 0) - new_index = 0; - - if (new_index != s_v1->first_pid_index) { - s_v1->first_pid_index = new_index; - GTK_ADJUSTMENT(s_view1_vsadj)->value = (gdouble)new_index; - gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); - view1_display_when_idle(); - } -} - -/**************************************************************************** -* view1_handle_key_press_event -* Relevant definitions in: /usr/include/gtk-1.2/gdk/gdktypes.h -* -* This routine implements hotkeys for the Quake generation: -* -* W - zoom in -* S - zoom out -* A - pan left -* D - pan right -* R - pan up -* F - pan down -* T - more traces -* G - fewer traces -* -* E - toggle summary mode -* C - toggle color mode -* -* X - take snapshot -* Z - next snapshot -* P - persist snapshots to file -* L - load snapshots from file -* -* ctrl-Q - exit -* -****************************************************************************/ -gint -view1_handle_key_press_event (GtkWidget *widget, GdkEventKey *event) -{ - long long delta; - - switch (event->keyval) { - case GDK_w: // zoom in - view1_button_click_callback(NULL, (gpointer)ZOOMIN_BUTTON); - break; - - case GDK_s: // zoom out - view1_button_click_callback(NULL, (gpointer)ZOOMOUT_BUTTON); - break; - - case GDK_a: // pan left - delta = (s_v1->maxvistime - s_v1->minvistime) / 6; - if (s_v1->minvistime < delta) { - delta = s_v1->minvistime; - } - s_v1->minvistime -= delta; - s_v1->maxvistime -= delta; - recompute_hscrollbar(); - break; - - case GDK_d: // pan right - delta = (s_v1->maxvistime - s_v1->minvistime) / 6; - if (s_v1->maxvistime + delta > g_events[g_nevents - 1].time) { - /* - * @@@ this doesn't seem to quite reach the far right hand - * side correctly - not sure why. - */ - delta = g_events[g_nevents - 1].time - s_v1->maxvistime; - } - s_v1->minvistime += delta; - s_v1->maxvistime += delta; - recompute_hscrollbar(); - break; - - case GDK_r: // pan up - scroll_y(-1); - break; - - case GDK_f: // pan down - scroll_y(+1); - break; - - case GDK_t: // fewer tracks - view1_button_click_callback(NULL, (gpointer)LESS_TRACES_BUTTON); - break; - - case GDK_g: // more tracks - view1_button_click_callback(NULL, (gpointer)MORE_TRACES_BUTTON); - break; - - case GDK_e: // toggle summary mode - view1_button_click_callback - (NULL, (gpointer)(unsigned long long) - (summary_mode ? NOSUMMARY_BUTTON : SUMMARY_BUTTON)); - break; - - case GDK_c: // toggle color mode - color_mode ^= 1; - view1_display_when_idle(); - break; - - case GDK_p: // persist snapshots - write_snapshot(); - break; - - case GDK_l: // load snapshots - read_snapshot(); - break; - - case GDK_x: // take snapshot - view1_button_click_callback(NULL, (gpointer)SNAP_BUTTON); - break; - - case GDK_z: // next snapshot - view1_button_click_callback(NULL, (gpointer)NEXT_BUTTON); - break; - - case GDK_q: // ctrl-q is exit - if (event->state & GDK_CONTROL_MASK) { - gtk_main_quit(); - } - break; - } - return TRUE; -} - -/**************************************************************************** -* button_press_event -* Relevant definitions in: /usr/include/gtk-1.2/gdk/gdktypes.h -* -* This routine implements three functions: zoom-to-area, time ruler, and -* show/hide event detail popup. -* -* The left mouse button (button 1) has two simultaneous functions: event -* detail popup, and zoom-to-area. If the press and release events occur -* within a small delta-x, it's a detail popup event. Otherwise, it's -* an area zoom. -* -* The right mouse button (button 3) implements the time ruler. -****************************************************************************/ - -static gint -button_press_event (GtkWidget *widget, GdkEventButton *event) -{ - static GdkEventButton press1_event; - static boolean press1_valid; - static GdkEventButton press3_event; - static guint32 last_truler_time; - static boolean press3_valid; - static boolean zoom_bar_up; - int time_ax_y, xdelta; - char tmpbuf [128]; - double time_per_pixel; - - time_ax_y = 0; - - switch(event->type) { - case GDK_BUTTON_PRESS: - /* Capture the appropriate starting point */ - if (event->button == 1) { - press1_valid = TRUE; - press1_event = *event; - return(TRUE); - } - if (event->button == 3) { - press3_valid = TRUE; - press3_event = *event; - return(TRUE); - } - return(TRUE); - - case GDK_BUTTON_RELEASE: - /* Time ruler */ - if (press3_valid) { - press3_valid = FALSE; - /* Fix the cursor, and repaint the screen from scratch */ - gdk_window_set_cursor (da->window, norm_cursor); - view1_display_when_idle(); - return(TRUE); - } - /* Event select / zoom-to-area */ - if (press1_valid) { - press1_valid = FALSE; - xdelta = (int)(press1_event.x - event->x); - if (xdelta < 0) - xdelta = -xdelta; - - /* is the mouse more or less where it started? */ - if (xdelta < 10) { - /* Control-left-mouse => sink the track */ - /* Shift-left-mouse => raise the track */ - if ((press1_event.state & GDK_CONTROL_MASK) == - GDK_CONTROL_MASK) { - move_current_track(event, s_v1, MOVE_BOTTOM); - } else if ((press1_event.state & GDK_SHIFT_MASK) == - GDK_SHIFT_MASK) { - move_current_track(event, s_v1, MOVE_TOP); - } else { - /* No modifiers: toggle the event */ - toggle_event_select(event, s_v1); - } - /* Repaint to get rid of the zoom bar */ - if (zoom_bar_up) { - /* Fix the cursor and leave. No zoom */ - gdk_window_set_cursor (da->window, norm_cursor); - zoom_bar_up = FALSE; - break; - } - } else { /* mouse moved enough to zoom */ - zoom_event(&press1_event, event, s_v1); - gdk_window_set_cursor (da->window, norm_cursor); - zoom_bar_up = FALSE; - } - } else if (event->button == 4) { - /* scroll wheel up */ - scroll_y(event->state & GDK_SHIFT_MASK ? -10 : -1); - } else if (event->button == 5) { - /* scroll wheel down */ - scroll_y(event->state & GDK_SHIFT_MASK ? +10 : +1); - } - return(TRUE); - - case GDK_MOTION_NOTIFY: - /* Button one followed by motion: draw zoom fence and fix cursor */ - if (press1_valid) { - /* Fence, cursor already set */ - if (zoom_bar_up) - return(TRUE); - - xdelta = (int)(press1_event.x - event->x); - if (xdelta < 0) - xdelta = -xdelta; - - /* Haven't moved enough to declare a zoom sequence yet */ - if (xdelta < 10) - return(TRUE); - - /* Draw the zoom fence, use the key-down X coordinate */ - time_ax_y = s_v1->npids * s_v1->strip_height + s_v1->pid_ax_offset; - - line((int)(press1_event.x), s_v1->pop_offset, - (int)(press1_event.x), time_ax_y, LINE_DRAW_BLACK); - tbox("Zoom From Here...", (int)(press1_event.x), s_v1->pop_offset, - TBOX_DRAW_BOXED); - gdk_window_set_cursor(da->window, zi_cursor); - zoom_bar_up = TRUE; - return(TRUE); - } - if (press3_valid) { - double nsec; - - gdk_window_set_cursor(da->window, zi_cursor); - - /* - * Some filtration is needed on Solaris, or the server will hang - */ - if (event->time - last_truler_time < 75) - return(TRUE); - - last_truler_time = event->time; - - line((int)(press3_event.x), s_v1->pop_offset, - (int)(press3_event.x), time_ax_y, LINE_DRAW_BLACK); - - xdelta = (int)(press3_event.x - event->x); - if (xdelta < 0) - xdelta = -xdelta; - - time_per_pixel = ((double)(s_v1->maxvistime - s_v1->minvistime)) / - ((double)(s_v1->total_width - s_v1->pid_ax_width)); - - time_ax_y = s_v1->npids * s_v1->strip_height + s_v1->pid_ax_offset; - - line((int)(press3_event.x), s_v1->pop_offset, - (int)(press3_event.x), time_ax_y, LINE_DRAW_BLACK); - /* - * Note: use a fixed-width format so it looks like we're - * erasing and redrawing the box. - */ - nsec = ((double)xdelta)*time_per_pixel; - if (nsec >1e9) { - sprintf(tmpbuf, "%8.3f sec ", nsec/1e9); - } else if (nsec > 1e6) { - sprintf(tmpbuf, "%8.3f msec", nsec/1e6); - } else if (nsec > 1e3) { - sprintf(tmpbuf, "%8.3f usec", nsec/1e3); - } else { - sprintf(tmpbuf, "%8.0f nsec", nsec); - } - tbox(tmpbuf, (int)(press3_event.x), s_v1->pop_offset, - TBOX_DRAW_BOXED); - return(TRUE); - } - - default: - break; -#ifdef DEBUG - g_print("button:\ttype = %d\n", event->type); - g_print("\twindow = 0x%x\n", event->window); - g_print("\tsend_event = %d\n", event->send_event); - g_print("\ttime = %d\n", event->time); - g_print("\tx = %6.2f\n", event->x); - g_print("\ty = %6.2f\n", event->y); - g_print("\tpressure = %6.2f\n", event->pressure); - g_print("\txtilt = %6.2f\n", event->xtilt); - g_print("\tytilt = %6.2f\n", event->ytilt); - g_print("\tstate = %d\n", event->state); - g_print("\tbutton = %d\n", event->button); - g_print("\tsource = %d\n", event->source); - g_print("\tdeviceid = %d\n", event->deviceid); - g_print("\tx_root = %6.2f\n", event->x_root); - g_print("\ty_root = %6.2f\n", event->y_root); - return(TRUE); -#endif - } - - view1_display_when_idle(); - - return(TRUE); -} - -/**************************************************************************** -* configure_event -* Happens when the window manager resizes the viewer's main window. -****************************************************************************/ - -static gint -configure_event (GtkWidget *widget, GdkEventConfigure *event) -{ - /* Toss the previous drawing area backing store pixmap */ - if (pm) - gdk_pixmap_unref(pm); - - /* Create a new pixmap, paint it */ - pm = gdk_pixmap_new(widget->window, - widget->allocation.width, - widget->allocation.height, - -1); - gdk_draw_rectangle (pm, - widget->style->white_gc, - TRUE, - 0, 0, - widget->allocation.width, - widget->allocation.height); - - /* Reset the view geometry parameters, as required */ - s_v1->total_width = widget->allocation.width; - s_v1->total_height = widget->allocation.height; - s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) / - s_v1->strip_height; - - /* Schedule a repaint */ - view1_display_when_idle(); - return(TRUE); -} - -/**************************************************************************** -* expose_event -* Use backing store to fix the screen. -****************************************************************************/ -static gint expose_event (GtkWidget *widget, GdkEventExpose *event) -{ - gdk_draw_pixmap(widget->window, - widget->style->fg_gc[GTK_WIDGET_STATE (widget)], - pm, - event->area.x, event->area.y, - event->area.x, event->area.y, - event->area.width, event->area.height); - - return(FALSE); -} - -/**************************************************************************** -* event_search_internal -* This routine searches forward from s_srchindex, looking for s_srchcode; -* wraps at the end of the buffer. -****************************************************************************/ - -boolean event_search_internal (void) -{ - event_t *ep; - int i; - int index; - int pid_index; - boolean full_redisplay = FALSE; - ulonglong current_width; - char tmpbuf [64]; - - /* No events yet? Act like the search worked, to avoid a loop */ - if (g_nevents == 0) - return(TRUE); - - ep = (g_events + s_srchindex); - ep->flags &= ~EVENT_FLAG_SEARCHRSLT; - - /* - * Assume the user wants to search [plus or minus] - * from where they are. - */ -#ifdef notdef - if (ep->time < s_v1->minvistime) - s_srchindex = find_event_index (s_v1->minvistime); -#endif - - for (i = 1; i <= g_nevents; i++) { - index = (srch_chase_dir == SRCH_CHASE_BACKWARD) ? - (s_srchindex - i) % g_nevents : - (i + s_srchindex) % g_nevents; - - ep = (g_events + index); - - if (ep->code == s_srchcode) { - if (s_srchfail_up) - message_line(""); - s_srchindex = index; - pid_index = ep->pid->pid_index; - - /* Need a vertical scroll? */ - if ((pid_index < s_v1->first_pid_index) || - (pid_index >= s_v1->first_pid_index + s_v1->npids)) { - if (pid_index > (g_npids - s_v1->npids)) - pid_index = (g_npids - s_v1->npids); - s_v1->first_pid_index = pid_index; - GTK_ADJUSTMENT(s_view1_vsadj)->value = - (gdouble)s_v1->first_pid_index; - gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); - full_redisplay = TRUE; - } - - /* Need a horizontal scroll? */ - if (ep->time < s_v1->minvistime || ep->time > s_v1->maxvistime) { - current_width = (s_v1->maxvistime - s_v1->minvistime); - if (ep->time < ((current_width+1) / 2)) { - s_v1->minvistime = 0ll; - s_v1->maxvistime = current_width; - } else { - s_v1->minvistime = ep->time - ((current_width+1)/2); - s_v1->maxvistime = ep->time + ((current_width+1)/2); - } - recompute_hscrollbar(); - full_redisplay = TRUE; - } - ep->flags |= EVENT_FLAG_SEARCHRSLT; - full_redisplay = TRUE; - -#ifdef NOTDEF - if (!full_redisplay){ - if (!s_result_up) { - s_result_up = TRUE; - time_per_pixel = dtime_per_pixel(s_v1); - - y = pid_index*s_v1->strip_height + s_v1->event_offset; - x = s_v1->pid_ax_width + - (int)(((double)(ep->time - s_v1->minvistime)) / - time_per_pixel); - sprintf(tmpbuf, "SEARCH RESULT"); - tbox(tmpbuf, x, y - s_v1->pop_offset, TBOX_DRAW_BOXED); - line(x, y-s_v1->pop_offset, x, y, LINE_DRAW_BLACK); - } else { - full_redisplay = TRUE; - } - } -#endif - - if (full_redisplay) - view1_display_when_idle(); - return(TRUE); - } - } - sprintf (tmpbuf, "Search for event %ld failed...\n", s_srchcode); - message_line(tmpbuf); - s_srchfail_up = TRUE; - return(TRUE); -} - -/**************************************************************************** -* event_search_callback -****************************************************************************/ - -boolean event_search_callback (char *s) -{ - /* No events yet? Act like the search worked, to avoid a loop */ - if (g_nevents == 0) - return(TRUE); - - s_srchcode = atol(s); - - if (s_srchcode == 0) - return(FALSE); - - return(event_search_internal()); -} - -/**************************************************************************** -* event_search -****************************************************************************/ - -static void event_search (void) -{ - modal_dialog ("Event Search: Please Enter Event Code", - "Invalid: Please Reenter Event Code", NULL, - event_search_callback); -} - -/**************************************************************************** -* init_track_colors -****************************************************************************/ -static void init_track_colors(void) -{ - int i; - unsigned hash; - char *label_char; - unsigned RGB[3]; - gboolean dont_care[g_npids]; - - /* - * If we've already allocated the colors once, then in theory we should - * just be able to re-order the GCs already created to match the new track - * order; the track -> color mapping doesn't currently change at runtime. - * However, it's easier just to allocate everything from fresh. As a nod in - * the direction of politeness towards our poor abused X server, we at - * least mop up the previously allocated GCs first, although in practice - * even omitting this didn't seem to cause a problem. - */ - if (s_color != NULL ) { - gdk_colormap_free_colors(gtk_widget_get_colormap(da), - s_color, g_npids); - memset(s_color, 0, sizeof(GdkColor) * g_npids); - } else { - /* - * First time through: allocate the array to hold the GCs. - */ - s_color = g_malloc(sizeof(GdkColor) * g_npids); - } - - /* - * Go through and assign a color for each track. - */ - for (i = 0; i < g_npids; i++) { - /* - * We compute the color from a hash of the thread name. That way we get - * a distribution of different colors, and the same thread has the same - * color across multiple data sets. Unfortunately, even though the - * process name and thread id are invariant across data sets, the - * process id isn't, so we want to exclude that from the hash. Since - * the pid appears in parentheses after the process name and tid, we - * can just stop at the '(' character. - * - * We could create a substring and use the CLIB Jenkins hash, but given - * we're hashing ascii data, a suitable Bernstein hash is pretty much - * just as good, and it's easiest just to compute it inline. - */ - label_char = get_track_label(g_pids[i].pid_value); - hash = 0; - while (*label_char != '\0' && *label_char != '(') { - hash = hash * 33 + *label_char++; - } - hash += hash >> 5; /* even out the lower order bits a touch */ - - /* - * OK, now we have our hash. We get the color by using the first three - * bytes of the hash for the RGB values (expanded from 8 to 16 bits), - * and then use the fourth byte to choose one of R, G, B and mask this - * one down. This ensures the color can't be too close to white and - * therefore hard to see. - * - * We also drop the top bit of the green, since bright green on its own - * is hard to see against white. Generally we err on the side of - * keeping it dark, rather than using the full spectrum of colors. This - * does result in something of a preponderance of muddy colors and a - * bit of a lack of cheery bright ones, but at least you can read - * everything. It would be nice to do better. - */ - RGB[0] = (hash & 0xff000000) >> 16; - RGB[1] = (hash & 0x007f0000) >> 8; - RGB[2] = (hash & 0x0000ff00); - RGB[hash % 3] &= 0x1fff; - - { - GdkColor color = {0, RGB[0], RGB[1], RGB[2]}; - s_color[i] = color; - g_pids[i].color_index = i; - } - } - - /* - * Actually allocate the colors in one bulk operation. We ignore the return - * values. - */ - gdk_colormap_alloc_colors(gtk_widget_get_colormap(da), - s_color, g_npids, FALSE, TRUE, dont_care); -} - - -/**************************************************************************** -* chase_event_etc -* Reorder the pid_index fields so the viewer "chases" the last selected -* event. -****************************************************************************/ - -static void chase_event_etc(enum chase_mode mode) -{ - pid_sort_t *psp, *new_pidvec; - pid_data_t *pp; - event_t *ep; - int pids_mapped; - ulong code_to_chase; - ulong datum_to_chase; - ulong pid_to_chase; - int i; - int winner; - - if (!s_last_selected_event) { - infobox("No selected event", - "\nPlease select an event and try again...\n"); - return; - } - - /* Clear all index assignments */ - psp = g_pids; - for (i = 0; i < g_npids; i++) { - pp = psp->pid; - pp->pid_index = 0xFFFFFFFF; - psp++; - } - - ep = s_last_selected_event; - code_to_chase = ep->code; - datum_to_chase = ep->datum; - pid_to_chase = ep->pid->pid_value; - pids_mapped = 0; - new_pidvec = g_malloc(sizeof(pid_sort_t)*g_npids); - - while (1) { - if (srch_chase_dir == SRCH_CHASE_FORWARD) { - if (ep >= g_events + g_nevents) - break; - } else { - if (ep < g_events) - break; - } - - winner = 0; - switch(mode) { - case CHASE_EVENT: - if (ep->code == code_to_chase) { - winner = 1; - } - break; - - case CHASE_DATUM: - if (ep->datum == datum_to_chase) { - winner = 1; - } - break; - - case CHASE_TRACK: - if (ep->pid->pid_value == pid_to_chase) { - winner = 1; - } - break; - - default: - infobox("BUG", "unknown mode in chase_event_etc\n"); - break; - } - - if (winner) { - if (ep->pid->pid_index == 0xFFFFFFFF) { - ep->pid->pid_index = pids_mapped; - new_pidvec[pids_mapped].pid = ep->pid; - new_pidvec[pids_mapped].pid_value = ep->pid->pid_value; - new_pidvec[pids_mapped].color_index = 0; - pids_mapped++; - if (pids_mapped == g_npids) - break; - } - } - if (srch_chase_dir == SRCH_CHASE_FORWARD) - ep++; - else - ep--; - } - - /* Pass 2, first-to-last, to collect stragglers */ - ep = g_events; - - while (ep < g_events + g_nevents) { - if (ep->pid->pid_index == 0xFFFFFFFF) { - ep->pid->pid_index = pids_mapped; - new_pidvec[pids_mapped].pid = ep->pid; - new_pidvec[pids_mapped].pid_value = ep->pid->pid_value; - new_pidvec[pids_mapped].color_index = 0; - pids_mapped++; - if (pids_mapped == g_npids) - break; - } - ep++; - } - - if (pids_mapped != g_npids) { - infobox("BUG", "\nDidn't map all pids in chase_event_etc\n"); - } - - g_free (g_pids); - g_pids = new_pidvec; - - /* - * The new g_pids vector contains the "chase" sort, so we revert - * the pid_index mapping to an identity map - */ - psp = g_pids; - - for (i = 0; i < g_npids; i++) { - pp = psp->pid; - pp->pid_index = i; - psp++; - } - - /* AutoScroll the PID axis so we show the first "chased" event */ - s_v1->first_pid_index = 0; - GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00; - gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); - init_track_colors(); - view1_display_when_idle(); -} - -/**************************************************************************** -* unchase_event_etc -* Copy g_original_pids to g_pids, revert index mapping -****************************************************************************/ -static void unchase_event_etc(void) -{ - int i; - pid_sort_t *psp; - pid_data_t *pp; - - memcpy (g_pids, g_original_pids, sizeof(pid_sort_t)*g_npids); - - /* Fix the pid structure index mappings */ - psp = g_pids; - - for (i = 0; i < g_npids; i++) { - pp = psp->pid; - pp->pid_index = i; - psp++; - } - - /* Scroll PID axis to the top */ - s_v1->first_pid_index = 0; - GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00; - gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); - init_track_colors(); - view1_display_when_idle(); -} - -/**************************************************************************** -* print_ps_header -* To fit a reasonable-sized landscape mode plot onto letter-size paper, -* scale everything by .75. -****************************************************************************/ - -static void print_ps_header (v1_geometry_t *vp, char *filename) -{ - time_t now; - - now = time(0); - - fprintf(s_printfp, "%%%%!PS-Adobe-3.0 EPSF-3.0\n"); - fprintf(s_printfp, "%%%%Creator: G2 Event Viewer\n"); - fprintf(s_printfp, "%%%%Title: %s\n", filename); - fprintf(s_printfp, "%%%%CreationDate: %s", ctime(&now)); - fprintf(s_printfp, "%%%%DocumentData: Clean7Bit\n"); - fprintf(s_printfp, "%%%%Origin: 0 0\n"); - fprintf(s_printfp, "%%%%BoundingBox: 0 0 %d %d\n", vp->total_height, - vp->total_width); - fprintf(s_printfp, "%%%%LanguageLevel: 2\n"); - fprintf(s_printfp, "%%%%Pages: 1\n"); - fprintf(s_printfp, "%%%%Page: 1 1\n"); - fprintf(s_printfp, "%%%%EOF\n"); - fprintf(s_printfp, "/Times-Roman findfont\n"); - fprintf(s_printfp, "12 scalefont\n"); - fprintf(s_printfp, "setfont\n"); - fprintf(s_printfp, ".75 .75 scale\n"); -} - -/**************************************************************************** -* xrt -* Xcoordinate rotate and translate. We need to emit postscript that -* has a reasonable aspect ratio for printing. To do that, we rotate the -* intended picture by 90 degrees, using the standard 2D rotation -* formula: -* -* Xr = x*cos(theta) - y*sin(theta); -* Yr = x*sin(theta) + y*cos(theta); -* -* If we let theta = 90, this reduces to -* Xr = -y -* Yr = x -* -* Translate back to the origin in X by adding Ymax, yielding -* Xrt = Ymax - y -****************************************************************************/ - -static inline int xrt(int x, int y) -{ - return (s_v1->total_height - y); -} - -static inline int yrt(int x, int y) -{ - return(x); -} - -/**************************************************************************** -* print_screen_callback -****************************************************************************/ - -static boolean print_screen_callback(char *filename) -{ - s_printfp = fopen (filename, "wt"); - - if (s_printfp == NULL) - return(FALSE); - - /* - * This variable allows us to magically turn the view1 display - * code into a print-driver, with a minimum of fuss. The idea is to - * magically change TBOX_DRAW_XXX into TBOX_PRINT_XXX by adding - * the required value, aka s_print_offset. - * Make sure to fix g2.h if you mess here, or vice versa. - */ - s_print_offset = TBOX_PRINT_PLAIN - TBOX_DRAW_PLAIN; - - print_ps_header(s_v1, filename); - - display_pid_axis(s_v1); - display_event_data(s_v1); - display_time_axis(s_v1); - - fclose (s_printfp); - s_printfp = 0; - s_print_offset = 0; - - /* For tactile feedback */ - view1_display_when_idle(); - return(TRUE); -} - -/**************************************************************************** -* view1_button_click_callback -****************************************************************************/ - -static void view1_button_click_callback(GtkButton *item, gpointer data) -{ - enum view1_button_click click = (enum view1_button_click) data; - event_t *ep; - ulonglong event_incdec; - ulonglong current_width; - ulonglong zoom_delta; - - - current_width = s_v1->maxvistime - s_v1->minvistime; - event_incdec = (current_width) / 3; - - if (event_incdec == 0LL) - event_incdec = 1; - - zoom_delta = (s_v1->maxvistime - s_v1->minvistime) / 6; - - switch(click) { - case TOP_BUTTON: - /* First PID to top of window */ - s_v1->first_pid_index = 0; - GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00; - gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); - break; - - case BOTTOM_BUTTON: - s_v1->first_pid_index = g_npids - s_v1->npids; - if (s_v1->first_pid_index < 0) - s_v1->first_pid_index = 0; - GTK_ADJUSTMENT(s_view1_vsadj)->value = (gdouble)s_v1->first_pid_index; - gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); - break; - - case SNAP_BUTTON: - add_snapshot(); - break; - - case NEXT_BUTTON: - next_snapshot(); - break; - - case DEL_BUTTON: - del_snapshot(); - break; - - case CHASE_EVENT_BUTTON: - chase_event_etc(CHASE_EVENT); - break; - - case CHASE_DATUM_BUTTON: - chase_event_etc(CHASE_DATUM); - break; - - case CHASE_TRACK_BUTTON: - chase_event_etc(CHASE_TRACK); - break; - - case UNCHASE_BUTTON: - unchase_event_etc(); - break; - - case START_BUTTON: - start_button: - s_v1->minvistime = 0LL; - s_v1->maxvistime = current_width; - recompute_hscrollbar(); - break; - - case ZOOMIN_BUTTON: - s_v1->minvistime += zoom_delta; - s_v1->maxvistime -= zoom_delta; - recompute_hscrollbar(); - break; - - case SEARCH_AGAIN_BUTTON: - if (s_srchcode) { - event_search_internal(); - break; - } - /* NOTE FALLTHROUGH */ - - case SEARCH_BUTTON: - event_search(); - break; - - case ZOOMOUT_BUTTON: - if (zoom_delta == 0LL) - zoom_delta = 1; - - if (s_v1->minvistime >= zoom_delta) { - s_v1->minvistime -= zoom_delta; - s_v1->maxvistime += zoom_delta; - } else { - s_v1->minvistime = 0; - s_v1->maxvistime += zoom_delta*2; - } - - if ((s_v1->maxvistime - s_v1->minvistime) * 8 > - g_events[g_nevents-1].time * 9) { - s_v1->minvistime = 0; - s_v1->maxvistime = g_events[g_nevents-1].time * 9 / 8; - } - recompute_hscrollbar(); - break; - - case END_BUTTON: - ep = (g_events + g_nevents - 1); - s_v1->maxvistime = ep->time + event_incdec/3; - s_v1->minvistime = s_v1->maxvistime - current_width; - if (s_v1->minvistime > s_v1->maxvistime) - goto start_button; - recompute_hscrollbar(); - break; - - case MORE_TRACES_BUTTON: - /* Reduce the strip height to fit more traces on screen */ - s_v1->strip_height -= 1; - - if (s_v1->strip_height < 1) { - s_v1->strip_height = 1; - } - - /* Recalculate the number of strips on the screen */ - s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) / - s_v1->strip_height; - recompute_vscrollbar(); - break; - - case LESS_TRACES_BUTTON: - /* Increase the strip height to fit fewer on the screen */ - s_v1->strip_height += 1; - if (s_v1->strip_height > 80) { - s_v1->strip_height = 80; - } - - /* Recalculate the number of strips on the screen */ - s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) / - s_v1->strip_height; - recompute_vscrollbar(); - break; - - case FORWARD_BUTTON: - srch_chase_dir = SRCH_CHASE_FORWARD; - gtk_widget_hide (s_view1_forward_button); - gtk_widget_show (s_view1_backward_button); - break; - - case BACKWARD_BUTTON: - srch_chase_dir = SRCH_CHASE_BACKWARD; - gtk_widget_show (s_view1_forward_button); - gtk_widget_hide (s_view1_backward_button); - break; - - case SUMMARY_BUTTON: - summary_mode = TRUE; - gtk_widget_hide (s_view1_summary_button); - gtk_widget_show (s_view1_nosummary_button); - break; - - case NOSUMMARY_BUTTON: - summary_mode = FALSE; - gtk_widget_show (s_view1_summary_button); - gtk_widget_hide (s_view1_nosummary_button); - break; - } - - view1_display_when_idle(); -} - -/**************************************************************************** -* view1_print_callback -****************************************************************************/ - -void view1_print_callback (GtkToggleButton *notused, gpointer nu2) -{ - modal_dialog("Print Screen (PostScript format) to file:", - "Invalid file: Print Screen to file:", - "g2.ps", print_screen_callback); -} - -/**************************************************************************** -* view1_hscroll -****************************************************************************/ - -static void view1_hscroll (GtkAdjustment *adj, GtkWidget *notused) -{ - ulonglong current_width; - - current_width = (s_v1->maxvistime - s_v1->minvistime); - - s_v1->minvistime = (ulonglong)(adj->value); - s_v1->maxvistime = s_v1->minvistime + current_width; - - view1_display_when_idle(); - -#ifdef NOTDEF - g_print ("adj->lower = %.2f\n", adj->lower); - g_print ("adj->upper = %.2f\n", adj->upper); - g_print ("adj->value = %.2f\n", adj->value); - g_print ("adj->step_increment = %.2f\n", adj->step_increment); - g_print ("adj->page_increment = %.2f\n", adj->page_increment); - g_print ("adj->page_size = %.2f\n", adj->page_size); -#endif -} - -/**************************************************************************** -* view1_vscroll -****************************************************************************/ - -static void view1_vscroll (GtkAdjustment *adj, GtkWidget *notused) -{ - s_v1->first_pid_index = (int)adj->value; - view1_display_when_idle(); -} - -void set_pid_ax_width(int width) -{ - s_v1->pid_ax_width = width; - view1_display_when_idle(); -} - -/**************************************************************************** -* view1_init -****************************************************************************/ - -void view1_init(void) -{ - - c_view1_draw_width = atol(getprop_default("drawbox_width", "700")); - c_view1_draw_height = atol(getprop_default("drawbox_height", "400")); - - s_v1->pid_ax_width = 80; - s_v1->time_ax_height = 80; - s_v1->time_ax_spacing = 100; - s_v1->strip_height = 25; - s_v1->pop_offset = 20; - s_v1->pid_ax_offset = 34; - s_v1->event_offset = 40; - s_v1->total_height = c_view1_draw_height; - s_v1->total_width = c_view1_draw_width; - s_v1->first_pid_index = 0; - - s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) / - s_v1->strip_height; - - s_v1->minvistime = 0; - s_v1->maxvistime = 200; - - s_view1_vbox = gtk_vbox_new(FALSE, 5); - - s_view1_hbox = gtk_hbox_new(FALSE, 5); - - da = gtk_drawing_area_new(); - gtk_drawing_area_size(GTK_DRAWING_AREA(da), c_view1_draw_width, - c_view1_draw_height); - -#ifdef NOTDEF - gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event", - (GtkSignalFunc) motion_notify_event, NULL); -#endif - - gtk_signal_connect (GTK_OBJECT (da), "expose_event", - (GtkSignalFunc) expose_event, NULL); - - gtk_signal_connect (GTK_OBJECT(da),"configure_event", - (GtkSignalFunc) configure_event, NULL); - - gtk_signal_connect (GTK_OBJECT (da), "button_press_event", - (GtkSignalFunc) button_press_event, NULL); - - gtk_signal_connect (GTK_OBJECT (da), "button_release_event", - (GtkSignalFunc) button_press_event, NULL); - - gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event", - (GtkSignalFunc) button_press_event, NULL); - - gtk_widget_set_events (da, GDK_BUTTON_PRESS_MASK - | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK - | GDK_BUTTON_MOTION_MASK); - - - gtk_box_pack_start(GTK_BOX(s_view1_hbox), da, TRUE, TRUE, 0); - - g_font = gdk_font_load ("8x13"); - if (g_font == NULL) { - g_error("Couldn't load 8x13 font...\n"); - } - gdk_font_ref(g_font); - - /* PID axis menu */ - s_view1_vmenubox = gtk_vbox_new(FALSE, 5); - - s_view1_vsadj = gtk_adjustment_new(0.0 /* initial value */, - 0.0 /* minimum value */, - 2000.0 /* maximum value */, - 0.1 /* step increment */, - 10.0/* page increment */, - 10.0/* page size */); - - s_view1_vscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT(s_view1_vsadj)); - - gtk_signal_connect (GTK_OBJECT (s_view1_vsadj), "value-changed", - GTK_SIGNAL_FUNC (view1_vscroll), - (gpointer)s_view1_vscroll); - - s_view1_topbutton = gtk_button_new_with_label("Top"); - s_view1_bottombutton = gtk_button_new_with_label("Bottom"); - - gtk_signal_connect (GTK_OBJECT(s_view1_topbutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) TOP_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_bottombutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) BOTTOM_BUTTON); - - /* More Traces button and Less Traces button */ - s_view1_more_traces_button = gtk_button_new_with_label("More Traces"); - s_view1_less_traces_button = gtk_button_new_with_label("Less Traces"); - gtk_signal_connect (GTK_OBJECT(s_view1_more_traces_button), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) MORE_TRACES_BUTTON); - gtk_signal_connect (GTK_OBJECT(s_view1_less_traces_button), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) LESS_TRACES_BUTTON); - -#ifdef NOTDEF - /* Trick to bottom-justify the menu: */ - s_view1_pad1 = gtk_vbox_new(FALSE, 0); - gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_pad1, - TRUE, FALSE, 0); - -#endif - - gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_topbutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_vscroll, - TRUE, TRUE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_bottombutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_more_traces_button, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_less_traces_button, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hbox), s_view1_vmenubox, - FALSE, FALSE, 0); - - /* Time axis menu */ - - s_view1_hmenubox = gtk_hbox_new(FALSE, 5); - - s_view1_startbutton = gtk_button_new_with_label("Start"); - - s_view1_zoominbutton = gtk_button_new_with_label("ZoomIn"); - - s_view1_searchbutton = gtk_button_new_with_label("Search"); - - s_view1_srchagainbutton = gtk_button_new_with_label("Search Again"); - - s_view1_zoomoutbutton = gtk_button_new_with_label("ZoomOut"); - - s_view1_endbutton = gtk_button_new_with_label("End"); - - gtk_signal_connect (GTK_OBJECT(s_view1_startbutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) START_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_zoominbutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) ZOOMIN_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_searchbutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) SEARCH_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_srchagainbutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) SEARCH_AGAIN_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_zoomoutbutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) ZOOMOUT_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_endbutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) END_BUTTON); - - s_view1_hsadj = gtk_adjustment_new(0.0 /* initial value */, - 0.0 /* minimum value */, - 2000.0 /* maximum value */, - 0.1 /* step increment */, - 10.0/* page increment */, - 10.0/* page size */); - - s_view1_hscroll = gtk_hscrollbar_new (GTK_ADJUSTMENT(s_view1_hsadj)); - - gtk_signal_connect (GTK_OBJECT (s_view1_hsadj), "value-changed", - GTK_SIGNAL_FUNC (view1_hscroll), - (gpointer)s_view1_hscroll); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_startbutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_hscroll, - TRUE, TRUE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_endbutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoominbutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_searchbutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_srchagainbutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoomoutbutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hbox, - TRUE, TRUE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox, - FALSE, FALSE, 0); - - - s_view1_hmenubox2 = gtk_hbox_new(FALSE, 5); - - s_view1_snapbutton = gtk_button_new_with_label("Snap"); - - s_view1_nextbutton = gtk_button_new_with_label("Next"); - - s_view1_delbutton = gtk_button_new_with_label("Del"); - - s_view1_chase_event_button = gtk_button_new_with_label("ChaseEvent"); - - s_view1_chase_datum_button = gtk_button_new_with_label("ChaseDatum"); - - s_view1_chase_track_button = gtk_button_new_with_label("ChaseTrack"); - - s_view1_unchasebutton = gtk_button_new_with_label("NoChase"); - - s_view1_forward_button = gtk_button_new_with_label("->SrchChase(is<-)"); - s_view1_backward_button = gtk_button_new_with_label("<-SrchChase(is->)"); - - s_view1_summary_button = gtk_button_new_with_label("Summary"); - s_view1_nosummary_button = gtk_button_new_with_label("NoSummary"); - - gtk_signal_connect (GTK_OBJECT(s_view1_snapbutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) SNAP_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_nextbutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) NEXT_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_delbutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) DEL_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_chase_event_button), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) CHASE_EVENT_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_chase_datum_button), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) CHASE_DATUM_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_chase_track_button), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) CHASE_TRACK_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_unchasebutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) UNCHASE_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_forward_button), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) FORWARD_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_backward_button), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) BACKWARD_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_summary_button), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) SUMMARY_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_nosummary_button), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) NOSUMMARY_BUTTON); - - gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox2, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_snapbutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nextbutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_delbutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_event_button, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_datum_button, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_track_button, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_unchasebutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_forward_button, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_backward_button, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_summary_button, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nosummary_button, - FALSE, FALSE, 0); - - s_view1_label = gtk_label_new(NULL); - - gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_label, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(g_mainhbox), s_view1_vbox, - TRUE, TRUE, 0); - - gtk_widget_show_all (s_view1_vbox); - GTK_WIDGET_SET_FLAGS(da, GTK_CAN_FOCUS); - gtk_widget_grab_focus(da); - - gtk_widget_hide (s_view1_forward_button); - gtk_widget_hide (summary_mode ? s_view1_summary_button - : s_view1_nosummary_button); - - zi_source = gdk_bitmap_create_from_data (NULL, (char *)zi_bits, zi_width, - zi_height); - zi_mask = gdk_bitmap_create_from_data (NULL, (char *)zi_bkgd, zi_width, - zi_height); - - zi_cursor = (GdkCursor *) gdk_cursor_new_from_pixmap (zi_source, - zi_mask, &fg_black, - &bg_white, zi_x_hot, - zi_y_hot); - gdk_pixmap_unref (zi_source); - gdk_pixmap_unref (zi_mask); - - norm_cursor = (GdkCursor *) gdk_cursor_new (GDK_TOP_LEFT_ARROW); -} - -/**************************************************************************** -* line_print -****************************************************************************/ - -void line_print (int x1, int y1, int x2, int y2) -{ - fprintf(s_printfp, "newpath\n"); - fprintf(s_printfp, "%d %d moveto\n", xrt(x1, s_v1->total_height - y1), - yrt(x1, s_v1->total_height - y1)); - - fprintf(s_printfp, "%d %d lineto\n", xrt (x2, s_v1->total_height - y2), - yrt (x2, s_v1->total_height - y2)); - fprintf(s_printfp, "1 setlinewidth\n"); - fprintf(s_printfp, "stroke\n"); -} - -/**************************************************************************** -* tbox_print -****************************************************************************/ -GdkRectangle *tbox_print (char *s, int x, int y, enum view1_tbox_fn function, - GdkRectangle *rp) -{ - if (function == TBOX_PRINT_BOXED) { - rp->width -= 4; - } - - if ((function == TBOX_PRINT_BOXED) || - (function == TBOX_PRINT_EVENT)) { - - fprintf(s_printfp, "newpath\n"); - fprintf(s_printfp, "0 setlinewidth\n"); - fprintf(s_printfp, "%d %d moveto\n", - xrt(rp->x, s_v1->total_height - rp->y), - yrt(rp->x, s_v1->total_height - rp->y)); - - fprintf(s_printfp, "%d %d lineto\n", - xrt (rp->x+rp->width, s_v1->total_height - rp->y), - yrt (rp->x+rp->width, s_v1->total_height - rp->y)); - - fprintf(s_printfp, "%d %d lineto\n", - xrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height)), - yrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height))); - - fprintf(s_printfp, "%d %d lineto\n", - xrt(rp->x, s_v1->total_height - (rp->y+rp->height)), - yrt(rp->x, s_v1->total_height - (rp->y+rp->height))); - - fprintf(s_printfp, "%d %d lineto\n", - xrt(rp->x, s_v1->total_height - rp->y), - yrt(rp->x, s_v1->total_height - rp->y)); - - fprintf(s_printfp, "stroke\n"); - } - - if ((function == TBOX_PRINT_BOXED) || - (function == TBOX_PRINT_PLAIN)) { - - fprintf(s_printfp, "newpath\n"); - fprintf(s_printfp, "%d %d moveto\n", - xrt(x, s_v1->total_height - (y-2)), - yrt(x, s_v1->total_height - (y-2))); - fprintf(s_printfp, "gsave\n"); - fprintf(s_printfp, "90 rotate\n"); - fprintf(s_printfp, "(%s) show\n", s); - fprintf(s_printfp, "grestore\n"); - } - - return(rp); -} - -/**************************************************************************** -* tbox - draws an optionally boxed string whose lower lefthand -* corner is at (x, y). As usual, Y is backwards. -****************************************************************************/ - -GdkRectangle *tbox (char *s, int x, int y, enum view1_tbox_fn function) -{ - static GdkRectangle update_rect; - gint lbearing, rbearing, width, ascent, descent; - - gdk_string_extents (g_font, s, - &lbearing, &rbearing, - &width, &ascent, &descent); - - /* - * If we have enough room to display full size events, then just - * use the BOXED function instead of the EVENT function. - */ - if (s_v1->strip_height > 9) { - switch (function) { - case TBOX_DRAW_EVENT: function = TBOX_DRAW_BOXED; break; - case TBOX_GETRECT_EVENT: function = TBOX_GETRECT_BOXED; break; - case TBOX_PRINT_EVENT: function = TBOX_PRINT_BOXED; break; - default: - break; - /* Nothing */ - } - } - - switch (function) { - case TBOX_DRAW_BOXED: - gdk_draw_rectangle (pm, da->style->white_gc, TRUE, - x, y - (ascent+descent+3), width + 2, - ascent + descent + 3); - - gdk_draw_rectangle (pm, da->style->black_gc, FALSE, - x, y - (ascent+descent+3), width + 2, - ascent + descent + 3); - - gdk_draw_string (pm, g_font, da->style->black_gc, - x + 1, y - 1, (const gchar *)s); - /* NOTE FALLTHROUGH */ - case TBOX_GETRECT_BOXED: - update_rect.x = x; - update_rect.y = y -(ascent+descent+3); - update_rect.width = width + 3; - update_rect.height = ascent + descent + 4; - if (function == TBOX_DRAW_BOXED) - gtk_widget_draw (da, &update_rect); - break; - - case TBOX_DRAW_EVENT: - /* We have a small event to draw...no text */ - gdk_draw_rectangle (pm, da->style->black_gc, FALSE, - x, y - 1, 3, 3); - /* NOTE FALLTHROUGH */ - case TBOX_GETRECT_EVENT: - update_rect.x = x; - update_rect.y = y - 1; - update_rect.width = 4; - update_rect.height = 4; - if (function == TBOX_DRAW_EVENT) - gtk_widget_draw (da, &update_rect); - break; - - - case TBOX_DRAW_PLAIN: - - gdk_draw_string (pm, g_font, da->style->black_gc, - x + 1, y - 1, (const gchar *)s); - /* NOTE FALLTHROUGH */ - case TBOX_GETRECT_PLAIN: - update_rect.x = x; - update_rect.y = y -(ascent+descent+1); - update_rect.width = width; - update_rect.height = ascent + descent; - if (function == TBOX_DRAW_PLAIN) - gtk_widget_draw (da, &update_rect); - break; - - case TBOX_PRINT_BOXED: - update_rect.x = x; - update_rect.y = y -(ascent+descent+3); - update_rect.width = width + 3; - update_rect.height = ascent + descent + 4; - /* note fallthrough */ - case TBOX_PRINT_PLAIN: - return(tbox_print(s, x, y, function, &update_rect)); - - case TBOX_PRINT_EVENT: - /* We have a small event box to print...no text */ - update_rect.x = x; - update_rect.y = y - 1; - update_rect.width = 4; - update_rect.height = 4; - return(tbox_print(s, x, y, function, &update_rect)); - } - return(&update_rect); -} - -/**************************************************************************** -* line -* -* For lines there is a primitive batching facility, that doesn't update -* the drawing area until the batch is complete. This is handy for drawing -* the pid axis and for summary mode. -* -* line_batch_mode contains the state for this: -* -* BATCH_OFF: no batching, update for every line -* BATCH_NEW: just entered a batch, so initialize the area to update from -* scratch -* BATCH_EXISTING: have drawn at least one line in batch mode, so the update -* area should only be expanded from now on to include the -* union of the "rectangular hull" of all lines -****************************************************************************/ - -static enum { BATCH_OFF, BATCH_NEW, BATCH_EXISTING } line_batch_mode; -static int line_batch_count; -static int line_minx, line_miny, line_maxx, line_maxy; - -void line_batch_start (void) -{ - line_batch_mode = BATCH_NEW; - line_batch_count = 0; -} - -void line_batch_end (void) -{ - GdkRectangle update_rect; - if (line_batch_count > 0) { - update_rect.x = line_minx; - update_rect.y = line_miny; - update_rect.width = (line_maxx - line_minx) + 1; - update_rect.height = (line_maxy - line_miny) + 1; - gtk_widget_draw (da, &update_rect); - } - line_batch_mode = BATCH_OFF; -} - -void line (int x1, int y1, int x2, int y2, enum view1_line_fn function) -{ - GdkRectangle update_rect; - GdkGC *gc = NULL; - - switch(function) { - case LINE_DRAW_BLACK: - gc = da->style->black_gc; - break; - - case LINE_DRAW_WHITE: - gc = da->style->white_gc; - break; - - case LINE_PRINT: - line_print (x1, y1, x2, y2); - return; - } - - gdk_draw_line (pm, gc, x1, y1, x2, y2); - - switch (line_batch_mode) { - case BATCH_OFF: - update_rect.x = x1; - update_rect.y = y1; - update_rect.width = (x2-x1) + 1; - update_rect.height = (y2-y1) + 1; - gtk_widget_draw (da, &update_rect); - break; - - case BATCH_NEW: - line_minx = x1; - line_maxx = x2; - line_miny = y1; - line_maxy = y2; - line_batch_mode = BATCH_EXISTING; - line_batch_count = 1; - break; - - case BATCH_EXISTING: - if (line_minx > x1) - line_minx = x1; - if (line_miny > y1) - line_miny = y1; - if (line_maxx < x2) - line_maxx = x2; - if (line_maxy < y2) - line_maxy = y2; - line_batch_count++; - break; - } -} - - -/**************************************************************************** -* display_pid_axis -****************************************************************************/ - -static void display_pid_axis(v1_geometry_t *vp) -{ - int y, i, label_tick; - int last_printed_y = -vp->strip_height; - pid_sort_t *pp; - int pid_index; - char *label_fmt; - char tmpbuf [128]; - - /* No pids yet? Outta here */ - if (g_pids == NULL) - return; - - line_batch_start(); - - for (i = 0; i < vp->npids; i++) { - pid_index = vp->first_pid_index + i; - if (pid_index >= g_npids) - break; - - set_color(pid_index); - pp = (g_pids + pid_index); - - label_fmt = get_track_label(pp->pid_value); - snprintf(tmpbuf, sizeof(tmpbuf)-1, label_fmt, pp->pid_value); - - y = i*vp->strip_height + vp->pid_ax_offset; - - /* - * Have we incremented enough space to have another label not - * overlap the previous label? - */ - if (y - last_printed_y > 9) { - /* Draw label */ - tbox(tmpbuf, 0, y +4, TBOX_DRAW_PLAIN+s_print_offset); - - last_printed_y = y; - - /* - * And let the line stick out a bit more to indicate this label - * relates to the following line. - */ - label_tick = 4; - } - else { - label_tick = 0; - } - - /* Draw axis line, but only if the lines aren't too close together */ - if (vp->strip_height > 4) { - line(vp->pid_ax_width - label_tick, y+4*s_print_offset, - vp->total_width, y+4*s_print_offset, - LINE_DRAW_BLACK+s_print_offset); - } - } - - set_color(COLOR_DEFAULT); - line_batch_end(); -} - -/**************************************************************************** -* view1_read_events_callback -* New event data just showed up, reset a few things. -****************************************************************************/ - -void view1_read_events_callback(void) -{ - int max_vis_index; - - s_v1->first_pid_index = 0; - - max_vis_index = 300; - if (max_vis_index > g_nevents) - max_vis_index = g_nevents-1; - - s_v1->minvistime = 0LL; - s_v1->maxvistime = (g_events[g_nevents - 1].time * 9)/ 8; - s_srchindex = 0; - s_srchcode = 0; - s_last_selected_event = 0; - - init_track_colors(); - - recompute_hscrollbar(); - recompute_vscrollbar(); -} - -/**************************************************************************** -* display_event_data -****************************************************************************/ - -static void display_event_data(v1_geometry_t *vp) -{ - int start_index; - int pid_index; - int x, y; - event_t *ep; - event_def_t *edp; - double time_per_pixel; - char tmpbuf[1024]; - GdkRectangle *print_rect; - int *last_x_used; - - /* Happens if one loads the event def header first, for example. */ - if (g_nevents == 0) - return; - - time_per_pixel = dtime_per_pixel(vp); - - start_index = find_event_index (vp->minvistime); - - /* Scrolled too far right? */ - if (start_index >= g_nevents) - return; - - ep = (g_events + start_index); - - if (s_print_offset || summary_mode) { - last_x_used = (int *)g_malloc0(vp->npids * sizeof(int)); - } else { - last_x_used = NULL; - } - - line_batch_start(); - - while (ep < (g_events + g_nevents) && - (ep->time < vp->maxvistime)) { - pid_index = ep->pid->pid_index; - set_color(pid_index); - - /* First filter: pid out of range */ - if ((pid_index < vp->first_pid_index) || - (pid_index >= vp->first_pid_index + vp->npids)) { - ep++; - continue; - } - - /* Second filter: event hidden */ - edp = find_event_definition (ep->code); - if (!edp->selected) { - ep++; - continue; - } - - /* Display it... */ - - pid_index -= vp->first_pid_index; - - y = pid_index*vp->strip_height + vp->event_offset; - - x = vp->pid_ax_width + - (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel); - - if (last_x_used != NULL && x < last_x_used[pid_index]) { - ep++; - continue; - } - - if (ep->flags & (EVENT_FLAG_SELECT | EVENT_FLAG_SEARCHRSLT)) { - if (ep->flags & EVENT_FLAG_SELECT) { - format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp); -#ifdef NOTDEF - sprintf(tmpbuf, edp->name); - sprintf(tmpbuf+strlen(tmpbuf), ": "); - sprintf(tmpbuf+strlen(tmpbuf), edp->format, ep->datum); -#endif - } else { - sprintf(tmpbuf, "SEARCH RESULT"); - } - print_rect = tbox(tmpbuf, x, y - vp->pop_offset, - TBOX_DRAW_BOXED+s_print_offset); - line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK+s_print_offset); - if (last_x_used != NULL) - last_x_used[pid_index] = x + print_rect->width; - } - if (summary_mode) { - int delta = vp->strip_height / 3; - if (delta < 1) - delta = 1; - y = pid_index*vp->strip_height + vp->pid_ax_offset; - line(x, y - delta, x, y + delta, LINE_DRAW_BLACK); - last_x_used[pid_index] = x + 1; - } else { - sprintf(tmpbuf, "%ld", ep->code); - print_rect = tbox(tmpbuf, x, y, TBOX_DRAW_EVENT+s_print_offset); - if (last_x_used != NULL) - last_x_used[pid_index] = x + print_rect->width; - } - - ep++; - } - if (last_x_used) - g_free(last_x_used); - line_batch_end(); - set_color(COLOR_DEFAULT); -} - -/**************************************************************************** -* display_clear -****************************************************************************/ - -static void display_clear(void) -{ - GdkRectangle update_rect; - - gdk_draw_rectangle (pm, da->style->white_gc, TRUE, - 0, 0, da->allocation.width, - da->allocation.height); - - update_rect.x = 0; - update_rect.y = 0; - update_rect.width = da->allocation.width; - update_rect.height = da->allocation.height; - - gtk_widget_draw (da, &update_rect); -} - -/**************************************************************************** -* display_time_axis -****************************************************************************/ - -static void display_time_axis(v1_geometry_t *vp) -{ - int x, y, i; - int xoffset, nticks; - char tmpbuf [128]; - double unit_divisor; - double time; - char *units; - double time_per_pixel; - - y = vp->npids * vp->strip_height + vp->pid_ax_offset; - - x = vp->pid_ax_width; - - nticks = (vp->total_width - vp->pid_ax_width) / vp->time_ax_spacing; - - time_per_pixel = dtime_per_pixel(vp); - - units = "ns"; - unit_divisor = 1.00; - - if ((vp->maxvistime / unit_divisor) > 1000) { - units = "us"; - unit_divisor = 1000.00; - } - - if ((vp->maxvistime / unit_divisor) > 1000) { - units = "ms"; - unit_divisor = 1000.00*1000.00; - } - if ((vp->maxvistime / unit_divisor) > 1000) { - units = "s"; - unit_divisor = 1000.00*1000.00*1000.00; - } - - /* Draw line */ - line(x, y, vp->total_width, y, LINE_DRAW_BLACK+s_print_offset); - - xoffset = 0; - - for (i = 0; i < nticks; i++) { - /* Tick mark */ - line(x+xoffset, y-3, x+xoffset, y+3, LINE_DRAW_BLACK+s_print_offset); - - time = (double)(x + xoffset - vp->pid_ax_width); - time *= time_per_pixel; - time += (double)(vp->minvistime); - time /= unit_divisor; - - sprintf (tmpbuf, "%.2f%s", time, units); - - tbox(tmpbuf, x+xoffset, y+15, TBOX_DRAW_PLAIN+s_print_offset); - - xoffset += vp->time_ax_spacing; - } -} - -/**************************************************************************** -* clear_scoreboard -* Forget about any temporary displays, they're gone now... -****************************************************************************/ - -static void clear_scoreboard(void) -{ - s_result_up = FALSE; -} - -/**************************************************************************** -* view1_display -****************************************************************************/ - -void view1_display(void) -{ - display_clear(); - display_pid_axis(s_v1); - display_event_data(s_v1); - display_time_axis(s_v1); - clear_scoreboard(); -} - -static gint idle_tag; - -/**************************************************************************** -* view1_display_eventually -****************************************************************************/ - -static void view1_display_eventually(void) -{ - gtk_idle_remove(idle_tag); - idle_tag = 0; - view1_display(); -} - - -/**************************************************************************** -* view1_display_when_idle -****************************************************************************/ - -void view1_display_when_idle(void) -{ - if (idle_tag == 0) { - idle_tag = gtk_idle_add((GtkFunction) view1_display_eventually, 0); - } -} - -/**************************************************************************** -* view1_about -****************************************************************************/ - -void view1_about (char *tmpbuf) -{ - int nsnaps; - snapshot_t *snaps; - - sprintf(tmpbuf+strlen(tmpbuf), "Minvistime %lld\nMaxvistime %lld\n", - s_v1->minvistime, s_v1->maxvistime); - sprintf(tmpbuf+strlen(tmpbuf), "Strip Height %d\n", - s_v1->strip_height); - - for (nsnaps = 0, snaps = s_snapshots; snaps; snaps = snaps->next) { - nsnaps++; - } - sprintf(tmpbuf+strlen(tmpbuf), "%d snapshots in the ring\n", nsnaps); -} diff --git a/gmod/gmod/mod_vpp.c b/gmod/gmod/mod_vpp.c index 4a1da83c..572f9ef5 100644 --- a/gmod/gmod/mod_vpp.c +++ b/gmod/gmod/mod_vpp.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include mmodule vpp_module; diff --git a/perftool/Makefile.am b/perftool/Makefile.am deleted file mode 100644 index ac652aa6..00000000 --- a/perftool/Makefile.am +++ /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. - -AUTOMAKE_OPTIONS = foreign -AM_CFLAGS = -Wall - -bin_PROGRAMS = c2cpel cpelatency cpeldump cpelinreg cpelstate - -lib_LTLIBRARIES = libcperf.la - -libcperf_la_SOURCES = delsvec.c linreg.c props.c cpel_util.c - -TOOL_LIBS = libcperf.la -lvppinfra -lm - -c2cpel_SOURCE = c2cpel.c -c2cpel_LDADD = $(TOOL_LIBS) - -cpelatency_SOURCE = cpelatency.c -cpelatency_LDADD = $(TOOL_LIBS) - -cpeldump_SOURCE = cpeldump.c -cpeldump_LDADD = $(TOOL_LIBS) - -cpelinreg_SOURCE = cpelinreg.c -cpelinreg_LDADD = $(TOOL_LIBS) - -cpelstate_SOURCE = cpelstate.c -cpelstate_LDADD = $(TOOL_LIBS) - - - - - - diff --git a/perftool/c2cpel.c b/perftool/c2cpel.c deleted file mode 100644 index 38e6fe52..00000000 --- a/perftool/c2cpel.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2006-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 -#include -#include "cpel.h" -#include "cpel_util.h" - -static elog_main_t elog_main; - -/* - * convert_clib_file - */ -void convert_clib_file(char *clib_file) -{ - clib_error_t *error = 0; - int i; - elog_main_t *em = &elog_main; - double starttime, delta; - - error = elog_read_file (&elog_main, clib_file); - - if (error) { - clib_warning("%U", format_clib_error, error); - exit (1); - } - - em = &elog_main; - - starttime = em->events[0].time; - - for (i = 0; i < vec_len (em->events); i++) { - elog_event_t *e; /* clib event */ - evt_t *ep; /* xxx2cpel event */ - u8 *s; - u64 timestamp; - elog_event_type_t *t; - u8 *brief_event_name; - u8 *track_name; - int j; - - e = vec_elt_at_index(em->events, i); - - /* Seconds since start of log */ - delta = e->time - starttime; - - /* u64 nanoseconds since start of log */ - timestamp = delta * 1e9; - - s = format (0, "%U%c", format_elog_event, em, e, 0); - - /* allocate an event instance */ - vec_add2(the_events, ep, 1); - ep->timestamp = timestamp; - - /* convert string event code to a real number */ - t = vec_elt_at_index (em->event_types, e->type); - - /* - * Construct a reasonable event name. - * Truncate the format string at the first whitespace break - * or printf format character. - */ - brief_event_name = format (0, "%s", t->format); - - for (j = 0; j < vec_len (brief_event_name); j++) { - if (brief_event_name[j] == ' ' || - brief_event_name[j] == '%' || - brief_event_name[j] == '(') { - brief_event_name[j] = 0; - break; - } - } - /* Throw away that much of the formatted event */ - vec_delete (s, j+1, 0); - - ep->event_id = find_or_add_event(brief_event_name, "%s"); - - track_name = format (0, "%U%c", format_elog_track, em, e, 0); - - ep->track_id = find_or_add_track (track_name); - - ep->datum = find_or_add_strtab(s); - - vec_free (track_name); - vec_free(brief_event_name); - vec_free(s); - } -} - -u8 *vec_basename (char *s) -{ - u8 * rv; - char *cp = s; - - while (*cp) - cp++; - - cp--; - - while (cp > s && *cp != '/') - cp--; - - if (cp > s) - cp++; - - rv = format (0, "%s", cp); - return rv; -} - - -int event_compare (const void *a0, const void *a1) -{ - evt_t *e0 = (evt_t *)a0; - evt_t *e1 = (evt_t *)a1; - - if (e0->timestamp < e1->timestamp) - return -1; - else if (e0->timestamp > e1->timestamp) - return 1; - return 0; -} - -int main (int argc, char **argv) -{ - int curarg=1; - char **inputfiles = 0; - char *outputfile = 0; - FILE *ofp; - - if (argc < 3) - goto usage; - - while (curarg < argc) { - if (!strncmp(argv[curarg], "--input-file", 3)) { - curarg++; - if (curarg < argc) { - vec_add1 (inputfiles, argv[curarg]); - curarg++; - continue; - } - clib_warning("Missing filename after --input-file\n"); - exit (1); - } - - if (!strncmp(argv[curarg], "--output-file", 3)) { - curarg ++; - if (curarg < argc) { - outputfile = argv[curarg]; - curarg ++; - continue; - } - clib_warning("Missing filename after --output-file\n"); - exit(1); - } - vec_add1 (inputfiles, argv[curarg]); - curarg++; - continue; - - usage: - fformat(stderr, - "c2cpel [--input-file] --output-file \n"); - exit(1); - } - - if (vec_len(inputfiles) == 0 || outputfile == 0) - goto usage; - - if (vec_len(inputfiles) > 1) - goto usage; - - cpel_util_init(); - - convert_clib_file (inputfiles[0]); - - ofp = fopen (outputfile, "w"); - if (ofp == NULL) { - clib_unix_warning ("couldn't create %s", outputfile); - exit (1); - } - - alpha_sort_tracks(); - fixup_event_tracks(); - - /* - * Four sections: string-table, event definitions, track defs, events. - */ - if (!write_cpel_header(ofp, 4)) { - clib_warning ("Error writing cpel header to %s...\n", outputfile); - unlink(outputfile); - exit(1); - } - - if (!write_string_table(ofp)) { - clib_warning ("Error writing string table to %s...\n", outputfile); - unlink(outputfile); - exit(1); - } - - if (!write_event_defs(ofp)) { - clib_warning ("Error writing event defs to %s...\n", outputfile); - unlink(outputfile); - exit(1); - } - - if (!write_track_defs(ofp)) { - clib_warning ("Error writing track defs to %s...\n", outputfile); - unlink(outputfile); - exit(1); - } - - if (!write_events(ofp, (u64) 1e9)) { - clib_warning ("Error writing events to %s...\n", outputfile); - unlink(outputfile); - exit(1); - - } - fclose(ofp); - exit (0); -} diff --git a/perftool/configure.ac b/perftool/configure.ac deleted file mode 100644 index f4a98697..00000000 --- a/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/perftool/cpel.h b/perftool/cpel.h deleted file mode 100644 index 0bfb1a68..00000000 --- a/perftool/cpel.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2005-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 _CPEL_H_ -#define _CPEL_H_ 1 - -typedef struct cpel_file_header_ { - unsigned char endian_version; - unsigned char pad; - unsigned short nsections; - unsigned int file_date; -} cpel_file_header_t; - -#define CPEL_FILE_LITTLE_ENDIAN 0x80 -#define CPEL_FILE_VERSION 0x01 -#define CPEL_FILE_VERSION_MASK 0x7F - -typedef struct cpel_section_header_ { - unsigned int section_type; - unsigned int data_length; /* does NOT include type and itself */ -} cpel_section_header_t; - -#define CPEL_SECTION_STRTAB 1 -/* string at offset 0 is the name of the table */ - -#define CPEL_SECTION_SYMTAB 2 -#define CPEL_SECTION_EVTDEF 3 - -typedef struct event_definition_section_header_ { - char string_table_name[64]; - unsigned int number_of_event_definitions; -} event_definition_section_header_t; - -typedef struct event_definition_ { - unsigned int event; - unsigned int event_format; - unsigned int datum_format; -} event_definition_t; - -#define CPEL_SECTION_TRACKDEF 4 - -typedef struct track_definition_section_header_ { - char string_table_name[64]; - unsigned int number_of_track_definitions; -} track_definition_section_header_t; - -typedef struct track_definition_ { - unsigned int track; - unsigned int track_format; -} track_definition_t; - -#define CPEL_SECTION_EVENT 5 - -typedef struct event_section_header_ { - char string_table_name[64]; - unsigned int number_of_events; - unsigned int clock_ticks_per_second; -} event_section_header_t; - -typedef struct event_entry_ { - unsigned int time[2]; - unsigned int track; - unsigned int event_code; - unsigned int event_datum; -} event_entry_t; - -#define CPEL_NUM_SECTION_TYPES 5 - -#endif /* _CPEL_H_ */ - diff --git a/perftool/cpel_util.c b/perftool/cpel_util.c deleted file mode 100644 index 7ee9b6e2..00000000 --- a/perftool/cpel_util.c +++ /dev/null @@ -1,456 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2006-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 -#include -#include -#include "cpel.h" -#include "cpel_util.h" - -evt_t *the_events; - -track_t *the_tracks; -u32 *track_alpha_map; - -event_definition_t *the_event_definitions; -i64 min_timestamp; - -/* Hash tables, used to find previous instances of the same items */ -uword *the_track_hash; -uword *the_msg_event_hash; -uword *the_strtab_hash; -uword *the_pidtid_hash; -uword *the_pid_to_name_hash; -u8 *the_strtab; - -uword *the_event_id_bitmap; - -/* - * find_or_add_strtab - * Finds or adds a string to the string table - */ -u32 find_or_add_strtab(void *s_arg) -{ - uword *p; - int len; - u8 *this_string; - u8 *scopy=0; - char *s = s_arg; - - p = hash_get_mem(the_strtab_hash, s); - if (p) { - return (p[0]); - } - - /* - * Here's a CLIB bear-trap. We can't add the string-table - * strings to the to the hash table (directly), since it - * expands and moves periodically. All of the hash table - * entries turn into dangling references, yadda yadda. - */ - - len = strlen(s)+1; - vec_add2(the_strtab, this_string, len); - memcpy(this_string, s, len); - - /* Make a copy which won't be moving around... */ - vec_validate(scopy, len); - memcpy(scopy, s, len); - - hash_set_mem(the_strtab_hash, scopy, this_string - the_strtab); - - return(this_string - the_strtab); -} - -/* - * find_or_add_track - * returns index in track table - */ -u32 find_or_add_track(void *s_arg) -{ - uword *p; - track_t *this_track; - u8 *copy_s; - char *s=s_arg; - - p = hash_get_mem(the_track_hash, s); - if (p) { - return (p[0]); - } - vec_add2(the_tracks, this_track, 1); - - this_track->original_index = this_track - the_tracks; - this_track->strtab_offset = find_or_add_strtab(s); - - copy_s = (u8 *)vec_dup(s); - - hash_set_mem(the_track_hash, copy_s, this_track - the_tracks); - return(this_track - the_tracks); -} - -/* - * find_or_add_event - * Adds an event to the event definition vector and add it to - * the event hash table - */ - -u32 find_or_add_event(void *s_arg, char *datum_format) -{ - uword *p; - u8 *copy_s; - event_definition_t *this_event_definition; - u32 event_id; - char *s=s_arg; - - p = hash_get_mem(the_msg_event_hash, s); - if (p) { - return (p[0]); - } - vec_add2(the_event_definitions, this_event_definition, 1); - - /* Allocate a new event-id */ - event_id = clib_bitmap_first_clear (the_event_id_bitmap); - the_event_id_bitmap = clib_bitmap_set(the_event_id_bitmap, event_id, 1); - this_event_definition->event = event_id; - this_event_definition->event_format = find_or_add_strtab(s); - this_event_definition->datum_format = find_or_add_strtab(datum_format); - - copy_s = (u8 *)vec_dup(s); - - hash_set_mem(the_msg_event_hash, copy_s, event_id); - - return(event_id); -} - -/* - * write_string_table - */ -int write_string_table(FILE *ofp) -{ - cpel_section_header_t sh; - - /* Round up string table size */ - while (vec_len(the_strtab) & 0x7) - vec_add1(the_strtab, 0); - - sh.section_type = ntohl(CPEL_SECTION_STRTAB); - sh.data_length = ntohl(vec_len(the_strtab)); - - if (fwrite(&sh, sizeof(sh), 1, ofp) != 1) - return(0); - - if (fwrite(the_strtab, 1, vec_len(the_strtab), ofp) != - vec_len(the_strtab)) - return(0); - - return(1); -} - -/* - * write_cpel_header - */ -int write_cpel_header(FILE *ofp, u32 nsections) -{ - cpel_file_header_t h; - - h.endian_version = CPEL_FILE_VERSION; - h.pad = 0; - h.nsections = ntohs(nsections); - h.file_date = ntohl(time(0)); - if (fwrite(&h, sizeof(h), 1, ofp) != 1) - return (0); - - return(1); -} - -/* - * write_event_defs - */ -int write_event_defs(FILE *ofp) -{ - cpel_section_header_t sh; - event_definition_section_header_t edsh; - event_definition_t *this_event_definition; - int i; - - /* Next, the event definitions */ - sh.section_type = ntohl(CPEL_SECTION_EVTDEF); - sh.data_length = ntohl(vec_len(the_event_definitions) - *sizeof(the_event_definitions[0]) - + sizeof(event_definition_section_header_t)); - - if (fwrite(&sh, sizeof(sh), 1, ofp) != 1) - return(0); - - memset(&edsh, 0, sizeof(edsh)); - - strcpy(edsh.string_table_name, "FileStrtab"); - edsh.number_of_event_definitions = ntohl(vec_len(the_event_definitions)); - - if (fwrite(&edsh, sizeof(edsh), 1, ofp) != 1) - return(0); - - for (i = 0; i < vec_len(the_event_definitions); i++) { - this_event_definition = &the_event_definitions[i]; - /* Endian fixup */ - this_event_definition->event = ntohl(this_event_definition->event); - this_event_definition->event_format = - ntohl(this_event_definition->event_format); - this_event_definition->datum_format = - ntohl(this_event_definition->datum_format); - - if (fwrite(this_event_definition, sizeof(the_event_definitions[0]), - 1, ofp) != 1) - return(0); - } - return(1); -} - -/* - * ntohll - */ -u64 ntohll (u64 x) { - if (clib_arch_is_little_endian) - x = ((((x >> 0) & 0xff) << 56) - | (((x >> 8) & 0xff) << 48) - | (((x >> 16) & 0xff) << 40) - | (((x >> 24) & 0xff) << 32) - | (((x >> 32) & 0xff) << 24) - | (((x >> 40) & 0xff) << 16) - | (((x >> 48) & 0xff) << 8) - | (((x >> 56) & 0xff) << 0)); - - return x; -} - -/* - * write_events - */ -int write_events(FILE *ofp, u64 clock_ticks_per_second) -{ - cpel_section_header_t sh; - event_section_header_t eh; - u32 number_of_events; - int i; - event_entry_t e; - u64 net_timestamp; - evt_t *this_event; - u32 time0, time1; - - number_of_events = vec_len(the_events); - - sh.section_type = ntohl(CPEL_SECTION_EVENT); - sh.data_length = ntohl(number_of_events * sizeof(e) + - sizeof(event_section_header_t)); - - if (fwrite(&sh, sizeof(sh), 1, ofp) != 1) - return(0); - - memset(&eh, 0, sizeof(eh)); - strcpy(eh.string_table_name, "FileStrtab"); - eh.number_of_events = ntohl(number_of_events); - eh.clock_ticks_per_second = ntohl(clock_ticks_per_second); - - if (fwrite(&eh, sizeof(eh), 1, ofp) != 1) - return(0); - - for (i = 0; i < number_of_events; i++) { - this_event = &the_events[i]; - net_timestamp = ntohll(this_event->timestamp); - - time1 = net_timestamp>>32; - time0 = net_timestamp & 0xFFFFFFFF; - - e.time[0] = time0; - e.time[1] = time1; - e.track = ntohl(this_event->track_id); - e.event_code = ntohl(this_event->event_id); - e.event_datum = ntohl(this_event->datum); - - if (fwrite(&e, sizeof(e), 1, ofp) != 1) - return(0); - } - return(1); -} - -/* - * write_track_defs - */ -int write_track_defs(FILE *ofp) -{ - cpel_section_header_t sh; - track_definition_section_header_t tdsh; - track_definition_t record; - track_definition_t *this_track_definition = &record; - int i; - event_definition_section_header_t edsh; - - /* Next, the event definitions */ - sh.section_type = ntohl(CPEL_SECTION_TRACKDEF); - sh.data_length = ntohl(vec_len(the_tracks) - *sizeof(this_track_definition[0]) - + sizeof(track_definition_section_header_t)); - - if (fwrite(&sh, sizeof(sh), 1, ofp) != 1) - return(0); - - memset(&tdsh, 0, sizeof(tdsh)); - - strcpy(tdsh.string_table_name, "FileStrtab"); - tdsh.number_of_track_definitions = ntohl(vec_len(the_tracks)); - - if (fwrite(&tdsh, sizeof(edsh), 1, ofp) != 1) - return(0); - - for (i = 0; i < vec_len(the_tracks); i++) { - this_track_definition->track = ntohl(i); - this_track_definition->track_format = - ntohl(the_tracks[i].strtab_offset); - - if (fwrite(this_track_definition, sizeof(this_track_definition[0]), - 1, ofp) != 1) - return(0); - } - return(1); -} - -void cpel_util_init (void) -{ - u8 *eventstr; - - the_strtab_hash = hash_create_string (0, sizeof (uword)); - the_msg_event_hash = hash_create_string (0, sizeof (uword)); - the_track_hash = hash_create_string (0, sizeof (uword)); - the_pidtid_hash = hash_create_string (0, sizeof(uword)); - the_pid_to_name_hash = hash_create(0, sizeof(uword)); - - /* Must be first, or no supper... */ - find_or_add_strtab("FileStrtab"); - - /* Historical canned events, no longer used. */ - if (0) { - /* event 0 (not used) */ - eventstr = format(0, "PlaceholderNotUsed"); - vec_add1(eventstr, 0); - find_or_add_event(eventstr, "%s"); - vec_free(eventstr); - - /* event 1 (thread on CPU) */ - eventstr = format(0, "THREAD/THRUNNING"); - vec_add1(eventstr, 0); - find_or_add_event(eventstr, "%s"); - vec_free(eventstr); - - /* event 2 (thread ready) */ - eventstr = format(0, "THREAD/THREADY"); - vec_add1(eventstr, 0); - find_or_add_event(eventstr, "%s"); - vec_free(eventstr); - - /* event 3 (function enter) */ - eventstr = format(0, "FUNC/ENTER"); - vec_add1(eventstr, 0); - find_or_add_event(eventstr, "0x%x"); - vec_free(eventstr); - - /* event 4 (function enter) */ - eventstr = format(0, "FUNC/EXIT"); - vec_add1(eventstr, 0); - find_or_add_event(eventstr, "0x%x"); - vec_free(eventstr); - } -} - -/* - * alpha_compare_tracks - */ -static int alpha_compare_tracks(const void *a1, const void *a2) -{ - int i; - track_t *t1 = (track_t *)a1; - track_t *t2 = (track_t *)a2; - u8 *s1 = &the_strtab[t1->strtab_offset]; - u8 *s2 = &the_strtab[t2->strtab_offset]; - - for (i = 0; s1[i] && s2[i]; i++) { - if (s1[i] < s2[i]) - return(-1); - if (s1[i] > s2[i]) - return(1); - } - return(0); -} - -/* - * alpha_sort_tracks - * Alphabetically sort tracks, set up a mapping - * vector so we can quickly map the original track index to - * the new/improved/alpha-sorted index - */ -void alpha_sort_tracks(void) -{ - track_t *this_track; - int i; - - qsort(the_tracks, vec_len(the_tracks), sizeof(track_t), - alpha_compare_tracks); - - vec_validate(track_alpha_map, vec_len(the_tracks)); - _vec_len(track_alpha_map) = vec_len(the_tracks); - - for (i = 0; i < vec_len(the_tracks); i++) { - this_track = &the_tracks[i]; - track_alpha_map[this_track->original_index] = i; - } -} - -/* - * fixup_event_tracks - * Use the track alpha mapping to account for the alphabetic - * sort performed by the previous routine - */ -void fixup_event_tracks(void) -{ - int i; - u32 old_track; - - for (i = 0; i < vec_len(the_events); i++) { - old_track = the_events[i].track_id; - the_events[i].track_id = track_alpha_map[old_track]; - } -} - -/* Indispensable for debugging in gdb... */ - -u32 vl(void *x) -{ - return vec_len(x); -} diff --git a/perftool/cpel_util.h b/perftool/cpel_util.h deleted file mode 100644 index b76f7a4b..00000000 --- a/perftool/cpel_util.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2006-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 __cpel_util_h__ -#define __cpel_util_h__ - -/* - * Our idea of an event, as opposed to a CPEL event - */ -typedef struct evt_ { - u64 timestamp; - u32 track_id; - u32 event_id; - u32 datum; -} evt_t; - -evt_t *the_events; - -/* - * Track object, so we can sort the tracks alphabetically and - * fix the events later - */ -typedef struct track_ { - u32 original_index; - u32 strtab_offset; -} track_t; - -track_t *the_tracks; -u32 *track_alpha_map; - -event_definition_t *the_event_definitions; -i64 min_timestamp; - -/* Hash tables, used to find previous instances of the same items */ -uword *the_track_hash; -uword *the_msg_event_hash; -uword *the_strtab_hash; -uword *the_pidtid_hash; -uword *the_pid_to_name_hash; -u8 *the_strtab; - -u32 find_or_add_strtab(void *s_arg); -u32 find_or_add_track(void *s_arg); -u32 find_or_add_event(void *s_arg, char *datum_format); -int write_string_table(FILE *ofp); -int write_cpel_header(FILE *ofp, u32 nsections); -int write_event_defs(FILE *ofp); -u64 ntohll (u64 x); -int write_events(FILE *ofp, u64 clock_ticks_per_second); -int write_track_defs(FILE *ofp); -void cpel_util_init (void); -void alpha_sort_tracks(void); -void fixup_event_tracks(void); - -#endif /* __cpel_util_h__ */ diff --git a/perftool/cpelatency.c b/perftool/cpelatency.c deleted file mode 100644 index f40a1fb1..00000000 --- a/perftool/cpelatency.c +++ /dev/null @@ -1,927 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2006-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 -#include "cpel.h" -#include - -char *time_format = "%.03d:%.02d:%.02d:%.03d:%.03d "; -static char version[] = "cpelatency 2.0"; - -#define USEC_PER_MS 1000LL -#define USEC_PER_SECOND (1000*USEC_PER_MS) -#define USEC_PER_MINUTE (60*USEC_PER_SECOND) -#define USEC_PER_HOUR (60*USEC_PER_MINUTE) - -uword *the_strtab_hash; /* (name, base-VA) hash of all string tables */ -uword *the_evtdef_hash; /* (event-id, event-definition) hash */ -uword *the_trackdef_hash; /* (track-id, track-definition) hash */ -uword *the_pidtid_hash; /* ("pid:xxx tid:yy", track-definition) hash */ - -f64 ticks_per_us; -u32 start_event_code = 2; /* default: XR thread ready event */ -u32 end_event_code = 1; /* default: XR thread running event */ -int exclude_kernel_from_summary_stats=1; -int summary_stats_only; -int scatterplot; -u8 *name_filter; -int have_trackdefs; - -typedef enum { - SORT_MAX_TIME=1, - SORT_MAX_OCCURRENCES, - SORT_NAME, -} sort_t; - -sort_t sort_type = SORT_MAX_TIME; - -int widest_name_format=5; -int widest_track_format=20; - -typedef struct bound_event_ { - u32 event_code; - u8 *event_str; - u8 *datum_str; - u32 is_strtab_ref; -} bound_event_t; - -bound_event_t *bound_events; - -typedef struct bound_track_ { - u32 track; - u8 *track_str; - u64 state_start_ticks; - u64 *ticks_in_state; /* vector of state occurrences */ - f64 mean_ticks_in_state; - f64 variance_ticks_in_state; - f64 total_ticks_in_state; -} bound_track_t; - -bound_track_t *bound_tracks; - -void fatal(char *s) -{ - fprintf(stderr, "%s", s); - exit(1); -} - -typedef enum { - PASS1=1, - PASS2=2, -} pass_t; - -typedef struct { - int (*pass1)(cpel_section_header_t *, int, FILE *); - int (*pass2)(cpel_section_header_t *, int, FILE *); -} section_processor_t; - -int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - fprintf(ofp, "Bad (type 0) section, skipped...\n"); - return(0); -} - -int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - return(0); -} - -int strtab_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - uword *p; - u8 *strtab_data_area = (u8 *)(sh+1); - - /* Multiple string tables with the same name are Bad... */ - p = hash_get_mem(the_strtab_hash, strtab_data_area); - if (p) { - fprintf(ofp, "Duplicate string table name %s", strtab_data_area); - } - /* - * Looks funny, but we really do want key = first string in the - * table, value = address(first string in the table) - */ - hash_set_mem(the_strtab_hash, strtab_data_area, strtab_data_area); - if (verbose) { - fprintf(ofp, "String Table %s\n", strtab_data_area); - } - return(0); -} - -int evtdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - int i, nevents; - event_definition_section_header_t *edh; - event_definition_t *ep; - u8 *this_strtab; - u32 event_code; - uword *p; - bound_event_t *bp; - int thislen; - - edh = (event_definition_section_header_t *)(sh+1); - nevents = ntohl(edh->number_of_event_definitions); - - if (verbose) { - fprintf(ofp, "Event Definition Section: %d definitions\n", - nevents); - } - - p = hash_get_mem(the_strtab_hash, edh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - this_strtab = (u8 *)p[0]; - - ep = (event_definition_t *)(edh+1); - - for (i = 0; i < nevents; i++) { - event_code = ntohl(ep->event); - p = hash_get(the_evtdef_hash, event_code); - if (p) { - fprintf(ofp, "Event %d redefined, retain first definition\n", - event_code); - continue; - } - vec_add2(bound_events, bp, 1); - bp->event_code = event_code; - bp->event_str = this_strtab + ntohl(ep->event_format); - bp->datum_str = this_strtab + ntohl(ep->datum_format); - bp->is_strtab_ref = 0; - /* Decide if the datum format is a %s format => strtab reference */ - { - int j; - int seen_percent=0; - - for (j = 0; j < strlen((char *) bp->datum_str); j++) { - if (bp->datum_str[j] == '%'){ - seen_percent=1; - continue; - } - if (seen_percent && bp->datum_str[j] == 's') { - bp->is_strtab_ref = 1; - } - } - } - - hash_set(the_evtdef_hash, event_code, bp - bound_events); - - thislen = strlen((char *) bp->event_str); - if (thislen > widest_name_format) - widest_name_format = thislen; - - ep++; - } - return (0); -} - -int trackdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - int i, nevents; - track_definition_section_header_t *tdh; - track_definition_t *tp; - u8 *this_strtab; - u32 track_code; - uword *p; - bound_track_t *btp; - int thislen; - u8 *pidstr; - u8 *pidtid_str; - u8 *cp; - int tid, pid; - - tdh = (track_definition_section_header_t *)(sh+1); - nevents = ntohl(tdh->number_of_track_definitions); - - if (verbose) { - fprintf(ofp, "Track Definition Section: %d definitions\n", - nevents); - } - - p = hash_get_mem(the_strtab_hash, tdh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - this_strtab = (u8 *)p[0]; - - tp = (track_definition_t *)(tdh+1); - - for (i = 0; i < nevents; i++) { - track_code = ntohl(tp->track); - p = hash_get(the_trackdef_hash, track_code); - if (p) { - fprintf(stderr, "track %d redefined, retain first definition\n", - track_code); - continue; - } - vec_add2(bound_tracks, btp, 1); - btp->track = track_code; - btp->track_str = this_strtab + ntohl(tp->track_format); - hash_set(the_trackdef_hash, track_code, btp - bound_tracks); - - if (verbose) { - fprintf(stderr, "adding track '%s'\n", btp->track_str); - } - - thislen = strlen((char *) btp->track_str); - if (thislen > widest_track_format) - widest_track_format = thislen; - - /* convert track_str "eth_server t11(20498)" to "pid:20498 tid:11" */ - cp = btp->track_str; - while (*cp && *cp != '(') - cp++; - if (!*cp) { - fprintf(stderr, "error canonicalizing '%s'\n", btp->track_str); - goto out; - } - pidstr = cp+1; /* remember location of PID */ - - while (cp > btp->track_str && *cp != 't') - cp--; - - if (cp == btp->track_str) { - fprintf(stderr, "error canonicalizing '%s'\n", btp->track_str); - goto out; - } - tid = atol((char *)(cp+1)); - pid = atol((char *) pidstr); - pidtid_str = format(0, "pid:%d tid:%d", pid, tid); - vec_add1(pidtid_str, 0); - - /* - * Note: duplicates are possible due to thread create / - * thread destroy operations. - */ - p = hash_get_mem(the_pidtid_hash, pidtid_str); - if (p) { - vec_free(pidtid_str); - goto out; - } - hash_set_mem(the_pidtid_hash, pidtid_str, btp - bound_tracks); - - out: - tp++; - } - have_trackdefs = 1; - return (0); -} - -int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - if (verbose) { - fprintf(ofp, "Unsupported type %d section\n", - ntohl(sh->section_type)); - } - return(0); -} - -int event_pass2(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - event_section_header_t *eh; - int nevents; - int i; - uword *p; - event_entry_t *ep; - u64 now; - u32 time0, time1; - u32 track_code; - u8 *this_strtab; - u64 ticks_in_state; - bound_track_t *btp; - bound_track_t *state_track=0; - u8 *pidtid_str; - u8 *pidtid_dup; - u8 *ecp; - u32 event_code; - - eh = (event_section_header_t *)(sh+1); - nevents = ntohl(eh->number_of_events); - ticks_per_us = ((double)ntohl(eh->clock_ticks_per_second)) / 1e6; - - if (verbose) { - fprintf(ofp, "%.3f ticks_per_us\n", ticks_per_us); - } - - ep = (event_entry_t *)(eh+1); - - p = hash_get_mem(the_strtab_hash, eh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - this_strtab = (u8 *)p[0]; - - /* - * Some logger implementation that doesn't produce - * trackdef sections, synthesize the bound_tracks vector - */ - if (!have_trackdefs) { - for (i = 0; i < nevents; i++) { - track_code = ntohl(ep->track); - pidtid_dup = format(0, "%d", track_code); - vec_add1(pidtid_dup, 0); - p = hash_get_mem(the_pidtid_hash, pidtid_dup); - if (!p) { - vec_add2(bound_tracks, btp, 1); - btp->track = track_code; - btp->track_str = pidtid_dup; - hash_set(the_trackdef_hash, track_code, btp - bound_tracks); - hash_set_mem(the_pidtid_hash, pidtid_dup, btp - bound_tracks); - } else { - vec_free(pidtid_dup); - } - ep++; - } - } - - ep = (event_entry_t *)(eh+1); - - for (i = 0; i < nevents; i++) { - time0 = ntohl (ep->time[0]); - time1 = ntohl (ep->time[1]); - - now = (((u64) time0)<<32) | time1; - - event_code = ntohl(ep->event_code); - - /* Find the corresponding track via the pidtid hash table */ - if (event_code == start_event_code || event_code == end_event_code) { - if (have_trackdefs) { - pidtid_str = this_strtab + ntohl(ep->event_datum); - pidtid_dup = format(0, (char *) pidtid_str); - vec_add1(pidtid_dup, 0); - ecp = &pidtid_dup[vec_len(pidtid_dup)-1]; - while (*--ecp == ' ') - *ecp = 0; - } else { - pidtid_dup = format(0, "%d", ntohl(ep->track)); - vec_add1(pidtid_dup, 0); - } - - p = hash_get_mem(the_pidtid_hash, pidtid_dup); - if (!p) { - fprintf(stderr, "warning: couldn't find '%s'\n", - pidtid_dup); - vec_free(pidtid_dup); - ep++; - continue; - } - state_track = &bound_tracks[p[0]]; - } - /* Found the start-event code ? */ - if (event_code == start_event_code) { - state_track->state_start_ticks = now; - } else if (event_code == end_event_code) { - /* - * Add a ticks-in-state record, unless - * e.g. the log started with the exit event - */ - if (state_track->state_start_ticks) { - ticks_in_state = now - state_track->state_start_ticks; - vec_add1(state_track->ticks_in_state, ticks_in_state); - state_track->state_start_ticks = 0; - } - /* Otherwise, nothing */ - } - ep++; - } - return(0); -} - -/* - * Note: If necessary, add passes / columns to this table to - * handle section order dependencies. - */ - -section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] = -{ - {bad_section, noop_pass}, /* type 0 -- f**ked */ - {strtab_pass1, noop_pass}, /* type 1 -- STRTAB */ - {unsupported_pass, noop_pass}, /* type 2 -- SYMTAB */ - {evtdef_pass1, noop_pass}, /* type 3 -- EVTDEF */ - {trackdef_pass1, noop_pass}, /* type 4 -- TRACKDEF */ - {noop_pass, event_pass2}, /* type 5 -- EVENTS */ -}; - - -int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp, - pass_t pass) -{ - u32 type; - type = ntohl(sh->section_type); - int rv; - int (*fp)(cpel_section_header_t *, int, FILE *); - - if (type > CPEL_NUM_SECTION_TYPES) { - fprintf(stderr, "Unknown section type %d\n", type); - return(1); - } - switch(pass) { - case PASS1: - fp = processors[type].pass1; - break; - - case PASS2: - fp = processors[type].pass2; - break; - - default: - fprintf(stderr, "Unknown pass %d\n", pass); - return(1); - } - - rv = (*fp)(sh, verbose, ofp); - - return(rv); -} - -int cpel_dump_file_header(cpel_file_header_t *fh, int verbose, FILE *ofp) -{ - time_t file_time; - - if (verbose) { - fprintf(ofp, "CPEL file: %s-endian, version %d\n", - ((fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) ? - "little" : "big"), - fh->endian_version & CPEL_FILE_VERSION_MASK); - - file_time = ntohl(fh->file_date); - - fprintf(ofp, "File created %s", ctime(&file_time)); - fprintf(ofp, "File has %d sections\n", - ntohs(fh->nsections)); - } - - return(0); -} - - -int cpel_dump(u8 *cpel, int verbose, FILE *ofp) -{ - cpel_file_header_t *fh; - cpel_section_header_t *sh; - u16 nsections; - u32 section_size; - int i; - - /* First, the file header */ - fh = (cpel_file_header_t *)cpel; - if (fh->endian_version != CPEL_FILE_VERSION) { - if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) { - fprintf(stderr, "Little endian data format not supported\n"); - return(1); - } - fprintf(stderr, "Unsupported file version 0x%x\n", - fh->endian_version); - return(1); - } - cpel_dump_file_header(fh, verbose, ofp); - nsections = ntohs(fh->nsections); - - /* - * Take two passes through the file. PASS1 builds - * data structures, PASS2 actually dumps the file. - * Just in case the sections are in an unobvious order. - */ - sh = (cpel_section_header_t *)(fh+1); - for (i = 0; i < nsections; i++) { - section_size = ntohl(sh->data_length); - - if(verbose) { - fprintf(ofp, "Section type %d, size %d\n", ntohl(sh->section_type), - section_size); - } - - if(process_section(sh, verbose, ofp, PASS1)) - return(1); - - sh++; - sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); - } - - sh = (cpel_section_header_t *)(fh+1); - for (i = 0; i < nsections; i++) { - if(process_section(sh, verbose, ofp, PASS2)) - return(1); - section_size = ntohl(sh->data_length); - sh++; - sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); - } - return(0); -} - -void compute_state_statistics(int verbose, FILE *ofp) -{ - int i, j; - bound_track_t *bp; - f64 fticks; - - /* Across the bound tracks */ - for (i = 0; i < vec_len(bound_tracks); i++) { - bp = &bound_tracks[i]; - bp->mean_ticks_in_state = 0.0; - bp->variance_ticks_in_state = 0.0; - bp->total_ticks_in_state = 0.0; - for (j = 0; j < vec_len(bp->ticks_in_state); j++) { - bp->total_ticks_in_state += (f64) bp->ticks_in_state[j]; - } - /* Compute mean */ - if (vec_len(bp->ticks_in_state)) { - bp->mean_ticks_in_state = bp->total_ticks_in_state / - ((f64) vec_len(bp->ticks_in_state)); - } - /* Accumulate sum: (Xi-Xbar)**2 */ - for (j = 0; j < vec_len(bp->ticks_in_state); j++) { - fticks = bp->ticks_in_state[j]; - bp->variance_ticks_in_state += - (fticks - bp->mean_ticks_in_state)* - (fticks - bp->mean_ticks_in_state); - } - /* Compute s**2, the unbiased estimator of sigma**2 */ - if (vec_len(bp->ticks_in_state) > 1) { - bp->variance_ticks_in_state /= (f64) - (vec_len(bp->ticks_in_state)-1); - } - } -} - -int track_compare_max (const void *arg1, const void *arg2) -{ - bound_track_t *a1 = (bound_track_t *)arg1; - bound_track_t *a2 = (bound_track_t *)arg2; - f64 v1, v2; - - v1 = a1->total_ticks_in_state; - v2 = a2->total_ticks_in_state; - - if (v1 < v2) - return (1); - else if (v1 == v2) - return (0); - else return (-1); -} - -int track_compare_occurrences (const void *arg1, const void *arg2) -{ - bound_track_t *a1 = (bound_track_t *)arg1; - bound_track_t *a2 = (bound_track_t *)arg2; - f64 v1, v2; - - v1 = (f64) vec_len(a1->ticks_in_state); - v2 = (f64) vec_len(a2->ticks_in_state); - - if (v1 < v2) - return (1); - else if (v1 == v2) - return (0); - else return (-1); -} - -int track_compare_name (const void *arg1, const void *arg2) -{ - bound_track_t *a1 = (bound_track_t *)arg1; - bound_track_t *a2 = (bound_track_t *)arg2; - - return (strcmp((char *)(a1->track_str), (char *)(a2->track_str))); -} - -void sort_state_statistics(sort_t type, FILE *ofp) -{ - int (*compare)(const void *, const void *); - - if (summary_stats_only) - return; - - switch(type) { - case SORT_MAX_TIME: - fprintf(ofp, "Results sorted by max time in state.\n\n"); - compare = track_compare_max; - break; - - case SORT_MAX_OCCURRENCES: - fprintf(ofp, "Results sorted by max occurrences of state.\n\n"); - compare = track_compare_occurrences; - break; - - case SORT_NAME: - compare = track_compare_name; - fprintf(ofp, "Results sorted by process name, thread ID, PID\n\n"); - break; - - default: - fatal("sort type not set?"); - } - - qsort (bound_tracks, vec_len(bound_tracks), - sizeof (bound_track_t), compare); -} - -void print_state_statistics(int verbose, FILE *ofp) -{ - int i,j; - u8 *trackpad; - bound_track_t *bp; - f64 total_time = 0.0; - f64 total_switches = 0.0; - - trackpad = format(0, "%%-%ds ", widest_track_format); - vec_add1(trackpad, 0); - - if (!summary_stats_only) { - fprintf(ofp, (char *)trackpad, "ProcName Thread(PID)"); - fprintf(ofp, " Mean(us) Stdev(us) Total(us) N\n"); - } - - for (i = 0; i < vec_len(bound_tracks); i++) { - bp = &bound_tracks[i]; - if (bp->mean_ticks_in_state == 0.0) - continue; - - if (name_filter && - strncmp((char *)bp->track_str, (char *)name_filter, - strlen((char *)name_filter))) - continue; - - /* - * Exclude kernel threads (e.g. idle thread) from - * state statistics - */ - if (exclude_kernel_from_summary_stats && - !strncmp((char *) bp->track_str, "kernel ", 7)) - continue; - - total_switches += (f64) vec_len(bp->ticks_in_state); - - if (!summary_stats_only) { - fprintf(ofp, (char *) trackpad, bp->track_str); - fprintf(ofp, "%10.3f +- %10.3f", - bp->mean_ticks_in_state / ticks_per_us, - sqrt(bp->variance_ticks_in_state) - / ticks_per_us); - fprintf(ofp, "%12.3f", - bp->total_ticks_in_state / ticks_per_us); - fprintf(ofp, "%8d\n", vec_len(bp->ticks_in_state)); - } - - if (scatterplot) { - for (j = 0; j < vec_len(bp->ticks_in_state); j++) { - fprintf(ofp, "%.3f\n", - (f64)bp->ticks_in_state[j] / ticks_per_us); - } - } - - total_time += bp->total_ticks_in_state; - } - - if (!summary_stats_only) - fprintf(ofp, "\n"); - fprintf(ofp, "Note: the following statistics %s kernel-thread activity.\n", - exclude_kernel_from_summary_stats ? "exclude" : "include"); - if (name_filter) - fprintf(ofp, - "Note: only pid/proc/threads matching '%s' are included.\n", - name_filter); - - fprintf(ofp, - "Total time in state: %10.3f (us), Total state occurrences: %.0f\n", - total_time / ticks_per_us, total_switches); - fprintf(ofp, "Average time in state: %10.3f (us)\n", - (total_time / total_switches) / ticks_per_us); - fprintf(ofp, "State start event: %d, state end event: %d\n", - start_event_code, end_event_code); -} - -char *mapfile (char *file) -{ - struct stat statb; - char *rv; - int maphfile; - size_t mapfsize; - - maphfile = open (file, O_RDONLY); - - if (maphfile < 0) - { - fprintf (stderr, "Couldn't read %s, skipping it...\n", file); - return (NULL); - } - - if (fstat (maphfile, &statb) < 0) - { - fprintf (stderr, "Couldn't get size of %s, skipping it...\n", file); - return (NULL); - } - - /* Don't try to mmap directories, FIFOs, semaphores, etc. */ - if (! (statb.st_mode & S_IFREG)) { - fprintf (stderr, "%s is not a regular file, skipping it...\n", file); - return (NULL); - } - - mapfsize = statb.st_size; - - if (mapfsize < 3) - { - fprintf (stderr, "%s zero-length, skipping it...\n", file); - close (maphfile); - return (NULL); - } - - rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0); - - if (rv == 0) - { - fprintf (stderr, "%s problem mapping, I quit...\n", file); - exit (-1); - } - close (maphfile); - return (rv); -} - -/* - * main - */ -int main (int argc, char **argv) -{ - char *cpel_file = 0; - char *outputfile = 0; - FILE *ofp; - char *cpel; - int verbose=0; - int curarg=1; - - while (curarg < argc) { - if (!strncmp(argv[curarg], "--input-file", 3)) { - curarg++; - if (curarg < argc) { - cpel_file = argv[curarg]; - curarg++; - continue; - } - fatal("Missing filename after --input-file\n"); - } - if (!strncmp(argv[curarg], "--output-file", 3)) { - curarg ++; - if (curarg < argc) { - outputfile = argv[curarg]; - curarg ++; - continue; - } - fatal("Missing filename after --output-file\n"); - } - if (!strncmp(argv[curarg], "--verbose", 3)) { - curarg++; - verbose++; - continue; - } - if (!strncmp(argv[curarg], "--scatterplot", 4)) { - curarg++; - scatterplot=1; - continue; - } - - if (!strncmp(argv[curarg], "--start-event", 4)) { - curarg++; - if (curarg < argc) { - start_event_code = atol(argv[curarg]); - curarg ++; - continue; - } - fatal("Missing integer after --start-event\n"); - } - if (!strncmp(argv[curarg], "--end-event", 4)) { - curarg++; - if (curarg < argc) { - end_event_code = atol(argv[curarg]); - curarg ++; - continue; - } - fatal("Missing integer after --end-event\n"); - } - if (!strncmp(argv[curarg], "--max-time-sort", 7)) { - sort_type = SORT_MAX_TIME; - curarg++; - continue; - } - if (!strncmp(argv[curarg], "--max-occurrence-sort", 7)) { - sort_type = SORT_MAX_OCCURRENCES; - curarg++; - continue; - } - if (!strncmp(argv[curarg], "--name-sort", 3)) { - sort_type = SORT_NAME; - curarg++; - continue; - } - if (!strncmp(argv[curarg], "--kernel-included", 3)) { - exclude_kernel_from_summary_stats = 0; - curarg++; - continue; - } - if (!strncmp(argv[curarg], "--summary", 3)) { - summary_stats_only=1; - curarg++; - continue; - } - if (!strncmp(argv[curarg], "--filter", 3)) { - curarg ++; - if (curarg < argc) { - name_filter = (u8 *) argv[curarg]; - curarg ++; - continue; - } - fatal("Missing filter string after --filter\n"); - } - - - usage: - fprintf(stderr, - "cpelatency --input-file [--output-file ]\n"); - fprintf(stderr, - " [--start-event ] [--verbose]\n"); - fprintf(stderr, - " [--end-event ]\n"); - fprintf(stderr, - " [--max-time-sort(default) | --max-occurrence-sort |\n"); - - fprintf(stderr, - " --name-sort-sort] [--kernel-included]\n"); - - fprintf(stderr, - " [--summary-stats-only] [--scatterplot]\n"); - - fprintf(stderr, "%s\n", version); - exit(1); - } - - if (cpel_file == 0) - goto usage; - - cpel = mapfile(cpel_file); - if (cpel == 0) { - fprintf(stderr, "Couldn't map %s...\n", cpel_file); - exit(1); - } - - if (!outputfile) { - ofp = fdopen(1, "w"); - if (ofp == NULL) { - fprintf(stderr, "Couldn't fdopen(1)?\n"); - exit(1); - } - } else { - ofp = fopen(outputfile, "w"); - if (ofp == NULL) { - fprintf(stderr, "Couldn't create %s...\n", outputfile); - exit(1); - } - } - - the_strtab_hash = hash_create_string (0, sizeof (uword)); - the_evtdef_hash = hash_create (0, sizeof (uword)); - the_trackdef_hash = hash_create (0, sizeof (uword)); - the_pidtid_hash = hash_create_string (0, sizeof(uword)); - - if (cpel_dump((u8 *)cpel, verbose, ofp)) { - if (outputfile) - unlink(outputfile); - } - - compute_state_statistics(verbose, ofp); - sort_state_statistics(sort_type, ofp); - print_state_statistics(verbose, ofp); - - fclose(ofp); - return(0); -} diff --git a/perftool/cpeldump.c b/perftool/cpeldump.c deleted file mode 100644 index 9011bd03..00000000 --- a/perftool/cpeldump.c +++ /dev/null @@ -1,638 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2006-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 -#include "cpel.h" - -char *time_format = "%.03d:%.02d:%.02d:%.03d:%.03d "; -static char version[] = "cpeldump 2.0"; - -#define USEC_PER_MS 1000LL -#define USEC_PER_SECOND (1000*USEC_PER_MS) -#define USEC_PER_MINUTE (60*USEC_PER_SECOND) -#define USEC_PER_HOUR (60*USEC_PER_MINUTE) - -uword *the_strtab_hash; /* (name, base-VA) hash of all string tables */ -uword *the_evtdef_hash; /* (event-id, event-definition) hash */ -uword *the_trackdef_hash; /* (track-id, track-definition) hash */ - -int widest_name_format=5; -int widest_track_format=5; - -typedef struct bound_event_ { - u32 event_code; - u8 *event_str; - u8 *datum_str; - u32 is_strtab_ref; -} bound_event_t; - -bound_event_t *bound_events; - -typedef struct bound_track_ { - u32 track; - u8 *track_str; -} bound_track_t; - -bound_track_t *bound_tracks; - -void fatal(char *s) -{ - fprintf(stderr, "%s", s); - exit(1); -} - -typedef enum { - PASS1=1, - PASS2=2, -} pass_t; - -typedef struct { - int (*pass1)(cpel_section_header_t *, int, FILE *); - int (*pass2)(cpel_section_header_t *, int, FILE *); -} section_processor_t; - -int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - fprintf(ofp, "Bad (type 0) section, skipped...\n"); - return(0); -} - -int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - return(0); -} - -int strtab_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - uword *p; - u8 *strtab_data_area = (u8 *)(sh+1); - - /* Multiple string tables with the same name are Bad... */ - p = hash_get_mem(the_strtab_hash, strtab_data_area); - if (p) { - fprintf(ofp, "Duplicate string table name %s", strtab_data_area); - } - /* - * Looks funny, but we really do want key = first string in the - * table, value = address(first string in the table) - */ - hash_set_mem(the_strtab_hash, strtab_data_area, strtab_data_area); - if (verbose) { - fprintf(stderr, "String Table %s\n", strtab_data_area); - } - return(0); -} - -int evtdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - int i, nevents; - event_definition_section_header_t *edh; - event_definition_t *ep; - u8 *this_strtab; - u32 event_code; - uword *p; - bound_event_t *bp; - int thislen; - - edh = (event_definition_section_header_t *)(sh+1); - nevents = ntohl(edh->number_of_event_definitions); - - if (verbose) { - fprintf(stderr, "Event Definition Section: %d definitions\n", - nevents); - } - - p = hash_get_mem(the_strtab_hash, edh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - this_strtab = (u8 *)p[0]; - - ep = (event_definition_t *)(edh+1); - - for (i = 0; i < nevents; i++) { - event_code = ntohl(ep->event); - p = hash_get(the_evtdef_hash, event_code); - if (p) { - fprintf(ofp, "Event %d redefined, retain first definition\n", - event_code); - continue; - } - vec_add2(bound_events, bp, 1); - bp->event_code = event_code; - bp->event_str = this_strtab + ntohl(ep->event_format); - bp->datum_str = this_strtab + ntohl(ep->datum_format); - bp->is_strtab_ref = 0; - /* Decide if the datum format is a %s format => strtab reference */ - { - int j; - int seen_percent=0; - - for (j = 0; j < strlen((char *)bp->datum_str); j++) { - if (bp->datum_str[j] == '%'){ - seen_percent=1; - continue; - } - if (seen_percent && bp->datum_str[j] == 's') { - bp->is_strtab_ref = 1; - } - } - } - - hash_set(the_evtdef_hash, event_code, bp - bound_events); - - thislen = strlen((char *)bp->event_str); - if (thislen > widest_name_format) - widest_name_format = thislen; - - ep++; - } - return (0); -} - -int trackdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - int i, nevents; - track_definition_section_header_t *tdh; - track_definition_t *tp; - u8 *this_strtab; - u32 track_code; - uword *p; - bound_track_t *btp; - int thislen; - - tdh = (track_definition_section_header_t *)(sh+1); - nevents = ntohl(tdh->number_of_track_definitions); - - if (verbose) { - fprintf(stderr, "Track Definition Section: %d definitions\n", - nevents); - } - - p = hash_get_mem(the_strtab_hash, tdh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - this_strtab = (u8 *)p[0]; - - tp = (track_definition_t *)(tdh+1); - - for (i = 0; i < nevents; i++) { - track_code = ntohl(tp->track); - p = hash_get(the_trackdef_hash, track_code); - if (p) { - fprintf(ofp, "track %d redefined, retain first definition\n", - track_code); - continue; - } - vec_add2(bound_tracks, btp, 1); - btp->track = track_code; - btp->track_str = this_strtab + ntohl(tp->track_format); - hash_set(the_trackdef_hash, track_code, btp - bound_tracks); - - thislen = strlen((char *)btp->track_str); - if (thislen > widest_track_format) - widest_track_format = thislen; - tp++; - } - return (0); -} - -int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - if (verbose) { - fprintf(stderr, "Unsupported type %d section\n", - ntohl(sh->section_type)); - } - return(0); -} - -int event_pass2(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - event_section_header_t *eh; - f64 ticks_per_us; - u32 event_code, track_code; - u64 starttime = 0xFFFFFFFFFFFFFFFFULL; - int nevents; - int i; - uword *p; - event_entry_t *ep; - u64 now; - u64 delta; - u32 hours, minutes, seconds, msec, usec; - u32 time0, time1; - double d; - bound_event_t *bp; - bound_event_t generic_event; - bound_track_t *tp=0; - bound_track_t generic_track; - u32 last_track_code; - u8 *s, *evtpad, *trackpad; - u8 *this_strtab; - - generic_event.event_str = (u8 *)"%d"; - generic_event.datum_str = (u8 *)"0x%08x"; - generic_event.is_strtab_ref = 0; - - generic_track.track_str = (u8 *)"%d"; - last_track_code = 0xdeadbeef; - - eh = (event_section_header_t *)(sh+1); - nevents = ntohl(eh->number_of_events); - ticks_per_us = ((double)ntohl(eh->clock_ticks_per_second)) / 1e6; - - if (verbose) { - fprintf(stderr, "Event section: %d events, %.3f ticks_per_us\n", - nevents, ticks_per_us); - } - - ep = (event_entry_t *)(eh+1); - - p = hash_get_mem(the_strtab_hash, eh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - this_strtab = (u8 *)p[0]; - - evtpad = format(0, "%%-%ds ", widest_name_format); - vec_add1(evtpad, 0); - trackpad = format(0, "%%-%ds ", widest_track_format); - vec_add1(trackpad, 0); - - for (i = 0; i < nevents; i++) { - time0 = ntohl (ep->time[0]); - time1 = ntohl (ep->time[1]); - - now = (((u64) time0)<<32) | time1; - - /* Convert from bus ticks to usec */ - d = now; - d /= ticks_per_us; - - now = d; - - if (starttime == 0xFFFFFFFFFFFFFFFFULL) - starttime = now; - - delta = now - starttime; - - /* Delta = time since first event, in usec */ - - hours = delta / USEC_PER_HOUR; - if (hours) - delta -= ((u64) hours * USEC_PER_HOUR); - minutes = delta / USEC_PER_MINUTE; - if (minutes) - delta -= ((u64) minutes * USEC_PER_MINUTE); - seconds = delta / USEC_PER_SECOND; - if (seconds) - delta -= ((u64) seconds * USEC_PER_SECOND); - msec = delta / USEC_PER_MS; - if (msec) - delta -= ((u64) msec * USEC_PER_MS); - - usec = delta; - - /* Output the timestamp */ - fprintf(ofp, time_format, hours, minutes, seconds, msec, usec); - - /* output the track */ - track_code = ntohl(ep->track); - - if (track_code != last_track_code) { - p = hash_get(the_trackdef_hash, track_code); - if (p) { - tp = &bound_tracks[p[0]]; - } else { - tp = &generic_track; - } - } - s = format(0, (char *)tp->track_str, track_code); - vec_add1(s, 0); - fprintf(ofp, (char *)trackpad, s); - vec_free(s); - - /* output the event and datum */ - if (0 && verbose) { - fprintf(stderr, "raw event code %d, raw event datum 0x%x\n", - ntohl(ep->event_code), ntohl(ep->event_datum)); - } - - event_code = ntohl(ep->event_code); - p = hash_get(the_evtdef_hash, event_code); - if (p) { - bp = &bound_events[p[0]]; - } else { - bp = &generic_event; - } - s = format(0, (char *)bp->event_str, ntohl(ep->event_code)); - vec_add1(s, 0); - fprintf(ofp, (char *)evtpad, s); - vec_free(s); - if (bp->is_strtab_ref) { - fprintf(ofp, (char *) bp->datum_str, - &this_strtab[ntohl(ep->event_datum)]); - } else { - fprintf(ofp, (char *) bp->datum_str, ntohl(ep->event_datum)); - } - fputs("\n", ofp); - ep++; - } - vec_free(evtpad); - vec_free(trackpad); - return(0); -} - -/* - * Note: If necessary, add passes / columns to this table to - * handle section order dependencies. - */ - -section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] = -{ - {bad_section, noop_pass}, /* type 0 -- f**ked */ - {strtab_pass1, noop_pass}, /* type 1 -- STRTAB */ - {unsupported_pass, noop_pass}, /* type 2 -- SYMTAB */ - {evtdef_pass1, noop_pass}, /* type 3 -- EVTDEF */ - {trackdef_pass1, noop_pass}, /* type 4 -- TRACKDEF */ - {noop_pass, event_pass2}, /* type 5 -- EVENTS */ -}; - - -int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp, - pass_t pass) -{ - u32 type; - type = ntohl(sh->section_type); - int rv; - int (*fp)(cpel_section_header_t *, int, FILE *); - - if (type > CPEL_NUM_SECTION_TYPES) { - fprintf(stderr, "Unknown section type %d\n", type); - return(1); - } - switch(pass) { - case PASS1: - fp = processors[type].pass1; - break; - - case PASS2: - fp = processors[type].pass2; - break; - - default: - fprintf(stderr, "Unknown pass %d\n", pass); - return(1); - } - - rv = (*fp)(sh, verbose, ofp); - - return(rv); -} - -int cpel_dump_file_header(cpel_file_header_t *fh, int verbose, FILE *ofp) -{ - time_t file_time; - - if (verbose) { - fprintf(stderr, "CPEL file: %s-endian, version %d\n", - ((fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) ? - "little" : "big"), - fh->endian_version & CPEL_FILE_VERSION_MASK); - - file_time = ntohl(fh->file_date); - - fprintf(stderr, "File created %s", ctime(&file_time)); - fprintf(stderr, "File has %d sections\n", - ntohs(fh->nsections)); - } - - return(0); -} - - -int cpel_dump(u8 *cpel, int verbose, FILE *ofp) -{ - cpel_file_header_t *fh; - cpel_section_header_t *sh; - u16 nsections; - u32 section_size; - int i; - - /* First, the file header */ - fh = (cpel_file_header_t *)cpel; - if (fh->endian_version != CPEL_FILE_VERSION) { - if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) { - fprintf(stderr, "Little endian data format not supported\n"); - return(1); - } - fprintf(stderr, "Unsupported file version 0x%x\n", - fh->endian_version); - return(1); - } - cpel_dump_file_header(fh, verbose, ofp); - nsections = ntohs(fh->nsections); - - /* - * Take two passes through the file. PASS1 builds - * data structures, PASS2 actually dumps the file. - * Just in case the sections are in an unobvious order. - */ - sh = (cpel_section_header_t *)(fh+1); - for (i = 0; i < nsections; i++) { - section_size = ntohl(sh->data_length); - - if(verbose) { - fprintf(stderr, - "Section type %d, size %d\n", ntohl(sh->section_type), - section_size); - } - - if(process_section(sh, verbose, ofp, PASS1)) - return(1); - - sh++; - sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); - } - - sh = (cpel_section_header_t *)(fh+1); - for (i = 0; i < nsections; i++) { - if(process_section(sh, verbose, ofp, PASS2)) - return(1); - section_size = ntohl(sh->data_length); - sh++; - sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); - } - return(0); -} - - -char *mapfile (char *file) -{ - struct stat statb; - char *rv; - int maphfile; - size_t mapfsize; - - maphfile = open (file, O_RDONLY); - - if (maphfile < 0) - { - fprintf (stderr, "Couldn't read %s, skipping it...\n", file); - return (NULL); - } - - if (fstat (maphfile, &statb) < 0) - { - fprintf (stderr, "Couldn't get size of %s, skipping it...\n", file); - return (NULL); - } - - /* Don't try to mmap directories, FIFOs, semaphores, etc. */ - if (! (statb.st_mode & S_IFREG)) { - fprintf (stderr, "%s is not a regular file, skipping it...\n", file); - return (NULL); - } - - mapfsize = statb.st_size; - - if (mapfsize < 3) - { - fprintf (stderr, "%s zero-length, skipping it...\n", file); - close (maphfile); - return (NULL); - } - - rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0); - - if (rv == 0) - { - fprintf (stderr, "%s problem mapping, I quit...\n", file); - exit (-1); - } - close (maphfile); - return (rv); -} - -/* - * main - */ -int main (int argc, char **argv) -{ - char *cpel_file = 0; - char *outputfile = 0; - FILE *ofp; - char *cpel; - int verbose=0; - int curarg=1; - - while (curarg < argc) { - if (!strncmp(argv[curarg], "--input-file", 3)) { - curarg++; - if (curarg < argc) { - cpel_file = argv[curarg]; - curarg++; - continue; - } - fatal("Missing filename after --input-file\n"); - } - if (!strncmp(argv[curarg], "--output-file", 3)) { - curarg ++; - if (curarg < argc) { - outputfile = argv[curarg]; - curarg ++; - continue; - } - fatal("Missing filename after --output-file\n"); - } - if (!strncmp(argv[curarg], "--verbose", 3)) { - curarg++; - verbose = 1; - continue; - } - - usage: - fprintf(stderr, - "cpeldump --input-file [--output-file ]\n"); - fprintf(stderr, "%s\n", version); - exit(1); - } - - if (cpel_file == 0) - goto usage; - - cpel = mapfile(cpel_file); - if (cpel == 0) { - fprintf(stderr, "Couldn't map %s...\n", cpel_file); - exit(1); - } - - if (!outputfile) { - ofp = fdopen(1, "w"); - if (ofp == NULL) { - fprintf(stderr, "Couldn't fdopen(1)?\n"); - exit(1); - } - } else { - ofp = fopen(outputfile, "w"); - if (ofp == NULL) { - fprintf(stderr, "Couldn't create %s...\n", outputfile); - exit(1); - } - } - - the_strtab_hash = hash_create_string (0, sizeof (uword)); - the_evtdef_hash = hash_create (0, sizeof (uword)); - the_trackdef_hash = hash_create (0, sizeof (uword)); - -#ifdef TEST_TRACK_INFO - { - bound_track_t *btp; - vec_add2(bound_tracks, btp, 1); - btp->track = 0; - btp->track_str = "cpu %d"; - hash_set(the_trackdef_hash, 0, btp - bound_tracks); - hash_set(the_trackdef_hash, 1, btp - bound_tracks); - } -#endif - - if (cpel_dump((u8 *)cpel, verbose, ofp)) { - if (outputfile) - unlink(outputfile); - } - - fclose(ofp); - return(0); -} diff --git a/perftool/cpelinreg.c b/perftool/cpelinreg.c deleted file mode 100644 index 115afad7..00000000 --- a/perftool/cpelinreg.c +++ /dev/null @@ -1,892 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2008-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Search for O(N**2) functions bracketed by before/after - * events. The "before" event's datum is used as a tag, e.g. which function - * did we call that's strongly O(N). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "cpel.h" - -FILE *g_ifp; -char *g_ifile; - -typedef unsigned long long ulonglong; - -void process_traces (void); -void record_instance (ulong tag, ulonglong time); -void report_actors (void); -void scatterplot_data(void); -int entry_event, exit_event; -int nokey; -char *version = "cpelinreg 2.0"; -int model_these[10]; -int model_index; -int summary_stats; -ulonglong first_start_time; -ulonglong last_end_time; -ulonglong total_time; -ulong scatterkey; -int inline_mokus; - -typedef struct bound_track_ { - u32 track_code; - u32 *start_datum; - u8 *dup_event; - int state; - u64 *start_time; - u64 thread_timestamp; - u64 time_thread_on_cpu; -} bound_track_t; - -bound_track_t *bound_tracks; -uword *the_trackdef_hash; - - -#define MAXSTACK 128 - -typedef struct instance_ { - struct instance_ *next; - ulonglong time; -}instance_t; - -typedef struct actor_ { - struct actor_ *next; - ulong key; - struct instance_ *first; - struct instance_ *last; - double a; - double b; - double min; - double max; - double mean; - double r; - ulong ninst; -} actor_t; - -#define NBUCKETS 1811 - -actor_t *hash[NBUCKETS]; - -actor_t *find_or_create_actor (ulong key) -{ - ulong bucket; - actor_t *ap; - u8 *mem; - - bucket = key % NBUCKETS; - - ap = hash[bucket]; - - if (ap == NULL) { - /* Ensure 8-byte alignment to avoid (double) alignment faults */ - mem = malloc(sizeof(*ap) + 4); - if (((uword)(mem)) & 0x7) - mem += 4; - ap = (actor_t *)mem; - - if (ap == NULL) { - fprintf (stderr, "out of memory...\n"); - exit (1); - } - ap->next = 0; - ap->key = key; - ap->first = 0; - ap->last = 0; - ap->a = 0.00; - ap->b = 0.00; - hash [bucket] = ap; - return (ap); - } - - while (ap) { - if (ap->key == key) - return (ap); - ap = ap->next; - } - - mem = malloc(sizeof(*ap)+4); - if (((uword)(mem) & 0x7)) - mem += 4; - ap = (actor_t *)mem; - - if (ap == NULL) { - fprintf (stderr, "out of memory...\n"); - exit (1); - } - ap->key = key; - ap->first = 0; - ap->last = 0; - ap->a = 0.00; - ap->b = 0.00; - - ap->next = hash[bucket]; - hash[bucket] = ap; - - return (ap); -} - -void record_instance (ulong key, ulonglong time) -{ - actor_t *ap; - instance_t *ip; - - if (nokey) - key = 0; - - ap = find_or_create_actor (key); - - ip = (instance_t *)malloc(sizeof(*ip)); - if (ip == NULL) { - fprintf (stderr, "out of memory...\n"); - exit (1); - } - ip->time = time; - ip->next = 0; - - if (ap->first == 0) { - ap->first = ip; - ap->last = ip; - ap->ninst = 1; - } else { - ap->last->next = ip; - ap->last = ip; - ap->ninst++; - } -} - -#define NINSTANCE 200000 - -double x[NINSTANCE]; -double y[NINSTANCE]; - -int actor_compare (const void *arg1, const void *arg2) -{ - double e10k1, e10k2; - actor_t **a1 = (actor_t **)arg1; - actor_t **a2 = (actor_t **)arg2; - double ninst1, ninst2; - - ninst1 = ((double)((*a1)->ninst)); - ninst2 = ((double)((*a2)->ninst)); - - e10k1 = ninst1 * ((*a1)->mean); - e10k2 = ninst2 * ((*a2)->mean); - - if (e10k1 < e10k2) - return (1); - else if (e10k1 == e10k2) - return (0); - else - return (-1); -} - -void report_actors (void) -{ - int i; - actor_t *ap; - instance_t *ip; - int nactors = 0; - int ninstance; - actor_t **actor_vector; - double e10k; - extern void linreg (double *x, double *y, int nitems, double *a, double *b, - double *minp, double *maxp, double *meanp, double *r); - - for (i = 0; i < NBUCKETS; i++) { - ap = hash[i]; - if (ap == NULL) - continue; - while (ap) { - nactors++; - ninstance = 0; - - ip = ap->first; - - while (ip) { - if (ninstance < NINSTANCE) { - x[ninstance] = ninstance; - y[ninstance] = ((double)ip->time); - ninstance++; - } - ip = ip->next; - } - if (ninstance > 1) { -#if DEBUG > 0 - int j; - - for (j = 0; j < ninstance; j++) { - printf("x[%d] = %10.2f, y[%d] = %10.2f\n", - j, x[j], j, y[j]); - } -#endif - - linreg (x, y, ninstance, &ap->a, &ap->b, &ap->min, - &ap->max, &ap->mean, &ap->r); - } else { - ap->a = 0.00; - ap->b = 0.00; - } - - ap = ap->next; - } - } - - actor_vector = (actor_t **)malloc (nactors*sizeof(*actor_vector)); - nactors = 0; - - for (i = 0; i < NBUCKETS; i++) { - ap = hash[i]; - if (ap == NULL) - continue; - while (ap) { - if ((ap->a != 0.00) || (ap->b != 0.00)) { - actor_vector[nactors++] = ap; - } - ap = ap->next; - } - } - - qsort (actor_vector, nactors, sizeof (actor_t *), actor_compare); - - if (summary_stats) - printf("NInst Offset Slope T(Ninst) Min Max Avg %%InstTime R Key"); - else - printf("NInst Offset Slope T(Ninst) Key"); - - for (i = 0; i < model_index; i++) { - printf ("T @ %-8d ", model_these[i]); - } - - printf ("\n"); - - for (i = 0; i < nactors; i++) { - int j; - double ninst; - double pcttot; - ap = actor_vector[i]; - ninst = ap->ninst; - - e10k = ninst * (ap->a + ap->b*((ninst-1.0)/2.0)); - - if (ap->ninst) { - if (summary_stats) { - pcttot = (e10k / ((double)total_time)) * 100.0; - printf ("%6ld %11.2f %11.2f %11.2f %11.2f %11.2f %11.2f %11.2f %11.2f 0x%08lx ", - ap->ninst, ap->a, ap->b, e10k, ap->min, - ap->max, ap->mean, pcttot, ap->r, ap->key); - } - else - printf ("%6ld %11.2f %11.2f %11.2f 0x%08lx ", - ap->ninst, ap->a, ap->b, e10k, ap->key); - - for (j = 0; j < model_index; j++) { - ninst = model_these[j]; - e10k = ninst * (ap->a + ap->b*((ninst-1.0)/2.0)); - printf ("%10.2f ", e10k); - } - printf ("\n"); - } - } -} - -void scatterplot_data(void) -{ - actor_t *ap; - int i; - instance_t *ip; - double time; - int count=0; - - for (i = 0; i < NBUCKETS; i++) { - ap = hash[i]; - if (ap == NULL) - continue; - while (ap) { - if (ap->key == scatterkey){ - ip = ap->first; - while (ip) { - time = ((double)ip->time); - printf ("%d\t%.0f\n", count++, time); - ip = ip->next; - } - return; - } - ap = ap->next; - } - } -} - - -void fatal(char *s) -{ - fprintf(stderr, "%s", s); - fprintf(stderr, "\n"); - exit(1); -} - -typedef enum { - PASS1=1, -} pass_t; - -typedef struct { - int (*pass1)(cpel_section_header_t *, int, FILE *); -} section_processor_t; - -int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - fprintf(ofp, "Bad (type 0) section, skipped...\n"); - return(0); -} - -int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - return(0); -} - -int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - if (verbose) { - fprintf(ofp, "Unsupported type %d section\n", - ntohl(sh->section_type)); - } - return(0); -} - -int trackdef_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - int i, nevents; - track_definition_section_header_t *tdh; - track_definition_t *tp; - u32 track_code; - uword *p; - bound_track_t *btp; - - tdh = (track_definition_section_header_t *)(sh+1); - nevents = ntohl(tdh->number_of_track_definitions); - - if (verbose) { - fprintf(stderr, "Track Definition Section: %d definitions\n", - nevents); - } - - tp = (track_definition_t *)(tdh+1); - - for (i = 0; i < nevents; i++) { - track_code = ntohl(tp->track); - p = hash_get(the_trackdef_hash, track_code); - if (p) { - fprintf(ofp, "track %d redefined, retain first definition\n", - track_code); - continue; - } - vec_add2(bound_tracks, btp, 1); - btp->track_code = track_code; - hash_set(the_trackdef_hash, track_code, btp - bound_tracks); - tp++; - } - return (0); -} - - -int event_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - event_section_header_t *eh; - event_entry_t *ep; - f64 ticks_per_us; - long output_count; - long dup_events = 0; - ulonglong end_time = 0; - double t; - int sp, ancestor; - int nevents, i; - u64 now; - u64 time0, time1; - double d; - u32 last_track_code = 0xdeafb00b; - u32 track_code; - u32 event_code, event_datum; - bound_track_t *tp = 0; - uword *p; - - output_count = 0; - total_time = 0; - - eh = (event_section_header_t *)(sh+1); - nevents = ntohl(eh->number_of_events); - ticks_per_us = ((double)ntohl(eh->clock_ticks_per_second))/1e6; - - if (verbose) { - fprintf(ofp, "%.3f ticks_per_us\n", ticks_per_us); - } - - ep = (event_entry_t *)(eh+1); - - time0 = ntohl (ep->time[0]); - time1 = ntohl (ep->time[1]); - - now = (((u64) time0)<<32) | time1; - d = now; - d /= ticks_per_us; - first_start_time = d; - - for (i = 0; i < nevents; i++) { - time0 = ntohl (ep->time[0]); - time1 = ntohl (ep->time[1]); - - now = (((u64) time0)<<32) | time1; - - /* Convert from bus ticks to usec */ - d = now; - d /= ticks_per_us; - - now = d; - - track_code = ntohl(ep->track); - event_code = ntohl(ep->event_code); - event_datum = ntohl(ep->event_datum); - - if (track_code != last_track_code) { - if (tp) { - tp->thread_timestamp += now - tp->time_thread_on_cpu; - tp->time_thread_on_cpu = 0; - } - p = hash_get(the_trackdef_hash, track_code); - if (!p) { - /* synthesize a new track */ - vec_add2(bound_tracks, tp, 1); - tp->track_code = track_code; - hash_set(the_trackdef_hash, track_code, tp - bound_tracks); - } else { - tp = bound_tracks + p[0]; - } - last_track_code = track_code; - tp->time_thread_on_cpu = now; - } - - if (event_code != entry_event && - event_code != exit_event) { - ep++; - continue; - } - - again: - switch (tp->state) { - case 0: /* not in state */ - /* Another exit event? Stack pop */ - if (event_code == exit_event) { - /* Only if we have something on the stack */ - if (vec_len(tp->start_datum) > 0) { - tp->state = 1; - goto again; - } else { - fprintf (stderr, - "End event before start event, key 0x%x.", - ntohl(ep->event_datum)); - fprintf (stderr, " Interpret results carefully...\n"); - } - } - - tp->state = 1; - if (vec_len(tp->start_datum) >= MAXSTACK) { - int j; - - fprintf (stderr, "stack overflow..\n"); - for (j = vec_len(tp->start_datum)-1; j >= 0; j--) { - fprintf(stderr, "stack[%d]: datum 0x%x\n", - j, tp->start_datum[j]); - } - fprintf (stderr, - "Stack overflow... This occurs when " - "(start, datum)...(end, datum) events\n" - "are not properly paired.\n\n" - "A typical scenario looks like this:\n\n" - " ...\n" - " ELOG(..., START_EVENT, datum);\n" - " if (condition)\n" - " return; /*oops, forgot the end event*/\n" - " ELOG(..., END_EVENT, datum);\n" - " ...\n\n" - "The datum stack dump (above) should make it clear\n" - "where to start looking for a sneak path...\n"); - - exit (1); - } - vec_add1(tp->start_datum, event_datum); - vec_add1(tp->start_time, (tp->thread_timestamp + (now - tp->time_thread_on_cpu))); -#ifdef HAVING_TROUBLE - printf ("sp %lld key 0x%x start time %llu\n", - (long long) vec_len(tp->start_time)-1, event_datum, - (unsigned long long) - tp->start_time [vec_len(tp->start_time)-1]); - printf ("timestamp %llu, now %llu, thread on cpu %llu\n", - (unsigned long long) tp->thread_timestamp, - (unsigned long long) now, - (unsigned long long) tp->time_thread_on_cpu); -#endif - - - - /* - * Multiple identical enter events? If the user knows that - * gcc is producing bogus events due to inline functions, - * trash the duplicate. - */ - if (inline_mokus - && vec_len (tp->start_datum) > 1 - && tp->start_datum [vec_len(tp->start_datum)-1] == - tp->start_datum [vec_len(tp->start_datum)-2]) { - vec_add1 (tp->dup_event, 1); - } else { - vec_add1 (tp->dup_event, 0); - } - - - ep++; - continue; - - case 1: /* in state */ - /* Another entry event? Stack push*/ - if (event_code == entry_event) { - tp->state = 0; - goto again; - } - - if (vec_len(tp->start_datum) == 0) { - fprintf (stderr, "Stack underflow...\n"); - exit (1); - } - - sp = vec_len(tp->start_time)-1; - - end_time = tp->thread_timestamp + (now - tp->time_thread_on_cpu); - - if (!tp->dup_event[sp]) { -#ifdef HAVING_TROUBLE - printf ("sp %d key 0x%x charged %llu\n", sp, - tp->start_datum[sp], end_time - tp->start_time[sp]); - printf (" start %llu, end %llu\n", (unsigned long long) tp->start_time[sp], - (unsigned long long) end_time); -#endif - - record_instance (tp->start_datum[sp], (end_time - - tp->start_time[sp])); - - /* Factor out our time from surrounding services, if any */ - for (ancestor = sp-1; ancestor >= 0; ancestor--) { -#ifdef HAVING_TROUBLE - printf ("Factor out %lld from key 0x%08x\n", - (end_time - tp->start_time[sp]), tp->start_datum[ancestor]); -#endif - tp->start_time[ancestor] += (end_time - tp->start_time[sp]); - } - output_count++; - total_time += (end_time - tp->start_time[sp]); - tp->state = 0; - } else { - dup_events++; - } - _vec_len(tp->start_datum) = sp; - _vec_len(tp->start_time) = sp; - _vec_len(tp->dup_event) = sp; - } - - ep++; - } - last_end_time = now; - - if (scatterkey) { - scatterplot_data(); - exit (0); - } - - if (output_count) { - t = (double)total_time; - printf ("%ld instances of state, %.2f microseconds average\n", - output_count, t / output_count); - - printf ("Total instrumented runtime: %.2f microseconds\n", - ((double)total_time)); - printf ("Total runtime: %lld microseconds\n", - last_end_time - first_start_time); - - t /= (double)(last_end_time - first_start_time); - t *= 100.0; - - if (dup_events) { - printf ("Suppressed %ld duplicate state entry events\n", - dup_events); - } - printf ("Instrumented code accounts for %.2f%% of total time.\n\n", - t); - report_actors(); - } else { - printf ("No instances of state...\n"); - } - - return(0); -} - -/* - * Note: If necessary, add passes / columns to this table to - * handle section order dependencies. - */ - -section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] = -{ - {unsupported_pass}, /* type 0 -- f**ked */ - {noop_pass}, /* type 1 -- STRTAB */ - {noop_pass}, /* type 2 -- SYMTAB */ - {noop_pass}, /* type 3 -- EVTDEF */ - {trackdef_pass}, /* type 4 -- TRACKDEF */ - {event_pass}, /* type 5 -- EVENTS */ -}; - -int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp, - pass_t pass) -{ - u32 type; - type = ntohl(sh->section_type); - int rv; - int (*fp)(cpel_section_header_t *, int, FILE *); - - if (type > CPEL_NUM_SECTION_TYPES) { - fprintf(stderr, "Unknown section type %d\n", type); - return(1); - } - switch(pass) { - case PASS1: - fp = processors[type].pass1; - break; - - default: - fprintf(stderr, "Unknown pass %d\n", pass); - return(1); - } - - rv = (*fp)(sh, verbose, ofp); - - return(rv); -} - -char *mapfile (char *file) -{ - struct stat statb; - char *rv; - int maphfile; - size_t mapfsize; - - maphfile = open (file, O_RDONLY); - - if (maphfile < 0) - { - fprintf (stderr, "Couldn't read %s, skipping it...\n", file); - return (NULL); - } - - if (fstat (maphfile, &statb) < 0) - { - fprintf (stderr, "Couldn't get size of %s, skipping it...\n", file); - return (NULL); - } - - /* Don't try to mmap directories, FIFOs, semaphores, etc. */ - if (! (statb.st_mode & S_IFREG)) { - fprintf (stderr, "%s is not a regular file, skipping it...\n", file); - return (NULL); - } - - mapfsize = statb.st_size; - - if (mapfsize < 3) - { - fprintf (stderr, "%s zero-length, skipping it...\n", file); - close (maphfile); - return (NULL); - } - - rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0); - - if (rv == 0) - { - fprintf (stderr, "%s problem mapping, I quit...\n", file); - exit (-1); - } - close (maphfile); - return (rv); -} - -int process_file (u8 *cpel, int verbose) -{ - cpel_file_header_t *fh; - cpel_section_header_t *sh; - u16 nsections; - u32 section_size; - int i; - FILE *ofp = stderr; - - /* First, the file header */ - fh = (cpel_file_header_t *)cpel; - if (fh->endian_version != CPEL_FILE_VERSION) { - if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) { - fprintf(stderr, "Little endian data format not supported\n"); - return(1); - } - fprintf(stderr, "Unsupported file version 0x%x\n", - fh->endian_version); - return(1); - } - nsections = ntohs(fh->nsections); - - /* - * Take a passe through the file. - */ - sh = (cpel_section_header_t *)(fh+1); - for (i = 0; i < nsections; i++) { - section_size = ntohl(sh->data_length); - - if(verbose) { - fprintf(ofp, "Section type %d, size %d\n", - ntohl(sh->section_type), - section_size); - } - - if(process_section(sh, verbose, ofp, PASS1)) - return(1); - - sh++; - sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); - } - - return(0); -} - -/**************************************************************************** -* main - -****************************************************************************/ - -int main (int argc, char **argv) -{ - int curarg = 1; - u8 *cpel = 0; - int verbose = 0; - - if (argc < 6) - { - fprintf (stderr, "usage: cpelinreg -i \n"); - fprintf (stderr, " -s start-event --e end-event [-nokey]\n"); - fprintf (stderr, " [-m ][-xtra-stats]\n"); - fprintf (stderr, " [-keyscatterplot ]\n\n"); - fprintf (stderr, "%s\n", version); - exit (1); - } - - while (curarg < argc) { - if (!strncmp (argv[curarg], "-ifile", 2)) { - curarg++; - g_ifile = argv[curarg++]; - continue; - } - if (!strncmp (argv[curarg], "-start", 2)) { - curarg++; - entry_event = atol (argv [curarg++]); - continue; - } - if (!strncmp (argv[curarg], "-end", 2)) { - curarg++; - exit_event = atol (argv [curarg++]); - continue; - } - - if (!strncmp(argv[curarg], "-badinlines", 2)) { - curarg++; - inline_mokus = 1; - continue; - } - - if (!strncmp (argv[curarg], "-x", 2)) { - curarg++; - summary_stats=1; - continue; - } - if (!strncmp (argv[curarg], "-nokey", 2)) { - curarg++; - nokey = 1; - continue; - } - if (!strncmp (argv[curarg], "-keyscatterplot", 2)) { - curarg++; - sscanf (argv[curarg], "%lx", &scatterkey); - curarg++; - continue; - } - - if (!strncmp (argv[curarg], "-model", 2)) { - if (model_index >= sizeof(model_these) / sizeof(int)) { - fprintf (stderr, "Too many model requests\n"); - exit (1); - } - curarg++; - model_these[model_index++] = atol (argv [curarg++]); - continue; - } - if (!strncmp (argv[curarg], "-verbose", 2)) { - verbose++; - curarg++; - continue; - } - - fprintf (stderr, "unknown switch '%s'\n", argv[curarg]); - exit (1); - } - - cpel = (u8 *)mapfile(g_ifile); - - if (cpel == NULL) - { - fprintf (stderr, "Couldn't open %s\n", g_ifile); - exit (1); - } - - printf ("Extracting state info from %s\nentry_event %d, exit_event %d\n", - g_ifile, entry_event, exit_event); - if (nokey) { - printf ("All state instances mapped to a single actor chain\n"); - } - - the_trackdef_hash = hash_create (0, sizeof (uword)); - - process_file(cpel, verbose); - exit (0); -} diff --git a/perftool/cpelstate.c b/perftool/cpelstate.c deleted file mode 100644 index 3fd9ccb9..00000000 --- a/perftool/cpelstate.c +++ /dev/null @@ -1,822 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2006-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 -#include "cpel.h" -#include - -char *time_format = "%.03d:%.02d:%.02d:%.03d:%.03d "; -static char version[] = "cpelstate 2.0h"; - -#define USEC_PER_MS 1000LL -#define USEC_PER_SECOND (1000*USEC_PER_MS) -#define USEC_PER_MINUTE (60*USEC_PER_SECOND) -#define USEC_PER_HOUR (60*USEC_PER_MINUTE) - -uword *the_strtab_hash; /* (name, base-VA) hash of all string tables */ -uword *the_evtdef_hash; /* (event-id, event-definition) hash */ -uword *the_trackdef_hash; /* (track-id, track-definition) hash */ - -f64 ticks_per_us; -u32 state_event_code = 1; /* default: XR thread-on-cpu */ -int exclude_kernel_from_summary_stats=1; -int summary_stats_only; -int scatterplot; -u8 *name_filter; - -typedef enum { - SORT_MAX_TIME=1, - SORT_MAX_OCCURRENCES, - SORT_NAME, -} sort_t; - -sort_t sort_type = SORT_MAX_TIME; - -int widest_name_format=5; -int widest_track_format=5; - -typedef struct bound_event_ { - u32 event_code; - u8 *event_str; - u8 *datum_str; - u32 is_strtab_ref; -} bound_event_t; - -bound_event_t *bound_events; - -typedef struct bound_track_ { - u32 track; - u8 *track_str; - u64 *ticks_in_state; /* vector of state occurrences */ - f64 mean_ticks_in_state; - f64 variance_ticks_in_state; - f64 total_ticks_in_state; -} bound_track_t; - -bound_track_t *bound_tracks; - -void fatal(char *s) -{ - fprintf(stderr, "%s", s); - exit(1); -} - -typedef enum { - PASS1=1, - PASS2=2, -} pass_t; - -typedef struct { - int (*pass1)(cpel_section_header_t *, int, FILE *); - int (*pass2)(cpel_section_header_t *, int, FILE *); -} section_processor_t; - -int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - fprintf(ofp, "Bad (type 0) section, skipped...\n"); - return(0); -} - -int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - return(0); -} - -int strtab_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - uword *p; - u8 *strtab_data_area = (u8 *)(sh+1); - - /* Multiple string tables with the same name are Bad... */ - p = hash_get_mem(the_strtab_hash, strtab_data_area); - if (p) { - fprintf(ofp, "Duplicate string table name %s", strtab_data_area); - } - /* - * Looks funny, but we really do want key = first string in the - * table, value = address(first string in the table) - */ - hash_set_mem(the_strtab_hash, strtab_data_area, strtab_data_area); - if (verbose) { - fprintf(ofp, "String Table %s\n", strtab_data_area); - } - return(0); -} - -int evtdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - int i, nevents; - event_definition_section_header_t *edh; - event_definition_t *ep; - u8 *this_strtab; - u32 event_code; - uword *p; - bound_event_t *bp; - int thislen; - - edh = (event_definition_section_header_t *)(sh+1); - nevents = ntohl(edh->number_of_event_definitions); - - if (verbose) { - fprintf(ofp, "Event Definition Section: %d definitions\n", - nevents); - } - - p = hash_get_mem(the_strtab_hash, edh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - this_strtab = (u8 *)p[0]; - - ep = (event_definition_t *)(edh+1); - - for (i = 0; i < nevents; i++) { - event_code = ntohl(ep->event); - p = hash_get(the_evtdef_hash, event_code); - if (p) { - fprintf(ofp, "Event %d redefined, retain first definition\n", - event_code); - continue; - } - vec_add2(bound_events, bp, 1); - bp->event_code = event_code; - bp->event_str = this_strtab + ntohl(ep->event_format); - bp->datum_str = this_strtab + ntohl(ep->datum_format); - bp->is_strtab_ref = 0; - /* Decide if the datum format is a %s format => strtab reference */ - { - int j; - int seen_percent=0; - - for (j = 0; j < strlen((char *)(bp->datum_str)); j++) { - if (bp->datum_str[j] == '%'){ - seen_percent=1; - continue; - } - if (seen_percent && bp->datum_str[j] == 's') { - bp->is_strtab_ref = 1; - } - } - } - - hash_set(the_evtdef_hash, event_code, bp - bound_events); - - thislen = strlen((char *)bp->event_str); - if (thislen > widest_name_format) - widest_name_format = thislen; - - ep++; - } - return (0); -} - -int trackdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - int i, nevents; - track_definition_section_header_t *tdh; - track_definition_t *tp; - u8 *this_strtab; - u32 track_code; - uword *p; - bound_track_t *btp; - int thislen; - - tdh = (track_definition_section_header_t *)(sh+1); - nevents = ntohl(tdh->number_of_track_definitions); - - if (verbose) { - fprintf(ofp, "Track Definition Section: %d definitions\n", - nevents); - } - - p = hash_get_mem(the_strtab_hash, tdh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - this_strtab = (u8 *)p[0]; - - tp = (track_definition_t *)(tdh+1); - - for (i = 0; i < nevents; i++) { - track_code = ntohl(tp->track); - p = hash_get(the_trackdef_hash, track_code); - if (p) { - fprintf(ofp, "track %d redefined, retain first definition\n", - track_code); - continue; - } - vec_add2(bound_tracks, btp, 1); - btp->track = track_code; - btp->track_str = this_strtab + ntohl(tp->track_format); - hash_set(the_trackdef_hash, track_code, btp - bound_tracks); - - thislen = strlen((char *)(btp->track_str)); - if (thislen > widest_track_format) - widest_track_format = thislen; - tp++; - } - return (0); -} - -int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - if (verbose) { - fprintf(ofp, "Unsupported type %d section\n", - ntohl(sh->section_type)); - } - return(0); -} - -int event_pass2(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - event_section_header_t *eh; - u32 track_code; - int nevents; - int i; - uword *p; - event_entry_t *ep; - u64 now; - u32 time0, time1; - bound_track_t generic_track; - u32 last_track_code; - u64 state_start_ticks=0; - u64 ticks_in_state; - bound_track_t *state_track=0; - int in_state=0; - generic_track.track_str = (u8 *) "%d"; - last_track_code = 0xdeafbeef; - - eh = (event_section_header_t *)(sh+1); - nevents = ntohl(eh->number_of_events); - ticks_per_us = ((double)ntohl(eh->clock_ticks_per_second))/1e6; - - if (verbose) { - fprintf(ofp, "%.3f ticks_per_us\n", ticks_per_us); - } - - ep = (event_entry_t *)(eh+1); - - p = hash_get_mem(the_strtab_hash, eh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - - for (i = 0; i < nevents; i++) { - time0 = ntohl (ep->time[0]); - time1 = ntohl (ep->time[1]); - - now = (((u64) time0)<<32) | time1; - - /* Found the state-change event ? */ - if (ntohl(ep->event_code) == state_event_code) { - /* - * Add a ticks-in-state record, unless - * this is the "prime mover" event instance - */ - if (in_state) { - ticks_in_state = now - state_start_ticks; - vec_add1(state_track->ticks_in_state, ticks_in_state); - } - /* switch to now-current track */ - state_start_ticks = now; - track_code = ntohl(ep->track); - if (track_code != last_track_code) { - p = hash_get(the_trackdef_hash, track_code); - if (p) { - state_track = &bound_tracks[p[0]]; - } else { - state_track = &generic_track; - } - last_track_code = track_code; - } - in_state = 1; - } - ep++; - } - return(0); -} - -/* - * Note: If necessary, add passes / columns to this table to - * handle section order dependencies. - */ - -section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] = -{ - {bad_section, noop_pass}, /* type 0 -- f**ked */ - {strtab_pass1, noop_pass}, /* type 1 -- STRTAB */ - {unsupported_pass, noop_pass}, /* type 2 -- SYMTAB */ - {evtdef_pass1, noop_pass}, /* type 3 -- EVTDEF */ - {trackdef_pass1, noop_pass}, /* type 4 -- TRACKDEF */ - {noop_pass, event_pass2}, /* type 5 -- EVENTS */ -}; - - -int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp, - pass_t pass) -{ - u32 type; - type = ntohl(sh->section_type); - int rv; - int (*fp)(cpel_section_header_t *, int, FILE *); - - if (type > CPEL_NUM_SECTION_TYPES) { - fprintf(stderr, "Unknown section type %d\n", type); - return(1); - } - switch(pass) { - case PASS1: - fp = processors[type].pass1; - break; - - case PASS2: - fp = processors[type].pass2; - break; - - default: - fprintf(stderr, "Unknown pass %d\n", pass); - return(1); - } - - rv = (*fp)(sh, verbose, ofp); - - return(rv); -} - -int cpel_dump_file_header(cpel_file_header_t *fh, int verbose, FILE *ofp) -{ - time_t file_time; - - if (verbose) { - fprintf(ofp, "CPEL file: %s-endian, version %d\n", - ((fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) ? - "little" : "big"), - fh->endian_version & CPEL_FILE_VERSION_MASK); - - file_time = ntohl(fh->file_date); - - fprintf(ofp, "File created %s", ctime(&file_time)); - fprintf(ofp, "File has %d sections\n", - ntohs(fh->nsections)); - } - - return(0); -} - - -int cpel_dump(u8 *cpel, int verbose, FILE *ofp) -{ - cpel_file_header_t *fh; - cpel_section_header_t *sh; - u16 nsections; - u32 section_size; - int i; - - /* First, the file header */ - fh = (cpel_file_header_t *)cpel; - if (fh->endian_version != CPEL_FILE_VERSION) { - if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) { - fprintf(stderr, "Little endian data format not supported\n"); - return(1); - } - fprintf(stderr, "Unsupported file version 0x%x\n", - fh->endian_version); - return(1); - } - cpel_dump_file_header(fh, verbose, ofp); - nsections = ntohs(fh->nsections); - - /* - * Take two passes through the file. PASS1 builds - * data structures, PASS2 actually dumps the file. - * Just in case the sections are in an unobvious order. - */ - sh = (cpel_section_header_t *)(fh+1); - for (i = 0; i < nsections; i++) { - section_size = ntohl(sh->data_length); - - if(verbose) { - fprintf(ofp, "Section type %d, size %d\n", ntohl(sh->section_type), - section_size); - } - - if(process_section(sh, verbose, ofp, PASS1)) - return(1); - - sh++; - sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); - } - - sh = (cpel_section_header_t *)(fh+1); - for (i = 0; i < nsections; i++) { - if(process_section(sh, verbose, ofp, PASS2)) - return(1); - section_size = ntohl(sh->data_length); - sh++; - sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); - } - return(0); -} - -void compute_state_statistics(int verbose, FILE *ofp) -{ - int i, j; - bound_track_t *bp; - f64 fticks; - - /* Across the bound tracks */ - for (i = 0; i < vec_len(bound_tracks); i++) { - bp = &bound_tracks[i]; - bp->mean_ticks_in_state = 0.0; - bp->variance_ticks_in_state = 0.0; - bp->total_ticks_in_state = 0.0; - for (j = 0; j < vec_len(bp->ticks_in_state); j++) { - bp->total_ticks_in_state += (f64) bp->ticks_in_state[j]; - } - /* Compute mean */ - if (vec_len(bp->ticks_in_state)) { - bp->mean_ticks_in_state = bp->total_ticks_in_state / - ((f64) vec_len(bp->ticks_in_state)); - } - /* Accumulate sum: (Xi-Xbar)**2 */ - for (j = 0; j < vec_len(bp->ticks_in_state); j++) { - fticks = bp->ticks_in_state[j]; - bp->variance_ticks_in_state += - (fticks - bp->mean_ticks_in_state)* - (fticks - bp->mean_ticks_in_state); - } - /* Compute s**2, the unbiased estimator of sigma**2 */ - if (vec_len(bp->ticks_in_state) > 1) { - bp->variance_ticks_in_state /= (f64) - (vec_len(bp->ticks_in_state)-1); - } - } -} - -int track_compare_max (const void *arg1, const void *arg2) -{ - bound_track_t *a1 = (bound_track_t *)arg1; - bound_track_t *a2 = (bound_track_t *)arg2; - f64 v1, v2; - - v1 = a1->total_ticks_in_state; - v2 = a2->total_ticks_in_state; - - if (v1 < v2) - return (1); - else if (v1 == v2) - return (0); - else return (-1); -} - -int track_compare_occurrences (const void *arg1, const void *arg2) -{ - bound_track_t *a1 = (bound_track_t *)arg1; - bound_track_t *a2 = (bound_track_t *)arg2; - f64 v1, v2; - - v1 = (f64) vec_len(a1->ticks_in_state); - v2 = (f64) vec_len(a2->ticks_in_state); - - if (v1 < v2) - return (1); - else if (v1 == v2) - return (0); - else return (-1); -} - -int track_compare_name (const void *arg1, const void *arg2) -{ - bound_track_t *a1 = (bound_track_t *)arg1; - bound_track_t *a2 = (bound_track_t *)arg2; - - return (strcmp((char *)(a1->track_str), (char *)(a2->track_str))); -} - -void sort_state_statistics(sort_t type, FILE *ofp) -{ - int (*compare)(const void *, const void *)=0; - - if (summary_stats_only) - return; - - switch(type) { - case SORT_MAX_TIME: - fprintf(ofp, "Results sorted by max time in state.\n"); - compare = track_compare_max; - break; - - case SORT_MAX_OCCURRENCES: - fprintf(ofp, "Results sorted by max occurrences of state.\n"); - compare = track_compare_occurrences; - break; - - case SORT_NAME: - compare = track_compare_name; - fprintf(ofp, "Results sorted by process-id/name/thread ID\n"); - break; - - default: - fatal("sort type not set?"); - } - - qsort (bound_tracks, vec_len(bound_tracks), - sizeof (bound_track_t), compare); -} - -void print_state_statistics(int verbose, FILE *ofp) -{ - int i,j; - u8 *trackpad; - bound_track_t *bp; - f64 total_time = 0.0; - f64 total_switches = 0.0; - - trackpad = format(0, "%%-%ds ", widest_track_format); - vec_add1(trackpad, 0); - - if (!summary_stats_only) { - fprintf(ofp, (char *)trackpad, "ProcThread"); - fprintf(ofp, " Mean(us) Stdev(us) Total(us) N\n"); - } - - for (i = 0; i < vec_len(bound_tracks); i++) { - bp = &bound_tracks[i]; - if (bp->mean_ticks_in_state == 0.0) - continue; - - if (name_filter && - strncmp((char *)(bp->track_str), (char *)name_filter, - strlen((char *)name_filter))) - continue; - - /* - * Exclude kernel threads (e.g. idle thread) from - * state statistics - */ - if (exclude_kernel_from_summary_stats && - !strncmp((char *)(bp->track_str), "kernel ", 7)) - continue; - - total_switches += (f64) vec_len(bp->ticks_in_state); - - if (!summary_stats_only) { - fprintf(ofp, (char *) trackpad, bp->track_str); - fprintf(ofp, "%10.3f +- %10.3f", - bp->mean_ticks_in_state / ticks_per_us, - sqrt(bp->variance_ticks_in_state) - / (f64) ticks_per_us); - fprintf(ofp, "%12.3f", - bp->total_ticks_in_state / ticks_per_us); - fprintf(ofp, "%8d\n", (int)vec_len(bp->ticks_in_state)); - } - - if (scatterplot) { - for (j = 0; j < vec_len(bp->ticks_in_state); j++) { - fprintf(ofp, "%.3f\n", - (f64)bp->ticks_in_state[j] / ticks_per_us); - } - } - - total_time += bp->total_ticks_in_state; - } - - if (!summary_stats_only) - fprintf(ofp, "\n"); - fprintf(ofp, "Note: the following statistics %s kernel-thread activity.\n", - exclude_kernel_from_summary_stats ? "exclude" : "include"); - if (name_filter) - fprintf(ofp, - "Note: only pid/proc/threads matching '%s' are included.\n", - name_filter); - - fprintf(ofp, - "Total runtime: %10.3f (us), Total state switches: %.0f\n", - total_time / ticks_per_us, total_switches); - fprintf(ofp, "Average time in state: %10.3f (us)\n", - (total_time / total_switches) / ticks_per_us); -} - -char *mapfile (char *file) -{ - struct stat statb; - char *rv; - int maphfile; - size_t mapfsize; - - maphfile = open (file, O_RDONLY); - - if (maphfile < 0) - { - fprintf (stderr, "Couldn't read %s, skipping it...\n", file); - return (NULL); - } - - if (fstat (maphfile, &statb) < 0) - { - fprintf (stderr, "Couldn't get size of %s, skipping it...\n", file); - return (NULL); - } - - /* Don't try to mmap directories, FIFOs, semaphores, etc. */ - if (! (statb.st_mode & S_IFREG)) { - fprintf (stderr, "%s is not a regular file, skipping it...\n", file); - return (NULL); - } - - mapfsize = statb.st_size; - - if (mapfsize < 3) - { - fprintf (stderr, "%s zero-length, skipping it...\n", file); - close (maphfile); - return (NULL); - } - - rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0); - - if (rv == 0) - { - fprintf (stderr, "%s problem mapping, I quit...\n", file); - exit (-1); - } - close (maphfile); - return (rv); -} - -/* - * main - */ -int main (int argc, char **argv) -{ - char *cpel_file = 0; - char *outputfile = 0; - FILE *ofp; - char *cpel; - int verbose=0; - int curarg=1; - - while (curarg < argc) { - if (!strncmp(argv[curarg], "--input-file", 3)) { - curarg++; - if (curarg < argc) { - cpel_file = argv[curarg]; - curarg++; - continue; - } - fatal("Missing filename after --input-file\n"); - } - if (!strncmp(argv[curarg], "--output-file", 3)) { - curarg ++; - if (curarg < argc) { - outputfile = argv[curarg]; - curarg ++; - continue; - } - fatal("Missing filename after --output-file\n"); - } - if (!strncmp(argv[curarg], "--verbose", 3)) { - curarg++; - verbose++; - continue; - } - if (!strncmp(argv[curarg], "--scatterplot", 4)) { - curarg++; - scatterplot=1; - continue; - } - - if (!strncmp(argv[curarg], "--state-event", 4)) { - curarg++; - if (curarg < argc) { - state_event_code = atol(argv[curarg]); - curarg ++; - continue; - } - fatal("Missing integer after --state-event\n"); - } - if (!strncmp(argv[curarg], "--max-time-sort", 7)) { - sort_type = SORT_MAX_TIME; - curarg++; - continue; - } - if (!strncmp(argv[curarg], "--max-occurrence-sort", 7)) { - sort_type = SORT_MAX_OCCURRENCES; - curarg++; - continue; - } - if (!strncmp(argv[curarg], "--name-sort", 3)) { - sort_type = SORT_NAME; - curarg++; - continue; - } - if (!strncmp(argv[curarg], "--kernel-included", 3)) { - exclude_kernel_from_summary_stats = 0; - curarg++; - continue; - } - if (!strncmp(argv[curarg], "--summary", 3)) { - summary_stats_only=1; - curarg++; - continue; - } - if (!strncmp(argv[curarg], "--filter", 3)) { - curarg ++; - if (curarg < argc) { - name_filter = (u8 *)argv[curarg]; - curarg ++; - continue; - } - fatal("Missing filter string after --filter\n"); - } - - - usage: - fprintf(stderr, - "cpelstate --input-file [--output-file ]\n"); - fprintf(stderr, - " [--state-event ] [--verbose]\n"); - fprintf(stderr, - " [--max-time-sort(default) | --max-occurrence-sort |\n"); - - fprintf(stderr, - " --name-sort-sort] [--kernel-included]\n"); - - fprintf(stderr, - " [--summary-stats-only] [--scatterplot]\n"); - - fprintf(stderr, "%s\n", version); - exit(1); - } - - if (cpel_file == 0) - goto usage; - - cpel = mapfile(cpel_file); - if (cpel == 0) { - fprintf(stderr, "Couldn't map %s...\n", cpel_file); - exit(1); - } - - if (!outputfile) { - ofp = fdopen(1, "w"); - if (ofp == NULL) { - fprintf(stderr, "Couldn't fdopen(1)?\n"); - exit(1); - } - } else { - ofp = fopen(outputfile, "w"); - if (ofp == NULL) { - fprintf(stderr, "Couldn't create %s...\n", outputfile); - exit(1); - } - } - - the_strtab_hash = hash_create_string (0, sizeof (uword)); - the_evtdef_hash = hash_create (0, sizeof (uword)); - the_trackdef_hash = hash_create (0, sizeof (uword)); - - if (cpel_dump((u8 *) cpel, verbose, ofp)) { - if (outputfile) - unlink(outputfile); - } - - compute_state_statistics(verbose, ofp); - sort_state_statistics(sort_type, ofp); - print_state_statistics(verbose, ofp); - - fclose(ofp); - return(0); -} diff --git a/perftool/delsvec.c b/perftool/delsvec.c deleted file mode 100644 index 724935d3..00000000 --- a/perftool/delsvec.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2006-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* Break up a delimited string into a vector of substrings */ - -#include -#include -#include -#include -#include - -/* - * #define UNIT_TESTS 1 - * #define MATCH_TRACE 1 - */ - -/* - * delsvec - * break up an input string into a vector of [null-terminated] u8 *'s - * - * Each supplied delimiter character results in a string in the output - * vector, unless the delimiters occur back-to-back. When matched, - * a whitespace character in the delimiter consumes an arbitrary - * run of whitespace. See the unit tests at the end of this file - * for a set of examples. - * - * Returns a u8 **, or NULL if the input fails to match. It is assumed - * that both input and fmt are C strings, not necessarily vectors. - * - * Output strings are both vectors and proper C strings. - */ - -static u8 **string_cache; -static u8 **svec_cache; - -void delsvec_recycle_this_string (u8 *s) -{ - if (s) { - _vec_len (s) = 0; - vec_add1(string_cache, s); - } -} - -void delsvec_recycle_this_svec (u8 **svec) -{ - if (svec) { - if (svec_cache) { - vec_free (svec_cache); - } - _vec_len (svec) = 0; - svec_cache = svec; - } -} - -int pvl (char *a) -{ - return vec_len(a); -} - -u8 **delsvec(void *input_arg, char *fmt) -{ - u8 **rv = 0; - int input_index=0; - u8 *this; - int dirflag=0; - int i; - u8 *input = input_arg; - - if (svec_cache) { - rv = svec_cache; - svec_cache = 0; - } - - while (fmt) { - dirflag=0; - if (vec_len (string_cache) > 0) { - this = string_cache [vec_len(string_cache)-1]; - _vec_len (string_cache) = vec_len (string_cache) - 1; - } else - this = 0; - /* - * '*' means one of two things: match the rest of the input, - * or match as many characters as possible - */ - if (fmt[0] == '*') { - fmt++; - dirflag=1; - /* - * no more format: eat rest of string... - */ - if (!fmt[0]) { - for (;input[input_index]; input_index++) - vec_add1(this, input[input_index]); - if (vec_len(this)) { - vec_add1(this, 0); -#ifdef MATCH_TRACE - printf("final star-match adds: '%s'\n", this); -#endif - vec_add1(rv, this); - } else { - vec_add1(string_cache, this); - } - - return(rv); - } - } - /* - * Left-to-right scan, adding chars until next delimiter char - * appears. - */ - if (!dirflag) { - while (input[input_index]) { - if (input[input_index] == fmt[0]) { - /* If we just (exact) matched a whitespace delimiter */ - if (fmt[0] == ' '){ - /* scan forward eating whitespace */ - while (input[input_index] == ' ' || - input[input_index] == '\t' || - input[input_index] == '\n') - input_index++; - input_index--; - } - goto found; - } - /* If we're looking for whitespace */ - if (fmt[0] == ' ') { - /* and we have whitespace */ - if (input[input_index] == ' ' || - input[input_index] == '\t' || - input[input_index] == '\n') { - /* scan forward eating whitespace */ - while (input[input_index] == ' ' || - input[input_index] == '\t' || - input[input_index] == '\n') { - input_index++; - } - input_index--; - goto found; - } - } - /* Not a delimiter, save it */ - vec_add1(this, input[input_index]); - input_index++; - } - /* - * Fell off the wagon, clean up and bail out - */ - bail: - -#ifdef MATCH_TRACE - printf("failed, fmt[0] = '%c', input[%d]='%s'\n", - fmt[0], input_index, &input[input_index]); -#endif - delsvec_recycle_this_string(this); - for (i = 0; i < vec_len(rv); i++) - delsvec_recycle_this_string(rv[i]); - delsvec_recycle_this_svec(rv); - return(0); - - found: - /* - * Delimiter matched - */ - input_index++; - fmt++; - /* - * If we actually accumulated non-delimiter characters, - * add them to the result vector - */ - if (vec_len(this)) { - vec_add1(this, 0); -#ifdef MATCH_TRACE - printf("match: add '%s'\n", this); -#endif - vec_add1(rv, this); - } else { - vec_add1(string_cache, this); - } - } else { - /* - * right-to-left scan, '*' not at - * the end of the delimiter string - */ - i = input_index; - while (input[++i]) - ; /* scan forward */ - i--; - while (i > input_index) { - if (input[i] == fmt[0]) - goto found2; - - if (fmt[0] == ' ' || fmt[0] == '\t' || - fmt[0] == '\n') { - if (input[i] == ' ' || - input[i] == '\t' || - input[i] == '\n') - goto found2; - } - i--; - } - goto bail; - - found2: - for (; input_index < i; input_index++) { - vec_add1(this, input[input_index]); - } - input_index++; - fmt++; - vec_add1(this, 0); -#ifdef MATCH_TRACE - printf("inner '*' match: add '%s'\n", this); -#endif - vec_add1(rv, this); - } - } - return (rv); -} - -#ifdef UNIT_TESTS - -typedef struct utest_ { - char *string; - char *fmt; -} utest_t; - -utest_t tests[] = { -#ifdef NOTDEF - {"Dec 7 08:56", - " :*"}, - {"Dec 17 08:56", - " :*"}, - {"Dec 7 08:56:41.239 install/inst_repl 0/9/CPU0 t1 [40989] File List:Successfully blobbified file list. Took 1 milliseconds", - " ::. / // [] *"}, - {"RP/0/9/CPU0:Dec 7 08:55:28.550 : sam_server[291]: SAM backs up digest list to memory file", - "///: ::. : []: *"}, - /* Expected to fail */ - {"Dec 7 08:56:41.239 install/inst_repl 0/9/CPU0 t1 [40989] File List:Successfully blobbified file list. Took 1 milliseconds", - "///: ::. : : *"}, - /* Expected to fail */ - {"RP/0/9/CPU0:Dec 7 08:55:28.550 : sam_server[291]: SAM backs up digest list to memory file", - " ::. / // [] *"}, - {"THIS that and + theother", "*+ *"}, - {"Dec 12 15:33:07.103 ifmgr/errors 0/RP0/CPU0 3# t2 Failed to open IM connection: No such file or directory", " ::. / // *"}, - {"Dec 16 21:43:47.328 ifmgr/bulk 0/3/CPU0 t8 Bulk DPC async download complete. Partitions 1, node_count 1, total_out 0, out_offset 0, out_expected 0: No error"," ::. / // *"}, - {"t:0x53034bd6 CPU:00 PROCESS :PROCCREATE_NAME", - ": : :*"}, - {" pid:1", " *"}, - {"t:0x53034cbb CPU:00 THREAD :THCREATE pid:1 tid:1", - ": : : pid: tid:*"}, - {"t:0x5303f950 CPU:00 COMM :REC_PULSE scoid:0x40000003 pid:364659", - ": : : *"}, - {"/hfr-base-3.3.85/lib/libttyconnection.dll 0xfc000000 0x0000306c 0xfc027000 0x000001c8 1", - " *"}, - {"Feb 28 02:38:26.123 seqtrace 0/1/CPU0 t8 :msg_receive:ifmgr/t8:IMC_MSG_MTU_UPDATE:ppp_ma/t1", - " ::. // ::::*"}, - - {"Feb 28 02:38:26.123 seqtrace 0/1/CPU0 t8 :msg_send_event:call:ifmgr/t8:124/0:cdp/t1", - " ::. // :msg_send_event::::*"}, - - {"Feb 28 02:38:26.125 seqtrace 0/1/CPU0 t1 :msg_receive_event:cdp/t1:124/0", - " ::. // :msg_receive_event::*"} - {"t:0x645dd86d CPU:00 USREVENT:EVENT:100, d0:0x00000002 d1:0x00000000", - ": : USREVENT:EVENT:, d0: *"} - {"t:0x5303f950 CPU:00 COMM :REC_PULSE scoid:0x40000003 pid:364659", - ": : : *"}, - {"t:0x2ccf9f5a CPU:00 INT_ENTR:0x80000000 (-2147483648) IP:0x002d8b18", - ": : INT_ENTR: IP:*"} - {"t:0xd473951c CPU:00 KER_EXIT:SCHED_GET/88 ret_val:2 sched_priority:10", - ": : KER_EXIT:SCHED_GET : sched_priority:*"} - {"t:0x00000123 CPU:01 SYSTEM :FUNC_ENTER thisfn:0x40e62048 call_site:0x00000000", - ": : SYSTEM :FUNC_ thisfn: *"}, - {"t:0x5af8de95 CPU:00 INT_HANDLER_ENTR:0x0000004d (77) PID:8200 IP:0x00000000 AREA:0x0bf9b290", ": : INT_HANDLER_*"}, -#endif - {"t:0x6d1ff92f CPU:00 CONTROL: BUFFER sequence = 1053, num_events = 714", - ": : CONTROL*"}, - {"t:0x6d1ff92f CPU:00 CONTROL :TIME msb:0x0000003c lsb(offset):0x6d1ff921", - ": : CONTROL*"}, -}; - -int main (int argc, char **argv) -{ - int i, j; - u8 **svec; - - for (j = 0; j < ARRAY_LEN(tests); j++) { - printf ("input string: '%s'\n", tests[j].string); - printf ("delimiter arg: '%s'\n", tests[j].fmt); - printf ("parse trace:\n"); - svec = delsvec(tests[j].string, tests[j].fmt); - if (!svec) { - printf("index %d failed\n", j); - continue; - } - printf("%d substring vectors\n", vec_len(svec)); - for (i = 0; i < vec_len(svec); i++) { - printf("[%d]: '%s'\n", i, svec[i]); - } - printf ("-------------------\n"); - } - exit(0); -} -#endif diff --git a/perftool/linreg.c b/perftool/linreg.c deleted file mode 100644 index 084091bb..00000000 --- a/perftool/linreg.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2006-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* see "Numerical Recipies in C, 2nd ed." p 665 */ - -#include -#include - -/* - * linreg - * Linear regression of (xi, yi), returns parameters for least-squares - * fit y = a + bx. Also, compute Pearson's R. - */ -void linreg (double *x, double *y, int nitems, double *a, double *b, - double *minp, double *maxp, double *meanp, double *r) -{ - double sx = 0.0; - double sy = 0.0; - double st2 = 0.0; - double min = y[0]; - double max = 0.0; - double ss, meanx, meany, t; - double errx, erry, prodsum, sqerrx, sqerry; - int i; - - *b = 0.0; - - for (i = 0; i < nitems; i++) { - sx += x[i]; - sy += y[i]; - if (y[i] < min) - min = y[i]; - if (y[i] > max) - max = y[i]; - } - ss = nitems; - meanx = sx / ss; - meany = *meanp = sy / ss; - *minp = min; - *maxp = max; - - for (i = 0; i < nitems; i++) { - t = x[i] - meanx; - st2 += t*t; - *b += t*y[i]; - } - - *b /= st2; - *a = (sy-sx*(*b))/ss; - - prodsum = 0.0; - sqerrx = 0.0; - sqerry = 0.0; - - /* Compute numerator of Pearson's R */ - for (i = 0; i < nitems; i++) { - errx = x[i] - meanx; - erry = y[i] - meany; - prodsum += errx * erry; - sqerrx += errx*errx; - sqerry += erry*erry; - } - - *r = prodsum / (sqrt(sqerrx)*sqrt(sqerry)); -} diff --git a/perftool/new.cpel b/perftool/new.cpel deleted file mode 100644 index b0f35958..00000000 Binary files a/perftool/new.cpel and /dev/null differ diff --git a/perftool/new.elog b/perftool/new.elog deleted file mode 100644 index 2d99bb16..00000000 Binary files a/perftool/new.elog and /dev/null differ diff --git a/perftool/props.c b/perftool/props.c deleted file mode 100644 index 84af5b1c..00000000 --- a/perftool/props.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2006-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 - -static char *sxerox (char *s); - -#define NBUCKETS 97 - -typedef struct prop_ { - struct prop_ *next; - char *name; - char *value; -} prop_t; - -static prop_t *buckets [NBUCKETS]; -static int hash_shifts[4] = {24, 16, 8, 0}; - -/* - * getprop - */ - -char *getprop (char *name) -{ - unsigned char *cp; - unsigned long hash=0; - prop_t *bp; - int i=0; - - for (cp = (unsigned char *) name; *cp; cp++) - hash ^= (*cp)<<(hash_shifts[(i++)&0x3]); - - bp = buckets [hash%NBUCKETS]; - - while (bp && strcmp(bp->name, name)) { - bp = bp->next; - } - - if (bp == NULL) - return (0); - else - return (bp->value); -} - -/* - * getprop_default - */ - -char *getprop_default (char *name, char *def) -{ - char *rv; - rv = getprop (name); - if (rv) - return (rv); - else - return (def); -} - -/* - * addprop - */ - -void addprop (char *name, char *value) -{ - unsigned char *cp; - unsigned long hash=0; - prop_t **bpp; - prop_t *bp; - int i=0; - - bp = (prop_t *)malloc (sizeof (prop_t)); - - bp->next = 0; - bp->name = sxerox (name); - bp->value = sxerox (value); - - for (cp = (unsigned char *)name; *cp; cp++) - hash ^= (*cp)<<(hash_shifts[(i++)&0x3]); - - bpp = &buckets [hash%NBUCKETS]; - - if (*bpp == NULL) - *bpp = bp; - else { - bp->next = *bpp; - *bpp = bp; - } -} - -/* - * sxerox - */ - -static char *sxerox (char *s) -{ - char *rv = (char *) malloc (strlen (s) + 1); - strcpy (rv, s); - return rv; -} - -/* - * readprops - */ - -#define START 0 -#define READNAME 1 -#define READVALUE 2 -#define C_COMMENT 3 -#define CPP_COMMENT 4 - -int readprops (char *filename) -{ - FILE *ifp; - unsigned char c; - int state=START; - int linenum=1; - char namebuf [128]; - char valbuf [512]; - int i; - - ifp = fopen (filename, "r"); - - if (ifp == NULL) - return (-1); - - while (1) { - - readchar: - c = getc (ifp); - - again: - switch (state) { - case START: - if (feof (ifp)) { - fclose (ifp); - return (0); - } - - if (c == ' ' || c == '\t') - goto readchar; - - if (c == '\n') { - linenum++; - goto readchar; - } - if (isalpha (c) || (c == '_')) { - state = READNAME; - goto again; - } - if (c == '/') { - c = getc (ifp); - if (c == '/') { - state = CPP_COMMENT; - goto readchar; - } else if (c == '*') { - state = C_COMMENT; - goto readchar; - } else { - fprintf (stderr, "unknown token '/' line %d\n", - linenum); - exit(1); - } - } - fprintf (stderr, "unknown token '%c' line %d\n", - c, linenum); - exit (1); - break; - - case CPP_COMMENT: - while (1) { - c = getc (ifp); - if (feof (ifp)) - return (0); - if (c == '\n') { - linenum++; - state = START; - goto readchar; - } - } - break; - - case C_COMMENT: - while (1) { - c = getc (ifp); - if (feof (ifp)) { - fprintf (stderr, "unterminated comment, line %d\n", - linenum); - exit (1); - } - if (c == '*') { - staragain: - c = getc (ifp); - if (c == '/') { - state = START; - goto readchar; - } - if (c == '*') - goto staragain; - } - } - break; - - case READNAME: - i = 0; - namebuf[i++] = c; - while (1) { - c = getc (ifp); - if (feof (ifp)) { - fprintf (stderr, "EOF while reading a name, line %d\n", - linenum); - exit (1); - } - if ((!isalnum (c)) && (c != '_')) { - namebuf [i] = 0; - state = READVALUE; - goto again; - } - namebuf [i++] = c; - } - break; - - case READVALUE: - i = 0; - while ((c == ' ') || (c == '\t') || (c == '=')) { - c = getc (ifp); - if (feof (ifp)) { - fprintf (stderr, "EOF while reading a value, line %d\n", - linenum); - exit (1); - } - } - goto firsttime; - while (1) { - c = getc (ifp); - - firsttime: - if (c == '\\') { - c = getc (ifp); - if (feof (ifp)) { - fprintf (stderr, "EOF after '\\', line %d\n", - linenum); - exit (1); - } - valbuf[i++] = c; - continue; - } - if (c == '\n') { - linenum++; - while (valbuf [i-1] == ' ' || valbuf[i-1] == '\t') - i--; - valbuf[i] = 0; - addprop (namebuf, valbuf); - state = START; - goto readchar; - } - valbuf[i++] = c; - } - - } - } -} diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 100f089e..a101e47f 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -28,10 +28,6 @@ if ENABLE_sample_PLUGIN SUBDIRS += sample-plugin endif -if ENABLE_sixrd_PLUGIN -SUBDIRS += sixrd-plugin -endif - if ENABLE_ioam_PLUGIN SUBDIRS += ioam-plugin endif @@ -44,18 +40,10 @@ if ENABLE_snat_PLUGIN SUBDIRS += snat-plugin endif -if ENABLE_ila_PLUGIN -SUBDIRS += ila-plugin -endif - if ENABLE_lb_PLUGIN SUBDIRS += lb-plugin endif -if ENABLE_flowperpkt_PLUGIN -SUBDIRS += flowperpkt-plugin -endif - if ENABLE_acl_PLUGIN SUBDIRS += acl-plugin endif diff --git a/plugins/configure.ac b/plugins/configure.ac index 6e7d5b8a..9c631634 100644 --- a/plugins/configure.ac +++ b/plugins/configure.ac @@ -53,12 +53,9 @@ AM_CONDITIONAL(ENABLE_$1_PLUGIN, test "$enable_the_plugin" = "1") # SUBDIRS += new-plugin # endif -PLUGIN_ENABLED(sixrd) PLUGIN_ENABLED(ioam) PLUGIN_ENABLED(snat) -PLUGIN_ENABLED(ila) PLUGIN_ENABLED(lb) -PLUGIN_ENABLED(flowperpkt) PLUGIN_ENABLED(acl) # Disabled plugins, require --enable-XXX-plugin diff --git a/plugins/flowperpkt-plugin/Makefile.am b/plugins/flowperpkt-plugin/Makefile.am deleted file mode 100644 index 9354e26f..00000000 --- a/plugins/flowperpkt-plugin/Makefile.am +++ /dev/null @@ -1,64 +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 -AM_LDFLAGS = -module -shared -avoid-version - -vppapitestpluginsdir = ${libdir}/vpp_api_test_plugins -vpppluginsdir = ${libdir}/vpp_plugins - -vppplugins_LTLIBRARIES = flowperpkt_plugin.la -vppapitestplugins_LTLIBRARIES = flowperpkt_test_plugin.la - -flowperpkt_plugin_la_SOURCES = flowperpkt/flowperpkt.c \ - flowperpkt/l2_node.c \ - flowperpkt/node.c \ - flowperpkt/flowperpkt_plugin.api.h -flowperpkt_plugin_la_LDFLAGS = -module - -BUILT_SOURCES = \ - flowperpkt/flowperpkt.api.h \ - flowperpkt/flowperpkt.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)/flowperpkt/ -api_DATA = flowperpkt/flowperpkt.api.json - -noinst_HEADERS = \ - flowperpkt/flowperpkt_all_api_h.h \ - flowperpkt/flowperpkt_msg_enum.h \ - flowperpkt/flowperpkt.api.h - -flowperpkt_test_plugin_la_SOURCES = \ - flowperpkt/flowperpkt_test.c flowperpkt/flowperpkt_plugin.api.h - -# Remove *.la files -install-data-hook: - @(cd $(vpppluginsdir) && $(RM) $(vppplugins_LTLIBRARIES)) - @(cd $(vppapitestpluginsdir) && $(RM) $(vppapitestplugins_LTLIBRARIES)) - diff --git a/plugins/flowperpkt-plugin/configure.ac b/plugins/flowperpkt-plugin/configure.ac deleted file mode 100644 index 80546169..00000000 --- a/plugins/flowperpkt-plugin/configure.ac +++ /dev/null @@ -1,9 +0,0 @@ - -AC_INIT(flowperpkt_plugin, 1.0) -AM_INIT_AUTOMAKE -AM_SILENT_RULES([yes]) - -AC_PROG_LIBTOOL -AC_PROG_CC - -AC_OUTPUT([Makefile]) diff --git a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt.api b/plugins/flowperpkt-plugin/flowperpkt/flowperpkt.api deleted file mode 100644 index fa878f21..00000000 --- a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt.api +++ /dev/null @@ -1,42 +0,0 @@ -/* Define a simple enable-disable binary API to control the feature */ - -/** \file - This file defines the vpp control-plane API messages - used to control the flowperpkt plugin -*/ - -/** \brief Enable / disable per-packet IPFIX recording on an interface - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param is_add - add address if non-zero, else delete - @param is_ipv6 - if non-zero the address is ipv6, else ipv4 - @param sw_if_index - index of the interface -*/ -manual_print define flowperpkt_tx_interface_add_del -{ - /* 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_add; - u8 which; /* 0 = ipv4, 1 = l2, 2 = ipv6 (not yet implemented) */ - - /* Interface handle */ - u32 sw_if_index; -}; - -/** \brief Reply to enable/disable per-packet IPFIX recording messages - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define flowperpkt_tx_interface_add_del_reply -{ - /* From the request */ - u32 context; - - /* Return value, zero means all OK */ - i32 retval; -}; diff --git a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt.c b/plugins/flowperpkt-plugin/flowperpkt/flowperpkt.c deleted file mode 100644 index fb71d5b0..00000000 --- a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt.c +++ /dev/null @@ -1,671 +0,0 @@ -/* - * flowperpkt.c - per-packet data capture flow report plugin - * - * 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. - */ - -/** - * @file - * @brief Per-packet IPFIX flow record generator plugin - * - * This file implements vpp plugin registration mechanics, - * debug CLI, and binary API 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 - -flowperpkt_main_t flowperpkt_main; - -/* Get the API version number */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#undef vl_api_version - -/* Define the per-interface configurable features */ -/* *INDENT-OFF* */ -VNET_FEATURE_INIT (flow_perpacket_ipv4, static) = -{ - .arc_name = "ip4-output", - .node_name = "flowperpkt-ipv4", - .runs_before = VNET_FEATURES ("interface-output"), -}; - -VNET_FEATURE_INIT (flow_perpacket_l2, static) = -{ - .arc_name = "interface-output", - .node_name = "flowperpkt-l2", - .runs_before = VNET_FEATURES ("interface-tx"), -}; -/* *INDENT-ON* */ - -/* - * 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)+fm->msg_id_base); \ - rmp->context = mp->context; \ - rmp->retval = ntohl(rv); \ - \ - vl_msg_api_send_shmem (q, (u8 *)&rmp); \ -} while(0); - -/* Macro to finish up custom dump fns */ -#define FINISH \ - vec_add1 (s, 0); \ - vl_print (handle, (char *)s); \ - vec_free (s); \ - return handle; - -#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); - -/** - * @brief Create an IPFIX template packet rewrite string - * @param frm flow_report_main_t * - * @param fr flow_report_t * - * @param collector_address ip4_address_t * the IPFIX collector address - * @param src_address ip4_address_t * the source address we should use - * @param collector_port u16 the collector port we should use, host byte order - * @returns u8 * vector containing the indicated IPFIX template packet - */ -static inline u8 * -flowperpkt_template_rewrite_inline (flow_report_main_t * frm, - flow_report_t * fr, - ip4_address_t * collector_address, - ip4_address_t * src_address, - u16 collector_port, int variant) -{ - ip4_header_t *ip; - udp_header_t *udp; - ipfix_message_header_t *h; - ipfix_set_header_t *s; - ipfix_template_header_t *t; - ipfix_field_specifier_t *f; - ipfix_field_specifier_t *first_field; - u8 *rewrite = 0; - ip4_ipfix_template_packet_t *tp; - u32 field_count = 0; - flow_report_stream_t *stream; - flowperpkt_main_t *fm = &flowperpkt_main; - - stream = &frm->streams[fr->stream_index]; - - if (variant == FLOW_VARIANT_IPV4) - { - /* - * ip4 Supported Fields: - * - * ingressInterface, TLV type 10, u32 - * egressInterface, TLV type 14, u32 - * sourceIpv4Address, TLV type 8, u32 - * destinationIPv4Address, TLV type 12, u32 - * ipClassOfService, TLV type 5, u8 - * flowStartNanoseconds, TLV type 156, dateTimeNanoseconds (f64) - * Implementation: f64 nanoseconds since VPP started - * warning: wireshark doesn't really understand this TLV - * dataLinkFrameSize, TLV type 312, u16 - * warning: wireshark doesn't understand this TLV at all - */ - - /* Currently 7 fields */ - field_count += 7; - - /* allocate rewrite space */ - vec_validate_aligned - (rewrite, - sizeof (ip4_ipfix_template_packet_t) - + field_count * sizeof (ipfix_field_specifier_t) - 1, - CLIB_CACHE_LINE_BYTES); - } - else if (variant == FLOW_VARIANT_L2) - { - /* - * L2 Supported Fields: - * - * ingressInterface, TLV type 10, u32 - * egressInterface, TLV type 14, u32 - * sourceMacAddress, TLV type 56, u8[6] we hope - * destinationMacAddress, TLV type 57, u8[6] we hope - * ethernetType, TLV type 256, u16 - * flowStartNanoseconds, TLV type 156, dateTimeNanoseconds (f64) - * Implementation: f64 nanoseconds since VPP started - * warning: wireshark doesn't really understand this TLV - * dataLinkFrameSize, TLV type 312, u16 - * warning: wireshark doesn't understand this TLV at all - */ - - /* Currently 7 fields */ - field_count += 7; - - /* allocate rewrite space */ - vec_validate_aligned - (rewrite, - sizeof (ip4_ipfix_template_packet_t) - + field_count * sizeof (ipfix_field_specifier_t) - 1, - CLIB_CACHE_LINE_BYTES); - } - - tp = (ip4_ipfix_template_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); - t = (ipfix_template_header_t *) (s + 1); - first_field = f = (ipfix_field_specifier_t *) (t + 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 (stream->src_port); - udp->dst_port = clib_host_to_net_u16 (collector_port); - udp->length = clib_host_to_net_u16 (vec_len (rewrite) - sizeof (*ip)); - - /* FIXUP: message header export_time */ - /* FIXUP: message header sequence_number */ - h->domain_id = clib_host_to_net_u32 (stream->domain_id); - - /* Add TLVs to the template */ - if (variant == FLOW_VARIANT_IPV4) - { - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , ingressInterface, - 4); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , egressInterface, - 4); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , sourceIPv4Address, - 4); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , destinationIPv4Address, 4); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , ipClassOfService, - 1); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , flowStartNanoseconds, - 8); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , dataLinkFrameSize, - 2); - f++; - } - else if (variant == FLOW_VARIANT_L2) - { - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , ingressInterface, - 4); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , egressInterface, - 4); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , sourceMacAddress, - 6); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , destinationMacAddress, 6); - f++; - f->e_id_length = ipfix_e_id_length (0 /* enterprise */ , ethernetType, - 2); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , flowStartNanoseconds, - 8); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , dataLinkFrameSize, - 2); - f++; - } - - /* Extend in the obvious way, right here... */ - - /* Back to the template packet... */ - ip = (ip4_header_t *) & tp->ip4; - udp = (udp_header_t *) (ip + 1); - - ASSERT (f - first_field); - /* Field count in this template */ - t->id_count = ipfix_id_count (fr->template_id, f - first_field); - - if (variant == FLOW_VARIANT_IPV4) - fm->ipv4_report_id = fr->template_id; - else if (variant == FLOW_VARIANT_L2) - fm->l2_report_id = fr->template_id; - - /* set length in octets */ - s->set_id_length = - ipfix_set_id_length (2 /* set_id */ , (u8 *) f - (u8 *) s); - - /* message length in octets */ - h->version_length = version_length ((u8 *) f - (u8 *) h); - - ip->length = clib_host_to_net_u16 ((u8 *) f - (u8 *) ip); - ip->checksum = ip4_header_checksum (ip); - - return rewrite; -} - -u8 * -flowperpkt_template_rewrite_ipv4 (flow_report_main_t * frm, - flow_report_t * fr, - ip4_address_t * collector_address, - ip4_address_t * src_address, - u16 collector_port) -{ - return flowperpkt_template_rewrite_inline - (frm, fr, collector_address, src_address, collector_port, - FLOW_VARIANT_IPV4); -} - -u8 * -flowperpkt_template_rewrite_l2 (flow_report_main_t * frm, - flow_report_t * fr, - ip4_address_t * collector_address, - ip4_address_t * src_address, - u16 collector_port) -{ - return flowperpkt_template_rewrite_inline - (frm, fr, collector_address, src_address, collector_port, - FLOW_VARIANT_L2); -} - - -/** - * @brief Flush accumulated data - * @param frm flow_report_main_t * - * @param fr flow_report_t * - * @param f vlib_frame_t * - * - * Notes: - * This function must simply return the incoming frame, or no template packets - * will be sent. - */ -vlib_frame_t * -flowperpkt_data_callback_ipv4 (flow_report_main_t * frm, - flow_report_t * fr, - vlib_frame_t * f, u32 * to_next, - u32 node_index) -{ - flowperpkt_flush_callback_ipv4 (); - return f; -} - -vlib_frame_t * -flowperpkt_data_callback_l2 (flow_report_main_t * frm, - flow_report_t * fr, - vlib_frame_t * f, u32 * to_next, u32 node_index) -{ - flowperpkt_flush_callback_l2 (); - return f; -} - -/** - * @brief configure / deconfigure the IPFIX flow-per-packet - * @param fm flowperpkt_main_t * fm - * @param sw_if_index u32 the desired interface - * @param is_add int 1 to enable the feature, 0 to disable it - * @returns 0 if successful, non-zero otherwise - */ - -static int flowperpkt_tx_interface_add_del_feature - (flowperpkt_main_t * fm, u32 sw_if_index, int which, int is_add) -{ - flow_report_main_t *frm = &flow_report_main; - vnet_flow_report_add_del_args_t _a, *a = &_a; - int rv; - - if (which == FLOW_VARIANT_IPV4 && !fm->ipv4_report_created) - { - memset (a, 0, sizeof (*a)); - a->rewrite_callback = flowperpkt_template_rewrite_ipv4; - a->flow_data_callback = flowperpkt_data_callback_ipv4; - a->is_add = 1; - a->domain_id = 1; /*$$$$ config parameter */ - a->src_port = 4739; /*$$$$ config parameter */ - fm->ipv4_report_created = 1; - - rv = vnet_flow_report_add_del (frm, a); - if (rv) - { - clib_warning ("vnet_flow_report_add_del returned %d", rv); - return -1; - } - } - else if (which == FLOW_VARIANT_L2 && !fm->l2_report_created) - { - memset (a, 0, sizeof (*a)); - a->rewrite_callback = flowperpkt_template_rewrite_l2; - a->flow_data_callback = flowperpkt_data_callback_l2; - a->is_add = 1; - a->domain_id = 1; /*$$$$ config parameter */ - a->src_port = 4739; /*$$$$ config parameter */ - fm->l2_report_created = 1; - - rv = vnet_flow_report_add_del (frm, a); - if (rv) - { - clib_warning ("vnet_flow_report_add_del returned %d", rv); - return -1; - } - } - - if (which == FLOW_VARIANT_IPV4) - vnet_feature_enable_disable ("ip4-output", "flowperpkt-ipv4", - sw_if_index, is_add, 0, 0); - else if (which == FLOW_VARIANT_L2) - vnet_feature_enable_disable ("interface-output", "flowperpkt-l2", - sw_if_index, is_add, 0, 0); - - return 0; -} - -/** - * @brief API message handler - * @param mp vl_api_flowperpkt_tx_interface_add_del_t * mp the api message - */ -void vl_api_flowperpkt_tx_interface_add_del_t_handler - (vl_api_flowperpkt_tx_interface_add_del_t * mp) -{ - flowperpkt_main_t *fm = &flowperpkt_main; - vl_api_flowperpkt_tx_interface_add_del_reply_t *rmp; - u32 sw_if_index = ntohl (mp->sw_if_index); - int rv = 0; - - VALIDATE_SW_IF_INDEX (mp); - - if (mp->which != FLOW_VARIANT_IPV4 && mp->which != FLOW_VARIANT_L2) - { - rv = VNET_API_ERROR_UNIMPLEMENTED; - goto out; - } - - rv = flowperpkt_tx_interface_add_del_feature (fm, sw_if_index, mp->which, - mp->is_add); -out: - BAD_SW_IF_INDEX_LABEL; - - REPLY_MACRO (VL_API_FLOWPERPKT_TX_INTERFACE_ADD_DEL_REPLY); -} - -/** - * @brief API message custom-dump function - * @param mp vl_api_flowperpkt_tx_interface_add_del_t * mp the api message - * @param handle void * print function handle - * @returns u8 * output string - */ -static void *vl_api_flowperpkt_tx_interface_add_del_t_print - (vl_api_flowperpkt_tx_interface_add_del_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: flowperpkt_tx_interface_add_del "); - s = format (s, "sw_if_index %d is_add %d which %d ", - clib_host_to_net_u32 (mp->sw_if_index), - (int) mp->is_add, (int) mp->which); - FINISH; -} - -/* List of message types that this plugin understands */ -#define foreach_flowperpkt_plugin_api_msg \ -_(FLOWPERPKT_TX_INTERFACE_ADD_DEL, flowperpkt_tx_interface_add_del) - -/** - * @brief plugin-api required function - * @param vm vlib_main_t * vlib main data structure pointer - * @param h vlib_plugin_handoff_t * handoff structure - * @param from_early_init int notused - * - * Notes: - * 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) -{ - flowperpkt_main_t *fm = &flowperpkt_main; - clib_error_t *error = 0; - - fm->vlib_main = vm; - fm->vnet_main = h->vnet_main; - - return error; -} - -static clib_error_t * -flowperpkt_tx_interface_add_del_feature_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - flowperpkt_main_t *fm = &flowperpkt_main; - u32 sw_if_index = ~0; - int is_add = 1; - u8 which = FLOW_VARIANT_IPV4; - - int rv; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "disable")) - is_add = 0; - else if (unformat (input, "%U", unformat_vnet_sw_interface, - fm->vnet_main, &sw_if_index)); - else if (unformat (input, "l2")) - which = FLOW_VARIANT_L2; - else - break; - } - - if (sw_if_index == ~0) - return clib_error_return (0, "Please specify an interface..."); - - rv = - flowperpkt_tx_interface_add_del_feature (fm, sw_if_index, which, is_add); - 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, "ip6 not supported"); - break; - - default: - return clib_error_return (0, "flowperpkt_enable_disable returned %d", - rv); - } - return 0; -} - -/*? - * 'flowperpkt feature add-del' commands to enable/disable - * per-packet IPFIX flow record generation on an interface - * - * @cliexpar - * @parblock - * To enable per-packet IPFIX flow-record generation on an interface: - * @cliexcmd{flowperpkt feature add-del GigabitEthernet2/0/0} - * - * To disable per-packet IPFIX flow-record generation on an interface: - * @cliexcmd{flowperpkt feature add-del GigabitEthernet2/0/0 disable} - * @cliexend - * @endparblock -?*/ -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (flowperpkt_enable_disable_command, static) = { - .path = "flowperpkt feature add-del", - .short_help = - "flowperpkt feature add-del [disable]", - .function = flowperpkt_tx_interface_add_del_feature_command_fn, -}; -/* *INDENT-ON* */ - -/** - * @brief Set up the API message handling tables - * @param vm vlib_main_t * vlib main data structure pointer - * @returns 0 to indicate all is well - */ -static clib_error_t * -flowperpkt_plugin_api_hookup (vlib_main_t * vm) -{ - flowperpkt_main_t *fm = &flowperpkt_main; -#define _(N,n) \ - vl_msg_api_set_handlers((VL_API_##N + fm->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_flowperpkt_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 (flowperpkt_main_t * fm, api_main_t * am) -{ -#define _(id,n,crc) \ - vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + fm->msg_id_base); - foreach_vl_msg_name_crc_flowperpkt; -#undef _ -} - -/** - * @brief Set up the API message handling tables - * @param vm vlib_main_t * vlib main data structure pointer - * @returns 0 to indicate all is well, or a clib_error_t - */ -static clib_error_t * -flowperpkt_init (vlib_main_t * vm) -{ - flowperpkt_main_t *fm = &flowperpkt_main; - vlib_thread_main_t *tm = &vlib_thread_main; - clib_error_t *error = 0; - u32 num_threads; - u8 *name; - - /* Construct the API name */ - name = format (0, "flowperpkt_%08x%c", api_version, 0); - - /* Ask for a correctly-sized block of API message decode slots */ - fm->msg_id_base = vl_msg_api_get_msg_ids - ((char *) name, VL_MSG_FIRST_AVAILABLE); - - /* Hook up message handlers */ - error = flowperpkt_plugin_api_hookup (vm); - - /* Add our API messages to the global name_crc hash table */ - setup_message_id_table (fm, &api_main); - - vec_free (name); - - /* Decide how many worker threads we have */ - num_threads = 1 /* main thread */ + tm->n_eal_threads; - - /* Allocate per worker thread vectors */ - vec_validate (fm->ipv4_buffers_per_worker, num_threads - 1); - vec_validate (fm->l2_buffers_per_worker, num_threads - 1); - vec_validate (fm->ipv4_frames_per_worker, num_threads - 1); - vec_validate (fm->l2_frames_per_worker, num_threads - 1); - vec_validate (fm->ipv4_next_record_offset_per_worker, num_threads - 1); - vec_validate (fm->l2_next_record_offset_per_worker, num_threads - 1); - - /* Set up time reference pair */ - fm->vlib_time_0 = vlib_time_now (vm); - fm->nanosecond_time_0 = unix_time_now_nsec (); - - return error; -} - -VLIB_INIT_FUNCTION (flowperpkt_init); - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt.h b/plugins/flowperpkt-plugin/flowperpkt/flowperpkt.h deleted file mode 100644 index 20f6939d..00000000 --- a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * flowperpkt.h - skeleton vpp engine plug-in header 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. - */ -#ifndef __included_flowperpkt_h__ -#define __included_flowperpkt_h__ - -#include -#include -#include - -#include -#include -#include -#include - -/** - * @file - * @brief flow-per-packet plugin header file - */ -typedef struct -{ - /** API message ID base */ - u16 msg_id_base; - - /** Have the reports [templates] been created? */ - int ipv4_report_created; - int l2_report_created; - - /** stream/template IDs */ - u16 ipv4_report_id; - u16 l2_report_id; - - /** ipfix buffers under construction, per-worker thread */ - vlib_buffer_t **ipv4_buffers_per_worker; - vlib_buffer_t **l2_buffers_per_worker; - - /** frames containing ipfix buffers, per-worker thread */ - vlib_frame_t **ipv4_frames_per_worker; - vlib_frame_t **l2_frames_per_worker; - - /** next record offset, per worker thread */ - u16 *ipv4_next_record_offset_per_worker; - u16 *l2_next_record_offset_per_worker; - - /** Time reference pair */ - u64 nanosecond_time_0; - f64 vlib_time_0; - - /** convenience vlib_main_t pointer */ - vlib_main_t *vlib_main; - /** convenience vnet_main_t pointer */ - vnet_main_t *vnet_main; -} flowperpkt_main_t; - -typedef enum -{ - FLOW_VARIANT_IPV4, - FLOW_VARIANT_L2, - FLOW_N_VARIANTS, -} flowperpkt_variant_t; - -extern flowperpkt_main_t flowperpkt_main; - -extern vlib_node_registration_t flowperpkt_ipv4_node; - -void flowperpkt_flush_callback_ipv4 (void); -void flowperpkt_flush_callback_l2 (void); - -#endif /* __included_flowperpkt_h__ */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt_all_api_h.h b/plugins/flowperpkt-plugin/flowperpkt/flowperpkt_all_api_h.h deleted file mode 100644 index 329c375a..00000000 --- a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt_all_api_h.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * flowperpkt_all_api_h.h - 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/flowperpkt-plugin/flowperpkt/flowperpkt_msg_enum.h b/plugins/flowperpkt-plugin/flowperpkt/flowperpkt_msg_enum.h deleted file mode 100644 index 3177e77a..00000000 --- a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt_msg_enum.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * flowperpkt_msg_enum.h - 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_flowperpkt_msg_enum_h -#define included_flowperpkt_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_flowperpkt_msg_enum_h */ diff --git a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt_test.c b/plugins/flowperpkt-plugin/flowperpkt/flowperpkt_test.c deleted file mode 100644 index 716818ff..00000000 --- a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt_test.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * flowperpkt.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 - -/** - * @file vpp_api_test plugin - */ - -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 pointer */ - vat_main_t *vat_main; -} flowperpkt_test_main_t; - -flowperpkt_test_main_t flowperpkt_test_main; - -#define foreach_standard_reply_retval_handler \ -_(flowperpkt_tx_interface_add_del_reply) - -#define _(n) \ - static void vl_api_##n##_t_handler \ - (vl_api_##n##_t * mp) \ - { \ - vat_main_t * vam = flowperpkt_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 \ -_(FLOWPERPKT_TX_INTERFACE_ADD_DEL_REPLY, \ - flowperpkt_tx_interface_add_del_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_flowperpkt_tx_interface_add_del (vat_main_t * vam) -{ - flowperpkt_test_main_t *sm = &flowperpkt_test_main; - unformat_input_t *i = vam->input; - f64 timeout; - int enable_disable = 1; - u8 which = 0; /* ipv4 by default */ - u32 sw_if_index = ~0; - vl_api_flowperpkt_tx_interface_add_del_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 if (unformat (i, "l2")) - which = 1; - else - break; - } - - if (sw_if_index == ~0) - { - errmsg ("missing interface name / explicit sw_if_index number \n"); - return -99; - } - - /* Construct the API message */ - M (FLOWPERPKT_TX_INTERFACE_ADD_DEL, flowperpkt_tx_interface_add_del); - mp->sw_if_index = ntohl (sw_if_index); - mp->is_add = enable_disable; - mp->which = which; - - /* 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 \ -_(flowperpkt_tx_interface_add_del, " [disable]") - -void -vat_api_hookup (vat_main_t * vam) -{ - flowperpkt_test_main_t *sm = &flowperpkt_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) -{ - flowperpkt_test_main_t *sm = &flowperpkt_test_main; - u8 *name; - - sm->vat_main = vam; - - /* Ask the vpp engine for the first assigned message-id */ - name = format (0, "flowperpkt_%08x%c", api_version, 0); - sm->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name); - - /* Don't attempt to hook up API messages if the data plane plugin is AWOL */ - 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/flowperpkt-plugin/flowperpkt/l2_node.c b/plugins/flowperpkt-plugin/flowperpkt/l2_node.c deleted file mode 100644 index 1c2f681e..00000000 --- a/plugins/flowperpkt-plugin/flowperpkt/l2_node.c +++ /dev/null @@ -1,561 +0,0 @@ -/* - * l2_node.c - l2 ipfix-per-packet graph node - * - * 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 - -/** - * @file l2 flow record generator graph node - */ - -typedef struct -{ - /** interface handle */ - u32 rx_sw_if_index; - u32 tx_sw_if_index; - /** src and dst L2 addresses */ - u8 src_mac[6]; - u8 dst_mac[6]; - /** Ethertype */ - u16 ethertype; - /** packet timestamp */ - u64 timestamp; - /** size of the buffer */ - u16 buffer_size; -} flowperpkt_l2_trace_t; - -/* packet trace format function */ -static u8 * -format_flowperpkt_l2_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 *); - flowperpkt_l2_trace_t *t = va_arg (*args, flowperpkt_l2_trace_t *); - - s = format (s, - "FLOWPERPKT-L2: rx_sw_if_index %d, tx_sw_if_index %d, src %U dst %U ethertype %0x2, timestamp %lld, size %d", - t->rx_sw_if_index, t->tx_sw_if_index, - format_ethernet_address, &t->src_mac, - format_ethernet_address, &t->dst_mac, - t->ethertype, t->timestamp, t->buffer_size); - return s; -} - -vlib_node_registration_t flowperpkt_l2_node; - -/* No counters at the moment */ -#define foreach_flowperpkt_l2_error - -typedef enum -{ -#define _(sym,str) FLOWPERPKT_ERROR_##sym, - foreach_flowperpkt_l2_error -#undef _ - FLOWPERPKT_N_ERROR, -} flowperpkt_l2_error_t; - -static char *flowperpkt_l2_error_strings[] = { -#define _(sym,string) string, - foreach_flowperpkt_l2_error -#undef _ -}; - -typedef enum -{ - FLOWPERPKT_L2_NEXT_DROP, - FLOWPERPKT_L2_NEXT_IP4_LOOKUP, - FLOWPERPKT_L2_N_NEXT, -} flowperpkt_l2_next_t; - -/** - * @brief add an entry to the flow record under construction - * @param vm vlib_main_t * current worker thread main structure pointer - * @param fm flowperpkt_main_t * flow-per-packet main structure pointer - * @param sw_if_index u32 interface handle - * @param tos u8 ToS bits from the packet - * @param timestamp u64 timestamp, nanoseconds since 1/1/70 - * @param length u16 ip length of the packet - * @param do_flush int 1 = flush all cached records, 0 = construct a record - */ - -static inline void -add_to_flow_record_l2 (vlib_main_t * vm, - vlib_node_runtime_t * node, - flowperpkt_main_t * fm, - u32 rx_sw_if_index, u32 tx_sw_if_index, - u8 * src_mac, u8 * dst_mac, - u16 ethertype, u64 timestamp, u16 length, int do_flush) -{ - u32 my_cpu_number = vm->cpu_index; - flow_report_main_t *frm = &flow_report_main; - ip4_header_t *ip; - udp_header_t *udp; - ip4_ipfix_template_packet_t *tp; - ipfix_message_header_t *h; - ipfix_set_header_t *s; - vlib_frame_t *f; - vlib_buffer_t *b0; - u16 offset; - u32 bi0; - vlib_buffer_free_list_t *fl; - - /* Find or allocate a buffer */ - b0 = fm->l2_buffers_per_worker[my_cpu_number]; - - /* Need to allocate a buffer? */ - if (PREDICT_FALSE (b0 == 0)) - { - /* Nothing to flush */ - if (do_flush) - return; - - /* $$$$ drop counter? */ - if (vlib_buffer_alloc (vm, &bi0, 1) != 1) - return; - - /* Initialize the buffer */ - b0 = fm->l2_buffers_per_worker[my_cpu_number] = - vlib_get_buffer (vm, bi0); - fl = - vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX); - vlib_buffer_init_for_free_list (b0, fl); - VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0); - offset = 0; - } - else - { - /* use the current buffer */ - bi0 = vlib_get_buffer_index (vm, b0); - offset = fm->l2_next_record_offset_per_worker[my_cpu_number]; - } - - /* Find or allocate a frame */ - f = fm->l2_frames_per_worker[my_cpu_number]; - if (PREDICT_FALSE (f == 0)) - { - u32 *to_next; - f = vlib_get_frame_to_node (vm, ip4_lookup_node.index); - fm->l2_frames_per_worker[my_cpu_number] = f; - - /* Enqueue the buffer */ - to_next = vlib_frame_vector_args (f); - to_next[0] = bi0; - f->n_vectors = 1; - } - - /* Fresh packet, construct header */ - if (PREDICT_FALSE (offset == 0)) - { - flow_report_stream_t *stream; - - stream = &frm->streams[0]; - - b0->current_data = 0; - b0->current_length = sizeof (*ip) + sizeof (*udp) + sizeof (*h) + - sizeof (*s); - b0->flags |= (VLIB_BUFFER_TOTAL_LENGTH_VALID | VLIB_BUFFER_FLOW_REPORT); - vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; - vnet_buffer (b0)->sw_if_index[VLIB_TX] = frm->fib_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); - - ip->ip_version_and_header_length = 0x45; - ip->ttl = 254; - ip->protocol = IP_PROTOCOL_UDP; - ip->flags_and_fragment_offset = 0; - ip->src_address.as_u32 = frm->src_address.as_u32; - ip->dst_address.as_u32 = frm->ipfix_collector.as_u32; - udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix); - udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix); - udp->checksum = 0; - - /* FIXUP: message header export_time */ - h->export_time = (u32) - (((f64) frm->unix_time_0) + - (vlib_time_now (frm->vlib_main) - frm->vlib_time_0)); - h->export_time = clib_host_to_net_u32 (h->export_time); - h->domain_id = clib_host_to_net_u32 (stream->domain_id); - - /* FIXUP: message header sequence_number */ - h->sequence_number = stream->sequence_number++; - h->sequence_number = clib_host_to_net_u32 (h->sequence_number); - - offset = (u32) (((u8 *) (s + 1)) - (u8 *) tp); - } - - /* Add data, unless we're flushing stale data */ - if (PREDICT_TRUE (do_flush == 0)) - { - - /* Add data */ - /* Ingress interface */ - { - u32 ingress_interface = clib_host_to_net_u32 (rx_sw_if_index); - clib_memcpy (b0->data + offset, &ingress_interface, - sizeof (ingress_interface)); - offset += sizeof (ingress_interface); - } - /* Egress interface */ - { - u32 egress_interface = clib_host_to_net_u32 (tx_sw_if_index); - clib_memcpy (b0->data + offset, &egress_interface, - sizeof (egress_interface)); - offset += sizeof (egress_interface); - } - /* src mac address */ - { - clib_memcpy (b0->data + offset, src_mac, 6); - offset += 6; - } - /* dst mac address */ - { - clib_memcpy (b0->data + offset, dst_mac, 6); - offset += 6; - } - - /* ethertype */ - b0->data[offset++] = ethertype >> 8; - b0->data[offset++] = ethertype & 0xFF; - - /* Timestamp */ - clib_memcpy (b0->data + offset, ×tamp, sizeof (f64)); - offset += sizeof (f64); - - /* pkt size */ - { - u16 pkt_size = clib_host_to_net_u16 (length); - clib_memcpy (b0->data + offset, &pkt_size, sizeof (pkt_size)); - offset += sizeof (pkt_size); - } - - b0->current_length += - /* 2*sw_if_index + 2*mac + ethertype + timestamp + length = 32 */ - 2 * sizeof (u32) + 12 + sizeof (u16) + sizeof (f64) + sizeof (u16); - - } - /* Time to flush the buffer? */ - if (PREDICT_FALSE - (do_flush || (offset + 2 * sizeof (u32) + 12 + sizeof (u16) + - +sizeof (f64) + sizeof (u16)) > frm->path_mtu)) - { - 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); - - s->set_id_length = ipfix_set_id_length (fm->l2_report_id, - b0->current_length - - (sizeof (*ip) + sizeof (*udp) + - sizeof (*h))); - h->version_length = version_length (b0->current_length - - (sizeof (*ip) + sizeof (*udp))); - - ip->length = clib_host_to_net_u16 (b0->current_length); - - ip->checksum = ip4_header_checksum (ip); - udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip)); - - if (frm->udp_checksum) - { - /* RFC 7011 section 10.3.2. */ - udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip); - if (udp->checksum == 0) - udp->checksum = 0xffff; - } - - ASSERT (ip->checksum == ip4_header_checksum (ip)); - - if (PREDICT_FALSE (vlib_get_trace_count (vm, node) > 0)) - { - vlib_trace_buffer (vm, node, FLOWPERPKT_L2_NEXT_IP4_LOOKUP, b0, - 0 /* follow chain */ ); - flowperpkt_l2_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - memset (t, 0, sizeof (*t)); - t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - t->buffer_size = b0->current_length; - } - - vlib_put_frame_to_node (vm, ip4_lookup_node.index, - fm->l2_frames_per_worker[my_cpu_number]); - fm->l2_frames_per_worker[my_cpu_number] = 0; - fm->l2_buffers_per_worker[my_cpu_number] = 0; - offset = 0; - } - - fm->l2_next_record_offset_per_worker[my_cpu_number] = offset; -} - -void -flowperpkt_flush_callback_l2 (void) -{ - vlib_main_t *vm = vlib_get_main (); - flowperpkt_main_t *fm = &flowperpkt_main; - vlib_node_runtime_t *node; - node = vlib_node_get_runtime (vm, flowperpkt_l2_node.index); - - add_to_flow_record_l2 (vm, node, fm, 0 /* rx_sw_if_index */ , - 0 /* tx_sw_if_index */ , - 0 /* src mac */ , - 0 /* dst mac */ , - 0 /* ethertype */ , - 0ULL /* timestamp */ , - 0 /* length */ , - 1 /* do_flush */ ); -} - - -static uword -flowperpkt_l2_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) -{ - u32 n_left_from, *from, *to_next; - flowperpkt_l2_next_t next_index; - flowperpkt_main_t *fm = &flowperpkt_main; - u64 now; - - now = (u64) ((vlib_time_now (vm) - fm->vlib_time_0) * 1e9); - now += fm->nanosecond_time_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 = FLOWPERPKT_L2_NEXT_DROP; - u32 next1 = FLOWPERPKT_L2_NEXT_DROP; - ethernet_header_t *eh0, *eh1; - u16 len0, len1; - 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); - - vnet_feature_next (vnet_buffer (b0)->sw_if_index[VLIB_TX], - &next0, b0); - vnet_feature_next (vnet_buffer (b1)->sw_if_index[VLIB_TX], - &next1, b1); - - eh0 = vlib_buffer_get_current (b0); - len0 = vlib_buffer_length_in_chain (vm, b0); - - if (PREDICT_TRUE ((b0->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) - add_to_flow_record_l2 (vm, node, fm, - vnet_buffer (b0)->sw_if_index[VLIB_RX], - vnet_buffer (b0)->sw_if_index[VLIB_TX], - eh0->src_address, - eh0->dst_address, - eh0->type, now, len0, 0 /* flush */ ); - - eh1 = vlib_buffer_get_current (b0); - len1 = vlib_buffer_length_in_chain (vm, b0); - - if (PREDICT_TRUE ((b1->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) - add_to_flow_record_l2 (vm, node, fm, - vnet_buffer (b1)->sw_if_index[VLIB_RX], - vnet_buffer (b1)->sw_if_index[VLIB_TX], - eh1->src_address, - eh1->dst_address, - eh1->type, now, len1, 0 /* flush */ ); - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) - { - if (b0->flags & VLIB_BUFFER_IS_TRACED) - { - flowperpkt_l2_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - clib_memcpy (t->src_mac, eh0->src_address, 6); - clib_memcpy (t->dst_mac, eh0->dst_address, 6); - t->ethertype = clib_net_to_host_u16 (eh0->type); - t->timestamp = now; - t->buffer_size = len0; - } - if (b1->flags & VLIB_BUFFER_IS_TRACED) - { - flowperpkt_l2_trace_t *t = - vlib_add_trace (vm, node, b1, sizeof (*t)); - t->rx_sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX]; - t->tx_sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_TX]; - clib_memcpy (t->src_mac, eh1->src_address, 6); - clib_memcpy (t->dst_mac, eh1->dst_address, 6); - t->ethertype = clib_net_to_host_u16 (eh1->type); - t->timestamp = now; - t->buffer_size = len1; - } - } - - /* 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 = FLOWPERPKT_L2_NEXT_DROP; - ethernet_header_t *eh0; - u16 len0; - - /* 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); - - vnet_feature_next (vnet_buffer (b0)->sw_if_index[VLIB_TX], - &next0, b0); - - eh0 = vlib_buffer_get_current (b0); - len0 = vlib_buffer_length_in_chain (vm, b0); - - if (PREDICT_TRUE ((b0->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) - add_to_flow_record_l2 (vm, node, fm, - vnet_buffer (b0)->sw_if_index[VLIB_RX], - vnet_buffer (b0)->sw_if_index[VLIB_TX], - eh0->src_address, - eh0->dst_address, - eh0->type, now, len0, 0 /* flush */ ); - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - flowperpkt_l2_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - clib_memcpy (t->src_mac, eh0->src_address, 6); - clib_memcpy (t->dst_mac, eh0->dst_address, 6); - t->ethertype = clib_net_to_host_u16 (eh0->type); - t->timestamp = now; - t->buffer_size = len0; - } - - /* 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; -} - -/** - * @brief IPFIX l2 flow-per-packet graph node - * @node flowperpkt-l2 - * - * This is the IPFIX flow-record-per-packet node. - * - * @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. - * - * @par Graph mechanics: buffer metadata, next index usage - * - * Uses: - * - vnet_buffer(b)->ip.save_rewrite_length - * - tells the node the length of the rewrite which was applied in - * ip4/6_rewrite_inline, allows the code to find the IP header without - * having to parse L2 headers, or make stupid assumptions about their - * length. - * - vnet_buffer(b)->flags & VLIB_BUFFER_FLOW_REPORT - * - Used to suppress flow record generation for flow record packets. - * - * Sets: - * - vnet_buffer(b)->flags & VLIB_BUFFER_FLOW_REPORT - * - To suppress flow record generation for flow record packets - * - * Next Index: - * - Next configured output feature on the interface, usually - * "interface-output." Generated flow records head for ip4-lookup - */ - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (flowperpkt_l2_node) = { - .function = flowperpkt_l2_node_fn, - .name = "flowperpkt-l2", - .vector_size = sizeof (u32), - .format_trace = format_flowperpkt_l2_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(flowperpkt_l2_error_strings), - .error_strings = flowperpkt_l2_error_strings, - - .n_next_nodes = FLOWPERPKT_L2_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [FLOWPERPKT_L2_NEXT_DROP] = "error-drop", - [FLOWPERPKT_L2_NEXT_IP4_LOOKUP] = "ip4-lookup", - }, -}; -/* *INDENT-ON* */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/flowperpkt-plugin/flowperpkt/node.c b/plugins/flowperpkt-plugin/flowperpkt/node.c deleted file mode 100644 index f77f087d..00000000 --- a/plugins/flowperpkt-plugin/flowperpkt/node.c +++ /dev/null @@ -1,574 +0,0 @@ -/* - * node.c - ipv4 ipfix-per-packet graph node - * - * 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 - -/** - * @file ipv4 flow record generator graph node - */ - -typedef struct -{ - /** interface handle */ - u32 rx_sw_if_index; - u32 tx_sw_if_index; - u32 src_address; - u32 dst_address; - /** ToS bits */ - u8 tos; - /** packet timestamp */ - u64 timestamp; - /** size of the buffer */ - u16 buffer_size; -} flowperpkt_ipv4_trace_t; - -/* packet trace format function */ -static u8 * -format_flowperpkt_ipv4_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 *); - flowperpkt_ipv4_trace_t *t = va_arg (*args, flowperpkt_ipv4_trace_t *); - - s = format (s, - "FLOWPERPKT-V4: rx_sw_if_index %d, tx_sw_if_index %d, src %U dst %U tos %0x2, timestamp %lld, size %d", - t->rx_sw_if_index, t->tx_sw_if_index, - format_ip4_address, &t->src_address, - format_ip4_address, &t->dst_address, - t->tos, t->timestamp, t->buffer_size); - return s; -} - -vlib_node_registration_t flowperpkt_ipv4_node; - -/* No counters at the moment */ -#define foreach_flowperpkt_ipv4_error - -typedef enum -{ -#define _(sym,str) FLOWPERPKT_ERROR_##sym, - foreach_flowperpkt_ipv4_error -#undef _ - FLOWPERPKT_N_ERROR, -} flowperpkt_ipv4_error_t; - -static char *flowperpkt_ipv4_error_strings[] = { -#define _(sym,string) string, - foreach_flowperpkt_ipv4_error -#undef _ -}; - -typedef enum -{ - FLOWPERPKT_IPV4_NEXT_DROP, - FLOWPERPKT_IPV4_NEXT_LOOKUP, - FLOWPERPKT_IPV4_N_NEXT, -} flowperpkt_ipv4_next_t; - -/** - * @brief add an entry to the flow record under construction - * @param vm vlib_main_t * current worker thread main structure pointer - * @param fm flowperpkt_main_t * flow-per-packet main structure pointer - * @param sw_if_index u32 interface handle - * @param tos u8 ToS bits from the packet - * @param timestamp u64 timestamp, nanoseconds since 1/1/70 - * @param length u16 ip length of the packet - * @param do_flush int 1 = flush all cached records, 0 = construct a record - */ - -static inline void -add_to_flow_record_ipv4 (vlib_main_t * vm, - vlib_node_runtime_t * node, - flowperpkt_main_t * fm, - u32 rx_sw_if_index, u32 tx_sw_if_index, - u32 src_address, u32 dst_address, - u8 tos, u64 timestamp, u16 length, int do_flush) -{ - u32 my_cpu_number = vm->cpu_index; - flow_report_main_t *frm = &flow_report_main; - ip4_header_t *ip; - udp_header_t *udp; - ip4_ipfix_template_packet_t *tp; - ipfix_message_header_t *h; - ipfix_set_header_t *s; - vlib_frame_t *f; - vlib_buffer_t *b0; - u16 offset; - u32 bi0; - vlib_buffer_free_list_t *fl; - - /* Find or allocate a buffer */ - b0 = fm->ipv4_buffers_per_worker[my_cpu_number]; - - /* Need to allocate a buffer? */ - if (PREDICT_FALSE (b0 == 0)) - { - /* Nothing to flush */ - if (do_flush) - return; - - /* $$$$ drop counter? */ - if (vlib_buffer_alloc (vm, &bi0, 1) != 1) - return; - - /* Initialize the buffer */ - b0 = fm->ipv4_buffers_per_worker[my_cpu_number] = - vlib_get_buffer (vm, bi0); - fl = - vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX); - vlib_buffer_init_for_free_list (b0, fl); - VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0); - offset = 0; - } - else - { - /* use the current buffer */ - bi0 = vlib_get_buffer_index (vm, b0); - offset = fm->ipv4_next_record_offset_per_worker[my_cpu_number]; - } - - /* Find or allocate a frame */ - f = fm->ipv4_frames_per_worker[my_cpu_number]; - if (PREDICT_FALSE (f == 0)) - { - u32 *to_next; - f = vlib_get_frame_to_node (vm, ip4_lookup_node.index); - fm->ipv4_frames_per_worker[my_cpu_number] = f; - - /* Enqueue the buffer */ - to_next = vlib_frame_vector_args (f); - to_next[0] = bi0; - f->n_vectors = 1; - } - - /* Fresh packet, construct header */ - if (PREDICT_FALSE (offset == 0)) - { - flow_report_stream_t *stream; - - stream = &frm->streams[0]; - - b0->current_data = 0; - b0->current_length = sizeof (*ip) + sizeof (*udp) + sizeof (*h) + - sizeof (*s); - b0->flags |= (VLIB_BUFFER_TOTAL_LENGTH_VALID | VLIB_BUFFER_FLOW_REPORT); - vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; - vnet_buffer (b0)->sw_if_index[VLIB_TX] = frm->fib_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); - - ip->ip_version_and_header_length = 0x45; - ip->ttl = 254; - ip->protocol = IP_PROTOCOL_UDP; - ip->flags_and_fragment_offset = 0; - ip->src_address.as_u32 = frm->src_address.as_u32; - ip->dst_address.as_u32 = frm->ipfix_collector.as_u32; - udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix); - udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix); - udp->checksum = 0; - - /* FIXUP: message header export_time */ - h->export_time = (u32) - (((f64) frm->unix_time_0) + - (vlib_time_now (frm->vlib_main) - frm->vlib_time_0)); - h->export_time = clib_host_to_net_u32 (h->export_time); - h->domain_id = clib_host_to_net_u32 (stream->domain_id); - - /* FIXUP: message header sequence_number */ - h->sequence_number = stream->sequence_number++; - h->sequence_number = clib_host_to_net_u32 (h->sequence_number); - - offset = (u32) (((u8 *) (s + 1)) - (u8 *) tp); - } - - /* Add data, unless we're flushing stale data */ - if (PREDICT_TRUE (do_flush == 0)) - { - - /* Add data */ - /* Ingress interface */ - { - u32 ingress_interface = clib_host_to_net_u32 (rx_sw_if_index); - clib_memcpy (b0->data + offset, &ingress_interface, - sizeof (ingress_interface)); - offset += sizeof (ingress_interface); - } - /* Egress interface */ - { - u32 egress_interface = clib_host_to_net_u32 (tx_sw_if_index); - clib_memcpy (b0->data + offset, &egress_interface, - sizeof (egress_interface)); - offset += sizeof (egress_interface); - } - /* ip4 src address */ - { - clib_memcpy (b0->data + offset, &src_address, sizeof (src_address)); - offset += sizeof (src_address); - } - /* ip4 dst address */ - { - clib_memcpy (b0->data + offset, &dst_address, sizeof (dst_address)); - offset += sizeof (dst_address); - } - - /* ToS */ - b0->data[offset++] = tos; - - /* Timestamp */ - clib_memcpy (b0->data + offset, ×tamp, sizeof (f64)); - offset += sizeof (f64); - - /* pkt size */ - { - u16 pkt_size = clib_host_to_net_u16 (length); - clib_memcpy (b0->data + offset, &pkt_size, sizeof (pkt_size)); - offset += sizeof (pkt_size); - } - - b0->current_length += - /* sw_if_index + tos + timestamp + length = 15 */ - 4 * sizeof (u32) + sizeof (u8) + sizeof (f64) + sizeof (u16); - - } - /* Time to flush the buffer? */ - if (PREDICT_FALSE - (do_flush || (offset + 4 * sizeof (u32) + sizeof (u8) - + sizeof (f64) + sizeof (u16)) > frm->path_mtu)) - { - 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); - - s->set_id_length = ipfix_set_id_length (fm->ipv4_report_id, - b0->current_length - - (sizeof (*ip) + sizeof (*udp) + - sizeof (*h))); - h->version_length = version_length (b0->current_length - - (sizeof (*ip) + sizeof (*udp))); - - ip->length = clib_host_to_net_u16 (b0->current_length); - - ip->checksum = ip4_header_checksum (ip); - udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip)); - - if (frm->udp_checksum) - { - /* RFC 7011 section 10.3.2. */ - udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip); - if (udp->checksum == 0) - udp->checksum = 0xffff; - } - - ASSERT (ip->checksum == ip4_header_checksum (ip)); - - if (PREDICT_FALSE (vlib_get_trace_count (vm, node) > 0)) - { - vlib_trace_buffer (vm, node, FLOWPERPKT_IPV4_NEXT_LOOKUP, b0, - 0 /* follow chain */ ); - flowperpkt_ipv4_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - t->src_address = 0; - t->dst_address = 0; - t->tos = 0; - t->timestamp = 0; - t->buffer_size = b0->current_length; - } - - vlib_put_frame_to_node (vm, ip4_lookup_node.index, - fm->ipv4_frames_per_worker[my_cpu_number]); - fm->ipv4_frames_per_worker[my_cpu_number] = 0; - fm->ipv4_buffers_per_worker[my_cpu_number] = 0; - offset = 0; - } - - fm->ipv4_next_record_offset_per_worker[my_cpu_number] = offset; -} - -void -flowperpkt_flush_callback_ipv4 (void) -{ - vlib_main_t *vm = vlib_get_main (); - flowperpkt_main_t *fm = &flowperpkt_main; - vlib_node_runtime_t *node; - node = vlib_node_get_runtime (vm, flowperpkt_ipv4_node.index); - - add_to_flow_record_ipv4 (vm, node, fm, 0 /* rx_sw_if_index */ , - 0 /* tx_sw_if_index */ , - 0 /* src_address */ , - 0 /* dst_address */ , - 0 /* ToS */ , - 0ULL /* timestamp */ , - 0 /* length */ , - 1 /* do_flush */ ); -} - - -static uword -flowperpkt_ipv4_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) -{ - u32 n_left_from, *from, *to_next; - flowperpkt_ipv4_next_t next_index; - flowperpkt_main_t *fm = &flowperpkt_main; - u64 now; - - now = (u64) ((vlib_time_now (vm) - fm->vlib_time_0) * 1e9); - now += fm->nanosecond_time_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 = FLOWPERPKT_IPV4_NEXT_DROP; - u32 next1 = FLOWPERPKT_IPV4_NEXT_DROP; - ip4_header_t *ip0, *ip1; - u16 len0, len1; - 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); - - vnet_feature_next (vnet_buffer (b0)->sw_if_index[VLIB_TX], - &next0, b0); - vnet_feature_next (vnet_buffer (b1)->sw_if_index[VLIB_TX], - &next1, b1); - - ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) + - vnet_buffer (b0)->ip.save_rewrite_length); - - len0 = vlib_buffer_length_in_chain (vm, b0); - - if (PREDICT_TRUE ((b0->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) - add_to_flow_record_ipv4 (vm, node, fm, - vnet_buffer (b0)->sw_if_index[VLIB_RX], - vnet_buffer (b0)->sw_if_index[VLIB_TX], - ip0->src_address.as_u32, - ip0->dst_address.as_u32, - ip0->tos, now, len0, 0 /* flush */ ); - - ip1 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b1) + - vnet_buffer (b1)->ip.save_rewrite_length); - len1 = vlib_buffer_length_in_chain (vm, b1); - - if (PREDICT_TRUE ((b1->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) - add_to_flow_record_ipv4 (vm, node, fm, - vnet_buffer (b1)->sw_if_index[VLIB_RX], - vnet_buffer (b1)->sw_if_index[VLIB_TX], - ip1->src_address.as_u32, - ip1->dst_address.as_u32, - ip1->tos, now, len1, 0 /* flush */ ); - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) - { - if (b0->flags & VLIB_BUFFER_IS_TRACED) - { - flowperpkt_ipv4_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - t->src_address = ip0->src_address.as_u32; - t->dst_address = ip0->dst_address.as_u32; - t->tos = ip0->tos; - t->timestamp = now; - t->buffer_size = len0; - } - if (b1->flags & VLIB_BUFFER_IS_TRACED) - { - flowperpkt_ipv4_trace_t *t = - vlib_add_trace (vm, node, b1, sizeof (*t)); - t->rx_sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX]; - t->tx_sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_TX]; - t->src_address = ip1->src_address.as_u32; - t->dst_address = ip1->dst_address.as_u32; - t->tos = ip1->tos; - t->timestamp = now; - t->buffer_size = len1; - } - } - - /* 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 = FLOWPERPKT_IPV4_NEXT_DROP; - ip4_header_t *ip0; - u16 len0; - - /* 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); - - vnet_feature_next (vnet_buffer (b0)->sw_if_index[VLIB_TX], - &next0, b0); - - ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) + - vnet_buffer (b0)->ip.save_rewrite_length); - /* - * egressInterface, TLV type 14, u32 - * ipClassOfService, TLV type 5, u8 - * flowStartNanoseconds, TLV type 156, dateTimeNanoseconds (f64) - * Implementation: f64 nanoseconds since VPP started - * dataLinkFrameSize, TLV type 312, u16 - */ - len0 = vlib_buffer_length_in_chain (vm, b0); - - if (PREDICT_TRUE ((b0->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) - add_to_flow_record_ipv4 (vm, node, fm, - vnet_buffer (b0)->sw_if_index[VLIB_RX], - vnet_buffer (b0)->sw_if_index[VLIB_TX], - ip0->src_address.as_u32, - ip0->dst_address.as_u32, - ip0->tos, now, len0, 0 /* flush */ ); - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - flowperpkt_ipv4_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - t->src_address = ip0->src_address.as_u32; - t->dst_address = ip0->dst_address.as_u32; - t->tos = ip0->tos; - t->timestamp = now; - t->buffer_size = len0; - } - - /* 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; -} - -/** - * @brief IPFIX ipv4 flow-per-packet graph node - * @node flowperpkt-ipv4 - * - * This is the IPFIX flow-record-per-packet node. - * - * @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. - * - * @par Graph mechanics: buffer metadata, next index usage - * - * Uses: - * - vnet_buffer(b)->ip.save_rewrite_length - * - tells the node the length of the rewrite which was applied in - * ip4/6_rewrite_inline, allows the code to find the IP header without - * having to parse L2 headers, or make stupid assumptions about their - * length. - * - vnet_buffer(b)->flags & VLIB_BUFFER_FLOW_REPORT - * - Used to suppress flow record generation for flow record packets. - * - * Sets: - * - vnet_buffer(b)->flags & VLIB_BUFFER_FLOW_REPORT - * - To suppress flow record generation for flow record packets - * - * Next Index: - * - Next configured output feature on the interface, usually - * "interface-output." Generated flow records head for ip4-lookup - */ - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (flowperpkt_ipv4_node) = { - .function = flowperpkt_ipv4_node_fn, - .name = "flowperpkt-ipv4", - .vector_size = sizeof (u32), - .format_trace = format_flowperpkt_ipv4_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(flowperpkt_ipv4_error_strings), - .error_strings = flowperpkt_ipv4_error_strings, - - .n_next_nodes = FLOWPERPKT_IPV4_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [FLOWPERPKT_IPV4_NEXT_DROP] = "error-drop", - /* Used only to trace ipfix data packets */ - [FLOWPERPKT_IPV4_NEXT_LOOKUP] = "ip4-lookup", - }, -}; -/* *INDENT-ON* */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/flowperpkt-plugin/flowperpkt_plugin_doc.md b/plugins/flowperpkt-plugin/flowperpkt_plugin_doc.md deleted file mode 100644 index ed76c45c..00000000 --- a/plugins/flowperpkt-plugin/flowperpkt_plugin_doc.md +++ /dev/null @@ -1,13 +0,0 @@ -Per-packet IPFIX flow record plugin {#flowperpkt_plugin_doc} -=================================== - -## Introduction - -This plugin generates one ipfix record entry per packet transmitted -on interfaces which have the feature enabled - -## Sample configuration - -set ipfix exporter collector 192.168.6.2 src 192.168.6.1 template-interval 20 port 4739 path-mtu 1500 - -flowperpkt feature add-del GigabitEthernet2/3/0 diff --git a/plugins/ila-plugin/Makefile.am b/plugins/ila-plugin/Makefile.am deleted file mode 100644 index fe785df9..00000000 --- a/plugins/ila-plugin/Makefile.am +++ /dev/null @@ -1,29 +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 - -vpppluginsdir = ${libdir}/vpp_plugins - -vppplugins_LTLIBRARIES = ila_plugin.la - -ila_plugin_la_SOURCES = ila/ila.c - -noinst_HEADERS = ila/ila.h - -# Remove *.la files -install-data-hook: - @(cd $(vpppluginsdir) && $(RM) $(vppplugins_LTLIBRARIES)) diff --git a/plugins/ila-plugin/configure.ac b/plugins/ila-plugin/configure.ac deleted file mode 100644 index 56016b4d..00000000 --- a/plugins/ila-plugin/configure.ac +++ /dev/null @@ -1,9 +0,0 @@ -AC_INIT(ila_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/ila-plugin/ila/ila.c b/plugins/ila-plugin/ila/ila.c deleted file mode 100644 index 336f4cf5..00000000 --- a/plugins/ila-plugin/ila/ila.c +++ /dev/null @@ -1,1070 +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 - -static ila_main_t ila_main; - -#define ILA_TABLE_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) -#define ILA_TABLE_DEFAULT_HASH_MEMORY_SIZE (32<<20) - -#define foreach_ila_error \ - _(NONE, "valid ILA packets") - -typedef enum { -#define _(sym,str) ILA_ERROR_##sym, - foreach_ila_error -#undef _ - ILA_N_ERROR, -} ila_error_t; - -static char *ila_error_strings[] = { -#define _(sym,string) string, - foreach_ila_error -#undef _ -}; - -typedef enum { - ILA_ILA2SIR_NEXT_DROP, - ILA_ILA2SIR_N_NEXT, -} ila_ila2sir_next_t; - -typedef struct { - u32 ila_index; - ip6_address_t initial_dst; - u32 adj_index; -} ila_ila2sir_trace_t; - -static ila_entry_t ila_sir2ila_default_entry = { - .csum_mode = ILA_CSUM_MODE_NO_ACTION, - .type = ILA_TYPE_IID, - .dir = ILA_DIR_ILA2SIR, //Will pass the packet with no -}; - -/** - * @brief Dynamically registered DPO Type for ILA - */ -static dpo_type_t ila_dpo_type; - -/** - * @brief Dynamically registered FIB node type for ILA - */ -static fib_node_type_t ila_fib_node_type; - -u8 * -format_half_ip6_address (u8 * s, va_list * va) -{ - u64 v = clib_net_to_host_u64 (va_arg (*va, u64)); - - return format (s, "%04x:%04x:%04x:%04x", - v >> 48, (v >> 32) & 0xffff, (v >> 16) & 0xffff, v & 0xffff); - -} - -u8 * -format_ila_direction (u8 * s, va_list * args) -{ - ila_direction_t t = va_arg (*args, ila_direction_t); -#define _(i,n,st) \ - if (t == ILA_DIR_##i) \ - return format(s, st); - ila_foreach_direction -#undef _ - return format (s, "invalid_ila_direction"); -} - -static u8 * -format_csum_mode (u8 * s, va_list * va) -{ - ila_csum_mode_t csum_mode = va_arg (*va, ila_csum_mode_t); - char *txt; - - switch (csum_mode) - { -#define _(i,n,st) \ - case ILA_CSUM_MODE_##i: \ - txt = st; \ - break; - ila_csum_foreach_type -#undef _ - default: - txt = "invalid_ila_csum_mode"; - break; - } - return format (s, txt); -} - -u8 * -format_ila_type (u8 * s, va_list * args) -{ - ila_type_t t = va_arg (*args, ila_type_t); -#define _(i,n,st) \ - if (t == ILA_TYPE_##i) \ - return format(s, st); - ila_foreach_type -#undef _ - return format (s, "invalid_ila_type"); -} - -static u8 * -format_ila_entry (u8 * s, va_list * va) -{ - vnet_main_t *vnm = va_arg (*va, vnet_main_t *); - ila_entry_t *e = va_arg (*va, ila_entry_t *); - - if (!e) - { - return format (s, "%-15s%=40s%=40s%+16s%+18s%+11s", "Type", "SIR Address", - "ILA Address", "Checksum Mode", "Direction", "Next DPO"); - } - else if (vnm) - { - if (ip6_address_is_zero(&e->next_hop)) - { - return format (s, "%-15U%=40U%=40U%18U%11U%s", - format_ila_type, e->type, - format_ip6_address, &e->sir_address, - format_ip6_address, &e->ila_address, - format_csum_mode, e->csum_mode, - format_ila_direction, e->dir, - "n/a"); - } - else - { - return format (s, "%-15U%=40U%=40U%18U%11U%U", - format_ila_type, e->type, - format_ip6_address, &e->sir_address, - format_ip6_address, &e->ila_address, - format_csum_mode, e->csum_mode, - format_ila_direction, e->dir, - format_dpo_id, &e->ila_dpo, 0); - } - } - - return NULL; -} - -u8 * -format_ila_ila2sir_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 *); - ila_ila2sir_trace_t *t = va_arg (*args, ila_ila2sir_trace_t *); - return format (s, - "ILA -> SIR adj index: %d entry index: %d initial_dst: %U", - t->adj_index, t->ila_index, format_ip6_address, - &t->initial_dst); -} - -static uword -unformat_ila_direction (unformat_input_t * input, va_list * args) -{ - ila_direction_t *result = va_arg (*args, ila_direction_t *); -#define _(i,n,s) \ - if (unformat(input, s)) \ - { \ - *result = ILA_DIR_##i; \ - return 1;\ - } - - ila_foreach_direction -#undef _ - return 0; -} - -static uword -unformat_ila_type (unformat_input_t * input, va_list * args) -{ - ila_type_t *result = va_arg (*args, ila_type_t *); -#define _(i,n,s) \ - if (unformat(input, s)) \ - { \ - *result = ILA_TYPE_##i; \ - return 1;\ - } - - ila_foreach_type -#undef _ - return 0; -} - -static uword -unformat_ila_csum_mode (unformat_input_t * input, va_list * args) -{ - ila_csum_mode_t *result = va_arg (*args, ila_csum_mode_t *); - if (unformat (input, "none") || unformat (input, "no-action")) - { - *result = ILA_CSUM_MODE_NO_ACTION; - return 1; - } - if (unformat (input, "neutral-map")) - { - *result = ILA_CSUM_MODE_NEUTRAL_MAP; - return 1; - } - if (unformat (input, "adjust-transport")) - { - *result = ILA_CSUM_MODE_ADJUST_TRANSPORT; - return 1; - } - return 0; -} - -static uword -unformat_half_ip6_address (unformat_input_t * input, va_list * args) -{ - u64 *result = va_arg (*args, u64 *); - u32 a[4]; - - if (!unformat (input, "%x:%x:%x:%x", &a[0], &a[1], &a[2], &a[3])) - return 0; - - if (a[0] > 0xFFFF || a[1] > 0xFFFF || a[2] > 0xFFFF || a[3] > 0xFFFF) - return 0; - - *result = clib_host_to_net_u64 ((((u64) a[0]) << 48) | - (((u64) a[1]) << 32) | - (((u64) a[2]) << 16) | (((u64) a[3]))); - - return 1; -} - -static vlib_node_registration_t ila_ila2sir_node; - -static uword -ila_ila2sir (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) -{ - u32 n_left_from, *from, next_index, *to_next, n_left_to_next; - ila_main_t *ilm = &ila_main; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - 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 pi0, pi1; - vlib_buffer_t *p0, *p1; - ila_entry_t *ie0, *ie1; - ip6_header_t *ip60, *ip61; - ip6_address_t *sir_address0, *sir_address1; - - { - 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, sizeof (ip6_header_t), LOAD); - CLIB_PREFETCH (p3->data, sizeof (ip6_header_t), LOAD); - } - - pi0 = to_next[0] = from[0]; - pi1 = to_next[1] = from[1]; - from += 2; - n_left_from -= 2; - to_next += 2; - n_left_to_next -= 2; - - p0 = vlib_get_buffer (vm, pi0); - p1 = vlib_get_buffer (vm, pi1); - ip60 = vlib_buffer_get_current (p0); - ip61 = vlib_buffer_get_current (p1); - sir_address0 = &ip60->dst_address; - sir_address1 = &ip61->dst_address; - ie0 = pool_elt_at_index (ilm->entries, - vnet_buffer (p0)->ip.adj_index[VLIB_TX]); - ie1 = pool_elt_at_index (ilm->entries, - vnet_buffer (p1)->ip.adj_index[VLIB_TX]); - - if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) - { - ila_ila2sir_trace_t *tr = - vlib_add_trace (vm, node, p0, sizeof (*tr)); - tr->ila_index = ie0 - ilm->entries; - tr->initial_dst = ip60->dst_address; - tr->adj_index = vnet_buffer (p0)->ip.adj_index[VLIB_TX]; - } - - if (PREDICT_FALSE (p1->flags & VLIB_BUFFER_IS_TRACED)) - { - ila_ila2sir_trace_t *tr = - vlib_add_trace (vm, node, p1, sizeof (*tr)); - tr->ila_index = ie1 - ilm->entries; - tr->initial_dst = ip61->dst_address; - tr->adj_index = vnet_buffer (p1)->ip.adj_index[VLIB_TX]; - } - - sir_address0 = (ie0->dir != ILA_DIR_SIR2ILA) ? &ie0->sir_address : sir_address0; - sir_address1 = (ie1->dir != ILA_DIR_SIR2ILA) ? &ie1->sir_address : sir_address1; - ip60->dst_address.as_u64[0] = sir_address0->as_u64[0]; - ip60->dst_address.as_u64[1] = sir_address0->as_u64[1]; - ip61->dst_address.as_u64[0] = sir_address1->as_u64[0]; - ip61->dst_address.as_u64[1] = sir_address1->as_u64[1]; - - vnet_buffer (p0)->ip.adj_index[VLIB_TX] = ie0->ila_dpo.dpoi_index; - vnet_buffer (p1)->ip.adj_index[VLIB_TX] = ie1->ila_dpo.dpoi_index; - - vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, - n_left_to_next, pi0, pi1, - ie0->ila_dpo.dpoi_next_node, - ie1->ila_dpo.dpoi_next_node); - } - - /* Single loop */ - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 pi0; - vlib_buffer_t *p0; - ila_entry_t *ie0; - ip6_header_t *ip60; - ip6_address_t *sir_address0; - - 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); - ip60 = vlib_buffer_get_current (p0); - sir_address0 = &ip60->dst_address; - ie0 = pool_elt_at_index (ilm->entries, - vnet_buffer (p0)->ip.adj_index[VLIB_TX]); - - if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) - { - ila_ila2sir_trace_t *tr = - vlib_add_trace (vm, node, p0, sizeof (*tr)); - tr->ila_index = ie0 ? (ie0 - ilm->entries) : ~0; - tr->initial_dst = ip60->dst_address; - tr->adj_index = vnet_buffer (p0)->ip.adj_index[VLIB_TX]; - } - - sir_address0 = (ie0->dir != ILA_DIR_SIR2ILA) ? &ie0->sir_address : sir_address0; - ip60->dst_address.as_u64[0] = sir_address0->as_u64[0]; - ip60->dst_address.as_u64[1] = sir_address0->as_u64[1]; - vnet_buffer (p0)->ip.adj_index[VLIB_TX] = ie0->ila_dpo.dpoi_index; - - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, pi0, - ie0->ila_dpo.dpoi_next_node); - } - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - return frame->n_vectors; -} - -/** *INDENT-OFF* */ -VLIB_REGISTER_NODE (ila_ila2sir_node, static) = -{ - .function = ila_ila2sir, - .name = "ila-to-sir", - .vector_size = sizeof (u32), - .format_trace = format_ila_ila2sir_trace, - .n_errors = ILA_N_ERROR, - .error_strings = ila_error_strings, - .n_next_nodes = ILA_ILA2SIR_N_NEXT, - .next_nodes = - { - [ILA_ILA2SIR_NEXT_DROP] = "error-drop" - }, -}; -/** *INDENT-ON* */ - -typedef enum -{ - ILA_SIR2ILA_NEXT_DROP, - ILA_SIR2ILA_N_NEXT, -} ila_sir2ila_next_t; - -typedef struct -{ - u32 ila_index; - ip6_address_t initial_dst; -} ila_sir2ila_trace_t; - -u8 * -format_ila_sir2ila_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 *); - ila_sir2ila_trace_t *t = va_arg (*args, ila_sir2ila_trace_t *); - - return format (s, "SIR -> ILA entry index: %d initial_dst: %U", - t->ila_index, format_ip6_address, &t->initial_dst); -} - -static vlib_node_registration_t ila_sir2ila_node; - -static uword -ila_sir2ila (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) -{ - u32 n_left_from, *from, next_index, *to_next, n_left_to_next; - ila_main_t *ilm = &ila_main; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - 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 pi0, pi1; - vlib_buffer_t *p0, *p1; - ip6_header_t *ip60, *ip61; - u32 next0 = ILA_SIR2ILA_NEXT_DROP; - u32 next1 = ILA_SIR2ILA_NEXT_DROP; - BVT (clib_bihash_kv) kv0, value0; - BVT (clib_bihash_kv) kv1, value1; - ila_entry_t *ie0 = &ila_sir2ila_default_entry; - ila_entry_t *ie1 = &ila_sir2ila_default_entry; - ip6_address_t *ila_address0, *ila_address1; - - { - 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, sizeof (ip6_header_t), LOAD); - CLIB_PREFETCH (p3->data, sizeof (ip6_header_t), LOAD); - } - - pi0 = to_next[0] = from[0]; - pi1 = to_next[1] = from[1]; - from += 2; - n_left_from -= 2; - to_next += 2; - n_left_to_next -= 2; - - p0 = vlib_get_buffer (vm, pi0); - p1 = vlib_get_buffer (vm, pi1); - ip60 = vlib_buffer_get_current (p0); - ip61 = vlib_buffer_get_current (p1); - ila_address0 = &ip60->dst_address; - ila_address1 = &ip61->dst_address; - kv0.key[0] = ip60->dst_address.as_u64[0]; - kv0.key[1] = ip60->dst_address.as_u64[1]; - kv0.key[2] = 0; - kv1.key[0] = ip61->dst_address.as_u64[0]; - kv1.key[1] = ip61->dst_address.as_u64[1]; - kv1.key[2] = 0; - - if (PREDICT_TRUE((BV (clib_bihash_search) - (&ilm->id_to_entry_table, &kv0, &value0)) == 0)) { - ie0 = &ilm->entries[value0.value]; - ila_address0 = (ie0->dir != ILA_DIR_ILA2SIR) ? &ie0->ila_address : ila_address0; - } - - if ((BV (clib_bihash_search) - (&ilm->id_to_entry_table, &kv1, &value1)) == 0) { - ie1 = &ilm->entries[value1.value]; - ila_address1 = (ie1->dir != ILA_DIR_ILA2SIR) ? &ie1->ila_address : ila_address1; - } - - if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) - { - ila_sir2ila_trace_t *tr = - vlib_add_trace (vm, node, p0, sizeof (*tr)); - tr->ila_index = - (ie0 != &ila_sir2ila_default_entry) ? (ie0 - ilm->entries) : ~0; - tr->initial_dst = ip60->dst_address; - } - - if (PREDICT_FALSE (p1->flags & VLIB_BUFFER_IS_TRACED)) - { - ila_sir2ila_trace_t *tr = - vlib_add_trace (vm, node, p1, sizeof (*tr)); - tr->ila_index = - (ie1 != &ila_sir2ila_default_entry) ? (ie1 - ilm->entries) : ~0; - tr->initial_dst = ip61->dst_address; - } - - ip60->dst_address.as_u64[0] = ila_address0->as_u64[0]; - ip60->dst_address.as_u64[1] = ila_address0->as_u64[1]; - ip61->dst_address.as_u64[0] = ila_address1->as_u64[0]; - ip61->dst_address.as_u64[1] = ila_address1->as_u64[1]; - - vnet_feature_next (vnet_buffer (p0)->sw_if_index[VLIB_RX], &next0, p0); - vnet_feature_next (vnet_buffer (p1)->sw_if_index[VLIB_RX], &next1, p1); - - vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, - n_left_to_next, pi0, pi1, next0, - next1); - } - - /* Single loop */ - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 pi0; - vlib_buffer_t *p0; - ip6_header_t *ip60; - u32 next0 = ILA_SIR2ILA_NEXT_DROP; - BVT (clib_bihash_kv) kv0, value0; - ila_entry_t *ie0 = &ila_sir2ila_default_entry; - ip6_address_t *ila_address0; - - 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); - ip60 = vlib_buffer_get_current (p0); - ila_address0 = &ip60->dst_address; - - kv0.key[0] = ip60->dst_address.as_u64[0]; - kv0.key[1] = ip60->dst_address.as_u64[1]; - kv0.key[2] = 0; - - if (PREDICT_TRUE((BV (clib_bihash_search) - (&ilm->id_to_entry_table, &kv0, &value0)) == 0)) { - ie0 = &ilm->entries[value0.value]; - ila_address0 = (ie0->dir != ILA_DIR_ILA2SIR) ? &ie0->ila_address : ila_address0; - } - - if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) - { - ila_sir2ila_trace_t *tr = - vlib_add_trace (vm, node, p0, sizeof (*tr)); - tr->ila_index = - (ie0 != &ila_sir2ila_default_entry) ? (ie0 - ilm->entries) : ~0; - tr->initial_dst = ip60->dst_address; - } - - //This operation should do everything for any type (except vnid4 obviously) - ip60->dst_address.as_u64[0] = ila_address0->as_u64[0]; - ip60->dst_address.as_u64[1] = ila_address0->as_u64[1]; - - vnet_feature_next (vnet_buffer (p0)->sw_if_index[VLIB_RX], &next0, p0); - - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, pi0, next0); - } - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - return frame->n_vectors; -} - -/** *INDENT-OFF* */ -VLIB_REGISTER_NODE (ila_sir2ila_node, static) = -{ - .function = ila_sir2ila,.name = "sir-to-ila", - .vector_size = sizeof (u32), - .format_trace = format_ila_sir2ila_trace, - .n_errors = ILA_N_ERROR, - .error_strings = ila_error_strings, - .n_next_nodes = ILA_SIR2ILA_N_NEXT, - .next_nodes = - { - [ILA_SIR2ILA_NEXT_DROP] = "error-drop" - }, -}; -/** *INDENT-ON* */ - -/** *INDENT-OFF* */ -VNET_FEATURE_INIT (ila_sir2ila, static) = -{ - .arc_name = "ip6-unicast", - .node_name = "sir-to-ila", - .runs_before = VNET_FEATURES ("ip6-lookup"), -}; -/** *INDENT-ON* */ - -static void -ila_entry_stack (ila_entry_t *ie) -{ - /* - * restack on the next-hop's FIB entry - */ - dpo_stack(ila_dpo_type, - DPO_PROTO_IP6, - &ie->ila_dpo, - fib_entry_contribute_ip_forwarding( - ie->next_hop_fib_entry_index)); -} - -int -ila_add_del_entry (ila_add_del_entry_args_t * args) -{ - ila_main_t *ilm = &ila_main; - BVT (clib_bihash_kv) kv, value; - - //Sanity check - if (args->type == ILA_TYPE_IID || args->type == ILA_TYPE_LUID) - { - if ((args->sir_address.as_u8[8] >> 5) != args->type) - { - clib_warning ("Incorrect SIR address (ILA type mismatch %d %d)", - args->sir_address.as_u8[8] >> 1, args->type); - return -1; - } - if (args->sir_address.as_u8[8] & 0x10) - { - clib_warning ("Checksum bit should not be set in SIR address"); - return -1; - } - } - else if (args->type == ILA_TYPE_VNIDM) - { - if (args->sir_address.as_u8[0] != 0xff || - (args->sir_address.as_u8[1] & 0xf0) != 0xf0) - { - clib_warning ("SIR multicast address must start with fff"); - return -1; - } - if (args->sir_address.as_u16[1] || args->sir_address.as_u16[2] || - args->sir_address.as_u16[3] || args->sir_address.as_u16[4] || - args->sir_address.as_u16[5] || (args->sir_address.as_u8[12] & 0xf0)) - { - clib_warning ("SIR multicast address must start with fff"); - return -1; - } - } - - if (!args->is_del) - { - ila_entry_t *e; - pool_get (ilm->entries, e); - e->type = args->type; - e->sir_address = args->sir_address; - e->next_hop = args->next_hop_address; - e->csum_mode = args->csum_mode; - e->dir = args->dir; - - //Construct ILA address - switch (e->type) - { - case ILA_TYPE_IID: - e->ila_address = e->sir_address; - break; - case ILA_TYPE_LUID: - e->ila_address.as_u64[0] = args->locator; - e->ila_address.as_u64[1] = args->sir_address.as_u64[1]; - break; - case ILA_TYPE_VNID6: - e->ila_address.as_u64[0] = args->locator; - e->ila_address.as_u8[8] = (ILA_TYPE_VNID6 << 1); - e->ila_address.as_u32[2] |= args->vnid; - e->ila_address.as_u32[3] = args->sir_address.as_u32[3]; - break; - case ILA_TYPE_VNIDM: - e->ila_address.as_u64[0] = args->locator; - e->ila_address.as_u8[8] = (ILA_TYPE_VNIDM << 1); - e->ila_address.as_u32[2] |= args->vnid; - e->ila_address.as_u32[3] = args->sir_address.as_u32[3]; - e->ila_address.as_u8[12] |= args->sir_address.as_u8[2] << 4; - break; - case ILA_TYPE_VNID4: - clib_warning ("ILA type '%U' is not supported", format_ila_type, - e->type); - return -1; - } - - //Modify ILA checksum if necessary - if (e->csum_mode == ILA_CSUM_MODE_NEUTRAL_MAP) - { - ip_csum_t csum = e->ila_address.as_u16[7]; - int i; - for (i = 0; i < 4; i++) - { - csum = ip_csum_sub_even (csum, e->sir_address.as_u32[i]); - csum = ip_csum_add_even (csum, e->ila_address.as_u32[i]); - } - csum = ip_csum_add_even (csum, clib_host_to_net_u16 (0x1000)); - e->ila_address.as_u16[7] = ip_csum_fold (csum); - e->ila_address.as_u8[8] |= 0x10; - } - - //Create entry with the sir address - kv.key[0] = e->sir_address.as_u64[0]; - kv.key[1] = e->sir_address.as_u64[1]; - kv.key[2] = 0; - kv.value = e - ilm->entries; - BV (clib_bihash_add_del) (&ilm->id_to_entry_table, &kv, - 1 /* is_add */ ); - - if (!ip6_address_is_zero(&e->next_hop)) - { - /* - * become a child of the FIB netry for the next-hop - * so we are informed when its forwarding changes - */ - fib_prefix_t next_hop = { - .fp_addr = { - .ip6 = e->next_hop, - }, - .fp_len = 128, - .fp_proto = FIB_PROTOCOL_IP6, - }; - - e->next_hop_fib_entry_index = - fib_table_entry_special_add(0, - &next_hop, - FIB_SOURCE_RR, - FIB_ENTRY_FLAG_NONE, - ADJ_INDEX_INVALID); - e->next_hop_child_index = - fib_entry_child_add(e->next_hop_fib_entry_index, - ila_fib_node_type, - e - ilm->entries); - - /* - * Create a route that results in the ILA entry - */ - dpo_id_t dpo = DPO_INVALID; - fib_prefix_t pfx = { - .fp_addr = { - .ip6 = e->ila_address, - }, - .fp_len = 128, - .fp_proto = FIB_PROTOCOL_IP6, - }; - - dpo_set(&dpo, ila_dpo_type, DPO_PROTO_IP6, e - ilm->entries); - - fib_table_entry_special_dpo_add(0, - &pfx, - FIB_SOURCE_PLUGIN_HI, - FIB_ENTRY_FLAG_EXCLUSIVE, - &dpo); - dpo_reset(&dpo); - - /* - * finally stack the ILA entry so it will forward to the next-hop - */ - ila_entry_stack (e); - } - } - else - { - ila_entry_t *e; - kv.key[0] = args->sir_address.as_u64[0]; - kv.key[1] = args->sir_address.as_u64[1]; - kv.key[2] = 0; - - if ((BV (clib_bihash_search) (&ilm->id_to_entry_table, &kv, &value) < - 0)) - { - return -1; - } - - e = &ilm->entries[value.value]; - - if (!ip6_address_is_zero(&e->next_hop)) - { - fib_prefix_t pfx = { - .fp_addr = { - .ip6 = e->ila_address, - }, - .fp_len = 128, - .fp_proto = FIB_PROTOCOL_IP6, - }; - - fib_table_entry_special_remove(0, &pfx, FIB_SOURCE_PLUGIN_HI); - /* - * remove this ILA entry as child of the FIB netry for the next-hop - */ - fib_entry_child_remove(e->next_hop_fib_entry_index, - e->next_hop_child_index); - fib_table_entry_delete_index(e->next_hop_fib_entry_index, - FIB_SOURCE_RR); - e->next_hop_fib_entry_index = FIB_NODE_INDEX_INVALID; - } - dpo_reset (&e->ila_dpo); - - BV (clib_bihash_add_del) (&ilm->id_to_entry_table, &kv, - 0 /* is_add */ ); - pool_put (ilm->entries, e); - } - return 0; -} - -int -ila_interface (u32 sw_if_index, u8 disable) -{ - vnet_feature_enable_disable ("ip4-unicast", "sir-to-ila", sw_if_index, - !disable, 0, 0); - 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_ila_dpo (u8 * s, va_list * va) -{ - index_t index = va_arg (*va, index_t); - CLIB_UNUSED(u32 indent) = va_arg (*va, u32); - ila_main_t *ilm = &ila_main; - ila_entry_t *ie = pool_elt_at_index (ilm->entries, index); - return format(s, "ILA: idx:%d sir:%U", - index, - format_ip6_address, &ie->sir_address); -} - -/** - * @brief no-op lock function. - * The lifetime of the ILA entry is managed by the control plane - */ -static void -ila_dpo_lock (dpo_id_t *dpo) -{ -} - -/** - * @brief no-op unlock function. - * The lifetime of the ILA entry is managed by the control plane - */ -static void -ila_dpo_unlock (dpo_id_t *dpo) -{ -} - -const static dpo_vft_t ila_vft = { - .dv_lock = ila_dpo_lock, - .dv_unlock = ila_dpo_unlock, - .dv_format = format_ila_dpo, -}; -const static char* const ila_ip6_nodes[] = -{ - "ila-to-sir", - NULL, -}; -const static char* const * const ila_nodes[DPO_PROTO_NUM] = -{ - [DPO_PROTO_IP6] = ila_ip6_nodes, -}; - -static fib_node_t * -ila_fib_node_get_node (fib_node_index_t index) -{ - ila_main_t *ilm = &ila_main; - ila_entry_t *ie = pool_elt_at_index (ilm->entries, index); - - return (&ie->ila_fib_node); -} - -/** - * @brief no-op unlock function. - * The lifetime of the ILA entry is managed by the control plane - */ -static void -ila_fib_node_last_lock_gone (fib_node_t *node) -{ -} - -static ila_entry_t * -ila_entry_from_fib_node (fib_node_t *node) -{ - return ((ila_entry_t*)(((char*)node) - - STRUCT_OFFSET_OF(ila_entry_t, ila_fib_node))); -} - -/** - * @brief - * Callback function invoked when the forwarding changes for the ILA next-hop - */ -static fib_node_back_walk_rc_t -ila_fib_node_back_walk_notify (fib_node_t *node, - fib_node_back_walk_ctx_t *ctx) -{ - ila_entry_stack(ila_entry_from_fib_node(node)); - - return (FIB_NODE_BACK_WALK_CONTINUE); -} - -/* - * ILA's FIB graph node virtual function table - */ -static const fib_node_vft_t ila_fib_node_vft = { - .fnv_get = ila_fib_node_get_node, - .fnv_last_lock = ila_fib_node_last_lock_gone, - .fnv_back_walk = ila_fib_node_back_walk_notify, -}; - -clib_error_t * -ila_init (vlib_main_t * vm) -{ - ila_main_t *ilm = &ila_main; - ilm->entries = NULL; - - ilm->lookup_table_nbuckets = ILA_TABLE_DEFAULT_HASH_NUM_BUCKETS; - ilm->lookup_table_nbuckets = 1 << max_log2 (ilm->lookup_table_nbuckets); - ilm->lookup_table_size = ILA_TABLE_DEFAULT_HASH_MEMORY_SIZE; - - BV (clib_bihash_init) (&ilm->id_to_entry_table, - "ila id to entry index table", - ilm->lookup_table_nbuckets, ilm->lookup_table_size); - - ila_dpo_type = dpo_register_new_type(&ila_vft, ila_nodes); - ila_fib_node_type = fib_node_register_new_type(&ila_fib_node_vft); - - return NULL; -} - -VLIB_INIT_FUNCTION (ila_init); - -static clib_error_t * -ila_entry_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - ila_add_del_entry_args_t args = { 0 }; - u8 next_hop_set = 0; - int ret; - - args.type = ILA_TYPE_IID; - args.csum_mode = ILA_CSUM_MODE_NO_ACTION; - args.local_adj_index = ~0; - args.dir = ILA_DIR_BIDIR; - - 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, "type %U", unformat_ila_type, &args.type)) - ; - else if (unformat - (line_input, "sir-address %U", unformat_ip6_address, - &args.sir_address)) - ; - else if (unformat - (line_input, "locator %U", unformat_half_ip6_address, - &args.locator)) - ; - else if (unformat - (line_input, "csum-mode %U", unformat_ila_csum_mode, - &args.csum_mode)) - ; - else if (unformat (line_input, "vnid %x", &args.vnid)) - ; - else if (unformat - (line_input, "next-hop %U", unformat_ip6_address, - &args.next_hop_address)) - ; - else if (unformat - (line_input, "direction %U", unformat_ila_direction, &args.dir)) - next_hop_set = 1; - else if (unformat (line_input, "del")) - args.is_del = 1; - else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); - } - - unformat_free (line_input); - - if (!next_hop_set) - return clib_error_return (0, "Specified a next hop"); - - if ((ret = ila_add_del_entry (&args))) - return clib_error_return (0, "ila_add_del_entry returned error %d", ret); - - return NULL; -} - -VLIB_CLI_COMMAND (ila_entry_command, static) = -{ - .path = "ila entry", - .short_help = "ila entry [type ] [sir-address

] [locator ] [vnid ]" - " [adj-index ] [next-hop ] [direction (bidir|sir2ila|ila2sir)]" - " [csum-mode (no-action|neutral-map|transport-adjust)] [del]", - .function = ila_entry_command_fn, -}; - -static clib_error_t * -ila_interface_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - vnet_main_t *vnm = vnet_get_main (); - u32 sw_if_index = ~0; - u8 disable = 0; - - if (!unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index)) - { - return clib_error_return (0, "Invalid interface name"); - } - - if (unformat (input, "disable")) - { - disable = 1; - } - - int ret; - if ((ret = ila_interface (sw_if_index, disable))) - return clib_error_return (0, "ila_interface returned error %d", ret); - - return NULL; -} - -VLIB_CLI_COMMAND (ila_interface_command, static) = -{ - .path = "ila interface", - .short_help = "ila interface [disable]", - .function = ila_interface_command_fn, -}; - -static clib_error_t * -ila_show_entries_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - vnet_main_t *vnm = vnet_get_main (); - ila_main_t *ilm = &ila_main; - ila_entry_t *e; - - vlib_cli_output (vm, " %U\n", format_ila_entry, vnm, NULL); - pool_foreach (e, ilm->entries, - ({ - vlib_cli_output (vm, " %U\n", format_ila_entry, vnm, e); - })); - - return NULL; -} - -VLIB_CLI_COMMAND (ila_show_entries_command, static) = -{ - .path = "show ila entries", - .short_help = "show ila entries", - .function = ila_show_entries_command_fn, -}; diff --git a/plugins/ila-plugin/ila/ila.h b/plugins/ila-plugin/ila/ila.h deleted file mode 100644 index 26620983..00000000 --- a/plugins/ila-plugin/ila/ila.h +++ /dev/null @@ -1,116 +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 ILA_H -#define ILA_H - -#include -#include -#include - -#include -#include - -#define ila_foreach_type \ - _(IID, 0, "iid") \ - _(LUID, 1, "luid") \ - _(VNID4, 2, "vnid-ip4") \ - _(VNID6, 3, "vnid-ip6") \ - _(VNIDM, 4, "vnid-multicast") - -typedef enum { -#define _(i,n,s) ILA_TYPE_##i = n, - ila_foreach_type -#undef _ -} ila_type_t; - -#define ila_csum_foreach_type \ -_(NO_ACTION, 0, "no-action") \ -_(NEUTRAL_MAP, 1, "neutral-map") \ -_(ADJUST_TRANSPORT, 2, "adjust-transport") - -typedef enum { -#define _(i,n,s) ILA_CSUM_MODE_##i = n, - ila_csum_foreach_type -#undef _ - ILA_CSUM_N_TYPES -} ila_csum_mode_t; - -#define ila_foreach_direction \ -_(BIDIR, 0, "bidir") \ -_(SIR2ILA, 1, "sir2ila") \ -_(ILA2SIR, 2, "ila2sir") - -typedef enum { -#define _(i,n,s) ILA_DIR_##i = n, - ila_foreach_direction -#undef _ -} ila_direction_t; - -typedef struct { - /** - * Fib Node base class - */ - fib_node_t ila_fib_node; - ila_type_t type; - ip6_address_t sir_address; - ip6_address_t ila_address; - ip6_address_t next_hop; - ila_csum_mode_t csum_mode; - ila_direction_t dir; - - /** - * 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 grpah to follow - */ - dpo_id_t ila_dpo; -} ila_entry_t; - -typedef struct { - ila_entry_t *entries; //Pool of ILA entries - - u64 lookup_table_nbuckets; - u64 lookup_table_size; - clib_bihash_24_8_t id_to_entry_table; - - u32 ip6_lookup_next_index; -} ila_main_t; - - -typedef struct { - ila_type_t type; - ip6_address_t sir_address; - ip6_address_t next_hop_address; - u64 locator; - u32 vnid; - u32 local_adj_index; - ila_csum_mode_t csum_mode; - ila_direction_t dir; - u8 is_del; -} ila_add_del_entry_args_t; - -int ila_add_del_entry (ila_add_del_entry_args_t * args); -int ila_interface (u32 sw_if_index, u8 disable); - -#endif //ILA_H diff --git a/plugins/sixrd-plugin/Makefile.am b/plugins/sixrd-plugin/Makefile.am deleted file mode 100644 index eb0d806a..00000000 --- a/plugins/sixrd-plugin/Makefile.am +++ /dev/null @@ -1,38 +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 - -libsixrd_plugin_la_SOURCES = \ - sixrd/sixrd.c \ - sixrd/sixrd_dpo.c \ - sixrd/ip4_sixrd.c \ - sixrd/ip6_sixrd.c - -noinst_HEADERS = \ - sixrd/sixrd.h \ - sixrd/sixrd_dpo.h - -BUILT_SOURCES = - -vpppluginsdir = ${libdir}/vpp_plugins - -vppplugins_LTLIBRARIES = libsixrd_plugin.la - - -# Remove *.la files -install-data-hook: - @(cd $(vpppluginsdir) && $(RM) $(vppplugins_LTLIBRARIES)) diff --git a/plugins/sixrd-plugin/configure.ac b/plugins/sixrd-plugin/configure.ac deleted file mode 100644 index 3aa4c425..00000000 --- a/plugins/sixrd-plugin/configure.ac +++ /dev/null @@ -1,9 +0,0 @@ -AC_INIT(sixrd_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/sixrd-plugin/sixrd/ip4_sixrd.c b/plugins/sixrd-plugin/sixrd/ip4_sixrd.c deleted file mode 100644 index 2fb8015d..00000000 --- a/plugins/sixrd-plugin/sixrd/ip4_sixrd.c +++ /dev/null @@ -1,127 +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. - *--------------------------------------------------------------------------- - */ -#include "sixrd.h" - -static vlib_node_registration_t ip4_sixrd_node; - -typedef enum { - IP4_SIXRD_NEXT_IP6_LOOKUP, - IP4_SIXRD_NEXT_DROP, - IP4_SIXRD_N_NEXT, -} ip4_sixrd_next_t; - -/* - * ip4_sixrd_sec_check - */ -static_always_inline void -ip4_sixrd_sec_check (sixrd_domain_t *d, ip4_address_t sa4, ip6_address_t sa6, u8 *error) -{ - u32 a = sixrd_get_addr(d, sa6.as_u64[0]); - clib_warning("Security check: %U %U", format_ip4_address, &a, format_ip4_address, &sa4); - if (PREDICT_FALSE(sixrd_get_addr(d, sa6.as_u64[0]) != sa4.as_u32)) - *error = SIXRD_ERROR_SEC_CHECK; -} - -/* - * ip4_sixrd - */ -static uword -ip4_sixrd (vlib_main_t *vm, - vlib_node_runtime_t *node, - vlib_frame_t *frame) -{ - u32 n_left_from, *from, next_index, *to_next, n_left_to_next; - vlib_node_runtime_t *error_node = vlib_node_get_runtime(vm, ip4_sixrd_node.index); - u32 decap = 0; - - from = vlib_frame_vector_args(frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - while (n_left_from > 0) { - vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next); - - /* Single loop */ - while (n_left_from > 0 && n_left_to_next > 0) { - u32 pi0; - vlib_buffer_t *p0; - u8 error0 = SIXRD_ERROR_NONE; - sixrd_domain_t *d0 = 0; - ip4_header_t *ip40; - ip6_header_t *ip60; - u32 sixrd_domain_index0 = ~0; - u32 next0; - - 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); - ip40 = vlib_buffer_get_current(p0); - - /* Throw away anything that isn't IP in IP. */ - if (PREDICT_TRUE(ip40->protocol == IP_PROTOCOL_IPV6 && clib_net_to_host_u16(ip40->length) >= 60)) { - vlib_buffer_advance(p0, sizeof(ip4_header_t)); - ip60 = vlib_buffer_get_current(p0); - d0 = ip4_sixrd_get_domain(vnet_buffer(p0)->ip.adj_index[VLIB_TX], (ip6_address_t *)&ip60->src_address, - &sixrd_domain_index0, &error0); - } else { - error0 = SIXRD_ERROR_BAD_PROTOCOL; - } - if (d0) { - /* SIXRD inbound security check */ - ip4_sixrd_sec_check(d0, ip40->src_address, ip60->src_address, &error0); - } - - next0 = error0 == SIXRD_ERROR_NONE ? IP4_SIXRD_NEXT_IP6_LOOKUP : IP4_SIXRD_NEXT_DROP; - - if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED)) { - sixrd_trace_t *tr = vlib_add_trace(vm, node, p0, sizeof(*tr)); - tr->sixrd_domain_index = sixrd_domain_index0; - } - - p0->error = error_node->errors[error0]; - if (PREDICT_TRUE(error0 == SIXRD_ERROR_NONE)) decap++; - vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, pi0, next0); - - } - vlib_put_next_frame(vm, node, next_index, n_left_to_next); - } - vlib_node_increment_counter(vm, ip4_sixrd_node.index, SIXRD_ERROR_DECAPSULATED, decap); - - return frame->n_vectors; -} - -static char *sixrd_error_strings[] = { -#define _(sym,string) string, - foreach_sixrd_error -#undef _ -}; - -VLIB_REGISTER_NODE(ip4_sixrd_node,static) = { - .function = ip4_sixrd, - .name = "ip4-sixrd", - .vector_size = sizeof(u32), - .format_trace = format_sixrd_trace, - .n_errors = SIXRD_N_ERROR, - .error_strings = sixrd_error_strings, - .n_next_nodes = IP4_SIXRD_N_NEXT, - .next_nodes = { - [IP4_SIXRD_NEXT_IP6_LOOKUP] = "ip6-lookup", - [IP4_SIXRD_NEXT_DROP] = "error-drop", - }, -}; diff --git a/plugins/sixrd-plugin/sixrd/ip6_sixrd.c b/plugins/sixrd-plugin/sixrd/ip6_sixrd.c deleted file mode 100644 index 36f3fab3..00000000 --- a/plugins/sixrd-plugin/sixrd/ip6_sixrd.c +++ /dev/null @@ -1,129 +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. - *--------------------------------------------------------------------------- - */ -/* - * Defines used for testing various optimisation schemes - */ -#define SIXRD_ENCAP_DUAL 0 - -#include "sixrd.h" - -static vlib_node_registration_t ip6_sixrd_node; - -typedef enum { - IP6_SIXRD_NEXT_IP4_LOOKUP, - IP6_SIXRD_NEXT_DROP, - IP6_SIXRD_N_NEXT, -} ip6_sixrd_next_t; - -/* - * ip6_sixrd - */ -static uword -ip6_sixrd (vlib_main_t *vm, - vlib_node_runtime_t *node, - vlib_frame_t *frame) -{ - u32 n_left_from, *from, next_index, *to_next, n_left_to_next; - vlib_node_runtime_t *error_node = vlib_node_get_runtime(vm, ip6_sixrd_node.index); - u32 encap = 0; - from = vlib_frame_vector_args(frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - 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; - sixrd_domain_t *d0; - u8 error0 = SIXRD_ERROR_NONE; - ip6_header_t *ip60; - ip4_header_t *ip4h0; - u32 next0 = IP6_SIXRD_NEXT_IP4_LOOKUP; - u32 sixrd_domain_index0 = ~0; - - 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); - ip60 = vlib_buffer_get_current(p0); - // p0->current_length = clib_net_to_host_u16(ip40->length); - d0 = ip6_sixrd_get_domain(vnet_buffer(p0)->ip.adj_index[VLIB_TX], &sixrd_domain_index0); - ASSERT(d0); - - /* SIXRD calc */ - u64 dal60 = clib_net_to_host_u64(ip60->dst_address.as_u64[0]); - u32 da40 = sixrd_get_addr(d0, dal60); - u16 len = clib_net_to_host_u16(ip60->payload_length) + 60; - if (da40 == 0) error0 = SIXRD_ERROR_UNKNOWN; - - /* construct ipv4 header */ - vlib_buffer_advance(p0, - (sizeof(ip4_header_t))); - ip4h0 = vlib_buffer_get_current(p0); - vnet_buffer(p0)->sw_if_index[VLIB_TX] = (u32)~0; - ip4h0->ip_version_and_header_length = 0x45; - ip4h0->tos = 0; - ip4h0->length = clib_host_to_net_u16(len); - ip4h0->fragment_id = 0; - ip4h0->flags_and_fragment_offset = 0; - ip4h0->ttl = 0x40; - ip4h0->protocol = IP_PROTOCOL_IPV6; - ip4h0->src_address = d0->ip4_src; - ip4h0->dst_address.as_u32 = clib_host_to_net_u32(da40); - ip4h0->checksum = ip4_header_checksum(ip4h0); - - next0 = error0 == SIXRD_ERROR_NONE ? IP6_SIXRD_NEXT_IP4_LOOKUP : IP6_SIXRD_NEXT_DROP; - - if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED)) { - sixrd_trace_t *tr = vlib_add_trace(vm, node, p0, sizeof(*tr)); - tr->sixrd_domain_index = sixrd_domain_index0; - } - - p0->error = error_node->errors[error0]; - if (PREDICT_TRUE(error0 == SIXRD_ERROR_NONE)) encap++; - - vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, pi0, next0); - } - vlib_put_next_frame(vm, node, next_index, n_left_to_next); - } - vlib_node_increment_counter(vm, ip6_sixrd_node.index, SIXRD_ERROR_ENCAPSULATED, encap); - - return frame->n_vectors; -} - -static char *sixrd_error_strings[] = { -#define _(sym,string) string, - foreach_sixrd_error -#undef _ -}; - -VLIB_REGISTER_NODE(ip6_sixrd_node,static) = { - .function = ip6_sixrd, - .name = "ip6-sixrd", - .vector_size = sizeof(u32), - .format_trace = format_sixrd_trace, - .n_errors = SIXRD_N_ERROR, - .error_strings = sixrd_error_strings, - .n_next_nodes = IP6_SIXRD_N_NEXT, - .next_nodes = { - [IP6_SIXRD_NEXT_IP4_LOOKUP] = "ip4-lookup", - [IP6_SIXRD_NEXT_DROP] = "error-drop", - }, -}; diff --git a/plugins/sixrd-plugin/sixrd/sixrd.c b/plugins/sixrd-plugin/sixrd/sixrd.c deleted file mode 100644 index 66e631a2..00000000 --- a/plugins/sixrd-plugin/sixrd/sixrd.c +++ /dev/null @@ -1,369 +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 "sixrd.h" -#include - -#include -#include -#include - -/* - * This code supports the following sixrd modes: - * - * 32 EA bits (Complete IPv4 address is embedded): - * ea_bits_len = 32 - * IPv4 suffix is embedded: - * ea_bits_len = < 32 - * No embedded address bits (1:1 mode): - * ea_bits_len = 0 - */ - -int -sixrd_create_domain (ip6_address_t *ip6_prefix, - u8 ip6_prefix_len, - ip4_address_t *ip4_prefix, - u8 ip4_prefix_len, - ip4_address_t *ip4_src, - u32 *sixrd_domain_index, - u16 mtu) -{ - dpo_id_t dpo_v6 = DPO_INVALID, dpo_v4 = DPO_INVALID; - sixrd_main_t *mm = &sixrd_main; - fib_node_index_t fei; - sixrd_domain_t *d; - - /* Get domain index */ - pool_get_aligned(mm->domains, d, CLIB_CACHE_LINE_BYTES); - memset(d, 0, sizeof (*d)); - *sixrd_domain_index = d - mm->domains; - - /* Init domain struct */ - d->ip4_prefix.as_u32 = ip4_prefix->as_u32; - d->ip4_prefix_len = ip4_prefix_len; - d->ip6_prefix = *ip6_prefix; - d->ip6_prefix_len = ip6_prefix_len; - d->ip4_src = *ip4_src; - d->mtu = mtu; - - if (ip4_prefix_len < 32) - d->shift = 64 - ip6_prefix_len + (32 - ip4_prefix_len); - - /* Create IPv6 route/adjacency */ - fib_prefix_t pfx6 = { - .fp_proto = FIB_PROTOCOL_IP6, - .fp_len = d->ip6_prefix_len, - .fp_addr = { - .ip6 = d->ip6_prefix, - }, - }; - sixrd_dpo_create(DPO_PROTO_IP6, - *sixrd_domain_index, - &dpo_v6); - fib_table_entry_special_dpo_add(0, &pfx6, - FIB_SOURCE_SIXRD, - FIB_ENTRY_FLAG_EXCLUSIVE, - &dpo_v6); - dpo_reset (&dpo_v6); - - /* - * Multiple SIXRD domains may share same source IPv4 TEP - * In this case the route will exist and be SixRD sourced. - * Find the adj (if any) already contributed and modify it - */ - fib_prefix_t pfx4 = { - .fp_proto = FIB_PROTOCOL_IP4, - .fp_len = 32, - .fp_addr = { - .ip4 = d->ip4_src, - }, - }; - fei = fib_table_lookup_exact_match(0, &pfx4); - - if (FIB_NODE_INDEX_INVALID != fei) - { - dpo_id_t dpo = DPO_INVALID; - - if (fib_entry_get_dpo_for_source (fei, FIB_SOURCE_SIXRD, &dpo)) - { - /* - * modify the existing adj to indicate it's shared - * skip to route add. - * It is locked to pair with the unlock below. - */ - const dpo_id_t *sd_dpo; - sixrd_dpo_t *sd; - - ASSERT(DPO_LOAD_BALANCE == dpo.dpoi_type); - - sd_dpo = load_balance_get_bucket(dpo.dpoi_index, 0); - sd = sixrd_dpo_get (sd_dpo->dpoi_index); - - sd->sd_domain = ~0; - dpo_copy (&dpo_v4, sd_dpo); - dpo_reset (&dpo); - - goto route_add; - } - } - /* first time addition of the route */ - sixrd_dpo_create(DPO_PROTO_IP4, - *sixrd_domain_index, - &dpo_v4); - -route_add: - /* - * Create ip4 route. This is a reference counted add. If the prefix - * already exists and is SixRD sourced, it is now SixRD source n+1 times - * and will need to be removed n+1 times. - */ - fib_table_entry_special_dpo_add(0, &pfx4, - FIB_SOURCE_SIXRD, - FIB_ENTRY_FLAG_EXCLUSIVE, - &dpo_v4); - dpo_reset (&dpo_v4); - - return 0; -} - -/* - * sixrd_delete_domain - */ -int -sixrd_delete_domain (u32 sixrd_domain_index) -{ - sixrd_main_t *mm = &sixrd_main; - sixrd_domain_t *d; - - if (pool_is_free_index(mm->domains, sixrd_domain_index)) { - clib_warning("SIXRD domain delete: domain does not exist: %d", - sixrd_domain_index); - return -1; - } - - d = pool_elt_at_index(mm->domains, sixrd_domain_index); - - fib_prefix_t pfx = { - .fp_proto = FIB_PROTOCOL_IP4, - .fp_len = 32, - .fp_addr = { - .ip4 = d->ip4_src, - }, - }; - fib_table_entry_special_remove(0, &pfx, FIB_SOURCE_SIXRD); - - fib_prefix_t pfx6 = { - .fp_proto = FIB_PROTOCOL_IP6, - .fp_len = d->ip6_prefix_len, - .fp_addr = { - .ip6 = d->ip6_prefix, - }, - }; - fib_table_entry_special_remove(0, &pfx6, FIB_SOURCE_SIXRD); - - pool_put(mm->domains, d); - - return 0; -} - -static clib_error_t * -sixrd_add_domain_command_fn (vlib_main_t *vm, - unformat_input_t *input, - vlib_cli_command_t *cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - ip4_address_t ip4_prefix; - ip6_address_t ip6_prefix; - ip4_address_t ip4_src; - u32 ip6_prefix_len=0, ip4_prefix_len=0, sixrd_domain_index; - u32 num_m_args = 0; - /* Optional arguments */ - u32 mtu = 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, "ip6-pfx %U/%d", unformat_ip6_address, &ip6_prefix, &ip6_prefix_len)) - num_m_args++; - else if (unformat(line_input, "ip4-pfx %U/%d", unformat_ip4_address, &ip4_prefix, &ip4_prefix_len)) - num_m_args++; - else if (unformat(line_input, "ip4-src %U", unformat_ip4_address, &ip4_src)) - num_m_args++; - else if (unformat(line_input, "mtu %d", &mtu)) - num_m_args++; - else - return clib_error_return(0, "unknown input `%U'", - format_unformat_error, input); - } - unformat_free(line_input); - - if (num_m_args < 3) - return clib_error_return(0, "mandatory argument(s) missing"); - - sixrd_create_domain(&ip6_prefix, ip6_prefix_len, &ip4_prefix, ip4_prefix_len, - &ip4_src, &sixrd_domain_index, mtu); - - return 0; -} - -static clib_error_t * -sixrd_del_domain_command_fn (vlib_main_t *vm, - unformat_input_t *input, - vlib_cli_command_t *cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - u32 num_m_args = 0; - u32 sixrd_domain_index; - - /* 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, "index %d", &sixrd_domain_index)) - num_m_args++; - else - return clib_error_return(0, "unknown input `%U'", - format_unformat_error, input); - } - unformat_free(line_input); - - if (num_m_args != 1) - return clib_error_return(0, "mandatory argument(s) missing"); - - sixrd_delete_domain(sixrd_domain_index); - - return 0; -} - -static u8 * -format_sixrd_domain (u8 *s, va_list *args) -{ - sixrd_domain_t *d = va_arg(*args, sixrd_domain_t *); - sixrd_main_t *mm = &sixrd_main; - - s = format(s, - "[%d] ip6-pfx %U/%d ip4-pfx %U/%d ip4-src %U mtu %d", - d - mm->domains, - format_ip6_address, &d->ip6_prefix, d->ip6_prefix_len, - format_ip4_address, &d->ip4_prefix, d->ip4_prefix_len, - format_ip4_address, &d->ip4_src, d->mtu); - - return s; -} - -static clib_error_t * -show_sixrd_domain_command_fn (vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd) -{ - sixrd_main_t *mm = &sixrd_main; - sixrd_domain_t *d; - - if (pool_elts(mm->domains) == 0) - vlib_cli_output(vm, "No SIXRD domains are configured..."); - - pool_foreach(d, mm->domains, ({vlib_cli_output(vm, "%U", format_sixrd_domain, d);})); - - return 0; - -} - -static clib_error_t * -show_sixrd_stats_command_fn (vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd) -{ - sixrd_main_t *mm = &sixrd_main; - sixrd_domain_t *d; - int domains = 0, domaincount = 0; - if (pool_elts (mm->domains) == 0) - vlib_cli_output (vm, "No SIXRD domains are configured..."); - - pool_foreach(d, mm->domains, ({ - domains += sizeof(*d); - domaincount++; - })); - - vlib_cli_output(vm, "SIXRD domains structure: %d\n", sizeof (sixrd_domain_t)); - vlib_cli_output(vm, "SIXRD domains: %d (%d bytes)\n", domaincount, domains); - - return 0; -} - -/* - * packet trace format function - */ -u8 * -format_sixrd_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 *); - sixrd_trace_t *t = va_arg (*args, sixrd_trace_t *); - u32 sixrd_domain_index = t->sixrd_domain_index; - - s = format(s, "SIXRD domain index: %d", sixrd_domain_index); - - return s; -} - -VLIB_CLI_COMMAND(sixrd_add_domain_command, static) = { - .path = "sixrd add domain", - .short_help = - "sixrd add domain ip6-pfx ip4-pfx ip4-src ", - .function = sixrd_add_domain_command_fn, -}; - -VLIB_CLI_COMMAND(sixrd_del_command, static) = { - .path = "sixrd del domain", - .short_help = - "sixrd del domain index ", - .function = sixrd_del_domain_command_fn, -}; - -VLIB_CLI_COMMAND(show_sixrd_domain_command, static) = { - .path = "show sixrd domain", - .function = show_sixrd_domain_command_fn, -}; - -VLIB_CLI_COMMAND(show_sixrd_stats_command, static) = { - .path = "show sixrd stats", - .function = show_sixrd_stats_command_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; - sixrd_main_t *mm = &sixrd_main; - - mm->vnet_main = vnet_get_main(); - mm->vlib_main = vm; - - return error; -} - -static clib_error_t * sixrd_init (vlib_main_t * vm) -{ - sixrd_dpo_module_init (); - - return (NULL); -} - -VLIB_INIT_FUNCTION (sixrd_init); diff --git a/plugins/sixrd-plugin/sixrd/sixrd.h b/plugins/sixrd-plugin/sixrd/sixrd.h deleted file mode 100644 index 56714c9e..00000000 --- a/plugins/sixrd-plugin/sixrd/sixrd.h +++ /dev/null @@ -1,141 +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. - *--------------------------------------------------------------------------- - */ -#include -#include -#include -#include -#include - -#include "sixrd_dpo.h" - -int sixrd_create_domain(ip6_address_t *ip6_prefix, u8 ip6_prefix_len, - ip4_address_t *ip4_prefix, u8 ip4_prefix_len, - ip4_address_t *ip4_src, u32 *sixrd_domain_index, u16 mtu); -int sixrd_delete_domain(u32 sixrd_domain_index); -u8 *format_sixrd_trace(u8 *s, va_list *args); - -typedef struct { - ip6_address_t ip6_prefix; - ip4_address_t ip4_prefix; - ip4_address_t ip4_src; - u8 ip6_prefix_len; - u8 ip4_prefix_len; - - /* helpers */ - u8 shift; - - u16 mtu; -} sixrd_domain_t; - -typedef struct { - /* pool of SIXRD domains */ - sixrd_domain_t *domains; - - /* convenience */ - vlib_main_t *vlib_main; - vnet_main_t *vnet_main; -} sixrd_main_t; - -#define foreach_sixrd_error \ - /* Must be first. */ \ - _(NONE, "valid SIXRD packets") \ - _(BAD_PROTOCOL, "bad protocol") \ - _(WRONG_ICMP_TYPE, "wrong icmp type") \ - _(SEC_CHECK, "security check failed") \ - _(ICMP, "unable to translate ICMP") \ - _(UNKNOWN, "unknown") \ - _(NO_DOMAIN, "no domain") \ - _(ENCAPSULATED, "encapsulated") \ - _(DECAPSULATED, "decapsulated") \ - _(TRANSLATED_4TO6, "translated 4 to 6") \ - _(TRANSLATED_6TO4, "translated 6 to 4") \ - _(FRAGMENT, "fragment handling error") \ - _(FRAGMENT_QUEUED, "dropped, missing first fragment") \ - _(FRAGMENTED, "packets requiring fragmentation") \ - _(FRAGMENT_PARTS, "fragment parts") \ - _(MALFORMED, "malformed packet") - -typedef enum { -#define _(sym,str) SIXRD_ERROR_##sym, - foreach_sixrd_error -#undef _ - SIXRD_N_ERROR, - } sixrd_error_t; - -typedef struct { - u32 sixrd_domain_index; -} sixrd_trace_t; - -sixrd_main_t sixrd_main; - -/* - * sixrd_get_addr - */ -static_always_inline u32 -sixrd_get_addr (sixrd_domain_t *d, u64 dal) -{ - - /* 1:1 mode */ - if (d->ip4_prefix_len == 32) return (d->ip4_prefix.as_u32); - - /* Grab 32 - ip4_prefix_len bits out of IPv6 address from offset ip6_prefix_len */ - return (d->ip4_prefix.as_u32 | (u32)(dal >> d->shift)); -} - -/* - * Get the SIXRD domain from an IPv6 lookup adjacency. - */ -static_always_inline sixrd_domain_t * -ip6_sixrd_get_domain (u32 sdi, u32 *sixrd_domain_index) -{ - sixrd_main_t *mm = &sixrd_main; - sixrd_dpo_t *sd; - - sd = sixrd_dpo_get(sdi); - - ASSERT(sd); - *sixrd_domain_index = sd->sd_domain; - return pool_elt_at_index(mm->domains, *sixrd_domain_index); -} - -/* - * Get the SIXRD domain from an IPv4 lookup adjacency. - * If the IPv4 address is not shared, no lookup is required. - * The IPv6 address is used otherwise. - */ -static_always_inline sixrd_domain_t * -ip4_sixrd_get_domain (u32 sdi, ip6_address_t *addr, - u32 *sixrd_domain_index, u8 *error) -{ - sixrd_main_t *mm = &sixrd_main; - sixrd_dpo_t *sd; - - sd = sixrd_dpo_get(sdi); - *sixrd_domain_index = sd->sd_domain; - if (*sixrd_domain_index != ~0) - return pool_elt_at_index(mm->domains, *sixrd_domain_index); - - u32 lbi = ip6_fib_table_fwding_lookup(&ip6_main, 0, addr); - const dpo_id_t *dpo = load_balance_get_bucket(lbi, 0); - if (PREDICT_TRUE(dpo->dpoi_type == sixrd_dpo_type)) - { - sd = sixrd_dpo_get(dpo->dpoi_index); - *sixrd_domain_index = sd->sd_domain; - return pool_elt_at_index(mm->domains, *sixrd_domain_index); - } - *error = SIXRD_ERROR_NO_DOMAIN; - return NULL; -} diff --git a/plugins/sixrd-plugin/sixrd/sixrd_dpo.c b/plugins/sixrd-plugin/sixrd/sixrd_dpo.c deleted file mode 100644 index 88a07935..00000000 --- a/plugins/sixrd-plugin/sixrd/sixrd_dpo.c +++ /dev/null @@ -1,132 +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 "sixrd_dpo.h" -#include - -/** - * pool of all MPLS Label DPOs - */ -sixrd_dpo_t *sixrd_dpo_pool; - -/** - * The register SIXRD DPO type - */ -dpo_type_t sixrd_dpo_type; - -static sixrd_dpo_t * -sixrd_dpo_alloc (void) -{ - sixrd_dpo_t *sd; - - pool_get_aligned(sixrd_dpo_pool, sd, CLIB_CACHE_LINE_BYTES); - memset(sd, 0, sizeof(*sd)); - - return (sd); -} - -static index_t -sixrd_dpo_get_index (sixrd_dpo_t *sd) -{ - return (sd - sixrd_dpo_pool); -} - -void -sixrd_dpo_create (dpo_proto_t dproto, - u32 domain_index, - dpo_id_t *dpo) -{ - sixrd_dpo_t *sd; - - sd = sixrd_dpo_alloc(); - sd->sd_domain = domain_index; - sd->sd_proto = dproto; - - dpo_set(dpo, - sixrd_dpo_type, - dproto, - sixrd_dpo_get_index(sd)); -} - -u8* -format_sixrd_dpo (u8 *s, va_list *args) -{ - index_t index = va_arg (*args, index_t); - CLIB_UNUSED(u32 indent) = va_arg (*args, u32); - sixrd_dpo_t *sd; - - sd = sixrd_dpo_get(index); - - return (format(s, "sixrd:[%d]:%U domain:%d", - index, - format_dpo_proto, sd->sd_proto, - sd->sd_domain)); -} - - -static void -sixrd_dpo_lock (dpo_id_t *dpo) -{ - sixrd_dpo_t *sd; - - sd = sixrd_dpo_get(dpo->dpoi_index); - - sd->sd_locks++; -} - -static void -sixrd_dpo_unlock (dpo_id_t *dpo) -{ - sixrd_dpo_t *sd; - - sd = sixrd_dpo_get(dpo->dpoi_index); - - sd->sd_locks--; - - if (0 == sd->sd_locks) - { - pool_put(sixrd_dpo_pool, sd); - } -} - -const static dpo_vft_t sd_vft = { - .dv_lock = sixrd_dpo_lock, - .dv_unlock = sixrd_dpo_unlock, - .dv_format = format_sixrd_dpo, -}; - -const static char* const sixrd_ip4_nodes[] = -{ - "ip4-sixrd", - NULL, -}; -const static char* const sixrd_ip6_nodes[] = -{ - "ip6-sixrd", - NULL, -}; - -const static char* const * const sixrd_nodes[DPO_PROTO_NUM] = -{ - [DPO_PROTO_IP4] = sixrd_ip4_nodes, - [DPO_PROTO_IP6] = sixrd_ip6_nodes, - [DPO_PROTO_MPLS] = NULL, -}; - -void -sixrd_dpo_module_init (void) -{ - sixrd_dpo_type = dpo_register_new_type(&sd_vft, sixrd_nodes); -} diff --git a/plugins/sixrd-plugin/sixrd/sixrd_dpo.h b/plugins/sixrd-plugin/sixrd/sixrd_dpo.h deleted file mode 100644 index 17142288..00000000 --- a/plugins/sixrd-plugin/sixrd/sixrd_dpo.h +++ /dev/null @@ -1,61 +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 __SIXRD_DPO_H__ -#define __SIXRD_DPO_H__ - -#include -#include - -/** - * A representation of a 6RD DPO - */ -typedef struct sixrd_dpo_t -{ - /** - * The dat-plane protocol - */ - dpo_proto_t sd_proto; - - /** - * the SIXRD domain index - */ - u32 sd_domain; - - /** - * Number of locks/users of the label - */ - u16 sd_locks; -} sixrd_dpo_t; - -extern void sixrd_dpo_create (dpo_proto_t dproto, - u32 domain_index, - dpo_id_t *dpo); - -/* - * Encapsulation violation for fast data-path access - */ -extern sixrd_dpo_t *sixrd_dpo_pool; -extern dpo_type_t sixrd_dpo_type; - -static inline sixrd_dpo_t * -sixrd_dpo_get (index_t index) -{ - return (pool_elt_at_index(sixrd_dpo_pool, index)); -} - -extern void sixrd_dpo_module_init(void); - -#endif diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 00000000..e691a539 --- /dev/null +++ b/src/Makefile.am @@ -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. + +############################################################################### +# Global Defines +############################################################################### + +AUTOMAKE_OPTIONS = foreign subdir-objects +ACLOCAL_AMFLAGS = -I m4 + +AM_CFLAGS = -Wall + +SUBDIRS = . +SUFFIXES = .api.h .api .api.json +API_FILES = +noinst_HEADERS = +dist_bin_SCRIPTS = +lib_LTLIBRARIES = +BUILT_SOURCES = + +############################################################################### +# DPDK +############################################################################### + +if WITH_DPDK +if ENABLE_DPDK_SHARED +DPDK_LD_FLAGS = -Wl,--whole-archive,-ldpdk,--no-whole-archive +else +DPDK_LD_FLAGS = -Wl,--whole-archive,-l:libdpdk.a,--no-whole-archive +endif +if WITH_DPDK_CRYPTO +DPDK_LD_ADD = -L$(AESNI_MULTI_BUFFER_LIB_PATH) -lIPSec_MB +endif +if WITH_DPDK_MLX5_PMD +DPDK_LD_FLAGS += -libverbs -lmlx5 -lnuma +endif +else +DPDK_LD_FLAGS = +DPDK_LD_ADD = +endif + +############################################################################### +# Components +############################################################################### + +include vppinfra.am +include vppapigen.am + +if ENABLE_PERFTOOL +include perftool.am +endif + +if ENABLE_G2 +include g2.am +endif + +if ENABLE_SVM +include svm.am +endif + +if ENABLE_VLIB +include vlib.am +endif + +if ENABLE_SVM +if ENABLE_VLIB +include vlib-api.am +include vnet.am +include vpp.am +include vpp-api-test.am + +SUBDIRS += vpp-api/python plugins + +############################################################################### +# API +############################################################################### + +include suffix-rules.mk + +# Set the suffix list +apidir = $(prefix)/share/vpp/api/core + +api_DATA = \ + $(patsubst %.api,%.api.json,$(API_FILES)) + +BUILT_SOURCES += \ + $(patsubst %.api,%.api.json,$(API_FILES)) \ + $(patsubst %.api,%.api.h,$(API_FILES)) + +endif # if ENABLE_VLIB +endif # if ENABLE_SVM diff --git a/src/configure.ac b/src/configure.ac new file mode 100644 index 00000000..f8e4d94f --- /dev/null +++ b/src/configure.ac @@ -0,0 +1,195 @@ +AC_INIT([vpp], [17.04], [vpp-dev@fd.io]) +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_PROG_CC +AM_PROG_AS +AM_PROG_LIBTOOL +AC_PROG_YACC + +############################################################################### +# Macros +############################################################################### + +AC_DEFUN([ENABLE_ARG], +[ + AC_ARG_ENABLE($1, + AC_HELP_STRING(patsubst([--enable-$1],[_],[-]), $2), + [enable_$1=yes n_enable_$1=1], + [enable_$1=no n_enable_$1=0]) + AM_CONDITIONAL(m4_toupper(ENABLE_$1), test "$enable_$1" = "yes") + m4_append([list_of_enabled], [$1], [, ]) +]) + +AC_DEFUN([DISABLE_ARG], +[ + AC_ARG_ENABLE($1, + AC_HELP_STRING(patsubst([--disable-$1],[_],[-]), $2), + [enable_$1=no n_enable_$1=0], + [enable_$1=yes n_enable_$1=1]) + AM_CONDITIONAL(m4_toupper(ENABLE_$1), test "$enable_$1" = "yes") + m4_append([list_of_enabled], [$1], [, ]) +]) + +AC_DEFUN([WITH_ARG], +[ + AC_ARG_WITH($1, + AC_HELP_STRING(patsubst([--with-$1],[_],[-]), $2), + [with_$1=yes n_with_$1=1], + [with_$1=no n_with_$1=0]) + AM_CONDITIONAL(m4_toupper(WITH_$1), test "$with_$1" = "yes") + m4_append([list_of_with], [$1], [, ]) +]) + +AC_DEFUN([WITHOUT_ARG], +[ + AC_ARG_WITH($1, + AC_HELP_STRING(patsubst([--without-$1],[_],[-]), $2), + [with_$1=no n_with_$1=0], + [with_$1=yes n_with_$1=1]) + AM_CONDITIONAL(m4_toupper(WITH_$1), test "$with_$1" = "yes") + m4_append([list_of_with], [$1], [, ]) +]) + +AC_DEFUN([PLUGIN_ENABLED], +[ + AC_ARG_ENABLE($1_plugin, + AC_HELP_STRING([--disable-$1-plugin], [Do not build $1 plugin]), + [enable_$1_plugin=no], + [enable_$1_plugin=yes ]) + AM_CONDITIONAL(m4_toupper(ENABLE_$1_PLUGIN), test "$enable_$1_plugin" = "yes") + m4_append([list_of_plugins], [$1], [, ]) +]) + +AC_DEFUN([PLUGIN_DISABLED], +[ + AC_ARG_ENABLE($1_plugin, + AC_HELP_STRING([--enable-$1-plugin], [Build $1 plugin]), + [enable_$1_plugin=yes ], + [enable_$1_plugin=no]) + AM_CONDITIONAL(m4_toupper((ENABLE_$1_PLUGIN), test "$enable_$1_plugin" = "yes") + m4_append([list_of_plugins], [$1], [, ]) +]) + +AC_DEFUN([PRINT_VAL], [ AC_MSG_RESULT(AC_HELP_STRING($1,$2)) ]) + +############################################################################### +# configure arguments +############################################################################### + +# --enable-X +ENABLE_ARG(tests, [Enable unit tests]) +ENABLE_ARG(dpdk_shared, [Enable unit tests]) +ENABLE_ARG(perftool, [Enable perftool]) +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]) + +# --with-X +WITH_ARG(dpdk, [Use use DPDK]) +WITH_ARG(dpdk_crypto, [Use DPDK cryptodev]) +WITH_ARG(dpdk_mlx5_pmd, [Use DPDK with mlx5 PMD]) + +# --without-X +WITHOUT_ARG(ipsec, [Disable IPSec]) +WITHOUT_ARG(ipv6sr, [Disable IPv6 SR]) +WITHOUT_ARG(apicli, [Disable binary api CLI]) + +AC_ARG_WITH(unix, + AC_HELP_STRING([--with-unix],[Compile unix version of clib]), + [], + [case $host_os in + darwin* | linux*) with_unix=yes;; + *) with_unix=no;; + esac]) + +AM_CONDITIONAL(WITH_UNIX, test "$with_unix" = "yes") + +AC_ARG_WITH(pre-data, + AC_HELP_STRING([--with-pre-data],[Set buffer rewrite space]), + [case $with_pre_data in + 128) ;; + 256) ;; + *) with_pre_data="pre-data-not-set" ;; + esac], [with_pre_data=128]) + +############################################################################### +# Substitutions and defines +############################################################################### + +AC_SUBST(PRE_DATA_SIZE, [$with_pre_data]) +AC_SUBST(APICLI, [-DVPP_API_TEST_BUILTIN=${n_with_apicli}]) + +AC_DEFINE_UNQUOTED(DPDK, [${n_with_dpdk}]) +AC_DEFINE_UNQUOTED(DPDK_SHARED_LIB, [${n_enable_dpdk_shared}]) +AC_DEFINE_UNQUOTED(DPDK_CRYPTO, [${n_with_dpdk_crypto}]) +AC_DEFINE_UNQUOTED(IPSEC, [${n_with_ipsec}]) +AC_DEFINE_UNQUOTED(IPV6SR, [${n_with_ipv6sr}]) + +############################################################################### +# Dependency checks +############################################################################### + +AM_COND_IF([ENABLE_DPDK_SHARED], +[ + AC_CHECK_HEADERS([rte_config.h], + [], + [AC_MSG_ERROR([DPDK header files not found])],) + AC_CHECK_LIB( [dpdk], [rte_eal_init], + [], + [AC_MSG_ERROR([DPDK shared library not found])],) +]) + +AM_COND_IF([ENABLE_G2], +[ + PKG_CHECK_MODULES(g2, gtk+-2.0) +]) + +############################################################################### +# Plugins +############################################################################### + +PLUGIN_ENABLED(sixrd) +PLUGIN_ENABLED(ila) +PLUGIN_ENABLED(flowperpkt) + +############################################################################### +# Output +############################################################################### + +AC_OUTPUT + +AC_MSG_RESULT([==============================================================================]) +PRINT_VAL([version], $PACKAGE $VERSION) +PRINT_VAL([prefix], ${prefix}) +PRINT_VAL([libdir], ${libdir}) +PRINT_VAL([includedir], ${includedir}) +PRINT_VAL([CFLAGS], ${CFLAGS}) +PRINT_VAL([CPPFLAGS], ${CPPFLAGS}) +PRINT_VAL([LDFLAGS], ${LDFLAGS}) + +AC_MSG_RESULT([]) +AC_MSG_RESULT([with:]) +m4_foreach([x], m4_dquote(list_of_with), [ + AC_MSG_RESULT(AC_HELP_STRING(x, m4_join([], [${with_], x, [}]))) +]) + +AC_MSG_RESULT([]) +AC_MSG_RESULT([enabled:]) +m4_foreach([x], m4_dquote(list_of_enabled), [ + AC_MSG_RESULT(AC_HELP_STRING(x, m4_join([], [${enable_], x, [}]))) +]) + +AC_MSG_RESULT([]) +AC_MSG_RESULT([plugins:]) +m4_foreach([x], m4_dquote(list_of_plugins), [ + AC_MSG_RESULT(AC_HELP_STRING(x, m4_join([], [${enable_], x, [_plugin}]))) +]) +AC_MSG_RESULT([==============================================================================]) + + diff --git a/src/examples/vlib/dir.dox b/src/examples/vlib/dir.dox new file mode 100644 index 00000000..d3ac0ee4 --- /dev/null +++ b/src/examples/vlib/dir.dox @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Copyright (c) 2016 Comcast Cable Communications Management, LLC. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Doxygen directory documentation */ +/** +@dir +@brief Someone please fix this description +@todo This directory needs a description. +*/ diff --git a/src/examples/vlib/main_stub.c b/src/examples/vlib/main_stub.c new file mode 100644 index 00000000..4d74bd77 --- /dev/null +++ b/src/examples/vlib/main_stub.c @@ -0,0 +1,418 @@ +/* + * 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 + +int +main (int argc, char *argv[]) +{ + return vlib_unix_main (argc, argv); +} + +static clib_error_t * +main_stub_init (vlib_main_t * vm) +{ + clib_error_t *error; + + if ((error = + unix_physmem_init (vm, /* fail_if_physical_memory_not_present */ 0))) + return error; + + if ((error = vlib_call_init_function (vm, unix_cli_init))) + return error; + + return error; +} + +VLIB_INIT_FUNCTION (main_stub_init); + +#if 0 +/* Node test code. */ +typedef struct +{ + int scalar; + int vector[0]; +} my_frame_t; + +static u8 * +format_my_node_frame (u8 * s, va_list * va) +{ + vlib_frame_t *f = va_arg (*va, vlib_frame_t *); + my_frame_t *g = vlib_frame_args (f); + int i; + + s = format (s, "scalar %d, vector { ", g->scalar); + for (i = 0; i < f->n_vectors; i++) + s = format (s, "%d, ", g->vector[i]); + s = format (s, " }"); + + return s; +} + +static uword +my_func (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) +{ + vlib_node_t *node; + my_frame_t *y; + u32 i, n_left = 0; + static int serial; + int verbose; + + node = vlib_get_node (vm, rt->node_index); + + verbose = 0; + + if (verbose && f) + vlib_cli_output (vm, "%v: call frame %p %U", node->name, + f, format_my_node_frame, f); + + if (rt->n_next_nodes > 0) + { + vlib_frame_t *next = vlib_get_next_frame (vm, rt, /* next index */ 0); + n_left = VLIB_FRAME_SIZE - next->n_vectors; + y = vlib_frame_args (next); + y->scalar = serial++; + } + else + y = 0; + + for (i = 0; i < 5; i++) + { + if (y) + { + ASSERT (n_left > 0); + n_left--; + y->vector[i] = y->scalar + i; + } + } + if (y) + vlib_put_next_frame (vm, rt, /* next index */ 0, n_left); + + if (verbose) + vlib_cli_output (vm, "%v: return frame %p", node->name, f); + + return i; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (my_node1,static) = { + .function = my_func, + .type = VLIB_NODE_TYPE_INPUT, + .name = "my-node1", + .scalar_size = sizeof (my_frame_t), + .vector_size = STRUCT_SIZE_OF (my_frame_t, vector[0]), + .n_next_nodes = 1, + .next_nodes = { + [0] = "my-node2", + }, +}; +/* *INDENT-ON* */ + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (my_node2,static) = { + .function = my_func, + .name = "my-node2", + .scalar_size = sizeof (my_frame_t), + .vector_size = STRUCT_SIZE_OF (my_frame_t, vector[0]), +}; +/* *INDENT-ON* */ + +#endif + +#if 0 + +typedef enum +{ + MY_EVENT_TYPE1, + MY_EVENT_TYPE2, +} my_process_completion_type_t; + +typedef struct +{ + int a; + f64 b; +} my_process_event_data_t; + +static u8 * +format_my_process_event_data (u8 * s, va_list * va) +{ + my_process_event_data_t *d = va_arg (*va, my_process_event_data_t *); + return format (s, "{ a %d b %.6f}", d->a, d->b); +} + +static uword +my_proc (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) +{ + vlib_node_t *node; + u32 i; + + node = vlib_get_node (vm, rt->node_index); + + vlib_cli_output (vm, "%v: call frame %p", node->name, f); + + for (i = 0; i < 5; i++) + { + vlib_cli_output (vm, "%v: %d", node->name, i); + vlib_process_suspend (vm, 1e0 /* secs */ ); + } + + vlib_cli_output (vm, "%v: return frame %p", node->name, f); + + if (0) + { + uword n_events_seen, type, *data = 0; + + for (n_events_seen = 0; n_events_seen < 2;) + { + vlib_process_wait_for_event (vm); + type = vlib_process_get_events (vm, &data); + n_events_seen += vec_len (data); + vlib_cli_output (vm, "%U %v: completion #%d type %d data 0x%wx", + format_time_interval, "h:m:s:u", + vlib_time_now (vm), node->name, i, type, data[0]); + _vec_len (data) = 0; + } + + vec_free (data); + } + else + { + uword n_events_seen, i, type; + my_process_event_data_t *data; + for (n_events_seen = 0; n_events_seen < 2;) + { + vlib_process_wait_for_event (vm); + data = vlib_process_get_event_data (vm, &type); + vec_foreach_index (i, data) + { + vlib_cli_output (vm, "%U event type %d data %U", + format_time_interval, "h:m:s:u", + vlib_time_now (vm), type, + format_my_process_event_data, data); + } + n_events_seen += vec_len (data); + vlib_process_put_event_data (vm, data); + } + } + + return i; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (my_proc_node,static) = { + .function = my_proc, + .type = VLIB_NODE_TYPE_PROCESS, + .name = "my-proc", +}; +/* *INDENT-ON* */ + +static uword +my_proc_input (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) +{ + static int i; + + if (i++ < 2) + { + if (0) + vlib_process_signal_event (vm, my_proc_node.index, + i == 1 ? MY_EVENT_TYPE1 : MY_EVENT_TYPE2, + 0x12340000 + i); + else + { + my_process_event_data_t *d; + f64 dt = 5; + d = vlib_process_signal_event_at_time (vm, + i * dt, + my_proc_node.index, + i == + 1 ? MY_EVENT_TYPE1 : + MY_EVENT_TYPE2, + 1 /* elts */ , + sizeof (d[0])); + d->a = i; + d->b = vlib_time_now (vm); + } + } + else + vlib_node_set_state (vm, rt->node_index, VLIB_NODE_STATE_DISABLED); + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (my_proc_input_node,static) = { + .function = my_proc_input, + .type = VLIB_NODE_TYPE_INPUT, + .name = "my-proc-input", +}; +/* *INDENT-ON* */ + +static uword +_unformat_farith (unformat_input_t * i, va_list * args) +{ + u32 prec = va_arg (*args, u32); + f64 *result = va_arg (*args, f64 *); + f64 tmp[2]; + + /* Binary operations in from lowest to highest precedence. */ + char *binops[] = { + "+%U", "-%U", "/%U", "*%U", "^%U", + }; + + if (prec <= ARRAY_LEN (binops) - 1 + && unformat_user (i, _unformat_farith, prec + 1, &tmp[0])) + { + int p; + for (p = prec; p < ARRAY_LEN (binops); p++) + { + if (unformat (i, binops[p], _unformat_farith, prec + 0, &tmp[1])) + { + switch (binops[p][0]) + { + case '+': + result[0] = tmp[0] + tmp[1]; + break; + case '-': + result[0] = tmp[0] - tmp[1]; + break; + case '/': + result[0] = tmp[0] / tmp[1]; + break; + case '*': + result[0] = tmp[0] * tmp[1]; + break; + case '^': + result[0] = pow (tmp[0], tmp[1]); + break; + default: + abort (); + } + return 1; + } + } + result[0] = tmp[0]; + return 1; + } + + else if (unformat (i, "-%U", _unformat_farith, prec + 0, &tmp[0])) + { + result[0] = -tmp[0]; + return 1; + } + + else if (unformat (i, "(%U)", _unformat_farith, 0, &tmp[0])) + { + result[0] = tmp[0]; + return 1; + } + + else if (unformat (i, "%f", result)) + return 1; + + else + return 0; +} + +static uword +unformat_farith (unformat_input_t * i, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + f64 *result = va_arg (*args, f64 *); + return unformat_user (i, _unformat_farith, 0, result); +} + +static uword +unformat_integer (unformat_input_t * i, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + u32 *data = va_arg (*args, u32 *); + return unformat (i, "%d", data); +} + +static VLIB_CLI_PARSE_RULE (my_parse_rule1) = +{ +.name = "decimal_integer",.short_help = + "a decimal integer",.unformat_function = unformat_integer,.data_size = + sizeof (u32),}; + +static VLIB_CLI_PARSE_RULE (my_parse_rule2) = +{ +.name = "float_expression",.short_help = + "floating point expression",.unformat_function = + unformat_farith,.data_size = sizeof (f64),}; + +static clib_error_t * +bar_command (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + switch (cmd->function_arg) + { + case 2: + { + u32 *d, *e; + d = vlib_cli_get_parse_rule_result (vm, 0); + e = vlib_cli_get_parse_rule_result (vm, 1); + vlib_cli_output (vm, "bar2 %d %d", d[0], e[0]); + break; + } + + case 1: + { + u32 *d = vlib_cli_get_parse_rule_result (vm, 0); + vlib_cli_output (vm, "bar1 %d", d[0]); + break; + } + + case 3: + { + f64 *d = vlib_cli_get_parse_rule_result (vm, 0); + vlib_cli_output (vm, "expr %.6f", d[0]); + } + } + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (bar_command2, static) = { + .path = "bar %decimal_integer", + .short_help = "bar1 command", + .function = bar_command, + .function_arg = 1, +}; +VLIB_CLI_COMMAND (bar_command1, static) = { + .path = "bar %decimal_integer %decimal_integer", + .short_help = "bar2 command", + .function = bar_command, + .function_arg = 2, +}; +VLIB_CLI_COMMAND (bar_command3, static) = { + .path = "zap %float_expression", + .short_help = "bar3 command", + .function = bar_command, + .function_arg = 3, +}; +/* *INDENT-ON* */ + +#endif + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/examples/vlib/mc_test.c b/src/examples/vlib/mc_test.c new file mode 100644 index 00000000..e84a713c --- /dev/null +++ b/src/examples/vlib/mc_test.c @@ -0,0 +1,384 @@ +/* + * mc_test.c: test program for vlib mc + * + * Copyright (c) 2010 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +typedef struct +{ + u32 min_n_msg_bytes; + u32 max_n_msg_bytes; + u32 tx_serial; + u32 rx_serial; + u32 seed; + u32 verbose; + u32 validate; + u32 window_size; + f64 min_delay, max_delay; + f64 n_packets_to_send; +} mc_test_main_t; + +always_inline u32 +choose_msg_size (mc_test_main_t * tm) +{ + u32 r = tm->min_n_msg_bytes; + if (tm->max_n_msg_bytes > tm->min_n_msg_bytes) + r += + random_u32 (&tm->seed) % (1 + tm->max_n_msg_bytes - + tm->min_n_msg_bytes); + return r; +} + +static mc_test_main_t mc_test_main; + +static void +serialize_test_msg (serialize_main_t * m, va_list * va) +{ + mc_test_main_t *tm = &mc_test_main; + u32 n_bytes = choose_msg_size (tm); + u8 *msg; + int i; + serialize_integer (m, n_bytes, sizeof (n_bytes)); + msg = serialize_get (m, n_bytes); + for (i = 0; i < n_bytes; i++) + msg[i] = i + tm->tx_serial; + tm->tx_serial += n_bytes; +} + +static void +unserialize_test_msg (serialize_main_t * m, va_list * va) +{ + mc_test_main_t *tm = &mc_test_main; + u32 i, n_bytes, dump_msg = tm->verbose; + u8 *p; + unserialize_integer (m, &n_bytes, sizeof (n_bytes)); + p = unserialize_get (m, n_bytes); + if (tm->validate) + for (i = 0; i < n_bytes; i++) + if (p[i] != ((tm->rx_serial + i) & 0xff)) + { + clib_warning ("corrupt msg at offset %d", i); + dump_msg = 1; + break; + } + if (dump_msg) + clib_warning ("got %d bytes, %U", n_bytes, format_hex_bytes, p, n_bytes); + tm->rx_serial += n_bytes; +} + +MC_SERIALIZE_MSG (test_msg, static) = +{ +.name = "test_msg",.serialize = serialize_test_msg,.unserialize = + unserialize_test_msg,}; + +#define SERIALIZE 1 + +#define EVENT_JOIN_STREAM 10 +#define EVENT_SEND_DATA 11 + +static void +test_rx_callback (mc_main_t * mcm, + mc_stream_t * stream, + mc_peer_id_t peer_id, u32 buffer_index) +{ + if (SERIALIZE) + { + return mc_unserialize (mcm, stream, buffer_index); + } + else + { +#if DEBUG > 1 + vlib_main_t *vm = mcm->vlib_main; + vlib_buffer_t *b = vlib_get_buffer (vm, buffer_index); + u8 *dp = vlib_buffer_get_current (b); + + fformat (stdout, "RX from %U %U\n", + stream->transport->format_peer_id, peer_id, + format_hex_bytes, dp, tm->n_msg_bytes); + +#endif + } +} + +static u8 * +test_snapshot_callback (mc_main_t * mcm, + u8 * data_vector, u32 last_global_sequence_processed) +{ + if (SERIALIZE) + { + serialize_main_t m; + + /* Append serialized data to data vector. */ + serialize_open_vector (&m, data_vector); + m.stream.current_buffer_index = vec_len (data_vector); + + return serialize_close_vector (&m); + } + else + return format (data_vector, + "snapshot, last global seq 0x%x", + last_global_sequence_processed); +} + +static void +test_handle_snapshot_callback (mc_main_t * mcm, u8 * data, u32 n_data_bytes) +{ + if (SERIALIZE) + { + serialize_main_t s; + unserialize_open_data (&s, data, n_data_bytes); + } + else + clib_warning ("snapshot `%*s'", n_data_bytes, data); +} + +static mc_socket_main_t mc_socket_main; + +static uword +mc_test_process (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * f) +{ + mc_test_main_t *tm = &mc_test_main; + mc_socket_main_t *msm = &mc_socket_main; + mc_main_t *mcm = &msm->mc_main; + uword event_type, *event_data = 0; + u32 data_serial = 0, stream_index; + f64 delay; + mc_stream_config_t config; + clib_error_t *error; + int i; + char *intfcs[] = { "eth1", "eth0", "ce" }; + + memset (&config, 0, sizeof (config)); + config.name = "test"; + config.window_size = tm->window_size; + config.rx_buffer = test_rx_callback; + config.catchup_snapshot = test_snapshot_callback; + config.catchup = test_handle_snapshot_callback; + stream_index = ~0; + + msm->multicast_tx_ip4_address_host_byte_order = 0xefff0100; + msm->base_multicast_udp_port_host_byte_order = 0xffab; + + error = mc_socket_main_init (&mc_socket_main, intfcs, ARRAY_LEN (intfcs)); + if (error) + { + clib_error_report (error); + exit (1); + } + + mcm->we_can_be_relay_master = 1; + + while (1) + { + vlib_process_wait_for_event (vm); + event_type = vlib_process_get_events (vm, &event_data); + + switch (event_type) + { + case EVENT_JOIN_STREAM: + stream_index = mc_stream_join (mcm, &config); + break; + + case EVENT_SEND_DATA: + { + f64 times[2]; + + if (stream_index == ~0) + stream_index = mc_stream_join (mcm, &config); + + times[0] = vlib_time_now (vm); + for (i = 0; i < event_data[0]; i++) + { + u32 bi; + if (SERIALIZE) + { + mc_serialize_stream (mcm, stream_index, &test_msg, + data_serial); + } + else + { + u8 *mp; + mp = mc_get_vlib_buffer (vm, sizeof (mp[0]), &bi); + mp[0] = data_serial; + mc_stream_send (mcm, stream_index, bi); + } + if (tm->min_delay > 0) + { + delay = + tm->min_delay + + random_f64 (&tm->seed) * (tm->max_delay - + tm->min_delay); + vlib_process_suspend (vm, delay); + } + data_serial++; + } + times[1] = vlib_time_now (vm); + clib_warning ("done sending %d; %.4e per sec", + event_data[0], + (f64) event_data[0] / (times[1] - times[0])); + break; + } + + default: + clib_warning ("bug"); + break; + } + + if (event_data) + _vec_len (event_data) = 0; + } +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (mc_test_process_node, static) = +{ +.function = mc_test_process,.type = VLIB_NODE_TYPE_PROCESS,.name = + "mc-test-process",}; +/* *INDENT-ON* */ + +static clib_error_t * +mc_test_command (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + f64 npkts = 10; + + if (unformat (input, "join")) + { + vlib_cli_output (vm, "Join stream...\n"); + vlib_process_signal_event (vm, mc_test_process_node.index, + EVENT_JOIN_STREAM, 0); + return 0; + } + else if (unformat (input, "send %f", &npkts) || unformat (input, "send")) + { + vlib_process_signal_event (vm, mc_test_process_node.index, + EVENT_SEND_DATA, (uword) npkts); + vlib_cli_output (vm, "Send %.0f pkts...\n", npkts); + + return 0; + } + else + return unformat_parse_error (input); +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (test_mc_command, static) = +{ +.path = "test mc",.short_help = "Test mc command",.function = + mc_test_command,}; +/* *INDENT-ON* */ + +static clib_error_t * +mc_show_command (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + mc_main_t *mcm = &mc_socket_main.mc_main; + vlib_cli_output (vm, "%U", format_mc_main, mcm); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_mc_command, static) = +{ +.path = "show mc",.short_help = "Show mc command",.function = + mc_show_command,}; +/* *INDENT-ON* */ + +static clib_error_t * +mc_clear_command (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + mc_main_t *mcm = &mc_socket_main.mc_main; + mc_clear_stream_stats (mcm); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (clear_mc_command, static) = +{ +.path = "clear mc",.short_help = "Clear mc command",.function = + mc_clear_command,}; +/* *INDENT-ON* */ + +static clib_error_t * +mc_config (vlib_main_t * vm, unformat_input_t * input) +{ + mc_test_main_t *tm = &mc_test_main; + mc_socket_main_t *msm = &mc_socket_main; + clib_error_t *error = 0; + + tm->min_n_msg_bytes = 4; + tm->max_n_msg_bytes = 4; + tm->window_size = 8; + tm->seed = getpid (); + tm->verbose = 0; + tm->validate = 1; + tm->min_delay = 10e-6; + tm->max_delay = 10e-3; + tm->n_packets_to_send = 0; + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "interface %s", &msm->multicast_interface_name)) + ; + + else if (unformat (input, "n-bytes %d", &tm->max_n_msg_bytes)) + tm->min_n_msg_bytes = tm->max_n_msg_bytes; + else if (unformat (input, "max-n-bytes %d", &tm->max_n_msg_bytes)) + ; + else if (unformat (input, "min-n-bytes %d", &tm->min_n_msg_bytes)) + ; + else if (unformat (input, "seed %d", &tm->seed)) + ; + else if (unformat (input, "window %d", &tm->window_size)) + ; + else if (unformat (input, "verbose")) + tm->verbose = 1; + else if (unformat (input, "no-validate")) + tm->validate = 0; + else if (unformat (input, "min-delay %f", &tm->min_delay)) + ; + else if (unformat (input, "max-delay %f", &tm->max_delay)) + ; + else if (unformat (input, "no-delay")) + tm->min_delay = tm->max_delay = 0; + else if (unformat (input, "n-packets %f", &tm->n_packets_to_send)) + ; + + else + return clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); + } + + if (tm->n_packets_to_send > 0) + vlib_process_signal_event (vm, mc_test_process_node.index, + EVENT_SEND_DATA, + (uword) tm->n_packets_to_send); + + return error; +} + +VLIB_CONFIG_FUNCTION (mc_config, "mc"); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/examples/vlib/plex_test.c b/src/examples/vlib/plex_test.c new file mode 100644 index 00000000..ce0c8ef1 --- /dev/null +++ b/src/examples/vlib/plex_test.c @@ -0,0 +1,527 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include + +static u8 * +format_value_v4_address (u8 * s, va_list * args) +{ + vlib_parse_value_t *v = va_arg (*args, vlib_parse_value_t *); + u32 a = v->value.as_uword; + + s = format (s, "%d.%d.%d.%d", + (a >> 24) & 0xFF, + (a >> 16) & 0xFF, (a >> 8) & 0xFF, (a >> 0) & 0xFF); + + return s; +} + +static vlib_parse_match_t +v4_address_match (vlib_parse_main_t * pm, vlib_parse_type_t * type, + vlib_lex_token_t * t, vlib_parse_value_t * valuep) +{ + u32 digit; + u32 value = 0; + int i; + + if (vec_len (pm->tokens) - (t - pm->tokens) < 7) + return VLIB_PARSE_MATCH_FAIL; + + /* NUMBER DOT NUMBER DOT NUMBER DOT NUMBER */ + + for (i = 0; i < 7; i++) + { + if ((i & 1) == 0) + { + if (t[i].token != VLIB_LEX_number) + return VLIB_PARSE_MATCH_FAIL; + if (t[i].value.as_uword > 0xff) + return VLIB_PARSE_MATCH_FAIL; + digit = t[i].value.as_uword; + value = (value << 8) | digit; + } + else + { + if (t[i].token != VLIB_LEX_dot) + return VLIB_PARSE_MATCH_FAIL; + } + } + /* note: caller advances by 1 */ + pm->current_token_index += 6; + valuep->value.as_uword = value; + return VLIB_PARSE_MATCH_VALUE; +} + +PARSE_TYPE_INIT (v4_address, v4_address_match, 0, format_value_v4_address) + static u8 *format_value_v4_address_and_mask (u8 * s, va_list * args) +{ + vlib_parse_value_t *v = va_arg (*args, vlib_parse_value_t *); + u32 *a = v->value.as_pointer; + + s = format (s, "%d.%d.%d.%d", + (a[0] >> 24) & 0xFF, + (a[0] >> 16) & 0xFF, (a[0] >> 8) & 0xFF, (a[0] >> 0) & 0xFF); + s = format (s, "/%d", a[1]); + + return s; +} + +static vlib_parse_match_t +v4_address_and_mask_match (vlib_parse_main_t * pm, vlib_parse_type_t * type, + vlib_lex_token_t * t, vlib_parse_value_t * valuep) +{ + u32 digit; + u32 address = 0; + u32 *rv = 0; + int i; + + if (vec_len (pm->tokens) - (t - pm->tokens) < 9) + return VLIB_PARSE_MATCH_FAIL; + + /* NUMBER DOT NUMBER DOT NUMBER DOT NUMBER */ + + for (i = 0; i < 7; i++) + { + if ((i & 1) == 0) + { + if (t[i].token != VLIB_LEX_number) + return VLIB_PARSE_MATCH_FAIL; + if (t[i].value.as_uword > 0xff) + return VLIB_PARSE_MATCH_FAIL; + digit = t[i].value.as_uword; + address = (address << 8) | digit; + } + else + { + if (t[i].token != VLIB_LEX_dot) + return VLIB_PARSE_MATCH_FAIL; + } + } + + if (t[7].token != VLIB_LEX_slash || t[8].token != VLIB_LEX_number) + return VLIB_PARSE_MATCH_FAIL; + + vec_add1 (rv, address); + vec_add1 (rv, t[8].value.as_uword); + + /* note: caller advances by 1 */ + pm->current_token_index += 8; + valuep->value.as_pointer = rv; + return VLIB_PARSE_MATCH_VALUE; +} + +void +v4_address_and_mask_cleanup (vlib_parse_value_t * valuep) +{ + u32 *trash = valuep->value.as_pointer; + vec_free (trash); +} + +PARSE_TYPE_INIT (v4_address_and_mask, v4_address_and_mask_match, + v4_address_and_mask_cleanup, + format_value_v4_address_and_mask) + vlib_lex_main_t vlib_lex_main; + + + + vlib_parse_match_t eval_factor0 (vlib_parse_main_t * pm, + vlib_parse_item_t * item, + vlib_parse_value_t * value) +{ + clib_warning ("%U", format_vlib_parse_value, pm); + return VLIB_PARSE_MATCH_RULE; +} + +vlib_parse_match_t +eval_factor1 (vlib_parse_main_t * pm, + vlib_parse_item_t * item, vlib_parse_value_t * value) +{ + clib_warning ("%U", format_vlib_parse_value, pm); + return VLIB_PARSE_MATCH_RULE; +} + +vlib_parse_match_t +eval_factor2 (vlib_parse_main_t * pm, + vlib_parse_item_t * item, vlib_parse_value_t * value) +{ + word a; + int index = vec_len (pm->parse_value) - 1; + + a = pm->parse_value[index].value.as_word; + + pm->parse_value[index].value.as_word = -a; + return VLIB_PARSE_MATCH_RULE; +} + +vlib_parse_match_t +eval_term0 (vlib_parse_main_t * pm, + vlib_parse_item_t * item, vlib_parse_value_t * value) +{ + clib_warning ("%U", format_vlib_parse_value, pm); + return VLIB_PARSE_MATCH_RULE; +} + +vlib_parse_match_t +eval_term1 (vlib_parse_main_t * pm, + vlib_parse_item_t * item, vlib_parse_value_t * value) +{ + uword a, b; + int index = vec_len (pm->parse_value) - 2; + + a = pm->parse_value[index].value.as_uword; + b = pm->parse_value[index + 1].value.as_uword; + + pm->parse_value[index].value.as_uword = a * b; + _vec_len (pm->parse_value) -= 1; + clib_warning ("%U", format_vlib_parse_value, pm); + + return VLIB_PARSE_MATCH_RULE; +} + +vlib_parse_match_t +eval_term2 (vlib_parse_main_t * pm, + vlib_parse_item_t * item, vlib_parse_value_t * value) +{ + uword a, b; + int index = vec_len (pm->parse_value) - 2; + + a = pm->parse_value[index].value.as_uword; + b = pm->parse_value[index + 1].value.as_uword; + + pm->parse_value[index].value.as_uword = a / b; + _vec_len (pm->parse_value) -= 1; + clib_warning ("%U", format_vlib_parse_value, pm); + + return VLIB_PARSE_MATCH_RULE; +} + +vlib_parse_match_t +eval_exp0 (vlib_parse_main_t * pm, + vlib_parse_item_t * item, vlib_parse_value_t * value) +{ + return VLIB_PARSE_MATCH_RULE; +} + +vlib_parse_match_t +eval_exp1 (vlib_parse_main_t * pm, + vlib_parse_item_t * item, vlib_parse_value_t * value) +{ + uword a, b; + int index = vec_len (pm->parse_value) - 2; + + a = pm->parse_value[index].value.as_uword; + b = pm->parse_value[index + 1].value.as_uword; + + pm->parse_value[index].value.as_uword = a + b; + _vec_len (pm->parse_value) -= 1; + clib_warning ("%U", format_vlib_parse_value, pm); + + return VLIB_PARSE_MATCH_RULE; +} + +vlib_parse_match_t +eval_exp2 (vlib_parse_main_t * pm, + vlib_parse_item_t * item, vlib_parse_value_t * value) +{ + uword a, b; + int index = vec_len (pm->parse_value) - 2; + + a = pm->parse_value[index].value.as_uword; + b = pm->parse_value[index + 1].value.as_uword; + + pm->parse_value[index].value.as_uword = a - b; + _vec_len (pm->parse_value) -= 1; + clib_warning ("%U", format_vlib_parse_value, pm); + + return VLIB_PARSE_MATCH_RULE; +} + +vlib_parse_match_t +eval_result (vlib_parse_main_t * pm, + vlib_parse_item_t * item, vlib_parse_value_t * value) +{ + clib_warning ("%U", format_vlib_parse_value, pm); + return VLIB_PARSE_MATCH_DONE; +} + +vlib_parse_match_t +noop_match_rule (vlib_parse_main_t * pm, + vlib_parse_item_t * item, vlib_parse_value_t * value) +{ + clib_warning ("%U", format_vlib_parse_value, pm); + return VLIB_PARSE_MATCH_RULE; +} + +#if 0 +PARSE_INIT (t1, "moo", eval0); +PARSE_INIT (t2, "moo cow mumble", eval1); +PARSE_INIT (t3, "moo cow", eval2); +PARSE_INIT (t4, "moo cow mumble grunch", eval3); +#endif + +#if 0 +PARSE_INIT (r1, "eval ", eval_result); + +PARSE_INIT (r2, " = ", eval_exp0); +PARSE_INIT (r3, " = ", eval_exp1); +PARSE_INIT (r4, " = ", eval_exp2); +PARSE_INIT (r5, " = ", noop_match_rule); +PARSE_TYPE_INIT (exp, rule_match, 0, 0); +PARSE_TYPE_INIT (exp2, rule_match, 0, 0); + +PARSE_INIT (r6, " = ", eval_term0); +PARSE_INIT (r7, " = ", eval_term1); +PARSE_INIT (r8, " = ", eval_term2); +PARSE_INIT (r9, " = ", noop_match_rule); +PARSE_TYPE_INIT (term, rule_match, 0, 0); +PARSE_TYPE_INIT (term2, rule_match, 0, 0); + +PARSE_INIT (r11, " = ", eval_factor1); +PARSE_INIT (r10, " = ", eval_factor0); +PARSE_INIT (r12, " = ", eval_factor2); + +PARSE_TYPE_INIT (factor, rule_match, 0, 0); +#endif + +PARSE_INIT (r1, "eval ", eval_result); + +#if 1 +PARSE_INIT (r2, " = ", eval_exp0); +PARSE_INIT (r3, " = ", eval_exp1); +PARSE_INIT (r4, " = ", eval_exp2); +PARSE_INIT (r5, " = ", noop_match_rule); +PARSE_TYPE_INIT (exp, rule_match, 0, 0); +PARSE_TYPE_INIT (exp2, rule_match, 0, 0); + +PARSE_INIT (r6, " = ", eval_term0); +PARSE_INIT (r7, " = ", eval_term1); +PARSE_INIT (r8, " = ", eval_term2); +PARSE_INIT (r9, " = ", noop_match_rule); +PARSE_TYPE_INIT (term, rule_match, 0, 0); +PARSE_TYPE_INIT (term2, rule_match, 0, 0); + +PARSE_INIT (r11, " = ", eval_factor1); +PARSE_INIT (r10, " = ", eval_factor0); +PARSE_INIT (r12, " = ", eval_factor2); + +PARSE_TYPE_INIT (factor, rule_match, 0, 0); +#endif + +#if 0 +PARSE_TYPE_INIT (exp, rule_match, 0, 0); +PARSE_INIT (r6, " = a b", eval_term0); +PARSE_INIT (r7, " = c d", eval_term1); +PARSE_INIT (r9, " = ", noop_match_rule); +#endif + +#if 0 +#define foreach_rule_evaluator \ +_(0) \ +_(1) \ +_(2) \ +_(3) + +#define _(n) \ +vlib_parse_match_t eval##n (vlib_parse_main_t *pm, \ + vlib_parse_item_t *item, \ + vlib_parse_value_t *value) \ +{ \ + clib_warning ("%U", format_vlib_parse_value, pm); \ + return VLIB_PARSE_MATCH_DONE; \ +} +foreach_rule_evaluator +#undef _ +PARSE_INIT (r1, "eval ", eval_result); + +PARSE_INIT (r2, " = cow", eval0); +PARSE_INIT (r4, " = ", eval1); +PARSE_TYPE_INIT (moo, rule_match, 0, 0); +#endif + + +clib_error_t * +test_init (vlib_main_t * vm) +{ + clib_error_t *error; + + if ((error = vlib_call_init_function (vm, parse_init))) + return error; + + return 0; +} + +VLIB_INIT_FUNCTION (test_init); + +clib_error_t * +vlib_stdlex_init (vlib_main_t * vm) +{ + vlib_lex_main_t *lm = &vlib_lex_main; + u16 top_index; + u16 slash_index, slash_star_index, slash_slash_index, slash_star_star_index; + u16 slash_token; + u16 word_index; + u16 zero_index, octal_index, decimal_index, hex_index, binary_index; + + top_index = vlib_lex_add_table ("top"); + +#define foreach_top_level_single_character_token \ + _('(', lpar) \ + _(')', rpar) \ + _(';', semi) \ + _('[', lbrack) \ + _(']', rbrack) \ + _('{', lcurly) \ + _('}', rcurly) \ + _('+', plus) \ + _('-', minus) \ + _('*', star) \ + _('%', percent) \ + _('@', atsign) \ + _(',', comma) \ + _('.', dot) \ + _('?', qmark) + +#define _(c,t) \ + vlib_lex_set_action_range(top_index,c,c,VLIB_LEX_RETURN,vlib_lex_add_token(lm, #t), top_index); + foreach_top_level_single_character_token; +#undef _ + + /* Numbers */ + zero_index = vlib_lex_add_table ("zero"); + octal_index = vlib_lex_add_table ("octal"); + decimal_index = vlib_lex_add_table ("decimal"); + hex_index = vlib_lex_add_table ("hex"); + binary_index = vlib_lex_add_table ("binary"); + + /* Support 0x 0b 0t and 0123 [octal] */ + vlib_lex_set_action_range (top_index, '0', '0', VLIB_LEX_START_NUMBER, 10, + zero_index); + vlib_lex_set_action_range (top_index, '1', '9', VLIB_LEX_START_NUMBER, 10, + decimal_index); + + vlib_lex_set_action_range (zero_index, 0, 0x7F, VLIB_LEX_RETURN_AND_RESCAN, + VLIB_LEX_number, top_index); + + vlib_lex_set_action_range (zero_index, 'x', 'x', VLIB_LEX_IGNORE, ~0, + hex_index); + vlib_lex_set_action_range (zero_index, 'b', 'b', VLIB_LEX_IGNORE, ~0, + binary_index); + vlib_lex_set_action_range (zero_index, 't', 't', VLIB_LEX_IGNORE, ~0, + decimal_index); + vlib_lex_set_action_range (zero_index, '0', '7', VLIB_LEX_START_NUMBER, 8, + octal_index); + + /* Octal */ + vlib_lex_set_action_range (octal_index, 0, 0x7f, VLIB_LEX_RETURN_AND_RESCAN, + VLIB_LEX_number, top_index); + vlib_lex_set_action_range (octal_index, '0', '7', VLIB_LEX_ADD_TO_NUMBER, 8, + octal_index); + + /* Decimal */ + vlib_lex_set_action_range (decimal_index, 0, 0x7f, + VLIB_LEX_RETURN_AND_RESCAN, VLIB_LEX_number, + top_index); + vlib_lex_set_action_range (decimal_index, '0', '9', VLIB_LEX_ADD_TO_NUMBER, + 10, decimal_index); + + /* Hex */ + vlib_lex_set_action_range (hex_index, 0, 0x7f, VLIB_LEX_RETURN_AND_RESCAN, + VLIB_LEX_number, top_index); + vlib_lex_set_action_range (hex_index, '0', '9', VLIB_LEX_ADD_TO_NUMBER, 16, + hex_index); + vlib_lex_set_action_range (hex_index, 'a', 'f', VLIB_LEX_ADD_TO_NUMBER, 16, + hex_index); + vlib_lex_set_action_range (hex_index, 'A', 'F', VLIB_LEX_ADD_TO_NUMBER, 16, + hex_index); + + /* Binary */ + vlib_lex_set_action_range (binary_index, 0, 0x7f, + VLIB_LEX_RETURN_AND_RESCAN, VLIB_LEX_number, + top_index); + vlib_lex_set_action_range (binary_index, '0', '1', VLIB_LEX_ADD_TO_NUMBER, + 2, binary_index); + + /* c/c++ comment syntax is the worst... */ + + slash_index = vlib_lex_add_table ("slash"); + slash_star_index = vlib_lex_add_table ("slash_star"); + slash_star_star_index = vlib_lex_add_table ("slash_star_star"); + slash_slash_index = vlib_lex_add_table ("slash_slash"); + slash_token = vlib_lex_add_token (lm, "slash"); + + /* Top level: see a slash, ignore, go to slash table */ + vlib_lex_set_action_range (top_index, '/', '/', VLIB_LEX_IGNORE, ~0, + slash_index); + + /* default for slash table: return SLASH, go to top table */ + vlib_lex_set_action_range (slash_index, 1, 0x7F, VLIB_LEX_RETURN_AND_RESCAN, + slash_token, top_index); + /* see slash-slash, go to s-s table */ + vlib_lex_set_action_range (slash_index, '/', '/', VLIB_LEX_IGNORE, ~0, + slash_slash_index); + /* see slash-star, go to s-* table */ + vlib_lex_set_action_range (slash_index, '*', '*', VLIB_LEX_IGNORE, ~0, + slash_star_index); + + /* EOL in s-s table, ignore, go to top table */ + vlib_lex_set_action_range (slash_slash_index, '\n', '\n', VLIB_LEX_IGNORE, + ~0, top_index); + + /* slash-star blah blah star */ + vlib_lex_set_action_range (slash_star_index, '*', '*', VLIB_LEX_IGNORE, ~0, + slash_star_star_index); + + /* slash star blah blah star slash */ + vlib_lex_set_action_range (slash_star_star_index, '/', '/', VLIB_LEX_IGNORE, + ~0, top_index); + + /* LT, =, GT */ + vlib_lex_set_action_range (top_index, '<', '<', VLIB_LEX_RETURN, + VLIB_LEX_lt, top_index); + vlib_lex_set_action_range (top_index, '=', '=', VLIB_LEX_RETURN, + VLIB_LEX_equals, top_index); + vlib_lex_set_action_range (top_index, '>', '>', VLIB_LEX_RETURN, + VLIB_LEX_gt, top_index); + + /* words, key and otherwise */ + word_index = vlib_lex_add_table ("word"); + + vlib_lex_set_action_range (top_index, 'a', 'z', VLIB_LEX_ADD_TO_TOKEN, ~0, + word_index); + vlib_lex_set_action_range (top_index, 'A', 'Z', VLIB_LEX_ADD_TO_TOKEN, ~0, + word_index); + + vlib_lex_set_action_range (word_index, 0, 0x7f, VLIB_LEX_KEYWORD_CHECK, ~0, + top_index); + + vlib_lex_set_action_range (word_index, 'a', 'z', VLIB_LEX_ADD_TO_TOKEN, ~0, + word_index); + vlib_lex_set_action_range (word_index, 'A', 'Z', VLIB_LEX_ADD_TO_TOKEN, ~0, + word_index); + vlib_lex_set_action_range (word_index, '_', '_', VLIB_LEX_ADD_TO_TOKEN, ~0, + word_index); + vlib_lex_set_action_range (word_index, '0', '9', VLIB_LEX_ADD_TO_TOKEN, ~0, + word_index); + + return 0; +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/g2.am b/src/g2.am new file mode 100644 index 00000000..e7965733 --- /dev/null +++ b/src/g2.am @@ -0,0 +1,32 @@ +# Copyright (c) 2016 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +bin_PROGRAMS += g2 + +g2_SOURCES = \ + tools/g2/clib.c \ + tools/g2/cpel.c \ + tools/g2/cpel.h \ + tools/g2/events.c \ + tools/g2/g2.h \ + tools/g2/main.c \ + tools/g2/menu1.c \ + tools/g2/pointsel.c \ + tools/g2/props.c \ + tools/g2/props.h \ + tools/g2/g2version.c \ + tools/g2/view1.c + +g2_LDADD = $(g2_LIBS) libvppinfra.la -lpthread -lm + +# vi:syntax=automake diff --git a/src/perftool.am b/src/perftool.am new file mode 100644 index 00000000..09f1681a --- /dev/null +++ b/src/perftool.am @@ -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. + +bin_PROGRAMS += c2cpel cpelatency cpeldump cpelinreg cpelstate + +lib_LTLIBRARIES += libcperf.la + +libcperf_la_SOURCES = \ + tools/perftool/delsvec.c \ + tools/perftool/linreg.c \ + tools/perftool/props.c \ + tools/perftool/cpel_util.c + +PERFTOOL_LIBS = libcperf.la libvppinfra.la -lm + +c2cpel_SOURCES = tools/perftool/c2cpel.c +c2cpel_LDADD = $(PERFTOOL_LIBS) + +cpelatency_SOURCES = tools/perftool/cpelatency.c +cpelatency_LDADD = $(PERFTOOL_LIBS) + +cpeldump_SOURCES = tools/perftool/cpeldump.c +cpeldump_LDADD = $(PERFTOOL_LIBS) + +cpelinreg_SOURCES = tools/perftool/cpelinreg.c +cpelinreg_LDADD = $(PERFTOOL_LIBS) + +cpelstate_SOURCES = tools/perftool/cpelstate.c +cpelstate_LDADD = $(PERFTOOL_LIBS) + +# vi:syntax=automake diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am new file mode 100644 index 00000000..ffc4b3ab --- /dev/null +++ b/src/plugins/Makefile.am @@ -0,0 +1,60 @@ + +# 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 -I${top_srcdir} -I${top_builddir} +AM_LDFLAGS = -module -shared -avoid-version +SUFFIXES = .api.h .api .api.json +API_FILES = +BUILT_SOURCES = +vppplugins_LTLIBRARIES = +vppapitestplugins_LTLIBRARIES = +noinst_HEADERS = + +vppapitestpluginsdir = ${libdir}/vpp_api_test_plugins +vpppluginsdir = ${libdir}/vpp_plugins + +if ENABLE_FLOWPERPKT_PLUGIN +include flowperpkt.am +endif + +if ENABLE_ILA_PLUGIN +include ila.am +endif + +if ENABLE_SIXRD_PLUGIN +include sixrd.am +endif + +include ../suffix-rules.mk + +# Remove *.la files +install-data-hook: + @-(cd $(vpppluginsdir) && $(RM) $(vppplugins_LTLIBRARIES)) + @-(cd $(vppapitestpluginsdir) && $(RM) $(vppapitestplugins_LTLIBRARIES)) + +############################################################################### +# API +############################################################################### + +apidir = $(prefix)/share/vpp/api/plugins + +api_DATA = \ + $(patsubst %.api,%.api.json,$(API_FILES)) + +BUILT_SOURCES += \ + $(patsubst %.api,%.api.json,$(API_FILES)) \ + $(patsubst %.api,%.api.h,$(API_FILES)) + diff --git a/src/plugins/flowperpkt.am b/src/plugins/flowperpkt.am new file mode 100644 index 00000000..a400603a --- /dev/null +++ b/src/plugins/flowperpkt.am @@ -0,0 +1,38 @@ + +# 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 += flowperpkt_plugin.la +vppapitestplugins_LTLIBRARIES += flowperpkt_test_plugin.la + +flowperpkt_plugin_la_SOURCES = flowperpkt/flowperpkt.c \ + flowperpkt/l2_node.c \ + flowperpkt/node.c \ + flowperpkt/flowperpkt_plugin.api.h + +BUILT_SOURCES += \ + flowperpkt/flowperpkt.api.h \ + flowperpkt/flowperpkt.api.json + +noinst_HEADERS += \ + flowperpkt/flowperpkt_all_api_h.h \ + flowperpkt/flowperpkt_msg_enum.h \ + flowperpkt/flowperpkt.api.h + +flowperpkt_test_plugin_la_SOURCES = \ + flowperpkt/flowperpkt_test.c \ + flowperpkt/flowperpkt_plugin.api.h + +API_FILES += flowperpkt/flowperpkt.api + +# vi:syntax=automake diff --git a/src/plugins/flowperpkt/flowperpkt.api b/src/plugins/flowperpkt/flowperpkt.api new file mode 100644 index 00000000..fa878f21 --- /dev/null +++ b/src/plugins/flowperpkt/flowperpkt.api @@ -0,0 +1,42 @@ +/* Define a simple enable-disable binary API to control the feature */ + +/** \file + This file defines the vpp control-plane API messages + used to control the flowperpkt plugin +*/ + +/** \brief Enable / disable per-packet IPFIX recording on an interface + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param is_add - add address if non-zero, else delete + @param is_ipv6 - if non-zero the address is ipv6, else ipv4 + @param sw_if_index - index of the interface +*/ +manual_print define flowperpkt_tx_interface_add_del +{ + /* 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_add; + u8 which; /* 0 = ipv4, 1 = l2, 2 = ipv6 (not yet implemented) */ + + /* Interface handle */ + u32 sw_if_index; +}; + +/** \brief Reply to enable/disable per-packet IPFIX recording messages + @param context - returned sender context, to match reply w/ request + @param retval - return code +*/ +define flowperpkt_tx_interface_add_del_reply +{ + /* From the request */ + u32 context; + + /* Return value, zero means all OK */ + i32 retval; +}; diff --git a/src/plugins/flowperpkt/flowperpkt.c b/src/plugins/flowperpkt/flowperpkt.c new file mode 100644 index 00000000..fb71d5b0 --- /dev/null +++ b/src/plugins/flowperpkt/flowperpkt.c @@ -0,0 +1,671 @@ +/* + * flowperpkt.c - per-packet data capture flow report plugin + * + * 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. + */ + +/** + * @file + * @brief Per-packet IPFIX flow record generator plugin + * + * This file implements vpp plugin registration mechanics, + * debug CLI, and binary API 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 + +flowperpkt_main_t flowperpkt_main; + +/* Get the API version number */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#undef vl_api_version + +/* Define the per-interface configurable features */ +/* *INDENT-OFF* */ +VNET_FEATURE_INIT (flow_perpacket_ipv4, static) = +{ + .arc_name = "ip4-output", + .node_name = "flowperpkt-ipv4", + .runs_before = VNET_FEATURES ("interface-output"), +}; + +VNET_FEATURE_INIT (flow_perpacket_l2, static) = +{ + .arc_name = "interface-output", + .node_name = "flowperpkt-l2", + .runs_before = VNET_FEATURES ("interface-tx"), +}; +/* *INDENT-ON* */ + +/* + * 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)+fm->msg_id_base); \ + rmp->context = mp->context; \ + rmp->retval = ntohl(rv); \ + \ + vl_msg_api_send_shmem (q, (u8 *)&rmp); \ +} while(0); + +/* Macro to finish up custom dump fns */ +#define FINISH \ + vec_add1 (s, 0); \ + vl_print (handle, (char *)s); \ + vec_free (s); \ + return handle; + +#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); + +/** + * @brief Create an IPFIX template packet rewrite string + * @param frm flow_report_main_t * + * @param fr flow_report_t * + * @param collector_address ip4_address_t * the IPFIX collector address + * @param src_address ip4_address_t * the source address we should use + * @param collector_port u16 the collector port we should use, host byte order + * @returns u8 * vector containing the indicated IPFIX template packet + */ +static inline u8 * +flowperpkt_template_rewrite_inline (flow_report_main_t * frm, + flow_report_t * fr, + ip4_address_t * collector_address, + ip4_address_t * src_address, + u16 collector_port, int variant) +{ + ip4_header_t *ip; + udp_header_t *udp; + ipfix_message_header_t *h; + ipfix_set_header_t *s; + ipfix_template_header_t *t; + ipfix_field_specifier_t *f; + ipfix_field_specifier_t *first_field; + u8 *rewrite = 0; + ip4_ipfix_template_packet_t *tp; + u32 field_count = 0; + flow_report_stream_t *stream; + flowperpkt_main_t *fm = &flowperpkt_main; + + stream = &frm->streams[fr->stream_index]; + + if (variant == FLOW_VARIANT_IPV4) + { + /* + * ip4 Supported Fields: + * + * ingressInterface, TLV type 10, u32 + * egressInterface, TLV type 14, u32 + * sourceIpv4Address, TLV type 8, u32 + * destinationIPv4Address, TLV type 12, u32 + * ipClassOfService, TLV type 5, u8 + * flowStartNanoseconds, TLV type 156, dateTimeNanoseconds (f64) + * Implementation: f64 nanoseconds since VPP started + * warning: wireshark doesn't really understand this TLV + * dataLinkFrameSize, TLV type 312, u16 + * warning: wireshark doesn't understand this TLV at all + */ + + /* Currently 7 fields */ + field_count += 7; + + /* allocate rewrite space */ + vec_validate_aligned + (rewrite, + sizeof (ip4_ipfix_template_packet_t) + + field_count * sizeof (ipfix_field_specifier_t) - 1, + CLIB_CACHE_LINE_BYTES); + } + else if (variant == FLOW_VARIANT_L2) + { + /* + * L2 Supported Fields: + * + * ingressInterface, TLV type 10, u32 + * egressInterface, TLV type 14, u32 + * sourceMacAddress, TLV type 56, u8[6] we hope + * destinationMacAddress, TLV type 57, u8[6] we hope + * ethernetType, TLV type 256, u16 + * flowStartNanoseconds, TLV type 156, dateTimeNanoseconds (f64) + * Implementation: f64 nanoseconds since VPP started + * warning: wireshark doesn't really understand this TLV + * dataLinkFrameSize, TLV type 312, u16 + * warning: wireshark doesn't understand this TLV at all + */ + + /* Currently 7 fields */ + field_count += 7; + + /* allocate rewrite space */ + vec_validate_aligned + (rewrite, + sizeof (ip4_ipfix_template_packet_t) + + field_count * sizeof (ipfix_field_specifier_t) - 1, + CLIB_CACHE_LINE_BYTES); + } + + tp = (ip4_ipfix_template_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); + t = (ipfix_template_header_t *) (s + 1); + first_field = f = (ipfix_field_specifier_t *) (t + 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 (stream->src_port); + udp->dst_port = clib_host_to_net_u16 (collector_port); + udp->length = clib_host_to_net_u16 (vec_len (rewrite) - sizeof (*ip)); + + /* FIXUP: message header export_time */ + /* FIXUP: message header sequence_number */ + h->domain_id = clib_host_to_net_u32 (stream->domain_id); + + /* Add TLVs to the template */ + if (variant == FLOW_VARIANT_IPV4) + { + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , ingressInterface, + 4); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , egressInterface, + 4); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , sourceIPv4Address, + 4); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , destinationIPv4Address, 4); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , ipClassOfService, + 1); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , flowStartNanoseconds, + 8); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , dataLinkFrameSize, + 2); + f++; + } + else if (variant == FLOW_VARIANT_L2) + { + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , ingressInterface, + 4); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , egressInterface, + 4); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , sourceMacAddress, + 6); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , destinationMacAddress, 6); + f++; + f->e_id_length = ipfix_e_id_length (0 /* enterprise */ , ethernetType, + 2); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , flowStartNanoseconds, + 8); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , dataLinkFrameSize, + 2); + f++; + } + + /* Extend in the obvious way, right here... */ + + /* Back to the template packet... */ + ip = (ip4_header_t *) & tp->ip4; + udp = (udp_header_t *) (ip + 1); + + ASSERT (f - first_field); + /* Field count in this template */ + t->id_count = ipfix_id_count (fr->template_id, f - first_field); + + if (variant == FLOW_VARIANT_IPV4) + fm->ipv4_report_id = fr->template_id; + else if (variant == FLOW_VARIANT_L2) + fm->l2_report_id = fr->template_id; + + /* set length in octets */ + s->set_id_length = + ipfix_set_id_length (2 /* set_id */ , (u8 *) f - (u8 *) s); + + /* message length in octets */ + h->version_length = version_length ((u8 *) f - (u8 *) h); + + ip->length = clib_host_to_net_u16 ((u8 *) f - (u8 *) ip); + ip->checksum = ip4_header_checksum (ip); + + return rewrite; +} + +u8 * +flowperpkt_template_rewrite_ipv4 (flow_report_main_t * frm, + flow_report_t * fr, + ip4_address_t * collector_address, + ip4_address_t * src_address, + u16 collector_port) +{ + return flowperpkt_template_rewrite_inline + (frm, fr, collector_address, src_address, collector_port, + FLOW_VARIANT_IPV4); +} + +u8 * +flowperpkt_template_rewrite_l2 (flow_report_main_t * frm, + flow_report_t * fr, + ip4_address_t * collector_address, + ip4_address_t * src_address, + u16 collector_port) +{ + return flowperpkt_template_rewrite_inline + (frm, fr, collector_address, src_address, collector_port, + FLOW_VARIANT_L2); +} + + +/** + * @brief Flush accumulated data + * @param frm flow_report_main_t * + * @param fr flow_report_t * + * @param f vlib_frame_t * + * + * Notes: + * This function must simply return the incoming frame, or no template packets + * will be sent. + */ +vlib_frame_t * +flowperpkt_data_callback_ipv4 (flow_report_main_t * frm, + flow_report_t * fr, + vlib_frame_t * f, u32 * to_next, + u32 node_index) +{ + flowperpkt_flush_callback_ipv4 (); + return f; +} + +vlib_frame_t * +flowperpkt_data_callback_l2 (flow_report_main_t * frm, + flow_report_t * fr, + vlib_frame_t * f, u32 * to_next, u32 node_index) +{ + flowperpkt_flush_callback_l2 (); + return f; +} + +/** + * @brief configure / deconfigure the IPFIX flow-per-packet + * @param fm flowperpkt_main_t * fm + * @param sw_if_index u32 the desired interface + * @param is_add int 1 to enable the feature, 0 to disable it + * @returns 0 if successful, non-zero otherwise + */ + +static int flowperpkt_tx_interface_add_del_feature + (flowperpkt_main_t * fm, u32 sw_if_index, int which, int is_add) +{ + flow_report_main_t *frm = &flow_report_main; + vnet_flow_report_add_del_args_t _a, *a = &_a; + int rv; + + if (which == FLOW_VARIANT_IPV4 && !fm->ipv4_report_created) + { + memset (a, 0, sizeof (*a)); + a->rewrite_callback = flowperpkt_template_rewrite_ipv4; + a->flow_data_callback = flowperpkt_data_callback_ipv4; + a->is_add = 1; + a->domain_id = 1; /*$$$$ config parameter */ + a->src_port = 4739; /*$$$$ config parameter */ + fm->ipv4_report_created = 1; + + rv = vnet_flow_report_add_del (frm, a); + if (rv) + { + clib_warning ("vnet_flow_report_add_del returned %d", rv); + return -1; + } + } + else if (which == FLOW_VARIANT_L2 && !fm->l2_report_created) + { + memset (a, 0, sizeof (*a)); + a->rewrite_callback = flowperpkt_template_rewrite_l2; + a->flow_data_callback = flowperpkt_data_callback_l2; + a->is_add = 1; + a->domain_id = 1; /*$$$$ config parameter */ + a->src_port = 4739; /*$$$$ config parameter */ + fm->l2_report_created = 1; + + rv = vnet_flow_report_add_del (frm, a); + if (rv) + { + clib_warning ("vnet_flow_report_add_del returned %d", rv); + return -1; + } + } + + if (which == FLOW_VARIANT_IPV4) + vnet_feature_enable_disable ("ip4-output", "flowperpkt-ipv4", + sw_if_index, is_add, 0, 0); + else if (which == FLOW_VARIANT_L2) + vnet_feature_enable_disable ("interface-output", "flowperpkt-l2", + sw_if_index, is_add, 0, 0); + + return 0; +} + +/** + * @brief API message handler + * @param mp vl_api_flowperpkt_tx_interface_add_del_t * mp the api message + */ +void vl_api_flowperpkt_tx_interface_add_del_t_handler + (vl_api_flowperpkt_tx_interface_add_del_t * mp) +{ + flowperpkt_main_t *fm = &flowperpkt_main; + vl_api_flowperpkt_tx_interface_add_del_reply_t *rmp; + u32 sw_if_index = ntohl (mp->sw_if_index); + int rv = 0; + + VALIDATE_SW_IF_INDEX (mp); + + if (mp->which != FLOW_VARIANT_IPV4 && mp->which != FLOW_VARIANT_L2) + { + rv = VNET_API_ERROR_UNIMPLEMENTED; + goto out; + } + + rv = flowperpkt_tx_interface_add_del_feature (fm, sw_if_index, mp->which, + mp->is_add); +out: + BAD_SW_IF_INDEX_LABEL; + + REPLY_MACRO (VL_API_FLOWPERPKT_TX_INTERFACE_ADD_DEL_REPLY); +} + +/** + * @brief API message custom-dump function + * @param mp vl_api_flowperpkt_tx_interface_add_del_t * mp the api message + * @param handle void * print function handle + * @returns u8 * output string + */ +static void *vl_api_flowperpkt_tx_interface_add_del_t_print + (vl_api_flowperpkt_tx_interface_add_del_t * mp, void *handle) +{ + u8 *s; + + s = format (0, "SCRIPT: flowperpkt_tx_interface_add_del "); + s = format (s, "sw_if_index %d is_add %d which %d ", + clib_host_to_net_u32 (mp->sw_if_index), + (int) mp->is_add, (int) mp->which); + FINISH; +} + +/* List of message types that this plugin understands */ +#define foreach_flowperpkt_plugin_api_msg \ +_(FLOWPERPKT_TX_INTERFACE_ADD_DEL, flowperpkt_tx_interface_add_del) + +/** + * @brief plugin-api required function + * @param vm vlib_main_t * vlib main data structure pointer + * @param h vlib_plugin_handoff_t * handoff structure + * @param from_early_init int notused + * + * Notes: + * 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) +{ + flowperpkt_main_t *fm = &flowperpkt_main; + clib_error_t *error = 0; + + fm->vlib_main = vm; + fm->vnet_main = h->vnet_main; + + return error; +} + +static clib_error_t * +flowperpkt_tx_interface_add_del_feature_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + flowperpkt_main_t *fm = &flowperpkt_main; + u32 sw_if_index = ~0; + int is_add = 1; + u8 which = FLOW_VARIANT_IPV4; + + int rv; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "disable")) + is_add = 0; + else if (unformat (input, "%U", unformat_vnet_sw_interface, + fm->vnet_main, &sw_if_index)); + else if (unformat (input, "l2")) + which = FLOW_VARIANT_L2; + else + break; + } + + if (sw_if_index == ~0) + return clib_error_return (0, "Please specify an interface..."); + + rv = + flowperpkt_tx_interface_add_del_feature (fm, sw_if_index, which, is_add); + 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, "ip6 not supported"); + break; + + default: + return clib_error_return (0, "flowperpkt_enable_disable returned %d", + rv); + } + return 0; +} + +/*? + * 'flowperpkt feature add-del' commands to enable/disable + * per-packet IPFIX flow record generation on an interface + * + * @cliexpar + * @parblock + * To enable per-packet IPFIX flow-record generation on an interface: + * @cliexcmd{flowperpkt feature add-del GigabitEthernet2/0/0} + * + * To disable per-packet IPFIX flow-record generation on an interface: + * @cliexcmd{flowperpkt feature add-del GigabitEthernet2/0/0 disable} + * @cliexend + * @endparblock +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (flowperpkt_enable_disable_command, static) = { + .path = "flowperpkt feature add-del", + .short_help = + "flowperpkt feature add-del [disable]", + .function = flowperpkt_tx_interface_add_del_feature_command_fn, +}; +/* *INDENT-ON* */ + +/** + * @brief Set up the API message handling tables + * @param vm vlib_main_t * vlib main data structure pointer + * @returns 0 to indicate all is well + */ +static clib_error_t * +flowperpkt_plugin_api_hookup (vlib_main_t * vm) +{ + flowperpkt_main_t *fm = &flowperpkt_main; +#define _(N,n) \ + vl_msg_api_set_handlers((VL_API_##N + fm->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_flowperpkt_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 (flowperpkt_main_t * fm, api_main_t * am) +{ +#define _(id,n,crc) \ + vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + fm->msg_id_base); + foreach_vl_msg_name_crc_flowperpkt; +#undef _ +} + +/** + * @brief Set up the API message handling tables + * @param vm vlib_main_t * vlib main data structure pointer + * @returns 0 to indicate all is well, or a clib_error_t + */ +static clib_error_t * +flowperpkt_init (vlib_main_t * vm) +{ + flowperpkt_main_t *fm = &flowperpkt_main; + vlib_thread_main_t *tm = &vlib_thread_main; + clib_error_t *error = 0; + u32 num_threads; + u8 *name; + + /* Construct the API name */ + name = format (0, "flowperpkt_%08x%c", api_version, 0); + + /* Ask for a correctly-sized block of API message decode slots */ + fm->msg_id_base = vl_msg_api_get_msg_ids + ((char *) name, VL_MSG_FIRST_AVAILABLE); + + /* Hook up message handlers */ + error = flowperpkt_plugin_api_hookup (vm); + + /* Add our API messages to the global name_crc hash table */ + setup_message_id_table (fm, &api_main); + + vec_free (name); + + /* Decide how many worker threads we have */ + num_threads = 1 /* main thread */ + tm->n_eal_threads; + + /* Allocate per worker thread vectors */ + vec_validate (fm->ipv4_buffers_per_worker, num_threads - 1); + vec_validate (fm->l2_buffers_per_worker, num_threads - 1); + vec_validate (fm->ipv4_frames_per_worker, num_threads - 1); + vec_validate (fm->l2_frames_per_worker, num_threads - 1); + vec_validate (fm->ipv4_next_record_offset_per_worker, num_threads - 1); + vec_validate (fm->l2_next_record_offset_per_worker, num_threads - 1); + + /* Set up time reference pair */ + fm->vlib_time_0 = vlib_time_now (vm); + fm->nanosecond_time_0 = unix_time_now_nsec (); + + return error; +} + +VLIB_INIT_FUNCTION (flowperpkt_init); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/flowperpkt/flowperpkt.h b/src/plugins/flowperpkt/flowperpkt.h new file mode 100644 index 00000000..20f6939d --- /dev/null +++ b/src/plugins/flowperpkt/flowperpkt.h @@ -0,0 +1,90 @@ +/* + * flowperpkt.h - skeleton vpp engine plug-in header 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. + */ +#ifndef __included_flowperpkt_h__ +#define __included_flowperpkt_h__ + +#include +#include +#include + +#include +#include +#include +#include + +/** + * @file + * @brief flow-per-packet plugin header file + */ +typedef struct +{ + /** API message ID base */ + u16 msg_id_base; + + /** Have the reports [templates] been created? */ + int ipv4_report_created; + int l2_report_created; + + /** stream/template IDs */ + u16 ipv4_report_id; + u16 l2_report_id; + + /** ipfix buffers under construction, per-worker thread */ + vlib_buffer_t **ipv4_buffers_per_worker; + vlib_buffer_t **l2_buffers_per_worker; + + /** frames containing ipfix buffers, per-worker thread */ + vlib_frame_t **ipv4_frames_per_worker; + vlib_frame_t **l2_frames_per_worker; + + /** next record offset, per worker thread */ + u16 *ipv4_next_record_offset_per_worker; + u16 *l2_next_record_offset_per_worker; + + /** Time reference pair */ + u64 nanosecond_time_0; + f64 vlib_time_0; + + /** convenience vlib_main_t pointer */ + vlib_main_t *vlib_main; + /** convenience vnet_main_t pointer */ + vnet_main_t *vnet_main; +} flowperpkt_main_t; + +typedef enum +{ + FLOW_VARIANT_IPV4, + FLOW_VARIANT_L2, + FLOW_N_VARIANTS, +} flowperpkt_variant_t; + +extern flowperpkt_main_t flowperpkt_main; + +extern vlib_node_registration_t flowperpkt_ipv4_node; + +void flowperpkt_flush_callback_ipv4 (void); +void flowperpkt_flush_callback_l2 (void); + +#endif /* __included_flowperpkt_h__ */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/flowperpkt/flowperpkt_all_api_h.h b/src/plugins/flowperpkt/flowperpkt_all_api_h.h new file mode 100644 index 00000000..329c375a --- /dev/null +++ b/src/plugins/flowperpkt/flowperpkt_all_api_h.h @@ -0,0 +1,18 @@ +/* + * flowperpkt_all_api_h.h - 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/flowperpkt/flowperpkt_msg_enum.h b/src/plugins/flowperpkt/flowperpkt_msg_enum.h new file mode 100644 index 00000000..3177e77a --- /dev/null +++ b/src/plugins/flowperpkt/flowperpkt_msg_enum.h @@ -0,0 +1,31 @@ +/* + * flowperpkt_msg_enum.h - 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_flowperpkt_msg_enum_h +#define included_flowperpkt_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_flowperpkt_msg_enum_h */ diff --git a/src/plugins/flowperpkt/flowperpkt_plugin_doc.md b/src/plugins/flowperpkt/flowperpkt_plugin_doc.md new file mode 100644 index 00000000..ed76c45c --- /dev/null +++ b/src/plugins/flowperpkt/flowperpkt_plugin_doc.md @@ -0,0 +1,13 @@ +Per-packet IPFIX flow record plugin {#flowperpkt_plugin_doc} +=================================== + +## Introduction + +This plugin generates one ipfix record entry per packet transmitted +on interfaces which have the feature enabled + +## Sample configuration + +set ipfix exporter collector 192.168.6.2 src 192.168.6.1 template-interval 20 port 4739 path-mtu 1500 + +flowperpkt feature add-del GigabitEthernet2/3/0 diff --git a/src/plugins/flowperpkt/flowperpkt_test.c b/src/plugins/flowperpkt/flowperpkt_test.c new file mode 100644 index 00000000..716818ff --- /dev/null +++ b/src/plugins/flowperpkt/flowperpkt_test.c @@ -0,0 +1,234 @@ +/* + * flowperpkt.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 + +/** + * @file vpp_api_test plugin + */ + +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 pointer */ + vat_main_t *vat_main; +} flowperpkt_test_main_t; + +flowperpkt_test_main_t flowperpkt_test_main; + +#define foreach_standard_reply_retval_handler \ +_(flowperpkt_tx_interface_add_del_reply) + +#define _(n) \ + static void vl_api_##n##_t_handler \ + (vl_api_##n##_t * mp) \ + { \ + vat_main_t * vam = flowperpkt_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 \ +_(FLOWPERPKT_TX_INTERFACE_ADD_DEL_REPLY, \ + flowperpkt_tx_interface_add_del_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_flowperpkt_tx_interface_add_del (vat_main_t * vam) +{ + flowperpkt_test_main_t *sm = &flowperpkt_test_main; + unformat_input_t *i = vam->input; + f64 timeout; + int enable_disable = 1; + u8 which = 0; /* ipv4 by default */ + u32 sw_if_index = ~0; + vl_api_flowperpkt_tx_interface_add_del_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 if (unformat (i, "l2")) + which = 1; + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("missing interface name / explicit sw_if_index number \n"); + return -99; + } + + /* Construct the API message */ + M (FLOWPERPKT_TX_INTERFACE_ADD_DEL, flowperpkt_tx_interface_add_del); + mp->sw_if_index = ntohl (sw_if_index); + mp->is_add = enable_disable; + mp->which = which; + + /* 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 \ +_(flowperpkt_tx_interface_add_del, " [disable]") + +void +vat_api_hookup (vat_main_t * vam) +{ + flowperpkt_test_main_t *sm = &flowperpkt_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) +{ + flowperpkt_test_main_t *sm = &flowperpkt_test_main; + u8 *name; + + sm->vat_main = vam; + + /* Ask the vpp engine for the first assigned message-id */ + name = format (0, "flowperpkt_%08x%c", api_version, 0); + sm->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name); + + /* Don't attempt to hook up API messages if the data plane plugin is AWOL */ + 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/flowperpkt/l2_node.c b/src/plugins/flowperpkt/l2_node.c new file mode 100644 index 00000000..1c2f681e --- /dev/null +++ b/src/plugins/flowperpkt/l2_node.c @@ -0,0 +1,561 @@ +/* + * l2_node.c - l2 ipfix-per-packet graph node + * + * 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 + +/** + * @file l2 flow record generator graph node + */ + +typedef struct +{ + /** interface handle */ + u32 rx_sw_if_index; + u32 tx_sw_if_index; + /** src and dst L2 addresses */ + u8 src_mac[6]; + u8 dst_mac[6]; + /** Ethertype */ + u16 ethertype; + /** packet timestamp */ + u64 timestamp; + /** size of the buffer */ + u16 buffer_size; +} flowperpkt_l2_trace_t; + +/* packet trace format function */ +static u8 * +format_flowperpkt_l2_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 *); + flowperpkt_l2_trace_t *t = va_arg (*args, flowperpkt_l2_trace_t *); + + s = format (s, + "FLOWPERPKT-L2: rx_sw_if_index %d, tx_sw_if_index %d, src %U dst %U ethertype %0x2, timestamp %lld, size %d", + t->rx_sw_if_index, t->tx_sw_if_index, + format_ethernet_address, &t->src_mac, + format_ethernet_address, &t->dst_mac, + t->ethertype, t->timestamp, t->buffer_size); + return s; +} + +vlib_node_registration_t flowperpkt_l2_node; + +/* No counters at the moment */ +#define foreach_flowperpkt_l2_error + +typedef enum +{ +#define _(sym,str) FLOWPERPKT_ERROR_##sym, + foreach_flowperpkt_l2_error +#undef _ + FLOWPERPKT_N_ERROR, +} flowperpkt_l2_error_t; + +static char *flowperpkt_l2_error_strings[] = { +#define _(sym,string) string, + foreach_flowperpkt_l2_error +#undef _ +}; + +typedef enum +{ + FLOWPERPKT_L2_NEXT_DROP, + FLOWPERPKT_L2_NEXT_IP4_LOOKUP, + FLOWPERPKT_L2_N_NEXT, +} flowperpkt_l2_next_t; + +/** + * @brief add an entry to the flow record under construction + * @param vm vlib_main_t * current worker thread main structure pointer + * @param fm flowperpkt_main_t * flow-per-packet main structure pointer + * @param sw_if_index u32 interface handle + * @param tos u8 ToS bits from the packet + * @param timestamp u64 timestamp, nanoseconds since 1/1/70 + * @param length u16 ip length of the packet + * @param do_flush int 1 = flush all cached records, 0 = construct a record + */ + +static inline void +add_to_flow_record_l2 (vlib_main_t * vm, + vlib_node_runtime_t * node, + flowperpkt_main_t * fm, + u32 rx_sw_if_index, u32 tx_sw_if_index, + u8 * src_mac, u8 * dst_mac, + u16 ethertype, u64 timestamp, u16 length, int do_flush) +{ + u32 my_cpu_number = vm->cpu_index; + flow_report_main_t *frm = &flow_report_main; + ip4_header_t *ip; + udp_header_t *udp; + ip4_ipfix_template_packet_t *tp; + ipfix_message_header_t *h; + ipfix_set_header_t *s; + vlib_frame_t *f; + vlib_buffer_t *b0; + u16 offset; + u32 bi0; + vlib_buffer_free_list_t *fl; + + /* Find or allocate a buffer */ + b0 = fm->l2_buffers_per_worker[my_cpu_number]; + + /* Need to allocate a buffer? */ + if (PREDICT_FALSE (b0 == 0)) + { + /* Nothing to flush */ + if (do_flush) + return; + + /* $$$$ drop counter? */ + if (vlib_buffer_alloc (vm, &bi0, 1) != 1) + return; + + /* Initialize the buffer */ + b0 = fm->l2_buffers_per_worker[my_cpu_number] = + vlib_get_buffer (vm, bi0); + fl = + vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX); + vlib_buffer_init_for_free_list (b0, fl); + VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0); + offset = 0; + } + else + { + /* use the current buffer */ + bi0 = vlib_get_buffer_index (vm, b0); + offset = fm->l2_next_record_offset_per_worker[my_cpu_number]; + } + + /* Find or allocate a frame */ + f = fm->l2_frames_per_worker[my_cpu_number]; + if (PREDICT_FALSE (f == 0)) + { + u32 *to_next; + f = vlib_get_frame_to_node (vm, ip4_lookup_node.index); + fm->l2_frames_per_worker[my_cpu_number] = f; + + /* Enqueue the buffer */ + to_next = vlib_frame_vector_args (f); + to_next[0] = bi0; + f->n_vectors = 1; + } + + /* Fresh packet, construct header */ + if (PREDICT_FALSE (offset == 0)) + { + flow_report_stream_t *stream; + + stream = &frm->streams[0]; + + b0->current_data = 0; + b0->current_length = sizeof (*ip) + sizeof (*udp) + sizeof (*h) + + sizeof (*s); + b0->flags |= (VLIB_BUFFER_TOTAL_LENGTH_VALID | VLIB_BUFFER_FLOW_REPORT); + vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = frm->fib_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); + + ip->ip_version_and_header_length = 0x45; + ip->ttl = 254; + ip->protocol = IP_PROTOCOL_UDP; + ip->flags_and_fragment_offset = 0; + ip->src_address.as_u32 = frm->src_address.as_u32; + ip->dst_address.as_u32 = frm->ipfix_collector.as_u32; + udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix); + udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix); + udp->checksum = 0; + + /* FIXUP: message header export_time */ + h->export_time = (u32) + (((f64) frm->unix_time_0) + + (vlib_time_now (frm->vlib_main) - frm->vlib_time_0)); + h->export_time = clib_host_to_net_u32 (h->export_time); + h->domain_id = clib_host_to_net_u32 (stream->domain_id); + + /* FIXUP: message header sequence_number */ + h->sequence_number = stream->sequence_number++; + h->sequence_number = clib_host_to_net_u32 (h->sequence_number); + + offset = (u32) (((u8 *) (s + 1)) - (u8 *) tp); + } + + /* Add data, unless we're flushing stale data */ + if (PREDICT_TRUE (do_flush == 0)) + { + + /* Add data */ + /* Ingress interface */ + { + u32 ingress_interface = clib_host_to_net_u32 (rx_sw_if_index); + clib_memcpy (b0->data + offset, &ingress_interface, + sizeof (ingress_interface)); + offset += sizeof (ingress_interface); + } + /* Egress interface */ + { + u32 egress_interface = clib_host_to_net_u32 (tx_sw_if_index); + clib_memcpy (b0->data + offset, &egress_interface, + sizeof (egress_interface)); + offset += sizeof (egress_interface); + } + /* src mac address */ + { + clib_memcpy (b0->data + offset, src_mac, 6); + offset += 6; + } + /* dst mac address */ + { + clib_memcpy (b0->data + offset, dst_mac, 6); + offset += 6; + } + + /* ethertype */ + b0->data[offset++] = ethertype >> 8; + b0->data[offset++] = ethertype & 0xFF; + + /* Timestamp */ + clib_memcpy (b0->data + offset, ×tamp, sizeof (f64)); + offset += sizeof (f64); + + /* pkt size */ + { + u16 pkt_size = clib_host_to_net_u16 (length); + clib_memcpy (b0->data + offset, &pkt_size, sizeof (pkt_size)); + offset += sizeof (pkt_size); + } + + b0->current_length += + /* 2*sw_if_index + 2*mac + ethertype + timestamp + length = 32 */ + 2 * sizeof (u32) + 12 + sizeof (u16) + sizeof (f64) + sizeof (u16); + + } + /* Time to flush the buffer? */ + if (PREDICT_FALSE + (do_flush || (offset + 2 * sizeof (u32) + 12 + sizeof (u16) + + +sizeof (f64) + sizeof (u16)) > frm->path_mtu)) + { + 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); + + s->set_id_length = ipfix_set_id_length (fm->l2_report_id, + b0->current_length - + (sizeof (*ip) + sizeof (*udp) + + sizeof (*h))); + h->version_length = version_length (b0->current_length - + (sizeof (*ip) + sizeof (*udp))); + + ip->length = clib_host_to_net_u16 (b0->current_length); + + ip->checksum = ip4_header_checksum (ip); + udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip)); + + if (frm->udp_checksum) + { + /* RFC 7011 section 10.3.2. */ + udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip); + if (udp->checksum == 0) + udp->checksum = 0xffff; + } + + ASSERT (ip->checksum == ip4_header_checksum (ip)); + + if (PREDICT_FALSE (vlib_get_trace_count (vm, node) > 0)) + { + vlib_trace_buffer (vm, node, FLOWPERPKT_L2_NEXT_IP4_LOOKUP, b0, + 0 /* follow chain */ ); + flowperpkt_l2_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + memset (t, 0, sizeof (*t)); + t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + t->buffer_size = b0->current_length; + } + + vlib_put_frame_to_node (vm, ip4_lookup_node.index, + fm->l2_frames_per_worker[my_cpu_number]); + fm->l2_frames_per_worker[my_cpu_number] = 0; + fm->l2_buffers_per_worker[my_cpu_number] = 0; + offset = 0; + } + + fm->l2_next_record_offset_per_worker[my_cpu_number] = offset; +} + +void +flowperpkt_flush_callback_l2 (void) +{ + vlib_main_t *vm = vlib_get_main (); + flowperpkt_main_t *fm = &flowperpkt_main; + vlib_node_runtime_t *node; + node = vlib_node_get_runtime (vm, flowperpkt_l2_node.index); + + add_to_flow_record_l2 (vm, node, fm, 0 /* rx_sw_if_index */ , + 0 /* tx_sw_if_index */ , + 0 /* src mac */ , + 0 /* dst mac */ , + 0 /* ethertype */ , + 0ULL /* timestamp */ , + 0 /* length */ , + 1 /* do_flush */ ); +} + + +static uword +flowperpkt_l2_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + flowperpkt_l2_next_t next_index; + flowperpkt_main_t *fm = &flowperpkt_main; + u64 now; + + now = (u64) ((vlib_time_now (vm) - fm->vlib_time_0) * 1e9); + now += fm->nanosecond_time_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 = FLOWPERPKT_L2_NEXT_DROP; + u32 next1 = FLOWPERPKT_L2_NEXT_DROP; + ethernet_header_t *eh0, *eh1; + u16 len0, len1; + 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); + + vnet_feature_next (vnet_buffer (b0)->sw_if_index[VLIB_TX], + &next0, b0); + vnet_feature_next (vnet_buffer (b1)->sw_if_index[VLIB_TX], + &next1, b1); + + eh0 = vlib_buffer_get_current (b0); + len0 = vlib_buffer_length_in_chain (vm, b0); + + if (PREDICT_TRUE ((b0->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) + add_to_flow_record_l2 (vm, node, fm, + vnet_buffer (b0)->sw_if_index[VLIB_RX], + vnet_buffer (b0)->sw_if_index[VLIB_TX], + eh0->src_address, + eh0->dst_address, + eh0->type, now, len0, 0 /* flush */ ); + + eh1 = vlib_buffer_get_current (b0); + len1 = vlib_buffer_length_in_chain (vm, b0); + + if (PREDICT_TRUE ((b1->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) + add_to_flow_record_l2 (vm, node, fm, + vnet_buffer (b1)->sw_if_index[VLIB_RX], + vnet_buffer (b1)->sw_if_index[VLIB_TX], + eh1->src_address, + eh1->dst_address, + eh1->type, now, len1, 0 /* flush */ ); + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + { + if (b0->flags & VLIB_BUFFER_IS_TRACED) + { + flowperpkt_l2_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + clib_memcpy (t->src_mac, eh0->src_address, 6); + clib_memcpy (t->dst_mac, eh0->dst_address, 6); + t->ethertype = clib_net_to_host_u16 (eh0->type); + t->timestamp = now; + t->buffer_size = len0; + } + if (b1->flags & VLIB_BUFFER_IS_TRACED) + { + flowperpkt_l2_trace_t *t = + vlib_add_trace (vm, node, b1, sizeof (*t)); + t->rx_sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX]; + t->tx_sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_TX]; + clib_memcpy (t->src_mac, eh1->src_address, 6); + clib_memcpy (t->dst_mac, eh1->dst_address, 6); + t->ethertype = clib_net_to_host_u16 (eh1->type); + t->timestamp = now; + t->buffer_size = len1; + } + } + + /* 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 = FLOWPERPKT_L2_NEXT_DROP; + ethernet_header_t *eh0; + u16 len0; + + /* 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); + + vnet_feature_next (vnet_buffer (b0)->sw_if_index[VLIB_TX], + &next0, b0); + + eh0 = vlib_buffer_get_current (b0); + len0 = vlib_buffer_length_in_chain (vm, b0); + + if (PREDICT_TRUE ((b0->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) + add_to_flow_record_l2 (vm, node, fm, + vnet_buffer (b0)->sw_if_index[VLIB_RX], + vnet_buffer (b0)->sw_if_index[VLIB_TX], + eh0->src_address, + eh0->dst_address, + eh0->type, now, len0, 0 /* flush */ ); + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + flowperpkt_l2_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + clib_memcpy (t->src_mac, eh0->src_address, 6); + clib_memcpy (t->dst_mac, eh0->dst_address, 6); + t->ethertype = clib_net_to_host_u16 (eh0->type); + t->timestamp = now; + t->buffer_size = len0; + } + + /* 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; +} + +/** + * @brief IPFIX l2 flow-per-packet graph node + * @node flowperpkt-l2 + * + * This is the IPFIX flow-record-per-packet node. + * + * @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. + * + * @par Graph mechanics: buffer metadata, next index usage + * + * Uses: + * - vnet_buffer(b)->ip.save_rewrite_length + * - tells the node the length of the rewrite which was applied in + * ip4/6_rewrite_inline, allows the code to find the IP header without + * having to parse L2 headers, or make stupid assumptions about their + * length. + * - vnet_buffer(b)->flags & VLIB_BUFFER_FLOW_REPORT + * - Used to suppress flow record generation for flow record packets. + * + * Sets: + * - vnet_buffer(b)->flags & VLIB_BUFFER_FLOW_REPORT + * - To suppress flow record generation for flow record packets + * + * Next Index: + * - Next configured output feature on the interface, usually + * "interface-output." Generated flow records head for ip4-lookup + */ + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (flowperpkt_l2_node) = { + .function = flowperpkt_l2_node_fn, + .name = "flowperpkt-l2", + .vector_size = sizeof (u32), + .format_trace = format_flowperpkt_l2_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(flowperpkt_l2_error_strings), + .error_strings = flowperpkt_l2_error_strings, + + .n_next_nodes = FLOWPERPKT_L2_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [FLOWPERPKT_L2_NEXT_DROP] = "error-drop", + [FLOWPERPKT_L2_NEXT_IP4_LOOKUP] = "ip4-lookup", + }, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/flowperpkt/node.c b/src/plugins/flowperpkt/node.c new file mode 100644 index 00000000..f77f087d --- /dev/null +++ b/src/plugins/flowperpkt/node.c @@ -0,0 +1,574 @@ +/* + * node.c - ipv4 ipfix-per-packet graph node + * + * 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 + +/** + * @file ipv4 flow record generator graph node + */ + +typedef struct +{ + /** interface handle */ + u32 rx_sw_if_index; + u32 tx_sw_if_index; + u32 src_address; + u32 dst_address; + /** ToS bits */ + u8 tos; + /** packet timestamp */ + u64 timestamp; + /** size of the buffer */ + u16 buffer_size; +} flowperpkt_ipv4_trace_t; + +/* packet trace format function */ +static u8 * +format_flowperpkt_ipv4_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 *); + flowperpkt_ipv4_trace_t *t = va_arg (*args, flowperpkt_ipv4_trace_t *); + + s = format (s, + "FLOWPERPKT-V4: rx_sw_if_index %d, tx_sw_if_index %d, src %U dst %U tos %0x2, timestamp %lld, size %d", + t->rx_sw_if_index, t->tx_sw_if_index, + format_ip4_address, &t->src_address, + format_ip4_address, &t->dst_address, + t->tos, t->timestamp, t->buffer_size); + return s; +} + +vlib_node_registration_t flowperpkt_ipv4_node; + +/* No counters at the moment */ +#define foreach_flowperpkt_ipv4_error + +typedef enum +{ +#define _(sym,str) FLOWPERPKT_ERROR_##sym, + foreach_flowperpkt_ipv4_error +#undef _ + FLOWPERPKT_N_ERROR, +} flowperpkt_ipv4_error_t; + +static char *flowperpkt_ipv4_error_strings[] = { +#define _(sym,string) string, + foreach_flowperpkt_ipv4_error +#undef _ +}; + +typedef enum +{ + FLOWPERPKT_IPV4_NEXT_DROP, + FLOWPERPKT_IPV4_NEXT_LOOKUP, + FLOWPERPKT_IPV4_N_NEXT, +} flowperpkt_ipv4_next_t; + +/** + * @brief add an entry to the flow record under construction + * @param vm vlib_main_t * current worker thread main structure pointer + * @param fm flowperpkt_main_t * flow-per-packet main structure pointer + * @param sw_if_index u32 interface handle + * @param tos u8 ToS bits from the packet + * @param timestamp u64 timestamp, nanoseconds since 1/1/70 + * @param length u16 ip length of the packet + * @param do_flush int 1 = flush all cached records, 0 = construct a record + */ + +static inline void +add_to_flow_record_ipv4 (vlib_main_t * vm, + vlib_node_runtime_t * node, + flowperpkt_main_t * fm, + u32 rx_sw_if_index, u32 tx_sw_if_index, + u32 src_address, u32 dst_address, + u8 tos, u64 timestamp, u16 length, int do_flush) +{ + u32 my_cpu_number = vm->cpu_index; + flow_report_main_t *frm = &flow_report_main; + ip4_header_t *ip; + udp_header_t *udp; + ip4_ipfix_template_packet_t *tp; + ipfix_message_header_t *h; + ipfix_set_header_t *s; + vlib_frame_t *f; + vlib_buffer_t *b0; + u16 offset; + u32 bi0; + vlib_buffer_free_list_t *fl; + + /* Find or allocate a buffer */ + b0 = fm->ipv4_buffers_per_worker[my_cpu_number]; + + /* Need to allocate a buffer? */ + if (PREDICT_FALSE (b0 == 0)) + { + /* Nothing to flush */ + if (do_flush) + return; + + /* $$$$ drop counter? */ + if (vlib_buffer_alloc (vm, &bi0, 1) != 1) + return; + + /* Initialize the buffer */ + b0 = fm->ipv4_buffers_per_worker[my_cpu_number] = + vlib_get_buffer (vm, bi0); + fl = + vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX); + vlib_buffer_init_for_free_list (b0, fl); + VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0); + offset = 0; + } + else + { + /* use the current buffer */ + bi0 = vlib_get_buffer_index (vm, b0); + offset = fm->ipv4_next_record_offset_per_worker[my_cpu_number]; + } + + /* Find or allocate a frame */ + f = fm->ipv4_frames_per_worker[my_cpu_number]; + if (PREDICT_FALSE (f == 0)) + { + u32 *to_next; + f = vlib_get_frame_to_node (vm, ip4_lookup_node.index); + fm->ipv4_frames_per_worker[my_cpu_number] = f; + + /* Enqueue the buffer */ + to_next = vlib_frame_vector_args (f); + to_next[0] = bi0; + f->n_vectors = 1; + } + + /* Fresh packet, construct header */ + if (PREDICT_FALSE (offset == 0)) + { + flow_report_stream_t *stream; + + stream = &frm->streams[0]; + + b0->current_data = 0; + b0->current_length = sizeof (*ip) + sizeof (*udp) + sizeof (*h) + + sizeof (*s); + b0->flags |= (VLIB_BUFFER_TOTAL_LENGTH_VALID | VLIB_BUFFER_FLOW_REPORT); + vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = frm->fib_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); + + ip->ip_version_and_header_length = 0x45; + ip->ttl = 254; + ip->protocol = IP_PROTOCOL_UDP; + ip->flags_and_fragment_offset = 0; + ip->src_address.as_u32 = frm->src_address.as_u32; + ip->dst_address.as_u32 = frm->ipfix_collector.as_u32; + udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix); + udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix); + udp->checksum = 0; + + /* FIXUP: message header export_time */ + h->export_time = (u32) + (((f64) frm->unix_time_0) + + (vlib_time_now (frm->vlib_main) - frm->vlib_time_0)); + h->export_time = clib_host_to_net_u32 (h->export_time); + h->domain_id = clib_host_to_net_u32 (stream->domain_id); + + /* FIXUP: message header sequence_number */ + h->sequence_number = stream->sequence_number++; + h->sequence_number = clib_host_to_net_u32 (h->sequence_number); + + offset = (u32) (((u8 *) (s + 1)) - (u8 *) tp); + } + + /* Add data, unless we're flushing stale data */ + if (PREDICT_TRUE (do_flush == 0)) + { + + /* Add data */ + /* Ingress interface */ + { + u32 ingress_interface = clib_host_to_net_u32 (rx_sw_if_index); + clib_memcpy (b0->data + offset, &ingress_interface, + sizeof (ingress_interface)); + offset += sizeof (ingress_interface); + } + /* Egress interface */ + { + u32 egress_interface = clib_host_to_net_u32 (tx_sw_if_index); + clib_memcpy (b0->data + offset, &egress_interface, + sizeof (egress_interface)); + offset += sizeof (egress_interface); + } + /* ip4 src address */ + { + clib_memcpy (b0->data + offset, &src_address, sizeof (src_address)); + offset += sizeof (src_address); + } + /* ip4 dst address */ + { + clib_memcpy (b0->data + offset, &dst_address, sizeof (dst_address)); + offset += sizeof (dst_address); + } + + /* ToS */ + b0->data[offset++] = tos; + + /* Timestamp */ + clib_memcpy (b0->data + offset, ×tamp, sizeof (f64)); + offset += sizeof (f64); + + /* pkt size */ + { + u16 pkt_size = clib_host_to_net_u16 (length); + clib_memcpy (b0->data + offset, &pkt_size, sizeof (pkt_size)); + offset += sizeof (pkt_size); + } + + b0->current_length += + /* sw_if_index + tos + timestamp + length = 15 */ + 4 * sizeof (u32) + sizeof (u8) + sizeof (f64) + sizeof (u16); + + } + /* Time to flush the buffer? */ + if (PREDICT_FALSE + (do_flush || (offset + 4 * sizeof (u32) + sizeof (u8) + + sizeof (f64) + sizeof (u16)) > frm->path_mtu)) + { + 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); + + s->set_id_length = ipfix_set_id_length (fm->ipv4_report_id, + b0->current_length - + (sizeof (*ip) + sizeof (*udp) + + sizeof (*h))); + h->version_length = version_length (b0->current_length - + (sizeof (*ip) + sizeof (*udp))); + + ip->length = clib_host_to_net_u16 (b0->current_length); + + ip->checksum = ip4_header_checksum (ip); + udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip)); + + if (frm->udp_checksum) + { + /* RFC 7011 section 10.3.2. */ + udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip); + if (udp->checksum == 0) + udp->checksum = 0xffff; + } + + ASSERT (ip->checksum == ip4_header_checksum (ip)); + + if (PREDICT_FALSE (vlib_get_trace_count (vm, node) > 0)) + { + vlib_trace_buffer (vm, node, FLOWPERPKT_IPV4_NEXT_LOOKUP, b0, + 0 /* follow chain */ ); + flowperpkt_ipv4_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + t->src_address = 0; + t->dst_address = 0; + t->tos = 0; + t->timestamp = 0; + t->buffer_size = b0->current_length; + } + + vlib_put_frame_to_node (vm, ip4_lookup_node.index, + fm->ipv4_frames_per_worker[my_cpu_number]); + fm->ipv4_frames_per_worker[my_cpu_number] = 0; + fm->ipv4_buffers_per_worker[my_cpu_number] = 0; + offset = 0; + } + + fm->ipv4_next_record_offset_per_worker[my_cpu_number] = offset; +} + +void +flowperpkt_flush_callback_ipv4 (void) +{ + vlib_main_t *vm = vlib_get_main (); + flowperpkt_main_t *fm = &flowperpkt_main; + vlib_node_runtime_t *node; + node = vlib_node_get_runtime (vm, flowperpkt_ipv4_node.index); + + add_to_flow_record_ipv4 (vm, node, fm, 0 /* rx_sw_if_index */ , + 0 /* tx_sw_if_index */ , + 0 /* src_address */ , + 0 /* dst_address */ , + 0 /* ToS */ , + 0ULL /* timestamp */ , + 0 /* length */ , + 1 /* do_flush */ ); +} + + +static uword +flowperpkt_ipv4_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + flowperpkt_ipv4_next_t next_index; + flowperpkt_main_t *fm = &flowperpkt_main; + u64 now; + + now = (u64) ((vlib_time_now (vm) - fm->vlib_time_0) * 1e9); + now += fm->nanosecond_time_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 = FLOWPERPKT_IPV4_NEXT_DROP; + u32 next1 = FLOWPERPKT_IPV4_NEXT_DROP; + ip4_header_t *ip0, *ip1; + u16 len0, len1; + 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); + + vnet_feature_next (vnet_buffer (b0)->sw_if_index[VLIB_TX], + &next0, b0); + vnet_feature_next (vnet_buffer (b1)->sw_if_index[VLIB_TX], + &next1, b1); + + ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) + + vnet_buffer (b0)->ip.save_rewrite_length); + + len0 = vlib_buffer_length_in_chain (vm, b0); + + if (PREDICT_TRUE ((b0->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) + add_to_flow_record_ipv4 (vm, node, fm, + vnet_buffer (b0)->sw_if_index[VLIB_RX], + vnet_buffer (b0)->sw_if_index[VLIB_TX], + ip0->src_address.as_u32, + ip0->dst_address.as_u32, + ip0->tos, now, len0, 0 /* flush */ ); + + ip1 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b1) + + vnet_buffer (b1)->ip.save_rewrite_length); + len1 = vlib_buffer_length_in_chain (vm, b1); + + if (PREDICT_TRUE ((b1->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) + add_to_flow_record_ipv4 (vm, node, fm, + vnet_buffer (b1)->sw_if_index[VLIB_RX], + vnet_buffer (b1)->sw_if_index[VLIB_TX], + ip1->src_address.as_u32, + ip1->dst_address.as_u32, + ip1->tos, now, len1, 0 /* flush */ ); + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + { + if (b0->flags & VLIB_BUFFER_IS_TRACED) + { + flowperpkt_ipv4_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + t->src_address = ip0->src_address.as_u32; + t->dst_address = ip0->dst_address.as_u32; + t->tos = ip0->tos; + t->timestamp = now; + t->buffer_size = len0; + } + if (b1->flags & VLIB_BUFFER_IS_TRACED) + { + flowperpkt_ipv4_trace_t *t = + vlib_add_trace (vm, node, b1, sizeof (*t)); + t->rx_sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX]; + t->tx_sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_TX]; + t->src_address = ip1->src_address.as_u32; + t->dst_address = ip1->dst_address.as_u32; + t->tos = ip1->tos; + t->timestamp = now; + t->buffer_size = len1; + } + } + + /* 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 = FLOWPERPKT_IPV4_NEXT_DROP; + ip4_header_t *ip0; + u16 len0; + + /* 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); + + vnet_feature_next (vnet_buffer (b0)->sw_if_index[VLIB_TX], + &next0, b0); + + ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) + + vnet_buffer (b0)->ip.save_rewrite_length); + /* + * egressInterface, TLV type 14, u32 + * ipClassOfService, TLV type 5, u8 + * flowStartNanoseconds, TLV type 156, dateTimeNanoseconds (f64) + * Implementation: f64 nanoseconds since VPP started + * dataLinkFrameSize, TLV type 312, u16 + */ + len0 = vlib_buffer_length_in_chain (vm, b0); + + if (PREDICT_TRUE ((b0->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) + add_to_flow_record_ipv4 (vm, node, fm, + vnet_buffer (b0)->sw_if_index[VLIB_RX], + vnet_buffer (b0)->sw_if_index[VLIB_TX], + ip0->src_address.as_u32, + ip0->dst_address.as_u32, + ip0->tos, now, len0, 0 /* flush */ ); + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + flowperpkt_ipv4_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + t->src_address = ip0->src_address.as_u32; + t->dst_address = ip0->dst_address.as_u32; + t->tos = ip0->tos; + t->timestamp = now; + t->buffer_size = len0; + } + + /* 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; +} + +/** + * @brief IPFIX ipv4 flow-per-packet graph node + * @node flowperpkt-ipv4 + * + * This is the IPFIX flow-record-per-packet node. + * + * @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. + * + * @par Graph mechanics: buffer metadata, next index usage + * + * Uses: + * - vnet_buffer(b)->ip.save_rewrite_length + * - tells the node the length of the rewrite which was applied in + * ip4/6_rewrite_inline, allows the code to find the IP header without + * having to parse L2 headers, or make stupid assumptions about their + * length. + * - vnet_buffer(b)->flags & VLIB_BUFFER_FLOW_REPORT + * - Used to suppress flow record generation for flow record packets. + * + * Sets: + * - vnet_buffer(b)->flags & VLIB_BUFFER_FLOW_REPORT + * - To suppress flow record generation for flow record packets + * + * Next Index: + * - Next configured output feature on the interface, usually + * "interface-output." Generated flow records head for ip4-lookup + */ + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (flowperpkt_ipv4_node) = { + .function = flowperpkt_ipv4_node_fn, + .name = "flowperpkt-ipv4", + .vector_size = sizeof (u32), + .format_trace = format_flowperpkt_ipv4_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(flowperpkt_ipv4_error_strings), + .error_strings = flowperpkt_ipv4_error_strings, + + .n_next_nodes = FLOWPERPKT_IPV4_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [FLOWPERPKT_IPV4_NEXT_DROP] = "error-drop", + /* Used only to trace ipfix data packets */ + [FLOWPERPKT_IPV4_NEXT_LOOKUP] = "ip4-lookup", + }, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ila.am b/src/plugins/ila.am new file mode 100644 index 00000000..d900f3eb --- /dev/null +++ b/src/plugins/ila.am @@ -0,0 +1,20 @@ +# 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. + +vppplugins_LTLIBRARIES += ila_plugin.la + +ila_plugin_la_SOURCES = ila/ila.c + +noinst_HEADERS += ila/ila.h + +# vi:syntax=automake diff --git a/src/plugins/ila/ila.c b/src/plugins/ila/ila.c new file mode 100644 index 00000000..336f4cf5 --- /dev/null +++ b/src/plugins/ila/ila.c @@ -0,0 +1,1070 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 + +static ila_main_t ila_main; + +#define ILA_TABLE_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) +#define ILA_TABLE_DEFAULT_HASH_MEMORY_SIZE (32<<20) + +#define foreach_ila_error \ + _(NONE, "valid ILA packets") + +typedef enum { +#define _(sym,str) ILA_ERROR_##sym, + foreach_ila_error +#undef _ + ILA_N_ERROR, +} ila_error_t; + +static char *ila_error_strings[] = { +#define _(sym,string) string, + foreach_ila_error +#undef _ +}; + +typedef enum { + ILA_ILA2SIR_NEXT_DROP, + ILA_ILA2SIR_N_NEXT, +} ila_ila2sir_next_t; + +typedef struct { + u32 ila_index; + ip6_address_t initial_dst; + u32 adj_index; +} ila_ila2sir_trace_t; + +static ila_entry_t ila_sir2ila_default_entry = { + .csum_mode = ILA_CSUM_MODE_NO_ACTION, + .type = ILA_TYPE_IID, + .dir = ILA_DIR_ILA2SIR, //Will pass the packet with no +}; + +/** + * @brief Dynamically registered DPO Type for ILA + */ +static dpo_type_t ila_dpo_type; + +/** + * @brief Dynamically registered FIB node type for ILA + */ +static fib_node_type_t ila_fib_node_type; + +u8 * +format_half_ip6_address (u8 * s, va_list * va) +{ + u64 v = clib_net_to_host_u64 (va_arg (*va, u64)); + + return format (s, "%04x:%04x:%04x:%04x", + v >> 48, (v >> 32) & 0xffff, (v >> 16) & 0xffff, v & 0xffff); + +} + +u8 * +format_ila_direction (u8 * s, va_list * args) +{ + ila_direction_t t = va_arg (*args, ila_direction_t); +#define _(i,n,st) \ + if (t == ILA_DIR_##i) \ + return format(s, st); + ila_foreach_direction +#undef _ + return format (s, "invalid_ila_direction"); +} + +static u8 * +format_csum_mode (u8 * s, va_list * va) +{ + ila_csum_mode_t csum_mode = va_arg (*va, ila_csum_mode_t); + char *txt; + + switch (csum_mode) + { +#define _(i,n,st) \ + case ILA_CSUM_MODE_##i: \ + txt = st; \ + break; + ila_csum_foreach_type +#undef _ + default: + txt = "invalid_ila_csum_mode"; + break; + } + return format (s, txt); +} + +u8 * +format_ila_type (u8 * s, va_list * args) +{ + ila_type_t t = va_arg (*args, ila_type_t); +#define _(i,n,st) \ + if (t == ILA_TYPE_##i) \ + return format(s, st); + ila_foreach_type +#undef _ + return format (s, "invalid_ila_type"); +} + +static u8 * +format_ila_entry (u8 * s, va_list * va) +{ + vnet_main_t *vnm = va_arg (*va, vnet_main_t *); + ila_entry_t *e = va_arg (*va, ila_entry_t *); + + if (!e) + { + return format (s, "%-15s%=40s%=40s%+16s%+18s%+11s", "Type", "SIR Address", + "ILA Address", "Checksum Mode", "Direction", "Next DPO"); + } + else if (vnm) + { + if (ip6_address_is_zero(&e->next_hop)) + { + return format (s, "%-15U%=40U%=40U%18U%11U%s", + format_ila_type, e->type, + format_ip6_address, &e->sir_address, + format_ip6_address, &e->ila_address, + format_csum_mode, e->csum_mode, + format_ila_direction, e->dir, + "n/a"); + } + else + { + return format (s, "%-15U%=40U%=40U%18U%11U%U", + format_ila_type, e->type, + format_ip6_address, &e->sir_address, + format_ip6_address, &e->ila_address, + format_csum_mode, e->csum_mode, + format_ila_direction, e->dir, + format_dpo_id, &e->ila_dpo, 0); + } + } + + return NULL; +} + +u8 * +format_ila_ila2sir_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 *); + ila_ila2sir_trace_t *t = va_arg (*args, ila_ila2sir_trace_t *); + return format (s, + "ILA -> SIR adj index: %d entry index: %d initial_dst: %U", + t->adj_index, t->ila_index, format_ip6_address, + &t->initial_dst); +} + +static uword +unformat_ila_direction (unformat_input_t * input, va_list * args) +{ + ila_direction_t *result = va_arg (*args, ila_direction_t *); +#define _(i,n,s) \ + if (unformat(input, s)) \ + { \ + *result = ILA_DIR_##i; \ + return 1;\ + } + + ila_foreach_direction +#undef _ + return 0; +} + +static uword +unformat_ila_type (unformat_input_t * input, va_list * args) +{ + ila_type_t *result = va_arg (*args, ila_type_t *); +#define _(i,n,s) \ + if (unformat(input, s)) \ + { \ + *result = ILA_TYPE_##i; \ + return 1;\ + } + + ila_foreach_type +#undef _ + return 0; +} + +static uword +unformat_ila_csum_mode (unformat_input_t * input, va_list * args) +{ + ila_csum_mode_t *result = va_arg (*args, ila_csum_mode_t *); + if (unformat (input, "none") || unformat (input, "no-action")) + { + *result = ILA_CSUM_MODE_NO_ACTION; + return 1; + } + if (unformat (input, "neutral-map")) + { + *result = ILA_CSUM_MODE_NEUTRAL_MAP; + return 1; + } + if (unformat (input, "adjust-transport")) + { + *result = ILA_CSUM_MODE_ADJUST_TRANSPORT; + return 1; + } + return 0; +} + +static uword +unformat_half_ip6_address (unformat_input_t * input, va_list * args) +{ + u64 *result = va_arg (*args, u64 *); + u32 a[4]; + + if (!unformat (input, "%x:%x:%x:%x", &a[0], &a[1], &a[2], &a[3])) + return 0; + + if (a[0] > 0xFFFF || a[1] > 0xFFFF || a[2] > 0xFFFF || a[3] > 0xFFFF) + return 0; + + *result = clib_host_to_net_u64 ((((u64) a[0]) << 48) | + (((u64) a[1]) << 32) | + (((u64) a[2]) << 16) | (((u64) a[3]))); + + return 1; +} + +static vlib_node_registration_t ila_ila2sir_node; + +static uword +ila_ila2sir (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, next_index, *to_next, n_left_to_next; + ila_main_t *ilm = &ila_main; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + 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 pi0, pi1; + vlib_buffer_t *p0, *p1; + ila_entry_t *ie0, *ie1; + ip6_header_t *ip60, *ip61; + ip6_address_t *sir_address0, *sir_address1; + + { + 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, sizeof (ip6_header_t), LOAD); + CLIB_PREFETCH (p3->data, sizeof (ip6_header_t), LOAD); + } + + pi0 = to_next[0] = from[0]; + pi1 = to_next[1] = from[1]; + from += 2; + n_left_from -= 2; + to_next += 2; + n_left_to_next -= 2; + + p0 = vlib_get_buffer (vm, pi0); + p1 = vlib_get_buffer (vm, pi1); + ip60 = vlib_buffer_get_current (p0); + ip61 = vlib_buffer_get_current (p1); + sir_address0 = &ip60->dst_address; + sir_address1 = &ip61->dst_address; + ie0 = pool_elt_at_index (ilm->entries, + vnet_buffer (p0)->ip.adj_index[VLIB_TX]); + ie1 = pool_elt_at_index (ilm->entries, + vnet_buffer (p1)->ip.adj_index[VLIB_TX]); + + if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) + { + ila_ila2sir_trace_t *tr = + vlib_add_trace (vm, node, p0, sizeof (*tr)); + tr->ila_index = ie0 - ilm->entries; + tr->initial_dst = ip60->dst_address; + tr->adj_index = vnet_buffer (p0)->ip.adj_index[VLIB_TX]; + } + + if (PREDICT_FALSE (p1->flags & VLIB_BUFFER_IS_TRACED)) + { + ila_ila2sir_trace_t *tr = + vlib_add_trace (vm, node, p1, sizeof (*tr)); + tr->ila_index = ie1 - ilm->entries; + tr->initial_dst = ip61->dst_address; + tr->adj_index = vnet_buffer (p1)->ip.adj_index[VLIB_TX]; + } + + sir_address0 = (ie0->dir != ILA_DIR_SIR2ILA) ? &ie0->sir_address : sir_address0; + sir_address1 = (ie1->dir != ILA_DIR_SIR2ILA) ? &ie1->sir_address : sir_address1; + ip60->dst_address.as_u64[0] = sir_address0->as_u64[0]; + ip60->dst_address.as_u64[1] = sir_address0->as_u64[1]; + ip61->dst_address.as_u64[0] = sir_address1->as_u64[0]; + ip61->dst_address.as_u64[1] = sir_address1->as_u64[1]; + + vnet_buffer (p0)->ip.adj_index[VLIB_TX] = ie0->ila_dpo.dpoi_index; + vnet_buffer (p1)->ip.adj_index[VLIB_TX] = ie1->ila_dpo.dpoi_index; + + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, + n_left_to_next, pi0, pi1, + ie0->ila_dpo.dpoi_next_node, + ie1->ila_dpo.dpoi_next_node); + } + + /* Single loop */ + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 pi0; + vlib_buffer_t *p0; + ila_entry_t *ie0; + ip6_header_t *ip60; + ip6_address_t *sir_address0; + + 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); + ip60 = vlib_buffer_get_current (p0); + sir_address0 = &ip60->dst_address; + ie0 = pool_elt_at_index (ilm->entries, + vnet_buffer (p0)->ip.adj_index[VLIB_TX]); + + if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) + { + ila_ila2sir_trace_t *tr = + vlib_add_trace (vm, node, p0, sizeof (*tr)); + tr->ila_index = ie0 ? (ie0 - ilm->entries) : ~0; + tr->initial_dst = ip60->dst_address; + tr->adj_index = vnet_buffer (p0)->ip.adj_index[VLIB_TX]; + } + + sir_address0 = (ie0->dir != ILA_DIR_SIR2ILA) ? &ie0->sir_address : sir_address0; + ip60->dst_address.as_u64[0] = sir_address0->as_u64[0]; + ip60->dst_address.as_u64[1] = sir_address0->as_u64[1]; + vnet_buffer (p0)->ip.adj_index[VLIB_TX] = ie0->ila_dpo.dpoi_index; + + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, + n_left_to_next, pi0, + ie0->ila_dpo.dpoi_next_node); + } + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + +/** *INDENT-OFF* */ +VLIB_REGISTER_NODE (ila_ila2sir_node, static) = +{ + .function = ila_ila2sir, + .name = "ila-to-sir", + .vector_size = sizeof (u32), + .format_trace = format_ila_ila2sir_trace, + .n_errors = ILA_N_ERROR, + .error_strings = ila_error_strings, + .n_next_nodes = ILA_ILA2SIR_N_NEXT, + .next_nodes = + { + [ILA_ILA2SIR_NEXT_DROP] = "error-drop" + }, +}; +/** *INDENT-ON* */ + +typedef enum +{ + ILA_SIR2ILA_NEXT_DROP, + ILA_SIR2ILA_N_NEXT, +} ila_sir2ila_next_t; + +typedef struct +{ + u32 ila_index; + ip6_address_t initial_dst; +} ila_sir2ila_trace_t; + +u8 * +format_ila_sir2ila_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 *); + ila_sir2ila_trace_t *t = va_arg (*args, ila_sir2ila_trace_t *); + + return format (s, "SIR -> ILA entry index: %d initial_dst: %U", + t->ila_index, format_ip6_address, &t->initial_dst); +} + +static vlib_node_registration_t ila_sir2ila_node; + +static uword +ila_sir2ila (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, next_index, *to_next, n_left_to_next; + ila_main_t *ilm = &ila_main; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + 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 pi0, pi1; + vlib_buffer_t *p0, *p1; + ip6_header_t *ip60, *ip61; + u32 next0 = ILA_SIR2ILA_NEXT_DROP; + u32 next1 = ILA_SIR2ILA_NEXT_DROP; + BVT (clib_bihash_kv) kv0, value0; + BVT (clib_bihash_kv) kv1, value1; + ila_entry_t *ie0 = &ila_sir2ila_default_entry; + ila_entry_t *ie1 = &ila_sir2ila_default_entry; + ip6_address_t *ila_address0, *ila_address1; + + { + 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, sizeof (ip6_header_t), LOAD); + CLIB_PREFETCH (p3->data, sizeof (ip6_header_t), LOAD); + } + + pi0 = to_next[0] = from[0]; + pi1 = to_next[1] = from[1]; + from += 2; + n_left_from -= 2; + to_next += 2; + n_left_to_next -= 2; + + p0 = vlib_get_buffer (vm, pi0); + p1 = vlib_get_buffer (vm, pi1); + ip60 = vlib_buffer_get_current (p0); + ip61 = vlib_buffer_get_current (p1); + ila_address0 = &ip60->dst_address; + ila_address1 = &ip61->dst_address; + kv0.key[0] = ip60->dst_address.as_u64[0]; + kv0.key[1] = ip60->dst_address.as_u64[1]; + kv0.key[2] = 0; + kv1.key[0] = ip61->dst_address.as_u64[0]; + kv1.key[1] = ip61->dst_address.as_u64[1]; + kv1.key[2] = 0; + + if (PREDICT_TRUE((BV (clib_bihash_search) + (&ilm->id_to_entry_table, &kv0, &value0)) == 0)) { + ie0 = &ilm->entries[value0.value]; + ila_address0 = (ie0->dir != ILA_DIR_ILA2SIR) ? &ie0->ila_address : ila_address0; + } + + if ((BV (clib_bihash_search) + (&ilm->id_to_entry_table, &kv1, &value1)) == 0) { + ie1 = &ilm->entries[value1.value]; + ila_address1 = (ie1->dir != ILA_DIR_ILA2SIR) ? &ie1->ila_address : ila_address1; + } + + if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) + { + ila_sir2ila_trace_t *tr = + vlib_add_trace (vm, node, p0, sizeof (*tr)); + tr->ila_index = + (ie0 != &ila_sir2ila_default_entry) ? (ie0 - ilm->entries) : ~0; + tr->initial_dst = ip60->dst_address; + } + + if (PREDICT_FALSE (p1->flags & VLIB_BUFFER_IS_TRACED)) + { + ila_sir2ila_trace_t *tr = + vlib_add_trace (vm, node, p1, sizeof (*tr)); + tr->ila_index = + (ie1 != &ila_sir2ila_default_entry) ? (ie1 - ilm->entries) : ~0; + tr->initial_dst = ip61->dst_address; + } + + ip60->dst_address.as_u64[0] = ila_address0->as_u64[0]; + ip60->dst_address.as_u64[1] = ila_address0->as_u64[1]; + ip61->dst_address.as_u64[0] = ila_address1->as_u64[0]; + ip61->dst_address.as_u64[1] = ila_address1->as_u64[1]; + + vnet_feature_next (vnet_buffer (p0)->sw_if_index[VLIB_RX], &next0, p0); + vnet_feature_next (vnet_buffer (p1)->sw_if_index[VLIB_RX], &next1, p1); + + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, + n_left_to_next, pi0, pi1, next0, + next1); + } + + /* Single loop */ + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 pi0; + vlib_buffer_t *p0; + ip6_header_t *ip60; + u32 next0 = ILA_SIR2ILA_NEXT_DROP; + BVT (clib_bihash_kv) kv0, value0; + ila_entry_t *ie0 = &ila_sir2ila_default_entry; + ip6_address_t *ila_address0; + + 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); + ip60 = vlib_buffer_get_current (p0); + ila_address0 = &ip60->dst_address; + + kv0.key[0] = ip60->dst_address.as_u64[0]; + kv0.key[1] = ip60->dst_address.as_u64[1]; + kv0.key[2] = 0; + + if (PREDICT_TRUE((BV (clib_bihash_search) + (&ilm->id_to_entry_table, &kv0, &value0)) == 0)) { + ie0 = &ilm->entries[value0.value]; + ila_address0 = (ie0->dir != ILA_DIR_ILA2SIR) ? &ie0->ila_address : ila_address0; + } + + if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) + { + ila_sir2ila_trace_t *tr = + vlib_add_trace (vm, node, p0, sizeof (*tr)); + tr->ila_index = + (ie0 != &ila_sir2ila_default_entry) ? (ie0 - ilm->entries) : ~0; + tr->initial_dst = ip60->dst_address; + } + + //This operation should do everything for any type (except vnid4 obviously) + ip60->dst_address.as_u64[0] = ila_address0->as_u64[0]; + ip60->dst_address.as_u64[1] = ila_address0->as_u64[1]; + + vnet_feature_next (vnet_buffer (p0)->sw_if_index[VLIB_RX], &next0, p0); + + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, + n_left_to_next, pi0, next0); + } + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + +/** *INDENT-OFF* */ +VLIB_REGISTER_NODE (ila_sir2ila_node, static) = +{ + .function = ila_sir2ila,.name = "sir-to-ila", + .vector_size = sizeof (u32), + .format_trace = format_ila_sir2ila_trace, + .n_errors = ILA_N_ERROR, + .error_strings = ila_error_strings, + .n_next_nodes = ILA_SIR2ILA_N_NEXT, + .next_nodes = + { + [ILA_SIR2ILA_NEXT_DROP] = "error-drop" + }, +}; +/** *INDENT-ON* */ + +/** *INDENT-OFF* */ +VNET_FEATURE_INIT (ila_sir2ila, static) = +{ + .arc_name = "ip6-unicast", + .node_name = "sir-to-ila", + .runs_before = VNET_FEATURES ("ip6-lookup"), +}; +/** *INDENT-ON* */ + +static void +ila_entry_stack (ila_entry_t *ie) +{ + /* + * restack on the next-hop's FIB entry + */ + dpo_stack(ila_dpo_type, + DPO_PROTO_IP6, + &ie->ila_dpo, + fib_entry_contribute_ip_forwarding( + ie->next_hop_fib_entry_index)); +} + +int +ila_add_del_entry (ila_add_del_entry_args_t * args) +{ + ila_main_t *ilm = &ila_main; + BVT (clib_bihash_kv) kv, value; + + //Sanity check + if (args->type == ILA_TYPE_IID || args->type == ILA_TYPE_LUID) + { + if ((args->sir_address.as_u8[8] >> 5) != args->type) + { + clib_warning ("Incorrect SIR address (ILA type mismatch %d %d)", + args->sir_address.as_u8[8] >> 1, args->type); + return -1; + } + if (args->sir_address.as_u8[8] & 0x10) + { + clib_warning ("Checksum bit should not be set in SIR address"); + return -1; + } + } + else if (args->type == ILA_TYPE_VNIDM) + { + if (args->sir_address.as_u8[0] != 0xff || + (args->sir_address.as_u8[1] & 0xf0) != 0xf0) + { + clib_warning ("SIR multicast address must start with fff"); + return -1; + } + if (args->sir_address.as_u16[1] || args->sir_address.as_u16[2] || + args->sir_address.as_u16[3] || args->sir_address.as_u16[4] || + args->sir_address.as_u16[5] || (args->sir_address.as_u8[12] & 0xf0)) + { + clib_warning ("SIR multicast address must start with fff"); + return -1; + } + } + + if (!args->is_del) + { + ila_entry_t *e; + pool_get (ilm->entries, e); + e->type = args->type; + e->sir_address = args->sir_address; + e->next_hop = args->next_hop_address; + e->csum_mode = args->csum_mode; + e->dir = args->dir; + + //Construct ILA address + switch (e->type) + { + case ILA_TYPE_IID: + e->ila_address = e->sir_address; + break; + case ILA_TYPE_LUID: + e->ila_address.as_u64[0] = args->locator; + e->ila_address.as_u64[1] = args->sir_address.as_u64[1]; + break; + case ILA_TYPE_VNID6: + e->ila_address.as_u64[0] = args->locator; + e->ila_address.as_u8[8] = (ILA_TYPE_VNID6 << 1); + e->ila_address.as_u32[2] |= args->vnid; + e->ila_address.as_u32[3] = args->sir_address.as_u32[3]; + break; + case ILA_TYPE_VNIDM: + e->ila_address.as_u64[0] = args->locator; + e->ila_address.as_u8[8] = (ILA_TYPE_VNIDM << 1); + e->ila_address.as_u32[2] |= args->vnid; + e->ila_address.as_u32[3] = args->sir_address.as_u32[3]; + e->ila_address.as_u8[12] |= args->sir_address.as_u8[2] << 4; + break; + case ILA_TYPE_VNID4: + clib_warning ("ILA type '%U' is not supported", format_ila_type, + e->type); + return -1; + } + + //Modify ILA checksum if necessary + if (e->csum_mode == ILA_CSUM_MODE_NEUTRAL_MAP) + { + ip_csum_t csum = e->ila_address.as_u16[7]; + int i; + for (i = 0; i < 4; i++) + { + csum = ip_csum_sub_even (csum, e->sir_address.as_u32[i]); + csum = ip_csum_add_even (csum, e->ila_address.as_u32[i]); + } + csum = ip_csum_add_even (csum, clib_host_to_net_u16 (0x1000)); + e->ila_address.as_u16[7] = ip_csum_fold (csum); + e->ila_address.as_u8[8] |= 0x10; + } + + //Create entry with the sir address + kv.key[0] = e->sir_address.as_u64[0]; + kv.key[1] = e->sir_address.as_u64[1]; + kv.key[2] = 0; + kv.value = e - ilm->entries; + BV (clib_bihash_add_del) (&ilm->id_to_entry_table, &kv, + 1 /* is_add */ ); + + if (!ip6_address_is_zero(&e->next_hop)) + { + /* + * become a child of the FIB netry for the next-hop + * so we are informed when its forwarding changes + */ + fib_prefix_t next_hop = { + .fp_addr = { + .ip6 = e->next_hop, + }, + .fp_len = 128, + .fp_proto = FIB_PROTOCOL_IP6, + }; + + e->next_hop_fib_entry_index = + fib_table_entry_special_add(0, + &next_hop, + FIB_SOURCE_RR, + FIB_ENTRY_FLAG_NONE, + ADJ_INDEX_INVALID); + e->next_hop_child_index = + fib_entry_child_add(e->next_hop_fib_entry_index, + ila_fib_node_type, + e - ilm->entries); + + /* + * Create a route that results in the ILA entry + */ + dpo_id_t dpo = DPO_INVALID; + fib_prefix_t pfx = { + .fp_addr = { + .ip6 = e->ila_address, + }, + .fp_len = 128, + .fp_proto = FIB_PROTOCOL_IP6, + }; + + dpo_set(&dpo, ila_dpo_type, DPO_PROTO_IP6, e - ilm->entries); + + fib_table_entry_special_dpo_add(0, + &pfx, + FIB_SOURCE_PLUGIN_HI, + FIB_ENTRY_FLAG_EXCLUSIVE, + &dpo); + dpo_reset(&dpo); + + /* + * finally stack the ILA entry so it will forward to the next-hop + */ + ila_entry_stack (e); + } + } + else + { + ila_entry_t *e; + kv.key[0] = args->sir_address.as_u64[0]; + kv.key[1] = args->sir_address.as_u64[1]; + kv.key[2] = 0; + + if ((BV (clib_bihash_search) (&ilm->id_to_entry_table, &kv, &value) < + 0)) + { + return -1; + } + + e = &ilm->entries[value.value]; + + if (!ip6_address_is_zero(&e->next_hop)) + { + fib_prefix_t pfx = { + .fp_addr = { + .ip6 = e->ila_address, + }, + .fp_len = 128, + .fp_proto = FIB_PROTOCOL_IP6, + }; + + fib_table_entry_special_remove(0, &pfx, FIB_SOURCE_PLUGIN_HI); + /* + * remove this ILA entry as child of the FIB netry for the next-hop + */ + fib_entry_child_remove(e->next_hop_fib_entry_index, + e->next_hop_child_index); + fib_table_entry_delete_index(e->next_hop_fib_entry_index, + FIB_SOURCE_RR); + e->next_hop_fib_entry_index = FIB_NODE_INDEX_INVALID; + } + dpo_reset (&e->ila_dpo); + + BV (clib_bihash_add_del) (&ilm->id_to_entry_table, &kv, + 0 /* is_add */ ); + pool_put (ilm->entries, e); + } + return 0; +} + +int +ila_interface (u32 sw_if_index, u8 disable) +{ + vnet_feature_enable_disable ("ip4-unicast", "sir-to-ila", sw_if_index, + !disable, 0, 0); + 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_ila_dpo (u8 * s, va_list * va) +{ + index_t index = va_arg (*va, index_t); + CLIB_UNUSED(u32 indent) = va_arg (*va, u32); + ila_main_t *ilm = &ila_main; + ila_entry_t *ie = pool_elt_at_index (ilm->entries, index); + return format(s, "ILA: idx:%d sir:%U", + index, + format_ip6_address, &ie->sir_address); +} + +/** + * @brief no-op lock function. + * The lifetime of the ILA entry is managed by the control plane + */ +static void +ila_dpo_lock (dpo_id_t *dpo) +{ +} + +/** + * @brief no-op unlock function. + * The lifetime of the ILA entry is managed by the control plane + */ +static void +ila_dpo_unlock (dpo_id_t *dpo) +{ +} + +const static dpo_vft_t ila_vft = { + .dv_lock = ila_dpo_lock, + .dv_unlock = ila_dpo_unlock, + .dv_format = format_ila_dpo, +}; +const static char* const ila_ip6_nodes[] = +{ + "ila-to-sir", + NULL, +}; +const static char* const * const ila_nodes[DPO_PROTO_NUM] = +{ + [DPO_PROTO_IP6] = ila_ip6_nodes, +}; + +static fib_node_t * +ila_fib_node_get_node (fib_node_index_t index) +{ + ila_main_t *ilm = &ila_main; + ila_entry_t *ie = pool_elt_at_index (ilm->entries, index); + + return (&ie->ila_fib_node); +} + +/** + * @brief no-op unlock function. + * The lifetime of the ILA entry is managed by the control plane + */ +static void +ila_fib_node_last_lock_gone (fib_node_t *node) +{ +} + +static ila_entry_t * +ila_entry_from_fib_node (fib_node_t *node) +{ + return ((ila_entry_t*)(((char*)node) - + STRUCT_OFFSET_OF(ila_entry_t, ila_fib_node))); +} + +/** + * @brief + * Callback function invoked when the forwarding changes for the ILA next-hop + */ +static fib_node_back_walk_rc_t +ila_fib_node_back_walk_notify (fib_node_t *node, + fib_node_back_walk_ctx_t *ctx) +{ + ila_entry_stack(ila_entry_from_fib_node(node)); + + return (FIB_NODE_BACK_WALK_CONTINUE); +} + +/* + * ILA's FIB graph node virtual function table + */ +static const fib_node_vft_t ila_fib_node_vft = { + .fnv_get = ila_fib_node_get_node, + .fnv_last_lock = ila_fib_node_last_lock_gone, + .fnv_back_walk = ila_fib_node_back_walk_notify, +}; + +clib_error_t * +ila_init (vlib_main_t * vm) +{ + ila_main_t *ilm = &ila_main; + ilm->entries = NULL; + + ilm->lookup_table_nbuckets = ILA_TABLE_DEFAULT_HASH_NUM_BUCKETS; + ilm->lookup_table_nbuckets = 1 << max_log2 (ilm->lookup_table_nbuckets); + ilm->lookup_table_size = ILA_TABLE_DEFAULT_HASH_MEMORY_SIZE; + + BV (clib_bihash_init) (&ilm->id_to_entry_table, + "ila id to entry index table", + ilm->lookup_table_nbuckets, ilm->lookup_table_size); + + ila_dpo_type = dpo_register_new_type(&ila_vft, ila_nodes); + ila_fib_node_type = fib_node_register_new_type(&ila_fib_node_vft); + + return NULL; +} + +VLIB_INIT_FUNCTION (ila_init); + +static clib_error_t * +ila_entry_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + ila_add_del_entry_args_t args = { 0 }; + u8 next_hop_set = 0; + int ret; + + args.type = ILA_TYPE_IID; + args.csum_mode = ILA_CSUM_MODE_NO_ACTION; + args.local_adj_index = ~0; + args.dir = ILA_DIR_BIDIR; + + 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, "type %U", unformat_ila_type, &args.type)) + ; + else if (unformat + (line_input, "sir-address %U", unformat_ip6_address, + &args.sir_address)) + ; + else if (unformat + (line_input, "locator %U", unformat_half_ip6_address, + &args.locator)) + ; + else if (unformat + (line_input, "csum-mode %U", unformat_ila_csum_mode, + &args.csum_mode)) + ; + else if (unformat (line_input, "vnid %x", &args.vnid)) + ; + else if (unformat + (line_input, "next-hop %U", unformat_ip6_address, + &args.next_hop_address)) + ; + else if (unformat + (line_input, "direction %U", unformat_ila_direction, &args.dir)) + next_hop_set = 1; + else if (unformat (line_input, "del")) + args.is_del = 1; + else + return clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + } + + unformat_free (line_input); + + if (!next_hop_set) + return clib_error_return (0, "Specified a next hop"); + + if ((ret = ila_add_del_entry (&args))) + return clib_error_return (0, "ila_add_del_entry returned error %d", ret); + + return NULL; +} + +VLIB_CLI_COMMAND (ila_entry_command, static) = +{ + .path = "ila entry", + .short_help = "ila entry [type ] [sir-address
] [locator ] [vnid ]" + " [adj-index ] [next-hop ] [direction (bidir|sir2ila|ila2sir)]" + " [csum-mode (no-action|neutral-map|transport-adjust)] [del]", + .function = ila_entry_command_fn, +}; + +static clib_error_t * +ila_interface_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + u32 sw_if_index = ~0; + u8 disable = 0; + + if (!unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index)) + { + return clib_error_return (0, "Invalid interface name"); + } + + if (unformat (input, "disable")) + { + disable = 1; + } + + int ret; + if ((ret = ila_interface (sw_if_index, disable))) + return clib_error_return (0, "ila_interface returned error %d", ret); + + return NULL; +} + +VLIB_CLI_COMMAND (ila_interface_command, static) = +{ + .path = "ila interface", + .short_help = "ila interface [disable]", + .function = ila_interface_command_fn, +}; + +static clib_error_t * +ila_show_entries_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + ila_main_t *ilm = &ila_main; + ila_entry_t *e; + + vlib_cli_output (vm, " %U\n", format_ila_entry, vnm, NULL); + pool_foreach (e, ilm->entries, + ({ + vlib_cli_output (vm, " %U\n", format_ila_entry, vnm, e); + })); + + return NULL; +} + +VLIB_CLI_COMMAND (ila_show_entries_command, static) = +{ + .path = "show ila entries", + .short_help = "show ila entries", + .function = ila_show_entries_command_fn, +}; diff --git a/src/plugins/ila/ila.h b/src/plugins/ila/ila.h new file mode 100644 index 00000000..26620983 --- /dev/null +++ b/src/plugins/ila/ila.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 ILA_H +#define ILA_H + +#include +#include +#include + +#include +#include + +#define ila_foreach_type \ + _(IID, 0, "iid") \ + _(LUID, 1, "luid") \ + _(VNID4, 2, "vnid-ip4") \ + _(VNID6, 3, "vnid-ip6") \ + _(VNIDM, 4, "vnid-multicast") + +typedef enum { +#define _(i,n,s) ILA_TYPE_##i = n, + ila_foreach_type +#undef _ +} ila_type_t; + +#define ila_csum_foreach_type \ +_(NO_ACTION, 0, "no-action") \ +_(NEUTRAL_MAP, 1, "neutral-map") \ +_(ADJUST_TRANSPORT, 2, "adjust-transport") + +typedef enum { +#define _(i,n,s) ILA_CSUM_MODE_##i = n, + ila_csum_foreach_type +#undef _ + ILA_CSUM_N_TYPES +} ila_csum_mode_t; + +#define ila_foreach_direction \ +_(BIDIR, 0, "bidir") \ +_(SIR2ILA, 1, "sir2ila") \ +_(ILA2SIR, 2, "ila2sir") + +typedef enum { +#define _(i,n,s) ILA_DIR_##i = n, + ila_foreach_direction +#undef _ +} ila_direction_t; + +typedef struct { + /** + * Fib Node base class + */ + fib_node_t ila_fib_node; + ila_type_t type; + ip6_address_t sir_address; + ip6_address_t ila_address; + ip6_address_t next_hop; + ila_csum_mode_t csum_mode; + ila_direction_t dir; + + /** + * 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 grpah to follow + */ + dpo_id_t ila_dpo; +} ila_entry_t; + +typedef struct { + ila_entry_t *entries; //Pool of ILA entries + + u64 lookup_table_nbuckets; + u64 lookup_table_size; + clib_bihash_24_8_t id_to_entry_table; + + u32 ip6_lookup_next_index; +} ila_main_t; + + +typedef struct { + ila_type_t type; + ip6_address_t sir_address; + ip6_address_t next_hop_address; + u64 locator; + u32 vnid; + u32 local_adj_index; + ila_csum_mode_t csum_mode; + ila_direction_t dir; + u8 is_del; +} ila_add_del_entry_args_t; + +int ila_add_del_entry (ila_add_del_entry_args_t * args); +int ila_interface (u32 sw_if_index, u8 disable); + +#endif //ILA_H diff --git a/src/plugins/sixrd.am b/src/plugins/sixrd.am new file mode 100644 index 00000000..0de45088 --- /dev/null +++ b/src/plugins/sixrd.am @@ -0,0 +1,26 @@ +# 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. + +libsixrd_plugin_la_SOURCES = \ + sixrd/sixrd.c \ + sixrd/sixrd_dpo.c \ + sixrd/ip4_sixrd.c \ + sixrd/ip6_sixrd.c + +noinst_HEADERS += \ + sixrd/sixrd.h \ + sixrd/sixrd_dpo.h + +vppplugins_LTLIBRARIES += libsixrd_plugin.la + +# vi:syntax=automake diff --git a/src/plugins/sixrd/ip4_sixrd.c b/src/plugins/sixrd/ip4_sixrd.c new file mode 100644 index 00000000..2fb8015d --- /dev/null +++ b/src/plugins/sixrd/ip4_sixrd.c @@ -0,0 +1,127 @@ +/*--------------------------------------------------------------------------- + * 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 "sixrd.h" + +static vlib_node_registration_t ip4_sixrd_node; + +typedef enum { + IP4_SIXRD_NEXT_IP6_LOOKUP, + IP4_SIXRD_NEXT_DROP, + IP4_SIXRD_N_NEXT, +} ip4_sixrd_next_t; + +/* + * ip4_sixrd_sec_check + */ +static_always_inline void +ip4_sixrd_sec_check (sixrd_domain_t *d, ip4_address_t sa4, ip6_address_t sa6, u8 *error) +{ + u32 a = sixrd_get_addr(d, sa6.as_u64[0]); + clib_warning("Security check: %U %U", format_ip4_address, &a, format_ip4_address, &sa4); + if (PREDICT_FALSE(sixrd_get_addr(d, sa6.as_u64[0]) != sa4.as_u32)) + *error = SIXRD_ERROR_SEC_CHECK; +} + +/* + * ip4_sixrd + */ +static uword +ip4_sixrd (vlib_main_t *vm, + vlib_node_runtime_t *node, + vlib_frame_t *frame) +{ + u32 n_left_from, *from, next_index, *to_next, n_left_to_next; + vlib_node_runtime_t *error_node = vlib_node_get_runtime(vm, ip4_sixrd_node.index); + u32 decap = 0; + + from = vlib_frame_vector_args(frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + while (n_left_from > 0) { + vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next); + + /* Single loop */ + while (n_left_from > 0 && n_left_to_next > 0) { + u32 pi0; + vlib_buffer_t *p0; + u8 error0 = SIXRD_ERROR_NONE; + sixrd_domain_t *d0 = 0; + ip4_header_t *ip40; + ip6_header_t *ip60; + u32 sixrd_domain_index0 = ~0; + u32 next0; + + 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); + ip40 = vlib_buffer_get_current(p0); + + /* Throw away anything that isn't IP in IP. */ + if (PREDICT_TRUE(ip40->protocol == IP_PROTOCOL_IPV6 && clib_net_to_host_u16(ip40->length) >= 60)) { + vlib_buffer_advance(p0, sizeof(ip4_header_t)); + ip60 = vlib_buffer_get_current(p0); + d0 = ip4_sixrd_get_domain(vnet_buffer(p0)->ip.adj_index[VLIB_TX], (ip6_address_t *)&ip60->src_address, + &sixrd_domain_index0, &error0); + } else { + error0 = SIXRD_ERROR_BAD_PROTOCOL; + } + if (d0) { + /* SIXRD inbound security check */ + ip4_sixrd_sec_check(d0, ip40->src_address, ip60->src_address, &error0); + } + + next0 = error0 == SIXRD_ERROR_NONE ? IP4_SIXRD_NEXT_IP6_LOOKUP : IP4_SIXRD_NEXT_DROP; + + if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED)) { + sixrd_trace_t *tr = vlib_add_trace(vm, node, p0, sizeof(*tr)); + tr->sixrd_domain_index = sixrd_domain_index0; + } + + p0->error = error_node->errors[error0]; + if (PREDICT_TRUE(error0 == SIXRD_ERROR_NONE)) decap++; + vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, pi0, next0); + + } + vlib_put_next_frame(vm, node, next_index, n_left_to_next); + } + vlib_node_increment_counter(vm, ip4_sixrd_node.index, SIXRD_ERROR_DECAPSULATED, decap); + + return frame->n_vectors; +} + +static char *sixrd_error_strings[] = { +#define _(sym,string) string, + foreach_sixrd_error +#undef _ +}; + +VLIB_REGISTER_NODE(ip4_sixrd_node,static) = { + .function = ip4_sixrd, + .name = "ip4-sixrd", + .vector_size = sizeof(u32), + .format_trace = format_sixrd_trace, + .n_errors = SIXRD_N_ERROR, + .error_strings = sixrd_error_strings, + .n_next_nodes = IP4_SIXRD_N_NEXT, + .next_nodes = { + [IP4_SIXRD_NEXT_IP6_LOOKUP] = "ip6-lookup", + [IP4_SIXRD_NEXT_DROP] = "error-drop", + }, +}; diff --git a/src/plugins/sixrd/ip6_sixrd.c b/src/plugins/sixrd/ip6_sixrd.c new file mode 100644 index 00000000..36f3fab3 --- /dev/null +++ b/src/plugins/sixrd/ip6_sixrd.c @@ -0,0 +1,129 @@ +/*--------------------------------------------------------------------------- + * 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. + *--------------------------------------------------------------------------- + */ +/* + * Defines used for testing various optimisation schemes + */ +#define SIXRD_ENCAP_DUAL 0 + +#include "sixrd.h" + +static vlib_node_registration_t ip6_sixrd_node; + +typedef enum { + IP6_SIXRD_NEXT_IP4_LOOKUP, + IP6_SIXRD_NEXT_DROP, + IP6_SIXRD_N_NEXT, +} ip6_sixrd_next_t; + +/* + * ip6_sixrd + */ +static uword +ip6_sixrd (vlib_main_t *vm, + vlib_node_runtime_t *node, + vlib_frame_t *frame) +{ + u32 n_left_from, *from, next_index, *to_next, n_left_to_next; + vlib_node_runtime_t *error_node = vlib_node_get_runtime(vm, ip6_sixrd_node.index); + u32 encap = 0; + from = vlib_frame_vector_args(frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + 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; + sixrd_domain_t *d0; + u8 error0 = SIXRD_ERROR_NONE; + ip6_header_t *ip60; + ip4_header_t *ip4h0; + u32 next0 = IP6_SIXRD_NEXT_IP4_LOOKUP; + u32 sixrd_domain_index0 = ~0; + + 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); + ip60 = vlib_buffer_get_current(p0); + // p0->current_length = clib_net_to_host_u16(ip40->length); + d0 = ip6_sixrd_get_domain(vnet_buffer(p0)->ip.adj_index[VLIB_TX], &sixrd_domain_index0); + ASSERT(d0); + + /* SIXRD calc */ + u64 dal60 = clib_net_to_host_u64(ip60->dst_address.as_u64[0]); + u32 da40 = sixrd_get_addr(d0, dal60); + u16 len = clib_net_to_host_u16(ip60->payload_length) + 60; + if (da40 == 0) error0 = SIXRD_ERROR_UNKNOWN; + + /* construct ipv4 header */ + vlib_buffer_advance(p0, - (sizeof(ip4_header_t))); + ip4h0 = vlib_buffer_get_current(p0); + vnet_buffer(p0)->sw_if_index[VLIB_TX] = (u32)~0; + ip4h0->ip_version_and_header_length = 0x45; + ip4h0->tos = 0; + ip4h0->length = clib_host_to_net_u16(len); + ip4h0->fragment_id = 0; + ip4h0->flags_and_fragment_offset = 0; + ip4h0->ttl = 0x40; + ip4h0->protocol = IP_PROTOCOL_IPV6; + ip4h0->src_address = d0->ip4_src; + ip4h0->dst_address.as_u32 = clib_host_to_net_u32(da40); + ip4h0->checksum = ip4_header_checksum(ip4h0); + + next0 = error0 == SIXRD_ERROR_NONE ? IP6_SIXRD_NEXT_IP4_LOOKUP : IP6_SIXRD_NEXT_DROP; + + if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED)) { + sixrd_trace_t *tr = vlib_add_trace(vm, node, p0, sizeof(*tr)); + tr->sixrd_domain_index = sixrd_domain_index0; + } + + p0->error = error_node->errors[error0]; + if (PREDICT_TRUE(error0 == SIXRD_ERROR_NONE)) encap++; + + vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, pi0, next0); + } + vlib_put_next_frame(vm, node, next_index, n_left_to_next); + } + vlib_node_increment_counter(vm, ip6_sixrd_node.index, SIXRD_ERROR_ENCAPSULATED, encap); + + return frame->n_vectors; +} + +static char *sixrd_error_strings[] = { +#define _(sym,string) string, + foreach_sixrd_error +#undef _ +}; + +VLIB_REGISTER_NODE(ip6_sixrd_node,static) = { + .function = ip6_sixrd, + .name = "ip6-sixrd", + .vector_size = sizeof(u32), + .format_trace = format_sixrd_trace, + .n_errors = SIXRD_N_ERROR, + .error_strings = sixrd_error_strings, + .n_next_nodes = IP6_SIXRD_N_NEXT, + .next_nodes = { + [IP6_SIXRD_NEXT_IP4_LOOKUP] = "ip4-lookup", + [IP6_SIXRD_NEXT_DROP] = "error-drop", + }, +}; diff --git a/src/plugins/sixrd/sixrd.c b/src/plugins/sixrd/sixrd.c new file mode 100644 index 00000000..66e631a2 --- /dev/null +++ b/src/plugins/sixrd/sixrd.c @@ -0,0 +1,369 @@ +/* + * 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 "sixrd.h" +#include + +#include +#include +#include + +/* + * This code supports the following sixrd modes: + * + * 32 EA bits (Complete IPv4 address is embedded): + * ea_bits_len = 32 + * IPv4 suffix is embedded: + * ea_bits_len = < 32 + * No embedded address bits (1:1 mode): + * ea_bits_len = 0 + */ + +int +sixrd_create_domain (ip6_address_t *ip6_prefix, + u8 ip6_prefix_len, + ip4_address_t *ip4_prefix, + u8 ip4_prefix_len, + ip4_address_t *ip4_src, + u32 *sixrd_domain_index, + u16 mtu) +{ + dpo_id_t dpo_v6 = DPO_INVALID, dpo_v4 = DPO_INVALID; + sixrd_main_t *mm = &sixrd_main; + fib_node_index_t fei; + sixrd_domain_t *d; + + /* Get domain index */ + pool_get_aligned(mm->domains, d, CLIB_CACHE_LINE_BYTES); + memset(d, 0, sizeof (*d)); + *sixrd_domain_index = d - mm->domains; + + /* Init domain struct */ + d->ip4_prefix.as_u32 = ip4_prefix->as_u32; + d->ip4_prefix_len = ip4_prefix_len; + d->ip6_prefix = *ip6_prefix; + d->ip6_prefix_len = ip6_prefix_len; + d->ip4_src = *ip4_src; + d->mtu = mtu; + + if (ip4_prefix_len < 32) + d->shift = 64 - ip6_prefix_len + (32 - ip4_prefix_len); + + /* Create IPv6 route/adjacency */ + fib_prefix_t pfx6 = { + .fp_proto = FIB_PROTOCOL_IP6, + .fp_len = d->ip6_prefix_len, + .fp_addr = { + .ip6 = d->ip6_prefix, + }, + }; + sixrd_dpo_create(DPO_PROTO_IP6, + *sixrd_domain_index, + &dpo_v6); + fib_table_entry_special_dpo_add(0, &pfx6, + FIB_SOURCE_SIXRD, + FIB_ENTRY_FLAG_EXCLUSIVE, + &dpo_v6); + dpo_reset (&dpo_v6); + + /* + * Multiple SIXRD domains may share same source IPv4 TEP + * In this case the route will exist and be SixRD sourced. + * Find the adj (if any) already contributed and modify it + */ + fib_prefix_t pfx4 = { + .fp_proto = FIB_PROTOCOL_IP4, + .fp_len = 32, + .fp_addr = { + .ip4 = d->ip4_src, + }, + }; + fei = fib_table_lookup_exact_match(0, &pfx4); + + if (FIB_NODE_INDEX_INVALID != fei) + { + dpo_id_t dpo = DPO_INVALID; + + if (fib_entry_get_dpo_for_source (fei, FIB_SOURCE_SIXRD, &dpo)) + { + /* + * modify the existing adj to indicate it's shared + * skip to route add. + * It is locked to pair with the unlock below. + */ + const dpo_id_t *sd_dpo; + sixrd_dpo_t *sd; + + ASSERT(DPO_LOAD_BALANCE == dpo.dpoi_type); + + sd_dpo = load_balance_get_bucket(dpo.dpoi_index, 0); + sd = sixrd_dpo_get (sd_dpo->dpoi_index); + + sd->sd_domain = ~0; + dpo_copy (&dpo_v4, sd_dpo); + dpo_reset (&dpo); + + goto route_add; + } + } + /* first time addition of the route */ + sixrd_dpo_create(DPO_PROTO_IP4, + *sixrd_domain_index, + &dpo_v4); + +route_add: + /* + * Create ip4 route. This is a reference counted add. If the prefix + * already exists and is SixRD sourced, it is now SixRD source n+1 times + * and will need to be removed n+1 times. + */ + fib_table_entry_special_dpo_add(0, &pfx4, + FIB_SOURCE_SIXRD, + FIB_ENTRY_FLAG_EXCLUSIVE, + &dpo_v4); + dpo_reset (&dpo_v4); + + return 0; +} + +/* + * sixrd_delete_domain + */ +int +sixrd_delete_domain (u32 sixrd_domain_index) +{ + sixrd_main_t *mm = &sixrd_main; + sixrd_domain_t *d; + + if (pool_is_free_index(mm->domains, sixrd_domain_index)) { + clib_warning("SIXRD domain delete: domain does not exist: %d", + sixrd_domain_index); + return -1; + } + + d = pool_elt_at_index(mm->domains, sixrd_domain_index); + + fib_prefix_t pfx = { + .fp_proto = FIB_PROTOCOL_IP4, + .fp_len = 32, + .fp_addr = { + .ip4 = d->ip4_src, + }, + }; + fib_table_entry_special_remove(0, &pfx, FIB_SOURCE_SIXRD); + + fib_prefix_t pfx6 = { + .fp_proto = FIB_PROTOCOL_IP6, + .fp_len = d->ip6_prefix_len, + .fp_addr = { + .ip6 = d->ip6_prefix, + }, + }; + fib_table_entry_special_remove(0, &pfx6, FIB_SOURCE_SIXRD); + + pool_put(mm->domains, d); + + return 0; +} + +static clib_error_t * +sixrd_add_domain_command_fn (vlib_main_t *vm, + unformat_input_t *input, + vlib_cli_command_t *cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + ip4_address_t ip4_prefix; + ip6_address_t ip6_prefix; + ip4_address_t ip4_src; + u32 ip6_prefix_len=0, ip4_prefix_len=0, sixrd_domain_index; + u32 num_m_args = 0; + /* Optional arguments */ + u32 mtu = 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, "ip6-pfx %U/%d", unformat_ip6_address, &ip6_prefix, &ip6_prefix_len)) + num_m_args++; + else if (unformat(line_input, "ip4-pfx %U/%d", unformat_ip4_address, &ip4_prefix, &ip4_prefix_len)) + num_m_args++; + else if (unformat(line_input, "ip4-src %U", unformat_ip4_address, &ip4_src)) + num_m_args++; + else if (unformat(line_input, "mtu %d", &mtu)) + num_m_args++; + else + return clib_error_return(0, "unknown input `%U'", + format_unformat_error, input); + } + unformat_free(line_input); + + if (num_m_args < 3) + return clib_error_return(0, "mandatory argument(s) missing"); + + sixrd_create_domain(&ip6_prefix, ip6_prefix_len, &ip4_prefix, ip4_prefix_len, + &ip4_src, &sixrd_domain_index, mtu); + + return 0; +} + +static clib_error_t * +sixrd_del_domain_command_fn (vlib_main_t *vm, + unformat_input_t *input, + vlib_cli_command_t *cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + u32 num_m_args = 0; + u32 sixrd_domain_index; + + /* 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, "index %d", &sixrd_domain_index)) + num_m_args++; + else + return clib_error_return(0, "unknown input `%U'", + format_unformat_error, input); + } + unformat_free(line_input); + + if (num_m_args != 1) + return clib_error_return(0, "mandatory argument(s) missing"); + + sixrd_delete_domain(sixrd_domain_index); + + return 0; +} + +static u8 * +format_sixrd_domain (u8 *s, va_list *args) +{ + sixrd_domain_t *d = va_arg(*args, sixrd_domain_t *); + sixrd_main_t *mm = &sixrd_main; + + s = format(s, + "[%d] ip6-pfx %U/%d ip4-pfx %U/%d ip4-src %U mtu %d", + d - mm->domains, + format_ip6_address, &d->ip6_prefix, d->ip6_prefix_len, + format_ip4_address, &d->ip4_prefix, d->ip4_prefix_len, + format_ip4_address, &d->ip4_src, d->mtu); + + return s; +} + +static clib_error_t * +show_sixrd_domain_command_fn (vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd) +{ + sixrd_main_t *mm = &sixrd_main; + sixrd_domain_t *d; + + if (pool_elts(mm->domains) == 0) + vlib_cli_output(vm, "No SIXRD domains are configured..."); + + pool_foreach(d, mm->domains, ({vlib_cli_output(vm, "%U", format_sixrd_domain, d);})); + + return 0; + +} + +static clib_error_t * +show_sixrd_stats_command_fn (vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd) +{ + sixrd_main_t *mm = &sixrd_main; + sixrd_domain_t *d; + int domains = 0, domaincount = 0; + if (pool_elts (mm->domains) == 0) + vlib_cli_output (vm, "No SIXRD domains are configured..."); + + pool_foreach(d, mm->domains, ({ + domains += sizeof(*d); + domaincount++; + })); + + vlib_cli_output(vm, "SIXRD domains structure: %d\n", sizeof (sixrd_domain_t)); + vlib_cli_output(vm, "SIXRD domains: %d (%d bytes)\n", domaincount, domains); + + return 0; +} + +/* + * packet trace format function + */ +u8 * +format_sixrd_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 *); + sixrd_trace_t *t = va_arg (*args, sixrd_trace_t *); + u32 sixrd_domain_index = t->sixrd_domain_index; + + s = format(s, "SIXRD domain index: %d", sixrd_domain_index); + + return s; +} + +VLIB_CLI_COMMAND(sixrd_add_domain_command, static) = { + .path = "sixrd add domain", + .short_help = + "sixrd add domain ip6-pfx ip4-pfx ip4-src ", + .function = sixrd_add_domain_command_fn, +}; + +VLIB_CLI_COMMAND(sixrd_del_command, static) = { + .path = "sixrd del domain", + .short_help = + "sixrd del domain index ", + .function = sixrd_del_domain_command_fn, +}; + +VLIB_CLI_COMMAND(show_sixrd_domain_command, static) = { + .path = "show sixrd domain", + .function = show_sixrd_domain_command_fn, +}; + +VLIB_CLI_COMMAND(show_sixrd_stats_command, static) = { + .path = "show sixrd stats", + .function = show_sixrd_stats_command_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; + sixrd_main_t *mm = &sixrd_main; + + mm->vnet_main = vnet_get_main(); + mm->vlib_main = vm; + + return error; +} + +static clib_error_t * sixrd_init (vlib_main_t * vm) +{ + sixrd_dpo_module_init (); + + return (NULL); +} + +VLIB_INIT_FUNCTION (sixrd_init); diff --git a/src/plugins/sixrd/sixrd.h b/src/plugins/sixrd/sixrd.h new file mode 100644 index 00000000..56714c9e --- /dev/null +++ b/src/plugins/sixrd/sixrd.h @@ -0,0 +1,141 @@ +/*--------------------------------------------------------------------------- + * 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 "sixrd_dpo.h" + +int sixrd_create_domain(ip6_address_t *ip6_prefix, u8 ip6_prefix_len, + ip4_address_t *ip4_prefix, u8 ip4_prefix_len, + ip4_address_t *ip4_src, u32 *sixrd_domain_index, u16 mtu); +int sixrd_delete_domain(u32 sixrd_domain_index); +u8 *format_sixrd_trace(u8 *s, va_list *args); + +typedef struct { + ip6_address_t ip6_prefix; + ip4_address_t ip4_prefix; + ip4_address_t ip4_src; + u8 ip6_prefix_len; + u8 ip4_prefix_len; + + /* helpers */ + u8 shift; + + u16 mtu; +} sixrd_domain_t; + +typedef struct { + /* pool of SIXRD domains */ + sixrd_domain_t *domains; + + /* convenience */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} sixrd_main_t; + +#define foreach_sixrd_error \ + /* Must be first. */ \ + _(NONE, "valid SIXRD packets") \ + _(BAD_PROTOCOL, "bad protocol") \ + _(WRONG_ICMP_TYPE, "wrong icmp type") \ + _(SEC_CHECK, "security check failed") \ + _(ICMP, "unable to translate ICMP") \ + _(UNKNOWN, "unknown") \ + _(NO_DOMAIN, "no domain") \ + _(ENCAPSULATED, "encapsulated") \ + _(DECAPSULATED, "decapsulated") \ + _(TRANSLATED_4TO6, "translated 4 to 6") \ + _(TRANSLATED_6TO4, "translated 6 to 4") \ + _(FRAGMENT, "fragment handling error") \ + _(FRAGMENT_QUEUED, "dropped, missing first fragment") \ + _(FRAGMENTED, "packets requiring fragmentation") \ + _(FRAGMENT_PARTS, "fragment parts") \ + _(MALFORMED, "malformed packet") + +typedef enum { +#define _(sym,str) SIXRD_ERROR_##sym, + foreach_sixrd_error +#undef _ + SIXRD_N_ERROR, + } sixrd_error_t; + +typedef struct { + u32 sixrd_domain_index; +} sixrd_trace_t; + +sixrd_main_t sixrd_main; + +/* + * sixrd_get_addr + */ +static_always_inline u32 +sixrd_get_addr (sixrd_domain_t *d, u64 dal) +{ + + /* 1:1 mode */ + if (d->ip4_prefix_len == 32) return (d->ip4_prefix.as_u32); + + /* Grab 32 - ip4_prefix_len bits out of IPv6 address from offset ip6_prefix_len */ + return (d->ip4_prefix.as_u32 | (u32)(dal >> d->shift)); +} + +/* + * Get the SIXRD domain from an IPv6 lookup adjacency. + */ +static_always_inline sixrd_domain_t * +ip6_sixrd_get_domain (u32 sdi, u32 *sixrd_domain_index) +{ + sixrd_main_t *mm = &sixrd_main; + sixrd_dpo_t *sd; + + sd = sixrd_dpo_get(sdi); + + ASSERT(sd); + *sixrd_domain_index = sd->sd_domain; + return pool_elt_at_index(mm->domains, *sixrd_domain_index); +} + +/* + * Get the SIXRD domain from an IPv4 lookup adjacency. + * If the IPv4 address is not shared, no lookup is required. + * The IPv6 address is used otherwise. + */ +static_always_inline sixrd_domain_t * +ip4_sixrd_get_domain (u32 sdi, ip6_address_t *addr, + u32 *sixrd_domain_index, u8 *error) +{ + sixrd_main_t *mm = &sixrd_main; + sixrd_dpo_t *sd; + + sd = sixrd_dpo_get(sdi); + *sixrd_domain_index = sd->sd_domain; + if (*sixrd_domain_index != ~0) + return pool_elt_at_index(mm->domains, *sixrd_domain_index); + + u32 lbi = ip6_fib_table_fwding_lookup(&ip6_main, 0, addr); + const dpo_id_t *dpo = load_balance_get_bucket(lbi, 0); + if (PREDICT_TRUE(dpo->dpoi_type == sixrd_dpo_type)) + { + sd = sixrd_dpo_get(dpo->dpoi_index); + *sixrd_domain_index = sd->sd_domain; + return pool_elt_at_index(mm->domains, *sixrd_domain_index); + } + *error = SIXRD_ERROR_NO_DOMAIN; + return NULL; +} diff --git a/src/plugins/sixrd/sixrd_dpo.c b/src/plugins/sixrd/sixrd_dpo.c new file mode 100644 index 00000000..88a07935 --- /dev/null +++ b/src/plugins/sixrd/sixrd_dpo.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 "sixrd_dpo.h" +#include + +/** + * pool of all MPLS Label DPOs + */ +sixrd_dpo_t *sixrd_dpo_pool; + +/** + * The register SIXRD DPO type + */ +dpo_type_t sixrd_dpo_type; + +static sixrd_dpo_t * +sixrd_dpo_alloc (void) +{ + sixrd_dpo_t *sd; + + pool_get_aligned(sixrd_dpo_pool, sd, CLIB_CACHE_LINE_BYTES); + memset(sd, 0, sizeof(*sd)); + + return (sd); +} + +static index_t +sixrd_dpo_get_index (sixrd_dpo_t *sd) +{ + return (sd - sixrd_dpo_pool); +} + +void +sixrd_dpo_create (dpo_proto_t dproto, + u32 domain_index, + dpo_id_t *dpo) +{ + sixrd_dpo_t *sd; + + sd = sixrd_dpo_alloc(); + sd->sd_domain = domain_index; + sd->sd_proto = dproto; + + dpo_set(dpo, + sixrd_dpo_type, + dproto, + sixrd_dpo_get_index(sd)); +} + +u8* +format_sixrd_dpo (u8 *s, va_list *args) +{ + index_t index = va_arg (*args, index_t); + CLIB_UNUSED(u32 indent) = va_arg (*args, u32); + sixrd_dpo_t *sd; + + sd = sixrd_dpo_get(index); + + return (format(s, "sixrd:[%d]:%U domain:%d", + index, + format_dpo_proto, sd->sd_proto, + sd->sd_domain)); +} + + +static void +sixrd_dpo_lock (dpo_id_t *dpo) +{ + sixrd_dpo_t *sd; + + sd = sixrd_dpo_get(dpo->dpoi_index); + + sd->sd_locks++; +} + +static void +sixrd_dpo_unlock (dpo_id_t *dpo) +{ + sixrd_dpo_t *sd; + + sd = sixrd_dpo_get(dpo->dpoi_index); + + sd->sd_locks--; + + if (0 == sd->sd_locks) + { + pool_put(sixrd_dpo_pool, sd); + } +} + +const static dpo_vft_t sd_vft = { + .dv_lock = sixrd_dpo_lock, + .dv_unlock = sixrd_dpo_unlock, + .dv_format = format_sixrd_dpo, +}; + +const static char* const sixrd_ip4_nodes[] = +{ + "ip4-sixrd", + NULL, +}; +const static char* const sixrd_ip6_nodes[] = +{ + "ip6-sixrd", + NULL, +}; + +const static char* const * const sixrd_nodes[DPO_PROTO_NUM] = +{ + [DPO_PROTO_IP4] = sixrd_ip4_nodes, + [DPO_PROTO_IP6] = sixrd_ip6_nodes, + [DPO_PROTO_MPLS] = NULL, +}; + +void +sixrd_dpo_module_init (void) +{ + sixrd_dpo_type = dpo_register_new_type(&sd_vft, sixrd_nodes); +} diff --git a/src/plugins/sixrd/sixrd_dpo.h b/src/plugins/sixrd/sixrd_dpo.h new file mode 100644 index 00000000..17142288 --- /dev/null +++ b/src/plugins/sixrd/sixrd_dpo.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 __SIXRD_DPO_H__ +#define __SIXRD_DPO_H__ + +#include +#include + +/** + * A representation of a 6RD DPO + */ +typedef struct sixrd_dpo_t +{ + /** + * The dat-plane protocol + */ + dpo_proto_t sd_proto; + + /** + * the SIXRD domain index + */ + u32 sd_domain; + + /** + * Number of locks/users of the label + */ + u16 sd_locks; +} sixrd_dpo_t; + +extern void sixrd_dpo_create (dpo_proto_t dproto, + u32 domain_index, + dpo_id_t *dpo); + +/* + * Encapsulation violation for fast data-path access + */ +extern sixrd_dpo_t *sixrd_dpo_pool; +extern dpo_type_t sixrd_dpo_type; + +static inline sixrd_dpo_t * +sixrd_dpo_get (index_t index) +{ + return (pool_elt_at_index(sixrd_dpo_pool, index)); +} + +extern void sixrd_dpo_module_init(void); + +#endif diff --git a/src/scripts/vnet/arp4 b/src/scripts/vnet/arp4 new file mode 100644 index 00000000..acb20da3 --- /dev/null +++ b/src/scripts/vnet/arp4 @@ -0,0 +1,21 @@ +packet-generator new { + name x + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + ICMP: 1.0.0.2 -> 2.0.0.2 + ICMP echo_request + incrementing 100 + } +} + +trace add pg-input 100 +loop create +loop create +set int state loop0 up +set int state loop1 up + +set int ip address loop0 1.0.0.1/24 +set int ip address loop1 2.0.0.1/24 diff --git a/src/scripts/vnet/arp4-mpls b/src/scripts/vnet/arp4-mpls new file mode 100644 index 00000000..d3d39f3b --- /dev/null +++ b/src/scripts/vnet/arp4-mpls @@ -0,0 +1,24 @@ +packet-generator new { + name x + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + ICMP: 1.0.0.2 -> 2.2.2.2 + ICMP echo_request + incrementing 100 + } +} + +loop create +loop create +set int state loop0 up +set int state loop1 up + +set int ip address loop0 1.0.0.1/24 +set int ip address loop1 2.0.0.1/24 + +ip route add 2.2.2.2/32 via 2.0.0.2 loop1 out-label 33 + +trace add pg-input 100 diff --git a/src/scripts/vnet/arp6 b/src/scripts/vnet/arp6 new file mode 100644 index 00000000..e6a98935 --- /dev/null +++ b/src/scripts/vnet/arp6 @@ -0,0 +1,21 @@ +packet-generator new { + name x + limit 1 + node ip6-input + size 64-64 + no-recycle + data { + ICMP6: 2000::2 -> 2001::2 + ICMP echo_request + incrementing 100 + } +} + +tr add pg-input 100 +loop create +loop create +set int state loop0 up +set int state loop1 up + +set int ip address loop0 2000::1/64 +set int ip address loop1 2001::1/64 diff --git a/src/scripts/vnet/bvi b/src/scripts/vnet/bvi new file mode 100644 index 00000000..2174da0d --- /dev/null +++ b/src/scripts/vnet/bvi @@ -0,0 +1,76 @@ + + +set int state tuntap-0 down +set int ip address GigabitEthernet2/1/0 1.2.3.4/24 + +set int state GigabitEthernet2/1/0 up +cre sub GigabitEthernet2/1/0 1 dot1q 7 +set int state GigabitEthernet2/1/0.1 up + +set int state GigabitEthernet2/2/0 up +cre sub GigabitEthernet2/2/0 1 dot1q 9 +set int state GigabitEthernet2/2/0.1 up + + +loop create +set int l2 bridge loop0 0 bvi +set int ip table loop0 0 +set int state loop0 up + + +set int l2 bridge GigabitEthernet2/1/0.1 0 +set int l2 bridge GigabitEthernet2/2/0.1 0 + +set int l2 tag-rewrite GigabitEthernet2/1/0.1 pop 1 +set int l2 tag-rewrite GigabitEthernet2/2/0.1 pop 1 + +l2fib add 00:22:44:06:08:0a 0 GigabitEthernet2/1/0.1 static +l2fib add 00:02:04:06:08:0a 0 GigabitEthernet2/2/0.1 static + + +ip route table 0 8.0.0.1/32 via loop0 +set ip arp loop0 8.0.0.1 00:02:04:06:08:0a + + +ip route add 1.2.3.3/32 via GigabitEthernet2/1/0 IP4: 00:15:17:61:73:47 -> 00:15:17:61:73:46 + +cle er +cle int +cle run + +packet-generator new { + name bvi_to_l2 + limit 100 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + data { + IP4: 0050.56b7.7c83 -> 0050.56b7.296d + GRE: 1.2.3.3 -> 8.0.0.1 mpls_unicast + } +} + +packet-generator new { + name l2_to_bvi + limit 50 + no-recycle + node ethernet-input + interface GigabitEthernet2/2/0 + data { + IP4: 0050.56b7.7c83 -> dead.0000.0000 vlan 9 + GRE: 8.0.0.1 -> 1.2.3.3 mpls_unicast + } +} + +packet-generator new { + name l2_to_bvi_via_flood + limit 25 + no-recycle + node ethernet-input + interface GigabitEthernet2/2/0 + data { + IP4: 0050.56b7.7c83 -> ffff.ffff.ffff vlan 9 + GRE: 8.0.0.1 -> 1.2.3.3 mpls_unicast + } +} + diff --git a/src/scripts/vnet/dhcp/dhcpd.conf b/src/scripts/vnet/dhcp/dhcpd.conf new file mode 100644 index 00000000..d4cb3ed7 --- /dev/null +++ b/src/scripts/vnet/dhcp/dhcpd.conf @@ -0,0 +1,8 @@ +# add at the bottom + +subnet 192.168.0.0 netmask 255.255.0.0 { + range 192.168.1.10 192.168.1.254; + option routers 192.168.1.1; + default-lease-time 15; + max-lease-time 15; +} diff --git a/src/scripts/vnet/dhcp/left-ping-target.sh b/src/scripts/vnet/dhcp/left-ping-target.sh new file mode 100644 index 00000000..2edc2a50 --- /dev/null +++ b/src/scripts/vnet/dhcp/left-ping-target.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +# to obtain dhcp address from leftpeer +dhclient -d -v eth1 diff --git a/src/scripts/vnet/dhcp/leftpeer.conf b/src/scripts/vnet/dhcp/leftpeer.conf new file mode 100644 index 00000000..458eecf0 --- /dev/null +++ b/src/scripts/vnet/dhcp/leftpeer.conf @@ -0,0 +1,17 @@ +set int ip table GigabitEthernet2/2/0 12 +set int ip address GigabitEthernet2/2/0 192.168.1.1/24 +set int state GigabitEthernet2/2/0 up + +set int ip table GigabitEthernet2/7/0 11 +set int ip address GigabitEthernet2/7/0 192.168.2.1/24 +set int state GigabitEthernet2/7/0 up + +comment { set dhcp proxy server 1.2.3.4 src-address 1.2.3.5 add-option-82 rx-fib-id 0 server-fib-id 0 } + +comment { set dhcp proxy server 192.168.2.2 src-address 192.168.2.1 add-option-82 rx-fib-id 12 server-fib-id 11 } + +ip route add 0.0.0.0/24 table 11 via local +ip route add 255.255.255.255/24 table 11 via local + +ip route add 0.0.0.0/24 table 12 via local +ip route add 255.255.255.255/24 table 12 via local diff --git a/src/scripts/vnet/icmp b/src/scripts/vnet/icmp new file mode 100644 index 00000000..1e054e2d --- /dev/null +++ b/src/scripts/vnet/icmp @@ -0,0 +1,16 @@ +packet-generator new { + name x + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + ICMP: 1.2.3.4 -> 5.6.7.8 + ICMP echo_request + incrementing 100 + } +} + +tr add pg-input 100 +ip route 5.6.7.8/32 via local +ip route 1.2.3.4/32 via local diff --git a/src/scripts/vnet/icmp6 b/src/scripts/vnet/icmp6 new file mode 100644 index 00000000..2a65acba --- /dev/null +++ b/src/scripts/vnet/icmp6 @@ -0,0 +1,16 @@ +packet-generator new { + name x + limit 1 + node ip6-input + size 64-64 + no-recycle + data { + ICMP6: ::1 -> ::2 + ICMP echo_request + incrementing 100 + } +} + +tr add pg-input 100 +ip route ::1/128 via local +ip route ::2/128 via local diff --git a/src/scripts/vnet/ige b/src/scripts/vnet/ige new file mode 100644 index 00000000..80d045af --- /dev/null +++ b/src/scripts/vnet/ige @@ -0,0 +1,19 @@ +packet-generator new { + name x + limit 1 + node ip4-lookup + size 50-50 + data { + ICMP: 1.0.0.1 -> 1.0.0.3 ttl 1 + incrementing 30 + } +} + +comment { tr add pg-input 100 } +set int ip address GigabitEthernet4/0/0 1.0.0.1/24 +set int ip address GigabitEthernet4/0/1 1.0.0.2/24 +set int state GigabitEthernet4/0/0 up +set int state GigabitEthernet4/0/1 up + +ip route add 1.0.0.3/32 via GigabitEthernet4/0/1 IP4: 00:15:17:61:73:47 -> 00:15:17:61:73:46 +tr add ige-input 10 diff --git a/src/scripts/vnet/ip6 b/src/scripts/vnet/ip6 new file mode 100644 index 00000000..4f9f3ee5 --- /dev/null +++ b/src/scripts/vnet/ip6 @@ -0,0 +1,15 @@ +packet-generator new { + name x + limit 1 + node ethernet-input + size 64-64 + no-recycle + data { + IP6: 1.2.3 -> 4.5.6 + ICMP: ::1 -> ::2 + ICMP echo_request + incrementing 100 + } +} + +tr add pg-input 100 diff --git a/src/scripts/vnet/ip6-hbh b/src/scripts/vnet/ip6-hbh new file mode 100644 index 00000000..0c6de47f --- /dev/null +++ b/src/scripts/vnet/ip6-hbh @@ -0,0 +1,84 @@ +tap connect tap0 +set int state tap-0 up +set int ip address tap-0 1::1/64 +packet-generator new { + name hbh1 + limit 1 + node ip6-input + size 48-48 + no-recycle + data { + IP6_HOP_BY_HOP_OPTIONS: 1::2 -> 1::2 + hex 0x3B00010403040506 + incrementing 100 + } +} +packet-generator new { + name hbh2 + limit 1 + node ip6-input + size 48-48 + no-recycle + data { + IP6_HOP_BY_HOP_OPTIONS: 1::2 -> 1::2 + hex 0x3B00C10403040506 + incrementing 100 + } +} + +packet-generator new { + name hbh3 + limit 1 + node ip6-input + size 48-48 + no-recycle + data { + IP6_HOP_BY_HOP_OPTIONS: 1::2 -> 1::2 + hex 0x3BffC10403040506 + incrementing 100 + } +} + +packet-generator new { + name hbh4 + limit 1 + node ip6-input + size 64-64 + no-recycle + data { + IP6_HOP_BY_HOP_OPTIONS: 1::2 -> 1::2 + hex 0x3BffC10403040506 + incrementing 100 + } +} + +packet-generator new { + name hbh5 + limit 1 + node ip6-input + size 56-56 + no-recycle + data { + IP6_HOP_BY_HOP_OPTIONS: 1::2 -> 1::2 + length 16 + hex 0x3B010104030405060106030405060708 + incrementing 100 + } +} + +packet-generator new { + name hbh6 + limit 1 + node ip6-input + size 56-56 + no-recycle + data { + IP6_HOP_BY_HOP_OPTIONS: 1::2 -> 1::2 + length 16 + hex 0x3a00050200000100 + ICMP echo_request + incrementing 100 + } +} + +tr add pg-input 100 diff --git a/src/scripts/vnet/ixge b/src/scripts/vnet/ixge new file mode 100644 index 00000000..6722b536 --- /dev/null +++ b/src/scripts/vnet/ixge @@ -0,0 +1,15 @@ +packet-generator new { + name x + limit 1 + node ip4-lookup + size 50-50 + data { + ICMP: 1.0.0.1 -> 1.0.0.3 ttl 1 + incrementing 30 + } +} + +comment { tr add pg-input 100 } +set int ip address TenGigabitEthernet5/0/0 33.0.1.1/8 +set int state TenGigabitEthernet5/0/0 up + diff --git a/src/scripts/vnet/l2efpfilter b/src/scripts/vnet/l2efpfilter new file mode 100644 index 00000000..307b4436 --- /dev/null +++ b/src/scripts/vnet/l2efpfilter @@ -0,0 +1,83 @@ + +set int ip address GigabitEthernet2/1/0 1.2.3.4/24 +set int state GigabitEthernet2/1/0 up +set int state tuntap-0 down + + +cre sub GigabitEthernet2/1/0 1 dot1q 1 +cre sub GigabitEthernet2/1/0 2 dot1q 2 +cre sub GigabitEthernet2/1/0 3 dot1q 3 +cre sub GigabitEthernet2/2/0 1 dot1q 1 +cre sub GigabitEthernet2/2/0 100 dot1q 100 + +set int l2 bridge GigabitEthernet2/1/0 0 +set int l2 bridge GigabitEthernet2/1/0.1 0 +set int l2 bridge GigabitEthernet2/1/0.2 0 +set int l2 bridge GigabitEthernet2/1/0.3 0 +set int l2 bridge GigabitEthernet2/2/0 0 +set int l2 bridge GigabitEthernet2/2/0.1 0 +set int l2 bridge GigabitEthernet2/2/0.100 0 + +set int l2 tag-rewrite GigabitEthernet2/2/0.1 push dot1q 50 +set int l2 tag-rewrite GigabitEthernet2/1/0.2 translate 1-1 dot1q 100 +set int l2 tag-rewrite GigabitEthernet2/1/0.3 translate 1-1 dot1q 99 + +set int l2 efp-filter GigabitEthernet2/2/0 +set int l2 efp-filter GigabitEthernet2/2/0.1 +set int l2 efp-filter GigabitEthernet2/2/0.100 + + +l2fib add 00:00:00:00:00:11 0 GigabitEthernet2/2/0.1 static +l2fib add 00:00:00:00:00:22 0 GigabitEthernet2/2/0.100 static + +set int state GigabitEthernet2/1/0 up +set int state GigabitEthernet2/1/0.1 up +set int state GigabitEthernet2/1/0.2 up +set int state GigabitEthernet2/1/0.3 up +set int state GigabitEthernet2/2/0 up +set int state GigabitEthernet2/2/0.1 up +set int state GigabitEthernet2/2/0.100 up + + +trace add pg-input 6 + +clear error +clear run +clear int + +packet-generator new { + name pre_vtr_fail + limit 10 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + data { + IP4: 0050.56b7.7c83 -> 00:00:00:00:00:11 vlan 1 + GRE: 8.0.0.1 -> 1.2.3.3 mpls_unicast + } +} + +packet-generator new { + name post_vtr_pass + limit 20 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + data { + IP4: 0050.56b7.7c83 -> 00:00:00:00:00:22 vlan 2 + GRE: 8.0.0.1 -> 1.2.3.3 mpls_unicast + } +} + +packet-generator new { + name post_vtr_fail + limit 50 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + data { + IP4: 0050.56b7.7c83 -> 00:00:00:00:00:22 vlan 3 + GRE: 8.0.0.1 -> 1.2.3.3 mpls_unicast + } +} + diff --git a/src/scripts/vnet/l2efpfilter_perf b/src/scripts/vnet/l2efpfilter_perf new file mode 100644 index 00000000..b2f4b490 --- /dev/null +++ b/src/scripts/vnet/l2efpfilter_perf @@ -0,0 +1,58 @@ + +set int ip address GigabitEthernet2/1/0 1.2.3.4/24 +set int state GigabitEthernet2/1/0 up +set int state tuntap-0 down + + +cre sub GigabitEthernet2/1/0 1 dot1q 1 +cre sub GigabitEthernet2/1/0 2 dot1q 2 +cre sub GigabitEthernet2/1/0 3 dot1q 3 +cre sub GigabitEthernet2/2/0 1 dot1q 1 +cre sub GigabitEthernet2/2/0 100 dot1q 100 + +set int l2 bridge GigabitEthernet2/1/0 0 +set int l2 bridge GigabitEthernet2/1/0.1 0 +set int l2 bridge GigabitEthernet2/1/0.2 0 +set int l2 bridge GigabitEthernet2/1/0.3 0 +set int l2 bridge GigabitEthernet2/2/0 0 +set int l2 bridge GigabitEthernet2/2/0.1 0 +set int l2 bridge GigabitEthernet2/2/0.100 0 + +set int l2 tag-rewrite GigabitEthernet2/2/0.1 push dot1q 50 +set int l2 tag-rewrite GigabitEthernet2/1/0.2 translate 1-1 dot1q 100 +set int l2 tag-rewrite GigabitEthernet2/1/0.3 translate 1-1 dot1q 99 + +set int l2 efp-filter GigabitEthernet2/2/0 +set int l2 efp-filter GigabitEthernet2/2/0.1 +set int l2 efp-filter GigabitEthernet2/2/0.100 + + +l2fib add 00:00:00:00:00:11 0 GigabitEthernet2/2/0.1 static +l2fib add 00:00:00:00:00:22 0 GigabitEthernet2/2/0.100 static + +set int state GigabitEthernet2/1/0 up +set int state GigabitEthernet2/1/0.1 up +set int state GigabitEthernet2/1/0.2 up +set int state GigabitEthernet2/1/0.3 up +set int state GigabitEthernet2/2/0 up +set int state GigabitEthernet2/2/0.1 up +set int state GigabitEthernet2/2/0.100 up + + +trace add pg-input 6 + +clear error +clear run +clear int + +packet-generator new { + name post_vtr_pass + limit 9111003 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + data { + IP4: 0050.56b7.7c83 -> 00:00:00:00:00:22 vlan 2 + GRE: 8.0.0.1 -> 1.2.3.3 mpls_unicast + } +} diff --git a/src/scripts/vnet/l2fib b/src/scripts/vnet/l2fib new file mode 100644 index 00000000..81ede171 --- /dev/null +++ b/src/scripts/vnet/l2fib @@ -0,0 +1,46 @@ + +set int ip address GigabitEthernet2/1/0 1.2.3.4/24 +set int state GigabitEthernet2/1/0 up + +set int state GigabitEthernet2/2/0 up +cre sub GigabitEthernet2/2/0 1 dot1q 9 +set int state GigabitEthernet2/2/0.1 up +set int state tuntap-0 down + +set int acl input GigabitEthernet2/1/0 +set int acl output GigabitEthernet2/1/0 +set int acl input GigabitEthernet2/2/0.1 +set int acl output GigabitEthernet2/2/0.1 + +set int l2 bridge GigabitEthernet2/1/0 0 +set int l2 bridge GigabitEthernet2/2/0.1 0 + +set int l2 tag-rewrite GigabitEthernet2/1/0 push dot1q 50 +set int l2 tag-rewrite GigabitEthernet2/2/0.1 pop 1 + + +trace add pg-input 6 + +clear error +clear run +clear int + +packet-generator new { + name new_input_if_index_mac_move + limit 4 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + size 98-98 + data { hex 0x00010203040500020406080a080045006402b46b96000100096978676265000500bf436973636f20494f5320536f6674776172652c2040160011000000010101cc000400000000001a00100000000100000000ffffffff } +} + +packet-generator new { + name dmac_hit + limit 7 + no-recycle + node ethernet-input + interface GigabitEthernet2/2/0 + size 98-98 + data { hex 0x00020406080a00224406080a8100000981000011080045006402b46b96000100096978676265000500bf436973636f20494f5320536f6674776172652c2040160011000000010101cc000400000000001a00100000000100000000ffffffff } +} diff --git a/src/scripts/vnet/l2fib_perf b/src/scripts/vnet/l2fib_perf new file mode 100644 index 00000000..638317ff --- /dev/null +++ b/src/scripts/vnet/l2fib_perf @@ -0,0 +1,29 @@ + +set int ip address GigabitEthernet2/1/0 1.2.3.4/24 +set int state GigabitEthernet2/1/0 up + +set int state GigabitEthernet2/2/0 up +cre sub GigabitEthernet2/2/0 1 dot1q 9 +set int state GigabitEthernet2/2/0.1 up +set int state tuntap-0 down + +set int l2 bridge GigabitEthernet2/1/0 0 +set int l2 bridge GigabitEthernet2/2/0.1 0 + +l2fib add 00:22:44:06:08:0a 0 GigabitEthernet2/1/0 static +l2fib add 00:02:04:06:08:0a 0 GigabitEthernet2/2/0.1 static + +cle er +cle int +cle run + +packet-generator new { + name perf + limit 9111003 + no-recycle + node ethernet-input + interface GigabitEthernet2/2/0.1 + size 98-98 + data { hex 0x00224406080a00020406080a81000009080045006402b46b96000100096978676265000500bf436973636f20494f5320536f6674776172652c2040160011000000010101cc000400000000001a00100000000100000000ffffffff } +} + diff --git a/src/scripts/vnet/l2fib_xc b/src/scripts/vnet/l2fib_xc new file mode 100644 index 00000000..35d7342b --- /dev/null +++ b/src/scripts/vnet/l2fib_xc @@ -0,0 +1,31 @@ + +set int ip address GigabitEthernet2/1/0 1.2.3.4/24 +set int state GigabitEthernet2/1/0 up + +set int state GigabitEthernet2/2/0 up +cre sub GigabitEthernet2/2/0 1 dot1q 9 +set int state GigabitEthernet2/2/0.1 up +set int state tuntap-0 down + +set int acl input GigabitEthernet2/1/0 +set int acl output GigabitEthernet2/1/0 +set int acl input GigabitEthernet2/2/0.1 +set int acl output GigabitEthernet2/2/0.1 + +set int l2 xc GigabitEthernet2/1/0 GigabitEthernet2/2/0.1 +set int l2 xc GigabitEthernet2/2/0.1 GigabitEthernet2/1/0 + +clear error +clear run +clear int + +packet-generator new { + name xc + limit 11 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + size 98-98 + data { hex 0x00010203040500020406080a080045006402b46b96000100096978676265000500bf436973636f20494f5320536f6674776172652c2040160011000000010101cc000400000000001a00100000000100000000ffffffff } +} + diff --git a/src/scripts/vnet/l2flood b/src/scripts/vnet/l2flood new file mode 100644 index 00000000..013462ce --- /dev/null +++ b/src/scripts/vnet/l2flood @@ -0,0 +1,42 @@ + +set int ip address GigabitEthernet2/1/0 1.2.3.4/24 +set int state GigabitEthernet2/1/0 up +set int state tuntap-0 down + + +loop create +cre sub loop0 1 dot1q 1 +cre sub loop0 2 dot1q 2 +cre sub loop0 3 dot1q 3 +cre sub GigabitEthernet2/1/0 1 dot1q 1 + + +set int l2 bridge loop0.1 7 +set int l2 bridge loop0.2 7 +set int l2 bridge loop0.3 7 +set int l2 bridge GigabitEthernet2/1/0.1 7 + +loop cre +set int l2 bridge loop1 7 bvi + +set int state GigabitEthernet2/1/0.1 up + +trace add pg-input 6 + +clear error +clear run +clear int + +packet-generator new { + name flood + limit 1 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + data { + IP4: 0050.56b7.7c83 -> ffff.ffff.ffff vlan 1 + GRE: 8.0.0.1 -> 1.2.3.3 mpls_unicast + } + +} + diff --git a/src/scripts/vnet/l2tp b/src/scripts/vnet/l2tp new file mode 100644 index 00000000..337805aa --- /dev/null +++ b/src/scripts/vnet/l2tp @@ -0,0 +1,134 @@ + +set int ip address GigabitEthernet2/1/0 1.2.3.4/24 +set int state GigabitEthernet2/1/0 up +set int state tuntap-0 down + + +cre sub GigabitEthernet2/1/0 1 dot1q 1 +cre sub GigabitEthernet2/1/0 2 dot1q 2 +cre sub GigabitEthernet2/1/0 3 dot1q 3 +cre sub GigabitEthernet2/2/0 1 dot1q 1 +cre sub GigabitEthernet2/2/0 100 dot1q 100 + + +set int l2 tag-rewrite GigabitEthernet2/1/0.1 pop 1 +set int l2 tag-rewrite GigabitEthernet2/1/0.2 pop 1 + + +l2tp session add client 11::1 our 22::2 l2-interface GigabitEthernet2/1/0.1 +l2tp session add client 11::1 our 22::3 l2-interface GigabitEthernet2/1/0.2 local-session-id 2 l2-sublayer-present + +ip route 11::1/128 via GigabitEthernet2/2/0 +set ip6 neighbor GigabitEthernet2/2/0 11::1 00:02:04:06:08:0a + +enable ip6 interface GigabitEthernet2/2/0 + +set int ip6 l2tpv3 GigabitEthernet2/2/0 + +set int state GigabitEthernet2/1/0 up +set int state GigabitEthernet2/1/0.1 up +set int state GigabitEthernet2/1/0.2 up +set int state GigabitEthernet2/1/0.3 up +set int state GigabitEthernet2/2/0 up + + +trace add pg-input 2 + +clear error +clear run +clear int + +packet-generator new { + name decap + limit 10 + size 200-200 + no-recycle + node ethernet-input + interface GigabitEthernet2/2/0 + data { + IP6: 00:50:00:00:00:01 -> 00:50:56:b7:29:7a + L2TP: 11::1 -> 22::2 + L2TP: session_id 1 cookie 0xffffffffffffffff + IP4: 00:55:55:55:00:01 -> 00:dd:dd:dd:00:01 + UDP: 1.2.3.4 -> 5.6.7.8 + incrementing 8 + } +} + +packet-generator new { + name decap_bad_sid + limit 30 + size 200-200 + no-recycle + node ethernet-input + interface GigabitEthernet2/2/0 + data { + IP6: 00:50:00:00:00:01 -> 00:50:56:b7:29:7a + L2TP: 11::1 -> 22::2 + L2TP: session_id 0x999 cookie 0xffffffffffffffff + IP4: 00:55:55:55:00:01 -> 00:dd:dd:dd:00:01 + UDP: 1.2.3.4 -> 5.6.7.8 + incrementing 8 + } +} + +packet-generator new { + name decap_bad_cookie + limit 50 + size 200-200 + no-recycle + node ethernet-input + interface GigabitEthernet2/2/0 + data { + IP6: 00:50:00:00:00:01 -> 00:50:56:b7:29:7a + L2TP: 11::1 -> 22::2 + L2TP: session_id 1 cookie 0x3333ffffffffffff + IP4: 00:55:55:55:00:01 -> 00:dd:dd:dd:00:01 + UDP: 1.2.3.4 -> 5.6.7.8 + incrementing 8 + } +} + +packet-generator new { + name encap + limit 100 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + data { + IP4: 0000.5555.0002 -> 00:00:dd:dd:00:02 vlan 1 + UDP: 1.2.3.4 -> 5.6.7.8 + incrementing 8 + } +} + +packet-generator new { + name decap_sublayer + limit 300 + size 200-200 + no-recycle + node ethernet-input + interface GigabitEthernet2/2/0 + data { + IP6: 00:50:00:00:00:01 -> 00:50:56:b7:29:7a + L2TP: 11::1 -> 22::3 + L2TP: session_id 2 cookie 0xffffffffffffffff l2_sublayer 0 + IP4: 00:55:55:55:00:01 -> 00:dd:dd:dd:00:01 + UDP: 1.2.3.4 -> 5.6.7.8 + incrementing 8 + } +} + +packet-generator new { + name encap_sublayer + limit 700 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + data { + IP4: 0000.5555.0002 -> 00:00:dd:dd:00:02 vlan 2 + UDP: 1.2.3.4 -> 5.6.7.8 + incrementing 8 + } +} + diff --git a/src/scripts/vnet/leftpeer/leftpeer-classify b/src/scripts/vnet/leftpeer/leftpeer-classify new file mode 100755 index 00000000..74285912 --- /dev/null +++ b/src/scripts/vnet/leftpeer/leftpeer-classify @@ -0,0 +1,8 @@ +classify table mask l2 src l3 ip4 src buckets 2 miss-next local + +comment { classify table mask l3 ip4 src buckets 2 miss-next local } +set ip classify intfc GigabitEthernet2/2/0 table-index 0 +set int ip address GigabitEthernet2/2/0 192.168.1.1/24 +set int state GigabitEthernet2/2/0 up + +classify session hit-next local table-index 0 match l2 src 00:50:56:b7:05:bb l3 ip4 src 192.168.1.2 diff --git a/src/scripts/vnet/leftpeer/leftpeer-classify6 b/src/scripts/vnet/leftpeer/leftpeer-classify6 new file mode 100644 index 00000000..6579d50d --- /dev/null +++ b/src/scripts/vnet/leftpeer/leftpeer-classify6 @@ -0,0 +1,5 @@ +classify table mask l3 ip6 src buckets 2 miss-next local +set ip6 classify intfc GigabitEthernet2/2/0 table-index 0 +set int ip address GigabitEthernet2/2/0 db01::1/64 +set int state GigabitEthernet2/2/0 up +classify session hit-next local table-index 0 match l3 ip6 src db01::2 diff --git a/src/scripts/vnet/leftpeer/leftpeer-classifyl2 b/src/scripts/vnet/leftpeer/leftpeer-classifyl2 new file mode 100644 index 00000000..6be4b1e5 --- /dev/null +++ b/src/scripts/vnet/leftpeer/leftpeer-classifyl2 @@ -0,0 +1,8 @@ +set int ip address GigabitEthernet2/2/0 192.168.1.1/24 +set int state GigabitEthernet2/2/0 up + +classify table mask l3 ip4 src buckets 2 l2-miss-next ethernet + +classify session advance 14 l2-hit-next ip4 table-index 0 match l3 ip4 src 192.168.1.2 + +set int l2 class intfc GigabitEthernet2/2/0 ip4-table 0 diff --git a/src/scripts/vnet/leftpeer/leftpeer-dhcp b/src/scripts/vnet/leftpeer/leftpeer-dhcp new file mode 100644 index 00000000..c13a8f3a --- /dev/null +++ b/src/scripts/vnet/leftpeer/leftpeer-dhcp @@ -0,0 +1,23 @@ +loop cre +set int ip table loop0 12 +set int ip address loop0 192.168.1.1/24 +set int state loop0 up + +set int ip table GigabitEthernet2/2/0 12 +comment { set int ip address GigabitEthernet2/2/0 192.168.1.1/24 } +set int unnumbered GigabitEthernet2/2/0 use loop0 +set int state GigabitEthernet2/2/0 up + +set int ip table GigabitEthernet2/7/0 11 +set int ip address GigabitEthernet2/7/0 192.168.2.1/24 +set int state GigabitEthernet2/7/0 up + +uncomment { set dhcp proxy server 1.2.3.4 src-address 1.2.3.5 add-option-82 rx-fib-id 0 server-fib-id 0 } + +uncomment { set dhcp proxy server 192.168.2.2 src-address 192.168.2.1 add-option-82 rx-fib-id 12 server-fib-id 11 } + +ip route add 0.0.0.0/24 table 11 via local +ip route add 255.255.255.255/24 table 11 via local + +ip route add 0.0.0.0/24 table 12 via local +ip route add 255.255.255.255/24 table 12 via local diff --git a/src/scripts/vnet/leftpeer/leftpeer-ioam.conf b/src/scripts/vnet/leftpeer/leftpeer-ioam.conf new file mode 100644 index 00000000..6c1b502c --- /dev/null +++ b/src/scripts/vnet/leftpeer/leftpeer-ioam.conf @@ -0,0 +1,15 @@ +comment { connects to linux ping source eth1 addr db02::2/64 } +set int ip address GigabitEthernet2/2/0 db02::1/64 +set int state GigabitEthernet2/2/0 up + +comment { connects to ioam domain rightpeer eth2 addr db03::3/64 } +set int ip address GigabitEthernet2/3/0 db03::1/64 +set int state GigabitEthernet2/3/0 up + +ioam set rewrite trace-elts 2 pow + +set ip6 neighbor GigabitEthernet2/3/0 db03::3 00:50:56:b7:05:cb + +ip route add db04::0/64 via db03::3 + +ioam set destination db04::0/64 add diff --git a/src/scripts/vnet/leftpeer/leftpeer-l3vxlan.conf b/src/scripts/vnet/leftpeer/leftpeer-l3vxlan.conf new file mode 100644 index 00000000..a75f9b4c --- /dev/null +++ b/src/scripts/vnet/leftpeer/leftpeer-l3vxlan.conf @@ -0,0 +1,12 @@ +comment { tunnel to rightpeer 6.0.3.3 on vlan 101 } + +set int ip address GigabitEthernet2/3/0 6.0.3.1/24 +set int state GigabitEthernet2/3/0 up + +comment { configure lc2 eth1 at e.g. 6.0.2.2/24 } + +set int ip address GigabitEthernet2/2/0 6.0.2.1/24 +set int state GigabitEthernet2/2/0 up + +vxlan tunnel src 6.0.3.1 peer 6.0.3.3 vni 123 adj 6.0.4.4/24 + diff --git a/src/scripts/vnet/leftpeer/leftpeer-lisp.conf b/src/scripts/vnet/leftpeer/leftpeer-lisp.conf new file mode 100644 index 00000000..cb3180b7 --- /dev/null +++ b/src/scripts/vnet/leftpeer/leftpeer-lisp.conf @@ -0,0 +1,18 @@ +comment { vpe_phase2 configuration } + +comment { local client facing interface on vlan 100 } +comment { configure lc2 eth1 at e.g. 6.0.2.2/24 } + +set int ip address GigabitEthernet2/2/0 6.0.2.1/24 +set int state GigabitEthernet2/2/0 up + +comment { tunnel to rightpeer on vlan 101 } +set int ip address GigabitEthernet2/3/0 6.0.3.1/24 +set int state GigabitEthernet2/3/0 up + +lisp gpe tunnel src 6.0.3.1 dst 6.0.3.3 next-ip4 decap-next ip4 iid 1133 +set int ip address lisp_gpe_tunnel0 6.0.4.1/24 +set int state lisp_gpe_tunnel0 up + +lisp gpe tunnel src 6.0.3.3 dst 6.0.3.1 next-ip4 decap-next ip4 iid 3311 +set int stat lisp_gpe_tunnel1 up diff --git a/src/scripts/vnet/leftpeer/leftpeer-mpls.conf b/src/scripts/vnet/leftpeer/leftpeer-mpls.conf new file mode 100644 index 00000000..74bce81b --- /dev/null +++ b/src/scripts/vnet/leftpeer/leftpeer-mpls.conf @@ -0,0 +1,17 @@ +comment { vpe_phase2 configuration } + +comment { local client facing interface on vlan 100 } +comment { configure lc2 eth1 at e.g. 6.0.2.2/24 } + +set int ip table GigabitEthernet2/2/0 1 +set int ip address GigabitEthernet2/2/0 6.0.2.1/24 +set int state GigabitEthernet2/2/0 up + +comment { tunnel to rightpeer on vlan 101 } +set int ip address GigabitEthernet2/3/0 6.0.3.1/24 +set int state GigabitEthernet2/3/0 up + +mpls encap add label 30 fib 1 dest 6.0.3.3 +mpls decap add label 30 fib 1 + +create mpls gre tunnel src 6.0.3.1 dst 6.0.3.3 intfc 6.0.4.1/24 inner-fib-id 1 outer-fib-id 0 diff --git a/src/scripts/vnet/leftpeer/leftpeer-sr.conf b/src/scripts/vnet/leftpeer/leftpeer-sr.conf new file mode 100644 index 00000000..a7b962d3 --- /dev/null +++ b/src/scripts/vnet/leftpeer/leftpeer-sr.conf @@ -0,0 +1,24 @@ +comment { test sr segment chunk-offset on } +test sr hmac validate on + +comment { trunk to rightpeer } +set int ip address GigabitEthernet2/3/0 db03::2/64 +enable ip6 interface GigabitEthernet2/3/0 +set int state GigabitEthernet2/3/0 up + +comment { subscriber linux-ping-source } +set int ip address GigabitEthernet2/2/0 db02::2/64 +enable ip6 interface GigabitEthernet2/2/0 +set int state GigabitEthernet2/2/0 up + +sr hmac id 2 key Gozzer +sr hmac id 3 key Hoser + +sr tunnel src db01::1 dst db04::1/128 next db03::1 next db04::1 tag db02::2 clean key Gozzer InPE 1 + +tap connect srlocal hwaddr random +set int ip6 table tap-0 1 +set int ip address tap-0 db04::99/64 +enable ip6 interface tap-0 +set int state tap-0 up +ip route add table 1 db02::0/64 lookup in table 0 diff --git a/src/scripts/vnet/leftpeer/leftpeer-vxlan.conf b/src/scripts/vnet/leftpeer/leftpeer-vxlan.conf new file mode 100644 index 00000000..d50e8bf4 --- /dev/null +++ b/src/scripts/vnet/leftpeer/leftpeer-vxlan.conf @@ -0,0 +1,17 @@ +comment { tunnel to rightpeer 6.0.3.3 on vlan 101 } + +set int ip address GigabitEthernet2/3/0 6.0.3.1/24 +set int state GigabitEthernet2/3/0 up + +comment { tunnel to thirdpeer 6.0.5.5 on vlan 105 } +set int ip address GigabitEthernet2/7/0 6.0.5.1/24 +set int state GigabitEthernet2/7/0 up + +comment { configure lc2 eth1 at e.g. 6.0.2.2/24 } + +set int ip address GigabitEthernet2/2/0 6.0.2.1/24 +set int state GigabitEthernet2/2/0 up + +vxlan tunnel src 6.0.3.1 peer 6.0.3.3 peer 6.0.3.5 vni 123 +vxlan l2 GigabitEthernet2/2/0 vni 123 + diff --git a/src/scripts/vnet/leftpeer/leftpeer.script b/src/scripts/vnet/leftpeer/leftpeer.script new file mode 100644 index 00000000..f08c8090 --- /dev/null +++ b/src/scripts/vnet/leftpeer/leftpeer.script @@ -0,0 +1,9 @@ +l2tp_set_lookup_key lookup_v6_src + +sw_interface_add_del_address GigabitEthernet2/3/0 db03::2/64 +sw_interface_set_flags GigabitEthernet2/3/0 admin-up + +comment sw_interface_add_del_address GigabitEthernet2/2/0 db02::2/64 +sw_interface_set_flags GigabitEthernet2/2/0 admin-up + +l2tp_session_add_del client_address db03::1 our_address db03::2 GigabitEthernet2/2/0 local_session_id 1 remote_session_id 3 local_cookie 11 remote_cookie 33 diff --git a/src/scripts/vnet/lfib/ip4-to-mpls b/src/scripts/vnet/lfib/ip4-to-mpls new file mode 100644 index 00000000..85753797 --- /dev/null +++ b/src/scripts/vnet/lfib/ip4-to-mpls @@ -0,0 +1,26 @@ +packet-generator new { + name x + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + ICMP: 1.0.0.2 -> 2.2.2.2 + ICMP echo_request + incrementing 100 + } +} + +loop create +loop create +set int state loop0 up +set int state loop1 up + +set int ip address loop0 1.0.0.1/24 +set int ip address loop1 2.0.0.1/24 + +set ip arp static loop1 2.0.0.2 dead.beef.babe +set int mpls loop1 enable +ip route add 2.2.2.2/32 via 2.0.0.2 loop1 out-label 33 + +trace add pg-input 100 diff --git a/src/scripts/vnet/lfib/mpls-pop-to-mpls b/src/scripts/vnet/lfib/mpls-pop-to-mpls new file mode 100644 index 00000000..2818ac13 --- /dev/null +++ b/src/scripts/vnet/lfib/mpls-pop-to-mpls @@ -0,0 +1,28 @@ +packet-generator new { + name x + limit 1 + node mpls-input + size 72-72 + no-recycle + data { + hex 0x0001e0ff0001f1ff4500004000000000400177ba010000020202020208007a6e000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627 + } +} + +loop create +loop create +set int state loop0 up +set int state loop1 up + +set int ip address loop0 1.0.0.1/24 +set int ip address loop1 2.0.0.1/24 + +set ip arp static loop1 2.0.0.2 dead.beef.babe +set int mpls loop1 enable + +ip route add 2.2.2.2/32 via 2.0.0.2 loop1 out-label 33 + +mpls local-label add 30 non-eos mpls-lookup-in-table 0 +mpls local-label add 31 2.2.2.2/32 + +trace add pg-input 100 diff --git a/src/scripts/vnet/lfib/mpls-to-ip4 b/src/scripts/vnet/lfib/mpls-to-ip4 new file mode 100644 index 00000000..24e235e0 --- /dev/null +++ b/src/scripts/vnet/lfib/mpls-to-ip4 @@ -0,0 +1,27 @@ +packet-generator new { + name x + limit 1 + node mpls-input + size 68-68 + no-recycle + data { + hex 0x0001e1ff4500004000000000400177ba010000020202020208007a6e000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627 + } +} + +loop create +loop create +set int state loop0 up +set int state loop1 up + +set int ip address loop0 1.0.0.1/24 +set int ip address loop1 2.0.0.1/24 + +set ip arp static loop1 2.0.0.2 dead.beef.babe +set int mpls loop1 enable + +ip route add 2.2.2.2/32 via 2.0.0.2 loop1 out-label 33 + +mpls local-label add 30 eos ip4-lookup-in-table 0 + +trace add pg-input 100 diff --git a/src/scripts/vnet/lfib/mpls-to-mpls b/src/scripts/vnet/lfib/mpls-to-mpls new file mode 100644 index 00000000..497dbab3 --- /dev/null +++ b/src/scripts/vnet/lfib/mpls-to-mpls @@ -0,0 +1,26 @@ +packet-generator new { + name x + limit 1 + node mpls-input + size 68-68 + no-recycle + data { + hex 0x0001e1ff4500004000000000400177ba010000020200000208007a6e000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627 + } +} + +loop create +loop create +set int state loop0 up +set int state loop1 up + +set int ip address loop0 1.0.0.1/24 +set int ip address loop1 2.0.0.1/24 + +set ip arp static loop1 2.0.0.2 dead.beef.babe +set int mpls loop1 enable + +ip route add 2.2.2.2/32 via 2.0.0.2 loop1 out-label 33 +mpls local-label add 30 2.2.2.2/32 + +trace add pg-input 100 diff --git a/src/scripts/vnet/mpls-o-ethernet/leftpeer.conf b/src/scripts/vnet/mpls-o-ethernet/leftpeer.conf new file mode 100644 index 00000000..dd37b942 --- /dev/null +++ b/src/scripts/vnet/mpls-o-ethernet/leftpeer.conf @@ -0,0 +1,17 @@ +comment { vpe_phase2 configuration } + +comment { local client facing interface } +comment { configure lc2 eth1 at e.g. 6.0.2.2/24 } + +set int ip table GigabitEthernet2/2/0 1 +set int ip address GigabitEthernet2/2/0 6.0.2.1/24 +set int state GigabitEthernet2/2/0 up + +comment { tunnel to rightpeer } +set int ip address GigabitEthernet2/3/0 6.0.3.1/24 +set int state GigabitEthernet2/3/0 up + +mpls encap add label 30 fib 1 dest 6.0.4.1 +mpls decap add label 30 fib 1 + +create mpls ethernet tunnel dst 00:50:56:b7:05:cb adj 6.0.4.1/24 tx-intfc GigabitEthernet2/3/0 fib-id 1 diff --git a/src/scripts/vnet/mpls-o-ethernet/pg b/src/scripts/vnet/mpls-o-ethernet/pg new file mode 100644 index 00000000..ba5397f7 --- /dev/null +++ b/src/scripts/vnet/mpls-o-ethernet/pg @@ -0,0 +1,10 @@ +packet-generator new { + name x + limit 1 + node mpls-ethernet-input + size 68-68 + no-recycle + data { + hex 0x0001e1ff4500004000000000400177ba010000020200000208007a6e000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627 + } +} \ No newline at end of file diff --git a/src/scripts/vnet/mpls-o-ethernet/rightpeer.conf b/src/scripts/vnet/mpls-o-ethernet/rightpeer.conf new file mode 100644 index 00000000..7709ce4d --- /dev/null +++ b/src/scripts/vnet/mpls-o-ethernet/rightpeer.conf @@ -0,0 +1,15 @@ +comment { local client facing interface } +comment { configure lc4 eth1 at e.g. 6.0.4.4/24 } + +set int ip table GigabitEthernet2/4/0 1 +set int ip address GigabitEthernet2/4/0 6.0.4.1/24 +set int state GigabitEthernet2/4/0 up + +comment { tunnel to leftpeer } +set int ip address GigabitEthernet2/3/0 6.0.3.3/24 +set int state GigabitEthernet2/3/0 up + +mpls encap add label 30 fib 1 dest 6.0.2.1 +mpls decap add label 30 fib 1 + +create mpls ethernet tunnel dst 00:50:56:b7:05:bf adj 6.0.2.1/24 tx-intfc GigabitEthernet2/3/0 fib-id 1 diff --git a/src/scripts/vnet/mpls-o-ethernet/single.conf b/src/scripts/vnet/mpls-o-ethernet/single.conf new file mode 100644 index 00000000..2a25d355 --- /dev/null +++ b/src/scripts/vnet/mpls-o-ethernet/single.conf @@ -0,0 +1,17 @@ +comment { single node configuration } + +loop create +loop create +set int state loop0 up +set int state loop1 up + +set int ip address loop0 1.0.0.1/24 +set int ip address loop1 2.0.0.1/24 + + +ip route add 2.2.2.2/32 via 2.0.0.2 loop1 + +mpls encap add label 30 fib 0 dest 2.2.2.2 +mpls decap add label 30 fib 0 + +create mpls ethernet tunnel dst 00:50:56:b7:05:cb adj 2.2.2.2/32 tx-intfc loop1 fib-id 0 diff --git a/src/scripts/vnet/mpls-o-gre/dhcpd.conf b/src/scripts/vnet/mpls-o-gre/dhcpd.conf new file mode 100644 index 00000000..f0f659cd --- /dev/null +++ b/src/scripts/vnet/mpls-o-gre/dhcpd.conf @@ -0,0 +1,116 @@ +# +# Sample configuration file for ISC dhcpd for Debian +# +# Attention: If /etc/ltsp/dhcpd.conf exists, that will be used as +# configuration file instead of this file. +# +# + +# The ddns-updates-style parameter controls whether or not the server will +# attempt to do a DNS update when a lease is confirmed. We default to the +# behavior of the version 2 packages ('none', since DHCP v2 didn't +# have support for DDNS.) +ddns-update-style none; + +# option definitions common to all supported networks... +option domain-name "example.org"; +option domain-name-servers ns1.example.org, ns2.example.org; + +default-lease-time 600; +max-lease-time 7200; + +# If this DHCP server is the official DHCP server for the local +# network, the authoritative directive should be uncommented. +#authoritative; + +# Use this to send dhcp log messages to a different log file (you also +# have to hack syslog.conf to complete the redirection). +log-facility local7; + +# No service will be given on this subnet, but declaring it helps the +# DHCP server to understand the network topology. + +#subnet 10.152.187.0 netmask 255.255.255.0 { +#} + +# This is a very basic subnet declaration. + +#subnet 10.254.239.0 netmask 255.255.255.224 { +# range 10.254.239.10 10.254.239.20; +# option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org; +#} + +# This declaration allows BOOTP clients to get dynamic addresses, +# which we don't really recommend. + +#subnet 10.254.239.32 netmask 255.255.255.224 { +# range dynamic-bootp 10.254.239.40 10.254.239.60; +# option broadcast-address 10.254.239.31; +# option routers rtr-239-32-1.example.org; +#} + +# A slightly different configuration for an internal subnet. +#subnet 10.5.5.0 netmask 255.255.255.224 { +# range 10.5.5.26 10.5.5.30; +# option domain-name-servers ns1.internal.example.org; +# option domain-name "internal.example.org"; +# option routers 10.5.5.1; +# option broadcast-address 10.5.5.31; +# default-lease-time 600; +# max-lease-time 7200; +#} + +# Hosts which require special configuration options can be listed in +# host statements. If no address is specified, the address will be +# allocated dynamically (if possible), but the host-specific information +# will still come from the host declaration. + +#host passacaglia { +# hardware ethernet 0:0:c0:5d:bd:95; +# filename "vmunix.passacaglia"; +# server-name "toccata.fugue.com"; +#} + +# Fixed IP addresses can also be specified for hosts. These addresses +# should not also be listed as being available for dynamic assignment. +# Hosts for which fixed IP addresses have been specified can boot using +# BOOTP or DHCP. Hosts for which no fixed address is specified can only +# be booted with DHCP, unless there is an address range on the subnet +# to which a BOOTP client is connected which has the dynamic-bootp flag +# set. +#host fantasia { +# hardware ethernet 08:00:07:26:c0:a5; +# fixed-address fantasia.fugue.com; +#} + +# You can declare a class of clients and then do address allocation +# based on that. The example below shows a case where all clients +# in a certain class get addresses on the 10.17.224/24 subnet, and all +# other clients get addresses on the 10.0.29/24 subnet. + +#class "foo" { +# match if substring (option vendor-class-identifier, 0, 4) = "SUNW"; +#} + +#shared-network 224-29 { +# subnet 10.17.224.0 netmask 255.255.255.0 { +# option routers rtr-224.example.org; +# } +# subnet 10.0.29.0 netmask 255.255.255.0 { +# option routers rtr-29.example.org; +# } +# pool { +# allow members of "foo"; +# range 10.17.224.10 10.17.224.250; +# } +# pool { +# deny members of "foo"; +# range 10.0.29.10 10.0.29.230; +# } +#} +subnet 6.0.0.0 netmask 255.255.0.0 { + range 6.0.2.2 6.0.2.5; + option routers 6.0.2.1; + default-lease-time 15; + max-lease-time 15; +} diff --git a/src/scripts/vnet/mpls-o-gre/leftpeer.conf b/src/scripts/vnet/mpls-o-gre/leftpeer.conf new file mode 100644 index 00000000..149c70c0 --- /dev/null +++ b/src/scripts/vnet/mpls-o-gre/leftpeer.conf @@ -0,0 +1,14 @@ +comment { left linux ping target configure at e.g. 6.0.2.2/24 } + +set int ip table GigabitEthernet2/2/0 1 +set int ip address GigabitEthernet2/2/0 6.0.2.1/24 +set int state GigabitEthernet2/2/0 up + +comment { tunnel to rightpeer } +set int ip address GigabitEthernet2/3/0 6.0.3.1/24 +set int state GigabitEthernet2/3/0 up + +mpls encap add label 30 fib 1 dest 6.0.3.3 +mpls decap add label 30 fib 1 + +create mpls gre tunnel src 6.0.3.1 dst 6.0.3.3 intfc 6.0.4.1/24 inner-fib-id 1 outer-fib-id 0 diff --git a/src/scripts/vnet/mpls-o-gre/rightpeer.conf b/src/scripts/vnet/mpls-o-gre/rightpeer.conf new file mode 100644 index 00000000..b5bb597d --- /dev/null +++ b/src/scripts/vnet/mpls-o-gre/rightpeer.conf @@ -0,0 +1,14 @@ +comment { right linux ping target configure e.g. 6.0.4.4/24 } + +set int ip table GigabitEthernet2/4/0 1 +set int ip address GigabitEthernet2/4/0 6.0.4.1/24 +set int state GigabitEthernet2/4/0 up + +comment { tunnel to leftpeer } +set int ip address GigabitEthernet2/3/0 6.0.3.3/24 +set int state GigabitEthernet2/3/0 up + +mpls encap add label 30 fib 1 dest 6.0.3.1 +mpls decap add label 30 fib 1 + +create mpls gre tunnel src 6.0.3.3 dst 6.0.3.1 intfc 6.0.2.1/24 inner-fib-id 1 outer-fib-id 0 diff --git a/src/scripts/vnet/mpls-tunnel b/src/scripts/vnet/mpls-tunnel new file mode 100644 index 00000000..d04b2970 --- /dev/null +++ b/src/scripts/vnet/mpls-tunnel @@ -0,0 +1,87 @@ +packet-generator new { + name x0 + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + ICMP: 1.0.0.2 -> 2.0.0.2 + ICMP echo_request + incrementing 100 + } +} +packet-generator new { + name x1 + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + ICMP: 1.0.0.2 -> 2.0.1.2 + ICMP echo_request + incrementing 100 + } +} +packet-generator new { + name x2 + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + ICMP: 1.0.0.2 -> 2.0.2.2 + ICMP echo_request + incrementing 100 + } +} +packet-generator new { + name x3 + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + ICMP: 1.0.0.2 -> 2.0.3.2 + ICMP echo_request + incrementing 100 + } +} + + + +trace add pg-input 100 + +loop create +set int state loop0 up + +set int ip address loop0 10.0.0.1/24 +set ip arp loop0 10.0.0.2 00:00:11:aa:bb:cc + +mpls tunnel add via 10.0.0.2 loop0 out-label 33 out-label 34 out-label 35 out-label 36 +set int state mpls-tunnel0 up +set int ip addr mpls-tunnel0 192.168.0.1/32 +ip route add 2.0.0.2/32 via 192.168.0.2 mpls-tunnel0 + + +mpls tunnel add via 10.0.0.2 out-label 33 +set int state mpls-tunnel1 up +set int ip addr mpls-tunnel1 192.168.1.1/32 +ip route add 2.0.1.2/32 via 192.168.1.2 mpls-tunnel1 out-label 99 + +mpls tunnel add via 10.0.0.2 loop0 out-label 3 +set int state mpls-tunnel2 up +set int ip addr mpls-tunnel2 192.168.2.1/32 +ip route add 2.0.2.2/32 via 192.168.2.2 mpls-tunnel2 + + +mpls tunnel add l2-only via 10.0.0.2 loop0 out-label 234 out-label 0 +set int state mpls-tunnel3 up +set int l2 bridge mpls-tunnel3 1 + +loop create +set int ip addr loop1 6.0.1.44/24 +set int l2 bridge loop1 1 bvi +set int l2 learn loop1 disable +set int state loop1 up + +ip route add 2.0.3.2/32 via 6.0.1.45 loop1 diff --git a/src/scripts/vnet/pcap b/src/scripts/vnet/pcap new file mode 100644 index 00000000..692e5f27 --- /dev/null +++ b/src/scripts/vnet/pcap @@ -0,0 +1,18 @@ +packet-generator new { + name x + limit 1 + node ethernet-input + no-recycle + pcap /home/eliot/pcap-data/ISIS_level1_adjacency.cap +} + +packet-generator new { + name y + limit 1 + node hdlc-input + no-recycle + pcap /home/eliot/pcap-data/ISIS_p2p_adjacency.cap +} + +tr add pg-input 10 + diff --git a/src/scripts/vnet/probe4 b/src/scripts/vnet/probe4 new file mode 100644 index 00000000..b530e0db --- /dev/null +++ b/src/scripts/vnet/probe4 @@ -0,0 +1,11 @@ +ethernet create-interfaces +set int state fake-eth0 up +set int ip address fake-eth0 1.0.0.1/24 +comment { error } +comment { ip probe fake-eth0 1.0.0.1 } +comment { ip probe fake-eth0 1.2.3.4 } +comment { error } +comment { ip probe fake-eth0 1.0.0.2 } + + + diff --git a/src/scripts/vnet/probe6 b/src/scripts/vnet/probe6 new file mode 100644 index 00000000..a5490c90 --- /dev/null +++ b/src/scripts/vnet/probe6 @@ -0,0 +1,7 @@ +ethernet create-interfaces +set int state fake-eth0 up +set int ip address fake-eth0 2000::1/64 +comment { ip probe fake-eth0 2000::1 } + + + diff --git a/src/scripts/vnet/rewrite b/src/scripts/vnet/rewrite new file mode 100644 index 00000000..d41b9dbf --- /dev/null +++ b/src/scripts/vnet/rewrite @@ -0,0 +1,62 @@ + + +comment { test ipv4 port/vlan/qinq rewrites by generating arps } + +set int state tuntap-0 down + +set int ip address GigabitEthernet2/2/0 1.2.5.4/24 + +cre sub GigabitEthernet2/2/0 1 dot1q 6 exact-match +set int ip address GigabitEthernet2/2/0.1 1.2.6.4/24 + +cre sub GigabitEthernet2/2/0 2 dot1ad 7 inner-dot1q 8 exact-match +set int ip address GigabitEthernet2/2/0.2 1.2.7.4/24 + +set int state GigabitEthernet2/1/0 up +set int state GigabitEthernet2/2/0 up +set int state GigabitEthernet2/2/0.1 up +set int state GigabitEthernet2/2/0.2 up + +trace add pg-input 2 + +cle er +cle int +cle run + +packet-generator new { + name toport + limit 2 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + data { + IP4: 0050.56b7.7c83 -> 0050.56b7.296d + GRE: 8.0.0.1 -> 1.2.5.6 mpls_unicast + } +} + +packet-generator new { + name tovlan + limit 2 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + data { + IP4: 0050.56b7.7c83 -> 0050.56b7.296d + GRE: 8.0.0.1 -> 1.2.6.6 mpls_unicast + } +} + +packet-generator new { + name toqinq + limit 2 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + data { + IP4: 0050.56b7.7c83 -> 0050.56b7.296d + GRE: 8.0.0.1 -> 1.2.7.6 mpls_unicast + } +} + + diff --git a/src/scripts/vnet/rightpeer/rightpeer-ioam.conf b/src/scripts/vnet/rightpeer/rightpeer-ioam.conf new file mode 100644 index 00000000..3e9a8d34 --- /dev/null +++ b/src/scripts/vnet/rightpeer/rightpeer-ioam.conf @@ -0,0 +1,14 @@ +comment { connects to right ping target eth3 addr db04::4/64 } +set int ip address GigabitEthernet2/4/0 db04::1/64 +set int state GigabitEthernet2/4/0 up + +comment { connects to ioam domain leftpeer addr db03::1/64 } +set int ip address GigabitEthernet2/3/0 db03::3/64 +set int state GigabitEthernet2/3/0 up + +set ip6 neighbor GigabitEthernet2/3/0 db03::1 00:50:56:b7:05:bf +set ip6 neighbor GigabitEthernet2/4/0 db04::4 00:50:56:b7:05:d2 + +ip route add db02::0/64 via db03::1 + +ioam set destination db04::4/128 pop diff --git a/src/scripts/vnet/rightpeer/rightpeer-l3vxlan.conf b/src/scripts/vnet/rightpeer/rightpeer-l3vxlan.conf new file mode 100644 index 00000000..abba1ab0 --- /dev/null +++ b/src/scripts/vnet/rightpeer/rightpeer-l3vxlan.conf @@ -0,0 +1,9 @@ +set int ip address GigabitEthernet2/4/0 6.0.4.1/24 +set int state GigabitEthernet2/4/0 up + +comment { tunnel to leftpeer on vlan 101 } +set int ip address GigabitEthernet2/3/0 6.0.3.3/24 +set int state GigabitEthernet2/3/0 up + +vxlan tunnel src 6.0.3.3 peer 6.0.3.1 vni 123 adj 6.0.2.0/24 + diff --git a/src/scripts/vnet/rightpeer/rightpeer-lisp.conf b/src/scripts/vnet/rightpeer/rightpeer-lisp.conf new file mode 100644 index 00000000..961204a3 --- /dev/null +++ b/src/scripts/vnet/rightpeer/rightpeer-lisp.conf @@ -0,0 +1,16 @@ +comment { local client facing interface } +comment { configure lc4 eth1 at e.g. 6.0.4.4/24 } + +set int ip address GigabitEthernet2/4/0 6.0.4.1/24 +set int state GigabitEthernet2/4/0 up + +comment { tunnel to leftpeer } +set int ip address GigabitEthernet2/3/0 6.0.3.3/24 +set int state GigabitEthernet2/3/0 up + +lisp gpe tunnel src 6.0.3.3 dst 6.0.3.1 next-ip4 decap-next ip4 iid 3311 +set int ip address lisp_gpe_tunnel0 6.0.2.3/24 +set int state lisp_gpe_tunnel0 up + +lisp gpe tunnel src 6.0.3.1 dst 6.0.3.3 next-ip4 decap-next ip4 iid 1133 +set int state lisp_gpe_tunnel1 up diff --git a/src/scripts/vnet/rightpeer/rightpeer-mpls-l2.conf b/src/scripts/vnet/rightpeer/rightpeer-mpls-l2.conf new file mode 100644 index 00000000..0ce38583 --- /dev/null +++ b/src/scripts/vnet/rightpeer/rightpeer-mpls-l2.conf @@ -0,0 +1,24 @@ +comment { vpe_phase1d configuration } + +comment { local client facing interface } +comment { configure lc4 eth1 at e.g. 6.0.4.4/24 } + +set int ip table GigabitEthernet2/4/0 1 +set int ip address GigabitEthernet2/4/0 6.0.4.1/24 +set int state GigabitEthernet2/4/0 up + +comment { tunnel to leftpeer } +set int ip address GigabitEthernet2/3/0 6.0.3.3/24 +set int state GigabitEthernet2/3/0 up + +mpls encap add label 30 fib 1 dest 6.0.3.1 +mpls decap add label 30 next output GigabitEthernet2/4/0 + +comment { create mpls gre tunnel src 6.0.3.3 dst 6.0.3.1 intfc 6.0.2.1/24 inner-fib-id 1 outer-fib-id 0 l2-only } + +comment {set int l2 xconnect GigabitEthernet2/4/0 mpls-gre0 } + +uncomment { create mpls ethernet tunnel dst 00:50:56:b7:05:bf adj 6.0.3.1/8 l2-only tx-intfc GigabitEthernet2/3/0 fib-id 1 } + +uncomment { set int l2 xconnect GigabitEthernet2/4/0 mpls-eth0 } + diff --git a/src/scripts/vnet/rightpeer/rightpeer-mpls.conf b/src/scripts/vnet/rightpeer/rightpeer-mpls.conf new file mode 100644 index 00000000..fc97ba16 --- /dev/null +++ b/src/scripts/vnet/rightpeer/rightpeer-mpls.conf @@ -0,0 +1,17 @@ +comment { vpe_phase1d configuration } + +comment { local client facing interface } +comment { configure lc4 eth1 at e.g. 6.0.4.4/24 } + +set int ip table GigabitEthernet2/4/0 1 +set int ip address GigabitEthernet2/4/0 6.0.4.1/24 +set int state GigabitEthernet2/4/0 up + +comment { tunnel to leftpeer } +set int ip address GigabitEthernet2/3/0 6.0.3.3/24 +set int state GigabitEthernet2/3/0 up + +mpls encap add label 30 fib 1 dest 6.0.3.1 +mpls decap add label 30 fib 1 + +create mpls gre tunnel src 6.0.3.3 dst 6.0.3.1 intfc 6.0.2.1/24 inner-fib-id 1 outer-fib-id 0 diff --git a/src/scripts/vnet/rightpeer/rightpeer-sr.conf b/src/scripts/vnet/rightpeer/rightpeer-sr.conf new file mode 100644 index 00000000..0b2a98bb --- /dev/null +++ b/src/scripts/vnet/rightpeer/rightpeer-sr.conf @@ -0,0 +1,28 @@ +comment { test sr segment chunk-offset on } +test sr hmac validate on + +comment { trunk to leftpeer } +set int ip address GigabitEthernet2/3/0 db03::1/64 +enable ip6 interface GigabitEthernet2/3/0 +set int state GigabitEthernet2/3/0 up + +comment { subscriber right peer target } +set int ip address GigabitEthernet2/4/0 db04::2/64 + +comment { next address to fake out ND on shared LAN segment } +comment { set int ip address GigabitEthernet2/4/0 db02::13/64 } + +enable ip6 interface GigabitEthernet2/4/0 +set int state GigabitEthernet2/4/0 up + +sr hmac id 2 key Gozzer +sr hmac id 3 key Hoser + +sr tunnel src db04::1 dst db02::1/128 next db03::2 next db02::1 tag db04::2 clean key Hoser + +tap connect srlocal hwaddr random +set int ip6 table tap-0 1 +set int ip address tap-0 db04::99/64 +enable ip6 interface tap-0 +set int state tap-0 up +ip route add table 1 db02::0/64 lookup in table 0 diff --git a/src/scripts/vnet/rightpeer/rightpeer-vxlan.conf b/src/scripts/vnet/rightpeer/rightpeer-vxlan.conf new file mode 100644 index 00000000..bd4c427e --- /dev/null +++ b/src/scripts/vnet/rightpeer/rightpeer-vxlan.conf @@ -0,0 +1,16 @@ + +comment { local client facing interface } + +comment { configure client lc4 eth1 } +set int state GigabitEthernet2/4/0 up + +comment { tunnel to leftpeer } +set int ip address GigabitEthernet2/3/0 6.0.3.3/24 +set int state GigabitEthernet2/3/0 up + +comment { tunnel to extra ping target } +set int ip address GigabitEthernet2/7/0 6.0.5.3/24 +set int state GigabitEthernet2/3/0 up + +vxlan tunnel src 6.0.3.3 peer 6.0.3.1 peer 6.0.3.5 vni 123 +vxlan l2 GigabitEthernet2/4/0 vni 123 diff --git a/src/scripts/vnet/rightpeer/rightpeer.script b/src/scripts/vnet/rightpeer/rightpeer.script new file mode 100644 index 00000000..153988ce --- /dev/null +++ b/src/scripts/vnet/rightpeer/rightpeer.script @@ -0,0 +1,9 @@ +l2tp_set_lookup_key lookup_v6_src + +sw_interface_add_del_address GigabitEthernet2/3/0 db03::1/64 +sw_interface_set_flags GigabitEthernet2/3/0 admin-up + +comment sw_interface_add_del_address GigabitEthernet2/4/0 db02::2/64 +sw_interface_set_flags GigabitEthernet2/4/0 admin-up + +l2tp_session_add_del client_address db03::2 our_address db03::1 GigabitEthernet2/4/0 local_session_id 3 remote_session_id 1 local_cookie 33 remote_cookie 11 diff --git a/src/scripts/vnet/rpf b/src/scripts/vnet/rpf new file mode 100644 index 00000000..571c6b79 --- /dev/null +++ b/src/scripts/vnet/rpf @@ -0,0 +1,18 @@ +packet-generator new { + name x + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + ICMP: 1.2.3.4 -> 5.6.7.8 + ICMP echo_request + incrementing 100 + } +} + +tr add pg-input 100 +set interface ip source-check pg/stream-0 +ip route 1.2.3.4/32 via pg/stream-0 0x01020304 +ip route 5.6.7.8/32 via drop + diff --git a/src/scripts/vnet/rtt-test b/src/scripts/vnet/rtt-test new file mode 100644 index 00000000..5501b99d --- /dev/null +++ b/src/scripts/vnet/rtt-test @@ -0,0 +1,31 @@ +set int state TenGigabitEthernet4/0/0 up +set int state TenGigabitEthernet5/0/0 up + +set int ip address TenGigabitEthernet4/0/0 1.0.0.1/24 +set int ip address TenGigabitEthernet5/0/0 2.0.0.1/24 + +ip route table 0 1.0.0.2/32 via TenGigabitEthernet4/0/0 IP4: 00:1b:21:74:5b:04 -> 00:1b:21:79:8e:bc +ip route table 0 2.0.0.2/32 via TenGigabitEthernet5/0/0 IP4: 00:1b:21:79:8e:bc -> 00:1b:21:74:5b:04 +ip route table 1 2.0.0.2/32 via local +ip route table 1 1.0.0.2/32 via local + +set int ip table TenGigabitEthernet5/0/0 1 +set int ip table TenGigabitEthernet4/0/0 1 + +comment { trace add rtt-test-tx 100 } +comment { trace add ixge-input 100 } +comment { te rtt { 1.0.0.2 -> 2.0.0.2 count 1e4 rate 1e9 size 100 histogram-time 1e-5 } } + +packet-generator new { + name x + limit 1 + node ip4-input + size 170-170 + data { + ICMP: 1.0.0.2 -> 2.0.0.2 + ICMP echo_request + incrementing 100 + } +} + + diff --git a/src/scripts/vnet/snat b/src/scripts/vnet/snat new file mode 100644 index 00000000..87fd699e --- /dev/null +++ b/src/scripts/vnet/snat @@ -0,0 +1,34 @@ +packet-generator new { + name f1 + limit 1000000 + node ip4-input + size 64-64 + no-recycle + worker 0 + data { + UDP: 10.0.0.3 -> 172.16.1.2 + UDP: 3000 -> 3001 + length 128 checksum 0 incrementing 1 + } +} + + +packet-generator new { + name f2 + limit 1000000 + node ip4-input + size 64-64 + no-recycle + worker 1 + data { + UDP: 10.0.0.3 -> 172.16.1.2 + UDP: 3005 -> 3006 + length 128 checksum 0 incrementing 1 + } +} + +snat add address 172.16.1.3 +ip route 172.16.1.2/32 via drop +set int ip address pg0 10.0.0.1/24 +set int snat in pg0 +trace add pg-input 10 diff --git a/src/scripts/vnet/snat_static b/src/scripts/vnet/snat_static new file mode 100644 index 00000000..8fe48bff --- /dev/null +++ b/src/scripts/vnet/snat_static @@ -0,0 +1,44 @@ +create packet-generator interface pg0 +create packet-generator interface pg1 + +packet-generator new { + name f1 + limit 1000000 + node ip4-input + size 64-64 + no-recycle + worker 0 + interface pg0 + data { + UDP: 10.0.0.3 -> 172.16.1.2 + UDP: 3000 -> 3001 + length 128 checksum 0 incrementing 1 + } +} + + +packet-generator new { + name f2 + limit 1000000 + node ip4-input + size 64-64 + no-recycle + worker 1 + interface pg1 + data { + UDP: 172.16.1.2 -> 172.16.1.3 + UDP: 3001 -> 3000 + length 128 checksum 0 incrementing 1 + } +} + +snat add address 172.16.1.3 +snat add static mapping local 10.0.0.3 external 172.16.1.3 +set int ip address pg0 10.0.0.1/24 +set int ip address pg1 172.16.1.1/24 +set int state pg0 up +set int state pg1 up +set ip arp static pg0 10.0.0.3 abcd.abcd.abcd +set ip arp static pg1 172.16.1.2 cdef.abcd.abcd +set int snat in pg0 out pg1 +trace add pg-input 10 diff --git a/src/scripts/vnet/snat_static_with_port b/src/scripts/vnet/snat_static_with_port new file mode 100644 index 00000000..f646145a --- /dev/null +++ b/src/scripts/vnet/snat_static_with_port @@ -0,0 +1,44 @@ +create packet-generator interface pg0 +create packet-generator interface pg1 + +packet-generator new { + name f1 + limit 1000000 + node ip4-input + size 64-64 + no-recycle + worker 0 + interface pg0 + data { + UDP: 10.0.0.3 -> 172.16.1.2 + UDP: 3000 -> 3001 + length 128 checksum 0 incrementing 1 + } +} + + +packet-generator new { + name f2 + limit 1000000 + node ip4-input + size 64-64 + no-recycle + worker 1 + interface pg1 + data { + UDP: 172.16.1.2 -> 172.16.1.3 + UDP: 3001 -> 3000 + length 128 checksum 0 incrementing 1 + } +} + +snat add address 172.16.1.3 +snat add static mapping local 10.0.0.3 3000 external 172.16.1.3 3000 +set int ip address pg0 10.0.0.1/24 +set int ip address pg1 172.16.1.1/24 +set int state pg0 up +set int state pg1 up +set ip arp static pg0 10.0.0.3 abcd.abcd.abcd +set ip arp static pg1 172.16.1.2 cdef.abcd.abcd +set int snat in pg0 out pg1 +trace add pg-input 10 diff --git a/src/scripts/vnet/source_and_port_range_check b/src/scripts/vnet/source_and_port_range_check new file mode 100644 index 00000000..dce227b4 --- /dev/null +++ b/src/scripts/vnet/source_and_port_range_check @@ -0,0 +1,63 @@ + +create loop int + +set int state loop0 up +set int ip addr loop0 10.10.10.10/32 + +packet-generator new { + name deny-from-default-route + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + UDP: 1.2.3.4 -> 5.6.7.8 + UDP: 3000 -> 3001 + length 128 checksum 0 incrementing 1 + } +} + +packet-generator new { + name allow + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + UDP: 1.1.1.1 -> 5.6.7.8 + UDP: 3000 -> 3001 + length 128 checksum 0 incrementing 1 + } +} + +packet-generator new { + name deny-from-port-range + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + UDP: 1.1.1.1 -> 5.6.7.8 + UDP: 6000 -> 6001 + length 128 checksum 0 incrementing 1 + } +} + +set ip source-and-port-range-check 1.1.1.0/24 range 2000 - 3000 vrf 99 + +set interface ip source-and-port-range-check pg0 udp-out-vrf 99 + + show ip source-and-port-range-check vrf 99 1.1.1.1 + +set ip source-and-port-range-check 1.1.1.0/24 range 4000 - 5000 vrf 99 + +set ip source-and-port-range-check 1.1.2.0/24 range 4000 - 5000 vrf 99 + +show ip source-and-port-range-check vrf 99 1.1.1.1 +show ip source-and-port-range-check vrf 99 1.1.2.1 + +set ip source-and-port-range-check 1.1.2.0/24 range 4000 - 5000 vrf 99 del + +show ip source-and-port-range-check vrf 99 1.1.2.1 + +tr add pg-input 100 diff --git a/src/scripts/vnet/speed b/src/scripts/vnet/speed new file mode 100644 index 00000000..d60d671f --- /dev/null +++ b/src/scripts/vnet/speed @@ -0,0 +1,14 @@ +packet-generator new { + name x + limit 1 + node ip4-input + size 50-50 + data { + ICMP: 1.2.3.4 -> 5.6.7.8 + ICMP echo_request + incrementing 100 + } +} + +tr add pg-input 100 +ip route 5.6.7.8/32 via pg/stream-0 000102030405060708090a0b0c0d diff --git a/src/scripts/vnet/sr/left-linux-ping.sh b/src/scripts/vnet/sr/left-linux-ping.sh new file mode 100755 index 00000000..55b83506 --- /dev/null +++ b/src/scripts/vnet/sr/left-linux-ping.sh @@ -0,0 +1,3 @@ +#!/bin/bash +ifconfig eth2 inet6 add db02::1/64 +route -A inet6 add db04::1/128 gw db02::2 diff --git a/src/scripts/vnet/sr/leftpeer.conf b/src/scripts/vnet/sr/leftpeer.conf new file mode 100644 index 00000000..9591d968 --- /dev/null +++ b/src/scripts/vnet/sr/leftpeer.conf @@ -0,0 +1,27 @@ +comment { test sr segment chunk-offset on } +test sr hmac validate on + +comment { trunk to rightpeer } +set int ip address GigabitEthernet2/3/0 db03::2/64 +enable ip6 interface GigabitEthernet2/3/0 +set int state GigabitEthernet2/3/0 up + +comment { subscriber left-linux-ping } +set int ip address GigabitEthernet2/2/0 db02::2/64 +enable ip6 interface GigabitEthernet2/2/0 +set int state GigabitEthernet2/2/0 up + +sr hmac id 2 key Gozzer +sr hmac id 3 key Hoser + +sr tunnel src db01::1 dst db04::1/128 next db03::1 next db04::1 tag db02::2 clean key Gozzer InPE 1 + +comment { sr unaware service chaining to db03::5 } +comment { sr tunnel src db01::1 dst db04::1/128 next db03::1 next db03::5 next db04::1 tag db02::2 clean key Gozzer InPE 1 } + +comment { tap connect srlocal hwaddr random } +comment { set int ip6 table tap-0 1 } +comment { set int ip address tap-0 db04::99/64 } +comment { enable ip6 interface tap-0 } +comment { set int state tap-0 up } +comment { ip route add table 1 db02::0/64 lookup in table 0 } diff --git a/src/scripts/vnet/sr/right-linux-ping.sh b/src/scripts/vnet/sr/right-linux-ping.sh new file mode 100755 index 00000000..029368db --- /dev/null +++ b/src/scripts/vnet/sr/right-linux-ping.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +ifconfig eth1 inet6 add db04::1/64 +route -A inet6 add db02::1/128 gw db04::2 diff --git a/src/scripts/vnet/sr/rightpeer.conf b/src/scripts/vnet/sr/rightpeer.conf new file mode 100644 index 00000000..6da7a7af --- /dev/null +++ b/src/scripts/vnet/sr/rightpeer.conf @@ -0,0 +1,22 @@ +comment { trunk to leftpeer } +set int ip address GigabitEthernet2/0/0 db03::1/64 +enable ip6 interface GigabitEthernet2/0/0 +set int state GigabitEthernet2/0/0 up + +comment { subscriber right-linux-ping } +set int ip address GigabitEthernet2/2/0 db04::2/64 + +comment { next address to fake out ND on shared LAN segment } +set int ip address GigabitEthernet2/2/0 db02::13/64 + +enable ip6 interface GigabitEthernet2/2/0 +set int state GigabitEthernet2/2/0 up + +sr tunnel src db04::1 dst db02::1/128 next db03::2 next db02::1 tag db04::2 clean + +tap connect srlocal hwaddr random +set int ip6 table tap-0 1 +set int ip address tap-0 db04::99/64 +enable ip6 interface tap-0 +set int state tap-0 up +ip route add table 1 db02::0/64 lookup in table 0 diff --git a/src/scripts/vnet/sr/srlocal.sh b/src/scripts/vnet/sr/srlocal.sh new file mode 100755 index 00000000..2f568408 --- /dev/null +++ b/src/scripts/vnet/sr/srlocal.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +ifconfig srlocal inet6 add db04::1/64 +route -6 add db02::0/64 gw db04::99 diff --git a/src/scripts/vnet/srp b/src/scripts/vnet/srp new file mode 100644 index 00000000..7cc37011 --- /dev/null +++ b/src/scripts/vnet/srp @@ -0,0 +1,27 @@ +srp create-interfaces +srp create-interfaces +set int hw-class fake-srp0 srp +set int hw-class fake-srp1 srp + +packet-generator new { + name x + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + ICMP: 1.0.0.2 -> 2.0.0.2 + ICMP echo_request + incrementing 100 + } +} + +tr add pg-input 100 +set int state fake-srp0 up +set int state fake-srp1 up + +set int ip address fake-srp0 1.0.0.1/24 +set int ip address fake-srp1 2.0.0.1/24 + + + diff --git a/src/scripts/vnet/tcp b/src/scripts/vnet/tcp new file mode 100644 index 00000000..a2ee8b2d --- /dev/null +++ b/src/scripts/vnet/tcp @@ -0,0 +1,16 @@ +packet-generator new { + name x + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + TCP: 1.2.3.4 -> 5.6.7.8 + TCP: 1234 -> 5678 + incrementing 100 + } +} + +tr add pg-input 100 +ip route 5.6.7.8/32 via local +ip route 1.2.3.4/32 via local diff --git a/src/scripts/vnet/tcp-test b/src/scripts/vnet/tcp-test new file mode 100644 index 00000000..52bfbcdd --- /dev/null +++ b/src/scripts/vnet/tcp-test @@ -0,0 +1,6 @@ +int create-ethernet +set int ip address fake-eth0 1.2.3.4/24 +set int state fake-eth0 up +ip route 1.2.3.5/32 via local +trace add tuntap-rx 100 + diff --git a/src/scripts/vnet/tf-ucs-1 b/src/scripts/vnet/tf-ucs-1 new file mode 100644 index 00000000..efa5f2dc --- /dev/null +++ b/src/scripts/vnet/tf-ucs-1 @@ -0,0 +1,16 @@ +comment { connected to Ixia port 1} +set int ip address TenGigabitEthernet4/0/0 1.0.0.2/8 + +set int state TenGigabitEthernet4/0/0 up + +comment { connected to Ixia port 2} +set int ip address TenGigabitEthernet4/0/1 2.0.0.2/8 +set int state TenGigabitEthernet4/0/1 up + +comment { connected to Ixia port 3} +set int ip address TenGigabitEthernet6/0/0 3.0.0.2/8 +set int state TenGigabitEthernet6/0/0 up + +comment { connected to Ixia port 4} +set int ip address TenGigabitEthernet6/0/1 4.0.0.2/8 +set int state TenGigabitEthernet6/0/1 up diff --git a/src/scripts/vnet/urpf b/src/scripts/vnet/urpf new file mode 100644 index 00000000..a4d87527 --- /dev/null +++ b/src/scripts/vnet/urpf @@ -0,0 +1,86 @@ + +create loop int + +set int state loop0 up +set int ip addr loop0 10.10.10.10/24 + +packet-generator new { + name transit-deny + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + UDP: 1.2.3.4 -> 2.2.2.2 + UDP: 3000 -> 3001 + length 128 checksum 0 incrementing 1 + } +} + +packet-generator new { + name transit-allow + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + UDP: 1.1.1.1 -> 2.2.2.2 + UDP: 3000 -> 3001 + length 128 checksum 0 incrementing 1 + } +} + +packet-generator new { + name transit-allow-from-excemption + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + UDP: 11.11.12.13 -> 2.2.2.2 + UDP: 6000 -> 6001 + length 128 checksum 0 incrementing 1 + } +} + +packet-generator new { + name for-us-allow-from-excemption + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + UDP: 11.11.12.13 -> 10.10.10.10 + UDP: 6000 -> 6001 + length 128 checksum 0 incrementing 1 + } +} + +packet-generator new { + name for-us-allow + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + UDP: 1.1.1.1 -> 10.10.10.10 + UDP: 3000 -> 3001 + length 128 checksum 0 incrementing 1 + } +} + +tr add pg-input 100 + +set int ip addr pg0 10.10.11.10/24 + +set interface ip source-check pg0 strict + +ip route add 1.1.1.1/32 via 10.10.11.11 pg0 +ip route add 2.2.2.2/32 via 10.10.10.11 loop0 + +ip urpf-accept 11.11.0.0/16 + +#set interface ip source-check pg0 strict del +#set interface ip source-check pg0 loose + +#ip urpf-accept del 11.11.0.0/16 diff --git a/src/scripts/vnet/virl/ip6sr.virl b/src/scripts/vnet/virl/ip6sr.virl new file mode 100644 index 00000000..5d4d1a0a --- /dev/null +++ b/src/scripts/vnet/virl/ip6sr.virl @@ -0,0 +1,874 @@ + + + + flat + dual_stack + false + + + + ! +! Last configuration change at 16:41:18 UTC Fri Mar 27 2015 +! +version 15.4 +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +! +hostname iosv-1 +! +boot-start-marker +boot-end-marker +! +! +enable password cisco +! +no aaa new-model +! +! +! +mmi polling-interval 60 +no mmi auto-configure +no mmi pvc +mmi snmp-timeout 180 +! +! +! +! +! +! +! +! +! +! +! +! +! +no ip domain lookup +ip cef +ipv6 unicast-routing +ipv6 cef +! +multilink bundle-name authenticated +! +! +cts logging verbose +! +! +! +redundancy +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + description Loopback + ip address 192.168.0.2 255.255.255.255 + ipv6 address ::B:1:0:0:2/128 +! +interface GigabitEthernet0/0 + description OOB Management + ip address 172.16.1.193 255.255.255.0 + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/1 + description to vpp-1 + ip address 10.0.0.5 255.255.255.252 + duplex auto + speed auto + media-type rj45 + ipv6 address ::A:1:1:0:6/126 +! +ip forward-protocol nd +! +! +no ip http server +no ip http secure-server +! +! route to iosv-2 +ipv6 route ::A:1:1:0:16/128 ::A:1:1:0:7 +! route to iosv-4 +ipv6 route ::A:1:1:0:22/128 ::A:1:1:0:7 +! +! +! +control-plane +! +banner exec ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner incoming ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner login ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +! +line con 0 + password cisco +line aux 0 +line vty 0 4 + exec-timeout 720 0 + password cisco + login + transport input telnet ssh +! +no scheduler allocate +! +end + + + + + + + ! +! Last configuration change at 16:41:10 UTC Fri Mar 27 2015 +! +version 15.4 +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +! +hostname iosv-2 +! +boot-start-marker +boot-end-marker +! +! +enable password cisco +! +no aaa new-model +! +! +! +mmi polling-interval 60 +no mmi auto-configure +no mmi pvc +mmi snmp-timeout 180 +! +! +! +! +! +! +! +! +! +! +! +! +! +no ip domain lookup +ip cef +ipv6 unicast-routing +ipv6 cef +! +multilink bundle-name authenticated +! +! +cts logging verbose +! +! +! +redundancy +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + description Loopback + ip address 192.168.0.3 255.255.255.255 + ipv6 address ::B:1:0:0:3/128 +! +interface GigabitEthernet0/0 + description OOB Management + ip address 172.16.1.191 255.255.255.0 + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/1 + description to vpp-2 + ip address 10.0.0.21 255.255.255.252 + duplex auto + speed auto + media-type rj45 + ipv6 address ::A:1:1:0:16/126 +! +ip forward-protocol nd +! +! +no ip http server +no ip http secure-server +! +ipv6 route ::A:1:1:0:6/128 ::A:1:1:0:17 +! +! +! +control-plane +! +banner exec ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner incoming ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner login ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +! +line con 0 + password cisco +line aux 0 +line vty 0 4 + exec-timeout 720 0 + password cisco + login + transport input telnet ssh +! +no scheduler allocate +! +end + + + + + + + ! +! Last configuration change at 16:27:43 UTC Fri Mar 27 2015 +! +version 15.4 +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +! +hostname iosv-3 +! +boot-start-marker +boot-end-marker +! +! +enable password cisco +! +no aaa new-model +! +! +! +mmi polling-interval 60 +no mmi auto-configure +no mmi pvc +mmi snmp-timeout 180 +! +! +! +! +! +! +! +! +! +! +! +! +! +no ip domain lookup +ip cef +ipv6 unicast-routing +ipv6 cef +! +multilink bundle-name authenticated +! +! +cts logging verbose +! +! +! +redundancy +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + description Loopback + ip address 192.168.0.6 255.255.255.255 + ipv6 address ::B:1:0:0:4/128 +! +interface GigabitEthernet0/0 + description OOB Management + ip address 172.16.1.192 255.255.255.0 + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/1 + description to vpp-1 + ip address 10.0.0.9 255.255.255.252 + duplex auto + speed auto + media-type rj45 + ipv6 address ::A:1:1:0:A/126 +! +ip forward-protocol nd +! +! +no ip http server +no ip http secure-server +! +! +! +! +control-plane +! +banner exec ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner incoming ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner login ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +! +line con 0 + password cisco +line aux 0 +line vty 0 4 + exec-timeout 720 0 + password cisco + login + transport input telnet ssh +! +no scheduler allocate +! +end + + + + + + + ! +! Last configuration change at 16:27:43 UTC Fri Mar 27 2015 +! +version 15.4 +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +! +hostname iosv-4 +! +boot-start-marker +boot-end-marker +! +! +enable password cisco +! +no aaa new-model +! +! +! +mmi polling-interval 60 +no mmi auto-configure +no mmi pvc +mmi snmp-timeout 180 +! +! +! +! +! +! +! +! +! +! +! +! +! +no ip domain lookup +ip cef +ipv6 unicast-routing +ipv6 cef +! +multilink bundle-name authenticated +! +! +cts logging verbose +! +! +! +redundancy +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + description Loopback + ip address 192.168.0.8 255.255.255.255 + ipv6 address ::B:1:0:0:5/128 +! +interface GigabitEthernet0/0 + description OOB Management + ip address 172.16.1.194 255.255.255.0 + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/1 + description to vpp-2 + ip address 10.0.0.33 255.255.255.252 + duplex auto + speed auto + media-type rj45 + ipv6 address ::A:1:1:0:22/126 +! +! Route to iosv-1 +ipv6 route ::A:1:1:0:6/128 ::A:1:1:0:23 +ip forward-protocol nd +! +! +no ip http server +no ip http secure-server +! +! +! +! +control-plane +! +banner exec ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner incoming ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner login ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +! +line con 0 + password cisco +line aux 0 +line vty 0 4 + exec-timeout 720 0 + password cisco + login + transport input telnet ssh +! +no scheduler allocate +! +end + + + + + + + #cloud-config +bootcmd: +- ln -s -t /etc/rc.d /etc/rc.local +hostname: vpp-1 +manage_etc_hosts: true +runcmd: +- start ttyS0 +- systemctl start getty@ttyS0.service +- systemctl start rc-local +- sed -i '/^\s*PasswordAuthentication\s\+no/d' /etc/ssh/sshd_config +- echo "UseDNS no" >> /etc/ssh/sshd_config +- service ssh restart +- service sshd restart +- sed -i 's/no-pci//' /cisco/etc/qn.conf +- sed -i 's/1024/1024 decimal-interface-names/g' /cisco/etc/qn.conf +users: +- default +- gecos: User configured by VIRL Configuration Engine 0.15.3 + lock-passwd: false + name: cisco + plain-text-passwd: cisco + shell: /bin/bash + ssh-authorized-keys: + - VIRL-USER-SSH-PUBLIC-KEY + sudo: ALL=(ALL) ALL +write_files: +- path: /etc/init/ttyS0.conf + owner: root:root + content: | + # ttyS0 - getty + # This service maintains a getty on ttyS0 from the point the system is + # started until it is shut down again. + start on stopped rc or RUNLEVEL=[12345] + stop on runlevel [!12345] + respawn + exec /sbin/getty -L 115200 ttyS0 vt102 + permissions: '0644' +- path: /etc/systemd/system/dhclient@.service + content: | + [Unit] + Description=Run dhclient on %i interface + After=network.target + [Service] + Type=oneshot + ExecStart=/sbin/dhclient %i -pf /var/run/dhclient.%i.pid -lf /var/lib/dhclient/dhclient.%i.lease + RemainAfterExit=yes + owner: root:root + permissions: '0644' +- path: /cisco/etc/vpp-server.conf + owner: root:root + permissions: '0644' + content: |- + set interface ip address GigabitEthernet0/4/0 10.0.0.6/30 + set interface ip address GigabitEthernet0/4/0 ::a:1:1:0:7/126 + set interface state GigabitEthernet0/4/0 up + set interface ip address GigabitEthernet0/5/0 10.0.0.10/30 + set interface ip address GigabitEthernet0/5/0 ::a:1:1:0:b/126 + set interface state GigabitEthernet0/5/0 up + set interface ip address GigabitEthernet0/6/0 10.0.0.13/30 + set interface ip address GigabitEthernet0/6/0 ::a:1:1:0:e/126 + set interface state GigabitEthernet0/6/0 up + set interface ip address GigabitEthernet0/7/0 10.0.0.17/30 + set interface ip address GigabitEthernet0/7/0 ::a:1:1:0:12/126 + set interface state GigabitEthernet0/7/0 up + sr tunnel src 0::a:1:1:0:6 dst 0::a:1:1:0:16/128 next 0::a:1:1:0:f next 0::a:1:1:0:1a next 0::a:1:1:0:16 tag 0::a:1:1:0:7 InPE 1 clean + sr tunnel src 0::a:1:1:0:6 dst 0::a:1:1:0:22/128 next 0::a:1:1:0:f next 0::a:1:1:0:1a next 0::a:1:1:0:22 tag 0::a:1:1:0:7 InPE 1 clean + + + + + + + + + + #cloud-config +bootcmd: +- ln -s -t /etc/rc.d /etc/rc.local +hostname: vpp-2 +manage_etc_hosts: true +runcmd: +- start ttyS0 +- systemctl start getty@ttyS0.service +- systemctl start rc-local +- sed -i '/^\s*PasswordAuthentication\s\+no/d' /etc/ssh/sshd_config +- echo "UseDNS no" >> /etc/ssh/sshd_config +- service ssh restart +- service sshd restart +- sed -i 's/no-pci//' /cisco/etc/qn.conf +- sed -i 's/1024/1024 decimal-interface-names/g' /cisco/etc/qn.conf +users: +- default +- gecos: User configured by VIRL Configuration Engine 0.15.3 + lock-passwd: false + name: cisco + plain-text-passwd: cisco + shell: /bin/bash + ssh-authorized-keys: + - VIRL-USER-SSH-PUBLIC-KEY + sudo: ALL=(ALL) ALL +write_files: +- path: /etc/init/ttyS0.conf + owner: root:root + content: | + # ttyS0 - getty + # This service maintains a getty on ttyS0 from the point the system is + # started until it is shut down again. + start on stopped rc or RUNLEVEL=[12345] + stop on runlevel [!12345] + respawn + exec /sbin/getty -L 115200 ttyS0 vt102 + permissions: '0644' +- path: /etc/systemd/system/dhclient@.service + content: | + [Unit] + Description=Run dhclient on %i interface + After=network.target + [Service] + Type=oneshot + ExecStart=/sbin/dhclient %i -pf /var/run/dhclient.%i.pid -lf /var/lib/dhclient/dhclient.%i.lease + RemainAfterExit=yes + owner: root:root + permissions: '0644' +- path: /cisco/etc/vpp-server.conf + owner: root:root + permissions: '0644' + content: |- + set interface ip address GigabitEthernet0/4/0 10.0.0.25/30 + set interface ip address GigabitEthernet0/4/0 ::a:1:1:0:1a/126 + set interface state GigabitEthernet0/4/0 up + set interface ip address GigabitEthernet0/5/0 10.0.0.29/30 + set interface ip address GigabitEthernet0/5/0 ::a:1:1:0:1e/126 + set interface state GigabitEthernet0/5/0 up + set interface ip address GigabitEthernet0/6/0 10.0.0.22/30 + set interface ip address GigabitEthernet0/6/0 ::a:1:1:0:17/126 + set interface state GigabitEthernet0/6/0 up + set interface ip address GigabitEthernet0/7/0 10.0.0.34/30 + set interface ip address GigabitEthernet0/7/0 ::a:1:1:0:23/126 + set interface state GigabitEthernet0/7/0 up + sr tunnel src 0::a:1:1:0:16 dst 0::a:1:1:0:6/128 next 0::a:1:1:0:1b next 0::a:1:1:0:e next 0::a:1:1:0:6 tag 0::a:1:1:0:17 InPE 1 clean + + + + + + + + + + #cloud-config +bootcmd: +- ln -s -t /etc/rc.d /etc/rc.local +hostname: vpp-3 +manage_etc_hosts: true +runcmd: +- start ttyS0 +- systemctl start getty@ttyS0.service +- systemctl start rc-local +- sed -i '/^\s*PasswordAuthentication\s\+no/d' /etc/ssh/sshd_config +- echo "UseDNS no" >> /etc/ssh/sshd_config +- service ssh restart +- service sshd restart +- sed -i 's/no-pci//' /cisco/etc/qn.conf +- sed -i 's/1024/1024 decimal-interface-names/g' /cisco/etc/qn.conf +users: +- default +- gecos: User configured by VIRL Configuration Engine 0.15.3 + lock-passwd: false + name: cisco + plain-text-passwd: cisco + shell: /bin/bash + ssh-authorized-keys: + - VIRL-USER-SSH-PUBLIC-KEY + sudo: ALL=(ALL) ALL +write_files: +- path: /etc/init/ttyS0.conf + owner: root:root + content: | + # ttyS0 - getty + # This service maintains a getty on ttyS0 from the point the system is + # started until it is shut down again. + start on stopped rc or RUNLEVEL=[12345] + stop on runlevel [!12345] + respawn + exec /sbin/getty -L 115200 ttyS0 vt102 + permissions: '0644' +- path: /etc/systemd/system/dhclient@.service + content: | + [Unit] + Description=Run dhclient on %i interface + After=network.target + [Service] + Type=oneshot + ExecStart=/sbin/dhclient %i -pf /var/run/dhclient.%i.pid -lf /var/lib/dhclient/dhclient.%i.lease + RemainAfterExit=yes + owner: root:root + permissions: '0644' +- path: /cisco/etc/vpp-server.conf + owner: root:root + permissions: '0644' + content: |- + set interface ip address GigabitEthernet0/4/0 10.0.0.14/30 + set interface ip address GigabitEthernet0/4/0 ::a:1:1:0:f/126 + set interface state GigabitEthernet0/4/0 up + set interface ip address GigabitEthernet0/5/0 10.0.0.26/30 + set interface ip address GigabitEthernet0/5/0 ::a:1:1:0:1b/126 + set interface state GigabitEthernet0/5/0 up + comment { fix src rpf drop screws} + ip route add ::a:1:1:0:6/128 via drop + ip route add ::a:1:1:0:16/128 via drop + ip route add ::a:1:1:0:22/128 via drop + + + + + + + + #cloud-config +bootcmd: +- ln -s -t /etc/rc.d /etc/rc.local +hostname: vpp-4 +manage_etc_hosts: true +runcmd: +- start ttyS0 +- systemctl start getty@ttyS0.service +- systemctl start rc-local +- sed -i '/^\s*PasswordAuthentication\s\+no/d' /etc/ssh/sshd_config +- echo "UseDNS no" >> /etc/ssh/sshd_config +- service ssh restart +- service sshd restart +- sed -i 's/no-pci//' /cisco/etc/qn.conf +- sed -i 's/1024/1024 decimal-interface-names/g' /cisco/etc/qn.conf +users: +- default +- gecos: User configured by VIRL Configuration Engine 0.15.3 + lock-passwd: false + name: cisco + plain-text-passwd: cisco + shell: /bin/bash + ssh-authorized-keys: + - VIRL-USER-SSH-PUBLIC-KEY + sudo: ALL=(ALL) ALL +write_files: +- path: /etc/init/ttyS0.conf + owner: root:root + content: | + # ttyS0 - getty + # This service maintains a getty on ttyS0 from the point the system is + # started until it is shut down again. + start on stopped rc or RUNLEVEL=[12345] + stop on runlevel [!12345] + respawn + exec /sbin/getty -L 115200 ttyS0 vt102 + permissions: '0644' +- path: /etc/systemd/system/dhclient@.service + content: | + [Unit] + Description=Run dhclient on %i interface + After=network.target + [Service] + Type=oneshot + ExecStart=/sbin/dhclient %i -pf /var/run/dhclient.%i.pid -lf /var/lib/dhclient/dhclient.%i.lease + RemainAfterExit=yes + owner: root:root + permissions: '0644' +- path: /cisco/etc/vpp-server.conf + owner: root:root + permissions: '0644' + content: |- + set interface ip address GigabitEthernet0/4/0 10.0.0.18/30 + set interface ip address GigabitEthernet0/4/0 ::a:1:1:0:13/126 + set interface state GigabitEthernet0/4/0 up + set interface ip address GigabitEthernet0/5/0 10.0.0.30/30 + set interface ip address GigabitEthernet0/5/0 ::a:1:1:0:1f/126 + set interface state GigabitEthernet0/5/0 up + + + + + + + + + + + + + + diff --git a/src/scripts/vnet/virl/ip6sr_notes.txt b/src/scripts/vnet/virl/ip6sr_notes.txt new file mode 100644 index 00000000..5febf2c6 --- /dev/null +++ b/src/scripts/vnet/virl/ip6sr_notes.txt @@ -0,0 +1,38 @@ +vpp-1, tunnel 1: iosv-1 vpp-1 vpp-3 vpp-2 iosv-2 + +iosv-1 +::a:1:1:0:6 + +to iosv2 +ipv6 route ::a:1:1:0:16/128 ::a:1:1:0:7 +to iosv4 +ipv6 route ::a:1:1:0:22/128 ::a:1:1:0:7 + +vpp-1 + +::a:1:1:0:7 +... +::a:1:1:0:e + +sr tunnel src 0::a:1:1:0:6 dst 0::a:1:1:0:16/128 next 0::a:1:1:0:f next 0::a:1:1:0:1a next 0::a:1:1:0:16 tag 0::a:1:1:0:7 InPE 1 clean + +vpp-3 +::a:1:1:0:f +.. +::a:1:1:0:1b + +comment {fix src rpf screws} +ip route add ::a:1:1:0:6/128 via drop +ip route add ::a:1:1:0:16/128 via drop +ip route add ::a:1:1:0:22/128 via drop +vpp-2 +::a:1:1:0:1a +.. +::a:1:1:0:17 + +sr tunnel src 0::a:1:1:0:16 dst 0::a:1:1:0:6/128 next 0::a:1:1:0:1b next 0::a:1:1:0:e next 0::a:1:1:0:6 tag 0::a:1:1:0:17 InPE 1 clean + +iosv-2 +::a:1:1:0:16 + +ipv6 route ::a:1:1:0:6/128 ::a:1:1:0:17 diff --git a/src/scripts/vnet/virl/mplsogre.virl b/src/scripts/vnet/virl/mplsogre.virl new file mode 100644 index 00000000..33dd0329 --- /dev/null +++ b/src/scripts/vnet/virl/mplsogre.virl @@ -0,0 +1,319 @@ + + + + flat + + + + #cloud-config +bootcmd: +- ln -s -t /etc/rc.d /etc/rc.local +hostname: vpp-1 +manage_etc_hosts: true +runcmd: +- start ttyS0 +- systemctl start getty@ttyS0.service +- systemctl start rc-local +- sed -i '/^\s*PasswordAuthentication\s\+no/d' /etc/ssh/sshd_config +- echo "UseDNS no" >> /etc/ssh/sshd_config +- service ssh restart +- service sshd restart +- sed -i 's/no-pci//' /cisco/etc/qn.conf +- sed -i 's/1024/1024 decimal-interface-names/g' /cisco/etc/qn.conf +users: +- default +- gecos: User configured by VIRL Configuration Engine 0.15.3 + lock-passwd: false + name: cisco + plain-text-passwd: cisco + shell: /bin/bash + ssh-authorized-keys: + - VIRL-USER-SSH-PUBLIC-KEY + sudo: ALL=(ALL) ALL +write_files: +- path: /etc/init/ttyS0.conf + owner: root:root + content: | + # ttyS0 - getty + # This service maintains a getty on ttyS0 from the point the system is + # started until it is shut down again. + start on stopped rc or RUNLEVEL=[12345] + stop on runlevel [!12345] + respawn + exec /sbin/getty -L 115200 ttyS0 vt102 + permissions: '0644' +- path: /etc/systemd/system/dhclient@.service + content: | + [Unit] + Description=Run dhclient on %i interface + After=network.target + [Service] + Type=oneshot + ExecStart=/sbin/dhclient %i -pf /var/run/dhclient.%i.pid -lf /var/lib/dhclient/dhclient.%i.lease + RemainAfterExit=yes + owner: root:root + permissions: '0644' +- path: /cisco/etc/vpp-server.conf + owner: root:root + permissions: '0644' + content: |- + set interface ip address GigabitEthernet0/4/0 10.0.0.6/30 + set interface state GigabitEthernet0/4/0 up + set interface ip address GigabitEthernet0/5/0 10.0.0.9/30 + set interface state GigabitEthernet0/5/0 up + mpls encap add label 30 fib 0 dest 10.0.0.10 + mpls decap add label 30 fib 0 + create mpls gre tunnel src 10.0.0.9 dst 10.0.0.10 intfc 10.0.0.13/30 inner-fib-id 0 outer-fib-id 0 + + + + + + + + #cloud-config +bootcmd: +- ln -s -t /etc/rc.d /etc/rc.local +hostname: vpp-2 +manage_etc_hosts: true +runcmd: +- start ttyS0 +- systemctl start getty@ttyS0.service +- systemctl start rc-local +- sed -i '/^\s*PasswordAuthentication\s\+no/d' /etc/ssh/sshd_config +- echo "UseDNS no" >> /etc/ssh/sshd_config +- service ssh restart +- service sshd restart +- sed -i 's/no-pci//' /cisco/etc/qn.conf +- sed -i 's/1024/1024 decimal-interface-names/g' /cisco/etc/qn.conf +users: +- default +- gecos: User configured by VIRL Configuration Engine 0.15.3 + lock-passwd: false + name: cisco + plain-text-passwd: cisco + shell: /bin/bash + ssh-authorized-keys: + - VIRL-USER-SSH-PUBLIC-KEY + sudo: ALL=(ALL) ALL +write_files: +- path: /etc/init/ttyS0.conf + owner: root:root + content: | + # ttyS0 - getty + # This service maintains a getty on ttyS0 from the point the system is + # started until it is shut down again. + start on stopped rc or RUNLEVEL=[12345] + stop on runlevel [!12345] + respawn + exec /sbin/getty -L 115200 ttyS0 vt102 + permissions: '0644' +- path: /etc/systemd/system/dhclient@.service + content: | + [Unit] + Description=Run dhclient on %i interface + After=network.target + [Service] + Type=oneshot + ExecStart=/sbin/dhclient %i -pf /var/run/dhclient.%i.pid -lf /var/lib/dhclient/dhclient.%i.lease + RemainAfterExit=yes + owner: root:root + permissions: '0644' +- path: /cisco/etc/vpp-server.conf + owner: root:root + permissions: '0644' + content: |- + set interface ip address GigabitEthernet0/4/0 10.0.0.10/30 + set interface state GigabitEthernet0/4/0 up + set interface ip address GigabitEthernet0/5/0 10.0.0.14/30 + set interface state GigabitEthernet0/5/0 up + mpls encap add label 30 fib 0 dest 10.0.0.9 + mpls decap add label 30 fib 0 + create mpls gre tunnel src 10.0.0.10 dst 10.0.0.9 intfc 10.0.0.5/30 inner-fib-id 0 outer-fib-id 0 + + + + + + + + ! IOS Config generated on 2015-03-03 17:26 +! by autonetkit_0.15.0 +! +hostname iosv-1 +boot-start-marker +boot-end-marker +! +no aaa new-model +! +! +ip cef +ipv6 unicast-routing +ipv6 cef +! +! +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +no service config +enable password cisco +ip classless +ip subnet-zero +no ip domain lookup +line vty 0 4 + transport input ssh telnet + exec-timeout 720 0 + password cisco + login +line con 0 + password cisco +! +! +interface Loopback0 + description Loopback + ip address 192.168.0.1 255.255.255.255 +! +interface GigabitEthernet0/0 + description OOB Management + ! Configured on launch + no ip address + duplex auto + speed auto + no shutdown +! +interface GigabitEthernet0/1 + description to vpp-1 + ip address 10.0.0.5 255.255.255.252 + ip ospf cost 1 + duplex auto + speed auto + no shutdown +! +! +! +router ospf 1 + network 192.168.0.1 0.0.0.0 area 0 + log-adjacency-changes + passive-interface Loopback0 + network 10.0.0.4 0.0.0.3 area 0 +! +! +router bgp 1 + bgp router-id 192.168.0.1 + no synchronization +! ibgp + ! ibgp peers + ! + neighbor 192.168.0.4 remote-as 1 + neighbor 192.168.0.4 description iBGP peer iosv-2 + neighbor 192.168.0.4 update-source Loopback0 +! +! + ! + address-family ipv4 + network 192.168.0.1 mask 255.255.255.255 + neighbor 192.168.0.4 activate + exit-address-family +! +! +! +ip route 10.0.0.13 255.255.255.255 10.0.0.6 +end + + + + + + + + ! IOS Config generated on 2015-03-03 17:26 +! by autonetkit_0.15.0 +! +hostname iosv-2 +boot-start-marker +boot-end-marker +! +no aaa new-model +! +! +ip cef +ipv6 unicast-routing +ipv6 cef +! +! +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +no service config +enable password cisco +ip classless +ip subnet-zero +no ip domain lookup +line vty 0 4 + transport input ssh telnet + exec-timeout 720 0 + password cisco + login +line con 0 + password cisco +! +! +interface Loopback0 + description Loopback + ip address 192.168.0.4 255.255.255.255 +! +interface GigabitEthernet0/0 + description OOB Management + ! Configured on launch + no ip address + duplex auto + speed auto + no shutdown +! +interface GigabitEthernet0/1 + description to vpp-2 + ip address 10.0.0.13 255.255.255.252 + ip ospf cost 1 + duplex auto + speed auto + no shutdown +! +! +! +router ospf 1 + network 192.168.0.4 0.0.0.0 area 0 + log-adjacency-changes + passive-interface Loopback0 + network 10.0.0.12 0.0.0.3 area 0 +! +! +router bgp 1 + bgp router-id 192.168.0.4 + no synchronization +! ibgp + ! ibgp peers + ! + neighbor 192.168.0.1 remote-as 1 + neighbor 192.168.0.1 description iBGP peer iosv-1 + neighbor 192.168.0.1 update-source Loopback0 +! +! + ! + address-family ipv4 + network 192.168.0.4 mask 255.255.255.255 + neighbor 192.168.0.1 activate + exit-address-family +! +! +ip route 10.0.0.5 255.255.255.255 10.0.0.14 +! +end + + + + + + + + + diff --git a/src/scripts/vnet/virl/simple.virl b/src/scripts/vnet/virl/simple.virl new file mode 100644 index 00000000..6033c42c --- /dev/null +++ b/src/scripts/vnet/virl/simple.virl @@ -0,0 +1,389 @@ + + + + flat + + + + ! +! Last configuration change at 14:27:32 UTC Fri Mar 27 2015 +! +version 15.4 +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +! +hostname iosv-1 +! +boot-start-marker +boot-end-marker +! +! +enable password cisco +! +no aaa new-model +! +! +! +mmi polling-interval 60 +no mmi auto-configure +no mmi pvc +mmi snmp-timeout 180 +! +! +! +! +! +! +! +! +! +! +! +! +! +no ip domain lookup +ip cef +ipv6 unicast-routing +ipv6 cef +! +multilink bundle-name authenticated +! +! +cts logging verbose +! +! +! +redundancy +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + description Loopback + ip address 192.168.0.2 255.255.255.255 +! +interface GigabitEthernet0/0 + description OOB Management + ip address 172.16.1.167 255.255.255.0 + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/1 + description to vpp-1 + ip address 10.0.0.5 255.255.255.252 + ip ospf cost 1 + duplex auto + speed auto + media-type rj45 +! +router ospf 1 + passive-interface Loopback0 + network 10.0.0.4 0.0.0.3 area 0 + network 192.168.0.2 0.0.0.0 area 0 +! +router bgp 1 + bgp router-id 192.168.0.2 + bgp log-neighbor-changes + neighbor 192.168.0.3 remote-as 1 + neighbor 192.168.0.3 description iBGP peer iosv-2 + neighbor 192.168.0.3 update-source Loopback0 + ! + address-family ipv4 + network 192.168.0.2 mask 255.255.255.255 + neighbor 192.168.0.3 activate + exit-address-family +! +ip forward-protocol nd +! +! +no ip http server +no ip http secure-server +ip route 10.0.0.9 255.255.255.255 10.0.0.6 +! +! +! +! +control-plane +! +banner exec ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner incoming ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner login ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +! +line con 0 + password cisco +line aux 0 +line vty 0 4 + exec-timeout 720 0 + password cisco + login + transport input telnet ssh +! +no scheduler allocate +! +end + + + + + + + ! +! Last configuration change at 14:26:58 UTC Fri Mar 27 2015 +! +version 15.4 +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +! +hostname iosv-2 +! +boot-start-marker +boot-end-marker +! +! +enable password cisco +! +no aaa new-model +! +! +! +mmi polling-interval 60 +no mmi auto-configure +no mmi pvc +mmi snmp-timeout 180 +! +! +! +! +! +! +! +! +! +! +! +! +! +no ip domain lookup +ip cef +ipv6 unicast-routing +ipv6 cef +! +multilink bundle-name authenticated +! +! +cts logging verbose +! +! +! +redundancy +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + description Loopback + ip address 192.168.0.3 255.255.255.255 +! +interface GigabitEthernet0/0 + description OOB Management + ip address 172.16.1.164 255.255.255.0 + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/1 + description to vpp-1 + ip address 10.0.0.9 255.255.255.252 + ip ospf cost 1 + duplex auto + speed auto + media-type rj45 +! +router ospf 1 + passive-interface Loopback0 + network 10.0.0.8 0.0.0.3 area 0 + network 192.168.0.3 0.0.0.0 area 0 +! +router bgp 1 + bgp router-id 192.168.0.3 + bgp log-neighbor-changes + neighbor 192.168.0.2 remote-as 1 + neighbor 192.168.0.2 description iBGP peer iosv-1 + neighbor 192.168.0.2 update-source Loopback0 + ! + address-family ipv4 + network 192.168.0.3 mask 255.255.255.255 + neighbor 192.168.0.2 activate + exit-address-family +! +ip forward-protocol nd +! +! +no ip http server +no ip http secure-server +ip route 10.0.0.5 255.255.255.255 10.0.0.10 +! +! +! +! +control-plane +! +banner exec ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner incoming ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner login ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +! +line con 0 + password cisco +line aux 0 +line vty 0 4 + exec-timeout 720 0 + password cisco + login + transport input telnet ssh +! +no scheduler allocate +! +end + + + + + + + #cloud-config +bootcmd: +- ln -s -t /etc/rc.d /etc/rc.local +hostname: vpp-1 +manage_etc_hosts: true +runcmd: +- start ttyS0 +- systemctl start getty@ttyS0.service +- systemctl start rc-local +- sed -i '/^\s*PasswordAuthentication\s\+no/d' /etc/ssh/sshd_config +- echo "UseDNS no" >> /etc/ssh/sshd_config +- service ssh restart +- service sshd restart +- sed -i 's/no-pci//' /cisco/etc/qn.conf +- sed -i 's/1024/1024 decimal-interface-names/g' /cisco/etc/qn.conf +users: +- default +- gecos: User configured by VIRL Configuration Engine 0.15.3 + lock-passwd: false + name: cisco + plain-text-passwd: cisco + shell: /bin/bash + ssh-authorized-keys: + - VIRL-USER-SSH-PUBLIC-KEY + sudo: ALL=(ALL) ALL +write_files: +- path: /etc/init/ttyS0.conf + owner: root:root + content: | + # ttyS0 - getty + # This service maintains a getty on ttyS0 from the point the system is + # started until it is shut down again. + start on stopped rc or RUNLEVEL=[12345] + stop on runlevel [!12345] + respawn + exec /sbin/getty -L 115200 ttyS0 vt102 + permissions: '0644' +- path: /etc/systemd/system/dhclient@.service + content: | + [Unit] + Description=Run dhclient on %i interface + After=network.target + [Service] + Type=oneshot + ExecStart=/sbin/dhclient %i -pf /var/run/dhclient.%i.pid -lf /var/lib/dhclient/dhclient.%i.lease + RemainAfterExit=yes + owner: root:root + permissions: '0644' +- path: /cisco/etc/vpp-server.conf + owner: root:root + permissions: '0644' + content: |- + set interface ip address GigabitEthernet0/4/0 10.0.0.6/30 + set interface state GigabitEthernet0/4/0 up + set interface ip address GigabitEthernet0/5/0 10.0.0.10/30 + set interface state GigabitEthernet0/5/0 up + + + + + + + + diff --git a/src/scripts/vnet/vlan b/src/scripts/vnet/vlan new file mode 100644 index 00000000..076080a6 --- /dev/null +++ b/src/scripts/vnet/vlan @@ -0,0 +1,23 @@ +int create-ethernet +int create-sub fake-eth0 1 +set int state fake-eth0 up +set int state fake-eth0.1 up + +packet-generator new { + name x + limit 1 + node ethernet-input + interface fake-eth0 + size 64-64 + no-recycle + data { + IP4: 1.2.3 -> 4.5.6 vlan 1 + ICMP: 1.2.3.4 -> 5.6.7.8 + ICMP echo_request + incrementing 100 + } +} + +tr add pg-input 100 +ip route 5.6.7.8/32 via local +ip route 1.2.3.4/32 via local diff --git a/src/scripts/vppctl b/src/scripts/vppctl new file mode 100755 index 00000000..4fdf03c7 --- /dev/null +++ b/src/scripts/vppctl @@ -0,0 +1,121 @@ +#! /usr/bin/python +''' +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. +''' + +from cmd import Cmd +import os +import subprocess +import re +import sys +try: + import readline +except ImportError: + readline = None + +persishist = os.path.expanduser('~/.vpphistory') +persishist_size = 1000 +if not persishist: + os.mknod(persishist, stat.S_IFREG) + +class Vppctl(Cmd): + + def historyWrite(self): + if readline: + readline.set_history_length(persishist_size) + readline.write_history_file(persishist) + + def runVat(self, line): + input_prefix = "exec " + input_command = input_prefix + line + line_remove = '^load_one_plugin:' + s = '\n' + command = ['vpp_api_test'] + + if os.geteuid() != 0: + command = ['sudo', 'vpp_api_test'] + + vpp_process = subprocess.Popen(command, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + stdout_value = vpp_process.communicate(input_command)[0] + + buffer_stdout = stdout_value.splitlines() + + buffer_stdout[:] = [b for b in buffer_stdout + if line_remove not in b] + + for i, num in enumerate(buffer_stdout): + buffer_stdout[i] = num.replace('vat# ','') + + stdout_value = s.join(buffer_stdout) + print stdout_value + + def do_help(self, line): + self.runVat("help") + + def default(self, line): + self.runVat(line) + + def do_exit(self, line): + self.historyWrite() + raise SystemExit + + def emptyline(self): + pass + + def do_EOF(self,line): + self.historyWrite() + sys.stdout.write('\n') + raise SystemExit + + def preloop(self): + if readline and os.path.exists(persishist): + readline.read_history_file(persishist) + + def postcmd(self, stop, line): + self.historyWrite() + +if __name__ == '__main__': + command_args = sys.argv + + + if not len(command_args) > 1: + prompt = Vppctl() + red_set = '\033[31m' + norm_set = '\033[0m' + if sys.stdout.isatty(): + prompt.prompt = 'vpp# ' + try: + prompt.cmdloop(red_set + " _______ _ " + norm_set + " _ _____ ___ \n" + + red_set + " __/ __/ _ \ (_)__ " + norm_set + " | | / / _ \/ _ \\\n" + + red_set + " _/ _// // / / / _ \\" + norm_set + " | |/ / ___/ ___/\n" + + red_set + " /_/ /____(_)_/\___/ " + norm_set + "|___/_/ /_/ \n") + except KeyboardInterrupt: + sys.stdout.write('\n') + else: + try: + prompt.cmdloop() + except KeyboardInterrupt: + sys.stdout.write('\n') + else: + del command_args[0] + stdout_value = " ".join(command_args) + VatAddress = Vppctl() + VatAddress.runVat(stdout_value) + + + diff --git a/src/suffix-rules.mk b/src/suffix-rules.mk new file mode 100644 index 00000000..e3eeb922 --- /dev/null +++ b/src/suffix-rules.mk @@ -0,0 +1,27 @@ +# Copyright (c) 2016 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Shared suffix rules +# Please do not set "SUFFIXES = .api.h .api" here + +%.api.h: %.api + @echo " APIGEN " $@ ; \ + 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 $@ diff --git a/src/svm.am b/src/svm.am new file mode 100644 index 00000000..d91eaa27 --- /dev/null +++ b/src/svm.am @@ -0,0 +1,31 @@ +# 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. + +bin_PROGRAMS += svmtool svmdbtool + +nobase_include_HEADERS += svm/svm.h svm/ssvm.h svm/svmdb.h + +libsvmdir = ${libdir} +libsvm_LTLIBRARIES = libsvm.la libsvmdb.la + +libsvm_la_SOURCES = svm/svm.c svm/ssvm.c + +svmtool_SOURCES = svm/svmtool.c +svmtool_LDADD = libsvm.la libvppinfra.la -lpthread -lrt + +libsvmdb_la_SOURCES = svm/svmdb.c + +svmdbtool_SOURCES = svm/svmdbtool.c +svmdbtool_LDADD = libsvmdb.la libsvm.la libvppinfra.la -lpthread -lrt + +# vi:syntax=automake diff --git a/src/svm/dir.dox b/src/svm/dir.dox new file mode 100644 index 00000000..83246979 --- /dev/null +++ b/src/svm/dir.dox @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Copyright (c) 2016 Comcast Cable Communications Management, LLC. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Doxygen directory documentation */ +/** +@dir +@brief Shared virtual memory allocation library. +*/ diff --git a/src/svm/persist.c b/src/svm/persist.c new file mode 100644 index 00000000..023c596b --- /dev/null +++ b/src/svm/persist.c @@ -0,0 +1,258 @@ +/* + *------------------------------------------------------------------ + * persist.c - persistent data structure storage test / demo code + * + * Copyright (c) 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 +#include +#include +#include +#include +#include +#include +#include + +typedef struct +{ + svmdb_client_t *c; +} persist_main_t; + +persist_main_t persist_main; + +typedef struct +{ + u8 *string1; + u8 *string2; +} demo_struct2_t; + +typedef struct +{ + demo_struct2_t *demo2; + u8 *name; +} demo_struct1_t; + +/* + * Data structures in persistent shared memory, all the time + */ +clib_error_t * +persist_malloc (persist_main_t * pm) +{ + demo_struct2_t *demo2; + demo_struct1_t *demo1; + time_t starttime = time (0); + char *datestring = ctime (&starttime); + void *oldheap; + + /* Get back the root pointer */ + demo1 = svmdb_local_get_variable_reference + (pm->c, SVMDB_NAMESPACE_VEC, "demo1_location"); + + /* It doesnt exist create our data structures */ + if (demo1 == 0) + { + /* If you want MP / thread safety, lock the region... */ + pthread_mutex_lock (&pm->c->db_rp->mutex); + + /* Switch to the shared memory region heap */ + oldheap = svm_push_data_heap (pm->c->db_rp); + + /* Allocate the top-level structure as a single element vector */ + vec_validate (demo1, 0); + + /* Allocate the next-level structure as a plain old memory obj */ + demo2 = clib_mem_alloc (sizeof (*demo2)); + + demo1->demo2 = demo2; + demo1->name = format (0, "My name is Ishmael%c", 0); + demo2->string1 = format (0, "Here is string1%c", 0); + demo2->string2 = format (0, "Born at %s%c", datestring, 0); + + /* Back to the process-private heap */ + svm_pop_heap (oldheap); + pthread_mutex_unlock (&pm->c->db_rp->mutex); + + /* + * Set the root pointer. Note: this guy switches heaps, locks, etc. + * We allocated demo1 as a vector to make this "just work..." + */ + svmdb_local_set_vec_variable (pm->c, "demo1_location", + demo1, sizeof (demo1)); + + } + else + { + /* retrieve and print data from shared memory */ + demo2 = demo1->demo2; + fformat (stdout, "name: %s\n", demo1->name); + fformat (stdout, "demo2 location: %llx\n", demo2); + fformat (stdout, "string1: %s\n", demo2->string1); + fformat (stdout, "string2: %s\n", demo2->string2); + } + return 0; +} + +void +unserialize_demo1 (serialize_main_t * sm, va_list * args) +{ + demo_struct1_t **result = va_arg (*args, demo_struct1_t **); + demo_struct1_t *demo1; + demo_struct2_t *demo2; + + /* Allocate data structures in process private memory */ + demo1 = clib_mem_alloc (sizeof (*demo1)); + demo2 = clib_mem_alloc (sizeof (*demo2)); + demo1->demo2 = demo2; + + /* retrieve data from shared memory checkpoint */ + unserialize_cstring (sm, (char **) &demo1->name); + unserialize_cstring (sm, (char **) &demo2->string1); + unserialize_cstring (sm, (char **) &demo2->string2); + *result = demo1; +} + +void +serialize_demo1 (serialize_main_t * sm, va_list * args) +{ + demo_struct1_t *demo1 = va_arg (*args, demo_struct1_t *); + demo_struct2_t *demo2 = demo1->demo2; + + serialize_cstring (sm, (char *) demo1->name); + serialize_cstring (sm, (char *) demo2->string1); + serialize_cstring (sm, (char *) demo2->string2); +} + +/* Serialize / unserialize variant */ +clib_error_t * +persist_serialize (persist_main_t * pm) +{ + u8 *checkpoint; + serialize_main_t sm; + + demo_struct2_t *demo2; + demo_struct1_t *demo1; + time_t starttime = time (0); + char *datestring = ctime (&starttime); + + /* Get back the root pointer */ + checkpoint = svmdb_local_get_vec_variable (pm->c, "demo1_checkpoint", + sizeof (u8)); + + /* It doesnt exist create our data structures */ + if (checkpoint == 0) + { + /* Allocate data structures in process-private memory */ + demo1 = clib_mem_alloc (sizeof (*demo2)); + vec_validate (demo1, 0); + demo2 = clib_mem_alloc (sizeof (*demo2)); + + demo1->demo2 = demo2; + demo1->name = format (0, "My name is Ishmael%c", 0); + demo2->string1 = format (0, "Here is string1%c", 0); + demo2->string2 = format (0, "Born at %s%c", datestring, 0); + + /* Create checkpoint */ + serialize_open_vector (&sm, checkpoint); + serialize (&sm, serialize_demo1, demo1); + checkpoint = serialize_close_vector (&sm); + + /* Copy checkpoint into shared memory */ + svmdb_local_set_vec_variable (pm->c, "demo1_checkpoint", + checkpoint, sizeof (u8)); + /* Toss the process-private-memory original.. */ + vec_free (checkpoint); + } + else + { + /* Open the checkpoint */ + unserialize_open_data (&sm, checkpoint, vec_len (checkpoint)); + unserialize (&sm, unserialize_demo1, &demo1); + + /* Toss the process-private-memory checkpoint copy */ + vec_free (checkpoint); + + /* Off we go... */ + demo2 = demo1->demo2; + fformat (stdout, "name: %s\n", demo1->name); + fformat (stdout, "demo2 location: %llx\n", demo2); + fformat (stdout, "string1: %s\n", demo2->string1); + fformat (stdout, "string2: %s\n", demo2->string2); + } + return 0; +} + + +int +main (int argc, char **argv) +{ + unformat_input_t _input, *input = &_input; + persist_main_t *pm = &persist_main; + clib_error_t *error = 0; + + /* Make a 4mb database arena, chroot so it's truly private */ + pm->c = svmdb_map_chroot_size ("/ptest", 4 << 20); + + ASSERT (pm->c); + + unformat_init_command_line (input, argv); + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "malloc")) + error = persist_malloc (pm); + else if (unformat (input, "serialize")) + error = persist_serialize (pm); + else + { + error = clib_error_return (0, "Unknown flavor '%U'", + format_unformat_error, input); + break; + } + } + + svmdb_unmap (pm->c); + + if (error) + { + clib_error_report (error); + exit (1); + } + return 0; +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/svm/ssvm.c b/src/svm/ssvm.c new file mode 100644 index 00000000..6f409eb6 --- /dev/null +++ b/src/svm/ssvm.c @@ -0,0 +1,178 @@ +/* + * 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 "ssvm.h" + +int +ssvm_master_init (ssvm_private_t * ssvm, u32 master_index) +{ + int ssvm_fd; + u8 *ssvm_filename; + u8 junk = 0; + int flags; + ssvm_shared_header_t *sh; + u64 ticks = clib_cpu_time_now (); + u64 randomize_baseva; + void *oldheap; + + if (ssvm->ssvm_size == 0) + return SSVM_API_ERROR_NO_SIZE; + + ssvm_filename = format (0, "/dev/shm/%s%c", ssvm->name, 0); + + unlink ((char *) ssvm_filename); + + vec_free (ssvm_filename); + + ssvm_fd = shm_open ((char *) ssvm->name, O_RDWR | O_CREAT | O_EXCL, 0777); + + if (ssvm_fd < 0) + { + clib_unix_warning ("create segment '%s'", ssvm->name); + return SSVM_API_ERROR_CREATE_FAILURE; + } + + if (lseek (ssvm_fd, ssvm->ssvm_size, SEEK_SET) < 0) + { + clib_unix_warning ("lseek"); + close (ssvm_fd); + return SSVM_API_ERROR_SET_SIZE; + } + + if (write (ssvm_fd, &junk, 1) != 1) + { + clib_unix_warning ("set ssvm size"); + close (ssvm_fd); + return SSVM_API_ERROR_SET_SIZE; + } + + flags = MAP_SHARED; + if (ssvm->requested_va) + flags |= MAP_FIXED; + + randomize_baseva = (ticks & 15) * MMAP_PAGESIZE; + + if (ssvm->requested_va) + ssvm->requested_va += randomize_baseva; + + sh = ssvm->sh = + (ssvm_shared_header_t *) mmap ((void *) ssvm->requested_va, + ssvm->ssvm_size, PROT_READ | PROT_WRITE, + flags, ssvm_fd, 0); + + if (ssvm->sh == MAP_FAILED) + { + clib_unix_warning ("mmap"); + close (ssvm_fd); + return SSVM_API_ERROR_MMAP; + } + + close (ssvm_fd); + + ssvm->my_pid = getpid (); + sh->master_pid = ssvm->my_pid; + sh->ssvm_size = ssvm->ssvm_size; + sh->heap = mheap_alloc_with_flags + (((u8 *) sh) + MMAP_PAGESIZE, ssvm->ssvm_size - MMAP_PAGESIZE, + MHEAP_FLAG_DISABLE_VM | MHEAP_FLAG_THREAD_SAFE); + + sh->ssvm_va = pointer_to_uword (sh); + sh->master_index = master_index; + + oldheap = ssvm_push_heap (sh); + sh->name = format (0, "%s%c", ssvm->name, 0); + ssvm_pop_heap (oldheap); + + ssvm->i_am_master = 1; + + /* The application has to set set sh->ready... */ + return 0; +} + +int +ssvm_slave_init (ssvm_private_t * ssvm, int timeout_in_seconds) +{ + struct stat stat; + int ssvm_fd = -1; + ssvm_shared_header_t *sh; + + ssvm->i_am_master = 0; + + while (timeout_in_seconds-- > 0) + { + if (ssvm_fd < 0) + ssvm_fd = shm_open ((char *) ssvm->name, O_RDWR, 0777); + if (ssvm_fd < 0) + { + sleep (1); + continue; + } + if (fstat (ssvm_fd, &stat) < 0) + { + sleep (1); + continue; + } + + if (stat.st_size > 0) + goto map_it; + } + clib_warning ("slave timeout"); + return SSVM_API_ERROR_SLAVE_TIMEOUT; + +map_it: + sh = (void *) mmap (0, MMAP_PAGESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, + ssvm_fd, 0); + if (sh == MAP_FAILED) + { + clib_unix_warning ("slave research mmap"); + close (ssvm_fd); + return SSVM_API_ERROR_MMAP; + } + + while (timeout_in_seconds-- > 0) + { + if (sh->ready) + goto re_map_it; + } + close (ssvm_fd); + munmap (sh, MMAP_PAGESIZE); + clib_warning ("slave timeout 2"); + return SSVM_API_ERROR_SLAVE_TIMEOUT; + +re_map_it: + ssvm->requested_va = (u64) sh->ssvm_va; + ssvm->ssvm_size = sh->ssvm_size; + munmap (sh, MMAP_PAGESIZE); + + sh = ssvm->sh = (void *) mmap ((void *) ssvm->requested_va, ssvm->ssvm_size, + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FIXED, ssvm_fd, 0); + + if (sh == MAP_FAILED) + { + clib_unix_warning ("slave final mmap"); + close (ssvm_fd); + return SSVM_API_ERROR_MMAP; + } + sh->slave_pid = getpid (); + return 0; +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/svm/ssvm.h b/src/svm/ssvm.h new file mode 100644 index 00000000..9e61b9a0 --- /dev/null +++ b/src/svm/ssvm.h @@ -0,0 +1,155 @@ +/* + * 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_ssvm_h__ +#define __included_ssvm_h__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MMAP_PAGESIZE (4<<10) +#define SSVM_N_OPAQUE 7 + +typedef struct +{ + /* Spin-lock */ + volatile u32 lock; + volatile u32 owner_pid; + int recursion_count; + u32 tag; /* for debugging */ + + /* The allocation arena */ + void *heap; + + /* Segment must be mapped at this address, or no supper */ + u64 ssvm_va; + /* The actual mmap size */ + u64 ssvm_size; + u32 master_pid; + u32 slave_pid; + u8 *name; + void *opaque[SSVM_N_OPAQUE]; + + /* Set when the master application thinks it's time to make the donuts */ + volatile u32 ready; + + /* Needed to make unique MAC addresses, etc. */ + u32 master_index; +} ssvm_shared_header_t; + +typedef struct +{ + ssvm_shared_header_t *sh; + u64 ssvm_size; + u32 my_pid; + u32 vlib_hw_if_index; + u8 *name; + uword requested_va; + int i_am_master; + u32 per_interface_next_index; + u32 *rx_queue; +} ssvm_private_t; + +always_inline void +ssvm_lock (ssvm_shared_header_t * h, u32 my_pid, u32 tag) +{ + if (h->owner_pid == my_pid) + { + h->recursion_count++; + return; + } + + while (__sync_lock_test_and_set (&h->lock, 1)) + ; + + h->owner_pid = my_pid; + h->recursion_count = 1; + h->tag = tag; +} + +always_inline void +ssvm_unlock (ssvm_shared_header_t * h) +{ + if (--h->recursion_count == 0) + { + h->owner_pid = 0; + h->tag = 0; + CLIB_MEMORY_BARRIER (); + h->lock = 0; + } +} + +static inline void * +ssvm_push_heap (ssvm_shared_header_t * sh) +{ + u8 *oldheap; + oldheap = clib_mem_set_heap (sh->heap); + return ((void *) oldheap); +} + +static inline void +ssvm_pop_heap (void *oldheap) +{ + clib_mem_set_heap (oldheap); +} + +#define foreach_ssvm_api_error \ +_(NO_NAME, "No shared segment name", -10) \ +_(NO_SIZE, "Size not set (master)", -11) \ +_(CREATE_FAILURE, "Create failed", -12) \ +_(SET_SIZE, "Set size failed", -13) \ +_(MMAP, "mmap failed", -14) \ +_(SLAVE_TIMEOUT, "Slave map timeout", -15) + +typedef enum +{ +#define _(n,s,c) SSVM_API_ERROR_##n = c, + foreach_ssvm_api_error +#undef _ +} ssvm_api_error_enum_t; + +#define SSVM_API_ERROR_NO_NAME (-10) + +int ssvm_master_init (ssvm_private_t * ssvm, u32 master_index); +int ssvm_slave_init (ssvm_private_t * ssvm, int timeout_in_seconds); + +#endif /* __included_ssvm_h__ */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/svm/svm.c b/src/svm/svm.c new file mode 100644 index 00000000..e4ca98e1 --- /dev/null +++ b/src/svm/svm.c @@ -0,0 +1,1237 @@ +/* + *------------------------------------------------------------------ + * svm.c - shared VM allocation, mmap(...MAP_FIXED...) + * library + * + * Copyright (c) 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. + *------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "svm.h" + +static svm_region_t *root_rp; +static int root_rp_refcount; + +#define MAXLOCK 2 +static pthread_mutex_t *mutexes_held[MAXLOCK]; +static int nheld; + +svm_region_t * +svm_get_root_rp (void) +{ + return root_rp; +} + +#define MUTEX_DEBUG + +static void +region_lock (svm_region_t * rp, int tag) +{ + pthread_mutex_lock (&rp->mutex); +#ifdef MUTEX_DEBUG + rp->mutex_owner_pid = getpid (); + rp->mutex_owner_tag = tag; +#endif + ASSERT (nheld < MAXLOCK); + /* + * Keep score of held mutexes so we can try to exit + * cleanly if the world comes to an end at the worst possible + * moment + */ + mutexes_held[nheld++] = &rp->mutex; +} + +static void +region_unlock (svm_region_t * rp) +{ + int i, j; +#ifdef MUTEX_DEBUG + rp->mutex_owner_pid = 0; + rp->mutex_owner_tag = 0; +#endif + + for (i = nheld - 1; i >= 0; i--) + { + if (mutexes_held[i] == &rp->mutex) + { + for (j = i; j < MAXLOCK - 1; j++) + mutexes_held[j] = mutexes_held[j + 1]; + nheld--; + goto found; + } + } + ASSERT (0); + +found: + CLIB_MEMORY_BARRIER (); + pthread_mutex_unlock (&rp->mutex); +} + + +static u8 * +format_svm_flags (u8 * s, va_list * args) +{ + uword f = va_arg (*args, uword); + + if (f & SVM_FLAGS_MHEAP) + s = format (s, "MHEAP "); + if (f & SVM_FLAGS_FILE) + s = format (s, "FILE "); + if (f & SVM_FLAGS_NODATA) + s = format (s, "NODATA "); + if (f & SVM_FLAGS_NEED_DATA_INIT) + s = format (s, "INIT "); + + return (s); +} + +static u8 * +format_svm_size (u8 * s, va_list * args) +{ + uword size = va_arg (*args, uword); + + if (size >= (1 << 20)) + { + s = format (s, "(%d mb)", size >> 20); + } + else if (size >= (1 << 10)) + { + s = format (s, "(%d kb)", size >> 10); + } + else + { + s = format (s, "(%d bytes)", size); + } + return (s); +} + +u8 * +format_svm_region (u8 * s, va_list * args) +{ + svm_region_t *rp = va_arg (*args, svm_region_t *); + int verbose = va_arg (*args, int); + int i; + uword lo, hi; + + s = format (s, "%s: base va 0x%x size 0x%x %U\n", + rp->region_name, rp->virtual_base, + rp->virtual_size, format_svm_size, rp->virtual_size); + s = format (s, " user_ctx 0x%x, bitmap_size %d\n", + rp->user_ctx, rp->bitmap_size); + + if (verbose) + { + s = format (s, " flags: 0x%x %U\n", rp->flags, + format_svm_flags, rp->flags); + s = format (s, + " region_heap 0x%x data_base 0x%x data_heap 0x%x\n", + rp->region_heap, rp->data_base, rp->data_heap); + } + + s = format (s, " %d clients, pids: ", vec_len (rp->client_pids)); + + for (i = 0; i < vec_len (rp->client_pids); i++) + s = format (s, "%d ", rp->client_pids[i]); + + s = format (s, "\n"); + + if (verbose) + { + lo = hi = ~0; + + s = format (s, " VM in use: "); + + for (i = 0; i < rp->bitmap_size; i++) + { + if (clib_bitmap_get_no_check (rp->bitmap, i) != 0) + { + if (lo == ~0) + { + hi = lo = rp->virtual_base + i * MMAP_PAGESIZE; + } + else + { + hi = rp->virtual_base + i * MMAP_PAGESIZE; + } + } + else + { + if (lo != ~0) + { + hi = rp->virtual_base + i * MMAP_PAGESIZE - 1; + s = format (s, " 0x%x - 0x%x (%dk)\n", lo, hi, + (hi - lo) >> 10); + lo = hi = ~0; + } + } + } + s = format (s, " rgn heap stats: %U", format_mheap, + rp->region_heap, 0); + if ((rp->flags & SVM_FLAGS_MHEAP) && rp->data_heap) + { + s = format (s, "\n data heap stats: %U", format_mheap, + rp->data_heap, 1); + } + s = format (s, "\n"); + } + + return (s); +} + +/* + * rnd_pagesize + * Round to a pagesize multiple, presumably 4k works + */ +static u64 +rnd_pagesize (u64 size) +{ + u64 rv; + + rv = (size + (MMAP_PAGESIZE - 1)) & ~(MMAP_PAGESIZE - 1); + return (rv); +} + +/* + * svm_data_region_setup + */ +static int +svm_data_region_create (svm_map_region_args_t * a, svm_region_t * rp) +{ + int fd; + u8 junk = 0; + uword map_size; + + map_size = rp->virtual_size - (MMAP_PAGESIZE + + (a->pvt_heap_size ? a->pvt_heap_size : + SVM_PVT_MHEAP_SIZE)); + + if (a->flags & SVM_FLAGS_FILE) + { + struct stat statb; + + fd = open (a->backing_file, O_RDWR | O_CREAT, 0777); + + if (fd < 0) + { + clib_unix_warning ("open"); + return -1; + } + + if (fstat (fd, &statb) < 0) + { + clib_unix_warning ("fstat"); + close (fd); + return -2; + } + + if (statb.st_mode & S_IFREG) + { + if (statb.st_size == 0) + { + if (lseek (fd, map_size, SEEK_SET) == (off_t) - 1) + { + clib_unix_warning ("seek region size"); + close (fd); + return -3; + } + if (write (fd, &junk, 1) != 1) + { + clib_unix_warning ("set region size"); + close (fd); + return -3; + } + } + else + { + map_size = rnd_pagesize (statb.st_size); + } + } + else + { + map_size = a->backing_mmap_size; + } + + ASSERT (map_size <= rp->virtual_size - + (MMAP_PAGESIZE + SVM_PVT_MHEAP_SIZE)); + + if (mmap (rp->data_base, map_size, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FIXED, fd, 0) == MAP_FAILED) + { + clib_unix_warning ("mmap"); + close (fd); + return -3; + } + close (fd); + rp->backing_file = (char *) format (0, "%s\0", a->backing_file); + rp->flags |= SVM_FLAGS_FILE; + } + + if (a->flags & SVM_FLAGS_MHEAP) + { + rp->data_heap = + mheap_alloc_with_flags ((void *) (rp->data_base), map_size, + MHEAP_FLAG_DISABLE_VM); + rp->flags |= SVM_FLAGS_MHEAP; + } + return 0; +} + +static int +svm_data_region_map (svm_map_region_args_t * a, svm_region_t * rp) +{ + int fd; + u8 junk = 0; + uword map_size; + struct stat statb; + + map_size = rp->virtual_size - + (MMAP_PAGESIZE + + (a->pvt_heap_size ? a->pvt_heap_size : SVM_PVT_MHEAP_SIZE)); + + if (a->flags & SVM_FLAGS_FILE) + { + + fd = open (a->backing_file, O_RDWR, 0777); + + if (fd < 0) + { + clib_unix_warning ("open"); + return -1; + } + + if (fstat (fd, &statb) < 0) + { + clib_unix_warning ("fstat"); + close (fd); + return -2; + } + + if (statb.st_mode & S_IFREG) + { + if (statb.st_size == 0) + { + if (lseek (fd, map_size, SEEK_SET) == (off_t) - 1) + { + clib_unix_warning ("seek region size"); + close (fd); + return -3; + } + if (write (fd, &junk, 1) != 1) + { + clib_unix_warning ("set region size"); + close (fd); + return -3; + } + } + else + { + map_size = rnd_pagesize (statb.st_size); + } + } + else + { + map_size = a->backing_mmap_size; + } + + ASSERT (map_size <= rp->virtual_size + - (MMAP_PAGESIZE + + + (a->pvt_heap_size ? a->pvt_heap_size : SVM_PVT_MHEAP_SIZE))); + + if (mmap (rp->data_base, map_size, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FIXED, fd, 0) == MAP_FAILED) + { + clib_unix_warning ("mmap"); + close (fd); + return -3; + } + close (fd); + } + return 0; +} + +u8 * +shm_name_from_svm_map_region_args (svm_map_region_args_t * a) +{ + u8 *path; + u8 *shm_name; + u8 *split_point; + u8 *mkdir_arg = 0; + int root_path_offset = 0; + int name_offset = 0; + + if (a->root_path) + { + /* Tolerate present or absent slashes */ + if (a->root_path[0] == '/') + root_path_offset++; + + /* create the root_path under /dev/shm + iterate through path creating directories */ + + path = format (0, "/dev/shm/%s%c", &a->root_path[root_path_offset], 0); + split_point = path + 1; + vec_add1 (mkdir_arg, '-'); + + while (*split_point) + { + while (*split_point && *split_point != '/') + { + vec_add1 (mkdir_arg, *split_point); + split_point++; + } + vec_add1 (mkdir_arg, 0); + + /* ready to descend another level */ + mkdir_arg[vec_len (mkdir_arg) - 1] = '-'; + split_point++; + } + vec_free (mkdir_arg); + vec_free (path); + + if (a->name[0] == '/') + name_offset = 1; + + shm_name = format (0, "/%s-%s%c", a->root_path, + &a->name[name_offset], 0); + } + else + shm_name = format (0, "%s%c", a->name, 0); + return (shm_name); +} + +/* + * svm_map_region + */ +void * +svm_map_region (svm_map_region_args_t * a) +{ + int svm_fd; + svm_region_t *rp; + pthread_mutexattr_t attr; + pthread_condattr_t cattr; + int deadman = 0; + u8 junk = 0; + void *oldheap; + int overhead_space; + int rv; + uword data_base; + int nbits, words, bit; + int pid_holding_region_lock; + u8 *shm_name; + int dead_region_recovery = 0; + int time_left; + struct stat stat; + struct timespec ts, tsrem; + + if (CLIB_DEBUG > 1) + clib_warning ("[%d] map region %s", getpid (), a->name); + + ASSERT ((a->size & ~(MMAP_PAGESIZE - 1)) == a->size); + ASSERT (a->name); + + shm_name = shm_name_from_svm_map_region_args (a); + + svm_fd = shm_open ((char *) shm_name, O_RDWR | O_CREAT | O_EXCL, 0777); + + if (svm_fd >= 0) + { + if (fchmod (svm_fd, 0770) < 0) + clib_unix_warning ("segment chmod"); + /* This turns out to fail harmlessly if the client starts first */ + if (fchown (svm_fd, a->uid, a->gid) < 0) + clib_unix_warning ("segment chown [ok if client starts first]"); + + vec_free (shm_name); + + if (lseek (svm_fd, a->size, SEEK_SET) == (off_t) - 1) + { + clib_warning ("seek region size"); + close (svm_fd); + return (0); + } + if (write (svm_fd, &junk, 1) != 1) + { + clib_warning ("set region size"); + close (svm_fd); + return (0); + } + + rp = mmap ((void *) a->baseva, a->size, + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, svm_fd, 0); + + if (rp == (svm_region_t *) MAP_FAILED) + { + clib_unix_warning ("mmap create"); + close (svm_fd); + return (0); + } + close (svm_fd); + memset (rp, 0, sizeof (*rp)); + + if (pthread_mutexattr_init (&attr)) + clib_unix_warning ("mutexattr_init"); + + if (pthread_mutexattr_setpshared (&attr, PTHREAD_PROCESS_SHARED)) + clib_unix_warning ("mutexattr_setpshared"); + + if (pthread_mutex_init (&rp->mutex, &attr)) + clib_unix_warning ("mutex_init"); + + if (pthread_mutexattr_destroy (&attr)) + clib_unix_warning ("mutexattr_destroy"); + + if (pthread_condattr_init (&cattr)) + clib_unix_warning ("condattr_init"); + + if (pthread_condattr_setpshared (&cattr, PTHREAD_PROCESS_SHARED)) + clib_unix_warning ("condattr_setpshared"); + + if (pthread_cond_init (&rp->condvar, &cattr)) + clib_unix_warning ("cond_init"); + + if (pthread_condattr_destroy (&cattr)) + clib_unix_warning ("condattr_destroy"); + + region_lock (rp, 1); + + rp->virtual_base = a->baseva; + rp->virtual_size = a->size; + + rp->region_heap = + mheap_alloc_with_flags ((void *) (a->baseva + MMAP_PAGESIZE), + (a->pvt_heap_size != 0) ? + a->pvt_heap_size : SVM_PVT_MHEAP_SIZE, + MHEAP_FLAG_DISABLE_VM); + oldheap = svm_push_pvt_heap (rp); + + rp->region_name = (char *) format (0, "%s%c", a->name, 0); + vec_add1 (rp->client_pids, getpid ()); + + nbits = rp->virtual_size / MMAP_PAGESIZE; + + ASSERT (nbits > 0); + rp->bitmap_size = nbits; + words = (nbits + BITS (uword) - 1) / BITS (uword); + vec_validate (rp->bitmap, words - 1); + + overhead_space = MMAP_PAGESIZE /* header */ + + ((a->pvt_heap_size != 0) ? a->pvt_heap_size : SVM_PVT_MHEAP_SIZE); + + bit = 0; + data_base = (uword) rp->virtual_base; + + if (a->flags & SVM_FLAGS_NODATA) + rp->flags |= SVM_FLAGS_NEED_DATA_INIT; + + do + { + clib_bitmap_set_no_check (rp->bitmap, bit, 1); + bit++; + overhead_space -= MMAP_PAGESIZE; + data_base += MMAP_PAGESIZE; + } + while (overhead_space > 0); + + rp->data_base = (void *) data_base; + + /* + * Note: although the POSIX spec guarantees that only one + * process enters this block, we have to play games + * to hold off clients until e.g. the mutex is ready + */ + rp->version = SVM_VERSION; + + /* setup the data portion of the region */ + + rv = svm_data_region_create (a, rp); + if (rv) + { + clib_warning ("data_region_create: %d", rv); + } + + region_unlock (rp); + + svm_pop_heap (oldheap); + + return ((void *) rp); + } + else + { + svm_fd = shm_open ((char *) shm_name, O_RDWR, 0777); + + vec_free (shm_name); + + if (svm_fd < 0) + { + perror ("svm_region_map(mmap open)"); + return (0); + } + + time_left = 20; + while (1) + { + if (0 != fstat (svm_fd, &stat)) + { + clib_warning ("fstat failed: %d", errno); + close (svm_fd); + return (0); + } + if (stat.st_size > 0) + { + break; + } + if (0 == time_left) + { + clib_warning ("waiting for resize of shm file timed out"); + close (svm_fd); + return (0); + } + ts.tv_sec = 0; + ts.tv_nsec = 100000000; + while (nanosleep (&ts, &tsrem) < 0) + ts = tsrem; + time_left--; + } + + rp = mmap (0, MMAP_PAGESIZE, + PROT_READ | PROT_WRITE, MAP_SHARED, svm_fd, 0); + + if (rp == (svm_region_t *) MAP_FAILED) + { + close (svm_fd); + clib_warning ("mmap"); + return (0); + } + /* + * We lost the footrace to create this region; make sure + * the winner has crossed the finish line. + */ + while (rp->version == 0 && deadman++ < 5) + { + sleep (1); + } + + /* + * -ed? + */ + if (rp->version == 0) + { + clib_warning ("rp->version %d not %d", rp->version, SVM_VERSION); + close (svm_fd); + munmap (rp, a->size); + return (0); + } + /* Remap now that the region has been placed */ + a->baseva = rp->virtual_base; + a->size = rp->virtual_size; + munmap (rp, MMAP_PAGESIZE); + + rp = (void *) mmap ((void *) a->baseva, a->size, + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FIXED, svm_fd, 0); + if ((uword) rp == (uword) MAP_FAILED) + { + clib_unix_warning ("mmap"); + close (svm_fd); + return (0); + } + + if ((uword) rp != rp->virtual_base) + { + clib_warning ("mmap botch"); + } + + /* + * Try to fix the region mutex if it is held by + * a dead process + */ + pid_holding_region_lock = rp->mutex_owner_pid; + if (pid_holding_region_lock && kill (pid_holding_region_lock, 0) < 0) + { + clib_warning + ("region %s mutex held by dead pid %d, tag %d, force unlock", + rp->region_name, pid_holding_region_lock, rp->mutex_owner_tag); + /* owner pid is nonexistent */ + rp->mutex.__data.__owner = 0; + rp->mutex.__data.__lock = 0; + dead_region_recovery = 1; + } + + if (dead_region_recovery) + clib_warning ("recovery: attempt to re-lock region"); + + region_lock (rp, 2); + oldheap = svm_push_pvt_heap (rp); + vec_add1 (rp->client_pids, getpid ()); + + if (dead_region_recovery) + clib_warning ("recovery: attempt svm_data_region_map"); + + rv = svm_data_region_map (a, rp); + if (rv) + { + clib_warning ("data_region_map: %d", rv); + } + + if (dead_region_recovery) + clib_warning ("unlock and continue"); + + region_unlock (rp); + + svm_pop_heap (oldheap); + + return ((void *) rp); + + } + return 0; /* NOTREACHED */ +} + +static void +svm_mutex_cleanup (void) +{ + int i; + for (i = 0; i < nheld; i++) + { + pthread_mutex_unlock (mutexes_held[i]); + } +} + +static void +svm_region_init_internal (svm_map_region_args_t * a) +{ + svm_region_t *rp; + u64 ticks = clib_cpu_time_now (); + uword randomize_baseva; + + /* guard against klutz calls */ + if (root_rp) + return; + + root_rp_refcount++; + + atexit (svm_mutex_cleanup); + + /* Randomize the shared-VM base at init time */ + if (MMAP_PAGESIZE <= (4 << 10)) + randomize_baseva = (ticks & 15) * MMAP_PAGESIZE; + else + randomize_baseva = (ticks & 3) * MMAP_PAGESIZE; + + a->baseva += randomize_baseva; + + rp = svm_map_region (a); + ASSERT (rp); + + region_lock (rp, 3); + + /* Set up the main region data structures */ + if (rp->flags & SVM_FLAGS_NEED_DATA_INIT) + { + svm_main_region_t *mp = 0; + void *oldheap; + + rp->flags &= ~(SVM_FLAGS_NEED_DATA_INIT); + + oldheap = svm_push_pvt_heap (rp); + vec_validate (mp, 0); + mp->name_hash = hash_create_string (0, sizeof (uword)); + mp->root_path = a->root_path ? format (0, "%s%c", a->root_path, 0) : 0; + rp->data_base = mp; + svm_pop_heap (oldheap); + } + region_unlock (rp); + root_rp = rp; +} + +void +svm_region_init (void) +{ + svm_map_region_args_t _a, *a = &_a; + + memset (a, 0, sizeof (*a)); + a->root_path = 0; + a->name = SVM_GLOBAL_REGION_NAME; + a->baseva = SVM_GLOBAL_REGION_BASEVA; + a->size = SVM_GLOBAL_REGION_SIZE; + a->flags = SVM_FLAGS_NODATA; + a->uid = 0; + a->gid = 0; + + svm_region_init_internal (a); +} + +void +svm_region_init_chroot (char *root_path) +{ + svm_map_region_args_t _a, *a = &_a; + + memset (a, 0, sizeof (*a)); + a->root_path = root_path; + a->name = SVM_GLOBAL_REGION_NAME; + a->baseva = SVM_GLOBAL_REGION_BASEVA; + a->size = SVM_GLOBAL_REGION_SIZE; + a->flags = SVM_FLAGS_NODATA; + a->uid = 0; + a->gid = 0; + + svm_region_init_internal (a); +} + +void +svm_region_init_chroot_uid_gid (char *root_path, int uid, int gid) +{ + svm_map_region_args_t _a, *a = &_a; + + memset (a, 0, sizeof (*a)); + a->root_path = root_path; + a->name = SVM_GLOBAL_REGION_NAME; + a->baseva = SVM_GLOBAL_REGION_BASEVA; + a->size = SVM_GLOBAL_REGION_SIZE; + a->flags = SVM_FLAGS_NODATA; + a->uid = uid; + a->gid = gid; + + svm_region_init_internal (a); +} + +void +svm_region_init_args (svm_map_region_args_t * a) +{ + svm_region_init_internal (a); +} + +void * +svm_region_find_or_create (svm_map_region_args_t * a) +{ + svm_main_region_t *mp; + svm_region_t *rp; + uword need_nbits; + int index, i; + void *oldheap; + uword *p; + u8 *name; + svm_subregion_t *subp; + + ASSERT (root_rp); + + a->size += MMAP_PAGESIZE + + ((a->pvt_heap_size != 0) ? a->pvt_heap_size : SVM_PVT_MHEAP_SIZE); + a->size = rnd_pagesize (a->size); + + region_lock (root_rp, 4); + oldheap = svm_push_pvt_heap (root_rp); + mp = root_rp->data_base; + + ASSERT (mp); + + /* Map the named region from the correct chroot environment */ + a->root_path = (char *) mp->root_path; + + /* + * See if this region is already known. If it is, we're + * almost done... + */ + p = hash_get_mem (mp->name_hash, a->name); + + if (p) + { + rp = svm_map_region (a); + region_unlock (root_rp); + svm_pop_heap (oldheap); + return rp; + } + + /* Create the region. */ + ASSERT ((a->size & ~(MMAP_PAGESIZE - 1)) == a->size); + + need_nbits = a->size / MMAP_PAGESIZE; + + index = 1; /* $$$ fixme, figure out how many bit to really skip */ + + /* + * Scan the virtual space allocation bitmap, looking for a large + * enough chunk + */ + do + { + if (clib_bitmap_get_no_check (root_rp->bitmap, index) == 0) + { + for (i = 0; i < (need_nbits - 1); i++) + { + if (clib_bitmap_get_no_check (root_rp->bitmap, index + i) == 1) + { + index = index + i; + goto next; + } + } + break; + } + index++; + next:; + } + while (index < root_rp->bitmap_size); + + /* Completely out of VM? */ + if (index >= root_rp->bitmap_size) + { + clib_warning ("region %s: not enough VM to allocate 0x%llx (%lld)", + root_rp->region_name, a->size, a->size); + svm_pop_heap (oldheap); + region_unlock (root_rp); + return 0; + } + + /* + * Mark virtual space allocated + */ +#if CLIB_DEBUG > 1 + clib_warning ("set %d bits at index %d", need_nbits, index); +#endif + + for (i = 0; i < need_nbits; i++) + { + clib_bitmap_set_no_check (root_rp->bitmap, index + i, 1); + } + + /* Place this region where it goes... */ + a->baseva = root_rp->virtual_base + index * MMAP_PAGESIZE; + + rp = svm_map_region (a); + + pool_get (mp->subregions, subp); + name = format (0, "%s%c", a->name, 0); + subp->subregion_name = name; + + hash_set_mem (mp->name_hash, name, subp - mp->subregions); + + svm_pop_heap (oldheap); + + region_unlock (root_rp); + + return (rp); +} + +/* + * svm_region_unmap + * + * Let go of the indicated region. If the calling process + * is the last customer, throw it away completely. + * The root region mutex guarantees atomicity with respect to + * a new region client showing up at the wrong moment. + */ +void +svm_region_unmap (void *rp_arg) +{ + int i, mypid = getpid (); + int nclients_left; + void *oldheap; + uword virtual_base, virtual_size; + svm_region_t *rp = rp_arg; + char *name; + + /* + * If we take a signal while holding one or more shared-memory + * mutexes, we may end up back here from an otherwise + * benign exit handler. Bail out to avoid a recursive + * mutex screw-up. + */ + if (nheld) + return; + + ASSERT (rp); + ASSERT (root_rp); + + if (CLIB_DEBUG > 1) + clib_warning ("[%d] unmap region %s", getpid (), rp->region_name); + + region_lock (root_rp, 5); + region_lock (rp, 6); + + oldheap = svm_push_pvt_heap (rp); /* nb vec_delete() in the loop */ + + /* Remove the caller from the list of mappers */ + for (i = 0; i < vec_len (rp->client_pids); i++) + { + if (rp->client_pids[i] == mypid) + { + vec_delete (rp->client_pids, 1, i); + goto found; + } + } + clib_warning ("pid %d AWOL", mypid); + +found: + + svm_pop_heap (oldheap); + + nclients_left = vec_len (rp->client_pids); + virtual_base = rp->virtual_base; + virtual_size = rp->virtual_size; + + if (nclients_left == 0) + { + int index, nbits, i; + svm_main_region_t *mp; + uword *p; + svm_subregion_t *subp; + + /* Kill the region, last guy on his way out */ + + oldheap = svm_push_pvt_heap (root_rp); + name = vec_dup (rp->region_name); + + virtual_base = rp->virtual_base; + virtual_size = rp->virtual_size; + + /* Figure out which bits to clear in the root region bitmap */ + index = (virtual_base - root_rp->virtual_base) / MMAP_PAGESIZE; + + nbits = (virtual_size + MMAP_PAGESIZE - 1) / MMAP_PAGESIZE; + +#if CLIB_DEBUG > 1 + clib_warning ("clear %d bits at index %d", nbits, index); +#endif + /* Give back the allocated VM */ + for (i = 0; i < nbits; i++) + { + clib_bitmap_set_no_check (root_rp->bitmap, index + i, 0); + } + + mp = root_rp->data_base; + + p = hash_get_mem (mp->name_hash, name); + + /* Better never happen ... */ + if (p == NULL) + { + region_unlock (rp); + region_unlock (root_rp); + svm_pop_heap (oldheap); + clib_warning ("Region name '%s' not found?", name); + return; + } + + /* Remove from the root region subregion pool */ + subp = mp->subregions + p[0]; + pool_put (mp->subregions, subp); + + hash_unset_mem (mp->name_hash, name); + + vec_free (name); + + region_unlock (rp); + shm_unlink (rp->region_name); + munmap ((void *) virtual_base, virtual_size); + region_unlock (root_rp); + svm_pop_heap (oldheap); + return; + } + + region_unlock (rp); + region_unlock (root_rp); + + munmap ((void *) virtual_base, virtual_size); +} + +/* + * svm_region_exit + * There is no clean way to unlink the + * root region when all clients go away, + * so remove the pid entry and call it a day. + */ +void +svm_region_exit () +{ + void *oldheap; + int i, mypid = getpid (); + uword virtual_base, virtual_size; + + /* It felt so nice we did it twice... */ + if (root_rp == 0) + return; + + if (--root_rp_refcount > 0) + return; + + /* + * If we take a signal while holding one or more shared-memory + * mutexes, we may end up back here from an otherwise + * benign exit handler. Bail out to avoid a recursive + * mutex screw-up. + */ + if (nheld) + return; + + region_lock (root_rp, 7); + oldheap = svm_push_pvt_heap (root_rp); + + virtual_base = root_rp->virtual_base; + virtual_size = root_rp->virtual_size; + + for (i = 0; i < vec_len (root_rp->client_pids); i++) + { + if (root_rp->client_pids[i] == mypid) + { + vec_delete (root_rp->client_pids, 1, i); + goto found; + } + } + clib_warning ("pid %d AWOL", mypid); + +found: + + region_unlock (root_rp); + svm_pop_heap (oldheap); + + root_rp = 0; + munmap ((void *) virtual_base, virtual_size); +} + +void +svm_client_scan_this_region_nolock (svm_region_t * rp) +{ + int j; + int mypid = getpid (); + void *oldheap; + + for (j = 0; j < vec_len (rp->client_pids); j++) + { + if (mypid == rp->client_pids[j]) + continue; + if (rp->client_pids[j] && (kill (rp->client_pids[j], 0) < 0)) + { + clib_warning ("%s: cleanup ghost pid %d", + rp->region_name, rp->client_pids[j]); + /* nb: client vec in rp->region_heap */ + oldheap = svm_push_pvt_heap (rp); + vec_delete (rp->client_pids, 1, j); + j--; + svm_pop_heap (oldheap); + } + } +} + + +/* + * Scan svm regions for dead clients + */ +void +svm_client_scan (char *root_path) +{ + int i, j; + svm_main_region_t *mp; + svm_map_region_args_t *a = 0; + svm_region_t *root_rp; + svm_region_t *rp; + svm_subregion_t *subp; + u8 *name = 0; + u8 **svm_names = 0; + void *oldheap; + int mypid = getpid (); + + vec_validate (a, 0); + + svm_region_init_chroot (root_path); + + root_rp = svm_get_root_rp (); + + pthread_mutex_lock (&root_rp->mutex); + + mp = root_rp->data_base; + + for (j = 0; j < vec_len (root_rp->client_pids); j++) + { + if (mypid == root_rp->client_pids[j]) + continue; + if (root_rp->client_pids[j] && (kill (root_rp->client_pids[j], 0) < 0)) + { + clib_warning ("%s: cleanup ghost pid %d", + root_rp->region_name, root_rp->client_pids[j]); + /* nb: client vec in root_rp->region_heap */ + oldheap = svm_push_pvt_heap (root_rp); + vec_delete (root_rp->client_pids, 1, j); + j--; + svm_pop_heap (oldheap); + } + } + + /* + * Snapshoot names, can't hold root rp mutex across + * find_or_create. + */ + /* *INDENT-OFF* */ + pool_foreach (subp, mp->subregions, ({ + name = vec_dup (subp->subregion_name); + vec_add1(svm_names, name); + })); + /* *INDENT-ON* */ + + pthread_mutex_unlock (&root_rp->mutex); + + for (i = 0; i < vec_len (svm_names); i++) + { + vec_validate (a, 0); + a->root_path = root_path; + a->name = (char *) svm_names[i]; + rp = svm_region_find_or_create (a); + if (rp) + { + pthread_mutex_lock (&rp->mutex); + + svm_client_scan_this_region_nolock (rp); + + pthread_mutex_unlock (&rp->mutex); + svm_region_unmap (rp); + vec_free (svm_names[i]); + } + vec_free (a); + } + vec_free (svm_names); + + svm_region_exit (); + + vec_free (a); +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/svm/svm.h b/src/svm/svm.h new file mode 100644 index 00000000..0b87dbcb --- /dev/null +++ b/src/svm/svm.h @@ -0,0 +1,207 @@ +/* + *------------------------------------------------------------------ + * svm.h - shared VM allocation, mmap(...MAP_FIXED...) + * brain police + * + * Copyright (c) 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 __included_svm_h__ +#define __included_svm_h__ + +#include +#include +#include + +#define MMAP_PAGESIZE (clib_mem_get_page_size()) + +#define SVM_VERSION ((1<<16) | 1) /* set to declare region ready. */ + +#define SVM_FLAGS_MHEAP (1<<0) /* region contains an mheap */ +#define SVM_FLAGS_FILE (1<<1) /* region backed by one or more files */ +#define SVM_FLAGS_NODATA (1<<2) /* region will be further subdivided */ +#define SVM_FLAGS_NEED_DATA_INIT (1<<3) + +#define SVM_PVT_MHEAP_SIZE (128<<10) /* region's private mheap (128k) */ + +typedef struct svm_region_ +{ + volatile uword version; + pthread_mutex_t mutex; + pthread_cond_t condvar; + int mutex_owner_pid; /* in case of trouble */ + int mutex_owner_tag; + uword flags; + uword virtual_base; /* base of the region object */ + uword virtual_size; + void *region_heap; + void *data_base; /* data portion base address */ + void *data_heap; /* data heap, if any */ + volatile void *user_ctx; /* user context pointer */ + /* stuff allocated in the region's heap */ + uword bitmap_size; /* nbits in virtual alloc bitmap */ + uword *bitmap; /* the bitmap */ + char *region_name; + char *backing_file; + char **filenames; + uword *client_pids; + /* pad */ + + /* next page: + * (64K) clib heap for the region itself + * + * data_base -> whatever is in this region + */ + +} svm_region_t; + +typedef struct svm_map_region_args_ +{ + char *root_path; /* NULL means use the truly global arena */ + char *name; + u64 baseva; + u64 size; + u64 pvt_heap_size; + uword flags; + char *backing_file; + uword backing_mmap_size; + /* uid, gid to own the svm region(s) */ + int uid; + int gid; +} svm_map_region_args_t; + + +/* + * Memory shared across all router instances. Packet buffers, etc + * Base should be "out of the way," and size should be big enough to + * cover everything we plan to put here. + */ +#define SVM_GLOBAL_REGION_BASEVA 0x30000000 +#define SVM_GLOBAL_REGION_SIZE (64<<20) +#define SVM_GLOBAL_REGION_NAME "/global_vm" + +/* + * Memory shared across individual router instances. + */ +#define SVM_OVERLAY_REGION_BASEVA \ + (SVM_GLOBAL_REGION_BASEVA + SVM_GLOBAL_REGION_SIZE) +#define SVM_OVERLAY_REGION_SIZE (1<<20) +#define SVM_OVERLAY_REGION_BASENAME "/overlay_vm" + +typedef struct +{ + u8 *subregion_name; +} svm_subregion_t; + +typedef struct +{ + svm_subregion_t *subregions; /* subregion pool */ + uword *name_hash; + u8 *root_path; +} svm_main_region_t; + + +void *svm_region_find_or_create (svm_map_region_args_t * a); +void svm_region_init (void); +void svm_region_init_chroot (char *root_path); +void svm_region_init_chroot_uid_gid (char *root_path, int uid, int gid); +void svm_region_init_args (svm_map_region_args_t * a); +void svm_region_exit (void); +void svm_region_unmap (void *rp_arg); +void svm_client_scan (char *root_path); +void svm_client_scan_this_region_nolock (svm_region_t * rp); +u8 *shm_name_from_svm_map_region_args (svm_map_region_args_t * a); + +static inline void * +svm_mem_alloc (svm_region_t * rp, uword size) +{ + u8 *oldheap; + ASSERT (rp->flags & SVM_FLAGS_MHEAP); + u8 *rv; + + pthread_mutex_lock (&rp->mutex); + oldheap = clib_mem_set_heap (rp->data_heap); + rv = clib_mem_alloc (size); + clib_mem_set_heap (oldheap); + pthread_mutex_unlock (&rp->mutex); + return (rv); +} + +static inline void * +svm_mem_alloc_aligned_at_offset (svm_region_t * rp, + uword size, uword align, uword offset) +{ + u8 *oldheap; + ASSERT (rp->flags & SVM_FLAGS_MHEAP); + u8 *rv; + + pthread_mutex_lock (&rp->mutex); + oldheap = clib_mem_set_heap (rp->data_heap); + rv = clib_mem_alloc_aligned_at_offset (size, align, offset, + 1 /* yes, call os_out_of_memory */ ); + clib_mem_set_heap (oldheap); + pthread_mutex_unlock (&rp->mutex); + return (rv); +} + +static inline void +svm_mem_free (svm_region_t * rp, void *ptr) +{ + u8 *oldheap; + ASSERT (rp->flags & SVM_FLAGS_MHEAP); + + pthread_mutex_lock (&rp->mutex); + oldheap = clib_mem_set_heap (rp->data_heap); + clib_mem_free (ptr); + clib_mem_set_heap (oldheap); + pthread_mutex_unlock (&rp->mutex); + +} + +static inline void * +svm_push_pvt_heap (svm_region_t * rp) +{ + u8 *oldheap; + oldheap = clib_mem_set_heap (rp->region_heap); + return ((void *) oldheap); +} + +static inline void * +svm_push_data_heap (svm_region_t * rp) +{ + u8 *oldheap; + oldheap = clib_mem_set_heap (rp->data_heap); + return ((void *) oldheap); +} + +static inline void +svm_pop_heap (void *oldheap) +{ + clib_mem_set_heap (oldheap); +} + +u8 *format_svm_region (u8 * s, va_list * args); + +svm_region_t *svm_get_root_rp (void); + +#endif /* __included_svm_h__ */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/svm/svm_test.c b/src/svm/svm_test.c new file mode 100644 index 00000000..ab0b9e24 --- /dev/null +++ b/src/svm/svm_test.c @@ -0,0 +1,79 @@ +/* + * 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. + */ +/* + *------------------------------------------------------------------ + * svm_test.c -- brain police + *------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "svm.h" + + +int +main (int argc, char **argv) +{ + svm_region_t *root_rp, *rp; + svm_map_region_args_t *a = 0; + + vec_validate (a, 0); + + root_rp = svm_region_init (); + + ASSERT (root_rp); + + a->name = "/qvnet"; + a->size = (4 << 10); + + rp = svm_region_find_or_create (root_rp, a); + + ASSERT (rp); + + *((u32 *) rp->data_base) = 0xdeadbeef; + svm_region_unmap (root_rp, rp); + + fformat (stdout, "exiting...\n"); + + exit (0); +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/svm/svmdb.c b/src/svm/svmdb.c new file mode 100644 index 00000000..03dfe7c3 --- /dev/null +++ b/src/svm/svmdb.c @@ -0,0 +1,671 @@ +/* + *------------------------------------------------------------------ + * svmdb.c -- simple shared memory database + * + * Copyright (c) 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. + *------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "svmdb.h" + +static void local_set_variable_nolock (svmdb_client_t * client, + svmdb_namespace_t namespace, + u8 * var, u8 * val, u32 elsize); + +always_inline void +region_lock (svm_region_t * rp, int tag) +{ + pthread_mutex_lock (&rp->mutex); +#ifdef MUTEX_DEBUG + rp->mutex_owner_pid = getpid (); + rp->mutex_owner_tag = tag; +#endif +} + +always_inline void +region_unlock (svm_region_t * rp) +{ +#ifdef MUTEX_DEBUG + rp->mutex_owner_pid = 0; + rp->mutex_owner_tag = 0; +#endif + pthread_mutex_unlock (&rp->mutex); +} + +svmdb_client_t * +svmdb_map (svmdb_map_args_t * dba) +{ + svmdb_client_t *client = 0; + svm_map_region_args_t *a = 0; + svm_region_t *db_rp; + void *oldheap; + svmdb_shm_hdr_t *hp = 0; + + vec_validate (client, 0); + vec_validate (a, 0); + + svm_region_init_chroot_uid_gid (dba->root_path, dba->uid, dba->gid); + + a->root_path = dba->root_path; + a->name = "/db"; + a->size = dba->size ? dba->size : SVMDB_DEFAULT_SIZE; + a->flags = SVM_FLAGS_MHEAP; + a->uid = dba->uid; + a->gid = dba->gid; + + db_rp = client->db_rp = svm_region_find_or_create (a); + + ASSERT (db_rp); + + vec_free (a); + + region_lock (client->db_rp, 10); + /* Has someone else set up the shared-memory variable table? */ + if (db_rp->user_ctx) + { + client->shm = (void *) db_rp->user_ctx; + client->pid = getpid (); + region_unlock (client->db_rp); + ASSERT (client->shm->version == SVMDB_SHM_VERSION); + return (client); + } + /* Nope, it's our problem... */ + + /* Add a bogus client (pid=0) so the svm won't be deallocated */ + oldheap = svm_push_pvt_heap (db_rp); + vec_add1 (client->db_rp->client_pids, 0); + svm_pop_heap (oldheap); + + oldheap = svm_push_data_heap (db_rp); + + vec_validate (hp, 0); + hp->version = SVMDB_SHM_VERSION; + hp->namespaces[SVMDB_NAMESPACE_STRING] + = hash_create_string (0, sizeof (uword)); + hp->namespaces[SVMDB_NAMESPACE_VEC] + = hash_create_string (0, sizeof (uword)); + + db_rp->user_ctx = hp; + client->shm = hp; + + svm_pop_heap (oldheap); + region_unlock (client->db_rp); + client->pid = getpid (); + + return (client); +} + +void +svmdb_unmap (svmdb_client_t * client) +{ + ASSERT (client); + + if (!svm_get_root_rp ()) + return; + + svm_region_unmap ((void *) client->db_rp); + svm_region_exit (); + vec_free (client); +} + +static void +notify_value (svmdb_value_t * v, svmdb_action_t a) +{ + int i; + int rv; + union sigval sv; + u32 value; + u32 *dead_registrations = 0; + + svmdb_notify_t *np; + + for (i = 0; i < vec_len (v->notifications); i++) + { + np = vec_elt_at_index (v->notifications, i); + if (np->action == a) + { + value = (np->action << 28) | (np->opaque); + sv.sival_ptr = (void *) (uword) value; + do + { + rv = 0; + if (sigqueue (np->pid, np->signum, sv) == 0) + break; + rv = errno; + } + while (rv == EAGAIN); + if (rv == 0) + continue; + vec_add1 (dead_registrations, i); + } + } + + for (i = 0; i < vec_len (dead_registrations); i++) + { + np = vec_elt_at_index (v->notifications, dead_registrations[i]); + clib_warning ("dead reg pid %d sig %d action %d opaque %x", + np->pid, np->signum, np->action, np->opaque); + vec_delete (v->notifications, 1, dead_registrations[i]); + } + vec_free (dead_registrations); +} + +int +svmdb_local_add_del_notification (svmdb_client_t * client, + svmdb_notification_args_t * a) +{ + uword *h; + void *oldheap; + hash_pair_t *hp; + svmdb_shm_hdr_t *shm; + u8 *dummy_value = 0; + svmdb_value_t *value; + svmdb_notify_t *np; + int i; + int rv = 0; + + ASSERT (a->elsize); + + region_lock (client->db_rp, 18); + shm = client->shm; + oldheap = svm_push_data_heap (client->db_rp); + + h = shm->namespaces[a->nspace]; + + hp = hash_get_pair_mem (h, a->var); + if (hp == 0) + { + local_set_variable_nolock (client, a->nspace, (u8 *) a->var, + dummy_value, a->elsize); + /* might have moved */ + h = shm->namespaces[a->nspace]; + hp = hash_get_pair_mem (h, a->var); + ASSERT (hp); + } + + value = pool_elt_at_index (shm->values, hp->value[0]); + + for (i = 0; i < vec_len (value->notifications); i++) + { + np = vec_elt_at_index (value->notifications, i); + if ((np->pid == client->pid) + && (np->signum == a->signum) + && (np->action == a->action) && (np->opaque == a->opaque)) + { + if (a->add_del == 0 /* delete */ ) + { + vec_delete (value->notifications, 1, i); + goto out; + } + else + { /* add */ + clib_warning + ("%s: ignore dup reg pid %d signum %d action %d opaque %x", + a->var, client->pid, a->signum, a->action, a->opaque); + rv = -2; + goto out; + } + } + } + if (a->add_del == 0) + { + rv = -3; + goto out; + } + + vec_add2 (value->notifications, np, 1); + np->pid = client->pid; + np->signum = a->signum; + np->action = a->action; + np->opaque = a->opaque; + +out: + svm_pop_heap (oldheap); + region_unlock (client->db_rp); + return rv; +} + + +static void +local_unset_variable_nolock (svmdb_client_t * client, + svmdb_namespace_t namespace, char *var) +{ + uword *h; + svmdb_value_t *oldvalue; + hash_pair_t *hp; + + h = client->shm->namespaces[namespace]; + hp = hash_get_pair_mem (h, var); + if (hp) + { + oldvalue = pool_elt_at_index (client->shm->values, hp->value[0]); + if (vec_len (oldvalue->notifications)) + notify_value (oldvalue, SVMDB_ACTION_UNSET); + /* zero length value means unset */ + _vec_len (oldvalue->value) = 0; + } + client->shm->namespaces[namespace] = h; +} + +void +svmdb_local_unset_string_variable (svmdb_client_t * client, char *var) +{ + void *oldheap; + + region_lock (client->db_rp, 11); + oldheap = svm_push_data_heap (client->db_rp); + local_unset_variable_nolock (client, SVMDB_NAMESPACE_STRING, var); + svm_pop_heap (oldheap); + region_unlock (client->db_rp); +} + +static void +local_set_variable_nolock (svmdb_client_t * client, + svmdb_namespace_t namespace, + u8 * var, u8 * val, u32 elsize) +{ + uword *h; + hash_pair_t *hp; + u8 *name; + svmdb_shm_hdr_t *shm; + + shm = client->shm; + h = shm->namespaces[namespace]; + hp = hash_get_pair_mem (h, var); + if (hp) + { + svmdb_value_t *oldvalue; + oldvalue = pool_elt_at_index (client->shm->values, hp->value[0]); + vec_alloc (oldvalue->value, vec_len (val) * elsize); + clib_memcpy (oldvalue->value, val, vec_len (val) * elsize); + _vec_len (oldvalue->value) = vec_len (val); + notify_value (oldvalue, SVMDB_ACTION_SET); + } + else + { + svmdb_value_t *newvalue; + pool_get (shm->values, newvalue); + memset (newvalue, 0, sizeof (*newvalue)); + newvalue->elsize = elsize; + vec_alloc (newvalue->value, vec_len (val) * elsize); + clib_memcpy (newvalue->value, val, vec_len (val) * elsize); + _vec_len (newvalue->value) = vec_len (val); + name = format (0, "%s%c", var, 0); + hash_set_mem (h, name, newvalue - shm->values); + } + shm->namespaces[namespace] = h; +} + +void +svmdb_local_set_string_variable (svmdb_client_t * client, + char *var, char *val) +{ + void *oldheap; + + region_lock (client->db_rp, 12); + oldheap = svm_push_data_heap (client->db_rp); + + local_unset_variable_nolock (client, SVMDB_NAMESPACE_STRING, var); + + local_set_variable_nolock (client, SVMDB_NAMESPACE_STRING, + (u8 *) var, (u8 *) val, 1 /* elsize */ ); + svm_pop_heap (oldheap); + region_unlock (client->db_rp); +} + +static u8 * +local_get_variable_nolock (svmdb_client_t * client, + svmdb_namespace_t namespace, u8 * var) +{ + uword *h; + uword *p; + svmdb_shm_hdr_t *shm; + svmdb_value_t *oldvalue; + + shm = client->shm; + h = shm->namespaces[namespace]; + p = hash_get_mem (h, var); + if (p) + { + oldvalue = pool_elt_at_index (shm->values, p[0]); + notify_value (oldvalue, SVMDB_ACTION_GET); + return (oldvalue->value); + } + return 0; +} + +void * +svmdb_local_get_variable_reference (svmdb_client_t * client, + svmdb_namespace_t namespace, char *var) +{ + u8 *rv; + + region_lock (client->db_rp, 19); + rv = local_get_variable_nolock (client, namespace, (u8 *) var); + region_unlock (client->db_rp); + return (void *) rv; +} + +char * +svmdb_local_get_string_variable (svmdb_client_t * client, char *var) +{ + u8 *rv = 0; + + region_lock (client->db_rp, 13); + rv = local_get_variable_nolock (client, SVMDB_NAMESPACE_STRING, (u8 *) var); + + if (rv && vec_len (rv)) + { + rv = format (0, "%s", rv); + vec_add1 (rv, 0); + } + region_unlock (client->db_rp); + return ((char *) rv); +} + +void +svmdb_local_dump_strings (svmdb_client_t * client) +{ + uword *h; + u8 *key; + u32 value; + svmdb_shm_hdr_t *shm = client->shm; + + region_lock (client->db_rp, 14); + + h = client->shm->namespaces[SVMDB_NAMESPACE_STRING]; + + /* *INDENT-OFF* */ + hash_foreach_mem(key, value, h, + ({ + svmdb_value_t *v = pool_elt_at_index (shm->values, value); + + fformat(stdout, "%s: %s\n", key, + vec_len(v->value) ? v->value : (u8 *)"(nil)"); + })); + /* *INDENT-ON* */ + region_unlock (client->db_rp); +} + +int +svmdb_local_serialize_strings (svmdb_client_t * client, char *filename) +{ + uword *h; + u8 *key; + u32 value; + svmdb_shm_hdr_t *shm = client->shm; + serialize_main_t _sm, *sm = &_sm; + clib_error_t *error = 0; + u8 *sanitized_name = 0; + int fd = 0; + + if (strstr (filename, "..") || index (filename, '/')) + { + error = clib_error_return (0, "Illegal characters in filename '%s'", + filename); + goto out; + } + + sanitized_name = format (0, "/tmp/%s%c", filename, 0); + + fd = creat ((char *) sanitized_name, 0644); + + if (fd < 0) + { + error = clib_error_return_unix (0, "Create '%s'", sanitized_name); + goto out; + } + + serialize_open_unix_file_descriptor (sm, fd); + + region_lock (client->db_rp, 20); + + h = client->shm->namespaces[SVMDB_NAMESPACE_STRING]; + + serialize_likely_small_unsigned_integer (sm, hash_elts (h)); + + /* *INDENT-OFF* */ + hash_foreach_mem(key, value, h, + ({ + svmdb_value_t *v = pool_elt_at_index (shm->values, value); + + /* Omit names with nil values */ + if (vec_len(v->value)) + { + serialize_cstring (sm, (char *)key); + serialize_cstring (sm, (char *)v->value); + } + })); + /* *INDENT-ON* */ + region_unlock (client->db_rp); + + serialize_close (sm); + +out: + if (fd > 0 && close (fd) < 0) + error = clib_error_return_unix (0, "close fd %d", fd); + + if (error) + { + clib_error_report (error); + return -1; + } + return 0; +} + +int +svmdb_local_unserialize_strings (svmdb_client_t * client, char *filename) +{ + serialize_main_t _sm, *sm = &_sm; + void *oldheap; + clib_error_t *error = 0; + u8 *key, *value; + int fd = 0; + u32 nelts; + int i; + + fd = open (filename, O_RDONLY); + + if (fd < 0) + { + error = clib_error_return_unix (0, "Failed to open '%s'", filename); + goto out; + } + + unserialize_open_unix_file_descriptor (sm, fd); + + region_lock (client->db_rp, 21); + oldheap = svm_push_data_heap (client->db_rp); + + nelts = unserialize_likely_small_unsigned_integer (sm); + + for (i = 0; i < nelts; i++) + { + unserialize_cstring (sm, (char **) &key); + unserialize_cstring (sm, (char **) &value); + local_set_variable_nolock (client, SVMDB_NAMESPACE_STRING, + key, value, 1 /* elsize */ ); + vec_free (key); + vec_free (value); + } + svm_pop_heap (oldheap); + region_unlock (client->db_rp); + + serialize_close (sm); + +out: + if (fd > 0 && close (fd) < 0) + error = clib_error_return_unix (0, "close fd %d", fd); + + if (error) + { + clib_error_report (error); + return -1; + } + return 0; +} + +void +svmdb_local_unset_vec_variable (svmdb_client_t * client, char *var) +{ + void *oldheap; + + region_lock (client->db_rp, 15); + oldheap = svm_push_data_heap (client->db_rp); + local_unset_variable_nolock (client, SVMDB_NAMESPACE_VEC, var); + svm_pop_heap (oldheap); + region_unlock (client->db_rp); +} + +void +svmdb_local_set_vec_variable (svmdb_client_t * client, + char *var, void *val_arg, u32 elsize) +{ + u8 *val = (u8 *) val_arg; + void *oldheap; + + region_lock (client->db_rp, 16); + oldheap = svm_push_data_heap (client->db_rp); + + local_unset_variable_nolock (client, SVMDB_NAMESPACE_VEC, var); + local_set_variable_nolock (client, SVMDB_NAMESPACE_VEC, (u8 *) var, + val, elsize); + + svm_pop_heap (oldheap); + region_unlock (client->db_rp); +} + +void * +svmdb_local_get_vec_variable (svmdb_client_t * client, char *var, u32 elsize) +{ + u8 *rv = 0; + u8 *copy = 0; + + region_lock (client->db_rp, 17); + + rv = local_get_variable_nolock (client, SVMDB_NAMESPACE_VEC, (u8 *) var); + + if (rv && vec_len (rv)) + { + /* Make a copy in process-local memory */ + vec_alloc (copy, vec_len (rv) * elsize); + clib_memcpy (copy, rv, vec_len (rv) * elsize); + _vec_len (copy) = vec_len (rv); + region_unlock (client->db_rp); + return (copy); + } + region_unlock (client->db_rp); + return (0); +} + +void +svmdb_local_dump_vecs (svmdb_client_t * client) +{ + uword *h; + u8 *key; + u32 value; + svmdb_shm_hdr_t *shm; + + region_lock (client->db_rp, 17); + shm = client->shm; + + h = client->shm->namespaces[SVMDB_NAMESPACE_VEC]; + + /* *INDENT-OFF* */ + hash_foreach_mem(key, value, h, + ({ + svmdb_value_t *v = pool_elt_at_index (shm->values, value); + (void) fformat(stdout, "%s:\n %U (%.2f)\n", key, + format_hex_bytes, v->value, + vec_len(v->value)*v->elsize, ((f64 *)(v->value))[0]); + })); + /* *INDENT-ON* */ + + region_unlock (client->db_rp); +} + +void * +svmdb_local_find_or_add_vec_variable (svmdb_client_t * client, + char *var, u32 nbytes) +{ + void *oldheap; + u8 *rv = 0; + + region_lock (client->db_rp, 18); + oldheap = svm_push_data_heap (client->db_rp); + + rv = local_get_variable_nolock (client, SVMDB_NAMESPACE_VEC, (u8 *) var); + + if (rv) + { + goto out; + } + else + { + uword *h; + u8 *name; + svmdb_shm_hdr_t *shm; + svmdb_value_t *newvalue; + + shm = client->shm; + h = shm->namespaces[SVMDB_NAMESPACE_VEC]; + + pool_get (shm->values, newvalue); + memset (newvalue, 0, sizeof (*newvalue)); + newvalue->elsize = 1; + vec_alloc (newvalue->value, nbytes); + _vec_len (newvalue->value) = nbytes; + name = format (0, "%s%c", var, 0); + hash_set_mem (h, name, newvalue - shm->values); + shm->namespaces[SVMDB_NAMESPACE_VEC] = h; + rv = newvalue->value; + } + +out: + svm_pop_heap (oldheap); + region_unlock (client->db_rp); + return (rv); +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/svm/svmdb.h b/src/svm/svmdb.h new file mode 100644 index 00000000..e02628a0 --- /dev/null +++ b/src/svm/svmdb.h @@ -0,0 +1,135 @@ +/* + *------------------------------------------------------------------ + * svmdb.h - shared VM database + * + * Copyright (c) 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 __included_svmdb_h__ +#define __included_svmdb_h__ + +#include "svm.h" + +typedef enum +{ + SVMDB_ACTION_ILLEGAL = 0, + SVMDB_ACTION_GET, /* not clear why anyone would care */ + SVMDB_ACTION_SET, + SVMDB_ACTION_UNSET, +} svmdb_action_t; + +typedef struct +{ + int pid; + int signum; + u32 action:4; + u32 opaque:28; +} svmdb_notify_t; + +typedef struct +{ + u8 *value; + svmdb_notify_t *notifications; + u32 elsize; +} svmdb_value_t; + +typedef enum +{ + SVMDB_NAMESPACE_STRING = 0, + SVMDB_NAMESPACE_VEC, + SVMDB_N_NAMESPACES, +} svmdb_namespace_t; + +typedef struct +{ + uword version; + /* pool of values */ + svmdb_value_t *values; + uword *namespaces[SVMDB_N_NAMESPACES]; +} svmdb_shm_hdr_t; + +#define SVMDB_SHM_VERSION 2 + +typedef struct +{ + int flags; + int pid; + svm_region_t *db_rp; + svmdb_shm_hdr_t *shm; +} svmdb_client_t; + +typedef struct +{ + int add_del; + svmdb_namespace_t nspace; + char *var; + u32 elsize; + int signum; + u32 action:4; + u32 opaque:28; +} svmdb_notification_args_t; + +typedef struct +{ + char *root_path; + uword size; + u32 uid; + u32 gid; +} svmdb_map_args_t; + +/* + * Must be a reasonable number, several mb smaller than + * SVM_GLOBAL_REGION_SIZE, or no donut for you... + */ +#define SVMDB_DEFAULT_SIZE (4<<20) + +svmdb_client_t *svmdb_map (svmdb_map_args_t *); + +void svmdb_unmap (svmdb_client_t * client); +void svmdb_local_unset_string_variable (svmdb_client_t * client, char *var); +void svmdb_local_set_string_variable (svmdb_client_t * client, + char *var, char *val); +char *svmdb_local_get_string_variable (svmdb_client_t * client, char *var); +void *svmdb_local_get_variable_reference (svmdb_client_t * client, + svmdb_namespace_t ns, char *var); + +void svmdb_local_dump_strings (svmdb_client_t * client); + +void svmdb_local_unset_vec_variable (svmdb_client_t * client, char *var); +void svmdb_local_set_vec_variable (svmdb_client_t * client, + char *var, void *val, u32 elsize); +void *svmdb_local_get_vec_variable (svmdb_client_t * client, char *var, + u32 elsize); +void svmdb_local_dump_vecs (svmdb_client_t * client); + +int svmdb_local_add_del_notification (svmdb_client_t * client, + svmdb_notification_args_t * args); + +void *svmdb_local_find_or_add_vec_variable (svmdb_client_t * client, + char *var, u32 nbytes); + +int svmdb_local_serialize_strings (svmdb_client_t * client, char *filename); +int svmdb_local_unserialize_strings (svmdb_client_t * client, char *filename); + + +#endif /* __included_svmdb_h__ */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/svm/svmdbtool.c b/src/svm/svmdbtool.c new file mode 100644 index 00000000..a0af15fc --- /dev/null +++ b/src/svm/svmdbtool.c @@ -0,0 +1,537 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "svmdb.h" + +typedef struct +{ + svmdb_map_args_t map_args; + int uid, gid; + uword size; +} svmdbtool_main_t; + +svmdbtool_main_t svmdbtool_main; + +static inline svmdb_map_args_t * +map_arg_setup (char *chroot_path) +{ + svmdbtool_main_t *sm = &svmdbtool_main; + svmdb_map_args_t *ma = &sm->map_args; + + memset (ma, 0, sizeof (*ma)); + ma->root_path = chroot_path; + ma->size = sm->size; + ma->uid = sm->uid; + ma->gid = sm->gid; + return ma; +} + +static void +get_string (char *chroot_path, u8 * vbl) +{ + svmdb_client_t *c; + char *rv; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + + rv = svmdb_local_get_string_variable (c, (char *) vbl); + + fformat (stdout, "%s\n", rv ? rv : "UNSET"); + vec_free (rv); + svmdb_unmap (c); +} + +static void +set_string (char *chroot_path, u8 * vbl, u8 * value) +{ + svmdb_client_t *c; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + svmdb_local_set_string_variable (c, (char *) vbl, (char *) value); + svmdb_unmap (c); +} + +static void +unset_string (char *chroot_path, u8 * vbl) +{ + svmdb_client_t *c; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + svmdb_local_unset_string_variable (c, (char *) vbl); + svmdb_unmap (c); +} + +static void +dump_strings (char *chroot_path) +{ + svmdb_client_t *c; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + svmdb_local_dump_strings (c); + svmdb_unmap (c); +} + +static void +serialize_strings (char *chroot_path, char *filename) +{ + svmdb_client_t *c; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + (void) svmdb_local_serialize_strings (c, filename); + svmdb_unmap (c); +} + +static void +unserialize_strings (char *chroot_path, char *filename) +{ + svmdb_client_t *c; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + (void) svmdb_local_unserialize_strings (c, filename); + svmdb_unmap (c); +} + +static void +test_vlib_vec_rate (char *chroot_path, f64 vr) +{ + svmdb_client_t *c; + f64 *tv = 0; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + + vec_add1 (tv, vr); + + svmdb_local_set_vec_variable (c, "vlib_vector_rate", (char *) tv, + sizeof (*tv)); + svmdb_unmap (c); + + vec_free (tv); +} + + + +static void +test_vec (char *chroot_path, u8 * vbl) +{ + svmdb_client_t *c; + u64 *tv = 0; + int i; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + + /* my amp goes to 11 */ + for (i = 0; i < 11; i++) + { + vec_add1 (tv, i); + } + + svmdb_local_set_vec_variable (c, (char *) vbl, (char *) tv, sizeof (tv[0])); + svmdb_unmap (c); + + vec_free (tv); +} + +static void +fake_install (char *chroot_path, u8 * add_value) +{ + svmdb_client_t *c; + u8 *v = 0; + u8 **values = 0; + u8 *oldvalue; + u8 *value; + int nitems = 0, i; + serialize_main_t m; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + + oldvalue = svmdb_local_get_vec_variable (c, "installed_sw", 1); + if (oldvalue) + { + unserialize_open_data (&m, oldvalue, vec_len (oldvalue)); + nitems = unserialize_likely_small_unsigned_integer (&m); + for (i = 0; i < nitems; i++) + { + unserialize_cstring (&m, (char **) &value); + vec_add1 (values, value); + } + vec_free (v); + } + nitems++; + value = format (0, "%s%c", add_value, 0); + + vec_add1 (values, value); + + fformat (stdout, "Resulting installed_sw vector:\n"); + + serialize_open_vector (&m, v); + serialize_likely_small_unsigned_integer (&m, vec_len (values)); + for (i = 0; i < vec_len (values); i++) + { + fformat (stdout, "%s\n", values[i]); + serialize_cstring (&m, (char *) values[i]); + } + + v = serialize_close_vector (&m); + + svmdb_local_set_vec_variable (c, "installed_sw", v, sizeof (v[0])); + svmdb_unmap (c); + + for (i = 0; i < vec_len (values); i++) + vec_free (values[i]); + vec_free (values); +} + +static void +sigaction_handler (int signum, siginfo_t * i, void *notused) +{ + u32 action, opaque; + + action = (u32) (uword) i->si_ptr; + action >>= 28; + opaque = (u32) (uword) i->si_ptr; + opaque &= ~(0xF0000000); + + clib_warning ("signal %d, action %d, opaque %x", signum, action, opaque); +} + +static void +test_reg (char *chroot_path, u8 * vbl) +{ + svmdb_client_t *c; + svmdb_notification_args_t args; + svmdb_notification_args_t *a = &args; + struct sigaction sa; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + memset (&sa, 0, sizeof (sa)); + sa.sa_sigaction = sigaction_handler; + sa.sa_flags = SA_SIGINFO; + if (sigaction (SIGUSR2, &sa, 0) < 0) + { + clib_unix_warning ("sigaction"); + return; + } + + memset (a, 0, sizeof (*a)); + + c = svmdb_map (ma); + + a->add_del = 1 /* add */ ; + a->nspace = SVMDB_NAMESPACE_STRING; + a->var = (char *) vbl; + a->elsize = 1; + a->signum = SIGUSR2; + a->action = SVMDB_ACTION_GET; + a->opaque = 0x0eadbeef; + + svmdb_local_add_del_notification (c, a); + + (void) svmdb_local_get_string_variable (c, (char *) vbl); + + a->add_del = 0; /* del */ + svmdb_local_add_del_notification (c, a); + + + + svmdb_unmap (c); +} + +static void +unset_vec (char *chroot_path, u8 * vbl) +{ + svmdb_client_t *c; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + + svmdb_local_unset_vec_variable (c, (char *) vbl); + svmdb_unmap (c); +} + +static void +dump_vecs (char *chroot_path) +{ + svmdb_client_t *c; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + + svmdb_local_dump_vecs (c); + svmdb_unmap (c); +} + +static void +crash_test (char *chroot_path) +{ + svmdb_client_t *c; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + + clib_warning ("Grab region mutex and crash deliberately!"); + c->db_rp->mutex_owner_pid = getpid (); + c->db_rp->mutex_owner_tag = -13; + pthread_mutex_lock (&c->db_rp->mutex); + + abort (); +} + +static void +map_with_size (char *chroot_path, uword size) +{ + svmdb_client_t *c; + svmdb_map_args_t *ma; + + svmdbtool_main.size = size; + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + + svmdb_unmap (c); +} + +int +main (int argc, char **argv) +{ + unformat_input_t input; + int parsed = 0; + u8 *vbl = 0, *value = 0; + char *chroot_path = 0; + u8 *chroot_path_u8; + u8 *filename; + uword size; + f64 vr; + int uid, gid, rv; + struct passwd _pw, *pw; + struct group _grp, *grp; + char *s, buf[128]; + + svmdbtool_main.uid = geteuid (); + svmdbtool_main.gid = getegid (); + + unformat_init_command_line (&input, argv); + + while (unformat_check_input (&input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (&input, "get-string %s", &vbl)) + { + get_string (chroot_path, vbl); + vec_free (vbl); + parsed++; + } + else if (unformat (&input, "set-string %s %s", &vbl, &value)) + { + set_string (chroot_path, vbl, value); + vec_free (vbl); + vec_free (value); + parsed++; + } + else if (unformat (&input, "unset-string %s", &vbl)) + { + unset_string (chroot_path, vbl); + vec_free (vbl); + parsed++; + } + else if (unformat (&input, "dump-strings")) + { + dump_strings (chroot_path); + parsed++; + } + else if (unformat (&input, "unset-vec %s", &vbl)) + { + unset_vec (chroot_path, vbl); + vec_free (vbl); + parsed++; + } + else if (unformat (&input, "dump-vecs")) + { + dump_vecs (chroot_path); + parsed++; + } + else if (unformat (&input, "test-vec %s", &vbl)) + { + test_vec (chroot_path, vbl); + // vec_free(vbl); + parsed++; + } + else if (unformat (&input, "vlib-vec-rate %f", &vr)) + { + test_vlib_vec_rate (chroot_path, vr); + parsed++; + } + else if (unformat (&input, "test-reg %s", &vbl)) + { + test_reg (chroot_path, vbl); + parsed++; + } + else if (unformat (&input, "crash-test")) + { + crash_test (chroot_path); + } + else if (unformat (&input, "chroot %s", &chroot_path_u8)) + { + chroot_path = (char *) chroot_path_u8; + } + else if (unformat (&input, "fake-install %s", &value)) + { + fake_install (chroot_path, value); + parsed++; + } + else if (unformat (&input, "size %d", &size)) + { + map_with_size (chroot_path, size); + parsed++; + } + else if (unformat (&input, "uid %d", &uid)) + svmdbtool_main.uid = uid; + else if (unformat (&input, "gid %d", &gid)) + svmdbtool_main.gid = gid; + else if (unformat (&input, "uid %s", &s)) + { + /* lookup the username */ + pw = NULL; + rv = getpwnam_r (s, &_pw, buf, sizeof (buf), &pw); + if (rv < 0) + { + fformat (stderr, "cannot fetch username %s", s); + exit (1); + } + if (pw == NULL) + { + fformat (stderr, "username %s does not exist", s); + exit (1); + } + vec_free (s); + svmdbtool_main.uid = pw->pw_uid; + } + else if (unformat (&input, "gid %s", &s)) + { + /* lookup the group name */ + grp = NULL; + rv = getgrnam_r (s, &_grp, buf, sizeof (buf), &grp); + if (rv != 0) + { + fformat (stderr, "cannot fetch group %s", s); + exit (1); + } + if (grp == NULL) + { + fformat (stderr, "group %s does not exist", s); + exit (1); + } + vec_free (s); + svmdbtool_main.gid = grp->gr_gid; + } + else if (unformat (&input, "serialize-strings %s", &filename)) + { + vec_add1 (filename, 0); + serialize_strings (chroot_path, (char *) filename); + parsed++; + } + else if (unformat (&input, "unserialize-strings %s", &filename)) + { + vec_add1 (filename, 0); + unserialize_strings (chroot_path, (char *) filename); + parsed++; + } + else + { + break; + } + } + + unformat_free (&input); + + if (!parsed) + { + fformat (stdout, "%s: get-string | set-string \n", + argv[0]); + fformat (stdout, " unset-string | dump-strings\n"); + fformat (stdout, " test-vec |\n"); + fformat (stdout, " unset-vec | dump-vecs\n"); + fformat (stdout, " chroot [uid ]\n"); + fformat (stdout, " [gid ]\n"); + } + + exit (0); +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/svm/svmtool.c b/src/svm/svmtool.c new file mode 100644 index 00000000..b3195514 --- /dev/null +++ b/src/svm/svmtool.c @@ -0,0 +1,528 @@ +/* + *------------------------------------------------------------------ + * svmtool.c + * + * Copyright (c) 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. + *------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "svm.h" + + + +/* + * format_all_svm_regions + * Maps / unmaps regions. Do NOT call from client code! + */ +u8 * +format_all_svm_regions (u8 * s, va_list * args) +{ + int verbose = va_arg (*args, int); + svm_region_t *root_rp = svm_get_root_rp (); + svm_main_region_t *mp; + svm_subregion_t *subp; + svm_region_t *rp; + svm_map_region_args_t *a = 0; + u8 **svm_names = 0; + u8 *name = 0; + int i; + + ASSERT (root_rp); + + pthread_mutex_lock (&root_rp->mutex); + + s = format (s, "%U", format_svm_region, root_rp, verbose); + + mp = root_rp->data_base; + + /* + * Snapshoot names, can't hold root rp mutex across + * find_or_create. + */ + /* *INDENT-OFF* */ + pool_foreach (subp, mp->subregions, ({ + name = vec_dup (subp->subregion_name); + vec_add1(svm_names, name); + })); + /* *INDENT-ON* */ + + pthread_mutex_unlock (&root_rp->mutex); + + for (i = 0; i < vec_len (svm_names); i++) + { + vec_validate (a, 0); + a->name = (char *) svm_names[i]; + rp = svm_region_find_or_create (a); + if (rp) + { + pthread_mutex_lock (&rp->mutex); + s = format (s, "%U", format_svm_region, rp, verbose); + pthread_mutex_unlock (&rp->mutex); + svm_region_unmap (rp); + vec_free (svm_names[i]); + } + vec_free (a); + } + vec_free (svm_names); + return (s); +} + +void +show (char *chroot_path, int verbose) +{ + svm_map_region_args_t *a = 0; + + vec_validate (a, 0); + + svm_region_init_chroot (chroot_path); + + fformat (stdout, "My pid is %d\n", getpid ()); + + fformat (stdout, "%U", format_all_svm_regions, verbose); + + svm_region_exit (); + + vec_free (a); +} + + +static void * +svm_map_region_nolock (svm_map_region_args_t * a) +{ + int svm_fd; + svm_region_t *rp; + int deadman = 0; + u8 *shm_name; + + ASSERT ((a->size & ~(MMAP_PAGESIZE - 1)) == a->size); + + shm_name = shm_name_from_svm_map_region_args (a); + + svm_fd = shm_open ((char *) shm_name, O_RDWR, 0777); + + if (svm_fd < 0) + { + perror ("svm_region_map(mmap open)"); + return (0); + } + vec_free (shm_name); + + rp = mmap (0, MMAP_PAGESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, svm_fd, 0); + + if (rp == (svm_region_t *) MAP_FAILED) + { + close (svm_fd); + clib_warning ("mmap"); + return (0); + } + /* + * We lost the footrace to create this region; make sure + * the winner has crossed the finish line. + */ + while (rp->version == 0 && deadman++ < 5) + { + sleep (1); + } + + /* + * -ed? + */ + if (rp->version == 0) + { + clib_warning ("rp->version %d not %d", rp->version, SVM_VERSION); + munmap (rp, MMAP_PAGESIZE); + return (0); + } + /* Remap now that the region has been placed */ + a->baseva = rp->virtual_base; + a->size = rp->virtual_size; + munmap (rp, MMAP_PAGESIZE); + + rp = (void *) mmap ((void *) a->baseva, a->size, + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FIXED, svm_fd, 0); + if ((uword) rp == (uword) MAP_FAILED) + { + clib_unix_warning ("mmap"); + return (0); + } + + if ((uword) rp != rp->virtual_base) + { + clib_warning ("mmap botch"); + } + + if (pthread_mutex_trylock (&rp->mutex)) + { + clib_warning ("rp->mutex LOCKED by pid %d, tag %d, cleared...", + rp->mutex_owner_pid, rp->mutex_owner_tag); + memset (&rp->mutex, 0, sizeof (rp->mutex)); + + } + else + { + clib_warning ("mutex OK...\n"); + pthread_mutex_unlock (&rp->mutex); + } + + return ((void *) rp); +} + +/* + * rnd_pagesize + * Round to a pagesize multiple, presumably 4k works + */ +static u64 +rnd_pagesize (u64 size) +{ + u64 rv; + + rv = (size + (MMAP_PAGESIZE - 1)) & ~(MMAP_PAGESIZE - 1); + return (rv); +} + +#define MUTEX_DEBUG + +always_inline void +region_lock (svm_region_t * rp, int tag) +{ + pthread_mutex_lock (&rp->mutex); +#ifdef MUTEX_DEBUG + rp->mutex_owner_pid = getpid (); + rp->mutex_owner_tag = tag; +#endif +} + +always_inline void +region_unlock (svm_region_t * rp) +{ +#ifdef MUTEX_DEBUG + rp->mutex_owner_pid = 0; + rp->mutex_owner_tag = 0; +#endif + pthread_mutex_unlock (&rp->mutex); +} + + +static void * +svm_existing_region_map_nolock (void *root_arg, svm_map_region_args_t * a) +{ + svm_region_t *root_rp = root_arg; + svm_main_region_t *mp; + svm_region_t *rp; + void *oldheap; + uword *p; + + a->size += MMAP_PAGESIZE + + (a->pvt_heap_size ? a->pvt_heap_size : SVM_PVT_MHEAP_SIZE); + a->size = rnd_pagesize (a->size); + + region_lock (root_rp, 4); + oldheap = svm_push_pvt_heap (root_rp); + mp = root_rp->data_base; + + ASSERT (mp); + + p = hash_get_mem (mp->name_hash, a->name); + + if (p) + { + rp = svm_map_region_nolock (a); + region_unlock (root_rp); + svm_pop_heap (oldheap); + return rp; + } + return 0; + +} + +static void +trace (char *chroot_path, char *name, int enable_disable) +{ + svm_map_region_args_t *a = 0; + svm_region_t *db_rp; + void *oldheap; + + vec_validate (a, 0); + + svm_region_init_chroot (chroot_path); + + a->name = name; + a->size = 1 << 20; + a->flags = SVM_FLAGS_MHEAP; + + db_rp = svm_region_find_or_create (a); + + ASSERT (db_rp); + + region_lock (db_rp, 20); + + oldheap = svm_push_data_heap (db_rp); + + mheap_trace (db_rp->data_heap, enable_disable); + + svm_pop_heap (oldheap); + region_unlock (db_rp); + + svm_region_unmap ((void *) db_rp); + svm_region_exit (); + vec_free (a); +} + + + +static void +subregion_repair (char *chroot_path) +{ + int i; + svm_main_region_t *mp; + svm_map_region_args_t a; + svm_region_t *root_rp; + svm_region_t *rp; + svm_subregion_t *subp; + u8 *name = 0; + u8 **svm_names = 0; + + svm_region_init_chroot (chroot_path); + root_rp = svm_get_root_rp (); + + pthread_mutex_lock (&root_rp->mutex); + + mp = root_rp->data_base; + + /* + * Snapshoot names, can't hold root rp mutex across + * find_or_create. + */ + /* *INDENT-OFF* */ + pool_foreach (subp, mp->subregions, ({ + name = vec_dup (subp->subregion_name); + vec_add1(svm_names, name); + })); + /* *INDENT-ON* */ + + pthread_mutex_unlock (&root_rp->mutex); + + for (i = 0; i < vec_len (svm_names); i++) + { + memset (&a, 0, sizeof (a)); + a.root_path = chroot_path; + a.name = (char *) svm_names[i]; + fformat (stdout, "Checking %s region...\n", a.name); + rp = svm_existing_region_map_nolock (root_rp, &a); + if (rp) + { + svm_region_unmap (rp); + vec_free (svm_names[i]); + } + } + vec_free (svm_names); +} + +void +repair (char *chroot_path, int crash_root_region) +{ + svm_region_t *root_rp = 0; + svm_map_region_args_t *a = 0; + void *svm_map_region (svm_map_region_args_t * a); + int svm_fd; + u8 *shm_name; + + fformat (stdout, "our pid: %d\n", getpid ()); + + vec_validate (a, 0); + + a->root_path = chroot_path; + a->name = SVM_GLOBAL_REGION_NAME; + a->baseva = SVM_GLOBAL_REGION_BASEVA; + a->size = SVM_GLOBAL_REGION_SIZE; + a->flags = SVM_FLAGS_NODATA; + + shm_name = shm_name_from_svm_map_region_args (a); + + svm_fd = shm_open ((char *) shm_name, O_RDWR, 0777); + + if (svm_fd < 0) + { + perror ("svm_region_map(mmap open)"); + goto out; + } + + vec_free (shm_name); + + root_rp = mmap (0, MMAP_PAGESIZE, + PROT_READ | PROT_WRITE, MAP_SHARED, svm_fd, 0); + + if (root_rp == (svm_region_t *) MAP_FAILED) + { + close (svm_fd); + clib_warning ("mmap"); + goto out; + } + + /* Remap now that the region has been placed */ + clib_warning ("remap to 0x%x", root_rp->virtual_base); + + a->baseva = root_rp->virtual_base; + a->size = root_rp->virtual_size; + munmap (root_rp, MMAP_PAGESIZE); + + root_rp = (void *) mmap ((void *) a->baseva, a->size, + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FIXED, svm_fd, 0); + if ((uword) root_rp == (uword) MAP_FAILED) + { + clib_unix_warning ("mmap"); + goto out; + } + + close (svm_fd); + + if ((uword) root_rp != root_rp->virtual_base) + { + clib_warning ("mmap botch"); + goto out; + } + + if (pthread_mutex_trylock (&root_rp->mutex)) + { + clib_warning ("root_rp->mutex LOCKED by pid %d, tag %d, cleared...", + root_rp->mutex_owner_pid, root_rp->mutex_owner_tag); + memset (&root_rp->mutex, 0, sizeof (root_rp->mutex)); + goto out; + } + else + { + clib_warning ("root_rp->mutex OK...\n"); + pthread_mutex_unlock (&root_rp->mutex); + } + +out: + vec_free (a); + /* + * Now that the root region is known to be OK, + * fix broken subregions + */ + subregion_repair (chroot_path); + + if (crash_root_region) + { + clib_warning ("Leaving root region locked on purpose..."); + pthread_mutex_lock (&root_rp->mutex); + root_rp->mutex_owner_pid = getpid (); + root_rp->mutex_owner_tag = 99; + } + svm_region_exit (); +} + +int +main (int argc, char **argv) +{ + unformat_input_t input; + int parsed = 0; + char *name; + char *chroot_path = 0; + u8 *chroot_u8; + + unformat_init_command_line (&input, argv); + + while (unformat_check_input (&input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (&input, "show-verbose")) + { + show (chroot_path, 1); + parsed++; + } + else if (unformat (&input, "show")) + { + show (chroot_path, 0); + parsed++; + } + else if (unformat (&input, "client-scan")) + { + svm_client_scan (chroot_path); + parsed++; + } + else if (unformat (&input, "repair")) + { + repair (chroot_path, 0 /* fix it */ ); + parsed++; + } + else if (unformat (&input, "crash")) + { + repair (chroot_path, 1 /* crash it */ ); + parsed++; + } + else if (unformat (&input, "trace-on %s", &name)) + { + trace (chroot_path, name, 1); + parsed++; + } + else if (unformat (&input, "trace-off %s", &name)) + { + trace (chroot_path, name, 0); + parsed++; + } + else if (unformat (&input, "chroot %s", &chroot_u8)) + { + chroot_path = (char *) chroot_u8; + } + else + { + break; + } + } + + unformat_free (&input); + + if (!parsed) + { + fformat (stdout, + "%s: show | show-verbose | client-scan | trace-on \n", + argv[0]); + fformat (stdout, " trace-off \n"); + } + exit (0); +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/tests/vnet/README b/src/tests/vnet/README new file mode 100644 index 00000000..10579e50 --- /dev/null +++ b/src/tests/vnet/README @@ -0,0 +1,10 @@ +Unit test infrastructure for vnet + +To run unit tests do the following: + + 1. build vpp with 'vpp_enable_tests = yes' in build-data/platforms/vpp.mk + + 2. go to build-root/build-$tag-$arch/vnet + + 3. run + $ make check diff --git a/src/tests/vnet/lisp-cp/test_cp_serdes.c b/src/tests/vnet/lisp-cp/test_cp_serdes.c new file mode 100644 index 00000000..9d51dc8f --- /dev/null +++ b/src/tests/vnet/lisp-cp/test_cp_serdes.c @@ -0,0 +1,639 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 + +/* FIXME */ +#include +vpe_api_main_t vpe_api_main; + +#define _assert(e) \ + error = CLIB_ERROR_ASSERT (e); \ + if (error) \ + goto done; + +static void print_chunk(u8 * b, int * offset, int c, char * des) +{ + int i, n = offset[0] + c;; + for (i = offset[0]; i < n; i++) + { + printf("0x%02x, ", b[i]); + } + printf(" // %s\n", des); + *offset += c; +} + +void print_map_request(map_request_hdr_t * h) +{ +#define pchunk(_count, _desc) \ + print_chunk((u8 *)h, &offset, _count, _desc) + + int offset = 0; + + pchunk(4, "data"); + pchunk(8, "Nonce"); + pchunk(2, "Source-EID-AFI"); + pchunk(4, "Source EID Address"); + pchunk(2, "ITR-RLOC-AFI 1"); + pchunk(4, "ITR-RLOC Address 1"); + pchunk(2, "ITR-RLOC-AFI 2"); + pchunk(16, "ITR-RLOC Address 2"); + pchunk(1, "REC: reserved"); + pchunk(1, "REC: EID mask-len"); + pchunk(2, "REC: EID-prefix-AFI"); + pchunk(4, "REC: EID-prefix"); + printf("\n"); +} + +static clib_error_t * test_lisp_msg_push_ecm () +{ + vlib_main_t * vm = vlib_get_main (); + clib_error_t * error = 0; + gid_address_t la, ra; + vlib_buffer_t * b = 0; + u32 buff_len = 900; + int lp = 0x15, rp = 0x14; + + b = clib_mem_alloc (buff_len); + memset((u8 *)b, 0, buff_len); + b->current_length = buff_len; + b->current_data = sizeof(udp_header_t) + sizeof(ip4_header_t) + + sizeof(ecm_hdr_t) + 1; + + la.type = GID_ADDR_IP_PREFIX; + la.ippref.addr.ip.v4.as_u32 = 0xa1b2c3d4; + la.ippref.addr.version = IP4; + + ra.type = GID_ADDR_IP_PREFIX; + ra.ippref.addr.ip.v4.as_u32 = 0x90817263; + ra.ippref.addr.version = IP4; + + ecm_hdr_t * lh = lisp_msg_push_ecm (vm, b, lp, rp, &la, &ra); + + u8 expected_ecm_hdr[] = { + 0x80, 0x00, 0x00, 0x00 + }; + _assert(0 == memcmp(expected_ecm_hdr, lh, sizeof(expected_ecm_hdr))); + + ip4_header_t * ih = (ip4_header_t *) (lh + 1); + /* clear ip checksum */ + memset((u8 *)ih + 10, 0, 2); + + u8 expected_ip4_hdr[] = { + 0x45, /* version; IHL */ + 0x00, /* services */ + 0x03, 0xa0, /* total length */ + 0x00, 0x00, /* identification */ + 0x40, 0x00, /* flags; fragment offset*/ + 0xff, /* TTL */ + 0x11, /* protocol */ + 0x00, 0x00, /* header checksum */ + 0xd4, 0xc3, 0xb2, 0xa1, /* src IP */ + 0x63, 0x72, 0x81, 0x90, /* dst IP */ + }; + _assert(0 == memcmp(ih, expected_ip4_hdr, sizeof(expected_ip4_hdr))); + + udp_header_t * uh = (udp_header_t *) (ih + 1); + /* clear udp checksum */ + memset((u8 *)uh + 6, 0, 2); + + u8 expected_udp_hdr[] = { + 0x00, 0x15, /* src port */ + 0x00, 0x14, /* dst port */ + 0x03, 0x8c, /* length */ + 0x00, 0x00, /* checksum */ + }; + _assert(0 == memcmp(uh, expected_udp_hdr, sizeof(expected_udp_hdr))); + +done: + clib_mem_free (b); + return error; +} + +static clib_error_t * test_lisp_msg_parse_mapping_record () +{ + clib_error_t * error = 0; + locator_t probed; + locator_t * locs = 0; + vlib_buffer_t * b = 0; + gid_address_t eid; + u32 buff_len = 500; + + b = clib_mem_alloc (buff_len); + memset((u8 *)b, 0, buff_len); + + u8 map_reply_records[] = { + /* 1. record */ + 0x01, 0x02, 0x03, 0x04, /* record TTL */ + 0x01, /* locator count */ + 0x00, 0x00, 0x00, /* eid-mask-len; ... */ + 0x00, 0x00, /* reserved; map-version num */ + 0x00, 0x01, /* EID-Prefix-AFI */ + 0x33, 0x44, 0x55, 0x66, /* eid-prefix */ + /* loc */ + 0x0a, /* prority */ + 0x0b, /* weight */ + 0x0c, /* m-prority */ + 0x0d, /* m-weight */ + 0x00, 0x00, /* unused flags */ + 0x00, 0x01, /* Loc-AFI */ + 0xaa, 0xbb, 0xcc, 0xdd, /* Loator */ + }; + b->current_length = buff_len; + clib_memcpy(b->data, map_reply_records, sizeof(map_reply_records)); + + lisp_msg_parse_mapping_record (b, &eid, &locs, &probed); + _assert(vec_len (locs) == 1); + _assert(eid.ippref.addr.ip.v4.as_u32 == 0x66554433); + _assert(locs[0].local == 0); + _assert(locs[0].address.ippref.addr.ip.v4.as_u32 == 0xddccbbaa); + _assert(locs[0].address.type == GID_ADDR_IP_PREFIX); + _assert(locs[0].priority == 0xa); + _assert(locs[0].weight == 0xb); + _assert(locs[0].mpriority == 0xc); + _assert(locs[0].mweight == 0xd); + +done: + clib_mem_free (b); + if (locs) + vec_free (locs); + return error; +} + +static map_request_hdr_t * +build_map_request (lisp_cp_main_t * lcm, vlib_buffer_t * b, + gid_address_t * rlocs) +{ + gid_address_t _seid, * seid = &_seid; + gid_address_t _deid, * deid = &_deid; + u8 is_smr_invoked = 1; + u8 rloc_probe_set = 0; + u64 nonce = 0; + map_request_hdr_t * h = 0; + memset (deid, 0, sizeof (deid[0])); + memset (seid, 0, sizeof (seid[0])); + + gid_address_type (seid) = GID_ADDR_IP_PREFIX; + ip_address_t * ip_addr = &gid_address_ip (seid); + ip_addr_v4 (ip_addr).as_u32 = 0x12345678; + seid->ippref.addr.version = IP4; + + gid_address_type (deid) = GID_ADDR_IP_PREFIX; + ip_address_t * ip_addr2 = &gid_address_ip (deid); + ip_addr_v4 (ip_addr2).as_u32 = 0x9abcdef0; + deid->ippref.addr.version = IP4; + gid_address_ippref_len (deid) = 24; + + h = lisp_msg_put_mreq (lcm, b, seid, deid, rlocs, + is_smr_invoked, rloc_probe_set, &nonce); + vec_free(rlocs); + return h; +} + +static void +generate_rlocs (gid_address_t **rlocs, u32 * count) +{ + gid_address_t gid_addr_data, * gid_addr = &gid_addr_data; + memset (gid_addr, 0, sizeof (gid_addr[0])); + ip_address_t * addr = &gid_address_ip (gid_addr); + + gid_address_type (gid_addr) = GID_ADDR_IP_PREFIX; + + ip_addr_version (addr) = IP4; + ip_addr_v4 (addr).data_u32 = 0x10203040; + vec_add1 (rlocs[0], gid_addr[0]); + + ip_addr_v6 (addr).as_u32[0] = 0xffeeddcc; + ip_addr_v6 (addr).as_u32[1] = 0xbbaa9988; + ip_addr_v6 (addr).as_u32[2] = 0x77665544; + ip_addr_v6 (addr).as_u32[3] = 0x33221100; + ip_addr_version (addr) = IP6; + vec_add1 (rlocs[0], gid_addr[0]); +} + +static clib_error_t * test_lisp_msg_parse () +{ + gid_address_t eid; + lisp_cp_main_t * lcm = vnet_lisp_cp_get_main(); + map_request_hdr_t *h; + gid_address_t gid; + clib_error_t * error = 0; + vlib_buffer_t * b; + gid_address_t * rlocs_decode = 0, * rlocs = 0; + u32 rloc_count_parse = 0; + + u8 * data = clib_mem_alloc(500); + memset(data, 0, 500); + b = (vlib_buffer_t *) data; + + generate_rlocs (&rlocs_decode, &rloc_count_parse); + h = build_map_request (lcm, b, rlocs_decode); + + vlib_buffer_pull(b, sizeof(*h)); + u32 len = lisp_msg_parse_addr(b, &gid); + _assert (len == 2 + 4 + /* Source-EID-AFI field lenght + IPv4 address length */); + _assert (gid.ippref.addr.ip.v4.as_u32 == 0x12345678); + _assert (gid.ippref.addr.version == IP4); + + u8 rloc_count = MREQ_ITR_RLOC_COUNT(h) + 1; + lisp_msg_parse_itr_rlocs (b, &rlocs, rloc_count); + + _assert (vec_len (rlocs) == 2); + _assert (rlocs[0].ippref.addr.ip.v4.as_u32 == 0x10203040); + _assert (rlocs[0].ippref.addr.version == IP4); + + _assert (rlocs[1].ippref.addr.ip.v6.as_u32[0] == 0xffeeddcc); + _assert (rlocs[1].ippref.addr.ip.v6.as_u32[1] == 0xbbaa9988); + _assert (rlocs[1].ippref.addr.ip.v6.as_u32[2] == 0x77665544); + _assert (rlocs[1].ippref.addr.ip.v6.as_u32[3] == 0x33221100); + _assert (rlocs[1].ippref.addr.version == IP6); + + lisp_msg_parse_eid_rec (b, &eid); + _assert (eid.ippref.addr.ip.v4.as_u32 == 0x9abcdef0); + _assert (eid.ippref.addr.version == IP4); + _assert (eid.ippref.len == 24); + +done: + clib_mem_free (data); + if (rlocs) + vec_free (rlocs); + return error; +} + +static clib_error_t * test_lisp_msg_put_mreq_with_lcaf () +{ + lisp_cp_main_t * lcm = vnet_lisp_cp_get_main (); + clib_error_t * error = 0; + map_request_hdr_t *h = 0; + gid_address_t * rlocs = 0; + + ip_prefix_t ippref; + ip_prefix_version (&ippref) = IP4; + ip4_address_t * ip = &ip_prefix_v4 (&ippref); + ip->as_u32 = 0x11223344; + + gid_address_t g = + { + .type = GID_ADDR_IP_PREFIX, + .ippref = ippref, + .vni = 0x90919293, + .vni_mask = 0x17 + }; + vec_add1 (rlocs, g); + + u8 * data = clib_mem_alloc (500); + memset (data, 0, 500); + + h = build_map_request (lcm, (vlib_buffer_t *) data, rlocs); + + /* clear Nonce to simplify comparison */ + memset ((u8 *)h + 4, 0, 8); + + u8 expected_data[] = + { + 0x10, 0x40, 0x00, 0x01, /* type; flags; IRC; REC count */ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* nonce */ + 0x00, 0x01, /* Source-EID-AFI */ + 0x78, 0x56, 0x34, 0x12, /* Source EID Address */ + + /* RLOCs */ + 0x40, 0x03, /* AFI = LCAF*/ + /* LCAF header*/ + 0x00, 0x00, /* reserved1, flags */ + 0x02, /* type = Instance ID */ + 0x17, /* IID mask-len */ + 0x00, 0x0a, /* lenght */ + 0x90, 0x91, 0x92, 0x93, /* IID / VNI */ + + 0x00, 0x01, /* AFI = ipv4 */ + 0x44, 0x33, 0x22, 0x11, /* ITR-RLOC Address 1 */ + + /* record */ + 0x00, /* reserved */ + 0x18, /* EID mask-len */ + 0x00, 0x01, /* EID-prefix-AFI */ + 0xf0, 0xde, 0xbc, 0x9a, /* EID-prefix */ + }; + + _assert (0 == memcmp (expected_data, (u8 *) h, sizeof (expected_data))); +done: + clib_mem_free (data); + return error; +} + +static clib_error_t * test_lisp_msg_put_mreq () +{ + lisp_cp_main_t * lcm = vnet_lisp_cp_get_main(); + clib_error_t * error = 0; + map_request_hdr_t *h; + gid_address_t * rlocs = 0; + u32 rloc_count = 0; + + u8 * data = clib_mem_alloc(500); + memset(data, 0, 500); + + generate_rlocs (&rlocs, &rloc_count); + h = build_map_request (lcm, (vlib_buffer_t *) data, rlocs); + + /* clear Nonce to simplify comparison */ + memset((u8 *)h + 4, 0, 8); + + print_map_request(h); + + u8 expected_data[50] = { + 0x10, 0x40, 0x01, 0x01, /* type; flags; IRC; REC count */ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* nonce */ + 0x00, 0x01, /* Source-EID-AFI */ + 0x78, 0x56, 0x34, 0x12, /* Source EID Address */ + + /* RLOCs */ + 0x00, 0x01, /* ITR-RLOC-AFI 1 */ + 0x40, 0x30, 0x20, 0x10, /* ITR-RLOC Address 1 */ + 0x00, 0x02, /* ITR-RLOC-AFI 2 */ + 0xcc, 0xdd, 0xee, 0xff, + 0x88, 0x99, 0xaa, 0xbb, + 0x44, 0x55, 0x66, 0x77, + 0x00, 0x11, 0x22, 0x33, /* ITR-RLOC Address 2 */ + + /* record */ + 0x00, /* reserved */ + 0x18, /* EID mask-len */ + 0x00, 0x01, /* EID-prefix-AFI */ + 0xf0, 0xde, 0xbc, 0x9a, /* EID-prefix */ + }; + _assert (0 == memcmp (expected_data, (u8 *) h, sizeof (expected_data))); + +done: + clib_mem_free (data); + return error; +} + +/* generate a vector of eid records */ +static mapping_t * +build_test_map_records () +{ + mapping_t * records = 0; + + mapping_t r = { + .ttl = 0x44332211, + .eid = { + .type = GID_ADDR_MAC, + .mac = {1, 2, 3, 4, 5, 6}, + .vni = 0x0 + } + }; + + locator_t loc = { + .weight = 1, + .priority = 2, + .local = 1, + .address = { + .type = GID_ADDR_IP_PREFIX, + .ippref = { + .addr = { + .ip.v4.as_u32 = 0x99887766, + .version = IP4 + } + } + } + }; + vec_add1 (r.locators, loc); + vec_add1 (records, r); + + return records; +} + +static void +free_test_map_records (mapping_t * maps) +{ + mapping_t * map; + vec_foreach (map, maps) + { + vec_free (map->locators); + } + vec_free (maps); +} + +static clib_error_t * +test_lisp_map_register () +{ + vlib_buffer_t *b; + clib_error_t * error = 0; + u64 nonce; + u32 msg_len = 0; + mapping_t * records = build_test_map_records (); + + u8 * data = clib_mem_alloc(500); + memset(data, 0, 500); + b = (vlib_buffer_t *) data; + + lisp_msg_put_map_register (b, records, 1 /* want map notify */, + 20 /* length of HMAC_SHA_1_96 */, + &nonce, &msg_len); + free_test_map_records (records); + + /* clear Nonce to simplify comparison */ + memset((u8 *)b->data + 4, 0, 8); + + /* clear authentication data */ + memset ((u8 *)b->data + 16, 0, 20); + + u8 expected_data[] = { + 0x30, 0x00, 0x01, 0x01, /* type; rsvd; want notify; REC count */ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* nonce */ + 0x00, 0x00, 0x00, 0x00, /* key id, auth data length: + both are zeroes because those are set in another + function (see auth_data_len_by_key_id())*/ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* auth data */ + + /* first record */ + 0x44, 0x33, 0x22, 0x11, /* ttl */ + 0x01, 0x00, 0x00, 0x00, /* loc count, eid len, ACT, A */ + 0x00, 0x00, 0x40, 0x05, /* rsvd, map ver num, AFI = MAC */ + 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, /* MAC EID */ + + /* locator 1 */ + 0x02, 0x01, 0x00, 0x00, /* prio, weight, mprio, mweight */ + 0x00, 0x04, 0x00, 0x01, /* flags, AFI = ipv4 */ + 0x66, 0x77, 0x88, 0x99, /* ipv4 locator address */ + }; + _assert (0 == memcmp (expected_data, b->data, sizeof (expected_data))); +done: + clib_mem_free (data); + return error; +} + +static clib_error_t * +test_lisp_parse_lcaf () +{ + int i; + clib_error_t * error = 0; + gid_address_t eid; + locator_t * locs = 0; + locator_t probed; + vlib_buffer_t * b = 0; + u32 buff_len = 500; + + b = clib_mem_alloc (buff_len); + memset ((u8 *)b, 0, buff_len); + + u8 map_reply_records[] = + { + /* 1. record */ + 0x01, 0x02, 0x03, 0x04, /* record TTL */ + 0x03, /* locator count */ + 0x00, 0x00, 0x00, /* eid-mask-len; ... */ + 0x00, 0x00, /* reserved; map-version num */ + 0x00, 0x01, /* EID-Prefix-AFI */ + 0x33, 0x44, 0x55, 0x66, /* eid-prefix */ + + /* 1st locator */ + 0x0a, /* prority */ + 0x0b, /* weight */ + 0x0c, /* m-prority */ + 0x0d, /* m-weight */ + 0x00, 0x00, /* unused flags */ + 0x40, 0x03, /* Loc-AFI = LCAF*/ + + /* LCAF header*/ + 0x00, 0x00, /* reserved1, flags */ + 0x02, /* type = Instance ID */ + 0x18, /* IID mask-len */ + 0x00, 0x0a, /* lenght */ + /* LCAF Instance ID */ + 0x00, 0x00, 0x00, 0x09, /* iid */ + 0x00, 0x01, /* AFI = ipv4 */ + 0x10, 0xbb, 0xcc, 0xdd, /* ipv4 loator address */ + + /* 2nd locator */ + 0x07, /* prority */ + 0x06, /* weight */ + 0x05, /* m-prority */ + 0x04, /* m-weight */ + 0x00, 0x00, /* unused flags */ + 0x40, 0x03, /* Loc-AFI = LCAF*/ + + /* LCAF header*/ + 0x00, 0x00, /* reserved1, flags */ + 0x02, /* type = Instance ID */ + 0x18, /* IID mask-len */ + 0x00, 0x16, /* iid length + next AFI lenght */ + /* LCAF Instance ID */ + 0x22, 0x44, 0x66, 0x88, /* iid */ + 0x00, 0x02, /* AFI = ipv6 */ + 0xcc, 0xdd, 0xee, 0xff, + 0x88, 0x99, 0xaa, 0xbb, + 0x44, 0x55, 0x66, 0x77, + 0x00, 0x11, 0x22, 0x33, /* ipv6 locator address */ + + /* 3rd locator */ + 0x0a, /* prority */ + 0x0b, /* weight */ + 0x0c, /* m-prority */ + 0x0d, /* m-weight */ + 0x00, 0x00, /* unused flags */ + 0x00, 0x01, /* Loc-AFI */ + 0xaa, 0xbb, 0xcc, 0xdd, /* Loator */ + }; + + b->current_length = buff_len; + memcpy (b->data, map_reply_records, sizeof (map_reply_records)); + + lisp_msg_parse_mapping_record (b, &eid, &locs, &probed); + _assert (vec_len (locs) == 3); + _assert (eid.ippref.addr.ip.v4.as_u32 == 0x66554433); + + /* check 1st locator - an LCAF with ipv4 */ + _assert (locs[0].local == 0); + _assert (locs[0].priority == 0xa); + _assert (locs[0].weight == 0xb); + _assert (locs[0].mpriority == 0xc); + _assert (locs[0].mweight == 0xd); + + _assert (gid_address_type (&locs[0].address) == GID_ADDR_IP_PREFIX); + _assert (gid_address_vni (&locs[0].address) == 0x09); + ip_prefix_t * ip_pref = &gid_address_ippref (&locs[0].address); + _assert (IP4 == ip_prefix_version (ip_pref)); + + /* 2nd locator - LCAF entry with ipv6 address */ + _assert (locs[1].local == 0); + _assert (locs[1].priority == 0x7); + _assert (locs[1].weight == 0x6); + _assert (locs[1].mpriority == 0x5); + _assert (locs[1].mweight == 0x4); + + _assert (gid_address_type (&locs[1].address) == GID_ADDR_IP_PREFIX); + _assert (0x22446688 == gid_address_vni (&locs[1].address)); + ip_pref = &gid_address_ippref (&locs[1].address); + _assert (IP6 == ip_prefix_version (ip_pref)); + + /* 3rd locator - simple ipv4 address */ + _assert (gid_address_type (&locs[2].address) == GID_ADDR_IP_PREFIX); +done: + clib_mem_free (b); + + for (i = 0; i < 3; i++) + locator_free (&locs[i]); + vec_free (locs); + return error; +} + +#define foreach_test_case \ + _(lisp_msg_put_mreq) \ + _(lisp_msg_put_mreq_with_lcaf) \ + _(lisp_msg_push_ecm) \ + _(lisp_msg_parse) \ + _(lisp_msg_parse_mapping_record) \ + _(lisp_parse_lcaf) \ + _(lisp_map_register) + +int run_tests (void) +{ + clib_error_t * error; + +#define _(_test_name) \ + error = test_ ## _test_name (); \ + if (error) \ + { \ + clib_error_report (error); \ + return 0; \ + } + + foreach_test_case +#undef _ + + return 0; +} + +int main() +{ + return run_tests (); +} +#undef _assert diff --git a/src/tests/vnet/lisp-cp/test_lisp_types.c b/src/tests/vnet/lisp-cp/test_lisp_types.c new file mode 100644 index 00000000..5d910f66 --- /dev/null +++ b/src/tests/vnet/lisp-cp/test_lisp_types.c @@ -0,0 +1,565 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 + +/* FIXME */ +#include +vpe_api_main_t vpe_api_main; + +#define _assert(e) \ + error = CLIB_ERROR_ASSERT (e); \ + if (error) \ + goto done; + +static clib_error_t * test_locator_type (void) +{ + clib_error_t * error = 0; + gid_address_t _gid_addr, * gid = &_gid_addr; + ip_prefix_t * ippref; + gid_address_type (gid) = GID_ADDR_IP_PREFIX; + gid_address_ippref_len (gid) = 24; + ippref = &gid_address_ippref (gid); + ip_prefix_version (ippref) = IP4; + ip_prefix_len (ippref) = 0; + ip4_address_t * ip4 = &ip_prefix_v4 (ippref); + ip4->as_u32 = 0x20304050; + + /* local locator */ + locator_t loc1, loc2 = { + .local = 1, + .state = 2, + .sw_if_index = 8, + .priority = 3, + .weight = 100, + .mpriority = 4, + .mweight = 101 + }; + locator_copy (&loc1, &loc2); + _assert (0 == locator_cmp (&loc1, &loc2)); + + /* remote locator */ + loc2.local = 0; + + ip_prefix_t nested_ippref; + ip_prefix_version (&nested_ippref) = IP4; + ip_prefix_len (&nested_ippref) = 0; + ip4 = &ip_prefix_v4 (&nested_ippref); + ip4->as_u32 = 0x33882299; + gid_address_t nested_gid = + { + .type = GID_ADDR_IP_PREFIX, + .ippref = nested_ippref + }; + + lcaf_t lcaf = + { + .type = LCAF_INSTANCE_ID, + .uni = + { + .vni_mask_len = 5, + .vni = 0xa1b2c3d4, + .gid_addr = &nested_gid + } + }; + gid_address_type (gid) = GID_ADDR_LCAF; + gid_address_lcaf (gid) = lcaf; + + loc2.address = gid[0]; + locator_copy(&loc1, &loc2); + + _assert (0 == locator_cmp (&loc1, &loc2)); + +done: + locator_free (&loc1); + return error; +} + +static clib_error_t * test_gid_parse_ip_pref () +{ + clib_error_t * error = 0; + gid_address_t _gid_addr, * gid_addr = &_gid_addr; + gid_address_t _gid_addr_copy, * gid_addr_copy = &_gid_addr_copy; + u8 data[] = + { + 0x00, 0x01, /* AFI = IPv4 */ + 0x10, 0xbb, 0xcc, 0xdd, /* ipv4 address */ + }; + + u32 len = gid_address_parse (data, gid_addr); + _assert (6 == len); + gid_address_copy (gid_addr_copy, gid_addr); + _assert (0 == gid_address_cmp (gid_addr_copy, gid_addr)); +done: + return error; +} + +static clib_error_t * test_gid_parse_mac () +{ + clib_error_t * error = 0; + gid_address_t _gid, * gid = &_gid; + gid_address_t _gid_copy, * gid_copy = &_gid_copy; + + u8 data[] = + { + 0x40, 0x05, /* AFI = MAC address */ + 0x10, 0xbb, 0xcc, 0xdd, /* MAC */ + 0x77, 0x99, + }; + + u32 len = gid_address_parse (data, gid); + _assert (8 == len); + _assert (GID_ADDR_MAC == gid_address_type (gid)); + gid_address_copy (gid_copy, gid); + _assert (0 == gid_address_cmp (gid_copy, gid)); +done: + return error; +} + +static clib_error_t * test_gid_parse_lcaf () +{ + clib_error_t * error = 0; + gid_address_t _gid_addr, * gid_addr = &_gid_addr; + gid_address_t _gid_addr_copy, * gid_addr_copy = &_gid_addr_copy; + + memset (gid_addr, 0, sizeof (gid_addr[0])); + memset (gid_addr_copy, 0, sizeof (gid_addr_copy[0])); + + u8 data[] = + { + 0x40, 0x03, /* AFI = LCAF*/ + + /* LCAF header*/ + 0x00, 0x00, /* reserved1, flags */ + 0x02, /* type = Instance ID */ + 0x18, /* IID mask-len */ + 0x00, 0x0a, /* iid length + next AFI lenght */ + /* LCAF Instance ID */ + 0x00, 0x00, 0x00, 0x09, /* iid */ + 0x00, 0x01, /* AFI = ipv4 */ + 0x10, 0xbb, 0xcc, 0xdd, /* ipv4 address */ + }; + u32 len = gid_address_parse (data, gid_addr); + _assert (18 == len); + gid_address_copy (gid_addr_copy, gid_addr); + _assert (0 == gid_address_cmp (gid_addr_copy, gid_addr)); + _assert (GID_ADDR_IP_PREFIX == gid_address_type (gid_addr)); + _assert (9 == gid_address_vni (gid_addr)); + _assert (0x18 == gid_address_vni_mask (gid_addr)); + _assert (0xddccbb10 == gid_addr->ippref.addr.ip.v4.as_u32); + +done: + gid_address_free (gid_addr); + gid_address_free (gid_addr_copy); + return error; +} + +/* recursive LCAFs are not supported */ +#if 0 +static clib_error_t * test_gid_parse_lcaf_complex () +{ + clib_error_t * error = 0; + gid_address_t _gid_addr, * gid_addr = &_gid_addr; + gid_address_t _gid_addr_copy, * gid_addr_copy = &_gid_addr_copy; + + memset (gid_addr, 0, sizeof (gid_addr[0])); + memset (gid_addr_copy, 0, sizeof (gid_addr_copy[0])); + + u8 data[] = + { + 0x40, 0x03, /* AFI = LCAF*/ + + /* LCAF header*/ + 0x00, 0x00, /* reserved1, flags */ + 0x02, /* type = Instance ID */ + 0x18, /* IID mask-len */ + 0x00, 0x0a, /* iid length + next AFI lenght */ + /* LCAF Instance ID */ + 0x00, 0x00, 0x00, 0x0b, /* iid */ + + 0x40, 0x03, /* AFI = LCAF*/ + /* LCAF header*/ + 0x00, 0x00, /* reserved1, flags */ + 0x02, /* type = Instance ID */ + 0x17, /* IID mask-len */ + 0x00, 0x0a, /* iid length + next AFI lenght */ + /* LCAF Instance ID */ + 0x00, 0x00, 0x00, 0x0c, /* iid */ + + 0x40, 0x03, /* AFI = LCAF*/ + /* LCAF header*/ + 0x00, 0x00, /* reserved1, flags */ + 0x02, /* type = Instance ID */ + 0x16, /* IID mask-len */ + 0x00, 0x16, /* iid length + next AFI lenght */ + /* LCAF Instance ID */ + 0x00, 0x00, 0x00, 0x0d, /* iid */ + + 0x00, 0x02, /* AFI = IPv6 */ + + 0x10, 0xbb, 0xcc, 0xdd, + 0x10, 0xbb, 0xcc, 0xdd, + 0x10, 0xbb, 0xcc, 0xdd, + 0x10, 0xbb, 0xcc, 0xdd, /* ipv6 address */ + }; + u32 len = gid_address_parse (data, gid_addr); + _assert (54 == len); + _assert (gid_addr->type == GID_ADDR_LCAF); + gid_address_copy (gid_addr_copy, gid_addr); + _assert (0 == gid_address_cmp (gid_addr_copy, gid_addr)); + _assert (gid_addr_copy->type == GID_ADDR_LCAF); + + lcaf_t * lcaf = &gid_address_lcaf (gid_addr_copy); + _assert (lcaf->type == LCAF_INSTANCE_ID); + vni_t * v = (vni_t *) lcaf; + _assert (v->vni == 0x0b); + _assert (v->vni_mask_len == 0x18); + + gid_address_t * tmp = vni_gid (v); + _assert (gid_address_type (tmp) == GID_ADDR_LCAF); + lcaf = &gid_address_lcaf (tmp); + _assert (lcaf->type == LCAF_INSTANCE_ID); + + v = (vni_t *) lcaf; + _assert (v->vni == 0x0c); + _assert (v->vni_mask_len == 0x17); + + tmp = vni_gid (v); + _assert (gid_address_type (tmp) == GID_ADDR_LCAF); + lcaf = &gid_address_lcaf (tmp); + + _assert (lcaf->type == LCAF_INSTANCE_ID); + v = (vni_t *) lcaf; + _assert (v->vni == 0x0d); + _assert (v->vni_mask_len == 0x16); + + tmp = vni_gid (v); + _assert (gid_address_type (tmp) == GID_ADDR_IP_PREFIX); + + ip_prefix_t * ip_pref = &gid_address_ippref (tmp); + ip6_address_t * ip6 = &ip_prefix_v6 (ip_pref); + _assert (ip6->as_u32[0] == 0xddccbb10); + _assert (ip6->as_u32[1] == 0xddccbb10); + _assert (ip6->as_u32[2] == 0xddccbb10); + _assert (ip6->as_u32[3] == 0xddccbb10); + _assert (ip_prefix_version (ip_pref) == IP6); + +done: + gid_address_free (gid_addr); + gid_address_free (gid_addr_copy); + return error; +} +#endif + +#if 0 /* uncomment this once VNI is supported */ +static clib_error_t * test_write_mac_in_lcaf (void) +{ + clib_error_t * error = 0; + + u8 * b = clib_mem_alloc(500); + memset(b, 0, 500); + + gid_address_t g = + { + .mac = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6}, + .vni = 0x30, + .vni_mask = 0x10, + .type = GID_ADDR_MAC, + }; + + u16 len = gid_address_put (b, &g); + _assert (8 == len); + + u8 expected[] = + { + 0x40, 0x03, /* AFI = LCAF */ + 0x00, /* reserved1 */ + 0x00, /* flags */ + 0x02, /* LCAF type = Instance ID */ + 0x20, /* IID/VNI mask len */ + 0x00, 0x0a, /* length */ + 0x01, 0x02, 0x03, 0x04, /* Instance ID / VNI */ + + 0x00, 0x06, /* AFI = MAC */ + 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06 /* MAC */ + } + _assert (0 == memcmp (expected, b, len)); +done: + clib_mem_free (b); + return error; +} +#endif + +static clib_error_t * test_mac_address_write (void) +{ + clib_error_t * error = 0; + + u8 * b = clib_mem_alloc(500); + memset(b, 0, 500); + + gid_address_t g = + { + .mac = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6}, + .type = GID_ADDR_MAC, + }; + + u16 len = gid_address_put (b, &g); + _assert (8 == len); + + u8 expected[] = + { + 0x40, 0x05, /* AFI = MAC */ + 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06 /* MAC */ + }; + _assert (0 == memcmp (expected, b, len)); +done: + clib_mem_free (b); + return error; +} + +static clib_error_t * +test_src_dst_with_vni_serdes (void) +{ + clib_error_t * error = 0; + u8 * b = clib_mem_alloc (500); + memset (b, 0, 500); + + fid_address_t src = + { + .type = FID_ADDR_IP_PREF, + .ippref = + { + .len = 24, + .addr = + { + .version = IP4, + .ip.v4.data = { 0x1, 0x2, 0x3, 0x0 } + } + } + }; + + fid_address_t dst = + { + .type = FID_ADDR_IP_PREF, + .ippref = + { + .len = 16, + .addr = + { + .version = IP4, + .ip.v4.data = { 0x9, 0x8, 0x0, 0x0 } + } + } + }; + + source_dest_t sd = + { + .src = src, + .dst = dst + }; + + gid_address_t g = + { + .sd = sd, + .type = GID_ADDR_SRC_DST, + .vni = 0x12345678, + .vni_mask = 0x9 + }; + + u16 size_to_put = gid_address_size_to_put(&g); + _assert (36 == size_to_put); + _assert (0 == gid_address_len(&g)); + + u16 write_len = gid_address_put (b, &g); + printf("sizetoput %d; writelen %d\n", size_to_put, write_len); + _assert (size_to_put == write_len); + + u8 expected_data[] = + { + 0x40, 0x03, 0x00, 0x00, /* AFI = LCAF, reserved1, flags */ + 0x02, 0x09, 0x00, 0x1c, /* LCAF type = IID, IID mask-len, length */ + 0x12, 0x34, 0x56, 0x78, /* reserved; source-ML, Dest-ML */ + + 0x40, 0x03, 0x00, 0x00, /* AFI = LCAF, reserved1, flags */ + 0x0c, 0x00, 0x00, 0x10, /* LCAF type = source/dest key, rsvd, length */ + 0x00, 0x00, 0x18, 0x10, /* reserved; source-ML, Dest-ML */ + + 0x00, 0x01, /* AFI = ip4 */ + 0x01, 0x02, 0x03, 0x00, /* source */ + + 0x00, 0x01, /* AFI = ip4 */ + 0x09, 0x08, 0x00, 0x00, /* destination */ + }; + _assert (0 == memcmp (expected_data, b, sizeof (expected_data))); + + gid_address_t p; + memset (&p, 0, sizeof (p)); + _assert (write_len == gid_address_parse (b, &p)); + _assert (0 == gid_address_cmp (&g, &p)); +done: + clib_mem_free (b); + return error; +} + +static clib_error_t * +test_src_dst_serdes (void) +{ + clib_error_t * error = 0; + + u8 * b = clib_mem_alloc (500); + memset (b, 0, 500); + + fid_address_t src = + { + .type = FID_ADDR_MAC, + .mac = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 } + }; + + fid_address_t dst = + { + .type = FID_ADDR_MAC, + .mac = { 0x10, 0x21, 0x32, 0x43, 0x54, 0x65 } + }; + + source_dest_t sd = + { + .src = src, + .dst = dst + }; + + gid_address_t g = + { + .sd = sd, + .type = GID_ADDR_SRC_DST, + .vni = 0x0, + .vni_mask = 0x0 + }; + + u16 size_to_put = gid_address_size_to_put(&g); + _assert (28 == size_to_put); + _assert (0 == gid_address_len(&g)); + + u16 write_len = gid_address_put (b, &g); + _assert (size_to_put == write_len); + + u8 expected_data[] = + { + 0x40, 0x03, 0x00, 0x00, /* AFI = LCAF, reserved1, flags */ + 0x0c, 0x00, 0x00, 0x14, /* LCAF type = source/dest key, rsvd, length */ + 0x00, 0x00, 0x00, 0x00, /* reserved; source-ML, Dest-ML */ + + 0x40, 0x05, /* AFI = MAC */ + 0x11, 0x22, 0x33, 0x44, + 0x55, 0x66, /* source */ + + 0x40, 0x05, /* AFI = MAC */ + 0x10, 0x21, 0x32, 0x43, + 0x54, 0x65, /* destination */ + }; + _assert (0 == memcmp (expected_data, b, sizeof (expected_data))); + + gid_address_t p; + memset (&p, 0, sizeof (p)); + _assert (write_len == gid_address_parse (b, &p)); + _assert (0 == gid_address_cmp (&g, &p)); +done: + clib_mem_free (b); + return error; +} + +static clib_error_t * test_gid_address_write (void) +{ + clib_error_t * error = 0; + ip_prefix_t ippref_data, * ippref = &ippref_data; + + u8 * b = clib_mem_alloc(500); + memset(b, 0, 500); + + ip_prefix_version (ippref) = IP4; + ip_prefix_len (ippref) = 9; + ip4_address_t * ip4 = &ip_prefix_v4 (ippref); + ip4->as_u32 = 0xaabbccdd; + + gid_address_t g = + { + .ippref = ippref[0], + .type = GID_ADDR_IP_PREFIX, + .vni = 0x01020304, + .vni_mask = 0x18 + }; + + _assert (18 == gid_address_size_to_put (&g)); + _assert (gid_address_len (&g) == 9); + + u16 write_len = gid_address_put (b, &g); + _assert (18 == write_len); + + u8 expected_gid_data[] = + { + 0x40, 0x03, /* AFI = LCAF */ + 0x00, /* reserved1 */ + 0x00, /* flags */ + 0x02, /* LCAF type = Instance ID */ + 0x18, /* IID/VNI mask len */ + 0x00, 0x0a, /* length */ + 0x01, 0x02, 0x03, 0x04, /* Instance ID / VNI */ + + 0x00, 0x01, /* AFI = IPv4 */ + 0xdd, 0xcc, 0xbb, 0xaa, /* ipv4 addr */ + }; + _assert (0 == memcmp (expected_gid_data, b, sizeof (expected_gid_data))); +done: + clib_mem_free (b); + return error; +} + +#define foreach_test_case \ + _(locator_type) \ + _(gid_parse_ip_pref) \ + _(gid_parse_mac) \ + _(gid_parse_lcaf) \ + _(mac_address_write) \ + _(gid_address_write) \ + _(src_dst_serdes) \ + _(src_dst_with_vni_serdes) + +int run_tests (void) +{ + clib_error_t * error; + +#define _(_test_name) \ + error = test_ ## _test_name (); \ + if (error) \ + { \ + clib_error_report (error); \ + return 0; \ + } + + foreach_test_case +#undef _ + + return 0; +} + +int main() +{ + return run_tests (); +} + diff --git a/src/tests/vnet/lisp-gpe/test.c b/src/tests/vnet/lisp-gpe/test.c new file mode 100644 index 00000000..dde633ae --- /dev/null +++ b/src/tests/vnet/lisp-gpe/test.c @@ -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. + */ + +int main(int argc, char **argv) { + return 0; +} diff --git a/src/tools/elftool/dir.dox b/src/tools/elftool/dir.dox new file mode 100644 index 00000000..40426e04 --- /dev/null +++ b/src/tools/elftool/dir.dox @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Copyright (c) 2016 Comcast Cable Communications Management, LLC. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** @dir + * @brief VPP instrastructure tools. + */ diff --git a/src/tools/elftool/elftool.c b/src/tools/elftool/elftool.c new file mode 100644 index 00000000..d9d3704b --- /dev/null +++ b/src/tools/elftool/elftool.c @@ -0,0 +1,464 @@ +/* + * 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. + */ +/* + Copyright (c) 2008 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. +*/ + +#include + +#include +#include +#include + +#ifndef CLIB_UNIX +#error "unix only" +#endif + +typedef struct { + elf_main_t elf_main; + char * input_file; + char * output_file; + char * set_interpreter; + char * set_rpath; + int unset_rpath; + int verbose; + int quiet; + int allow_elf_shared; + /* for use in the optimized / simplified case */ + u64 file_size; + u64 interpreter_offset; + u64 rpath_offset; +} elf_tool_main_t; + +static clib_error_t * elf_set_interpreter (elf_main_t * em, + elf_tool_main_t * tm) +{ + elf_segment_t * g; + elf_section_t * s; + clib_error_t * error; + char * interp = tm->set_interpreter; + + switch (em->first_header.file_type) + { + case ELF_EXEC: + break; + + case ELF_SHARED: + if (tm->allow_elf_shared) + break; + /* Note flowthrough */ + default: + return clib_error_return (0, "unacceptable file_type"); + } + + vec_foreach (g, em->segments) + { + if (g->header.type == ELF_SEGMENT_INTERP) + break; + } + + if (g >= vec_end (em->segments)) + return clib_error_return (0, "interpreter not found"); + + if (g->header.memory_size < 1 + strlen (interp)) + return clib_error_return (0, "given interpreter does not fit; must be less than %d bytes (`%s' given)", + g->header.memory_size, interp); + + error = elf_get_section_by_start_address (em, g->header.virtual_address, &s); + if (error) + return error; + + /* Put in new null terminated string. */ + memset (s->contents, 0, vec_len (s->contents)); + clib_memcpy (s->contents, interp, strlen (interp)); + + return 0; +} + +static void +delete_rpath_for_section (elf_main_t * em, elf_section_t * s) +{ + elf64_dynamic_entry_t * e; + elf64_dynamic_entry_t * new_es = 0; + + vec_foreach (e, em->dynamic_entries) + { + switch (e->type) + { + case ELF_DYNAMIC_ENTRY_RPATH: + case ELF_DYNAMIC_ENTRY_RUN_PATH: + break; + + default: + vec_add1 (new_es, e[0]); + break; + } + } + + /* Pad so as to keep section size constant. */ + { + elf64_dynamic_entry_t e_end; + e_end.type = ELF_DYNAMIC_ENTRY_END; + e_end.data = 0; + while (vec_len (new_es) < vec_len (em->dynamic_entries)) + vec_add1 (new_es, e_end); + } + + vec_free (em->dynamic_entries); + em->dynamic_entries = new_es; + + elf_set_dynamic_entries (em); +} + +static void delete_rpath (elf_main_t * em) +{ + elf_section_t * s; + + vec_foreach (s, em->sections) + { + switch (s->header.type) + { + case ELF_SECTION_DYNAMIC: + delete_rpath_for_section (em, s); + break; + + default: + break; + } + } +} + +static clib_error_t * +set_rpath_for_section (elf_main_t * em, elf_section_t * s, char * new_rpath) +{ + elf64_dynamic_entry_t * e; + char * old_rpath; + int old_len, new_len = strlen (new_rpath); + u8 * new_string_table = vec_dup (em->dynamic_string_table); + + vec_foreach (e, em->dynamic_entries) + { + switch (e->type) + { + case ELF_DYNAMIC_ENTRY_RPATH: + case ELF_DYNAMIC_ENTRY_RUN_PATH: + old_rpath = (char *) new_string_table + e->data; + old_len = strlen (old_rpath); + if (old_len < new_len) + return clib_error_return (0, "rpath of `%s' does not fit (old rpath `%s')", + new_rpath, old_rpath); + strcpy (old_rpath, new_rpath); + break; + + default: + break; + } + } + + elf_set_section_contents (em, em->dynamic_string_table_section_index, + new_string_table, + vec_bytes (new_string_table)); + + return 0; +} + +static clib_error_t * +set_rpath (elf_main_t * em, char * rpath) +{ + clib_error_t * error = 0; + elf_section_t * s; + + vec_foreach (s, em->sections) + { + switch (s->header.type) + { + case ELF_SECTION_DYNAMIC: + error = set_rpath_for_section (em, s, rpath); + if (error) + return error; + break; + + default: + break; + } + } + + return error; +} + +static clib_error_t * +set_interpreter_rpath (elf_tool_main_t * tm) +{ + int ifd = -1, ofd = -1; + struct stat fd_stat; + u8 *idp = 0; /* warning be gone */ + u64 mmap_length = 0, i; + u32 run_length; + u8 in_run; + u64 offset0 = 0, offset1 = 0; + clib_error_t * error = 0; + int fix_in_place = 0; + + if (!strcmp (tm->input_file, tm->output_file)) + fix_in_place = 1; + + ifd = open (tm->input_file, O_RDWR); + if (ifd < 0) + { + error = clib_error_return_unix (0, "open `%s'", tm->input_file); + goto done; + } + + if (fstat (ifd, &fd_stat) < 0) + { + error = clib_error_return_unix (0, "fstat `%s'", tm->input_file); + goto done; + } + + if (!(fd_stat.st_mode & S_IFREG)) + { + error = clib_error_return (0, "%s is not a regular file", tm->input_file); + goto done; + } + + mmap_length = fd_stat.st_size; + if (mmap_length < 4) + { + error = clib_error_return (0, "%s too short", tm->input_file); + goto done; + } + + /* COW-mapping, since we intend to write the fixups */ + if (fix_in_place) + idp = mmap (0, mmap_length, PROT_READ | PROT_WRITE, MAP_SHARED, + ifd, /* offset */ 0); + else + idp = mmap (0, mmap_length, PROT_READ | PROT_WRITE, MAP_PRIVATE, + ifd, /* offset */ 0); + if (~pointer_to_uword (idp) == 0) + { + mmap_length = 0; + error = clib_error_return_unix (0, "mmap `%s'", tm->input_file); + goto done; + } + + if (idp[0] != 0x7f || idp[1] != 'E' || idp[2] != 'L' || idp[3] != 'F') + { + error = clib_error_return (0, "not an ELF file '%s'", tm->input_file); + goto done; + } + + in_run = 0; + run_length = 0; + + for (i = 0; i < mmap_length; i++) + { + if (idp[i] == '/') + { + if (in_run) + run_length++; + else + { + in_run = 1; + run_length = 1; + } + } + else + { + if (in_run && run_length >= 16) + { + if (offset0 == 0) + offset0 = (i - run_length); + else if (offset1 == 0) + { + offset1 = (i - run_length); + goto found_both; + } + } + in_run = 0; + run_length = 0; + } + } + + if (offset0 == 0) + { + error = clib_error_return (0, "no fixup markers in %s", + tm->input_file); + goto done; + } + + found_both: + if (0) + clib_warning ("offset0 %lld (0x%llx), offset1 %lld (0x%llx)", + offset0, offset0, offset1, offset1); + + /* Executable file case */ + if (offset0 && offset1) + { + tm->interpreter_offset = offset0; + tm->rpath_offset = offset1; + } + else /* shared library case */ + { + tm->interpreter_offset = 0; + tm->rpath_offset = offset0; + } + + if (tm->interpreter_offset) + clib_memcpy (&idp[tm->interpreter_offset], tm->set_interpreter, + strlen (tm->set_interpreter)+1); + + if (tm->rpath_offset) + clib_memcpy (&idp[tm->rpath_offset], tm->set_rpath, + strlen (tm->set_rpath)+1); + + /* Write the output file... */ + if (fix_in_place == 0) + { + ofd = open (tm->output_file, O_RDWR | O_CREAT | O_TRUNC, 0644); + if (ofd < 0) + { + error = clib_error_return_unix (0, "create `%s'", tm->output_file); + goto done; + } + + if (write (ofd, idp, mmap_length) != mmap_length) + error = clib_error_return_unix (0, "write `%s'", tm->output_file); + } + + done: + if (mmap_length > 0 && idp) + munmap (idp, mmap_length); + if (ifd >= 0) + close (ifd); + if (ofd >= 0) + close (ofd); + return error; +} + + +int main (int argc, char * argv[]) +{ + elf_tool_main_t _tm, * tm = &_tm; + elf_main_t * em = &tm->elf_main; + unformat_input_t i; + clib_error_t * error = 0; + + memset (tm, 0, sizeof (tm[0])); + unformat_init_command_line (&i, argv); + + while (unformat_check_input (&i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (&i, "in %s", &tm->input_file)) + ; + else if (unformat (&i, "out %s", &tm->output_file)) + ; + else if (unformat (&i, "set-interpreter %s", &tm->set_interpreter)) + ; + else if (unformat (&i, "set-rpath %s", &tm->set_rpath)) + ; + else if (unformat (&i, "unset-rpath")) + tm->unset_rpath = 1; + else if (unformat (&i, "verbose")) + tm->verbose = ~0; + else if (unformat (&i, "verbose-symbols")) + tm->verbose |= FORMAT_ELF_MAIN_SYMBOLS; + else if (unformat (&i, "verbose-relocations")) + tm->verbose |= FORMAT_ELF_MAIN_RELOCATIONS; + else if (unformat (&i, "verbose-dynamic")) + tm->verbose |= FORMAT_ELF_MAIN_DYNAMIC; + else if (unformat (&i, "quiet")) + tm->quiet = 1; + else if (unformat (&i, "allow-elf-shared")) + tm->allow_elf_shared = 1; + else + { + error = unformat_parse_error (&i); + goto done; + } + } + + if (! tm->input_file) + { + error = clib_error_return (0, "no input file"); + goto done; + } + + /* Do the typical case a stone-simple way... */ + if (tm->quiet && tm->set_interpreter && tm->set_rpath && tm->output_file) + { + error = set_interpreter_rpath (tm); + goto done; + } + + error = elf_read_file (em, tm->input_file); + + if (error) + goto done; + + if (tm->verbose) + fformat (stdout, "%U", format_elf_main, em, tm->verbose); + + if (tm->set_interpreter) + { + error = elf_set_interpreter (em, tm); + if (error) + goto done; + } + + if (tm->set_rpath) + { + error = set_rpath (em, tm->set_rpath); + if (error) + goto done; + } + + if (tm->unset_rpath) + delete_rpath (em); + + if (tm->output_file) + error = elf_write_file (em, tm->output_file); + + elf_main_free (em); + + done: + if (error) + { + if (tm->quiet == 0) + clib_error_report (error); + return 1; + } + else + return 0; +} diff --git a/src/tools/g2/clib.c b/src/tools/g2/clib.c new file mode 100644 index 00000000..6454c84d --- /dev/null +++ b/src/tools/g2/clib.c @@ -0,0 +1,154 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2009-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 +#include +#include "cpel.h" +#include "g2.h" + +int widest_track_format; + +typedef struct bound_track_ { + u32 track; + u8 *track_str; +} bound_track_t; + +bound_track_t *bound_tracks; + +uword *the_evtdef_hash; /* (event-id, event-definition) hash */ +uword *the_trackdef_hash; /* (track-id, track-definition) hash */ + +elog_main_t elog_main; + +void *get_clib_event (unsigned int datum) +{ + elog_event_t *ep = vec_elt_at_index (elog_main.events, datum); + return (void *)ep; +} + +/* + * read_clib_file + */ +int read_clib_file(char *clib_file) +{ + static FILE *ofp; + clib_error_t *error = 0; + int i; + elog_main_t *em = &elog_main; + double starttime, delta; + + vec_free(em->events); + vec_free(em->event_types); + if (the_trackdef_hash) + hash_free(the_trackdef_hash); + + the_trackdef_hash = hash_create (0, sizeof (uword)); + + error = elog_read_file (&elog_main, clib_file); + + if (error) { + fformat(stderr, "%U", format_clib_error, error); + return (1); + } + + if (ofp == NULL) { + ofp = fdopen(2, "w"); + if (ofp == NULL) { + fprintf(stderr, "Couldn't fdopen(2)?\n"); + exit(1); + } + } + + em = &elog_main; + + for (i = 0; i < vec_len (em->tracks); i++) { + u32 track_code; + bound_track_t * btp; + elog_track_t * t; + uword * p; + int track_strlen; + + t = &em->tracks[i]; + track_code = i; + p = hash_get(the_trackdef_hash, track_code); + if (p) { + fprintf(ofp, "track %d redefined, retain first definition\n", + track_code); + continue; + } + vec_add2(bound_tracks, btp, 1); + btp->track = track_code; + btp->track_str = (u8 *) t->name; + hash_set(the_trackdef_hash, track_code, btp - bound_tracks); + + track_strlen = strlen((char *)btp->track_str); + if (track_strlen > widest_track_format) + widest_track_format = track_strlen; + } + + initialize_events(); + + for (i = 0; i < vec_len (em->event_types); i++) { + elog_event_type_t *ep; + u8 *tmp; + + ep = vec_elt_at_index(em->event_types, i); + tmp = (u8 *) vec_dup(ep->format); + vec_add1(tmp,0); + add_event_from_clib_file (ep->type_index_plus_one, (char *) tmp, i); + vec_free(tmp); + } + + finalize_events(); + + em->events = elog_get_events (em); + + cpel_event_init(vec_len(em->events)); + + starttime = em->events[0].time; + + for (i = 0; i < vec_len (em->events); i++) { + elog_event_t *ep; + + ep = vec_elt_at_index(em->events, i); + + delta = ep->time - starttime; + + add_clib_event (delta, ep->track, ep->type + 1, i); + } + + cpel_event_finalize(); + + set_pid_ax_width(8*widest_track_format); + + return(0); +} diff --git a/src/tools/g2/configure.ac b/src/tools/g2/configure.ac new file mode 100644 index 00000000..c8af7747 --- /dev/null +++ b/src/tools/g2/configure.ac @@ -0,0 +1,12 @@ +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/g2/cpel.c b/src/tools/g2/cpel.c new file mode 100644 index 00000000..8bcc91e6 --- /dev/null +++ b/src/tools/g2/cpel.c @@ -0,0 +1,470 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2005-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 +#include "cpel.h" +#include "g2.h" + +typedef struct bound_event_ { + u32 event_code; + u8 *event_str; + u8 *datum_str; +} bound_event_t; + +bound_event_t *bound_events; + +int widest_track_format=8; + +typedef struct bound_track_ { + u32 track; + u8 *track_str; +} bound_track_t; + +bound_track_t *bound_tracks; + +uword *the_strtab_hash; /* (name, base-VA) hash of all string tables */ +uword *the_evtdef_hash; /* (event-id, event-definition) hash */ +uword *the_trackdef_hash; /* (track-id, track-definition) hash */ +u8 *event_strtab; /* event string-table */ + +void fatal(char *s) +{ + fprintf(stderr, "%s", s); + exit(1); +} + +typedef enum { + PASS1=1, + PASS2=2, +} pass_t; + +typedef struct { + int (*pass1)(cpel_section_header_t *, int, FILE *); + int (*pass2)(cpel_section_header_t *, int, FILE *); +} section_processor_t; + +int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + fprintf(ofp, "Bad (type 0) section, skipped...\n"); + return(0); +} + +int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + return(0); +} + +int strtab_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + uword *p; + u8 *strtab_data_area = (u8 *)(sh+1); + + /* Multiple string tables with the same name are Bad... */ + p = hash_get_mem(the_strtab_hash, strtab_data_area); + if (p) { + fprintf(ofp, "Duplicate string table name %s", strtab_data_area); + } + /* + * Looks funny, but we really do want key = first string in the + * table, value = address(first string in the table) + */ + hash_set_mem(the_strtab_hash, strtab_data_area, strtab_data_area); + if (verbose) { + fprintf(ofp, "String Table %s\n", strtab_data_area); + } + return(0); +} + +int evtdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + int i, nevents; + event_definition_section_header_t *edh; + event_definition_t *ep; + u8 *this_strtab; + u32 event_code; + uword *p; + bound_event_t *bp; + + edh = (event_definition_section_header_t *)(sh+1); + nevents = ntohl(edh->number_of_event_definitions); + + if (verbose) { + fprintf(ofp, "Event Definition Section: %d definitions\n", + nevents); + } + + p = hash_get_mem(the_strtab_hash, edh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + this_strtab = (u8 *)p[0]; + + initialize_events(); + + ep = (event_definition_t *)(edh+1); + + for (i = 0; i < nevents; i++) { + event_code = ntohl(ep->event); + p = hash_get(the_evtdef_hash, event_code); + if (p) { + fprintf(ofp, "Event %d redefined, retain first definition\n", + event_code); + continue; + } + vec_add2(bound_events, bp, 1); + bp->event_code = event_code; + bp->event_str = this_strtab + ntohl(ep->event_format); + bp->datum_str = this_strtab + ntohl(ep->datum_format); + hash_set(the_evtdef_hash, event_code, bp - bound_events); + + add_event_from_cpel_file(event_code, (char *) bp->event_str, + (char *)bp->datum_str); + + ep++; + } + + finalize_events(); + return (0); +} + +int trackdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + int i, nevents; + track_definition_section_header_t *tdh; + track_definition_t *tp; + u8 *this_strtab; + u32 track_code; + uword *p; + bound_track_t *btp; + int track_strlen; + + tdh = (track_definition_section_header_t *)(sh+1); + nevents = ntohl(tdh->number_of_track_definitions); + + if (verbose) { + fprintf(ofp, "Track Definition Section: %d definitions\n", + nevents); + } + + p = hash_get_mem(the_strtab_hash, tdh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + this_strtab = (u8 *)p[0]; + + tp = (track_definition_t *)(tdh+1); + + for (i = 0; i < nevents; i++) { + track_code = ntohl(tp->track); + p = hash_get(the_trackdef_hash, track_code); + if (p) { + fprintf(ofp, "track %d redefined, retain first definition\n", + track_code); + continue; + } + vec_add2(bound_tracks, btp, 1); + btp->track = track_code; + btp->track_str = this_strtab + ntohl(tp->track_format); + hash_set(the_trackdef_hash, track_code, btp - bound_tracks); + + track_strlen = strlen((char *)btp->track_str); + if (track_strlen > widest_track_format) + widest_track_format = track_strlen; + tp++; + } + return (0); +} + +int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + if (verbose) { + fprintf(ofp, "Unsupported type %d section\n", + ntohl(sh->section_type)); + } + return(0); +} + +int event_pass2(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + event_section_header_t *eh; + u32 event_code, track_code, datum; + u64 starttime = ~0ULL; + int nevents; + int i; + event_entry_t *ep; + u64 now; + u64 delta; + u32 time0, time1; + double d; + uword *p; + + eh = (event_section_header_t *)(sh+1); + nevents = ntohl(eh->number_of_events); + ticks_per_ns = ntohl(eh->clock_ticks_per_second)/1e9; + ep = (event_entry_t *)(eh+1); + + p = hash_get_mem(the_strtab_hash, eh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + event_strtab = (u8 *)p[0]; + + cpel_event_init(nevents); + + for (i = 0; i < nevents; i++) { + time0 = ntohl (ep->time[0]); + time1 = ntohl (ep->time[1]); + + now = (((u64) time0)<<32) | time1; + + /* Convert from bus ticks to usec */ + d = now; + d /= ticks_per_ns; + + now = d; + + if (starttime == ~0ULL) + starttime = now; + + delta = now - starttime; + + /* Delta = time since first event, in usec */ + event_code = ntohl(ep->event_code); + track_code = ntohl(ep->track); + datum = ntohl(ep->event_datum); + + add_cpel_event(delta, track_code, event_code, datum); + + ep++; + } + cpel_event_finalize(); + return(0); +} + +char *strtab_ref(unsigned long datum) +{ + return ((char *)(event_strtab + datum)); +} + +/* + * Note: If necessary, add passes / columns to this table to + * handle section order dependencies. + */ + +section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] = +{ + {bad_section, noop_pass}, /* type 0 -- f**ked */ + {strtab_pass1, noop_pass}, /* type 1 -- STRTAB */ + {unsupported_pass, noop_pass}, /* type 2 -- SYMTAB */ + {evtdef_pass1, noop_pass}, /* type 3 -- EVTDEF */ + {trackdef_pass1, noop_pass}, /* type 4 -- TRACKDEF */ + {noop_pass, event_pass2}, /* type 5 -- EVENTS */ +}; + + +int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp, + pass_t pass) +{ + u32 type; + type = ntohl(sh->section_type); + int rv; + int (*fp)(cpel_section_header_t *, int, FILE *); + + if (type > CPEL_NUM_SECTION_TYPES) { + fprintf(stderr, "Unknown section type %d\n", type); + return(1); + } + switch(pass) { + case PASS1: + fp = processors[type].pass1; + break; + + case PASS2: + fp = processors[type].pass2; + break; + + default: + fprintf(stderr, "Unknown pass %d\n", pass); + return(1); + } + + rv = (*fp)(sh, verbose, ofp); + + return(rv); +} + +int cpel_dump_file_header(cpel_file_header_t *fh, int verbose, FILE *ofp) +{ + time_t file_time; + + if (verbose) { + fprintf(ofp, "CPEL file: %s-endian, version %d\n", + ((fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) ? + "little" : "big"), + fh->endian_version & CPEL_FILE_VERSION_MASK); + + file_time = ntohl(fh->file_date); + + fprintf(ofp, "File created %s", ctime(&file_time)); + } + + return(0); +} + + +int cpel_process(u8 *cpel, int verbose, FILE *ofp) +{ + cpel_file_header_t *fh; + cpel_section_header_t *sh; + u16 nsections; + u32 section_size; + int i; + + /* First, the file header */ + fh = (cpel_file_header_t *)cpel; + if (fh->endian_version != CPEL_FILE_VERSION) { + if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) { + fprintf(stderr, "Little endian data format not supported\n"); + return(1); + } + fprintf(stderr, "Unsupported file version 0x%x\n", + fh->endian_version); + return(1); + } + cpel_dump_file_header(fh, verbose, ofp); + nsections = ntohs(fh->nsections); + + /* + * Take two passes through the file. PASS1 builds + * data structures, PASS2 actually dumps the file. + * Just in case the sections are in an unobvious order. + */ + sh = (cpel_section_header_t *)(fh+1); + for (i = 0; i < nsections; i++) { + section_size = ntohl(sh->data_length); + + if(verbose) { + fprintf(ofp, "Section type %d, size %d\n", ntohl(sh->section_type), + section_size); + } + + if(process_section(sh, verbose, ofp, PASS1)) + return(1); + + sh++; + sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); + } + + sh = (cpel_section_header_t *)(fh+1); + for (i = 0; i < nsections; i++) { + if(process_section(sh, verbose, ofp, PASS2)) + return(1); + section_size = ntohl(sh->data_length); + sh++; + sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); + } + + + return(0); +} + +/* + * read_cpel_file + */ +int read_cpel_file(char *cpel_file) +{ + int verbose = 0; + int rv; + static u8 *cpel; + static unsigned long size; + static FILE *ofp; + + if (cpel) { + unmapfile((char *)cpel, size); + hash_free(the_strtab_hash); + the_strtab_hash = 0; + hash_free(the_evtdef_hash); + the_evtdef_hash = 0; + hash_free(the_trackdef_hash); + the_trackdef_hash = 0; + } + + cpel = (u8 *)mapfile((char *)cpel_file, &size); + if (cpel == 0) { + fprintf(stderr, "Couldn't map %s...\n", cpel_file); + exit(1); + } + + if (ofp == NULL) { + ofp = fdopen(2, "w"); + if (ofp == NULL) { + fprintf(stderr, "Couldn't fdopen(2)?\n"); + exit(1); + } + } + + the_strtab_hash = hash_create_string (0, sizeof (uword)); + the_evtdef_hash = hash_create (0, sizeof (uword)); + the_trackdef_hash = hash_create (0, sizeof (uword)); + + rv = cpel_process(cpel, verbose, ofp); + + set_pid_ax_width(8*widest_track_format); + + return(rv); +} + +static bound_track_t generic_hex_track = {0, (u8 *) "0x%08x"}; +static bound_track_t generic_decimal_track = {0, (u8 *) "%8ld"}; + +/* + * get_track_label + */ +char *get_track_label(unsigned long track) +{ + uword *p; + bound_track_t *tp; + + p = hash_get(the_trackdef_hash, track); + if (p) { + tp = &bound_tracks[p[0]]; + } else { + if (track > 65535) + tp = &generic_hex_track; + else + tp = &generic_decimal_track; + } + return((char *)tp->track_str); +} diff --git a/src/tools/g2/cpel.h b/src/tools/g2/cpel.h new file mode 100644 index 00000000..73e4aea5 --- /dev/null +++ b/src/tools/g2/cpel.h @@ -0,0 +1,83 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2005-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 _CPEL_H_ +#define _CPEL_H_ 1 + +typedef struct cpel_file_header_ { + unsigned char endian_version; + unsigned char pad; + unsigned short nsections; + unsigned file_date; +} cpel_file_header_t; + +#define CPEL_FILE_LITTLE_ENDIAN 0x80 +#define CPEL_FILE_VERSION 0x01 +#define CPEL_FILE_VERSION_MASK 0x7F + +typedef struct cpel_section_header_ { + unsigned int section_type; + unsigned int data_length; /* does NOT include type and itself */ +} cpel_section_header_t; + +#define CPEL_SECTION_STRTAB 1 +/* string at offset 0 is the name of the table */ + +#define CPEL_SECTION_SYMTAB 2 +#define CPEL_SECTION_EVTDEF 3 + +typedef struct event_definition_section_header_ { + char string_table_name[64]; + unsigned int number_of_event_definitions; +} event_definition_section_header_t; + +typedef struct event_definition_ { + unsigned int event; + unsigned int event_format; + unsigned int datum_format; +} event_definition_t; + +#define CPEL_SECTION_TRACKDEF 4 + +typedef struct track_definition_section_header_ { + char string_table_name[64]; + unsigned int number_of_track_definitions; +} track_definition_section_header_t; + +typedef struct track_definition_ { + unsigned int track; + unsigned int track_format; +} track_definition_t; + +#define CPEL_SECTION_EVENT 5 + +typedef struct event_section_header_ { + char string_table_name[64]; + unsigned int number_of_events; + unsigned int clock_ticks_per_second; +} event_section_header_t; + +typedef struct event_entry_ { + unsigned int time[2]; + unsigned int track; + unsigned int event_code; + unsigned int event_datum; +} event_entry_t; + +#define CPEL_NUM_SECTION_TYPES 5 + +#endif /* _CPEL_H_ */ + diff --git a/src/tools/g2/events.c b/src/tools/g2/events.c new file mode 100644 index 00000000..d4333bb0 --- /dev/null +++ b/src/tools/g2/events.c @@ -0,0 +1,475 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2005-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 "g2.h" +#include +#include +#include +#include + +/* + * globals + */ +boolean g_little_endian; +event_t *g_events; +ulong g_nevents; +pid_sort_t *g_pids; +pid_sort_t *g_original_pids; +int g_npids; +pid_data_t *g_pid_data_list; + +/* + * locals + */ +pid_data_t **s_pidhash; + +/* + * config parameters + */ + +double ticks_per_ns=1000.0; +boolean ticks_per_ns_set; + +/**************************************************************************** +* event_init +****************************************************************************/ + +void event_init(void) +{ + ulong endian; + char *ep; + char *askstr; + int tmp; + + ep = (char *)&endian; + endian = 0x12345678; + if (*ep != 0x12) + g_little_endian = TRUE; + else + g_little_endian = FALSE; + + askstr = getprop("dont_ask_ticks_per_ns_initially"); + + if (askstr && (*askstr == 't' || *askstr == 'T')) { + tmp = atol(getprop_default("ticks_per_ns", 0)); + if (tmp > 0) { + ticks_per_ns = tmp; + ticks_per_ns_set = TRUE; + } + } +} + +/**************************************************************************** +* find_or_add_pid +****************************************************************************/ + +pid_data_t *find_or_add_pid (ulong pid) +{ + pid_data_t *pp; + ulong bucket; + + bucket = pid % PIDHASH_NBUCKETS; + + pp = s_pidhash[bucket]; + + if (pp == 0) { + pp = g_malloc0(sizeof(pid_data_t)); + pp->pid_value = pid; + s_pidhash[bucket] = pp; + g_npids++; + return(pp); + } + while (pp) { + if (pp->pid_value == pid) + return(pp); + pp = pp->next; + } + + pp = g_malloc0(sizeof(pid_data_t)); + pp->pid_value = pid; + pp->next = s_pidhash[bucket]; + s_pidhash[bucket] = pp; + g_npids++; + return(pp); +} + +/**************************************************************************** +* pid_cmp +****************************************************************************/ + +int pid_cmp(const void *a1, const void *a2) +{ + pid_sort_t *p1 = (pid_sort_t *)a1; + pid_sort_t *p2 = (pid_sort_t *)a2; + + if (p1->pid_value < p2->pid_value) + return(-1); + else if (p1->pid_value == p2->pid_value) + return(0); + else + return(1); +} + +/**************************************************************************** +* make_sorted_pid_vector +****************************************************************************/ + +static void make_sorted_pid_vector(void) +{ + pid_data_t *pp; + pid_data_t **p_previous; + pid_sort_t *psp; + int i; + + psp = g_pids = g_malloc(sizeof(pid_sort_t)*g_npids); + + for (i = 0; i < PIDHASH_NBUCKETS; i++) { + pp = s_pidhash[i]; + while(pp) { + psp->pid = pp; + psp->pid_value = pp->pid_value; + psp++; + pp = pp->next; + } + } + + qsort(&g_pids[0], g_npids, sizeof(pid_sort_t), pid_cmp); + + /* put the sort order into the pid objects */ + psp = g_pids; + + /* + * This is rather gross. + * + * We happen to know that whenever this function is called, the hash table + * structure itself is immediately torn down. So the "next" pointers in the + * pid_data_t elements are about to become useless. + * + * So we re-use them, to link all the pid_data_t elements together into a + * single unified linked list, with g_pid_data_list pointing to the head. + * This means we can walk all the pid_data_t objects if we really want to. + * Reading snapshots from disk is one example. + * + * Alternatively we could just leave the hash table in place; this is + * far nicer, but as it happens, trading O(n) lookups for O(1) lookups + * isn't actually a problem for the restricted post-tear-down usage. So for + * now we take the memory savings and swap our hash table for a list. + */ + p_previous = &g_pid_data_list; + for (i = 0; i < g_npids; i++) { + pp = psp->pid; + pp->pid_index = i; + *p_previous = pp; + p_previous = &pp->next; + psp++; + } + *p_previous = NULL; + + /* + * Squirrel away original (sorted) vector, so we can + * toggle between "chase" mode, snapshots, and the original + * display method on short notice + */ + g_original_pids = g_malloc(sizeof(pid_sort_t)*g_npids); + memcpy (g_original_pids, g_pids, sizeof(pid_sort_t)*g_npids); +} + +/**************************************************************************** +* read_events +****************************************************************************/ + +void read_events(char *filename) +{ + ulong *ulp; + ulong size; + event_t *ep; + raw_event_t *rep; + ulonglong start_time=0ULL; + ulonglong low_time; + boolean once=TRUE; + int i; + char tmpbuf [128]; + + ulp = (ulong *)mapfile(filename, &size); + + if (ulp == NULL) { + sprintf(tmpbuf, "Couldn't open %s\n", filename); + infobox("Read Event Log Failure", tmpbuf); + return; + } + + g_nevents = ntohl(*ulp); + + if (size != (g_nevents*sizeof(raw_event_t) + sizeof(g_nevents))) { + sprintf(tmpbuf, "%s was damaged, or isn't an event log.\n", filename); + infobox("Bad Input File", tmpbuf); + g_nevents = 0; + unmapfile((char *)ulp, size); + return; + } + + rep = (raw_event_t *)(ulp+1); + + if (g_events) + g_free(g_events); + + g_events = (event_t *)g_malloc(g_nevents * sizeof(event_t)); + ep = g_events; + + while (g_npids > 0) { + g_free((g_pids + g_npids-1)->pid); + g_npids--; + } + if (g_pids) { + g_free(g_pids); + g_free(g_original_pids); + g_pids = 0; + g_original_pids = 0; + } + + s_pidhash = (pid_data_t **)g_malloc0( + PIDHASH_NBUCKETS*sizeof(pid_data_t *)); + + /* $$$ add a SEGV handler... */ + for (i = 0; i < g_nevents; i++) { + if (once) { + once = FALSE; + start_time = ((ulonglong)ntohl(rep->time[0])); + start_time <<= 32; + low_time = ntohl(rep->time[1]); + low_time &= 0xFFFFFFFF; + start_time |= low_time; + ep->time = 0LL; + } else { + ep->time = ((ulonglong)ntohl(rep->time[0])); + ep->time <<= 32; + low_time = ntohl(rep->time[1]); + low_time &= 0xFFFFFFFF; + ep->time |= low_time; + ep->time -= start_time; + ep->time /= ticks_per_ns; + } + ep->code = ntohl(rep->code); + ep->pid = find_or_add_pid(ntohl(rep->pid)); + ep->datum = ntohl(rep->datum); + ep->flags = 0; + ep++; + rep++; + } + + unmapfile((char *)ulp, size); + + make_sorted_pid_vector(); + g_free(s_pidhash); + s_pidhash = 0; + + /* Give the view-1 world a chance to reset a few things... */ + view1_read_events_callback(); +} + +static event_t *add_ep; + +/**************************************************************************** +* cpel_event_init +****************************************************************************/ +void cpel_event_init (ulong nevents) +{ + g_nevents = nevents; + if (g_events) + g_free(g_events); + add_ep = g_events = (event_t *)g_malloc(g_nevents * sizeof(event_t)); + while (g_npids > 0) { + g_free((g_pids + g_npids-1)->pid); + g_npids--; + } + if (g_pids) { + g_free(g_pids); + g_free(g_original_pids); + g_pids = 0; + g_original_pids = 0; + } + s_pidhash = (pid_data_t **)g_malloc0( + PIDHASH_NBUCKETS*sizeof(pid_data_t *)); +} + +/**************************************************************************** +* add_cpel_event +****************************************************************************/ + +void add_cpel_event(ulonglong delta, ulong track, ulong event, ulong datum) +{ + event_t *ep; + + ep = add_ep++; + ep->time = delta; + ep->pid = find_or_add_pid(track); + ep->code = event; + ep->datum = datum; + ep->flags = 0; +} + +/**************************************************************************** +* add_clib_event +****************************************************************************/ + +void add_clib_event(double delta, unsigned short track, + unsigned short event, unsigned int index) +{ + event_t *ep; + + ep = add_ep++; + ep->time = (ulonglong) (delta * 1e9); /* time in intger nanoseconds */ + ep->pid = find_or_add_pid(track); + ep->code = event; + ep->datum = index; + ep->flags = EVENT_FLAG_CLIB; +} + +/**************************************************************************** +* cpel_event_finalize +****************************************************************************/ + +void cpel_event_finalize(void) +{ + make_sorted_pid_vector(); + g_free(s_pidhash); + s_pidhash = 0; + + /* Give the view-1 world a chance to reset a few things... */ + view1_read_events_callback(); +} + +/**************************************************************************** +* mapfile +****************************************************************************/ + +char *mapfile (char *file, ulong *sizep) +{ + struct stat statb; + char *rv; + int maphfile; + size_t mapfsize; + + maphfile = open (file, O_RDONLY); + + if (maphfile < 0) + return (NULL); + + if (fstat (maphfile, &statb) < 0) { + return (NULL); + } + + /* Don't try to mmap directories, FIFOs, semaphores, etc. */ + if (! (statb.st_mode & S_IFREG)) { + return (NULL); + } + + mapfsize = statb.st_size; + + if (mapfsize < 3) { + close (maphfile); + return (NULL); + } + + rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0); + + if (rv == 0) { + g_error ("%s mapping problem, I quit...\n", file); + } + + close (maphfile); + + if (madvise (rv, mapfsize, MADV_SEQUENTIAL) < 0) { + return (rv); + } + + if (sizep) { + *sizep = mapfsize; + } + return (rv); +} + +/**************************************************************************** +* unmapfile +****************************************************************************/ + +boolean unmapfile (char *addr, ulong size) +{ + if (munmap (addr, size) < 0) { + g_warning("Unmap error, addr 0x%lx size 0x%x\n", + (unsigned long) addr, (unsigned int)size); + return(FALSE); + } + return(TRUE); +} + +/**************************************************************************** +* find_event_index +* Binary search for first event whose time is >= t +****************************************************************************/ + +int find_event_index (ulonglong t) +{ + int index, bottom, top; + event_t *ep; + + bottom = g_nevents-1; + top = 0; + + while (1) { + index = (bottom + top) / 2; + + ep = (g_events + index); + + if (ep->time == t) + return(index); + + if (top >= bottom) { + while (index > 0 && ep->time > t) { + ep--; + index--; + } + while (index < g_nevents && ep->time < t) { + ep++; + index++; + } + return(index); + } + + if (ep->time < t) + top = index + 1; + else + bottom = index - 1; + } +} + +/**************************************************************************** +* events_about +****************************************************************************/ + +void events_about (char *tmpbuf) +{ + sprintf(tmpbuf+strlen(tmpbuf), "%d total events, %.3f ticks per us\n", + (int)g_nevents, ticks_per_ns); +} diff --git a/src/tools/g2/g2.h b/src/tools/g2/g2.h new file mode 100644 index 00000000..1ab42191 --- /dev/null +++ b/src/tools/g2/g2.h @@ -0,0 +1,195 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2005-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * typedefs and so forth + */ +#include +#include +#include +#include "props.h" + +typedef char boolean; +typedef unsigned long long ulonglong; + +/* + * main.c + */ + +GtkWidget *g_mainwindow; +GtkWidget *g_mainvbox; +GtkWidget *g_mainhbox; + +/* + * pointsel.c + */ +void point_selector_init(void); +boolean read_event_definitions (char *filename); +char *sxerox(char *); +void pointsel_about(char *); +void pointsel_next_snapshot(void); +void initialize_events(void); +void finalize_events(void); + +#define NEVENTS 100000 + +typedef struct event_def_ { + ulong event; + char *name; + char *format; + boolean selected; + boolean is_clib; + char pad[2]; +} event_def_t; + +event_def_t *find_event_definition (ulong code); + +event_def_t g_eventdefs[NEVENTS]; + +/* + * config params + */ +int c_maxpointsel; /* max # points shown in selector dlg */ +gint c_view1_draw_width; +gint c_view1_draw_height; + +/* + * menu1.c + */ + +void menu1_init(void); +void modal_dialog (char *label_text, char *retry_text, char *default_value, + boolean (*cb)(char *)); +void infobox(char *label_text, char *text); +/* + * view1.c + */ +GdkFont *g_font; +GdkColor fg_black, bg_white; +void view1_init(void); +void view1_display(void); +void view1_read_events_callback(void); +void view1_display_when_idle(void); +void view1_print_callback(GtkToggleButton *item, gpointer data); +void view1_about(char *); +void set_pid_ax_width(int width); +void set_window_title(const char *filename); + +enum view1_tbox_fn { + TBOX_DRAW_BOXED = 1, /* note: order counts */ + TBOX_DRAW_EVENT, + TBOX_DRAW_PLAIN, + TBOX_PRINT_BOXED, + TBOX_PRINT_EVENT, + TBOX_PRINT_PLAIN, /* end restriction */ + TBOX_GETRECT_BOXED, + TBOX_GETRECT_EVENT, + TBOX_GETRECT_PLAIN, +}; + +enum view1_line_fn { + LINE_DRAW_BLACK = 1, + LINE_DRAW_WHITE, + LINE_PRINT, +}; + +GdkRectangle *tbox (char *s, int x, int y, enum view1_tbox_fn function); +void line (int x1, int y1, int x2, int y2, enum view1_line_fn function); +gint view1_handle_key_press_event (GtkWidget *widget, GdkEventKey *event); + +/* + * events.c + */ + +void events_about (char *); + +typedef struct raw_event { + unsigned long time[2]; + unsigned long pid; + unsigned long code; + unsigned long datum; +} raw_event_t; + +void event_init(void); +char *mapfile (char *file, ulong *sizep); +boolean unmapfile (char *addr, ulong size); +void read_events (char *); +int find_event_index (ulonglong t); +int read_cpel_file(char *file); +int read_clib_file(char *file); +void cpel_event_init(ulong); +void add_event_from_cpel_file(ulong, char * , char *); +void add_event_from_clib_file(unsigned int event, char *name, + unsigned int vec_index); +void add_cpel_event(ulonglong delta, ulong, ulong, ulong); +void add_clib_event(double delta, unsigned short track, + unsigned short event, unsigned int index); +void cpel_event_finalize(void); +void *get_clib_event (unsigned int datum); + +typedef struct pid_data { + struct pid_data *next; + ulong pid_value; /* The actual pid value */ + ulong pid_index; /* Index in pid sort order */ +} pid_data_t; + +#define EVENT_FLAG_SELECT 0x00000001 /* This event is selected */ +#define EVENT_FLAG_SEARCHRSLT 0x00000002 /* This event is the search rslt */ +#define EVENT_FLAG_CLIB 0x00000004 /* clib event */ + +typedef struct pid_sort { + struct pid_data *pid; + ulong pid_value; + /* + * This is a bit of a hack, since this is used only by the view: + */ + unsigned color_index; +} pid_sort_t; + +typedef struct event { + ulonglong time; + ulong code; + pid_data_t *pid; + ulong datum; + ulong flags; +} event_t; + + +boolean g_little_endian; +event_t *g_events; +ulong g_nevents; +pid_sort_t *g_pids; +pid_sort_t *g_original_pids; +int g_npids; +pid_data_t *g_pid_data_list; + +#define PIDHASH_NBUCKETS 20021 /* Should be prime */ + +boolean ticks_per_ns_set; +double ticks_per_ns; + +/* + * version.c + */ +const char *version_string; +const char *minor_v_string; + +/* + * cpel.c + */ +char *get_track_label(unsigned long); +int widest_track_format; +char *strtab_ref(unsigned long); diff --git a/src/tools/g2/g2version.c b/src/tools/g2/g2version.c new file mode 100644 index 00000000..4b6f9313 --- /dev/null +++ b/src/tools/g2/g2version.c @@ -0,0 +1,19 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2005-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const char *version_string = "G2 (x86_64 GNU/Linux) major version 3.0"; +const char *minor_v_string = + "Built Wed Feb 3 10:58:12 EST 2016"; diff --git a/src/tools/g2/main.c b/src/tools/g2/main.c new file mode 100644 index 00000000..a782e17f --- /dev/null +++ b/src/tools/g2/main.c @@ -0,0 +1,196 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2005-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 "g2.h" +#include "props.h" +#include +#include +#include +#include +#include + +/* + * globals + */ + +GtkWidget *g_mainwindow; /* The main window */ + +/* Graphical object heirarchy + * + * [main window] + * [main vbox] + * [main (e.g. file) menubar] + * [view hbox] + * [view bottom menu] + */ + +GtkWidget *g_mainvbox; +GtkWidget *g_mainhbox; + +gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) +{ + /* Allow window to be destroyed */ + return(FALSE); +} + +void destroy(GtkWidget *widget, gpointer data) +{ + gtk_main_quit(); +} + +int main (int argc, char **argv) +{ + char tmpbuf [128]; + struct passwd *pw; + char *event_file = 0; + char *cpel_file = 0; + char *clib_file =0; + char *title = "none"; + int curarg=1; + char *homedir; + + gtk_init(&argc, &argv); + + homedir = getenv ("HOME"); + tmpbuf[0] = 0; + + if (homedir) { + sprintf(tmpbuf, "%s/.g2", homedir); + } else { + pw = getpwuid(geteuid()); + if (pw) { + sprintf(tmpbuf, "%s/.g2", pw->pw_dir); + } + } + if (tmpbuf[0]) + readprops(tmpbuf); + + g_mainwindow = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT(g_mainwindow), "delete_event", + GTK_SIGNAL_FUNC (delete_event), NULL); + + gtk_signal_connect (GTK_OBJECT(g_mainwindow), "destroy", + GTK_SIGNAL_FUNC (destroy), NULL); + + gtk_container_set_border_width(GTK_CONTAINER(g_mainwindow), 5); + + g_mainvbox = gtk_vbox_new(FALSE, 0); + g_mainhbox = gtk_hbox_new(FALSE, 0); + + /* + * init routines + */ + + menu1_init(); + point_selector_init(); + view1_init(); + event_init(); + + /* + * Now that we're ready to rock 'n roll, see if we've been asked to + * press a few buttons... + */ + + while (curarg < argc) { + if (!strncmp(argv[curarg], "--cpel-input", 4)) { + curarg++; + if (curarg < argc) { + cpel_file = argv[curarg]; + curarg++; + break; + } + g_error("Missing filename after --cpel-input"); + } + if (!strncmp(argv[curarg], "--clib-input", 4)) { + curarg++; + if (curarg < argc) { + clib_file = argv[curarg]; + curarg++; + break; + } + g_error("Missing filename after --cpel-input"); + } + + if (!strncmp(argv[curarg], "--pointdefs", 3)) { + curarg++; + if (curarg < argc) { + read_event_definitions(argv[curarg]); + curarg++; + continue; + } + g_error ("Missing filename after --pointdefs\n"); + } + if (!strncmp(argv[curarg], "--event-log", 3)) { + curarg++; + if (curarg < argc) { + event_file = argv[curarg]; + curarg++; + continue; + } + g_error ("Missing filename after --event-log\n"); + } + + if (!strncmp(argv[curarg], "--ticks-per-us", 3)) { + curarg++; + if (curarg < argc) { + ticks_per_ns = 0.0; + ticks_per_ns = atof(argv[curarg]); + if (ticks_per_ns == 0.0) { + g_error("ticks-per-ns (%s) didn't convert properly\n", + argv[curarg]); + } + ticks_per_ns_set = TRUE; + curarg++; + continue; + } + g_error ("Missing filename after --event-log\n"); + } + + fprintf(stderr, + "g2 [--pointdefs ] [--event-log ]\n"); + fprintf(stderr, " [--ticks-per-us ]\n"); + fprintf(stderr, + " [--cpel-input ] [--clib-input \n"); + fprintf(stderr, + "%s\n%s\n", version_string, minor_v_string); + exit(0); + } + + if (clib_file) { + read_clib_file (clib_file); + title = clib_file; + } else if (cpel_file) { + read_cpel_file(cpel_file); + title = cpel_file; + } else if (event_file) { + read_events(event_file); + title = event_file; + } + + set_window_title(title); + + gtk_signal_connect (GTK_OBJECT (g_mainwindow), "key_press_event", + (GtkSignalFunc) view1_handle_key_press_event, NULL); + gtk_container_add(GTK_CONTAINER(g_mainvbox), g_mainhbox); + gtk_widget_show(g_mainhbox); + gtk_container_add(GTK_CONTAINER(g_mainwindow), g_mainvbox); + gtk_widget_show(g_mainvbox); + gtk_widget_show(g_mainwindow); + + gtk_main(); + return(0); +} diff --git a/src/tools/g2/menu1.c b/src/tools/g2/menu1.c new file mode 100644 index 00000000..fce81fa6 --- /dev/null +++ b/src/tools/g2/menu1.c @@ -0,0 +1,565 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2006-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 GTK_ENABLE_BROKEN // DGMS +#include +#include +#include "g2.h" +#include + +/* + * locals + */ +static GtkWidget *s_mainmenubar; +static GtkWidget *s_filemenu; +static GtkWidget *s_readdefs; +static GtkWidget *s_readevents; +static GtkWidget *s_readeventsclock; +static GtkWidget *s_readcpel; +static GtkWidget *s_readclib; +static GtkWidget *s_print; +static GtkWidget *s_quit; + +static GtkWidget *s_mainfilemenu; +static GtkWidget *s_help_general; +static GtkWidget *s_help_about; +static GtkWidget *s_mainhelpmenu; +static GtkWidget *s_helpmenu; + +static GtkWidget *s_filesel; +static GtkWidget *s_eventsel; + +typedef struct md_ { + GtkWidget *entry; + GtkWidget *label; + GtkWidget *dialog; + boolean (*callback)(char *); + char *retry_text; +} md_t; + +char *general_help = "\n" +"G2 is a performance event visualization tool.\n" +"\n" +"To view CPEL-format event data:\n" +"g2 --cpel \n" +"or use the File Menu->Read CPEL file option.\n" +"\n" +"To view vppinfra-format (.../open-repo/vppinfra/vppinfra/elog.h) event data:\n" +"g2 --clib \n" +"or use the File Menu->Read clib file option.\n" +"\n" +"To toggle event detail boxes, left-mouse-click on an event.\n" +"\n" +"To zoom to an area, depress the left mouse button. Move the\n" +"mouse. Release the mouse.\n" +"\n" +"To use the time ruler, depress the right mouse button. Move the\n" +"mouse. Release when done.\n" +"\n" +"To push a track to the bottom, \n" +"\n" +"To pull a track to the top, \n" +"\n" +"To selectively color/uncolor a track, \n" +"\n" +"To make the mouse scrollwheel faster, press \n" +"\n" +"Hotkeys, supposedly Quake-like:\n" +" w - zoom-in\n" +" s - zoom-out\n" +" a - pan-left\n" +" d - pan-right\n" +" r - pan-up\n" +" f - pan-down\n" +" t - less traces\n" +" g - more traces\n" +"\n" +" e - toggle summary-mode\n" +" c - toggle color-mode\n" +"\n" +" x - take snapshot\n" +" z - go to next snapshot\n" +" p - put snapshots to snapshots.g2 \n" +" l - load snapshots from snapshots.g2\n" +"\n" +"q - quit\n" +"Send comments / bug reports to the \"fd.io\" mailing list.\n"; + +/**************************************************************************** +* debug_dialog_callback +****************************************************************************/ + +boolean debug_dialog_callback (char *s) +{ + g_print("Dialog result: %s", s); + return (TRUE); +} + +/**************************************************************************** +* get_dialog_value +****************************************************************************/ + +static void get_dialog_value (GtkWidget *dialog, gpointer user_data) +{ + md_t *md = (md_t *)user_data; + char * cb_arg; + + cb_arg = (char *) gtk_entry_get_text(GTK_ENTRY(md->entry)); + + if ((*md->callback)(cb_arg)) { + gtk_grab_remove(md->dialog); + gtk_widget_destroy(md->dialog); + } else { + gtk_label_set_text (GTK_LABEL(md->label), md->retry_text); + } +} + +/**************************************************************************** +* modal_dialog +****************************************************************************/ + +void modal_dialog (char *label_text, char *retry_text, char *default_value, + boolean (*cb)(char *)) +{ + GtkWidget *dialog, *label, *ok_button, *entry; + static md_t dlg; + md_t *md = &dlg; + + dialog = gtk_dialog_new(); + label = gtk_label_new(label_text); + + entry = gtk_entry_new(); + if (default_value) + gtk_entry_set_text(GTK_ENTRY(entry), default_value); + + ok_button = gtk_button_new_with_label("OK"); + + md->entry = entry; + md->label = label; + md->retry_text = retry_text; + md->dialog = dialog; + if (cb) + md->callback = cb; + else + md->callback = debug_dialog_callback; + + gtk_signal_connect (GTK_OBJECT (ok_button), "clicked", + GTK_SIGNAL_FUNC(get_dialog_value), (gpointer) md); + + gtk_signal_connect (GTK_OBJECT (entry), "activate", + GTK_SIGNAL_FUNC(get_dialog_value), (gpointer) md); + + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), + entry); + + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), + ok_button); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); + gtk_widget_show_all(dialog); + gtk_widget_grab_focus(entry); + gtk_grab_add(dialog); +} + +/**************************************************************************** +* get_eventdef_name +****************************************************************************/ + +static void get_eventdef_name (GtkFileSelection *sel, gpointer user_data) +{ + char *filename = (char *) gtk_file_selection_get_filename ( + GTK_FILE_SELECTION(s_filesel)); + read_event_definitions(filename); + set_window_title(filename); +} + +/**************************************************************************** +* read_eventdef_callback +****************************************************************************/ + +static void read_eventdef_callback(GtkToggleButton *item, gpointer data) +{ + + s_filesel = gtk_file_selection_new("Read Event Definitions From..."); + + gtk_file_selection_set_filename(GTK_FILE_SELECTION(s_filesel), + "../h/elog.h"); + + gtk_signal_connect (GTK_OBJECT ( + GTK_FILE_SELECTION(s_filesel)->ok_button), + "clicked", + GTK_SIGNAL_FUNC(get_eventdef_name), NULL); + + gtk_signal_connect_object (GTK_OBJECT ( + GTK_FILE_SELECTION(s_filesel)->ok_button), + "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + (gpointer) s_filesel); + + gtk_signal_connect_object (GTK_OBJECT ( + GTK_FILE_SELECTION(s_filesel)->cancel_button), + "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + (gpointer) s_filesel); + gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(s_filesel)); + gtk_widget_show (s_filesel); +} + +/**************************************************************************** +* get_events_name +****************************************************************************/ + +static void get_events_name (GtkFileSelection *sel, gpointer user_data) +{ + char *filename = (char *) gtk_file_selection_get_filename ( + GTK_FILE_SELECTION(s_eventsel)); + read_events(filename); + view1_display_when_idle(); +} + + +/**************************************************************************** +* get_ticks_per_ns +****************************************************************************/ + +static boolean get_ticks_per_ns (char *value) +{ + double rv; + + rv = atof (value); + + if (rv == 0.0 || rv > 100000) + return(FALSE); + + ticks_per_ns = rv; + ticks_per_ns_set = TRUE; + + gtk_widget_show(s_eventsel); + return(TRUE); +} + +/**************************************************************************** +* read_events_callback +****************************************************************************/ + +static void read_events_callback(GtkToggleButton *item, gpointer data) +{ + char tmpbuf [32]; + + s_eventsel = gtk_file_selection_new("Read Events From..."); + + gtk_signal_connect (GTK_OBJECT ( + GTK_FILE_SELECTION(s_eventsel)->ok_button), + "clicked", + GTK_SIGNAL_FUNC(get_events_name), NULL); + + gtk_signal_connect_object (GTK_OBJECT ( + GTK_FILE_SELECTION(s_eventsel)->ok_button), + "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + (gpointer) s_eventsel); + + gtk_signal_connect_object (GTK_OBJECT ( + GTK_FILE_SELECTION(s_eventsel)->cancel_button), + "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + (gpointer) s_eventsel); + gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(s_eventsel)); + + if (ticks_per_ns_set) + gtk_widget_show (s_eventsel); + else { + sprintf(tmpbuf, "%.3f", ticks_per_ns); + modal_dialog ("Please enter clock ticks per nanosecond", + "Invalid: Please enter clock ticks per nanosecond", + tmpbuf, get_ticks_per_ns); + } +} + +/**************************************************************************** +* read_eventclock_callback +****************************************************************************/ + +static void read_eventsclock_callback(GtkToggleButton *item, gpointer data) +{ + ticks_per_ns_set = FALSE; + read_events_callback(item, data); +} + +/**************************************************************************** +* infobox_size_request +****************************************************************************/ + +void infobox_size_request (GtkWidget *widget, GtkRequisition *req, + gpointer user_data) +{ + char *text = (char *)user_data; + char *cp; + int widest_line_in_chars; + int w; + int nlines; + + /* + * You'd think that the string extent function would work here. + * You'd be wrong. + */ + nlines = w = widest_line_in_chars = 0; + for (cp = text; *cp; cp++) { + if (*cp == '\n') { + if (w > widest_line_in_chars) { + widest_line_in_chars = w; + } + w = 0; + nlines++; + } + w++; + } + + nlines++; + + req->width = (widest_line_in_chars * 8) + 20; + req->height = (nlines * 13) + 10; +} + +/**************************************************************************** +* infobox +****************************************************************************/ + +void infobox(char *label_text, char *text) +{ + GtkWidget *dialog, *label, *ok_button, *entry; + GtkWidget *box; + + dialog = gtk_dialog_new(); + label = gtk_label_new(label_text); + + entry = gtk_text_new(NULL, NULL); + + gtk_signal_connect (GTK_OBJECT (entry), "size-request", + GTK_SIGNAL_FUNC(infobox_size_request), + (gpointer) text); + + gtk_text_insert(GTK_TEXT(entry), g_font, &fg_black, &bg_white, + text, -1); + + gtk_text_set_editable(GTK_TEXT(entry), FALSE); + + ok_button = gtk_button_new_with_label("OK"); + + gtk_signal_connect_object (GTK_OBJECT (ok_button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + (gpointer) GTK_OBJECT(dialog)); + + box = gtk_vbox_new(FALSE, 5); + + + gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(box), ok_button, FALSE, FALSE, 0); + + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), + box); + + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); + gtk_widget_show_all(dialog); +} + +/**************************************************************************** +* help_general_callback +****************************************************************************/ + +static void help_general_callback(GtkToggleButton *item, gpointer data) +{ + infobox("General Help", general_help); +} + +/**************************************************************************** +* help_about_callback +****************************************************************************/ + +static void help_about_callback(GtkToggleButton *item, gpointer data) +{ + char tmpbuf [1024]; + sprintf (tmpbuf, "G2 -- Graphical Event Viewer\n\n"); + view1_about(tmpbuf); + pointsel_about(tmpbuf); + events_about(tmpbuf); + sprintf (tmpbuf+strlen(tmpbuf), "\n%s\n", version_string); + sprintf (tmpbuf+strlen(tmpbuf), "%s\n", minor_v_string); + infobox("About", tmpbuf); +} + + +/**************************************************************************** +* get_cpel_name +****************************************************************************/ + +static void get_cpel_name (GtkFileSelection *sel, gpointer user_data) +{ + char *filename = (char *)gtk_file_selection_get_filename ( + GTK_FILE_SELECTION(s_filesel)); + read_cpel_file(filename); + set_window_title(filename); +} + +/**************************************************************************** +* get_clib_name +****************************************************************************/ + +static void get_clib_name (GtkFileSelection *sel, gpointer user_data) +{ + char *filename = (char *) gtk_file_selection_get_filename ( + GTK_FILE_SELECTION(s_filesel)); + read_clib_file(filename); + set_window_title(filename); +} + +/**************************************************************************** +* read_cpel_callback +****************************************************************************/ + +static void read_cpel_callback(GtkToggleButton *item, gpointer data) +{ + + s_filesel = gtk_file_selection_new("Read CPEL data from..."); + + gtk_file_selection_set_filename(GTK_FILE_SELECTION(s_filesel), + "cpel.out"); + + gtk_signal_connect (GTK_OBJECT ( + GTK_FILE_SELECTION(s_filesel)->ok_button), + "clicked", + GTK_SIGNAL_FUNC(get_cpel_name), NULL); + + gtk_signal_connect_object (GTK_OBJECT ( + GTK_FILE_SELECTION(s_filesel)->ok_button), + "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + (gpointer) s_filesel); + + gtk_signal_connect_object (GTK_OBJECT ( + GTK_FILE_SELECTION(s_filesel)->cancel_button), + "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + (gpointer) s_filesel); + gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(s_filesel)); + gtk_widget_show (s_filesel); +} + +/**************************************************************************** +* read_clib_callback +****************************************************************************/ + +static void read_clib_callback(GtkToggleButton *item, gpointer data) +{ + + s_filesel = gtk_file_selection_new("Read clib data From..."); + + gtk_file_selection_set_filename(GTK_FILE_SELECTION(s_filesel), + "clib.out"); + + gtk_signal_connect (GTK_OBJECT ( + GTK_FILE_SELECTION(s_filesel)->ok_button), + "clicked", + GTK_SIGNAL_FUNC(get_clib_name), NULL); + + gtk_signal_connect_object (GTK_OBJECT ( + GTK_FILE_SELECTION(s_filesel)->ok_button), + "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + (gpointer) s_filesel); + + gtk_signal_connect_object (GTK_OBJECT ( + GTK_FILE_SELECTION(s_filesel)->cancel_button), + "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + (gpointer) s_filesel); + gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(s_filesel)); + gtk_widget_show (s_filesel); +} + +/**************************************************************************** +* menu1_init +****************************************************************************/ + +void menu1_init(void) +{ + + s_filemenu = gtk_menu_new(); + + s_readcpel = gtk_menu_item_new_with_label + ("Read CPEL file"); + gtk_menu_append(GTK_MENU(s_filemenu), s_readcpel); + gtk_signal_connect(GTK_OBJECT(s_readcpel), "activate", + GTK_SIGNAL_FUNC(read_cpel_callback), 0); + + s_readclib = gtk_menu_item_new_with_label + ("Read CLIB file"); + gtk_menu_append(GTK_MENU(s_filemenu), s_readclib); + gtk_signal_connect(GTK_OBJECT(s_readclib), "activate", + GTK_SIGNAL_FUNC(read_clib_callback), 0); + + s_readdefs = gtk_menu_item_new_with_label ("Read Event Definitions"); + gtk_menu_append(GTK_MENU(s_filemenu), s_readdefs); + gtk_signal_connect(GTK_OBJECT(s_readdefs), "activate", + GTK_SIGNAL_FUNC(read_eventdef_callback), 0); + + s_readevents = gtk_menu_item_new_with_label ("Read Event Log"); + gtk_menu_append(GTK_MENU(s_filemenu), s_readevents); + gtk_signal_connect(GTK_OBJECT(s_readevents), "activate", + GTK_SIGNAL_FUNC(read_events_callback), 0); + + s_readeventsclock = gtk_menu_item_new_with_label + ("Read Event Log with Different Clock Rate"); + gtk_menu_append(GTK_MENU(s_filemenu), s_readeventsclock); + gtk_signal_connect(GTK_OBJECT(s_readeventsclock), "activate", + GTK_SIGNAL_FUNC(read_eventsclock_callback), 0); + + s_print = gtk_menu_item_new_with_label ("Print"); + gtk_menu_append(GTK_MENU(s_filemenu), s_print); + gtk_signal_connect(GTK_OBJECT(s_print), "activate", + GTK_SIGNAL_FUNC(view1_print_callback), 0); + + s_quit = gtk_menu_item_new_with_label ("Exit"); + gtk_menu_append(GTK_MENU(s_filemenu), s_quit); + gtk_signal_connect(GTK_OBJECT(s_quit), "activate", + GTK_SIGNAL_FUNC(gtk_main_quit), 0); + + s_mainfilemenu = gtk_menu_item_new_with_label("File"); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(s_mainfilemenu), s_filemenu); + + s_helpmenu = gtk_menu_new(); + + s_help_general = gtk_menu_item_new_with_label ("General"); + gtk_menu_append(GTK_MENU(s_helpmenu), s_help_general); + gtk_signal_connect(GTK_OBJECT(s_help_general), "activate", + GTK_SIGNAL_FUNC(help_general_callback), 0); + + s_help_about = gtk_menu_item_new_with_label ("About"); + gtk_menu_append(GTK_MENU(s_helpmenu), s_help_about); + gtk_signal_connect(GTK_OBJECT(s_help_about), "activate", + GTK_SIGNAL_FUNC(help_about_callback), 0); + + s_mainhelpmenu = gtk_menu_item_new_with_label("Help"); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(s_mainhelpmenu), s_helpmenu); + + s_mainmenubar = gtk_menu_bar_new(); + gtk_menu_bar_append(GTK_MENU_BAR(s_mainmenubar), s_mainfilemenu); + gtk_menu_bar_append(GTK_MENU_BAR(s_mainmenubar), s_mainhelpmenu); + gtk_widget_show_all(s_mainmenubar); + + gtk_box_pack_start(GTK_BOX(g_mainvbox), s_mainmenubar, FALSE, FALSE, 0); +} diff --git a/src/tools/g2/mkversion.c b/src/tools/g2/mkversion.c new file mode 100644 index 00000000..3523fbe6 --- /dev/null +++ b/src/tools/g2/mkversion.c @@ -0,0 +1,77 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 1997-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 + +int main (int argc, char **argv) +{ + time_t now; + FILE *ofp; + char *dateval; + char *username; + char *userstr; + char *datestr; + int i; + char propname[32]; + char *propvalue; + char timestr[64]; + char *cp; + + if (argc < 4) { + printf ("usage: mkversion ostype version outputfile\n"); + exit (1); + } + + ofp = fopen (argv[3], "w"); + if (ofp == NULL) { + printf ("Couldn't create %s\n", argv[3]); + exit (1); + } + + now = time (0); + + fprintf (ofp, "/*\n"); + fprintf (ofp, " * G2 Version Stamp, %s", + ctime (&now)); + fprintf (ofp, " * Automatically generated, hand edits are pointless.\n"); + fprintf (ofp, " */\n\n"); + + fprintf (ofp, + "const char *version_string = \"G2 (%s) major version %s\";\n", + argv[1], argv[2]); + + username = (char *) cuserid (0); + + strcpy(timestr, ctime(&now)); + + cp = timestr; + + while (*cp) { + cp++; + } + if (*--cp == '\n') + *cp = 0; + + fprintf (ofp, + "const char *minor_v_string = \"Built by %s at %s\";\n", + username, timestr); + + exit (0); +} + + diff --git a/src/tools/g2/pointsel.c b/src/tools/g2/pointsel.c new file mode 100644 index 00000000..018dc213 --- /dev/null +++ b/src/tools/g2/pointsel.c @@ -0,0 +1,854 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2005-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 "g2.h" + +/* + * globals + */ +event_def_t g_eventdefs[NEVENTS]; + +/* + * locals + */ +static GtkWidget *s_pointselbox; +static FILE *s_hfp; +static FILE *s_elog_hfp; +static int s_basenum; +static GtkWidget *s_event_buttons[NEVENTS]; +static int s_min_shown_pointsel; +static int s_max_shown_pointsel; +static GtkWidget *s_allbutton; +static GtkWidget *s_nonebutton; +static GtkWidget *s_pointselbuttons; +static GtkWidget *s_ps_vscroll; +static GtkObject *s_ps_vsadj; +static int g_neventdefs; + +enum button_click { + ALL_BUTTON=1, + NONE_BUTTON, +}; + +/* + * config params + */ +int c_maxpointsel; + +/**************************************************************************** +* recompute_vscrollbar +****************************************************************************/ + +static void recompute_ps_vscrollbar (void) +{ + GtkAdjustment *adj; + ulong limit; + + adj = GTK_ADJUSTMENT(s_ps_vsadj); + +#ifdef NOTDEF + /* This seems like the right calculation, but seems not to work */ + if (g_neventdefs > c_maxpointsel) + limit = g_neventdefs - c_maxpointsel; + else + limit = g_neventdefs; +#else + limit = g_neventdefs-1; +#endif + + adj->lower = (gfloat)0.00; + adj->upper = (gfloat)limit; + adj->value = (gfloat)0.00; + adj->step_increment = (gfloat)1.00; + adj->page_increment = (gfloat)(c_maxpointsel / 3); + adj->page_size = (gfloat)c_maxpointsel; + gtk_adjustment_changed(adj); + gtk_adjustment_value_changed(adj); + gtk_widget_show(s_ps_vscroll); +} + +/**************************************************************************** +* point_select_callback +****************************************************************************/ + +static void point_select_callback(GtkToggleButton *item, gpointer data) +{ + int i = (int) (unsigned long long) data; + + g_eventdefs[i].selected = gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(s_event_buttons[i])); + view1_display_when_idle(); +} + +/**************************************************************************** +* up_button +****************************************************************************/ + +static void up_button(void) +{ + int i; + int increment = c_maxpointsel/4; + + if (s_min_shown_pointsel == 0) + return; + + s_min_shown_pointsel -= increment; + + if (s_min_shown_pointsel < 0) + s_min_shown_pointsel = 0; + + s_max_shown_pointsel = s_min_shown_pointsel + c_maxpointsel; + + for (i = 0; i < g_neventdefs; i++) { + if (i >= s_min_shown_pointsel && + i <= s_max_shown_pointsel) + gtk_widget_show(s_event_buttons[i]); + else + gtk_widget_hide(s_event_buttons[i]); + } + +} + +#ifdef NOTDEF +/**************************************************************************** +* down_button +****************************************************************************/ + +static void down_button(void) +{ + int i; + int increment = c_maxpointsel/4; + + if (s_max_shown_pointsel == g_neventdefs) + return; + + s_max_shown_pointsel += increment; + + if (s_max_shown_pointsel >= g_neventdefs) + s_max_shown_pointsel = (g_neventdefs-1); + + s_min_shown_pointsel = s_max_shown_pointsel - c_maxpointsel; + + if (s_min_shown_pointsel < 0) + s_min_shown_pointsel = 0; + + for (i = 0; i < g_neventdefs; i++) { + if (i >= s_min_shown_pointsel && + i <= s_max_shown_pointsel) + gtk_widget_show(s_event_buttons[i]); + else + gtk_widget_hide(s_event_buttons[i]); + } + +} +#endif + +/**************************************************************************** +* button_click_callback +****************************************************************************/ + +static void button_click_callback(GtkButton *item, gpointer data) +{ + int i; + enum button_click click = (enum button_click)data; + + switch (click) { + case ALL_BUTTON: + for (i = 0; i < g_neventdefs; i++) { + gtk_toggle_button_set_active ( + GTK_TOGGLE_BUTTON(s_event_buttons[i]), TRUE); + g_eventdefs[i].selected = TRUE; + } + break; + + case NONE_BUTTON: + for (i = 0; i < g_neventdefs; i++) { + gtk_toggle_button_set_active ( + GTK_TOGGLE_BUTTON(s_event_buttons[i]), FALSE); + g_eventdefs[i].selected = FALSE; + } + break; + } +} + +/**************************************************************************** +* scroll_callback +****************************************************************************/ + +static void scroll_callback (GtkAdjustment *adj, GtkWidget *notused) +{ + int i; + + s_min_shown_pointsel = (int)adj->value; + s_max_shown_pointsel = s_min_shown_pointsel + c_maxpointsel; + + for (i = 0; i < g_neventdefs; i++) { + if (i >= s_min_shown_pointsel && + i <= s_max_shown_pointsel) + gtk_widget_show(s_event_buttons[i]); + else + gtk_widget_hide(s_event_buttons[i]); + } +} + +/**************************************************************************** +* point_selector_init +****************************************************************************/ + +void point_selector_init(void) +{ + + c_maxpointsel = atol(getprop_default("event_selector_lines", "20")); + + s_pointselbox = gtk_vbox_new(FALSE,5); + + s_pointselbuttons = gtk_hbox_new(FALSE,5); + + s_allbutton = gtk_button_new_with_label("ALL"); + gtk_widget_show(s_allbutton); + s_nonebutton = gtk_button_new_with_label("NONE"); + gtk_widget_show(s_nonebutton); + + gtk_signal_connect (GTK_OBJECT(s_allbutton), "clicked", + GTK_SIGNAL_FUNC(button_click_callback), + (gpointer) ALL_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_nonebutton), "clicked", + GTK_SIGNAL_FUNC(button_click_callback), + (gpointer) NONE_BUTTON); + + gtk_box_pack_start(GTK_BOX(s_pointselbuttons), s_allbutton, FALSE, + FALSE, 0); + gtk_box_pack_start(GTK_BOX(s_pointselbuttons), s_nonebutton, FALSE, + FALSE, 0); + + gtk_widget_show(s_pointselbuttons); + gtk_widget_ref(s_pointselbuttons); + + gtk_box_pack_start(GTK_BOX(s_pointselbox), s_pointselbuttons, FALSE, + FALSE, 0); + + gtk_box_pack_end (GTK_BOX(g_mainhbox), s_pointselbox, + FALSE, FALSE, 0); + + s_ps_vsadj = gtk_adjustment_new(0.0 /* initial value */, + 0.0 /* minimum value */, + 2000.0 /* maximum value */, + 0.1 /* step increment */, + 10.0/* page increment */, + 10.0/* page size */); + + s_ps_vscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT(s_ps_vsadj)); + gtk_signal_connect (GTK_OBJECT (s_ps_vsadj), "value-changed", + GTK_SIGNAL_FUNC (scroll_callback), + (gpointer)s_ps_vscroll); + gtk_box_pack_end(GTK_BOX(g_mainhbox), s_ps_vscroll, FALSE, FALSE, 0); +} + +/**************************************************************************** +* sxerox +****************************************************************************/ + +char *sxerox (char *s) +{ + char *rv; + + /* Note: g_malloc does or dies... */ + rv = (char *)g_malloc(strlen(s)+1); + strcpy (rv, s); + return (rv); +} + +/**************************************************************************** +* reset_point_selector +****************************************************************************/ + +static void reset_point_selector(void) +{ + int i; + + gtk_widget_hide(s_pointselbox); + gtk_widget_hide(s_pointselbuttons); + gtk_widget_hide(s_ps_vscroll); + gtk_container_remove(GTK_CONTAINER(s_pointselbox), + s_pointselbuttons); + + for (i = 0; i < g_neventdefs; i++) { + if (s_event_buttons[i]) { + gtk_container_remove(GTK_CONTAINER(s_pointselbox), + s_event_buttons[i]); + s_event_buttons[i] = 0; + } + } +} + +/**************************************************************************** +* create_point_selector +****************************************************************************/ + +static void create_point_selector(void) +{ + int i; + char tmpbuf [1024]; + event_def_t *ep; + GtkWidget *wp; + + for (i = 0; i < g_neventdefs; i++) { + ep = &g_eventdefs[i]; + sprintf(tmpbuf, "[%lu] %s", ep->event, + ep->name ? ep->name : "(none)"); + /* Hack to reduce width of point selectors */ + if (strlen(tmpbuf) > 50) { + tmpbuf[50] = 0; + } + + wp = gtk_check_button_new_with_label (tmpbuf); + s_event_buttons[i] = wp; + gtk_signal_connect (GTK_OBJECT(wp), "toggled", + GTK_SIGNAL_FUNC(point_select_callback), + (gpointer) (unsigned long long) i); + gtk_toggle_button_set_active ( + GTK_TOGGLE_BUTTON(wp), TRUE); + gtk_box_pack_start(GTK_BOX(s_pointselbox), wp, FALSE, FALSE, 0); + } + + /* set up scroll parameters by faking an up-button */ + s_min_shown_pointsel = 1; + up_button(); + + gtk_box_pack_start(GTK_BOX(s_pointselbox), s_pointselbuttons, FALSE, + FALSE, 0); + gtk_widget_show(s_pointselbuttons); + gtk_widget_show(s_pointselbox); + gtk_widget_show(s_ps_vscroll); +} + +/**************************************************************************** +* remove_all_events +****************************************************************************/ + +static void remove_all_events(void) +{ + event_def_t *ep; + int i; + + for (i = 0; i < g_neventdefs; i++) { + ep = &g_eventdefs[i]; + if (!ep->is_clib) { + if (ep->name) + g_free(ep->name); + if(ep->format) + g_free(ep->format); + } + } + g_neventdefs = 0; +} + +/**************************************************************************** +* add_event +****************************************************************************/ + +static void add_event(ulong event, char *name, char *format) +{ + int i; + event_def_t *ep; + + if (g_neventdefs >= NEVENTS) { + g_error("Too many event definitions, increase NEVENTS!"); + /*NOTREACHED*/ + } + + /* Simple dup check, probably not needed very often */ + for (i = 0; i < g_neventdefs; i++) { + if (g_eventdefs[i].event == event) { + g_warning("Duplicate def event %lu: first definition retained\n", + event); + return; + } + } + + ep = &g_eventdefs[g_neventdefs++]; + + ep->event = event; + ep->name = sxerox(name); + ep->format = sxerox(format); + ep->selected = TRUE; +} + +/**************************************************************************** +* add_event_from_cpel_file +****************************************************************************/ + +void add_event_from_cpel_file(ulong event, char *event_format, + char *datum_format) +{ + event_def_t *ep; + + if (g_neventdefs >= NEVENTS) { + g_error("Too many event definitions, increase NEVENTS!"); + /*NOTREACHED*/ + } + + ep = &g_eventdefs[g_neventdefs++]; + + ep->event = event; + /* + * Duplicate the strings for backward compatibility. Otherwise, + * the g_free above will barf because the name/format strings are + * actually in mmap'ed memory + */ + ep->name = sxerox(event_format); + ep->format = sxerox(datum_format); + ep->selected = TRUE; +} + +/**************************************************************************** +* add_event_from_clib_file +****************************************************************************/ + +void add_event_from_clib_file(unsigned int event, char *name, + unsigned int vec_index) +{ + event_def_t *ep; + + if (g_neventdefs >= NEVENTS) { + g_error("Too many event definitions, increase NEVENTS!"); + /*NOTREACHED*/ + } + + ep = &g_eventdefs[g_neventdefs++]; + + ep->event = event; + + ep->name = sxerox(name); + ep->format = (void *)(unsigned long long) vec_index; + ep->selected = TRUE; + ep->is_clib = TRUE; +} + +/**************************************************************************** +* read_header_file - eats header file lines of the form +* +* #define EVENT_FOO 123 / * name: %d * / +* +****************************************************************************/ + +static void read_header_file (void) +{ + char tmpbuf [1024]; + char *name, *format; + char *cp; + unsigned long event; + int ev_num_flag; + + while (fgets (tmpbuf, sizeof (tmpbuf), s_hfp)) + { + cp = tmpbuf; + ev_num_flag = 0; + + if (strncmp (cp, "#define", 7)) + continue; + + /* skip #define */ + while (*cp && !(isspace ((int)*cp))) + cp++; + + if (*cp == 0) + continue; + + /* skip ws after #define */ + while (*cp && isspace ((int)*cp)) + cp++; + + if (*cp == 0) + continue; + + /* skip symbolic name */ + while (*cp && !(isspace ((int)*cp))) + cp++; + + if (*cp == 0) + continue; + + /* skip ws after symbolic name */ + while (*cp && isspace ((int)*cp)) + cp++; + + if (*cp == 0) + continue; + + event = 0; + + if (!strncmp(cp, "EV_NUM", 6)) { + cp += 6; + ev_num_flag = 1; + + while (*cp && *cp != '(') + cp++; + + if (*cp == 0) + continue; + + cp++; + + while (*cp && isspace ((int)*cp)) + cp++; + + } + + /* eat event code. */ + while (*cp && isdigit ((int)*cp)) + { + event = event * 10 + (*cp - '0'); + cp++; + } + + if (*cp == 0) + continue; + + if (ev_num_flag) { + while (*cp && *cp != ')') + cp++; + if (*cp == 0) + continue; + cp++; + event += s_basenum; + } + + /* skip ws after event code */ + while (*cp && isspace ((int)*cp)) + cp++; + + if (*cp != '/') + continue; + + cp++; + + if (*cp != '*') + continue; + + cp++; + + /* skip ws after comment start */ + while (*cp && isspace ((int)*cp)) + cp++; + + if (*cp == 0) + continue; + + name = cp; + + /* accumulate name */ + while (*cp && *cp != ':' && *cp != '*') + cp++; + + if (*cp == 0) + continue; + + *cp++ = 0; + + /* skip ws after name: */ + while (*cp && isspace ((int)*cp)) + cp++; + + if (*cp == 0 || *cp == '/') + { + format = " "; + goto write_it; + } + + format = cp; + + /* accumulate format string */ + while (*cp && !isspace ((int)*cp)) + cp++; + + *cp = 0; + + write_it: + + add_event (event, name, format); + } +} + +/**************************************************************************** +* read_header_files - eats header file lines of the form +* +* #define FILE1_BASE 100 / * pointdefs: ../vpn/vpn_points.h * / +* +****************************************************************************/ + +static boolean read_header_files (void) +{ + char *cp, *name; + char tmpbuf [1024]; + int basenum; + boolean rv=FALSE; + + while (fgets (tmpbuf, sizeof (tmpbuf), s_elog_hfp)) + { + cp = tmpbuf; + + if (strncmp (cp, "#define", 7)) + continue; + + cp += 7; + + /* skip ws after #define */ + while (*cp && isspace ((int)*cp)) + cp++; + + if (*cp == 0) + continue; + + /* skip EV_COMPxxx_START */ + while (*cp && !isspace((int)*cp)) + cp++; + + if (*cp == 0) + continue; + + /* skip ws after EV_COMPxxx_START */ + while (*cp && isspace ((int)*cp)) + cp++; + + if (*cp == 0) + continue; + + basenum = atol (cp); + + /* skip #define */ + while (*cp && (*cp != '/')) + cp++; + + if (*cp == 0) + continue; + + cp++; + if (*cp != '*') + continue; + + cp++; + + /* skip ws after comment start */ + while (*cp && isspace ((int)*cp)) + cp++; + + if (*cp == 0) + continue; + + if (strncmp (cp, "pointdefs:", 10)) + continue; + + cp += 10; + + /* skip ws after comment start */ + while (*cp && isspace ((int)*cp)) + cp++; + + name = cp; + + while (*cp && !isspace ((int)*cp)) + cp++; + + *cp = 0; + + s_hfp = fopen (name, "rt"); + + if (s_hfp == NULL) { + g_warning ("Couldn't open header file %s\n", name); + continue; + } + rv = TRUE; + + s_basenum = basenum; + + read_header_file(); + + fclose (s_hfp); + } + return(rv); +} + +/**************************************************************************** +* event_def_cmp +****************************************************************************/ + +int event_def_cmp(const void *a1, const void *a2) +{ + event_def_t *e1 = (event_def_t *)a1; + event_def_t *e2 = (event_def_t *)a2; + + if (e1->event < e2->event) + return(-1); + else if (e1->event == e2->event) + return(0); + else + return(1); +} + +/**************************************************************************** +* sort_event_definitions +****************************************************************************/ + +void sort_event_definitions(void) +{ + qsort(&g_eventdefs[0], g_neventdefs, sizeof(event_def_t), event_def_cmp); +} + +static boolean remove_needed=TRUE; + +void finalize_events(void) +{ + sort_event_definitions(); + create_point_selector(); + recompute_ps_vscrollbar(); + view1_display_when_idle(); + remove_needed = TRUE; +} + +void initialize_events(void) +{ + if (remove_needed) { + reset_point_selector(); + remove_all_events(); + remove_needed = FALSE; + } +} + +/**************************************************************************** +* read_event_definitions +****************************************************************************/ + +boolean read_event_definitions (char *filename) +{ + char tmpbuf [128]; + + initialize_events(); + + s_elog_hfp = fopen (filename, "rt"); + if (s_elog_hfp == NULL) { + sprintf (tmpbuf, "Couldn't open %s\n", filename); + infobox ("Open Failed", tmpbuf); + return(FALSE); + } + /* Presume "elog.h". Note fallthrough... */ + if (read_header_files()) { + sort_event_definitions(); + create_point_selector(); + recompute_ps_vscrollbar(); + fclose(s_elog_hfp); + view1_display_when_idle(); + remove_needed = TRUE; + return(TRUE); + } + fclose(s_elog_hfp); + + s_hfp = fopen (filename, "rt"); + if (s_hfp == NULL) { + sprintf (tmpbuf, "Couldn't open %s\n", filename); + infobox ("Read Event Definition Failure", tmpbuf); + return(FALSE); + } + + read_header_file(); + + /* Happens if the user feeds us the wrong file, for example */ + if (g_neventdefs == 0) { + sprintf (tmpbuf, "No event definitions found in %s\n", filename); + infobox ("No Event Definitions?", tmpbuf); + return(FALSE); + } + finalize_events(); + return(TRUE); +} + +static event_def_t dummy_event; +static char dummy_string[32]; + +/**************************************************************************** +* find_event_definition +* Binary search for first event whose time is >= t +****************************************************************************/ + +event_def_t *find_event_definition (ulong code) +{ + int index, bottom, top; + event_def_t *edp; + + if (g_neventdefs == 0) + goto use_dummy; + + bottom = g_neventdefs-1; + top = 0; + + while (1) { + index = (bottom + top) / 2; + + edp = (g_eventdefs + index); + + if (edp->event == code) + return(edp); + + if (top >= bottom) { + use_dummy: + edp = &dummy_event; + edp->selected = TRUE; + edp->event = code; + edp->format = "0x%x"; + sprintf (dummy_string, "E%lu", code); + edp->name = &dummy_string[0]; + return(edp); + } + + if (edp->event < code) + top = index + 1; + else + bottom = index - 1; + } +} + +/**************************************************************************** +* pointsel_next_snapshot +* Set dialog buttons from snapshot +****************************************************************************/ + +void pointsel_next_snapshot(void) +{ + int i; + + for (i = 0; i < g_neventdefs; i++) { + gtk_toggle_button_set_active ( + GTK_TOGGLE_BUTTON(s_event_buttons[i]), + g_eventdefs[i].selected); + } +} + +/**************************************************************************** +* pointsel_about +****************************************************************************/ + +void pointsel_about (char *tmpbuf) +{ + sprintf (tmpbuf+strlen(tmpbuf), "%d event definitions\n", + g_neventdefs); +} diff --git a/src/tools/g2/props.c b/src/tools/g2/props.c new file mode 100644 index 00000000..a23dc050 --- /dev/null +++ b/src/tools/g2/props.c @@ -0,0 +1,279 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 1997-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 + +static char *sxerox (char *s); +void exit(int); + +#define NBUCKETS 97 + +typedef struct prop_ { + struct prop_ *next; + char *name; + char *value; +} prop_t; + +static prop_t *buckets [NBUCKETS]; +static int hash_shifts[4] = {24, 16, 8, 0}; + +/* + * getprop + */ + +char *getprop (char *name) +{ + unsigned char *cp; + unsigned long hash=0; + prop_t *bp; + int i=0; + + for (cp = (unsigned char *) name; *cp; cp++) + hash ^= (*cp)<<(hash_shifts[(i++)&0x3]); + + bp = buckets [hash%NBUCKETS]; + + while (bp && strcmp (bp->name, name)) { + bp = bp->next; + } + + if (bp == NULL) + return (0); + else + return (bp->value); +} + +/* + * getprop_default + */ + +char *getprop_default (char *name, char *def) +{ + char *rv; + rv = getprop (name); + if (rv) + return (rv); + else + return (def); +} + +/* + * addprop + */ + +void addprop (char *name, char *value) +{ + unsigned char *cp; + unsigned long hash=0; + prop_t **bpp; + prop_t *bp; + int i=0; + + bp = (prop_t *)g_malloc (sizeof (prop_t)); + + bp->next = 0; + bp->name = sxerox (name); + bp->value = sxerox (value); + + for (cp = (unsigned char *)name; *cp; cp++) + hash ^= (*cp)<<(hash_shifts[(i++)&0x3]); + + bpp = &buckets [hash%NBUCKETS]; + + if (*bpp == NULL) + *bpp = bp; + else { + bp->next = *bpp; + *bpp = bp; + } +} + +/* + * sxerox + */ + +static char *sxerox (char *s) +{ + char *rv = (char *) g_malloc (strlen (s) + 1); + strcpy (rv, s); + return rv; +} + +/* + * readprops + */ + +#define START 0 +#define READNAME 1 +#define READVALUE 2 +#define C_COMMENT 3 +#define CPP_COMMENT 4 + +int readprops (char *filename) +{ + FILE *ifp; + unsigned char c; + int state=START; + int linenum=1; + char namebuf [128]; + char valbuf [512]; + int i; + + ifp = fopen (filename, "r"); + + if (ifp == NULL) + return (-1); + + while (1) { + + readchar: + c = getc (ifp); + + again: + switch (state) { + case START: + if (feof (ifp)) { + fclose (ifp); + return (0); + } + + if (c == ' ' || c == '\t') + goto readchar; + + if (c == '\n') { + linenum++; + goto readchar; + } + if (isalpha (c) || (c == '_')) { + state = READNAME; + goto again; + } + if (c == '/') { + c = getc (ifp); + if (c == '/') { + state = CPP_COMMENT; + goto readchar; + } else if (c == '*') { + state = C_COMMENT; + goto readchar; + } else { + fprintf (stderr, "unknown token '/' line %d\n", + linenum); + exit (1); + } + } + fprintf (stderr, "unknown token '%c' line %d\n", + c, linenum); + exit (1); + break; + + case CPP_COMMENT: + while (1) { + c = getc (ifp); + if (feof (ifp)) + return (0); + if (c == '\n') { + linenum++; + state = START; + goto readchar; + } + } + break; + + case C_COMMENT: + while (1) { + c = getc (ifp); + if (feof (ifp)) { + fprintf (stderr, "unterminated comment, line %d\n", + linenum); + exit (1); + } + if (c == '*') { + staragain: + c = getc (ifp); + if (c == '/') { + state = START; + goto readchar; + } + if (c == '*') + goto staragain; + } + } + break; + + case READNAME: + i = 0; + namebuf[i++] = c; + while (1) { + c = getc (ifp); + if (feof (ifp)) { + fprintf (stderr, "EOF while reading a name, line %d\n", + linenum); + exit (1); + } + if ((!isalnum (c)) && (c != '_')) { + namebuf [i] = 0; + state = READVALUE; + goto again; + } + namebuf [i++] = c; + } + break; + + case READVALUE: + i = 0; + while ((c == ' ') || (c == '\t') || (c == '=')) { + c = getc (ifp); + if (feof (ifp)) { + fprintf (stderr, "EOF while reading a value, line %d\n", + linenum); + exit (1); + } + } + goto firsttime; + while (1) { + c = getc (ifp); + + firsttime: + if (c == '\\') { + c = getc (ifp); + if (feof (ifp)) { + fprintf (stderr, "EOF after '\\', line %d\n", + linenum); + exit (1); + } + valbuf[i++] = c; + continue; + } + if (c == '\n') { + linenum++; + while (valbuf [i-1] == ' ' || valbuf[i-1] == '\t') + i--; + valbuf[i] = 0; + addprop (namebuf, valbuf); + state = START; + goto readchar; + } + valbuf[i++] = c; + } + + } + } +} diff --git a/src/tools/g2/props.h b/src/tools/g2/props.h new file mode 100644 index 00000000..6289941d --- /dev/null +++ b/src/tools/g2/props.h @@ -0,0 +1,21 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 1997-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern char *getprop (char *name); +extern char *getprop_default (char *name, char *def); +extern void addprop (char *name, char *value); +extern int readprops (char *filename); +extern int writeprops (char *filename); diff --git a/src/tools/g2/view1.c b/src/tools/g2/view1.c new file mode 100644 index 00000000..ec394cc3 --- /dev/null +++ b/src/tools/g2/view1.c @@ -0,0 +1,3077 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2005-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 "g2.h" +#include +#include +#include +#include + +/* + * The main event display view. + * + * Important variables: + * + * "da" -- the drawing area, aka the screen representation of the + * event view. + * + * "pm" -- the backing pixmap for the drawing area. Note that + * all graphics operations target this backing + * store, then call gtk_widget_draw to copy a rectangle from + * the backing store onto the screen. + * + * "s_v1" -- pointer to the current v1_geometry_t object. + * + * Box heirarchy: + * s_view1_vbox + * s_view1_hbox + * da s_view1_vmenubox + * s_view1_topbutton("Top") + * s_view1_vscroll (vertical scrollbar) + * s_view1_bottombutton("Bottom") + * s_view1_hmenubox + * s_view1_startbutton("Start"); + * s_view1_hscroll(horizontal scrollbar) + * s_view1_endbutton("End") + * s_view1_zoominbutton("Zoomin") + * s_view1_searchbutton("Search") + * s_view1_searchagainbutton("Search Again") + * s_view1_zoomoutbutton("Zoomout") + * s_view1_label + */ + +/* + * Globals + */ + +GdkFont *g_font; /* a fixed-width font to use */ +GdkColor fg_black = {0, 0, 0, 0}; +GdkColor bg_white = {0, 65535, 65535, 65535}; +static boolean summary_mode = TRUE; /* start out in summary mode */ +static boolean color_mode = FALSE; /* start out in color mode */ + +/* + * Locals + */ + +/* + * user_data values passed to view1_button_click_callback, + * which is used by the various action buttons noted above + */ +enum view1_button_click { + TOP_BUTTON=1, + BOTTOM_BUTTON, + START_BUTTON, + ZOOMIN_BUTTON, + SEARCH_BUTTON, + SEARCH_AGAIN_BUTTON, + ZOOMOUT_BUTTON, + END_BUTTON, + MORE_TRACES_BUTTON, + LESS_TRACES_BUTTON, + SNAP_BUTTON, + NEXT_BUTTON, + DEL_BUTTON, + CHASE_EVENT_BUTTON, + CHASE_DATUM_BUTTON, + CHASE_TRACK_BUTTON, + UNCHASE_BUTTON, + FORWARD_BUTTON, + BACKWARD_BUTTON, + SUMMARY_BUTTON, + NOSUMMARY_BUTTON, +}; + +enum chase_mode { + CHASE_EVENT=1, + CHASE_DATUM, + CHASE_TRACK, +}; + +enum sc_dir { + SRCH_CHASE_FORWARD = 0, + SRCH_CHASE_BACKWARD = 1, +}; + +static GtkWidget *s_view1_hbox; /* see box heirarchy chart */ +static GtkWidget *s_view1_vbox; /* see box heirarchy chart */ +static GtkWidget *da; /* main drawing area */ +static GdkPixmap *pm; /* and its backing pixmap */ +static GdkCursor *norm_cursor; /* the "normal" cursor */ + +/* + * view geometry parameters + * + * Remember: + * Y increases down the page. + * Strip origin is at the top + * Payday is Friday + * Don't put your fingers in your mouth. + * + * Most of these values are in pixels + */ + +typedef struct v1_geometry { + int pid_ax_width; /* Width of the PID axis */ + int time_ax_height; /* Height of the time axis */ + int time_ax_spacing; /* TimeAxis: Space between tick-marks */ + int strip_height; /* Height of a regular PID trace */ + int pop_offset; /* Vertical offset of the detail box */ + int pid_ax_offset; /* Vertical offset of the PID axis */ + int event_offset; /* Vertical offset of the event boxes */ + int total_height; /* total height of da, see configure_event */ + int total_width; /* ditto, for width */ + + /* Derived values */ + int first_pid_index; /* Index of first displayed PID */ + int npids; /* Max number of displayed pids */ + ulonglong minvistime; /* in usec */ + ulonglong maxvistime; /* in usec */ +} v1_geometry_t; + + +/* The active geometry object */ +static v1_geometry_t s_v1record; +static v1_geometry_t *s_v1 = &s_v1record; + +/* The color array */ +static GdkColor *s_color; + +/* Snapshot ring */ +typedef struct snapshot { + struct snapshot *next; + /* Screen geometry */ + v1_geometry_t geometry; + boolean show_event[NEVENTS]; + pid_sort_t *pidvec; + /* + * Note: not worth recomputing the vertical scrollbar, just save + * its value here + */ + gfloat vscroll_value; + boolean summary_mode; + boolean color_mode; +} snapshot_t; + +static snapshot_t *s_snapshots; +static snapshot_t *s_cursnap; +static event_t *s_last_selected_event; + +/* + * various widgets, see the box heirarchy chart above + * The toolkit keeps track of these things, we could lose many of + * these pointers. + */ +static GtkWidget *s_view1_vmenubox; +static GtkWidget *s_view1_topbutton; +static GtkWidget *s_view1_bottombutton; +static GtkWidget *s_view1_more_traces_button; +static GtkWidget *s_view1_less_traces_button; + +static GtkWidget *s_view1_hmenubox; +static GtkWidget *s_view1_hmenubox2; +static GtkWidget *s_view1_startbutton; +static GtkWidget *s_view1_zoominbutton; +static GtkWidget *s_view1_searchbutton; +static GtkWidget *s_view1_srchagainbutton; +static GtkWidget *s_view1_zoomoutbutton; +static GtkWidget *s_view1_endbutton; + +static GtkWidget *s_view1_snapbutton; +static GtkWidget *s_view1_nextbutton; +static GtkWidget *s_view1_delbutton; + +static GtkWidget *s_view1_chase_event_button; +static GtkWidget *s_view1_chase_datum_button; +static GtkWidget *s_view1_chase_track_button; +static GtkWidget *s_view1_unchasebutton; + +static GtkWidget *s_view1_forward_button; +static GtkWidget *s_view1_backward_button; + +static GtkWidget *s_view1_summary_button; +static GtkWidget *s_view1_nosummary_button; + +static GtkWidget *s_view1_hscroll; +static GtkObject *s_view1_hsadj; + +static GtkWidget *s_view1_vscroll; +static GtkObject *s_view1_vsadj; + +static GtkWidget *s_view1_label; + +/* + * Search context + */ +static ulong s_srchcode; /* search event code */ +static int s_srchindex; /* last hit was at this event index */ +static boolean s_result_up; /* The SEARCH RESULT dongle is displayed */ +static boolean s_srchfail_up; /* The status line "Search Failed" is up */ +static int srch_chase_dir; /* search/chase dir, 0=>forward */ + + +/* + * Print context + */ +static int s_print_offset; /* Magic offset added to line, tbox fn codes */ +static FILE *s_printfp; + +/* + * Forward reference prototypes + */ +static void display_pid_axis(v1_geometry_t *vp); +static void display_event_data(v1_geometry_t *vp); +static void display_time_axis(v1_geometry_t *vp); +static void view1_button_click_callback(GtkButton *item, gpointer data); + +/* + * config params + */ + +gint c_view1_draw_width; +gint c_view1_draw_height; + +/* + * Zoom-In / Time Ruler cursor + */ + +#define zi_width 32 +#define zi_height 32 +#define zi_x_hot 22 +#define zi_y_hot 14 +static unsigned char zi_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x88, 0x00, + 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xa0, 0x00, + 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x84, 0x00, + 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static unsigned char zi_bkgd[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x88, 0x00, + 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xa0, 0x00, + 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x84, 0x00, + 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static GdkCursor *zi_cursor; +static GdkPixmap *zi_source, *zi_mask; + +/* + * Frequently-used small computations, best + * done correctly once and instantiated. + */ + +/**************************************************************************** +* dtime_per_pixel +****************************************************************************/ + +static inline double dtime_per_pixel(v1_geometry_t *vp) +{ + return ((double)(vp->maxvistime - vp->minvistime)) / + ((double)(vp->total_width - vp->pid_ax_width)); +} + +/**************************************************************************** +* message_line +* Changes the status line. Pass "" to clear the status line. +****************************************************************************/ + +void message_line (char *s) +{ + gtk_label_set_text (GTK_LABEL(s_view1_label), s); +} + +/**************************************************************************** +* set_window_title +* Changes the window title to include the specified filename. +****************************************************************************/ + +void set_window_title (const char *filename) +{ + char title[128]; + snprintf(title, sizeof(title), "g2 (%s)", filename); + gtk_window_set_title(GTK_WINDOW(g_mainwindow), title); +} + +/**************************************************************************** +* recompute_hscrollbar +* Adjust the horizontal scrollbar's adjustment object. +* +* GtkAdjustments are really cool, but have to be set up exactly +* right or the various client objects screw up completely. +* +* Note: this function is *not* called when the user clicks the scrollbar. +****************************************************************************/ + +static void recompute_hscrollbar (void) +{ + ulonglong current_width; + ulonglong event_incdec; + GtkAdjustment *adj; + event_t *ep; + + if (g_nevents == 0) + return; + + ep = (g_events + (g_nevents-1)); + current_width = s_v1->maxvistime - s_v1->minvistime; + event_incdec = (current_width) / 6; + + adj = GTK_ADJUSTMENT(s_view1_hsadj); + + /* + * Structure member decoder ring + * ----------------------------- + * lower the minimum possible value + * value the current value + * upper the maximum possible value + * step_increment end button click increment + * page_increment click in trough increment + * page_size size of currently visible area + */ + + adj->lower = (gfloat)0.00; + adj->value = (gfloat)s_v1->minvistime; + + /* Minor click: move about 1/6 of a page */ + adj->step_increment = (gfloat)event_incdec; + + /* Major click: move about 1/3 of a page. */ + adj->page_increment = (gfloat)(2*event_incdec); + + /* allow the user to go a bit past the end */ + adj->upper = adj->page_increment/3 + (gfloat)(ep->time); + adj->page_size = (gfloat)(current_width); + + /* + * Tell all clients (e.g. the visible scrollbar) to + * make themselves look right + */ + gtk_adjustment_changed(adj); + gtk_adjustment_value_changed(adj); +} + +/**************************************************************************** +* recompute_vscrollbar +* Ditto, for the vertical scrollbar +****************************************************************************/ + +static void recompute_vscrollbar (void) +{ + GtkAdjustment *adj; + + adj = GTK_ADJUSTMENT(s_view1_vsadj); + + adj->lower = (gfloat)0.00; + adj->upper = (gfloat)g_npids; + adj->value = (gfloat)0.00; + adj->step_increment = 1.00; + adj->page_increment = (gfloat)(s_v1->npids / 3); + adj->page_size = (gfloat)s_v1->npids; + gtk_adjustment_changed(adj); + gtk_adjustment_value_changed(adj); +} + +/**************************************************************************** +* format_popbox_string +****************************************************************************/ + +elog_main_t elog_main; + +void format_popbox_string (char *tmpbuf, int len, event_t *ep, event_def_t *edp) +{ + char *fp; + +#ifdef NOTDEF + sprintf(tmpbuf,"%d:", ep->code); +#endif + if (ep->flags & EVENT_FLAG_CLIB) { + elog_event_t *eep; + u8 *s; + + eep = get_clib_event (ep->datum); + + s = format (0, "%U", format_elog_event, &elog_main, eep); + memcpy (tmpbuf, s, vec_len(s)); + tmpbuf[vec_len(s)] = 0; + vec_free(s); + return; + } + + snprintf(tmpbuf, len, "%s", edp->name); + fp = edp->format; + /* Make sure there's a real format string. If so, add it */ + while (fp && *fp) { + if (*fp != ' ') { + snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf), ": "); + /* %s only supported for cpel files */ + if (fp[1] == 's') { + snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf), + edp->format, strtab_ref(ep->datum)); + } else { + snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf), + edp->format, ep->datum); + } + return; + } + fp++; + } +} + +/**************************************************************************** + * add_snapshot + ****************************************************************************/ + +static void add_snapshot(void) +{ + int i; + snapshot_t *new = g_malloc(sizeof(snapshot_t)); + + memcpy(&new->geometry, s_v1, sizeof(new->geometry)); + for (i = 0; i < NEVENTS; i++) { + new->show_event[i] = g_eventdefs[i].selected; + } + new->pidvec = g_malloc(sizeof(pid_sort_t)*g_npids); + memcpy(new->pidvec, g_pids, sizeof(pid_sort_t)*g_npids); + new->vscroll_value = GTK_ADJUSTMENT(s_view1_vsadj)->value; + new->summary_mode = summary_mode; + new->color_mode = color_mode; + + if (s_snapshots) { + new->next = s_snapshots; + s_snapshots = new; + } else { + new->next = 0; + s_snapshots = new; + } + s_cursnap = new; +} + +/**************************************************************************** + * next_snapshot + ****************************************************************************/ + +static void next_snapshot(void) +{ + snapshot_t *next; + int i; + pid_sort_t *psp; + pid_data_t *pp; + + if (!s_snapshots) { + infobox("No snapshots", "\nNo snapshots in the ring...\n"); + return; + } + + next = s_cursnap->next; + if (next == 0) + next = s_snapshots; + + s_cursnap = next; + + memcpy(s_v1, &next->geometry, sizeof(next->geometry)); + for (i = 0; i < NEVENTS; i++) { + g_eventdefs[i].selected = next->show_event[i]; + } + memcpy(g_pids, next->pidvec, sizeof(pid_sort_t)*g_npids); + color_mode = next->color_mode; + /* + * Update summary mode via a button push so that the button state is + * updated accordingly. (Should ideally clean up the view/controller + * separation properly one day.) + */ + if (summary_mode != next->summary_mode) { + view1_button_click_callback + (NULL, (gpointer)(unsigned long long) + (summary_mode ? NOSUMMARY_BUTTON : SUMMARY_BUTTON)); + } + + /* Fix the pid structure index mappings */ + psp = g_pids; + + for (i = 0; i < g_npids; i++) { + pp = psp->pid; + pp->pid_index = i; + psp++; + } + GTK_ADJUSTMENT(s_view1_vsadj)->value = next->vscroll_value; + gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); + recompute_hscrollbar(); + pointsel_next_snapshot(); + view1_display_when_idle(); +} + + +/**************************************************************************** + * del_snapshot + ****************************************************************************/ + +static void del_snapshot(void) +{ + snapshot_t *prev; + snapshot_t *this; + + if (!s_snapshots) { + infobox("No snapshots", "\nNo snapshots to delete...\n"); + return; + } + + prev = NULL; + this = s_snapshots; + + while (this && this != s_cursnap) { + prev = this; + this = this->next; + } + + if (this != s_cursnap) { + infobox("BUG", "\nSnapshot AWOL!\n"); + return; + } + + s_cursnap = this->next; + + /* middle of the list? */ + if (prev) { + prev->next = this->next; + g_free(this->pidvec); + g_free(this); + } else { /* start of the list */ + s_snapshots = this->next; + g_free(this->pidvec); + g_free(this); + } + + /* Note: both will be NULL after last delete */ + if (s_cursnap == NULL) + s_cursnap = s_snapshots; +} + +/**************************************************************************** + * write_snapshot + * + * VERY primitive right now - not endian or version independent, and only + * writes to "snapshots.g2" in the current directory + ****************************************************************************/ +static void write_snapshot(void) +{ + FILE *file = NULL; + snapshot_t *snap; + char *error = NULL; + int records = 0; + + if (s_snapshots == NULL) { + error = "No snapshots defined"; + errno = 0; + } + + if (!error) { + file = fopen("snapshots.g2", "w"); + if (file == NULL) { + error = "Unable to open snapshots.g2"; + } + } + + /* + * Simply serialize the arch-dependent binary data, without a care in the + * world. Don't come running to me if you try to read it and crash. + */ + for (snap = s_snapshots; !error && snap != NULL; snap = snap->next) { + if (fwrite(&snap->geometry, + sizeof(snap->geometry), 1, file) != 1 || + fwrite(&snap->show_event, + sizeof(snap->show_event), 1, file) != 1 || + fwrite(snap->pidvec, + sizeof(pid_sort_t) * g_npids, 1, file) != 1 || + fwrite(&snap->vscroll_value, + sizeof(snap->vscroll_value), 1, file) != 1 || + fwrite(&snap->summary_mode, + sizeof(snap->summary_mode), 1, file) != 1 || + fwrite(&snap->color_mode, + sizeof(snap->color_mode), 1, file) != 1) { + error = "Error writing data"; + } + records++; + } + + if (!error) { + if (fclose(file)) { + error = "Unable to close file"; + } + } + + if (error) { + infobox(error, strerror(errno)); + } else { + char buf[64]; + snprintf(buf, sizeof(buf), "Wrote %d snapshots to snapshots.g2", + records); + message_line(buf); + } +} + +/**************************************************************************** + * read_snapshot + * + * VERY primitive right now - not endian or version independent, and only reads + * from "snapshots.g2" in the current directory + ****************************************************************************/ +static void read_snapshot(void) +{ + FILE *file; + snapshot_t *snap, *next_snap; + snapshot_t *new_snaps = NULL; + char *error = NULL; + int len, i, records = 0; + pid_data_t *pp; + + file = fopen("snapshots.g2", "r"); + if (file == NULL) { + error = "Unable to open snapshots.g2"; + } + + /* + * Read in the snapshots and link them together. We insert them backwards, + * but that's tolerable. If the data is in anyway not what we expect, we'll + * probably crash. Sorry. + */ + while (!error && !feof(file)) { + snap = g_malloc(sizeof(*snap)); + snap->pidvec = NULL; /* so we can free this if there's an error */ + + len = fread(&snap->geometry, sizeof(snap->geometry), 1, file); + if (len == 0) { + /* EOF */ + g_free(snap); + break; + } else { + /* insert into list straight away */ + snap->next = new_snaps; + new_snaps = snap; + } + if (len != 1) { + error = "Problem reading first item from file"; + break; + } + if (fread(&snap->show_event, sizeof(snap->show_event), 1, file) != 1) { + error = "Problem reading second item from file"; + break; + } + len = sizeof(pid_sort_t) * g_npids; + snap->pidvec = g_malloc(len); + if (fread(snap->pidvec, len, 1, file) != 1) { + error = "Problem reading third item from file"; + break; + } + if (fread(&snap->vscroll_value, + sizeof(snap->vscroll_value), 1, file) != 1 || + fread(&snap->summary_mode, + sizeof(snap->summary_mode), 1, file) != 1 || + fread(&snap->color_mode, + sizeof(snap->color_mode), 1, file) != 1) { + error = "Problem reading final items from file"; + break; + } + + /* + * Fix up the pointers from the sorted pid vector back into our pid + * data objects, by walking the linked list of pid_data_t objects for + * every one looking for a match. This is O(n^2) grossness, but in real + * life there aren't that many pids, and it seems zippy enough. + */ + for (i = 0; i < g_npids; i++) { + for (pp = g_pid_data_list; pp != NULL; pp = pp->next) { + if (pp->pid_value == snap->pidvec[i].pid_value) { + break; + } + } + if (pp != NULL) { + snap->pidvec[i].pid = pp; + } else { + error = "Snapshot file referenced unknown pids"; + break; + } + } + + records++; + } + + if (!error) { + if (fclose(file)) { + error = "Unable to close file"; + } + } + + if (error) { + /* + * Problem - clear up any detritus + */ + infobox(error, strerror(errno)); + for (snap = new_snaps; snap != NULL; snap = next_snap) { + next_snap = snap->next; + g_free(snap); + g_free(snap->pidvec); + } + } else { + /* + * Success! trash the old snapshots and replace with the new + */ + for (snap = s_snapshots; snap != NULL; snap = next_snap) { + next_snap = snap->next; + g_free(snap->pidvec); + g_free(snap); + } + + s_cursnap = s_snapshots = new_snaps; + } + + if (error) { + infobox(error, strerror(errno)); + } else { + char buf[64]; + snprintf(buf, sizeof(buf), + "Read %d snapshots from snapshots.g2", records); + message_line(buf); + } +} + +/**************************************************************************** +* set_color +* +* Set the color for the specified pid_index, or COLOR_DEFAULT to return it +* to the usual black. +****************************************************************************/ +#define COLOR_DEFAULT (-1) +static void set_color(int pid_index) +{ + if (pid_index == COLOR_DEFAULT || !color_mode) { + gdk_gc_set_foreground(da->style->black_gc, &fg_black); + } else { + gdk_gc_set_foreground(da->style->black_gc, + &s_color[g_pids[pid_index].color_index]); + } +} + +/**************************************************************************** +* toggle_event_select +****************************************************************************/ + +static void toggle_event_select(GdkEventButton *event, v1_geometry_t *vp) +{ + int pid_index, start_index; + int x, y; + GdkRectangle *rp; + GdkRectangle hit_rect; + GdkRectangle dummy; + event_t *ep; + event_def_t *edp; + char tmpbuf [1024]; + double time_per_pixel; + + if (g_nevents == 0) + return; + + time_per_pixel = dtime_per_pixel(vp); + + start_index = find_event_index (vp->minvistime); + + /* Too far right? */ + if (start_index >= g_nevents) + return; + + /* + * To see if the mouse hit a visible event, use a variant + * of the event display loop. + */ + + hit_rect.x = (int)event->x; + hit_rect.y = (int)event->y; + hit_rect.width = 1; + hit_rect.height = 1; + + ep = (g_events + start_index); + + while ((ep->time < vp->maxvistime) && + (ep < (g_events + g_nevents))) { + pid_index = ep->pid->pid_index; + + /* First filter: pid out of range */ + if ((pid_index < vp->first_pid_index) || + (pid_index >= vp->first_pid_index + vp->npids)) { + ep++; + continue; + } + + /* Second filter: event hidden */ + edp = find_event_definition (ep->code); + if (!edp->selected) { + ep++; + continue; + } + + /* + * At this point, we know that the point is at least on the + * screen. See if the mouse hit within the bounding box + */ + + /* + * $$$$ maybe keep looping until off the edge, + * maintain a "best hit", then declare that one the winner? + */ + + pid_index -= vp->first_pid_index; + + y = pid_index*vp->strip_height + vp->event_offset; + + x = vp->pid_ax_width + + (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel); + + /* Perhaps we're trying to toggle the detail box? */ + if (ep->flags & EVENT_FLAG_SELECT) { + /* Figure out the dimensions of the detail box */ + format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp); + rp = tbox(tmpbuf, x, y - vp->pop_offset, TBOX_GETRECT_BOXED); + if (gdk_rectangle_intersect(rp, &hit_rect, &dummy)) { + ep->flags &= ~EVENT_FLAG_SELECT; + view1_display_when_idle(); + break; + } + } + + sprintf(tmpbuf, "%ld", ep->code); + + /* Figure out the dimensions of the regular box */ + rp = tbox(tmpbuf, x, y, TBOX_GETRECT_EVENT); + + if (gdk_rectangle_intersect(rp, &hit_rect, &dummy)) { + /* we hit the rectangle. */ + if (ep->flags & EVENT_FLAG_SELECT) { + ep->flags &= ~EVENT_FLAG_SELECT; + view1_display_when_idle(); + break; + } else { + set_color(ep->pid->pid_index); + + /* It wasn't selected, so put up the detail box */ + format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp); + tbox(tmpbuf, x, y - vp->pop_offset, TBOX_DRAW_BOXED); + line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK); + ep->flags |= EVENT_FLAG_SELECT; + ep->flags &= ~EVENT_FLAG_SEARCHRSLT; + s_last_selected_event = ep; + } + break; + } + ep++; + } +} + +/**************************************************************************** +* move_current_track +****************************************************************************/ + +typedef enum { MOVE_TOP, MOVE_BOTTOM } move_type; + +static void move_current_track(GdkEventButton *event, + v1_geometry_t *vp, + move_type type) +{ + int i; + int pid_index; + int y, delta_y; + pid_sort_t *new_pidvec; + pid_sort_t *psp; + pid_sort_t *pold, *pnew; + pid_data_t *pp; + + if (g_nevents == 0) + return; + + /* Scan pid/track axis locations, looking for a match */ + for (i = 0; i < vp->npids; i++) { + y = i*vp->strip_height + vp->pid_ax_offset; + delta_y = y - event->y; + if (delta_y < 0) + delta_y = -delta_y; + if (delta_y < 10) { + goto found; + } + + } + infobox("NOTE", "\nNo PID/Track In Range\nPlease Try Again"); + return; + + found: + pid_index = i + vp->first_pid_index; + + new_pidvec = g_malloc(sizeof(pid_sort_t)*g_npids); + pold = g_pids; + pnew = new_pidvec; + + if (type == MOVE_TOP) { + /* move to top */ + *pnew++ = g_pids[pid_index]; + for (i = 0; i < pid_index; i++) + *pnew++ = *pold++; + pold++; + i++; + for (; i < g_npids; i++) + *pnew++ = *pold++; + } else { + /* move to bottom */ + for (i = 0; i < pid_index; i++) + *pnew++ = *pold++; + pold++; + i++; + for (; i < g_npids; i++) + *pnew++ = *pold++; + *pnew = g_pids[pid_index]; + } + + g_free(g_pids); + g_pids = new_pidvec; + + /* + * Revert the pid_index mapping to an identity map, + */ + psp = g_pids; + + for (i = 0; i < g_npids; i++) { + pp = psp->pid; + pp->pid_index = i; + psp++; + } + view1_display_when_idle(); +} + +/**************************************************************************** +* zoom_event +* Process a zoom gesture. The use of doubles is required to avoid +* truncating the various variable values, which in turn would lead to +* some pretty random-looking zoom responses. +****************************************************************************/ + +void zoom_event(GdkEventButton *e1, GdkEventButton *e2, v1_geometry_t *vp) +{ + double xrange; + double time_per_pixel; + double width_in_pixels; + double center_on_time, width_in_time; + double center_on_pixel; + + /* + * Clip the zoom area to the event display area. + * Otherwise, center_on_time - width_in_time is in hyperspace + * to the left of zero + */ + + if (e1->x < vp->pid_ax_width) + e1->x = vp->pid_ax_width; + + if (e2->x < vp->pid_ax_width) + e2->x = vp->pid_ax_width; + + if (e2->x == e1->x) + goto loser_zoom_repaint; + + xrange = (double) (e2->x - e1->x); + if (xrange < 0.00) + xrange = -xrange; + + /* Actually, width in pixels of half the zoom area */ + width_in_pixels = xrange / 2.00; + time_per_pixel = dtime_per_pixel(vp); + width_in_time = width_in_pixels * time_per_pixel; + + /* Center the screen on the center of the zoom area */ + center_on_pixel = (double)((e2->x + e1->x) / 2.00) - + (double)vp->pid_ax_width; + center_on_time = center_on_pixel*time_per_pixel + (double)vp->minvistime; + + /* + * Transform back to 64-bit integer microseconds, reset the + * scrollbar, schedule a repaint. + */ + vp->minvistime = (ulonglong)(center_on_time - width_in_time); + vp->maxvistime = (ulonglong)(center_on_time + width_in_time); + +loser_zoom_repaint: + recompute_hscrollbar(); + + view1_display_when_idle(); +} + +/**************************************************************************** +* scroll_y +* +* Scroll up or down by the specified delta +* +****************************************************************************/ +static void scroll_y(int delta) +{ + int new_index = s_v1->first_pid_index + delta; + if (new_index + s_v1->npids > g_npids) + new_index = g_npids - s_v1->npids; + if (new_index < 0) + new_index = 0; + + if (new_index != s_v1->first_pid_index) { + s_v1->first_pid_index = new_index; + GTK_ADJUSTMENT(s_view1_vsadj)->value = (gdouble)new_index; + gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); + view1_display_when_idle(); + } +} + +/**************************************************************************** +* view1_handle_key_press_event +* Relevant definitions in: /usr/include/gtk-1.2/gdk/gdktypes.h +* +* This routine implements hotkeys for the Quake generation: +* +* W - zoom in +* S - zoom out +* A - pan left +* D - pan right +* R - pan up +* F - pan down +* T - more traces +* G - fewer traces +* +* E - toggle summary mode +* C - toggle color mode +* +* X - take snapshot +* Z - next snapshot +* P - persist snapshots to file +* L - load snapshots from file +* +* ctrl-Q - exit +* +****************************************************************************/ +gint +view1_handle_key_press_event (GtkWidget *widget, GdkEventKey *event) +{ + long long delta; + + switch (event->keyval) { + case GDK_w: // zoom in + view1_button_click_callback(NULL, (gpointer)ZOOMIN_BUTTON); + break; + + case GDK_s: // zoom out + view1_button_click_callback(NULL, (gpointer)ZOOMOUT_BUTTON); + break; + + case GDK_a: // pan left + delta = (s_v1->maxvistime - s_v1->minvistime) / 6; + if (s_v1->minvistime < delta) { + delta = s_v1->minvistime; + } + s_v1->minvistime -= delta; + s_v1->maxvistime -= delta; + recompute_hscrollbar(); + break; + + case GDK_d: // pan right + delta = (s_v1->maxvistime - s_v1->minvistime) / 6; + if (s_v1->maxvistime + delta > g_events[g_nevents - 1].time) { + /* + * @@@ this doesn't seem to quite reach the far right hand + * side correctly - not sure why. + */ + delta = g_events[g_nevents - 1].time - s_v1->maxvistime; + } + s_v1->minvistime += delta; + s_v1->maxvistime += delta; + recompute_hscrollbar(); + break; + + case GDK_r: // pan up + scroll_y(-1); + break; + + case GDK_f: // pan down + scroll_y(+1); + break; + + case GDK_t: // fewer tracks + view1_button_click_callback(NULL, (gpointer)LESS_TRACES_BUTTON); + break; + + case GDK_g: // more tracks + view1_button_click_callback(NULL, (gpointer)MORE_TRACES_BUTTON); + break; + + case GDK_e: // toggle summary mode + view1_button_click_callback + (NULL, (gpointer)(unsigned long long) + (summary_mode ? NOSUMMARY_BUTTON : SUMMARY_BUTTON)); + break; + + case GDK_c: // toggle color mode + color_mode ^= 1; + view1_display_when_idle(); + break; + + case GDK_p: // persist snapshots + write_snapshot(); + break; + + case GDK_l: // load snapshots + read_snapshot(); + break; + + case GDK_x: // take snapshot + view1_button_click_callback(NULL, (gpointer)SNAP_BUTTON); + break; + + case GDK_z: // next snapshot + view1_button_click_callback(NULL, (gpointer)NEXT_BUTTON); + break; + + case GDK_q: // ctrl-q is exit + if (event->state & GDK_CONTROL_MASK) { + gtk_main_quit(); + } + break; + } + return TRUE; +} + +/**************************************************************************** +* button_press_event +* Relevant definitions in: /usr/include/gtk-1.2/gdk/gdktypes.h +* +* This routine implements three functions: zoom-to-area, time ruler, and +* show/hide event detail popup. +* +* The left mouse button (button 1) has two simultaneous functions: event +* detail popup, and zoom-to-area. If the press and release events occur +* within a small delta-x, it's a detail popup event. Otherwise, it's +* an area zoom. +* +* The right mouse button (button 3) implements the time ruler. +****************************************************************************/ + +static gint +button_press_event (GtkWidget *widget, GdkEventButton *event) +{ + static GdkEventButton press1_event; + static boolean press1_valid; + static GdkEventButton press3_event; + static guint32 last_truler_time; + static boolean press3_valid; + static boolean zoom_bar_up; + int time_ax_y, xdelta; + char tmpbuf [128]; + double time_per_pixel; + + time_ax_y = 0; + + switch(event->type) { + case GDK_BUTTON_PRESS: + /* Capture the appropriate starting point */ + if (event->button == 1) { + press1_valid = TRUE; + press1_event = *event; + return(TRUE); + } + if (event->button == 3) { + press3_valid = TRUE; + press3_event = *event; + return(TRUE); + } + return(TRUE); + + case GDK_BUTTON_RELEASE: + /* Time ruler */ + if (press3_valid) { + press3_valid = FALSE; + /* Fix the cursor, and repaint the screen from scratch */ + gdk_window_set_cursor (da->window, norm_cursor); + view1_display_when_idle(); + return(TRUE); + } + /* Event select / zoom-to-area */ + if (press1_valid) { + press1_valid = FALSE; + xdelta = (int)(press1_event.x - event->x); + if (xdelta < 0) + xdelta = -xdelta; + + /* is the mouse more or less where it started? */ + if (xdelta < 10) { + /* Control-left-mouse => sink the track */ + /* Shift-left-mouse => raise the track */ + if ((press1_event.state & GDK_CONTROL_MASK) == + GDK_CONTROL_MASK) { + move_current_track(event, s_v1, MOVE_BOTTOM); + } else if ((press1_event.state & GDK_SHIFT_MASK) == + GDK_SHIFT_MASK) { + move_current_track(event, s_v1, MOVE_TOP); + } else { + /* No modifiers: toggle the event */ + toggle_event_select(event, s_v1); + } + /* Repaint to get rid of the zoom bar */ + if (zoom_bar_up) { + /* Fix the cursor and leave. No zoom */ + gdk_window_set_cursor (da->window, norm_cursor); + zoom_bar_up = FALSE; + break; + } + } else { /* mouse moved enough to zoom */ + zoom_event(&press1_event, event, s_v1); + gdk_window_set_cursor (da->window, norm_cursor); + zoom_bar_up = FALSE; + } + } else if (event->button == 4) { + /* scroll wheel up */ + scroll_y(event->state & GDK_SHIFT_MASK ? -10 : -1); + } else if (event->button == 5) { + /* scroll wheel down */ + scroll_y(event->state & GDK_SHIFT_MASK ? +10 : +1); + } + return(TRUE); + + case GDK_MOTION_NOTIFY: + /* Button one followed by motion: draw zoom fence and fix cursor */ + if (press1_valid) { + /* Fence, cursor already set */ + if (zoom_bar_up) + return(TRUE); + + xdelta = (int)(press1_event.x - event->x); + if (xdelta < 0) + xdelta = -xdelta; + + /* Haven't moved enough to declare a zoom sequence yet */ + if (xdelta < 10) + return(TRUE); + + /* Draw the zoom fence, use the key-down X coordinate */ + time_ax_y = s_v1->npids * s_v1->strip_height + s_v1->pid_ax_offset; + + line((int)(press1_event.x), s_v1->pop_offset, + (int)(press1_event.x), time_ax_y, LINE_DRAW_BLACK); + tbox("Zoom From Here...", (int)(press1_event.x), s_v1->pop_offset, + TBOX_DRAW_BOXED); + gdk_window_set_cursor(da->window, zi_cursor); + zoom_bar_up = TRUE; + return(TRUE); + } + if (press3_valid) { + double nsec; + + gdk_window_set_cursor(da->window, zi_cursor); + + /* + * Some filtration is needed on Solaris, or the server will hang + */ + if (event->time - last_truler_time < 75) + return(TRUE); + + last_truler_time = event->time; + + line((int)(press3_event.x), s_v1->pop_offset, + (int)(press3_event.x), time_ax_y, LINE_DRAW_BLACK); + + xdelta = (int)(press3_event.x - event->x); + if (xdelta < 0) + xdelta = -xdelta; + + time_per_pixel = ((double)(s_v1->maxvistime - s_v1->minvistime)) / + ((double)(s_v1->total_width - s_v1->pid_ax_width)); + + time_ax_y = s_v1->npids * s_v1->strip_height + s_v1->pid_ax_offset; + + line((int)(press3_event.x), s_v1->pop_offset, + (int)(press3_event.x), time_ax_y, LINE_DRAW_BLACK); + /* + * Note: use a fixed-width format so it looks like we're + * erasing and redrawing the box. + */ + nsec = ((double)xdelta)*time_per_pixel; + if (nsec >1e9) { + sprintf(tmpbuf, "%8.3f sec ", nsec/1e9); + } else if (nsec > 1e6) { + sprintf(tmpbuf, "%8.3f msec", nsec/1e6); + } else if (nsec > 1e3) { + sprintf(tmpbuf, "%8.3f usec", nsec/1e3); + } else { + sprintf(tmpbuf, "%8.0f nsec", nsec); + } + tbox(tmpbuf, (int)(press3_event.x), s_v1->pop_offset, + TBOX_DRAW_BOXED); + return(TRUE); + } + + default: + break; +#ifdef DEBUG + g_print("button:\ttype = %d\n", event->type); + g_print("\twindow = 0x%x\n", event->window); + g_print("\tsend_event = %d\n", event->send_event); + g_print("\ttime = %d\n", event->time); + g_print("\tx = %6.2f\n", event->x); + g_print("\ty = %6.2f\n", event->y); + g_print("\tpressure = %6.2f\n", event->pressure); + g_print("\txtilt = %6.2f\n", event->xtilt); + g_print("\tytilt = %6.2f\n", event->ytilt); + g_print("\tstate = %d\n", event->state); + g_print("\tbutton = %d\n", event->button); + g_print("\tsource = %d\n", event->source); + g_print("\tdeviceid = %d\n", event->deviceid); + g_print("\tx_root = %6.2f\n", event->x_root); + g_print("\ty_root = %6.2f\n", event->y_root); + return(TRUE); +#endif + } + + view1_display_when_idle(); + + return(TRUE); +} + +/**************************************************************************** +* configure_event +* Happens when the window manager resizes the viewer's main window. +****************************************************************************/ + +static gint +configure_event (GtkWidget *widget, GdkEventConfigure *event) +{ + /* Toss the previous drawing area backing store pixmap */ + if (pm) + gdk_pixmap_unref(pm); + + /* Create a new pixmap, paint it */ + pm = gdk_pixmap_new(widget->window, + widget->allocation.width, + widget->allocation.height, + -1); + gdk_draw_rectangle (pm, + widget->style->white_gc, + TRUE, + 0, 0, + widget->allocation.width, + widget->allocation.height); + + /* Reset the view geometry parameters, as required */ + s_v1->total_width = widget->allocation.width; + s_v1->total_height = widget->allocation.height; + s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) / + s_v1->strip_height; + + /* Schedule a repaint */ + view1_display_when_idle(); + return(TRUE); +} + +/**************************************************************************** +* expose_event +* Use backing store to fix the screen. +****************************************************************************/ +static gint expose_event (GtkWidget *widget, GdkEventExpose *event) +{ + gdk_draw_pixmap(widget->window, + widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + pm, + event->area.x, event->area.y, + event->area.x, event->area.y, + event->area.width, event->area.height); + + return(FALSE); +} + +/**************************************************************************** +* event_search_internal +* This routine searches forward from s_srchindex, looking for s_srchcode; +* wraps at the end of the buffer. +****************************************************************************/ + +boolean event_search_internal (void) +{ + event_t *ep; + int i; + int index; + int pid_index; + boolean full_redisplay = FALSE; + ulonglong current_width; + char tmpbuf [64]; + + /* No events yet? Act like the search worked, to avoid a loop */ + if (g_nevents == 0) + return(TRUE); + + ep = (g_events + s_srchindex); + ep->flags &= ~EVENT_FLAG_SEARCHRSLT; + + /* + * Assume the user wants to search [plus or minus] + * from where they are. + */ +#ifdef notdef + if (ep->time < s_v1->minvistime) + s_srchindex = find_event_index (s_v1->minvistime); +#endif + + for (i = 1; i <= g_nevents; i++) { + index = (srch_chase_dir == SRCH_CHASE_BACKWARD) ? + (s_srchindex - i) % g_nevents : + (i + s_srchindex) % g_nevents; + + ep = (g_events + index); + + if (ep->code == s_srchcode) { + if (s_srchfail_up) + message_line(""); + s_srchindex = index; + pid_index = ep->pid->pid_index; + + /* Need a vertical scroll? */ + if ((pid_index < s_v1->first_pid_index) || + (pid_index >= s_v1->first_pid_index + s_v1->npids)) { + if (pid_index > (g_npids - s_v1->npids)) + pid_index = (g_npids - s_v1->npids); + s_v1->first_pid_index = pid_index; + GTK_ADJUSTMENT(s_view1_vsadj)->value = + (gdouble)s_v1->first_pid_index; + gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); + full_redisplay = TRUE; + } + + /* Need a horizontal scroll? */ + if (ep->time < s_v1->minvistime || ep->time > s_v1->maxvistime) { + current_width = (s_v1->maxvistime - s_v1->minvistime); + if (ep->time < ((current_width+1) / 2)) { + s_v1->minvistime = 0ll; + s_v1->maxvistime = current_width; + } else { + s_v1->minvistime = ep->time - ((current_width+1)/2); + s_v1->maxvistime = ep->time + ((current_width+1)/2); + } + recompute_hscrollbar(); + full_redisplay = TRUE; + } + ep->flags |= EVENT_FLAG_SEARCHRSLT; + full_redisplay = TRUE; + +#ifdef NOTDEF + if (!full_redisplay){ + if (!s_result_up) { + s_result_up = TRUE; + time_per_pixel = dtime_per_pixel(s_v1); + + y = pid_index*s_v1->strip_height + s_v1->event_offset; + x = s_v1->pid_ax_width + + (int)(((double)(ep->time - s_v1->minvistime)) / + time_per_pixel); + sprintf(tmpbuf, "SEARCH RESULT"); + tbox(tmpbuf, x, y - s_v1->pop_offset, TBOX_DRAW_BOXED); + line(x, y-s_v1->pop_offset, x, y, LINE_DRAW_BLACK); + } else { + full_redisplay = TRUE; + } + } +#endif + + if (full_redisplay) + view1_display_when_idle(); + return(TRUE); + } + } + sprintf (tmpbuf, "Search for event %ld failed...\n", s_srchcode); + message_line(tmpbuf); + s_srchfail_up = TRUE; + return(TRUE); +} + +/**************************************************************************** +* event_search_callback +****************************************************************************/ + +boolean event_search_callback (char *s) +{ + /* No events yet? Act like the search worked, to avoid a loop */ + if (g_nevents == 0) + return(TRUE); + + s_srchcode = atol(s); + + if (s_srchcode == 0) + return(FALSE); + + return(event_search_internal()); +} + +/**************************************************************************** +* event_search +****************************************************************************/ + +static void event_search (void) +{ + modal_dialog ("Event Search: Please Enter Event Code", + "Invalid: Please Reenter Event Code", NULL, + event_search_callback); +} + +/**************************************************************************** +* init_track_colors +****************************************************************************/ +static void init_track_colors(void) +{ + int i; + unsigned hash; + char *label_char; + unsigned RGB[3]; + gboolean dont_care[g_npids]; + + /* + * If we've already allocated the colors once, then in theory we should + * just be able to re-order the GCs already created to match the new track + * order; the track -> color mapping doesn't currently change at runtime. + * However, it's easier just to allocate everything from fresh. As a nod in + * the direction of politeness towards our poor abused X server, we at + * least mop up the previously allocated GCs first, although in practice + * even omitting this didn't seem to cause a problem. + */ + if (s_color != NULL ) { + gdk_colormap_free_colors(gtk_widget_get_colormap(da), + s_color, g_npids); + memset(s_color, 0, sizeof(GdkColor) * g_npids); + } else { + /* + * First time through: allocate the array to hold the GCs. + */ + s_color = g_malloc(sizeof(GdkColor) * g_npids); + } + + /* + * Go through and assign a color for each track. + */ + for (i = 0; i < g_npids; i++) { + /* + * We compute the color from a hash of the thread name. That way we get + * a distribution of different colors, and the same thread has the same + * color across multiple data sets. Unfortunately, even though the + * process name and thread id are invariant across data sets, the + * process id isn't, so we want to exclude that from the hash. Since + * the pid appears in parentheses after the process name and tid, we + * can just stop at the '(' character. + * + * We could create a substring and use the CLIB Jenkins hash, but given + * we're hashing ascii data, a suitable Bernstein hash is pretty much + * just as good, and it's easiest just to compute it inline. + */ + label_char = get_track_label(g_pids[i].pid_value); + hash = 0; + while (*label_char != '\0' && *label_char != '(') { + hash = hash * 33 + *label_char++; + } + hash += hash >> 5; /* even out the lower order bits a touch */ + + /* + * OK, now we have our hash. We get the color by using the first three + * bytes of the hash for the RGB values (expanded from 8 to 16 bits), + * and then use the fourth byte to choose one of R, G, B and mask this + * one down. This ensures the color can't be too close to white and + * therefore hard to see. + * + * We also drop the top bit of the green, since bright green on its own + * is hard to see against white. Generally we err on the side of + * keeping it dark, rather than using the full spectrum of colors. This + * does result in something of a preponderance of muddy colors and a + * bit of a lack of cheery bright ones, but at least you can read + * everything. It would be nice to do better. + */ + RGB[0] = (hash & 0xff000000) >> 16; + RGB[1] = (hash & 0x007f0000) >> 8; + RGB[2] = (hash & 0x0000ff00); + RGB[hash % 3] &= 0x1fff; + + { + GdkColor color = {0, RGB[0], RGB[1], RGB[2]}; + s_color[i] = color; + g_pids[i].color_index = i; + } + } + + /* + * Actually allocate the colors in one bulk operation. We ignore the return + * values. + */ + gdk_colormap_alloc_colors(gtk_widget_get_colormap(da), + s_color, g_npids, FALSE, TRUE, dont_care); +} + + +/**************************************************************************** +* chase_event_etc +* Reorder the pid_index fields so the viewer "chases" the last selected +* event. +****************************************************************************/ + +static void chase_event_etc(enum chase_mode mode) +{ + pid_sort_t *psp, *new_pidvec; + pid_data_t *pp; + event_t *ep; + int pids_mapped; + ulong code_to_chase; + ulong datum_to_chase; + ulong pid_to_chase; + int i; + int winner; + + if (!s_last_selected_event) { + infobox("No selected event", + "\nPlease select an event and try again...\n"); + return; + } + + /* Clear all index assignments */ + psp = g_pids; + for (i = 0; i < g_npids; i++) { + pp = psp->pid; + pp->pid_index = 0xFFFFFFFF; + psp++; + } + + ep = s_last_selected_event; + code_to_chase = ep->code; + datum_to_chase = ep->datum; + pid_to_chase = ep->pid->pid_value; + pids_mapped = 0; + new_pidvec = g_malloc(sizeof(pid_sort_t)*g_npids); + + while (1) { + if (srch_chase_dir == SRCH_CHASE_FORWARD) { + if (ep >= g_events + g_nevents) + break; + } else { + if (ep < g_events) + break; + } + + winner = 0; + switch(mode) { + case CHASE_EVENT: + if (ep->code == code_to_chase) { + winner = 1; + } + break; + + case CHASE_DATUM: + if (ep->datum == datum_to_chase) { + winner = 1; + } + break; + + case CHASE_TRACK: + if (ep->pid->pid_value == pid_to_chase) { + winner = 1; + } + break; + + default: + infobox("BUG", "unknown mode in chase_event_etc\n"); + break; + } + + if (winner) { + if (ep->pid->pid_index == 0xFFFFFFFF) { + ep->pid->pid_index = pids_mapped; + new_pidvec[pids_mapped].pid = ep->pid; + new_pidvec[pids_mapped].pid_value = ep->pid->pid_value; + new_pidvec[pids_mapped].color_index = 0; + pids_mapped++; + if (pids_mapped == g_npids) + break; + } + } + if (srch_chase_dir == SRCH_CHASE_FORWARD) + ep++; + else + ep--; + } + + /* Pass 2, first-to-last, to collect stragglers */ + ep = g_events; + + while (ep < g_events + g_nevents) { + if (ep->pid->pid_index == 0xFFFFFFFF) { + ep->pid->pid_index = pids_mapped; + new_pidvec[pids_mapped].pid = ep->pid; + new_pidvec[pids_mapped].pid_value = ep->pid->pid_value; + new_pidvec[pids_mapped].color_index = 0; + pids_mapped++; + if (pids_mapped == g_npids) + break; + } + ep++; + } + + if (pids_mapped != g_npids) { + infobox("BUG", "\nDidn't map all pids in chase_event_etc\n"); + } + + g_free (g_pids); + g_pids = new_pidvec; + + /* + * The new g_pids vector contains the "chase" sort, so we revert + * the pid_index mapping to an identity map + */ + psp = g_pids; + + for (i = 0; i < g_npids; i++) { + pp = psp->pid; + pp->pid_index = i; + psp++; + } + + /* AutoScroll the PID axis so we show the first "chased" event */ + s_v1->first_pid_index = 0; + GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00; + gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); + init_track_colors(); + view1_display_when_idle(); +} + +/**************************************************************************** +* unchase_event_etc +* Copy g_original_pids to g_pids, revert index mapping +****************************************************************************/ +static void unchase_event_etc(void) +{ + int i; + pid_sort_t *psp; + pid_data_t *pp; + + memcpy (g_pids, g_original_pids, sizeof(pid_sort_t)*g_npids); + + /* Fix the pid structure index mappings */ + psp = g_pids; + + for (i = 0; i < g_npids; i++) { + pp = psp->pid; + pp->pid_index = i; + psp++; + } + + /* Scroll PID axis to the top */ + s_v1->first_pid_index = 0; + GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00; + gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); + init_track_colors(); + view1_display_when_idle(); +} + +/**************************************************************************** +* print_ps_header +* To fit a reasonable-sized landscape mode plot onto letter-size paper, +* scale everything by .75. +****************************************************************************/ + +static void print_ps_header (v1_geometry_t *vp, char *filename) +{ + time_t now; + + now = time(0); + + fprintf(s_printfp, "%%%%!PS-Adobe-3.0 EPSF-3.0\n"); + fprintf(s_printfp, "%%%%Creator: G2 Event Viewer\n"); + fprintf(s_printfp, "%%%%Title: %s\n", filename); + fprintf(s_printfp, "%%%%CreationDate: %s", ctime(&now)); + fprintf(s_printfp, "%%%%DocumentData: Clean7Bit\n"); + fprintf(s_printfp, "%%%%Origin: 0 0\n"); + fprintf(s_printfp, "%%%%BoundingBox: 0 0 %d %d\n", vp->total_height, + vp->total_width); + fprintf(s_printfp, "%%%%LanguageLevel: 2\n"); + fprintf(s_printfp, "%%%%Pages: 1\n"); + fprintf(s_printfp, "%%%%Page: 1 1\n"); + fprintf(s_printfp, "%%%%EOF\n"); + fprintf(s_printfp, "/Times-Roman findfont\n"); + fprintf(s_printfp, "12 scalefont\n"); + fprintf(s_printfp, "setfont\n"); + fprintf(s_printfp, ".75 .75 scale\n"); +} + +/**************************************************************************** +* xrt +* Xcoordinate rotate and translate. We need to emit postscript that +* has a reasonable aspect ratio for printing. To do that, we rotate the +* intended picture by 90 degrees, using the standard 2D rotation +* formula: +* +* Xr = x*cos(theta) - y*sin(theta); +* Yr = x*sin(theta) + y*cos(theta); +* +* If we let theta = 90, this reduces to +* Xr = -y +* Yr = x +* +* Translate back to the origin in X by adding Ymax, yielding +* Xrt = Ymax - y +****************************************************************************/ + +static inline int xrt(int x, int y) +{ + return (s_v1->total_height - y); +} + +static inline int yrt(int x, int y) +{ + return(x); +} + +/**************************************************************************** +* print_screen_callback +****************************************************************************/ + +static boolean print_screen_callback(char *filename) +{ + s_printfp = fopen (filename, "wt"); + + if (s_printfp == NULL) + return(FALSE); + + /* + * This variable allows us to magically turn the view1 display + * code into a print-driver, with a minimum of fuss. The idea is to + * magically change TBOX_DRAW_XXX into TBOX_PRINT_XXX by adding + * the required value, aka s_print_offset. + * Make sure to fix g2.h if you mess here, or vice versa. + */ + s_print_offset = TBOX_PRINT_PLAIN - TBOX_DRAW_PLAIN; + + print_ps_header(s_v1, filename); + + display_pid_axis(s_v1); + display_event_data(s_v1); + display_time_axis(s_v1); + + fclose (s_printfp); + s_printfp = 0; + s_print_offset = 0; + + /* For tactile feedback */ + view1_display_when_idle(); + return(TRUE); +} + +/**************************************************************************** +* view1_button_click_callback +****************************************************************************/ + +static void view1_button_click_callback(GtkButton *item, gpointer data) +{ + enum view1_button_click click = (enum view1_button_click) data; + event_t *ep; + ulonglong event_incdec; + ulonglong current_width; + ulonglong zoom_delta; + + + current_width = s_v1->maxvistime - s_v1->minvistime; + event_incdec = (current_width) / 3; + + if (event_incdec == 0LL) + event_incdec = 1; + + zoom_delta = (s_v1->maxvistime - s_v1->minvistime) / 6; + + switch(click) { + case TOP_BUTTON: + /* First PID to top of window */ + s_v1->first_pid_index = 0; + GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00; + gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); + break; + + case BOTTOM_BUTTON: + s_v1->first_pid_index = g_npids - s_v1->npids; + if (s_v1->first_pid_index < 0) + s_v1->first_pid_index = 0; + GTK_ADJUSTMENT(s_view1_vsadj)->value = (gdouble)s_v1->first_pid_index; + gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); + break; + + case SNAP_BUTTON: + add_snapshot(); + break; + + case NEXT_BUTTON: + next_snapshot(); + break; + + case DEL_BUTTON: + del_snapshot(); + break; + + case CHASE_EVENT_BUTTON: + chase_event_etc(CHASE_EVENT); + break; + + case CHASE_DATUM_BUTTON: + chase_event_etc(CHASE_DATUM); + break; + + case CHASE_TRACK_BUTTON: + chase_event_etc(CHASE_TRACK); + break; + + case UNCHASE_BUTTON: + unchase_event_etc(); + break; + + case START_BUTTON: + start_button: + s_v1->minvistime = 0LL; + s_v1->maxvistime = current_width; + recompute_hscrollbar(); + break; + + case ZOOMIN_BUTTON: + s_v1->minvistime += zoom_delta; + s_v1->maxvistime -= zoom_delta; + recompute_hscrollbar(); + break; + + case SEARCH_AGAIN_BUTTON: + if (s_srchcode) { + event_search_internal(); + break; + } + /* NOTE FALLTHROUGH */ + + case SEARCH_BUTTON: + event_search(); + break; + + case ZOOMOUT_BUTTON: + if (zoom_delta == 0LL) + zoom_delta = 1; + + if (s_v1->minvistime >= zoom_delta) { + s_v1->minvistime -= zoom_delta; + s_v1->maxvistime += zoom_delta; + } else { + s_v1->minvistime = 0; + s_v1->maxvistime += zoom_delta*2; + } + + if ((s_v1->maxvistime - s_v1->minvistime) * 8 > + g_events[g_nevents-1].time * 9) { + s_v1->minvistime = 0; + s_v1->maxvistime = g_events[g_nevents-1].time * 9 / 8; + } + recompute_hscrollbar(); + break; + + case END_BUTTON: + ep = (g_events + g_nevents - 1); + s_v1->maxvistime = ep->time + event_incdec/3; + s_v1->minvistime = s_v1->maxvistime - current_width; + if (s_v1->minvistime > s_v1->maxvistime) + goto start_button; + recompute_hscrollbar(); + break; + + case MORE_TRACES_BUTTON: + /* Reduce the strip height to fit more traces on screen */ + s_v1->strip_height -= 1; + + if (s_v1->strip_height < 1) { + s_v1->strip_height = 1; + } + + /* Recalculate the number of strips on the screen */ + s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) / + s_v1->strip_height; + recompute_vscrollbar(); + break; + + case LESS_TRACES_BUTTON: + /* Increase the strip height to fit fewer on the screen */ + s_v1->strip_height += 1; + if (s_v1->strip_height > 80) { + s_v1->strip_height = 80; + } + + /* Recalculate the number of strips on the screen */ + s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) / + s_v1->strip_height; + recompute_vscrollbar(); + break; + + case FORWARD_BUTTON: + srch_chase_dir = SRCH_CHASE_FORWARD; + gtk_widget_hide (s_view1_forward_button); + gtk_widget_show (s_view1_backward_button); + break; + + case BACKWARD_BUTTON: + srch_chase_dir = SRCH_CHASE_BACKWARD; + gtk_widget_show (s_view1_forward_button); + gtk_widget_hide (s_view1_backward_button); + break; + + case SUMMARY_BUTTON: + summary_mode = TRUE; + gtk_widget_hide (s_view1_summary_button); + gtk_widget_show (s_view1_nosummary_button); + break; + + case NOSUMMARY_BUTTON: + summary_mode = FALSE; + gtk_widget_show (s_view1_summary_button); + gtk_widget_hide (s_view1_nosummary_button); + break; + } + + view1_display_when_idle(); +} + +/**************************************************************************** +* view1_print_callback +****************************************************************************/ + +void view1_print_callback (GtkToggleButton *notused, gpointer nu2) +{ + modal_dialog("Print Screen (PostScript format) to file:", + "Invalid file: Print Screen to file:", + "g2.ps", print_screen_callback); +} + +/**************************************************************************** +* view1_hscroll +****************************************************************************/ + +static void view1_hscroll (GtkAdjustment *adj, GtkWidget *notused) +{ + ulonglong current_width; + + current_width = (s_v1->maxvistime - s_v1->minvistime); + + s_v1->minvistime = (ulonglong)(adj->value); + s_v1->maxvistime = s_v1->minvistime + current_width; + + view1_display_when_idle(); + +#ifdef NOTDEF + g_print ("adj->lower = %.2f\n", adj->lower); + g_print ("adj->upper = %.2f\n", adj->upper); + g_print ("adj->value = %.2f\n", adj->value); + g_print ("adj->step_increment = %.2f\n", adj->step_increment); + g_print ("adj->page_increment = %.2f\n", adj->page_increment); + g_print ("adj->page_size = %.2f\n", adj->page_size); +#endif +} + +/**************************************************************************** +* view1_vscroll +****************************************************************************/ + +static void view1_vscroll (GtkAdjustment *adj, GtkWidget *notused) +{ + s_v1->first_pid_index = (int)adj->value; + view1_display_when_idle(); +} + +void set_pid_ax_width(int width) +{ + s_v1->pid_ax_width = width; + view1_display_when_idle(); +} + +/**************************************************************************** +* view1_init +****************************************************************************/ + +void view1_init(void) +{ + + c_view1_draw_width = atol(getprop_default("drawbox_width", "700")); + c_view1_draw_height = atol(getprop_default("drawbox_height", "400")); + + s_v1->pid_ax_width = 80; + s_v1->time_ax_height = 80; + s_v1->time_ax_spacing = 100; + s_v1->strip_height = 25; + s_v1->pop_offset = 20; + s_v1->pid_ax_offset = 34; + s_v1->event_offset = 40; + s_v1->total_height = c_view1_draw_height; + s_v1->total_width = c_view1_draw_width; + s_v1->first_pid_index = 0; + + s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) / + s_v1->strip_height; + + s_v1->minvistime = 0; + s_v1->maxvistime = 200; + + s_view1_vbox = gtk_vbox_new(FALSE, 5); + + s_view1_hbox = gtk_hbox_new(FALSE, 5); + + da = gtk_drawing_area_new(); + gtk_drawing_area_size(GTK_DRAWING_AREA(da), c_view1_draw_width, + c_view1_draw_height); + +#ifdef NOTDEF + gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event", + (GtkSignalFunc) motion_notify_event, NULL); +#endif + + gtk_signal_connect (GTK_OBJECT (da), "expose_event", + (GtkSignalFunc) expose_event, NULL); + + gtk_signal_connect (GTK_OBJECT(da),"configure_event", + (GtkSignalFunc) configure_event, NULL); + + gtk_signal_connect (GTK_OBJECT (da), "button_press_event", + (GtkSignalFunc) button_press_event, NULL); + + gtk_signal_connect (GTK_OBJECT (da), "button_release_event", + (GtkSignalFunc) button_press_event, NULL); + + gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event", + (GtkSignalFunc) button_press_event, NULL); + + gtk_widget_set_events (da, GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK + | GDK_BUTTON_MOTION_MASK); + + + gtk_box_pack_start(GTK_BOX(s_view1_hbox), da, TRUE, TRUE, 0); + + g_font = gdk_font_load ("8x13"); + if (g_font == NULL) { + g_error("Couldn't load 8x13 font...\n"); + } + gdk_font_ref(g_font); + + /* PID axis menu */ + s_view1_vmenubox = gtk_vbox_new(FALSE, 5); + + s_view1_vsadj = gtk_adjustment_new(0.0 /* initial value */, + 0.0 /* minimum value */, + 2000.0 /* maximum value */, + 0.1 /* step increment */, + 10.0/* page increment */, + 10.0/* page size */); + + s_view1_vscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT(s_view1_vsadj)); + + gtk_signal_connect (GTK_OBJECT (s_view1_vsadj), "value-changed", + GTK_SIGNAL_FUNC (view1_vscroll), + (gpointer)s_view1_vscroll); + + s_view1_topbutton = gtk_button_new_with_label("Top"); + s_view1_bottombutton = gtk_button_new_with_label("Bottom"); + + gtk_signal_connect (GTK_OBJECT(s_view1_topbutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) TOP_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_bottombutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) BOTTOM_BUTTON); + + /* More Traces button and Less Traces button */ + s_view1_more_traces_button = gtk_button_new_with_label("More Traces"); + s_view1_less_traces_button = gtk_button_new_with_label("Less Traces"); + gtk_signal_connect (GTK_OBJECT(s_view1_more_traces_button), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) MORE_TRACES_BUTTON); + gtk_signal_connect (GTK_OBJECT(s_view1_less_traces_button), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) LESS_TRACES_BUTTON); + +#ifdef NOTDEF + /* Trick to bottom-justify the menu: */ + s_view1_pad1 = gtk_vbox_new(FALSE, 0); + gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_pad1, + TRUE, FALSE, 0); + +#endif + + gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_topbutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_vscroll, + TRUE, TRUE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_bottombutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_more_traces_button, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_less_traces_button, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hbox), s_view1_vmenubox, + FALSE, FALSE, 0); + + /* Time axis menu */ + + s_view1_hmenubox = gtk_hbox_new(FALSE, 5); + + s_view1_startbutton = gtk_button_new_with_label("Start"); + + s_view1_zoominbutton = gtk_button_new_with_label("ZoomIn"); + + s_view1_searchbutton = gtk_button_new_with_label("Search"); + + s_view1_srchagainbutton = gtk_button_new_with_label("Search Again"); + + s_view1_zoomoutbutton = gtk_button_new_with_label("ZoomOut"); + + s_view1_endbutton = gtk_button_new_with_label("End"); + + gtk_signal_connect (GTK_OBJECT(s_view1_startbutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) START_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_zoominbutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) ZOOMIN_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_searchbutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) SEARCH_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_srchagainbutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) SEARCH_AGAIN_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_zoomoutbutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) ZOOMOUT_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_endbutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) END_BUTTON); + + s_view1_hsadj = gtk_adjustment_new(0.0 /* initial value */, + 0.0 /* minimum value */, + 2000.0 /* maximum value */, + 0.1 /* step increment */, + 10.0/* page increment */, + 10.0/* page size */); + + s_view1_hscroll = gtk_hscrollbar_new (GTK_ADJUSTMENT(s_view1_hsadj)); + + gtk_signal_connect (GTK_OBJECT (s_view1_hsadj), "value-changed", + GTK_SIGNAL_FUNC (view1_hscroll), + (gpointer)s_view1_hscroll); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_startbutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_hscroll, + TRUE, TRUE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_endbutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoominbutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_searchbutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_srchagainbutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoomoutbutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hbox, + TRUE, TRUE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox, + FALSE, FALSE, 0); + + + s_view1_hmenubox2 = gtk_hbox_new(FALSE, 5); + + s_view1_snapbutton = gtk_button_new_with_label("Snap"); + + s_view1_nextbutton = gtk_button_new_with_label("Next"); + + s_view1_delbutton = gtk_button_new_with_label("Del"); + + s_view1_chase_event_button = gtk_button_new_with_label("ChaseEvent"); + + s_view1_chase_datum_button = gtk_button_new_with_label("ChaseDatum"); + + s_view1_chase_track_button = gtk_button_new_with_label("ChaseTrack"); + + s_view1_unchasebutton = gtk_button_new_with_label("NoChase"); + + s_view1_forward_button = gtk_button_new_with_label("->SrchChase(is<-)"); + s_view1_backward_button = gtk_button_new_with_label("<-SrchChase(is->)"); + + s_view1_summary_button = gtk_button_new_with_label("Summary"); + s_view1_nosummary_button = gtk_button_new_with_label("NoSummary"); + + gtk_signal_connect (GTK_OBJECT(s_view1_snapbutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) SNAP_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_nextbutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) NEXT_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_delbutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) DEL_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_chase_event_button), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) CHASE_EVENT_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_chase_datum_button), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) CHASE_DATUM_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_chase_track_button), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) CHASE_TRACK_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_unchasebutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) UNCHASE_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_forward_button), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) FORWARD_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_backward_button), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) BACKWARD_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_summary_button), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) SUMMARY_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_nosummary_button), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) NOSUMMARY_BUTTON); + + gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox2, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_snapbutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nextbutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_delbutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_event_button, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_datum_button, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_track_button, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_unchasebutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_forward_button, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_backward_button, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_summary_button, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nosummary_button, + FALSE, FALSE, 0); + + s_view1_label = gtk_label_new(NULL); + + gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_label, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(g_mainhbox), s_view1_vbox, + TRUE, TRUE, 0); + + gtk_widget_show_all (s_view1_vbox); + GTK_WIDGET_SET_FLAGS(da, GTK_CAN_FOCUS); + gtk_widget_grab_focus(da); + + gtk_widget_hide (s_view1_forward_button); + gtk_widget_hide (summary_mode ? s_view1_summary_button + : s_view1_nosummary_button); + + zi_source = gdk_bitmap_create_from_data (NULL, (char *)zi_bits, zi_width, + zi_height); + zi_mask = gdk_bitmap_create_from_data (NULL, (char *)zi_bkgd, zi_width, + zi_height); + + zi_cursor = (GdkCursor *) gdk_cursor_new_from_pixmap (zi_source, + zi_mask, &fg_black, + &bg_white, zi_x_hot, + zi_y_hot); + gdk_pixmap_unref (zi_source); + gdk_pixmap_unref (zi_mask); + + norm_cursor = (GdkCursor *) gdk_cursor_new (GDK_TOP_LEFT_ARROW); +} + +/**************************************************************************** +* line_print +****************************************************************************/ + +void line_print (int x1, int y1, int x2, int y2) +{ + fprintf(s_printfp, "newpath\n"); + fprintf(s_printfp, "%d %d moveto\n", xrt(x1, s_v1->total_height - y1), + yrt(x1, s_v1->total_height - y1)); + + fprintf(s_printfp, "%d %d lineto\n", xrt (x2, s_v1->total_height - y2), + yrt (x2, s_v1->total_height - y2)); + fprintf(s_printfp, "1 setlinewidth\n"); + fprintf(s_printfp, "stroke\n"); +} + +/**************************************************************************** +* tbox_print +****************************************************************************/ +GdkRectangle *tbox_print (char *s, int x, int y, enum view1_tbox_fn function, + GdkRectangle *rp) +{ + if (function == TBOX_PRINT_BOXED) { + rp->width -= 4; + } + + if ((function == TBOX_PRINT_BOXED) || + (function == TBOX_PRINT_EVENT)) { + + fprintf(s_printfp, "newpath\n"); + fprintf(s_printfp, "0 setlinewidth\n"); + fprintf(s_printfp, "%d %d moveto\n", + xrt(rp->x, s_v1->total_height - rp->y), + yrt(rp->x, s_v1->total_height - rp->y)); + + fprintf(s_printfp, "%d %d lineto\n", + xrt (rp->x+rp->width, s_v1->total_height - rp->y), + yrt (rp->x+rp->width, s_v1->total_height - rp->y)); + + fprintf(s_printfp, "%d %d lineto\n", + xrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height)), + yrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height))); + + fprintf(s_printfp, "%d %d lineto\n", + xrt(rp->x, s_v1->total_height - (rp->y+rp->height)), + yrt(rp->x, s_v1->total_height - (rp->y+rp->height))); + + fprintf(s_printfp, "%d %d lineto\n", + xrt(rp->x, s_v1->total_height - rp->y), + yrt(rp->x, s_v1->total_height - rp->y)); + + fprintf(s_printfp, "stroke\n"); + } + + if ((function == TBOX_PRINT_BOXED) || + (function == TBOX_PRINT_PLAIN)) { + + fprintf(s_printfp, "newpath\n"); + fprintf(s_printfp, "%d %d moveto\n", + xrt(x, s_v1->total_height - (y-2)), + yrt(x, s_v1->total_height - (y-2))); + fprintf(s_printfp, "gsave\n"); + fprintf(s_printfp, "90 rotate\n"); + fprintf(s_printfp, "(%s) show\n", s); + fprintf(s_printfp, "grestore\n"); + } + + return(rp); +} + +/**************************************************************************** +* tbox - draws an optionally boxed string whose lower lefthand +* corner is at (x, y). As usual, Y is backwards. +****************************************************************************/ + +GdkRectangle *tbox (char *s, int x, int y, enum view1_tbox_fn function) +{ + static GdkRectangle update_rect; + gint lbearing, rbearing, width, ascent, descent; + + gdk_string_extents (g_font, s, + &lbearing, &rbearing, + &width, &ascent, &descent); + + /* + * If we have enough room to display full size events, then just + * use the BOXED function instead of the EVENT function. + */ + if (s_v1->strip_height > 9) { + switch (function) { + case TBOX_DRAW_EVENT: function = TBOX_DRAW_BOXED; break; + case TBOX_GETRECT_EVENT: function = TBOX_GETRECT_BOXED; break; + case TBOX_PRINT_EVENT: function = TBOX_PRINT_BOXED; break; + default: + break; + /* Nothing */ + } + } + + switch (function) { + case TBOX_DRAW_BOXED: + gdk_draw_rectangle (pm, da->style->white_gc, TRUE, + x, y - (ascent+descent+3), width + 2, + ascent + descent + 3); + + gdk_draw_rectangle (pm, da->style->black_gc, FALSE, + x, y - (ascent+descent+3), width + 2, + ascent + descent + 3); + + gdk_draw_string (pm, g_font, da->style->black_gc, + x + 1, y - 1, (const gchar *)s); + /* NOTE FALLTHROUGH */ + case TBOX_GETRECT_BOXED: + update_rect.x = x; + update_rect.y = y -(ascent+descent+3); + update_rect.width = width + 3; + update_rect.height = ascent + descent + 4; + if (function == TBOX_DRAW_BOXED) + gtk_widget_draw (da, &update_rect); + break; + + case TBOX_DRAW_EVENT: + /* We have a small event to draw...no text */ + gdk_draw_rectangle (pm, da->style->black_gc, FALSE, + x, y - 1, 3, 3); + /* NOTE FALLTHROUGH */ + case TBOX_GETRECT_EVENT: + update_rect.x = x; + update_rect.y = y - 1; + update_rect.width = 4; + update_rect.height = 4; + if (function == TBOX_DRAW_EVENT) + gtk_widget_draw (da, &update_rect); + break; + + + case TBOX_DRAW_PLAIN: + + gdk_draw_string (pm, g_font, da->style->black_gc, + x + 1, y - 1, (const gchar *)s); + /* NOTE FALLTHROUGH */ + case TBOX_GETRECT_PLAIN: + update_rect.x = x; + update_rect.y = y -(ascent+descent+1); + update_rect.width = width; + update_rect.height = ascent + descent; + if (function == TBOX_DRAW_PLAIN) + gtk_widget_draw (da, &update_rect); + break; + + case TBOX_PRINT_BOXED: + update_rect.x = x; + update_rect.y = y -(ascent+descent+3); + update_rect.width = width + 3; + update_rect.height = ascent + descent + 4; + /* note fallthrough */ + case TBOX_PRINT_PLAIN: + return(tbox_print(s, x, y, function, &update_rect)); + + case TBOX_PRINT_EVENT: + /* We have a small event box to print...no text */ + update_rect.x = x; + update_rect.y = y - 1; + update_rect.width = 4; + update_rect.height = 4; + return(tbox_print(s, x, y, function, &update_rect)); + } + return(&update_rect); +} + +/**************************************************************************** +* line +* +* For lines there is a primitive batching facility, that doesn't update +* the drawing area until the batch is complete. This is handy for drawing +* the pid axis and for summary mode. +* +* line_batch_mode contains the state for this: +* +* BATCH_OFF: no batching, update for every line +* BATCH_NEW: just entered a batch, so initialize the area to update from +* scratch +* BATCH_EXISTING: have drawn at least one line in batch mode, so the update +* area should only be expanded from now on to include the +* union of the "rectangular hull" of all lines +****************************************************************************/ + +static enum { BATCH_OFF, BATCH_NEW, BATCH_EXISTING } line_batch_mode; +static int line_batch_count; +static int line_minx, line_miny, line_maxx, line_maxy; + +void line_batch_start (void) +{ + line_batch_mode = BATCH_NEW; + line_batch_count = 0; +} + +void line_batch_end (void) +{ + GdkRectangle update_rect; + if (line_batch_count > 0) { + update_rect.x = line_minx; + update_rect.y = line_miny; + update_rect.width = (line_maxx - line_minx) + 1; + update_rect.height = (line_maxy - line_miny) + 1; + gtk_widget_draw (da, &update_rect); + } + line_batch_mode = BATCH_OFF; +} + +void line (int x1, int y1, int x2, int y2, enum view1_line_fn function) +{ + GdkRectangle update_rect; + GdkGC *gc = NULL; + + switch(function) { + case LINE_DRAW_BLACK: + gc = da->style->black_gc; + break; + + case LINE_DRAW_WHITE: + gc = da->style->white_gc; + break; + + case LINE_PRINT: + line_print (x1, y1, x2, y2); + return; + } + + gdk_draw_line (pm, gc, x1, y1, x2, y2); + + switch (line_batch_mode) { + case BATCH_OFF: + update_rect.x = x1; + update_rect.y = y1; + update_rect.width = (x2-x1) + 1; + update_rect.height = (y2-y1) + 1; + gtk_widget_draw (da, &update_rect); + break; + + case BATCH_NEW: + line_minx = x1; + line_maxx = x2; + line_miny = y1; + line_maxy = y2; + line_batch_mode = BATCH_EXISTING; + line_batch_count = 1; + break; + + case BATCH_EXISTING: + if (line_minx > x1) + line_minx = x1; + if (line_miny > y1) + line_miny = y1; + if (line_maxx < x2) + line_maxx = x2; + if (line_maxy < y2) + line_maxy = y2; + line_batch_count++; + break; + } +} + + +/**************************************************************************** +* display_pid_axis +****************************************************************************/ + +static void display_pid_axis(v1_geometry_t *vp) +{ + int y, i, label_tick; + int last_printed_y = -vp->strip_height; + pid_sort_t *pp; + int pid_index; + char *label_fmt; + char tmpbuf [128]; + + /* No pids yet? Outta here */ + if (g_pids == NULL) + return; + + line_batch_start(); + + for (i = 0; i < vp->npids; i++) { + pid_index = vp->first_pid_index + i; + if (pid_index >= g_npids) + break; + + set_color(pid_index); + pp = (g_pids + pid_index); + + label_fmt = get_track_label(pp->pid_value); + snprintf(tmpbuf, sizeof(tmpbuf)-1, label_fmt, pp->pid_value); + + y = i*vp->strip_height + vp->pid_ax_offset; + + /* + * Have we incremented enough space to have another label not + * overlap the previous label? + */ + if (y - last_printed_y > 9) { + /* Draw label */ + tbox(tmpbuf, 0, y +4, TBOX_DRAW_PLAIN+s_print_offset); + + last_printed_y = y; + + /* + * And let the line stick out a bit more to indicate this label + * relates to the following line. + */ + label_tick = 4; + } + else { + label_tick = 0; + } + + /* Draw axis line, but only if the lines aren't too close together */ + if (vp->strip_height > 4) { + line(vp->pid_ax_width - label_tick, y+4*s_print_offset, + vp->total_width, y+4*s_print_offset, + LINE_DRAW_BLACK+s_print_offset); + } + } + + set_color(COLOR_DEFAULT); + line_batch_end(); +} + +/**************************************************************************** +* view1_read_events_callback +* New event data just showed up, reset a few things. +****************************************************************************/ + +void view1_read_events_callback(void) +{ + int max_vis_index; + + s_v1->first_pid_index = 0; + + max_vis_index = 300; + if (max_vis_index > g_nevents) + max_vis_index = g_nevents-1; + + s_v1->minvistime = 0LL; + s_v1->maxvistime = (g_events[g_nevents - 1].time * 9)/ 8; + s_srchindex = 0; + s_srchcode = 0; + s_last_selected_event = 0; + + init_track_colors(); + + recompute_hscrollbar(); + recompute_vscrollbar(); +} + +/**************************************************************************** +* display_event_data +****************************************************************************/ + +static void display_event_data(v1_geometry_t *vp) +{ + int start_index; + int pid_index; + int x, y; + event_t *ep; + event_def_t *edp; + double time_per_pixel; + char tmpbuf[1024]; + GdkRectangle *print_rect; + int *last_x_used; + + /* Happens if one loads the event def header first, for example. */ + if (g_nevents == 0) + return; + + time_per_pixel = dtime_per_pixel(vp); + + start_index = find_event_index (vp->minvistime); + + /* Scrolled too far right? */ + if (start_index >= g_nevents) + return; + + ep = (g_events + start_index); + + if (s_print_offset || summary_mode) { + last_x_used = (int *)g_malloc0(vp->npids * sizeof(int)); + } else { + last_x_used = NULL; + } + + line_batch_start(); + + while (ep < (g_events + g_nevents) && + (ep->time < vp->maxvistime)) { + pid_index = ep->pid->pid_index; + set_color(pid_index); + + /* First filter: pid out of range */ + if ((pid_index < vp->first_pid_index) || + (pid_index >= vp->first_pid_index + vp->npids)) { + ep++; + continue; + } + + /* Second filter: event hidden */ + edp = find_event_definition (ep->code); + if (!edp->selected) { + ep++; + continue; + } + + /* Display it... */ + + pid_index -= vp->first_pid_index; + + y = pid_index*vp->strip_height + vp->event_offset; + + x = vp->pid_ax_width + + (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel); + + if (last_x_used != NULL && x < last_x_used[pid_index]) { + ep++; + continue; + } + + if (ep->flags & (EVENT_FLAG_SELECT | EVENT_FLAG_SEARCHRSLT)) { + if (ep->flags & EVENT_FLAG_SELECT) { + format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp); +#ifdef NOTDEF + sprintf(tmpbuf, edp->name); + sprintf(tmpbuf+strlen(tmpbuf), ": "); + sprintf(tmpbuf+strlen(tmpbuf), edp->format, ep->datum); +#endif + } else { + sprintf(tmpbuf, "SEARCH RESULT"); + } + print_rect = tbox(tmpbuf, x, y - vp->pop_offset, + TBOX_DRAW_BOXED+s_print_offset); + line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK+s_print_offset); + if (last_x_used != NULL) + last_x_used[pid_index] = x + print_rect->width; + } + if (summary_mode) { + int delta = vp->strip_height / 3; + if (delta < 1) + delta = 1; + y = pid_index*vp->strip_height + vp->pid_ax_offset; + line(x, y - delta, x, y + delta, LINE_DRAW_BLACK); + last_x_used[pid_index] = x + 1; + } else { + sprintf(tmpbuf, "%ld", ep->code); + print_rect = tbox(tmpbuf, x, y, TBOX_DRAW_EVENT+s_print_offset); + if (last_x_used != NULL) + last_x_used[pid_index] = x + print_rect->width; + } + + ep++; + } + if (last_x_used) + g_free(last_x_used); + line_batch_end(); + set_color(COLOR_DEFAULT); +} + +/**************************************************************************** +* display_clear +****************************************************************************/ + +static void display_clear(void) +{ + GdkRectangle update_rect; + + gdk_draw_rectangle (pm, da->style->white_gc, TRUE, + 0, 0, da->allocation.width, + da->allocation.height); + + update_rect.x = 0; + update_rect.y = 0; + update_rect.width = da->allocation.width; + update_rect.height = da->allocation.height; + + gtk_widget_draw (da, &update_rect); +} + +/**************************************************************************** +* display_time_axis +****************************************************************************/ + +static void display_time_axis(v1_geometry_t *vp) +{ + int x, y, i; + int xoffset, nticks; + char tmpbuf [128]; + double unit_divisor; + double time; + char *units; + double time_per_pixel; + + y = vp->npids * vp->strip_height + vp->pid_ax_offset; + + x = vp->pid_ax_width; + + nticks = (vp->total_width - vp->pid_ax_width) / vp->time_ax_spacing; + + time_per_pixel = dtime_per_pixel(vp); + + units = "ns"; + unit_divisor = 1.00; + + if ((vp->maxvistime / unit_divisor) > 1000) { + units = "us"; + unit_divisor = 1000.00; + } + + if ((vp->maxvistime / unit_divisor) > 1000) { + units = "ms"; + unit_divisor = 1000.00*1000.00; + } + if ((vp->maxvistime / unit_divisor) > 1000) { + units = "s"; + unit_divisor = 1000.00*1000.00*1000.00; + } + + /* Draw line */ + line(x, y, vp->total_width, y, LINE_DRAW_BLACK+s_print_offset); + + xoffset = 0; + + for (i = 0; i < nticks; i++) { + /* Tick mark */ + line(x+xoffset, y-3, x+xoffset, y+3, LINE_DRAW_BLACK+s_print_offset); + + time = (double)(x + xoffset - vp->pid_ax_width); + time *= time_per_pixel; + time += (double)(vp->minvistime); + time /= unit_divisor; + + sprintf (tmpbuf, "%.2f%s", time, units); + + tbox(tmpbuf, x+xoffset, y+15, TBOX_DRAW_PLAIN+s_print_offset); + + xoffset += vp->time_ax_spacing; + } +} + +/**************************************************************************** +* clear_scoreboard +* Forget about any temporary displays, they're gone now... +****************************************************************************/ + +static void clear_scoreboard(void) +{ + s_result_up = FALSE; +} + +/**************************************************************************** +* view1_display +****************************************************************************/ + +void view1_display(void) +{ + display_clear(); + display_pid_axis(s_v1); + display_event_data(s_v1); + display_time_axis(s_v1); + clear_scoreboard(); +} + +static gint idle_tag; + +/**************************************************************************** +* view1_display_eventually +****************************************************************************/ + +static void view1_display_eventually(void) +{ + gtk_idle_remove(idle_tag); + idle_tag = 0; + view1_display(); +} + + +/**************************************************************************** +* view1_display_when_idle +****************************************************************************/ + +void view1_display_when_idle(void) +{ + if (idle_tag == 0) { + idle_tag = gtk_idle_add((GtkFunction) view1_display_eventually, 0); + } +} + +/**************************************************************************** +* view1_about +****************************************************************************/ + +void view1_about (char *tmpbuf) +{ + int nsnaps; + snapshot_t *snaps; + + sprintf(tmpbuf+strlen(tmpbuf), "Minvistime %lld\nMaxvistime %lld\n", + s_v1->minvistime, s_v1->maxvistime); + sprintf(tmpbuf+strlen(tmpbuf), "Strip Height %d\n", + s_v1->strip_height); + + for (nsnaps = 0, snaps = s_snapshots; snaps; snaps = snaps->next) { + nsnaps++; + } + sprintf(tmpbuf+strlen(tmpbuf), "%d snapshots in the ring\n", nsnaps); +} diff --git a/src/tools/perftool/c2cpel.c b/src/tools/perftool/c2cpel.c new file mode 100644 index 00000000..38e6fe52 --- /dev/null +++ b/src/tools/perftool/c2cpel.c @@ -0,0 +1,248 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2006-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 +#include +#include "cpel.h" +#include "cpel_util.h" + +static elog_main_t elog_main; + +/* + * convert_clib_file + */ +void convert_clib_file(char *clib_file) +{ + clib_error_t *error = 0; + int i; + elog_main_t *em = &elog_main; + double starttime, delta; + + error = elog_read_file (&elog_main, clib_file); + + if (error) { + clib_warning("%U", format_clib_error, error); + exit (1); + } + + em = &elog_main; + + starttime = em->events[0].time; + + for (i = 0; i < vec_len (em->events); i++) { + elog_event_t *e; /* clib event */ + evt_t *ep; /* xxx2cpel event */ + u8 *s; + u64 timestamp; + elog_event_type_t *t; + u8 *brief_event_name; + u8 *track_name; + int j; + + e = vec_elt_at_index(em->events, i); + + /* Seconds since start of log */ + delta = e->time - starttime; + + /* u64 nanoseconds since start of log */ + timestamp = delta * 1e9; + + s = format (0, "%U%c", format_elog_event, em, e, 0); + + /* allocate an event instance */ + vec_add2(the_events, ep, 1); + ep->timestamp = timestamp; + + /* convert string event code to a real number */ + t = vec_elt_at_index (em->event_types, e->type); + + /* + * Construct a reasonable event name. + * Truncate the format string at the first whitespace break + * or printf format character. + */ + brief_event_name = format (0, "%s", t->format); + + for (j = 0; j < vec_len (brief_event_name); j++) { + if (brief_event_name[j] == ' ' || + brief_event_name[j] == '%' || + brief_event_name[j] == '(') { + brief_event_name[j] = 0; + break; + } + } + /* Throw away that much of the formatted event */ + vec_delete (s, j+1, 0); + + ep->event_id = find_or_add_event(brief_event_name, "%s"); + + track_name = format (0, "%U%c", format_elog_track, em, e, 0); + + ep->track_id = find_or_add_track (track_name); + + ep->datum = find_or_add_strtab(s); + + vec_free (track_name); + vec_free(brief_event_name); + vec_free(s); + } +} + +u8 *vec_basename (char *s) +{ + u8 * rv; + char *cp = s; + + while (*cp) + cp++; + + cp--; + + while (cp > s && *cp != '/') + cp--; + + if (cp > s) + cp++; + + rv = format (0, "%s", cp); + return rv; +} + + +int event_compare (const void *a0, const void *a1) +{ + evt_t *e0 = (evt_t *)a0; + evt_t *e1 = (evt_t *)a1; + + if (e0->timestamp < e1->timestamp) + return -1; + else if (e0->timestamp > e1->timestamp) + return 1; + return 0; +} + +int main (int argc, char **argv) +{ + int curarg=1; + char **inputfiles = 0; + char *outputfile = 0; + FILE *ofp; + + if (argc < 3) + goto usage; + + while (curarg < argc) { + if (!strncmp(argv[curarg], "--input-file", 3)) { + curarg++; + if (curarg < argc) { + vec_add1 (inputfiles, argv[curarg]); + curarg++; + continue; + } + clib_warning("Missing filename after --input-file\n"); + exit (1); + } + + if (!strncmp(argv[curarg], "--output-file", 3)) { + curarg ++; + if (curarg < argc) { + outputfile = argv[curarg]; + curarg ++; + continue; + } + clib_warning("Missing filename after --output-file\n"); + exit(1); + } + vec_add1 (inputfiles, argv[curarg]); + curarg++; + continue; + + usage: + fformat(stderr, + "c2cpel [--input-file] --output-file \n"); + exit(1); + } + + if (vec_len(inputfiles) == 0 || outputfile == 0) + goto usage; + + if (vec_len(inputfiles) > 1) + goto usage; + + cpel_util_init(); + + convert_clib_file (inputfiles[0]); + + ofp = fopen (outputfile, "w"); + if (ofp == NULL) { + clib_unix_warning ("couldn't create %s", outputfile); + exit (1); + } + + alpha_sort_tracks(); + fixup_event_tracks(); + + /* + * Four sections: string-table, event definitions, track defs, events. + */ + if (!write_cpel_header(ofp, 4)) { + clib_warning ("Error writing cpel header to %s...\n", outputfile); + unlink(outputfile); + exit(1); + } + + if (!write_string_table(ofp)) { + clib_warning ("Error writing string table to %s...\n", outputfile); + unlink(outputfile); + exit(1); + } + + if (!write_event_defs(ofp)) { + clib_warning ("Error writing event defs to %s...\n", outputfile); + unlink(outputfile); + exit(1); + } + + if (!write_track_defs(ofp)) { + clib_warning ("Error writing track defs to %s...\n", outputfile); + unlink(outputfile); + exit(1); + } + + if (!write_events(ofp, (u64) 1e9)) { + clib_warning ("Error writing events to %s...\n", outputfile); + unlink(outputfile); + exit(1); + + } + fclose(ofp); + exit (0); +} diff --git a/src/tools/perftool/configure.ac b/src/tools/perftool/configure.ac new file mode 100644 index 00000000..f4a98697 --- /dev/null +++ b/src/tools/perftool/configure.ac @@ -0,0 +1,12 @@ +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/perftool/cpel.h b/src/tools/perftool/cpel.h new file mode 100644 index 00000000..0bfb1a68 --- /dev/null +++ b/src/tools/perftool/cpel.h @@ -0,0 +1,83 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2005-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 _CPEL_H_ +#define _CPEL_H_ 1 + +typedef struct cpel_file_header_ { + unsigned char endian_version; + unsigned char pad; + unsigned short nsections; + unsigned int file_date; +} cpel_file_header_t; + +#define CPEL_FILE_LITTLE_ENDIAN 0x80 +#define CPEL_FILE_VERSION 0x01 +#define CPEL_FILE_VERSION_MASK 0x7F + +typedef struct cpel_section_header_ { + unsigned int section_type; + unsigned int data_length; /* does NOT include type and itself */ +} cpel_section_header_t; + +#define CPEL_SECTION_STRTAB 1 +/* string at offset 0 is the name of the table */ + +#define CPEL_SECTION_SYMTAB 2 +#define CPEL_SECTION_EVTDEF 3 + +typedef struct event_definition_section_header_ { + char string_table_name[64]; + unsigned int number_of_event_definitions; +} event_definition_section_header_t; + +typedef struct event_definition_ { + unsigned int event; + unsigned int event_format; + unsigned int datum_format; +} event_definition_t; + +#define CPEL_SECTION_TRACKDEF 4 + +typedef struct track_definition_section_header_ { + char string_table_name[64]; + unsigned int number_of_track_definitions; +} track_definition_section_header_t; + +typedef struct track_definition_ { + unsigned int track; + unsigned int track_format; +} track_definition_t; + +#define CPEL_SECTION_EVENT 5 + +typedef struct event_section_header_ { + char string_table_name[64]; + unsigned int number_of_events; + unsigned int clock_ticks_per_second; +} event_section_header_t; + +typedef struct event_entry_ { + unsigned int time[2]; + unsigned int track; + unsigned int event_code; + unsigned int event_datum; +} event_entry_t; + +#define CPEL_NUM_SECTION_TYPES 5 + +#endif /* _CPEL_H_ */ + diff --git a/src/tools/perftool/cpel_util.c b/src/tools/perftool/cpel_util.c new file mode 100644 index 00000000..7ee9b6e2 --- /dev/null +++ b/src/tools/perftool/cpel_util.c @@ -0,0 +1,456 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2006-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 +#include +#include +#include "cpel.h" +#include "cpel_util.h" + +evt_t *the_events; + +track_t *the_tracks; +u32 *track_alpha_map; + +event_definition_t *the_event_definitions; +i64 min_timestamp; + +/* Hash tables, used to find previous instances of the same items */ +uword *the_track_hash; +uword *the_msg_event_hash; +uword *the_strtab_hash; +uword *the_pidtid_hash; +uword *the_pid_to_name_hash; +u8 *the_strtab; + +uword *the_event_id_bitmap; + +/* + * find_or_add_strtab + * Finds or adds a string to the string table + */ +u32 find_or_add_strtab(void *s_arg) +{ + uword *p; + int len; + u8 *this_string; + u8 *scopy=0; + char *s = s_arg; + + p = hash_get_mem(the_strtab_hash, s); + if (p) { + return (p[0]); + } + + /* + * Here's a CLIB bear-trap. We can't add the string-table + * strings to the to the hash table (directly), since it + * expands and moves periodically. All of the hash table + * entries turn into dangling references, yadda yadda. + */ + + len = strlen(s)+1; + vec_add2(the_strtab, this_string, len); + memcpy(this_string, s, len); + + /* Make a copy which won't be moving around... */ + vec_validate(scopy, len); + memcpy(scopy, s, len); + + hash_set_mem(the_strtab_hash, scopy, this_string - the_strtab); + + return(this_string - the_strtab); +} + +/* + * find_or_add_track + * returns index in track table + */ +u32 find_or_add_track(void *s_arg) +{ + uword *p; + track_t *this_track; + u8 *copy_s; + char *s=s_arg; + + p = hash_get_mem(the_track_hash, s); + if (p) { + return (p[0]); + } + vec_add2(the_tracks, this_track, 1); + + this_track->original_index = this_track - the_tracks; + this_track->strtab_offset = find_or_add_strtab(s); + + copy_s = (u8 *)vec_dup(s); + + hash_set_mem(the_track_hash, copy_s, this_track - the_tracks); + return(this_track - the_tracks); +} + +/* + * find_or_add_event + * Adds an event to the event definition vector and add it to + * the event hash table + */ + +u32 find_or_add_event(void *s_arg, char *datum_format) +{ + uword *p; + u8 *copy_s; + event_definition_t *this_event_definition; + u32 event_id; + char *s=s_arg; + + p = hash_get_mem(the_msg_event_hash, s); + if (p) { + return (p[0]); + } + vec_add2(the_event_definitions, this_event_definition, 1); + + /* Allocate a new event-id */ + event_id = clib_bitmap_first_clear (the_event_id_bitmap); + the_event_id_bitmap = clib_bitmap_set(the_event_id_bitmap, event_id, 1); + this_event_definition->event = event_id; + this_event_definition->event_format = find_or_add_strtab(s); + this_event_definition->datum_format = find_or_add_strtab(datum_format); + + copy_s = (u8 *)vec_dup(s); + + hash_set_mem(the_msg_event_hash, copy_s, event_id); + + return(event_id); +} + +/* + * write_string_table + */ +int write_string_table(FILE *ofp) +{ + cpel_section_header_t sh; + + /* Round up string table size */ + while (vec_len(the_strtab) & 0x7) + vec_add1(the_strtab, 0); + + sh.section_type = ntohl(CPEL_SECTION_STRTAB); + sh.data_length = ntohl(vec_len(the_strtab)); + + if (fwrite(&sh, sizeof(sh), 1, ofp) != 1) + return(0); + + if (fwrite(the_strtab, 1, vec_len(the_strtab), ofp) != + vec_len(the_strtab)) + return(0); + + return(1); +} + +/* + * write_cpel_header + */ +int write_cpel_header(FILE *ofp, u32 nsections) +{ + cpel_file_header_t h; + + h.endian_version = CPEL_FILE_VERSION; + h.pad = 0; + h.nsections = ntohs(nsections); + h.file_date = ntohl(time(0)); + if (fwrite(&h, sizeof(h), 1, ofp) != 1) + return (0); + + return(1); +} + +/* + * write_event_defs + */ +int write_event_defs(FILE *ofp) +{ + cpel_section_header_t sh; + event_definition_section_header_t edsh; + event_definition_t *this_event_definition; + int i; + + /* Next, the event definitions */ + sh.section_type = ntohl(CPEL_SECTION_EVTDEF); + sh.data_length = ntohl(vec_len(the_event_definitions) + *sizeof(the_event_definitions[0]) + + sizeof(event_definition_section_header_t)); + + if (fwrite(&sh, sizeof(sh), 1, ofp) != 1) + return(0); + + memset(&edsh, 0, sizeof(edsh)); + + strcpy(edsh.string_table_name, "FileStrtab"); + edsh.number_of_event_definitions = ntohl(vec_len(the_event_definitions)); + + if (fwrite(&edsh, sizeof(edsh), 1, ofp) != 1) + return(0); + + for (i = 0; i < vec_len(the_event_definitions); i++) { + this_event_definition = &the_event_definitions[i]; + /* Endian fixup */ + this_event_definition->event = ntohl(this_event_definition->event); + this_event_definition->event_format = + ntohl(this_event_definition->event_format); + this_event_definition->datum_format = + ntohl(this_event_definition->datum_format); + + if (fwrite(this_event_definition, sizeof(the_event_definitions[0]), + 1, ofp) != 1) + return(0); + } + return(1); +} + +/* + * ntohll + */ +u64 ntohll (u64 x) { + if (clib_arch_is_little_endian) + x = ((((x >> 0) & 0xff) << 56) + | (((x >> 8) & 0xff) << 48) + | (((x >> 16) & 0xff) << 40) + | (((x >> 24) & 0xff) << 32) + | (((x >> 32) & 0xff) << 24) + | (((x >> 40) & 0xff) << 16) + | (((x >> 48) & 0xff) << 8) + | (((x >> 56) & 0xff) << 0)); + + return x; +} + +/* + * write_events + */ +int write_events(FILE *ofp, u64 clock_ticks_per_second) +{ + cpel_section_header_t sh; + event_section_header_t eh; + u32 number_of_events; + int i; + event_entry_t e; + u64 net_timestamp; + evt_t *this_event; + u32 time0, time1; + + number_of_events = vec_len(the_events); + + sh.section_type = ntohl(CPEL_SECTION_EVENT); + sh.data_length = ntohl(number_of_events * sizeof(e) + + sizeof(event_section_header_t)); + + if (fwrite(&sh, sizeof(sh), 1, ofp) != 1) + return(0); + + memset(&eh, 0, sizeof(eh)); + strcpy(eh.string_table_name, "FileStrtab"); + eh.number_of_events = ntohl(number_of_events); + eh.clock_ticks_per_second = ntohl(clock_ticks_per_second); + + if (fwrite(&eh, sizeof(eh), 1, ofp) != 1) + return(0); + + for (i = 0; i < number_of_events; i++) { + this_event = &the_events[i]; + net_timestamp = ntohll(this_event->timestamp); + + time1 = net_timestamp>>32; + time0 = net_timestamp & 0xFFFFFFFF; + + e.time[0] = time0; + e.time[1] = time1; + e.track = ntohl(this_event->track_id); + e.event_code = ntohl(this_event->event_id); + e.event_datum = ntohl(this_event->datum); + + if (fwrite(&e, sizeof(e), 1, ofp) != 1) + return(0); + } + return(1); +} + +/* + * write_track_defs + */ +int write_track_defs(FILE *ofp) +{ + cpel_section_header_t sh; + track_definition_section_header_t tdsh; + track_definition_t record; + track_definition_t *this_track_definition = &record; + int i; + event_definition_section_header_t edsh; + + /* Next, the event definitions */ + sh.section_type = ntohl(CPEL_SECTION_TRACKDEF); + sh.data_length = ntohl(vec_len(the_tracks) + *sizeof(this_track_definition[0]) + + sizeof(track_definition_section_header_t)); + + if (fwrite(&sh, sizeof(sh), 1, ofp) != 1) + return(0); + + memset(&tdsh, 0, sizeof(tdsh)); + + strcpy(tdsh.string_table_name, "FileStrtab"); + tdsh.number_of_track_definitions = ntohl(vec_len(the_tracks)); + + if (fwrite(&tdsh, sizeof(edsh), 1, ofp) != 1) + return(0); + + for (i = 0; i < vec_len(the_tracks); i++) { + this_track_definition->track = ntohl(i); + this_track_definition->track_format = + ntohl(the_tracks[i].strtab_offset); + + if (fwrite(this_track_definition, sizeof(this_track_definition[0]), + 1, ofp) != 1) + return(0); + } + return(1); +} + +void cpel_util_init (void) +{ + u8 *eventstr; + + the_strtab_hash = hash_create_string (0, sizeof (uword)); + the_msg_event_hash = hash_create_string (0, sizeof (uword)); + the_track_hash = hash_create_string (0, sizeof (uword)); + the_pidtid_hash = hash_create_string (0, sizeof(uword)); + the_pid_to_name_hash = hash_create(0, sizeof(uword)); + + /* Must be first, or no supper... */ + find_or_add_strtab("FileStrtab"); + + /* Historical canned events, no longer used. */ + if (0) { + /* event 0 (not used) */ + eventstr = format(0, "PlaceholderNotUsed"); + vec_add1(eventstr, 0); + find_or_add_event(eventstr, "%s"); + vec_free(eventstr); + + /* event 1 (thread on CPU) */ + eventstr = format(0, "THREAD/THRUNNING"); + vec_add1(eventstr, 0); + find_or_add_event(eventstr, "%s"); + vec_free(eventstr); + + /* event 2 (thread ready) */ + eventstr = format(0, "THREAD/THREADY"); + vec_add1(eventstr, 0); + find_or_add_event(eventstr, "%s"); + vec_free(eventstr); + + /* event 3 (function enter) */ + eventstr = format(0, "FUNC/ENTER"); + vec_add1(eventstr, 0); + find_or_add_event(eventstr, "0x%x"); + vec_free(eventstr); + + /* event 4 (function enter) */ + eventstr = format(0, "FUNC/EXIT"); + vec_add1(eventstr, 0); + find_or_add_event(eventstr, "0x%x"); + vec_free(eventstr); + } +} + +/* + * alpha_compare_tracks + */ +static int alpha_compare_tracks(const void *a1, const void *a2) +{ + int i; + track_t *t1 = (track_t *)a1; + track_t *t2 = (track_t *)a2; + u8 *s1 = &the_strtab[t1->strtab_offset]; + u8 *s2 = &the_strtab[t2->strtab_offset]; + + for (i = 0; s1[i] && s2[i]; i++) { + if (s1[i] < s2[i]) + return(-1); + if (s1[i] > s2[i]) + return(1); + } + return(0); +} + +/* + * alpha_sort_tracks + * Alphabetically sort tracks, set up a mapping + * vector so we can quickly map the original track index to + * the new/improved/alpha-sorted index + */ +void alpha_sort_tracks(void) +{ + track_t *this_track; + int i; + + qsort(the_tracks, vec_len(the_tracks), sizeof(track_t), + alpha_compare_tracks); + + vec_validate(track_alpha_map, vec_len(the_tracks)); + _vec_len(track_alpha_map) = vec_len(the_tracks); + + for (i = 0; i < vec_len(the_tracks); i++) { + this_track = &the_tracks[i]; + track_alpha_map[this_track->original_index] = i; + } +} + +/* + * fixup_event_tracks + * Use the track alpha mapping to account for the alphabetic + * sort performed by the previous routine + */ +void fixup_event_tracks(void) +{ + int i; + u32 old_track; + + for (i = 0; i < vec_len(the_events); i++) { + old_track = the_events[i].track_id; + the_events[i].track_id = track_alpha_map[old_track]; + } +} + +/* Indispensable for debugging in gdb... */ + +u32 vl(void *x) +{ + return vec_len(x); +} diff --git a/src/tools/perftool/cpel_util.h b/src/tools/perftool/cpel_util.h new file mode 100644 index 00000000..b76f7a4b --- /dev/null +++ b/src/tools/perftool/cpel_util.h @@ -0,0 +1,68 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2006-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 __cpel_util_h__ +#define __cpel_util_h__ + +/* + * Our idea of an event, as opposed to a CPEL event + */ +typedef struct evt_ { + u64 timestamp; + u32 track_id; + u32 event_id; + u32 datum; +} evt_t; + +evt_t *the_events; + +/* + * Track object, so we can sort the tracks alphabetically and + * fix the events later + */ +typedef struct track_ { + u32 original_index; + u32 strtab_offset; +} track_t; + +track_t *the_tracks; +u32 *track_alpha_map; + +event_definition_t *the_event_definitions; +i64 min_timestamp; + +/* Hash tables, used to find previous instances of the same items */ +uword *the_track_hash; +uword *the_msg_event_hash; +uword *the_strtab_hash; +uword *the_pidtid_hash; +uword *the_pid_to_name_hash; +u8 *the_strtab; + +u32 find_or_add_strtab(void *s_arg); +u32 find_or_add_track(void *s_arg); +u32 find_or_add_event(void *s_arg, char *datum_format); +int write_string_table(FILE *ofp); +int write_cpel_header(FILE *ofp, u32 nsections); +int write_event_defs(FILE *ofp); +u64 ntohll (u64 x); +int write_events(FILE *ofp, u64 clock_ticks_per_second); +int write_track_defs(FILE *ofp); +void cpel_util_init (void); +void alpha_sort_tracks(void); +void fixup_event_tracks(void); + +#endif /* __cpel_util_h__ */ diff --git a/src/tools/perftool/cpelatency.c b/src/tools/perftool/cpelatency.c new file mode 100644 index 00000000..7b87d606 --- /dev/null +++ b/src/tools/perftool/cpelatency.c @@ -0,0 +1,927 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2006-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 +#include "cpel.h" +#include + +char *time_format = "%.03d:%.02d:%.02d:%.03d:%.03d "; +static char version[] = "cpelatency 2.0"; + +#define USEC_PER_MS 1000LL +#define USEC_PER_SECOND (1000*USEC_PER_MS) +#define USEC_PER_MINUTE (60*USEC_PER_SECOND) +#define USEC_PER_HOUR (60*USEC_PER_MINUTE) + +uword *the_strtab_hash; /* (name, base-VA) hash of all string tables */ +uword *the_evtdef_hash; /* (event-id, event-definition) hash */ +uword *the_trackdef_hash; /* (track-id, track-definition) hash */ +uword *the_pidtid_hash; /* ("pid:xxx tid:yy", track-definition) hash */ + +f64 ticks_per_us; +u32 start_event_code = 2; /* default: XR thread ready event */ +u32 end_event_code = 1; /* default: XR thread running event */ +int exclude_kernel_from_summary_stats=1; +int summary_stats_only; +int scatterplot; +u8 *name_filter; +int have_trackdefs; + +typedef enum { + SORT_MAX_TIME=1, + SORT_MAX_OCCURRENCES, + SORT_NAME, +} sort_t; + +sort_t sort_type = SORT_MAX_TIME; + +int widest_name_format=5; +int widest_track_format=20; + +typedef struct bound_event_ { + u32 event_code; + u8 *event_str; + u8 *datum_str; + u32 is_strtab_ref; +} bound_event_t; + +bound_event_t *bound_events; + +typedef struct bound_track_ { + u32 track; + u8 *track_str; + u64 state_start_ticks; + u64 *ticks_in_state; /* vector of state occurrences */ + f64 mean_ticks_in_state; + f64 variance_ticks_in_state; + f64 total_ticks_in_state; +} bound_track_t; + +bound_track_t *bound_tracks; + +void fatal(char *s) +{ + fprintf(stderr, "%s", s); + exit(1); +} + +typedef enum { + PASS1=1, + PASS2=2, +} pass_t; + +typedef struct { + int (*pass1)(cpel_section_header_t *, int, FILE *); + int (*pass2)(cpel_section_header_t *, int, FILE *); +} section_processor_t; + +int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + fprintf(ofp, "Bad (type 0) section, skipped...\n"); + return(0); +} + +int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + return(0); +} + +int strtab_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + uword *p; + u8 *strtab_data_area = (u8 *)(sh+1); + + /* Multiple string tables with the same name are Bad... */ + p = hash_get_mem(the_strtab_hash, strtab_data_area); + if (p) { + fprintf(ofp, "Duplicate string table name %s", strtab_data_area); + } + /* + * Looks funny, but we really do want key = first string in the + * table, value = address(first string in the table) + */ + hash_set_mem(the_strtab_hash, strtab_data_area, strtab_data_area); + if (verbose) { + fprintf(ofp, "String Table %s\n", strtab_data_area); + } + return(0); +} + +int evtdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + int i, nevents; + event_definition_section_header_t *edh; + event_definition_t *ep; + u8 *this_strtab; + u32 event_code; + uword *p; + bound_event_t *bp; + int thislen; + + edh = (event_definition_section_header_t *)(sh+1); + nevents = ntohl(edh->number_of_event_definitions); + + if (verbose) { + fprintf(ofp, "Event Definition Section: %d definitions\n", + nevents); + } + + p = hash_get_mem(the_strtab_hash, edh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + this_strtab = (u8 *)p[0]; + + ep = (event_definition_t *)(edh+1); + + for (i = 0; i < nevents; i++) { + event_code = ntohl(ep->event); + p = hash_get(the_evtdef_hash, event_code); + if (p) { + fprintf(ofp, "Event %d redefined, retain first definition\n", + event_code); + continue; + } + vec_add2(bound_events, bp, 1); + bp->event_code = event_code; + bp->event_str = this_strtab + ntohl(ep->event_format); + bp->datum_str = this_strtab + ntohl(ep->datum_format); + bp->is_strtab_ref = 0; + /* Decide if the datum format is a %s format => strtab reference */ + { + int j; + int seen_percent=0; + + for (j = 0; j < strlen((char *) bp->datum_str); j++) { + if (bp->datum_str[j] == '%'){ + seen_percent=1; + continue; + } + if (seen_percent && bp->datum_str[j] == 's') { + bp->is_strtab_ref = 1; + } + } + } + + hash_set(the_evtdef_hash, event_code, bp - bound_events); + + thislen = strlen((char *) bp->event_str); + if (thislen > widest_name_format) + widest_name_format = thislen; + + ep++; + } + return (0); +} + +int trackdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + int i, nevents; + track_definition_section_header_t *tdh; + track_definition_t *tp; + u8 *this_strtab; + u32 track_code; + uword *p; + bound_track_t *btp; + int thislen; + u8 *pidstr; + u8 *pidtid_str; + u8 *cp; + int tid, pid; + + tdh = (track_definition_section_header_t *)(sh+1); + nevents = ntohl(tdh->number_of_track_definitions); + + if (verbose) { + fprintf(ofp, "Track Definition Section: %d definitions\n", + nevents); + } + + p = hash_get_mem(the_strtab_hash, tdh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + this_strtab = (u8 *)p[0]; + + tp = (track_definition_t *)(tdh+1); + + for (i = 0; i < nevents; i++) { + track_code = ntohl(tp->track); + p = hash_get(the_trackdef_hash, track_code); + if (p) { + fprintf(stderr, "track %d redefined, retain first definition\n", + track_code); + continue; + } + vec_add2(bound_tracks, btp, 1); + btp->track = track_code; + btp->track_str = this_strtab + ntohl(tp->track_format); + hash_set(the_trackdef_hash, track_code, btp - bound_tracks); + + if (verbose) { + fprintf(stderr, "adding track '%s'\n", btp->track_str); + } + + thislen = strlen((char *) btp->track_str); + if (thislen > widest_track_format) + widest_track_format = thislen; + + /* convert track_str "eth_server t11(20498)" to "pid:20498 tid:11" */ + cp = btp->track_str; + while (*cp && *cp != '(') + cp++; + if (!*cp) { + fprintf(stderr, "error canonicalizing '%s'\n", btp->track_str); + goto out; + } + pidstr = cp+1; /* remember location of PID */ + + while (cp > btp->track_str && *cp != 't') + cp--; + + if (cp == btp->track_str) { + fprintf(stderr, "error canonicalizing '%s'\n", btp->track_str); + goto out; + } + tid = atol((char *)(cp+1)); + pid = atol((char *) pidstr); + pidtid_str = format(0, "pid:%d tid:%d", pid, tid); + vec_add1(pidtid_str, 0); + + /* + * Note: duplicates are possible due to thread create / + * thread destroy operations. + */ + p = hash_get_mem(the_pidtid_hash, pidtid_str); + if (p) { + vec_free(pidtid_str); + goto out; + } + hash_set_mem(the_pidtid_hash, pidtid_str, btp - bound_tracks); + + out: + tp++; + } + have_trackdefs = 1; + return (0); +} + +int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + if (verbose) { + fprintf(ofp, "Unsupported type %d section\n", + ntohl(sh->section_type)); + } + return(0); +} + +int event_pass2(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + event_section_header_t *eh; + int nevents; + int i; + uword *p; + event_entry_t *ep; + u64 now; + u32 time0, time1; + u32 track_code; + u8 *this_strtab; + u64 ticks_in_state; + bound_track_t *btp; + bound_track_t *state_track=0; + u8 *pidtid_str; + u8 *pidtid_dup; + u8 *ecp; + u32 event_code; + + eh = (event_section_header_t *)(sh+1); + nevents = ntohl(eh->number_of_events); + ticks_per_us = ((double)ntohl(eh->clock_ticks_per_second)) / 1e6; + + if (verbose) { + fprintf(ofp, "%.3f ticks_per_us\n", ticks_per_us); + } + + ep = (event_entry_t *)(eh+1); + + p = hash_get_mem(the_strtab_hash, eh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + this_strtab = (u8 *)p[0]; + + /* + * Some logger implementation that doesn't produce + * trackdef sections, synthesize the bound_tracks vector + */ + if (!have_trackdefs) { + for (i = 0; i < nevents; i++) { + track_code = ntohl(ep->track); + pidtid_dup = format(0, "%d", track_code); + vec_add1(pidtid_dup, 0); + p = hash_get_mem(the_pidtid_hash, pidtid_dup); + if (!p) { + vec_add2(bound_tracks, btp, 1); + btp->track = track_code; + btp->track_str = pidtid_dup; + hash_set(the_trackdef_hash, track_code, btp - bound_tracks); + hash_set_mem(the_pidtid_hash, pidtid_dup, btp - bound_tracks); + } else { + vec_free(pidtid_dup); + } + ep++; + } + } + + ep = (event_entry_t *)(eh+1); + + for (i = 0; i < nevents; i++) { + time0 = ntohl (ep->time[0]); + time1 = ntohl (ep->time[1]); + + now = (((u64) time0)<<32) | time1; + + event_code = ntohl(ep->event_code); + + /* Find the corresponding track via the pidtid hash table */ + if (event_code == start_event_code || event_code == end_event_code) { + if (have_trackdefs) { + pidtid_str = this_strtab + ntohl(ep->event_datum); + pidtid_dup = format(0, (char *) pidtid_str); + vec_add1(pidtid_dup, 0); + ecp = &pidtid_dup[vec_len(pidtid_dup)-1]; + while (*--ecp == ' ') + *ecp = 0; + } else { + pidtid_dup = format(0, "%d", ntohl(ep->track)); + vec_add1(pidtid_dup, 0); + } + + p = hash_get_mem(the_pidtid_hash, pidtid_dup); + if (!p) { + fprintf(stderr, "warning: couldn't find '%s'\n", + pidtid_dup); + vec_free(pidtid_dup); + ep++; + continue; + } + state_track = &bound_tracks[p[0]]; + } + /* Found the start-event code ? */ + if (event_code == start_event_code) { + state_track->state_start_ticks = now; + } else if (event_code == end_event_code) { + /* + * Add a ticks-in-state record, unless + * e.g. the log started with the exit event + */ + if (state_track->state_start_ticks) { + ticks_in_state = now - state_track->state_start_ticks; + vec_add1(state_track->ticks_in_state, ticks_in_state); + state_track->state_start_ticks = 0; + } + /* Otherwise, nothing */ + } + ep++; + } + return(0); +} + +/* + * Note: If necessary, add passes / columns to this table to + * handle section order dependencies. + */ + +section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] = +{ + {bad_section, noop_pass}, /* type 0 -- f**ked */ + {strtab_pass1, noop_pass}, /* type 1 -- STRTAB */ + {unsupported_pass, noop_pass}, /* type 2 -- SYMTAB */ + {evtdef_pass1, noop_pass}, /* type 3 -- EVTDEF */ + {trackdef_pass1, noop_pass}, /* type 4 -- TRACKDEF */ + {noop_pass, event_pass2}, /* type 5 -- EVENTS */ +}; + + +int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp, + pass_t pass) +{ + u32 type; + type = ntohl(sh->section_type); + int rv; + int (*fp)(cpel_section_header_t *, int, FILE *); + + if (type > CPEL_NUM_SECTION_TYPES) { + fprintf(stderr, "Unknown section type %d\n", type); + return(1); + } + switch(pass) { + case PASS1: + fp = processors[type].pass1; + break; + + case PASS2: + fp = processors[type].pass2; + break; + + default: + fprintf(stderr, "Unknown pass %d\n", pass); + return(1); + } + + rv = (*fp)(sh, verbose, ofp); + + return(rv); +} + +int cpel_dump_file_header(cpel_file_header_t *fh, int verbose, FILE *ofp) +{ + time_t file_time; + + if (verbose) { + fprintf(ofp, "CPEL file: %s-endian, version %d\n", + ((fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) ? + "little" : "big"), + fh->endian_version & CPEL_FILE_VERSION_MASK); + + file_time = ntohl(fh->file_date); + + fprintf(ofp, "File created %s", ctime(&file_time)); + fprintf(ofp, "File has %d sections\n", + ntohs(fh->nsections)); + } + + return(0); +} + + +int cpel_dump(u8 *cpel, int verbose, FILE *ofp) +{ + cpel_file_header_t *fh; + cpel_section_header_t *sh; + u16 nsections; + u32 section_size; + int i; + + /* First, the file header */ + fh = (cpel_file_header_t *)cpel; + if (fh->endian_version != CPEL_FILE_VERSION) { + if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) { + fprintf(stderr, "Little endian data format not supported\n"); + return(1); + } + fprintf(stderr, "Unsupported file version 0x%x\n", + fh->endian_version); + return(1); + } + cpel_dump_file_header(fh, verbose, ofp); + nsections = ntohs(fh->nsections); + + /* + * Take two passes through the file. PASS1 builds + * data structures, PASS2 actually dumps the file. + * Just in case the sections are in an unobvious order. + */ + sh = (cpel_section_header_t *)(fh+1); + for (i = 0; i < nsections; i++) { + section_size = ntohl(sh->data_length); + + if(verbose) { + fprintf(ofp, "Section type %d, size %d\n", ntohl(sh->section_type), + section_size); + } + + if(process_section(sh, verbose, ofp, PASS1)) + return(1); + + sh++; + sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); + } + + sh = (cpel_section_header_t *)(fh+1); + for (i = 0; i < nsections; i++) { + if(process_section(sh, verbose, ofp, PASS2)) + return(1); + section_size = ntohl(sh->data_length); + sh++; + sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); + } + return(0); +} + +void compute_state_statistics(int verbose, FILE *ofp) +{ + int i, j; + bound_track_t *bp; + f64 fticks; + + /* Across the bound tracks */ + for (i = 0; i < vec_len(bound_tracks); i++) { + bp = &bound_tracks[i]; + bp->mean_ticks_in_state = 0.0; + bp->variance_ticks_in_state = 0.0; + bp->total_ticks_in_state = 0.0; + for (j = 0; j < vec_len(bp->ticks_in_state); j++) { + bp->total_ticks_in_state += (f64) bp->ticks_in_state[j]; + } + /* Compute mean */ + if (vec_len(bp->ticks_in_state)) { + bp->mean_ticks_in_state = bp->total_ticks_in_state / + ((f64) vec_len(bp->ticks_in_state)); + } + /* Accumulate sum: (Xi-Xbar)**2 */ + for (j = 0; j < vec_len(bp->ticks_in_state); j++) { + fticks = bp->ticks_in_state[j]; + bp->variance_ticks_in_state += + (fticks - bp->mean_ticks_in_state)* + (fticks - bp->mean_ticks_in_state); + } + /* Compute s**2, the unbiased estimator of sigma**2 */ + if (vec_len(bp->ticks_in_state) > 1) { + bp->variance_ticks_in_state /= (f64) + (vec_len(bp->ticks_in_state)-1); + } + } +} + +int track_compare_max (const void *arg1, const void *arg2) +{ + bound_track_t *a1 = (bound_track_t *)arg1; + bound_track_t *a2 = (bound_track_t *)arg2; + f64 v1, v2; + + v1 = a1->total_ticks_in_state; + v2 = a2->total_ticks_in_state; + + if (v1 < v2) + return (1); + else if (v1 == v2) + return (0); + else return (-1); +} + +int track_compare_occurrences (const void *arg1, const void *arg2) +{ + bound_track_t *a1 = (bound_track_t *)arg1; + bound_track_t *a2 = (bound_track_t *)arg2; + f64 v1, v2; + + v1 = (f64) vec_len(a1->ticks_in_state); + v2 = (f64) vec_len(a2->ticks_in_state); + + if (v1 < v2) + return (1); + else if (v1 == v2) + return (0); + else return (-1); +} + +int track_compare_name (const void *arg1, const void *arg2) +{ + bound_track_t *a1 = (bound_track_t *)arg1; + bound_track_t *a2 = (bound_track_t *)arg2; + + return (strcmp((char *)(a1->track_str), (char *)(a2->track_str))); +} + +void sort_state_statistics(sort_t type, FILE *ofp) +{ + int (*compare)(const void *, const void *) = 0; + + if (summary_stats_only) + return; + + switch(type) { + case SORT_MAX_TIME: + fprintf(ofp, "Results sorted by max time in state.\n\n"); + compare = track_compare_max; + break; + + case SORT_MAX_OCCURRENCES: + fprintf(ofp, "Results sorted by max occurrences of state.\n\n"); + compare = track_compare_occurrences; + break; + + case SORT_NAME: + compare = track_compare_name; + fprintf(ofp, "Results sorted by process name, thread ID, PID\n\n"); + break; + + default: + fatal("sort type not set?"); + } + + qsort (bound_tracks, vec_len(bound_tracks), + sizeof (bound_track_t), compare); +} + +void print_state_statistics(int verbose, FILE *ofp) +{ + int i,j; + u8 *trackpad; + bound_track_t *bp; + f64 total_time = 0.0; + f64 total_switches = 0.0; + + trackpad = format(0, "%%-%ds ", widest_track_format); + vec_add1(trackpad, 0); + + if (!summary_stats_only) { + fprintf(ofp, (char *)trackpad, "ProcName Thread(PID)"); + fprintf(ofp, " Mean(us) Stdev(us) Total(us) N\n"); + } + + for (i = 0; i < vec_len(bound_tracks); i++) { + bp = &bound_tracks[i]; + if (bp->mean_ticks_in_state == 0.0) + continue; + + if (name_filter && + strncmp((char *)bp->track_str, (char *)name_filter, + strlen((char *)name_filter))) + continue; + + /* + * Exclude kernel threads (e.g. idle thread) from + * state statistics + */ + if (exclude_kernel_from_summary_stats && + !strncmp((char *) bp->track_str, "kernel ", 7)) + continue; + + total_switches += (f64) vec_len(bp->ticks_in_state); + + if (!summary_stats_only) { + fprintf(ofp, (char *) trackpad, bp->track_str); + fprintf(ofp, "%10.3f +- %10.3f", + bp->mean_ticks_in_state / ticks_per_us, + sqrt(bp->variance_ticks_in_state) + / ticks_per_us); + fprintf(ofp, "%12.3f", + bp->total_ticks_in_state / ticks_per_us); + fprintf(ofp, "%8d\n", vec_len(bp->ticks_in_state)); + } + + if (scatterplot) { + for (j = 0; j < vec_len(bp->ticks_in_state); j++) { + fprintf(ofp, "%.3f\n", + (f64)bp->ticks_in_state[j] / ticks_per_us); + } + } + + total_time += bp->total_ticks_in_state; + } + + if (!summary_stats_only) + fprintf(ofp, "\n"); + fprintf(ofp, "Note: the following statistics %s kernel-thread activity.\n", + exclude_kernel_from_summary_stats ? "exclude" : "include"); + if (name_filter) + fprintf(ofp, + "Note: only pid/proc/threads matching '%s' are included.\n", + name_filter); + + fprintf(ofp, + "Total time in state: %10.3f (us), Total state occurrences: %.0f\n", + total_time / ticks_per_us, total_switches); + fprintf(ofp, "Average time in state: %10.3f (us)\n", + (total_time / total_switches) / ticks_per_us); + fprintf(ofp, "State start event: %d, state end event: %d\n", + start_event_code, end_event_code); +} + +char *mapfile (char *file) +{ + struct stat statb; + char *rv; + int maphfile; + size_t mapfsize; + + maphfile = open (file, O_RDONLY); + + if (maphfile < 0) + { + fprintf (stderr, "Couldn't read %s, skipping it...\n", file); + return (NULL); + } + + if (fstat (maphfile, &statb) < 0) + { + fprintf (stderr, "Couldn't get size of %s, skipping it...\n", file); + return (NULL); + } + + /* Don't try to mmap directories, FIFOs, semaphores, etc. */ + if (! (statb.st_mode & S_IFREG)) { + fprintf (stderr, "%s is not a regular file, skipping it...\n", file); + return (NULL); + } + + mapfsize = statb.st_size; + + if (mapfsize < 3) + { + fprintf (stderr, "%s zero-length, skipping it...\n", file); + close (maphfile); + return (NULL); + } + + rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0); + + if (rv == 0) + { + fprintf (stderr, "%s problem mapping, I quit...\n", file); + exit (-1); + } + close (maphfile); + return (rv); +} + +/* + * main + */ +int main (int argc, char **argv) +{ + char *cpel_file = 0; + char *outputfile = 0; + FILE *ofp; + char *cpel; + int verbose=0; + int curarg=1; + + while (curarg < argc) { + if (!strncmp(argv[curarg], "--input-file", 3)) { + curarg++; + if (curarg < argc) { + cpel_file = argv[curarg]; + curarg++; + continue; + } + fatal("Missing filename after --input-file\n"); + } + if (!strncmp(argv[curarg], "--output-file", 3)) { + curarg ++; + if (curarg < argc) { + outputfile = argv[curarg]; + curarg ++; + continue; + } + fatal("Missing filename after --output-file\n"); + } + if (!strncmp(argv[curarg], "--verbose", 3)) { + curarg++; + verbose++; + continue; + } + if (!strncmp(argv[curarg], "--scatterplot", 4)) { + curarg++; + scatterplot=1; + continue; + } + + if (!strncmp(argv[curarg], "--start-event", 4)) { + curarg++; + if (curarg < argc) { + start_event_code = atol(argv[curarg]); + curarg ++; + continue; + } + fatal("Missing integer after --start-event\n"); + } + if (!strncmp(argv[curarg], "--end-event", 4)) { + curarg++; + if (curarg < argc) { + end_event_code = atol(argv[curarg]); + curarg ++; + continue; + } + fatal("Missing integer after --end-event\n"); + } + if (!strncmp(argv[curarg], "--max-time-sort", 7)) { + sort_type = SORT_MAX_TIME; + curarg++; + continue; + } + if (!strncmp(argv[curarg], "--max-occurrence-sort", 7)) { + sort_type = SORT_MAX_OCCURRENCES; + curarg++; + continue; + } + if (!strncmp(argv[curarg], "--name-sort", 3)) { + sort_type = SORT_NAME; + curarg++; + continue; + } + if (!strncmp(argv[curarg], "--kernel-included", 3)) { + exclude_kernel_from_summary_stats = 0; + curarg++; + continue; + } + if (!strncmp(argv[curarg], "--summary", 3)) { + summary_stats_only=1; + curarg++; + continue; + } + if (!strncmp(argv[curarg], "--filter", 3)) { + curarg ++; + if (curarg < argc) { + name_filter = (u8 *) argv[curarg]; + curarg ++; + continue; + } + fatal("Missing filter string after --filter\n"); + } + + + usage: + fprintf(stderr, + "cpelatency --input-file [--output-file ]\n"); + fprintf(stderr, + " [--start-event ] [--verbose]\n"); + fprintf(stderr, + " [--end-event ]\n"); + fprintf(stderr, + " [--max-time-sort(default) | --max-occurrence-sort |\n"); + + fprintf(stderr, + " --name-sort-sort] [--kernel-included]\n"); + + fprintf(stderr, + " [--summary-stats-only] [--scatterplot]\n"); + + fprintf(stderr, "%s\n", version); + exit(1); + } + + if (cpel_file == 0) + goto usage; + + cpel = mapfile(cpel_file); + if (cpel == 0) { + fprintf(stderr, "Couldn't map %s...\n", cpel_file); + exit(1); + } + + if (!outputfile) { + ofp = fdopen(1, "w"); + if (ofp == NULL) { + fprintf(stderr, "Couldn't fdopen(1)?\n"); + exit(1); + } + } else { + ofp = fopen(outputfile, "w"); + if (ofp == NULL) { + fprintf(stderr, "Couldn't create %s...\n", outputfile); + exit(1); + } + } + + the_strtab_hash = hash_create_string (0, sizeof (uword)); + the_evtdef_hash = hash_create (0, sizeof (uword)); + the_trackdef_hash = hash_create (0, sizeof (uword)); + the_pidtid_hash = hash_create_string (0, sizeof(uword)); + + if (cpel_dump((u8 *)cpel, verbose, ofp)) { + if (outputfile) + unlink(outputfile); + } + + compute_state_statistics(verbose, ofp); + sort_state_statistics(sort_type, ofp); + print_state_statistics(verbose, ofp); + + fclose(ofp); + return(0); +} diff --git a/src/tools/perftool/cpeldump.c b/src/tools/perftool/cpeldump.c new file mode 100644 index 00000000..9011bd03 --- /dev/null +++ b/src/tools/perftool/cpeldump.c @@ -0,0 +1,638 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2006-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 +#include "cpel.h" + +char *time_format = "%.03d:%.02d:%.02d:%.03d:%.03d "; +static char version[] = "cpeldump 2.0"; + +#define USEC_PER_MS 1000LL +#define USEC_PER_SECOND (1000*USEC_PER_MS) +#define USEC_PER_MINUTE (60*USEC_PER_SECOND) +#define USEC_PER_HOUR (60*USEC_PER_MINUTE) + +uword *the_strtab_hash; /* (name, base-VA) hash of all string tables */ +uword *the_evtdef_hash; /* (event-id, event-definition) hash */ +uword *the_trackdef_hash; /* (track-id, track-definition) hash */ + +int widest_name_format=5; +int widest_track_format=5; + +typedef struct bound_event_ { + u32 event_code; + u8 *event_str; + u8 *datum_str; + u32 is_strtab_ref; +} bound_event_t; + +bound_event_t *bound_events; + +typedef struct bound_track_ { + u32 track; + u8 *track_str; +} bound_track_t; + +bound_track_t *bound_tracks; + +void fatal(char *s) +{ + fprintf(stderr, "%s", s); + exit(1); +} + +typedef enum { + PASS1=1, + PASS2=2, +} pass_t; + +typedef struct { + int (*pass1)(cpel_section_header_t *, int, FILE *); + int (*pass2)(cpel_section_header_t *, int, FILE *); +} section_processor_t; + +int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + fprintf(ofp, "Bad (type 0) section, skipped...\n"); + return(0); +} + +int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + return(0); +} + +int strtab_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + uword *p; + u8 *strtab_data_area = (u8 *)(sh+1); + + /* Multiple string tables with the same name are Bad... */ + p = hash_get_mem(the_strtab_hash, strtab_data_area); + if (p) { + fprintf(ofp, "Duplicate string table name %s", strtab_data_area); + } + /* + * Looks funny, but we really do want key = first string in the + * table, value = address(first string in the table) + */ + hash_set_mem(the_strtab_hash, strtab_data_area, strtab_data_area); + if (verbose) { + fprintf(stderr, "String Table %s\n", strtab_data_area); + } + return(0); +} + +int evtdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + int i, nevents; + event_definition_section_header_t *edh; + event_definition_t *ep; + u8 *this_strtab; + u32 event_code; + uword *p; + bound_event_t *bp; + int thislen; + + edh = (event_definition_section_header_t *)(sh+1); + nevents = ntohl(edh->number_of_event_definitions); + + if (verbose) { + fprintf(stderr, "Event Definition Section: %d definitions\n", + nevents); + } + + p = hash_get_mem(the_strtab_hash, edh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + this_strtab = (u8 *)p[0]; + + ep = (event_definition_t *)(edh+1); + + for (i = 0; i < nevents; i++) { + event_code = ntohl(ep->event); + p = hash_get(the_evtdef_hash, event_code); + if (p) { + fprintf(ofp, "Event %d redefined, retain first definition\n", + event_code); + continue; + } + vec_add2(bound_events, bp, 1); + bp->event_code = event_code; + bp->event_str = this_strtab + ntohl(ep->event_format); + bp->datum_str = this_strtab + ntohl(ep->datum_format); + bp->is_strtab_ref = 0; + /* Decide if the datum format is a %s format => strtab reference */ + { + int j; + int seen_percent=0; + + for (j = 0; j < strlen((char *)bp->datum_str); j++) { + if (bp->datum_str[j] == '%'){ + seen_percent=1; + continue; + } + if (seen_percent && bp->datum_str[j] == 's') { + bp->is_strtab_ref = 1; + } + } + } + + hash_set(the_evtdef_hash, event_code, bp - bound_events); + + thislen = strlen((char *)bp->event_str); + if (thislen > widest_name_format) + widest_name_format = thislen; + + ep++; + } + return (0); +} + +int trackdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + int i, nevents; + track_definition_section_header_t *tdh; + track_definition_t *tp; + u8 *this_strtab; + u32 track_code; + uword *p; + bound_track_t *btp; + int thislen; + + tdh = (track_definition_section_header_t *)(sh+1); + nevents = ntohl(tdh->number_of_track_definitions); + + if (verbose) { + fprintf(stderr, "Track Definition Section: %d definitions\n", + nevents); + } + + p = hash_get_mem(the_strtab_hash, tdh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + this_strtab = (u8 *)p[0]; + + tp = (track_definition_t *)(tdh+1); + + for (i = 0; i < nevents; i++) { + track_code = ntohl(tp->track); + p = hash_get(the_trackdef_hash, track_code); + if (p) { + fprintf(ofp, "track %d redefined, retain first definition\n", + track_code); + continue; + } + vec_add2(bound_tracks, btp, 1); + btp->track = track_code; + btp->track_str = this_strtab + ntohl(tp->track_format); + hash_set(the_trackdef_hash, track_code, btp - bound_tracks); + + thislen = strlen((char *)btp->track_str); + if (thislen > widest_track_format) + widest_track_format = thislen; + tp++; + } + return (0); +} + +int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + if (verbose) { + fprintf(stderr, "Unsupported type %d section\n", + ntohl(sh->section_type)); + } + return(0); +} + +int event_pass2(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + event_section_header_t *eh; + f64 ticks_per_us; + u32 event_code, track_code; + u64 starttime = 0xFFFFFFFFFFFFFFFFULL; + int nevents; + int i; + uword *p; + event_entry_t *ep; + u64 now; + u64 delta; + u32 hours, minutes, seconds, msec, usec; + u32 time0, time1; + double d; + bound_event_t *bp; + bound_event_t generic_event; + bound_track_t *tp=0; + bound_track_t generic_track; + u32 last_track_code; + u8 *s, *evtpad, *trackpad; + u8 *this_strtab; + + generic_event.event_str = (u8 *)"%d"; + generic_event.datum_str = (u8 *)"0x%08x"; + generic_event.is_strtab_ref = 0; + + generic_track.track_str = (u8 *)"%d"; + last_track_code = 0xdeadbeef; + + eh = (event_section_header_t *)(sh+1); + nevents = ntohl(eh->number_of_events); + ticks_per_us = ((double)ntohl(eh->clock_ticks_per_second)) / 1e6; + + if (verbose) { + fprintf(stderr, "Event section: %d events, %.3f ticks_per_us\n", + nevents, ticks_per_us); + } + + ep = (event_entry_t *)(eh+1); + + p = hash_get_mem(the_strtab_hash, eh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + this_strtab = (u8 *)p[0]; + + evtpad = format(0, "%%-%ds ", widest_name_format); + vec_add1(evtpad, 0); + trackpad = format(0, "%%-%ds ", widest_track_format); + vec_add1(trackpad, 0); + + for (i = 0; i < nevents; i++) { + time0 = ntohl (ep->time[0]); + time1 = ntohl (ep->time[1]); + + now = (((u64) time0)<<32) | time1; + + /* Convert from bus ticks to usec */ + d = now; + d /= ticks_per_us; + + now = d; + + if (starttime == 0xFFFFFFFFFFFFFFFFULL) + starttime = now; + + delta = now - starttime; + + /* Delta = time since first event, in usec */ + + hours = delta / USEC_PER_HOUR; + if (hours) + delta -= ((u64) hours * USEC_PER_HOUR); + minutes = delta / USEC_PER_MINUTE; + if (minutes) + delta -= ((u64) minutes * USEC_PER_MINUTE); + seconds = delta / USEC_PER_SECOND; + if (seconds) + delta -= ((u64) seconds * USEC_PER_SECOND); + msec = delta / USEC_PER_MS; + if (msec) + delta -= ((u64) msec * USEC_PER_MS); + + usec = delta; + + /* Output the timestamp */ + fprintf(ofp, time_format, hours, minutes, seconds, msec, usec); + + /* output the track */ + track_code = ntohl(ep->track); + + if (track_code != last_track_code) { + p = hash_get(the_trackdef_hash, track_code); + if (p) { + tp = &bound_tracks[p[0]]; + } else { + tp = &generic_track; + } + } + s = format(0, (char *)tp->track_str, track_code); + vec_add1(s, 0); + fprintf(ofp, (char *)trackpad, s); + vec_free(s); + + /* output the event and datum */ + if (0 && verbose) { + fprintf(stderr, "raw event code %d, raw event datum 0x%x\n", + ntohl(ep->event_code), ntohl(ep->event_datum)); + } + + event_code = ntohl(ep->event_code); + p = hash_get(the_evtdef_hash, event_code); + if (p) { + bp = &bound_events[p[0]]; + } else { + bp = &generic_event; + } + s = format(0, (char *)bp->event_str, ntohl(ep->event_code)); + vec_add1(s, 0); + fprintf(ofp, (char *)evtpad, s); + vec_free(s); + if (bp->is_strtab_ref) { + fprintf(ofp, (char *) bp->datum_str, + &this_strtab[ntohl(ep->event_datum)]); + } else { + fprintf(ofp, (char *) bp->datum_str, ntohl(ep->event_datum)); + } + fputs("\n", ofp); + ep++; + } + vec_free(evtpad); + vec_free(trackpad); + return(0); +} + +/* + * Note: If necessary, add passes / columns to this table to + * handle section order dependencies. + */ + +section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] = +{ + {bad_section, noop_pass}, /* type 0 -- f**ked */ + {strtab_pass1, noop_pass}, /* type 1 -- STRTAB */ + {unsupported_pass, noop_pass}, /* type 2 -- SYMTAB */ + {evtdef_pass1, noop_pass}, /* type 3 -- EVTDEF */ + {trackdef_pass1, noop_pass}, /* type 4 -- TRACKDEF */ + {noop_pass, event_pass2}, /* type 5 -- EVENTS */ +}; + + +int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp, + pass_t pass) +{ + u32 type; + type = ntohl(sh->section_type); + int rv; + int (*fp)(cpel_section_header_t *, int, FILE *); + + if (type > CPEL_NUM_SECTION_TYPES) { + fprintf(stderr, "Unknown section type %d\n", type); + return(1); + } + switch(pass) { + case PASS1: + fp = processors[type].pass1; + break; + + case PASS2: + fp = processors[type].pass2; + break; + + default: + fprintf(stderr, "Unknown pass %d\n", pass); + return(1); + } + + rv = (*fp)(sh, verbose, ofp); + + return(rv); +} + +int cpel_dump_file_header(cpel_file_header_t *fh, int verbose, FILE *ofp) +{ + time_t file_time; + + if (verbose) { + fprintf(stderr, "CPEL file: %s-endian, version %d\n", + ((fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) ? + "little" : "big"), + fh->endian_version & CPEL_FILE_VERSION_MASK); + + file_time = ntohl(fh->file_date); + + fprintf(stderr, "File created %s", ctime(&file_time)); + fprintf(stderr, "File has %d sections\n", + ntohs(fh->nsections)); + } + + return(0); +} + + +int cpel_dump(u8 *cpel, int verbose, FILE *ofp) +{ + cpel_file_header_t *fh; + cpel_section_header_t *sh; + u16 nsections; + u32 section_size; + int i; + + /* First, the file header */ + fh = (cpel_file_header_t *)cpel; + if (fh->endian_version != CPEL_FILE_VERSION) { + if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) { + fprintf(stderr, "Little endian data format not supported\n"); + return(1); + } + fprintf(stderr, "Unsupported file version 0x%x\n", + fh->endian_version); + return(1); + } + cpel_dump_file_header(fh, verbose, ofp); + nsections = ntohs(fh->nsections); + + /* + * Take two passes through the file. PASS1 builds + * data structures, PASS2 actually dumps the file. + * Just in case the sections are in an unobvious order. + */ + sh = (cpel_section_header_t *)(fh+1); + for (i = 0; i < nsections; i++) { + section_size = ntohl(sh->data_length); + + if(verbose) { + fprintf(stderr, + "Section type %d, size %d\n", ntohl(sh->section_type), + section_size); + } + + if(process_section(sh, verbose, ofp, PASS1)) + return(1); + + sh++; + sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); + } + + sh = (cpel_section_header_t *)(fh+1); + for (i = 0; i < nsections; i++) { + if(process_section(sh, verbose, ofp, PASS2)) + return(1); + section_size = ntohl(sh->data_length); + sh++; + sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); + } + return(0); +} + + +char *mapfile (char *file) +{ + struct stat statb; + char *rv; + int maphfile; + size_t mapfsize; + + maphfile = open (file, O_RDONLY); + + if (maphfile < 0) + { + fprintf (stderr, "Couldn't read %s, skipping it...\n", file); + return (NULL); + } + + if (fstat (maphfile, &statb) < 0) + { + fprintf (stderr, "Couldn't get size of %s, skipping it...\n", file); + return (NULL); + } + + /* Don't try to mmap directories, FIFOs, semaphores, etc. */ + if (! (statb.st_mode & S_IFREG)) { + fprintf (stderr, "%s is not a regular file, skipping it...\n", file); + return (NULL); + } + + mapfsize = statb.st_size; + + if (mapfsize < 3) + { + fprintf (stderr, "%s zero-length, skipping it...\n", file); + close (maphfile); + return (NULL); + } + + rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0); + + if (rv == 0) + { + fprintf (stderr, "%s problem mapping, I quit...\n", file); + exit (-1); + } + close (maphfile); + return (rv); +} + +/* + * main + */ +int main (int argc, char **argv) +{ + char *cpel_file = 0; + char *outputfile = 0; + FILE *ofp; + char *cpel; + int verbose=0; + int curarg=1; + + while (curarg < argc) { + if (!strncmp(argv[curarg], "--input-file", 3)) { + curarg++; + if (curarg < argc) { + cpel_file = argv[curarg]; + curarg++; + continue; + } + fatal("Missing filename after --input-file\n"); + } + if (!strncmp(argv[curarg], "--output-file", 3)) { + curarg ++; + if (curarg < argc) { + outputfile = argv[curarg]; + curarg ++; + continue; + } + fatal("Missing filename after --output-file\n"); + } + if (!strncmp(argv[curarg], "--verbose", 3)) { + curarg++; + verbose = 1; + continue; + } + + usage: + fprintf(stderr, + "cpeldump --input-file [--output-file ]\n"); + fprintf(stderr, "%s\n", version); + exit(1); + } + + if (cpel_file == 0) + goto usage; + + cpel = mapfile(cpel_file); + if (cpel == 0) { + fprintf(stderr, "Couldn't map %s...\n", cpel_file); + exit(1); + } + + if (!outputfile) { + ofp = fdopen(1, "w"); + if (ofp == NULL) { + fprintf(stderr, "Couldn't fdopen(1)?\n"); + exit(1); + } + } else { + ofp = fopen(outputfile, "w"); + if (ofp == NULL) { + fprintf(stderr, "Couldn't create %s...\n", outputfile); + exit(1); + } + } + + the_strtab_hash = hash_create_string (0, sizeof (uword)); + the_evtdef_hash = hash_create (0, sizeof (uword)); + the_trackdef_hash = hash_create (0, sizeof (uword)); + +#ifdef TEST_TRACK_INFO + { + bound_track_t *btp; + vec_add2(bound_tracks, btp, 1); + btp->track = 0; + btp->track_str = "cpu %d"; + hash_set(the_trackdef_hash, 0, btp - bound_tracks); + hash_set(the_trackdef_hash, 1, btp - bound_tracks); + } +#endif + + if (cpel_dump((u8 *)cpel, verbose, ofp)) { + if (outputfile) + unlink(outputfile); + } + + fclose(ofp); + return(0); +} diff --git a/src/tools/perftool/cpelinreg.c b/src/tools/perftool/cpelinreg.c new file mode 100644 index 00000000..115afad7 --- /dev/null +++ b/src/tools/perftool/cpelinreg.c @@ -0,0 +1,892 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2008-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Search for O(N**2) functions bracketed by before/after + * events. The "before" event's datum is used as a tag, e.g. which function + * did we call that's strongly O(N). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cpel.h" + +FILE *g_ifp; +char *g_ifile; + +typedef unsigned long long ulonglong; + +void process_traces (void); +void record_instance (ulong tag, ulonglong time); +void report_actors (void); +void scatterplot_data(void); +int entry_event, exit_event; +int nokey; +char *version = "cpelinreg 2.0"; +int model_these[10]; +int model_index; +int summary_stats; +ulonglong first_start_time; +ulonglong last_end_time; +ulonglong total_time; +ulong scatterkey; +int inline_mokus; + +typedef struct bound_track_ { + u32 track_code; + u32 *start_datum; + u8 *dup_event; + int state; + u64 *start_time; + u64 thread_timestamp; + u64 time_thread_on_cpu; +} bound_track_t; + +bound_track_t *bound_tracks; +uword *the_trackdef_hash; + + +#define MAXSTACK 128 + +typedef struct instance_ { + struct instance_ *next; + ulonglong time; +}instance_t; + +typedef struct actor_ { + struct actor_ *next; + ulong key; + struct instance_ *first; + struct instance_ *last; + double a; + double b; + double min; + double max; + double mean; + double r; + ulong ninst; +} actor_t; + +#define NBUCKETS 1811 + +actor_t *hash[NBUCKETS]; + +actor_t *find_or_create_actor (ulong key) +{ + ulong bucket; + actor_t *ap; + u8 *mem; + + bucket = key % NBUCKETS; + + ap = hash[bucket]; + + if (ap == NULL) { + /* Ensure 8-byte alignment to avoid (double) alignment faults */ + mem = malloc(sizeof(*ap) + 4); + if (((uword)(mem)) & 0x7) + mem += 4; + ap = (actor_t *)mem; + + if (ap == NULL) { + fprintf (stderr, "out of memory...\n"); + exit (1); + } + ap->next = 0; + ap->key = key; + ap->first = 0; + ap->last = 0; + ap->a = 0.00; + ap->b = 0.00; + hash [bucket] = ap; + return (ap); + } + + while (ap) { + if (ap->key == key) + return (ap); + ap = ap->next; + } + + mem = malloc(sizeof(*ap)+4); + if (((uword)(mem) & 0x7)) + mem += 4; + ap = (actor_t *)mem; + + if (ap == NULL) { + fprintf (stderr, "out of memory...\n"); + exit (1); + } + ap->key = key; + ap->first = 0; + ap->last = 0; + ap->a = 0.00; + ap->b = 0.00; + + ap->next = hash[bucket]; + hash[bucket] = ap; + + return (ap); +} + +void record_instance (ulong key, ulonglong time) +{ + actor_t *ap; + instance_t *ip; + + if (nokey) + key = 0; + + ap = find_or_create_actor (key); + + ip = (instance_t *)malloc(sizeof(*ip)); + if (ip == NULL) { + fprintf (stderr, "out of memory...\n"); + exit (1); + } + ip->time = time; + ip->next = 0; + + if (ap->first == 0) { + ap->first = ip; + ap->last = ip; + ap->ninst = 1; + } else { + ap->last->next = ip; + ap->last = ip; + ap->ninst++; + } +} + +#define NINSTANCE 200000 + +double x[NINSTANCE]; +double y[NINSTANCE]; + +int actor_compare (const void *arg1, const void *arg2) +{ + double e10k1, e10k2; + actor_t **a1 = (actor_t **)arg1; + actor_t **a2 = (actor_t **)arg2; + double ninst1, ninst2; + + ninst1 = ((double)((*a1)->ninst)); + ninst2 = ((double)((*a2)->ninst)); + + e10k1 = ninst1 * ((*a1)->mean); + e10k2 = ninst2 * ((*a2)->mean); + + if (e10k1 < e10k2) + return (1); + else if (e10k1 == e10k2) + return (0); + else + return (-1); +} + +void report_actors (void) +{ + int i; + actor_t *ap; + instance_t *ip; + int nactors = 0; + int ninstance; + actor_t **actor_vector; + double e10k; + extern void linreg (double *x, double *y, int nitems, double *a, double *b, + double *minp, double *maxp, double *meanp, double *r); + + for (i = 0; i < NBUCKETS; i++) { + ap = hash[i]; + if (ap == NULL) + continue; + while (ap) { + nactors++; + ninstance = 0; + + ip = ap->first; + + while (ip) { + if (ninstance < NINSTANCE) { + x[ninstance] = ninstance; + y[ninstance] = ((double)ip->time); + ninstance++; + } + ip = ip->next; + } + if (ninstance > 1) { +#if DEBUG > 0 + int j; + + for (j = 0; j < ninstance; j++) { + printf("x[%d] = %10.2f, y[%d] = %10.2f\n", + j, x[j], j, y[j]); + } +#endif + + linreg (x, y, ninstance, &ap->a, &ap->b, &ap->min, + &ap->max, &ap->mean, &ap->r); + } else { + ap->a = 0.00; + ap->b = 0.00; + } + + ap = ap->next; + } + } + + actor_vector = (actor_t **)malloc (nactors*sizeof(*actor_vector)); + nactors = 0; + + for (i = 0; i < NBUCKETS; i++) { + ap = hash[i]; + if (ap == NULL) + continue; + while (ap) { + if ((ap->a != 0.00) || (ap->b != 0.00)) { + actor_vector[nactors++] = ap; + } + ap = ap->next; + } + } + + qsort (actor_vector, nactors, sizeof (actor_t *), actor_compare); + + if (summary_stats) + printf("NInst Offset Slope T(Ninst) Min Max Avg %%InstTime R Key"); + else + printf("NInst Offset Slope T(Ninst) Key"); + + for (i = 0; i < model_index; i++) { + printf ("T @ %-8d ", model_these[i]); + } + + printf ("\n"); + + for (i = 0; i < nactors; i++) { + int j; + double ninst; + double pcttot; + ap = actor_vector[i]; + ninst = ap->ninst; + + e10k = ninst * (ap->a + ap->b*((ninst-1.0)/2.0)); + + if (ap->ninst) { + if (summary_stats) { + pcttot = (e10k / ((double)total_time)) * 100.0; + printf ("%6ld %11.2f %11.2f %11.2f %11.2f %11.2f %11.2f %11.2f %11.2f 0x%08lx ", + ap->ninst, ap->a, ap->b, e10k, ap->min, + ap->max, ap->mean, pcttot, ap->r, ap->key); + } + else + printf ("%6ld %11.2f %11.2f %11.2f 0x%08lx ", + ap->ninst, ap->a, ap->b, e10k, ap->key); + + for (j = 0; j < model_index; j++) { + ninst = model_these[j]; + e10k = ninst * (ap->a + ap->b*((ninst-1.0)/2.0)); + printf ("%10.2f ", e10k); + } + printf ("\n"); + } + } +} + +void scatterplot_data(void) +{ + actor_t *ap; + int i; + instance_t *ip; + double time; + int count=0; + + for (i = 0; i < NBUCKETS; i++) { + ap = hash[i]; + if (ap == NULL) + continue; + while (ap) { + if (ap->key == scatterkey){ + ip = ap->first; + while (ip) { + time = ((double)ip->time); + printf ("%d\t%.0f\n", count++, time); + ip = ip->next; + } + return; + } + ap = ap->next; + } + } +} + + +void fatal(char *s) +{ + fprintf(stderr, "%s", s); + fprintf(stderr, "\n"); + exit(1); +} + +typedef enum { + PASS1=1, +} pass_t; + +typedef struct { + int (*pass1)(cpel_section_header_t *, int, FILE *); +} section_processor_t; + +int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + fprintf(ofp, "Bad (type 0) section, skipped...\n"); + return(0); +} + +int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + return(0); +} + +int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + if (verbose) { + fprintf(ofp, "Unsupported type %d section\n", + ntohl(sh->section_type)); + } + return(0); +} + +int trackdef_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + int i, nevents; + track_definition_section_header_t *tdh; + track_definition_t *tp; + u32 track_code; + uword *p; + bound_track_t *btp; + + tdh = (track_definition_section_header_t *)(sh+1); + nevents = ntohl(tdh->number_of_track_definitions); + + if (verbose) { + fprintf(stderr, "Track Definition Section: %d definitions\n", + nevents); + } + + tp = (track_definition_t *)(tdh+1); + + for (i = 0; i < nevents; i++) { + track_code = ntohl(tp->track); + p = hash_get(the_trackdef_hash, track_code); + if (p) { + fprintf(ofp, "track %d redefined, retain first definition\n", + track_code); + continue; + } + vec_add2(bound_tracks, btp, 1); + btp->track_code = track_code; + hash_set(the_trackdef_hash, track_code, btp - bound_tracks); + tp++; + } + return (0); +} + + +int event_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + event_section_header_t *eh; + event_entry_t *ep; + f64 ticks_per_us; + long output_count; + long dup_events = 0; + ulonglong end_time = 0; + double t; + int sp, ancestor; + int nevents, i; + u64 now; + u64 time0, time1; + double d; + u32 last_track_code = 0xdeafb00b; + u32 track_code; + u32 event_code, event_datum; + bound_track_t *tp = 0; + uword *p; + + output_count = 0; + total_time = 0; + + eh = (event_section_header_t *)(sh+1); + nevents = ntohl(eh->number_of_events); + ticks_per_us = ((double)ntohl(eh->clock_ticks_per_second))/1e6; + + if (verbose) { + fprintf(ofp, "%.3f ticks_per_us\n", ticks_per_us); + } + + ep = (event_entry_t *)(eh+1); + + time0 = ntohl (ep->time[0]); + time1 = ntohl (ep->time[1]); + + now = (((u64) time0)<<32) | time1; + d = now; + d /= ticks_per_us; + first_start_time = d; + + for (i = 0; i < nevents; i++) { + time0 = ntohl (ep->time[0]); + time1 = ntohl (ep->time[1]); + + now = (((u64) time0)<<32) | time1; + + /* Convert from bus ticks to usec */ + d = now; + d /= ticks_per_us; + + now = d; + + track_code = ntohl(ep->track); + event_code = ntohl(ep->event_code); + event_datum = ntohl(ep->event_datum); + + if (track_code != last_track_code) { + if (tp) { + tp->thread_timestamp += now - tp->time_thread_on_cpu; + tp->time_thread_on_cpu = 0; + } + p = hash_get(the_trackdef_hash, track_code); + if (!p) { + /* synthesize a new track */ + vec_add2(bound_tracks, tp, 1); + tp->track_code = track_code; + hash_set(the_trackdef_hash, track_code, tp - bound_tracks); + } else { + tp = bound_tracks + p[0]; + } + last_track_code = track_code; + tp->time_thread_on_cpu = now; + } + + if (event_code != entry_event && + event_code != exit_event) { + ep++; + continue; + } + + again: + switch (tp->state) { + case 0: /* not in state */ + /* Another exit event? Stack pop */ + if (event_code == exit_event) { + /* Only if we have something on the stack */ + if (vec_len(tp->start_datum) > 0) { + tp->state = 1; + goto again; + } else { + fprintf (stderr, + "End event before start event, key 0x%x.", + ntohl(ep->event_datum)); + fprintf (stderr, " Interpret results carefully...\n"); + } + } + + tp->state = 1; + if (vec_len(tp->start_datum) >= MAXSTACK) { + int j; + + fprintf (stderr, "stack overflow..\n"); + for (j = vec_len(tp->start_datum)-1; j >= 0; j--) { + fprintf(stderr, "stack[%d]: datum 0x%x\n", + j, tp->start_datum[j]); + } + fprintf (stderr, + "Stack overflow... This occurs when " + "(start, datum)...(end, datum) events\n" + "are not properly paired.\n\n" + "A typical scenario looks like this:\n\n" + " ...\n" + " ELOG(..., START_EVENT, datum);\n" + " if (condition)\n" + " return; /*oops, forgot the end event*/\n" + " ELOG(..., END_EVENT, datum);\n" + " ...\n\n" + "The datum stack dump (above) should make it clear\n" + "where to start looking for a sneak path...\n"); + + exit (1); + } + vec_add1(tp->start_datum, event_datum); + vec_add1(tp->start_time, (tp->thread_timestamp + (now - tp->time_thread_on_cpu))); +#ifdef HAVING_TROUBLE + printf ("sp %lld key 0x%x start time %llu\n", + (long long) vec_len(tp->start_time)-1, event_datum, + (unsigned long long) + tp->start_time [vec_len(tp->start_time)-1]); + printf ("timestamp %llu, now %llu, thread on cpu %llu\n", + (unsigned long long) tp->thread_timestamp, + (unsigned long long) now, + (unsigned long long) tp->time_thread_on_cpu); +#endif + + + + /* + * Multiple identical enter events? If the user knows that + * gcc is producing bogus events due to inline functions, + * trash the duplicate. + */ + if (inline_mokus + && vec_len (tp->start_datum) > 1 + && tp->start_datum [vec_len(tp->start_datum)-1] == + tp->start_datum [vec_len(tp->start_datum)-2]) { + vec_add1 (tp->dup_event, 1); + } else { + vec_add1 (tp->dup_event, 0); + } + + + ep++; + continue; + + case 1: /* in state */ + /* Another entry event? Stack push*/ + if (event_code == entry_event) { + tp->state = 0; + goto again; + } + + if (vec_len(tp->start_datum) == 0) { + fprintf (stderr, "Stack underflow...\n"); + exit (1); + } + + sp = vec_len(tp->start_time)-1; + + end_time = tp->thread_timestamp + (now - tp->time_thread_on_cpu); + + if (!tp->dup_event[sp]) { +#ifdef HAVING_TROUBLE + printf ("sp %d key 0x%x charged %llu\n", sp, + tp->start_datum[sp], end_time - tp->start_time[sp]); + printf (" start %llu, end %llu\n", (unsigned long long) tp->start_time[sp], + (unsigned long long) end_time); +#endif + + record_instance (tp->start_datum[sp], (end_time - + tp->start_time[sp])); + + /* Factor out our time from surrounding services, if any */ + for (ancestor = sp-1; ancestor >= 0; ancestor--) { +#ifdef HAVING_TROUBLE + printf ("Factor out %lld from key 0x%08x\n", + (end_time - tp->start_time[sp]), tp->start_datum[ancestor]); +#endif + tp->start_time[ancestor] += (end_time - tp->start_time[sp]); + } + output_count++; + total_time += (end_time - tp->start_time[sp]); + tp->state = 0; + } else { + dup_events++; + } + _vec_len(tp->start_datum) = sp; + _vec_len(tp->start_time) = sp; + _vec_len(tp->dup_event) = sp; + } + + ep++; + } + last_end_time = now; + + if (scatterkey) { + scatterplot_data(); + exit (0); + } + + if (output_count) { + t = (double)total_time; + printf ("%ld instances of state, %.2f microseconds average\n", + output_count, t / output_count); + + printf ("Total instrumented runtime: %.2f microseconds\n", + ((double)total_time)); + printf ("Total runtime: %lld microseconds\n", + last_end_time - first_start_time); + + t /= (double)(last_end_time - first_start_time); + t *= 100.0; + + if (dup_events) { + printf ("Suppressed %ld duplicate state entry events\n", + dup_events); + } + printf ("Instrumented code accounts for %.2f%% of total time.\n\n", + t); + report_actors(); + } else { + printf ("No instances of state...\n"); + } + + return(0); +} + +/* + * Note: If necessary, add passes / columns to this table to + * handle section order dependencies. + */ + +section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] = +{ + {unsupported_pass}, /* type 0 -- f**ked */ + {noop_pass}, /* type 1 -- STRTAB */ + {noop_pass}, /* type 2 -- SYMTAB */ + {noop_pass}, /* type 3 -- EVTDEF */ + {trackdef_pass}, /* type 4 -- TRACKDEF */ + {event_pass}, /* type 5 -- EVENTS */ +}; + +int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp, + pass_t pass) +{ + u32 type; + type = ntohl(sh->section_type); + int rv; + int (*fp)(cpel_section_header_t *, int, FILE *); + + if (type > CPEL_NUM_SECTION_TYPES) { + fprintf(stderr, "Unknown section type %d\n", type); + return(1); + } + switch(pass) { + case PASS1: + fp = processors[type].pass1; + break; + + default: + fprintf(stderr, "Unknown pass %d\n", pass); + return(1); + } + + rv = (*fp)(sh, verbose, ofp); + + return(rv); +} + +char *mapfile (char *file) +{ + struct stat statb; + char *rv; + int maphfile; + size_t mapfsize; + + maphfile = open (file, O_RDONLY); + + if (maphfile < 0) + { + fprintf (stderr, "Couldn't read %s, skipping it...\n", file); + return (NULL); + } + + if (fstat (maphfile, &statb) < 0) + { + fprintf (stderr, "Couldn't get size of %s, skipping it...\n", file); + return (NULL); + } + + /* Don't try to mmap directories, FIFOs, semaphores, etc. */ + if (! (statb.st_mode & S_IFREG)) { + fprintf (stderr, "%s is not a regular file, skipping it...\n", file); + return (NULL); + } + + mapfsize = statb.st_size; + + if (mapfsize < 3) + { + fprintf (stderr, "%s zero-length, skipping it...\n", file); + close (maphfile); + return (NULL); + } + + rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0); + + if (rv == 0) + { + fprintf (stderr, "%s problem mapping, I quit...\n", file); + exit (-1); + } + close (maphfile); + return (rv); +} + +int process_file (u8 *cpel, int verbose) +{ + cpel_file_header_t *fh; + cpel_section_header_t *sh; + u16 nsections; + u32 section_size; + int i; + FILE *ofp = stderr; + + /* First, the file header */ + fh = (cpel_file_header_t *)cpel; + if (fh->endian_version != CPEL_FILE_VERSION) { + if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) { + fprintf(stderr, "Little endian data format not supported\n"); + return(1); + } + fprintf(stderr, "Unsupported file version 0x%x\n", + fh->endian_version); + return(1); + } + nsections = ntohs(fh->nsections); + + /* + * Take a passe through the file. + */ + sh = (cpel_section_header_t *)(fh+1); + for (i = 0; i < nsections; i++) { + section_size = ntohl(sh->data_length); + + if(verbose) { + fprintf(ofp, "Section type %d, size %d\n", + ntohl(sh->section_type), + section_size); + } + + if(process_section(sh, verbose, ofp, PASS1)) + return(1); + + sh++; + sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); + } + + return(0); +} + +/**************************************************************************** +* main - +****************************************************************************/ + +int main (int argc, char **argv) +{ + int curarg = 1; + u8 *cpel = 0; + int verbose = 0; + + if (argc < 6) + { + fprintf (stderr, "usage: cpelinreg -i \n"); + fprintf (stderr, " -s start-event --e end-event [-nokey]\n"); + fprintf (stderr, " [-m ][-xtra-stats]\n"); + fprintf (stderr, " [-keyscatterplot ]\n\n"); + fprintf (stderr, "%s\n", version); + exit (1); + } + + while (curarg < argc) { + if (!strncmp (argv[curarg], "-ifile", 2)) { + curarg++; + g_ifile = argv[curarg++]; + continue; + } + if (!strncmp (argv[curarg], "-start", 2)) { + curarg++; + entry_event = atol (argv [curarg++]); + continue; + } + if (!strncmp (argv[curarg], "-end", 2)) { + curarg++; + exit_event = atol (argv [curarg++]); + continue; + } + + if (!strncmp(argv[curarg], "-badinlines", 2)) { + curarg++; + inline_mokus = 1; + continue; + } + + if (!strncmp (argv[curarg], "-x", 2)) { + curarg++; + summary_stats=1; + continue; + } + if (!strncmp (argv[curarg], "-nokey", 2)) { + curarg++; + nokey = 1; + continue; + } + if (!strncmp (argv[curarg], "-keyscatterplot", 2)) { + curarg++; + sscanf (argv[curarg], "%lx", &scatterkey); + curarg++; + continue; + } + + if (!strncmp (argv[curarg], "-model", 2)) { + if (model_index >= sizeof(model_these) / sizeof(int)) { + fprintf (stderr, "Too many model requests\n"); + exit (1); + } + curarg++; + model_these[model_index++] = atol (argv [curarg++]); + continue; + } + if (!strncmp (argv[curarg], "-verbose", 2)) { + verbose++; + curarg++; + continue; + } + + fprintf (stderr, "unknown switch '%s'\n", argv[curarg]); + exit (1); + } + + cpel = (u8 *)mapfile(g_ifile); + + if (cpel == NULL) + { + fprintf (stderr, "Couldn't open %s\n", g_ifile); + exit (1); + } + + printf ("Extracting state info from %s\nentry_event %d, exit_event %d\n", + g_ifile, entry_event, exit_event); + if (nokey) { + printf ("All state instances mapped to a single actor chain\n"); + } + + the_trackdef_hash = hash_create (0, sizeof (uword)); + + process_file(cpel, verbose); + exit (0); +} diff --git a/src/tools/perftool/cpelstate.c b/src/tools/perftool/cpelstate.c new file mode 100644 index 00000000..3fd9ccb9 --- /dev/null +++ b/src/tools/perftool/cpelstate.c @@ -0,0 +1,822 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2006-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 +#include "cpel.h" +#include + +char *time_format = "%.03d:%.02d:%.02d:%.03d:%.03d "; +static char version[] = "cpelstate 2.0h"; + +#define USEC_PER_MS 1000LL +#define USEC_PER_SECOND (1000*USEC_PER_MS) +#define USEC_PER_MINUTE (60*USEC_PER_SECOND) +#define USEC_PER_HOUR (60*USEC_PER_MINUTE) + +uword *the_strtab_hash; /* (name, base-VA) hash of all string tables */ +uword *the_evtdef_hash; /* (event-id, event-definition) hash */ +uword *the_trackdef_hash; /* (track-id, track-definition) hash */ + +f64 ticks_per_us; +u32 state_event_code = 1; /* default: XR thread-on-cpu */ +int exclude_kernel_from_summary_stats=1; +int summary_stats_only; +int scatterplot; +u8 *name_filter; + +typedef enum { + SORT_MAX_TIME=1, + SORT_MAX_OCCURRENCES, + SORT_NAME, +} sort_t; + +sort_t sort_type = SORT_MAX_TIME; + +int widest_name_format=5; +int widest_track_format=5; + +typedef struct bound_event_ { + u32 event_code; + u8 *event_str; + u8 *datum_str; + u32 is_strtab_ref; +} bound_event_t; + +bound_event_t *bound_events; + +typedef struct bound_track_ { + u32 track; + u8 *track_str; + u64 *ticks_in_state; /* vector of state occurrences */ + f64 mean_ticks_in_state; + f64 variance_ticks_in_state; + f64 total_ticks_in_state; +} bound_track_t; + +bound_track_t *bound_tracks; + +void fatal(char *s) +{ + fprintf(stderr, "%s", s); + exit(1); +} + +typedef enum { + PASS1=1, + PASS2=2, +} pass_t; + +typedef struct { + int (*pass1)(cpel_section_header_t *, int, FILE *); + int (*pass2)(cpel_section_header_t *, int, FILE *); +} section_processor_t; + +int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + fprintf(ofp, "Bad (type 0) section, skipped...\n"); + return(0); +} + +int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + return(0); +} + +int strtab_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + uword *p; + u8 *strtab_data_area = (u8 *)(sh+1); + + /* Multiple string tables with the same name are Bad... */ + p = hash_get_mem(the_strtab_hash, strtab_data_area); + if (p) { + fprintf(ofp, "Duplicate string table name %s", strtab_data_area); + } + /* + * Looks funny, but we really do want key = first string in the + * table, value = address(first string in the table) + */ + hash_set_mem(the_strtab_hash, strtab_data_area, strtab_data_area); + if (verbose) { + fprintf(ofp, "String Table %s\n", strtab_data_area); + } + return(0); +} + +int evtdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + int i, nevents; + event_definition_section_header_t *edh; + event_definition_t *ep; + u8 *this_strtab; + u32 event_code; + uword *p; + bound_event_t *bp; + int thislen; + + edh = (event_definition_section_header_t *)(sh+1); + nevents = ntohl(edh->number_of_event_definitions); + + if (verbose) { + fprintf(ofp, "Event Definition Section: %d definitions\n", + nevents); + } + + p = hash_get_mem(the_strtab_hash, edh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + this_strtab = (u8 *)p[0]; + + ep = (event_definition_t *)(edh+1); + + for (i = 0; i < nevents; i++) { + event_code = ntohl(ep->event); + p = hash_get(the_evtdef_hash, event_code); + if (p) { + fprintf(ofp, "Event %d redefined, retain first definition\n", + event_code); + continue; + } + vec_add2(bound_events, bp, 1); + bp->event_code = event_code; + bp->event_str = this_strtab + ntohl(ep->event_format); + bp->datum_str = this_strtab + ntohl(ep->datum_format); + bp->is_strtab_ref = 0; + /* Decide if the datum format is a %s format => strtab reference */ + { + int j; + int seen_percent=0; + + for (j = 0; j < strlen((char *)(bp->datum_str)); j++) { + if (bp->datum_str[j] == '%'){ + seen_percent=1; + continue; + } + if (seen_percent && bp->datum_str[j] == 's') { + bp->is_strtab_ref = 1; + } + } + } + + hash_set(the_evtdef_hash, event_code, bp - bound_events); + + thislen = strlen((char *)bp->event_str); + if (thislen > widest_name_format) + widest_name_format = thislen; + + ep++; + } + return (0); +} + +int trackdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + int i, nevents; + track_definition_section_header_t *tdh; + track_definition_t *tp; + u8 *this_strtab; + u32 track_code; + uword *p; + bound_track_t *btp; + int thislen; + + tdh = (track_definition_section_header_t *)(sh+1); + nevents = ntohl(tdh->number_of_track_definitions); + + if (verbose) { + fprintf(ofp, "Track Definition Section: %d definitions\n", + nevents); + } + + p = hash_get_mem(the_strtab_hash, tdh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + this_strtab = (u8 *)p[0]; + + tp = (track_definition_t *)(tdh+1); + + for (i = 0; i < nevents; i++) { + track_code = ntohl(tp->track); + p = hash_get(the_trackdef_hash, track_code); + if (p) { + fprintf(ofp, "track %d redefined, retain first definition\n", + track_code); + continue; + } + vec_add2(bound_tracks, btp, 1); + btp->track = track_code; + btp->track_str = this_strtab + ntohl(tp->track_format); + hash_set(the_trackdef_hash, track_code, btp - bound_tracks); + + thislen = strlen((char *)(btp->track_str)); + if (thislen > widest_track_format) + widest_track_format = thislen; + tp++; + } + return (0); +} + +int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + if (verbose) { + fprintf(ofp, "Unsupported type %d section\n", + ntohl(sh->section_type)); + } + return(0); +} + +int event_pass2(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + event_section_header_t *eh; + u32 track_code; + int nevents; + int i; + uword *p; + event_entry_t *ep; + u64 now; + u32 time0, time1; + bound_track_t generic_track; + u32 last_track_code; + u64 state_start_ticks=0; + u64 ticks_in_state; + bound_track_t *state_track=0; + int in_state=0; + generic_track.track_str = (u8 *) "%d"; + last_track_code = 0xdeafbeef; + + eh = (event_section_header_t *)(sh+1); + nevents = ntohl(eh->number_of_events); + ticks_per_us = ((double)ntohl(eh->clock_ticks_per_second))/1e6; + + if (verbose) { + fprintf(ofp, "%.3f ticks_per_us\n", ticks_per_us); + } + + ep = (event_entry_t *)(eh+1); + + p = hash_get_mem(the_strtab_hash, eh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + + for (i = 0; i < nevents; i++) { + time0 = ntohl (ep->time[0]); + time1 = ntohl (ep->time[1]); + + now = (((u64) time0)<<32) | time1; + + /* Found the state-change event ? */ + if (ntohl(ep->event_code) == state_event_code) { + /* + * Add a ticks-in-state record, unless + * this is the "prime mover" event instance + */ + if (in_state) { + ticks_in_state = now - state_start_ticks; + vec_add1(state_track->ticks_in_state, ticks_in_state); + } + /* switch to now-current track */ + state_start_ticks = now; + track_code = ntohl(ep->track); + if (track_code != last_track_code) { + p = hash_get(the_trackdef_hash, track_code); + if (p) { + state_track = &bound_tracks[p[0]]; + } else { + state_track = &generic_track; + } + last_track_code = track_code; + } + in_state = 1; + } + ep++; + } + return(0); +} + +/* + * Note: If necessary, add passes / columns to this table to + * handle section order dependencies. + */ + +section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] = +{ + {bad_section, noop_pass}, /* type 0 -- f**ked */ + {strtab_pass1, noop_pass}, /* type 1 -- STRTAB */ + {unsupported_pass, noop_pass}, /* type 2 -- SYMTAB */ + {evtdef_pass1, noop_pass}, /* type 3 -- EVTDEF */ + {trackdef_pass1, noop_pass}, /* type 4 -- TRACKDEF */ + {noop_pass, event_pass2}, /* type 5 -- EVENTS */ +}; + + +int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp, + pass_t pass) +{ + u32 type; + type = ntohl(sh->section_type); + int rv; + int (*fp)(cpel_section_header_t *, int, FILE *); + + if (type > CPEL_NUM_SECTION_TYPES) { + fprintf(stderr, "Unknown section type %d\n", type); + return(1); + } + switch(pass) { + case PASS1: + fp = processors[type].pass1; + break; + + case PASS2: + fp = processors[type].pass2; + break; + + default: + fprintf(stderr, "Unknown pass %d\n", pass); + return(1); + } + + rv = (*fp)(sh, verbose, ofp); + + return(rv); +} + +int cpel_dump_file_header(cpel_file_header_t *fh, int verbose, FILE *ofp) +{ + time_t file_time; + + if (verbose) { + fprintf(ofp, "CPEL file: %s-endian, version %d\n", + ((fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) ? + "little" : "big"), + fh->endian_version & CPEL_FILE_VERSION_MASK); + + file_time = ntohl(fh->file_date); + + fprintf(ofp, "File created %s", ctime(&file_time)); + fprintf(ofp, "File has %d sections\n", + ntohs(fh->nsections)); + } + + return(0); +} + + +int cpel_dump(u8 *cpel, int verbose, FILE *ofp) +{ + cpel_file_header_t *fh; + cpel_section_header_t *sh; + u16 nsections; + u32 section_size; + int i; + + /* First, the file header */ + fh = (cpel_file_header_t *)cpel; + if (fh->endian_version != CPEL_FILE_VERSION) { + if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) { + fprintf(stderr, "Little endian data format not supported\n"); + return(1); + } + fprintf(stderr, "Unsupported file version 0x%x\n", + fh->endian_version); + return(1); + } + cpel_dump_file_header(fh, verbose, ofp); + nsections = ntohs(fh->nsections); + + /* + * Take two passes through the file. PASS1 builds + * data structures, PASS2 actually dumps the file. + * Just in case the sections are in an unobvious order. + */ + sh = (cpel_section_header_t *)(fh+1); + for (i = 0; i < nsections; i++) { + section_size = ntohl(sh->data_length); + + if(verbose) { + fprintf(ofp, "Section type %d, size %d\n", ntohl(sh->section_type), + section_size); + } + + if(process_section(sh, verbose, ofp, PASS1)) + return(1); + + sh++; + sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); + } + + sh = (cpel_section_header_t *)(fh+1); + for (i = 0; i < nsections; i++) { + if(process_section(sh, verbose, ofp, PASS2)) + return(1); + section_size = ntohl(sh->data_length); + sh++; + sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); + } + return(0); +} + +void compute_state_statistics(int verbose, FILE *ofp) +{ + int i, j; + bound_track_t *bp; + f64 fticks; + + /* Across the bound tracks */ + for (i = 0; i < vec_len(bound_tracks); i++) { + bp = &bound_tracks[i]; + bp->mean_ticks_in_state = 0.0; + bp->variance_ticks_in_state = 0.0; + bp->total_ticks_in_state = 0.0; + for (j = 0; j < vec_len(bp->ticks_in_state); j++) { + bp->total_ticks_in_state += (f64) bp->ticks_in_state[j]; + } + /* Compute mean */ + if (vec_len(bp->ticks_in_state)) { + bp->mean_ticks_in_state = bp->total_ticks_in_state / + ((f64) vec_len(bp->ticks_in_state)); + } + /* Accumulate sum: (Xi-Xbar)**2 */ + for (j = 0; j < vec_len(bp->ticks_in_state); j++) { + fticks = bp->ticks_in_state[j]; + bp->variance_ticks_in_state += + (fticks - bp->mean_ticks_in_state)* + (fticks - bp->mean_ticks_in_state); + } + /* Compute s**2, the unbiased estimator of sigma**2 */ + if (vec_len(bp->ticks_in_state) > 1) { + bp->variance_ticks_in_state /= (f64) + (vec_len(bp->ticks_in_state)-1); + } + } +} + +int track_compare_max (const void *arg1, const void *arg2) +{ + bound_track_t *a1 = (bound_track_t *)arg1; + bound_track_t *a2 = (bound_track_t *)arg2; + f64 v1, v2; + + v1 = a1->total_ticks_in_state; + v2 = a2->total_ticks_in_state; + + if (v1 < v2) + return (1); + else if (v1 == v2) + return (0); + else return (-1); +} + +int track_compare_occurrences (const void *arg1, const void *arg2) +{ + bound_track_t *a1 = (bound_track_t *)arg1; + bound_track_t *a2 = (bound_track_t *)arg2; + f64 v1, v2; + + v1 = (f64) vec_len(a1->ticks_in_state); + v2 = (f64) vec_len(a2->ticks_in_state); + + if (v1 < v2) + return (1); + else if (v1 == v2) + return (0); + else return (-1); +} + +int track_compare_name (const void *arg1, const void *arg2) +{ + bound_track_t *a1 = (bound_track_t *)arg1; + bound_track_t *a2 = (bound_track_t *)arg2; + + return (strcmp((char *)(a1->track_str), (char *)(a2->track_str))); +} + +void sort_state_statistics(sort_t type, FILE *ofp) +{ + int (*compare)(const void *, const void *)=0; + + if (summary_stats_only) + return; + + switch(type) { + case SORT_MAX_TIME: + fprintf(ofp, "Results sorted by max time in state.\n"); + compare = track_compare_max; + break; + + case SORT_MAX_OCCURRENCES: + fprintf(ofp, "Results sorted by max occurrences of state.\n"); + compare = track_compare_occurrences; + break; + + case SORT_NAME: + compare = track_compare_name; + fprintf(ofp, "Results sorted by process-id/name/thread ID\n"); + break; + + default: + fatal("sort type not set?"); + } + + qsort (bound_tracks, vec_len(bound_tracks), + sizeof (bound_track_t), compare); +} + +void print_state_statistics(int verbose, FILE *ofp) +{ + int i,j; + u8 *trackpad; + bound_track_t *bp; + f64 total_time = 0.0; + f64 total_switches = 0.0; + + trackpad = format(0, "%%-%ds ", widest_track_format); + vec_add1(trackpad, 0); + + if (!summary_stats_only) { + fprintf(ofp, (char *)trackpad, "ProcThread"); + fprintf(ofp, " Mean(us) Stdev(us) Total(us) N\n"); + } + + for (i = 0; i < vec_len(bound_tracks); i++) { + bp = &bound_tracks[i]; + if (bp->mean_ticks_in_state == 0.0) + continue; + + if (name_filter && + strncmp((char *)(bp->track_str), (char *)name_filter, + strlen((char *)name_filter))) + continue; + + /* + * Exclude kernel threads (e.g. idle thread) from + * state statistics + */ + if (exclude_kernel_from_summary_stats && + !strncmp((char *)(bp->track_str), "kernel ", 7)) + continue; + + total_switches += (f64) vec_len(bp->ticks_in_state); + + if (!summary_stats_only) { + fprintf(ofp, (char *) trackpad, bp->track_str); + fprintf(ofp, "%10.3f +- %10.3f", + bp->mean_ticks_in_state / ticks_per_us, + sqrt(bp->variance_ticks_in_state) + / (f64) ticks_per_us); + fprintf(ofp, "%12.3f", + bp->total_ticks_in_state / ticks_per_us); + fprintf(ofp, "%8d\n", (int)vec_len(bp->ticks_in_state)); + } + + if (scatterplot) { + for (j = 0; j < vec_len(bp->ticks_in_state); j++) { + fprintf(ofp, "%.3f\n", + (f64)bp->ticks_in_state[j] / ticks_per_us); + } + } + + total_time += bp->total_ticks_in_state; + } + + if (!summary_stats_only) + fprintf(ofp, "\n"); + fprintf(ofp, "Note: the following statistics %s kernel-thread activity.\n", + exclude_kernel_from_summary_stats ? "exclude" : "include"); + if (name_filter) + fprintf(ofp, + "Note: only pid/proc/threads matching '%s' are included.\n", + name_filter); + + fprintf(ofp, + "Total runtime: %10.3f (us), Total state switches: %.0f\n", + total_time / ticks_per_us, total_switches); + fprintf(ofp, "Average time in state: %10.3f (us)\n", + (total_time / total_switches) / ticks_per_us); +} + +char *mapfile (char *file) +{ + struct stat statb; + char *rv; + int maphfile; + size_t mapfsize; + + maphfile = open (file, O_RDONLY); + + if (maphfile < 0) + { + fprintf (stderr, "Couldn't read %s, skipping it...\n", file); + return (NULL); + } + + if (fstat (maphfile, &statb) < 0) + { + fprintf (stderr, "Couldn't get size of %s, skipping it...\n", file); + return (NULL); + } + + /* Don't try to mmap directories, FIFOs, semaphores, etc. */ + if (! (statb.st_mode & S_IFREG)) { + fprintf (stderr, "%s is not a regular file, skipping it...\n", file); + return (NULL); + } + + mapfsize = statb.st_size; + + if (mapfsize < 3) + { + fprintf (stderr, "%s zero-length, skipping it...\n", file); + close (maphfile); + return (NULL); + } + + rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0); + + if (rv == 0) + { + fprintf (stderr, "%s problem mapping, I quit...\n", file); + exit (-1); + } + close (maphfile); + return (rv); +} + +/* + * main + */ +int main (int argc, char **argv) +{ + char *cpel_file = 0; + char *outputfile = 0; + FILE *ofp; + char *cpel; + int verbose=0; + int curarg=1; + + while (curarg < argc) { + if (!strncmp(argv[curarg], "--input-file", 3)) { + curarg++; + if (curarg < argc) { + cpel_file = argv[curarg]; + curarg++; + continue; + } + fatal("Missing filename after --input-file\n"); + } + if (!strncmp(argv[curarg], "--output-file", 3)) { + curarg ++; + if (curarg < argc) { + outputfile = argv[curarg]; + curarg ++; + continue; + } + fatal("Missing filename after --output-file\n"); + } + if (!strncmp(argv[curarg], "--verbose", 3)) { + curarg++; + verbose++; + continue; + } + if (!strncmp(argv[curarg], "--scatterplot", 4)) { + curarg++; + scatterplot=1; + continue; + } + + if (!strncmp(argv[curarg], "--state-event", 4)) { + curarg++; + if (curarg < argc) { + state_event_code = atol(argv[curarg]); + curarg ++; + continue; + } + fatal("Missing integer after --state-event\n"); + } + if (!strncmp(argv[curarg], "--max-time-sort", 7)) { + sort_type = SORT_MAX_TIME; + curarg++; + continue; + } + if (!strncmp(argv[curarg], "--max-occurrence-sort", 7)) { + sort_type = SORT_MAX_OCCURRENCES; + curarg++; + continue; + } + if (!strncmp(argv[curarg], "--name-sort", 3)) { + sort_type = SORT_NAME; + curarg++; + continue; + } + if (!strncmp(argv[curarg], "--kernel-included", 3)) { + exclude_kernel_from_summary_stats = 0; + curarg++; + continue; + } + if (!strncmp(argv[curarg], "--summary", 3)) { + summary_stats_only=1; + curarg++; + continue; + } + if (!strncmp(argv[curarg], "--filter", 3)) { + curarg ++; + if (curarg < argc) { + name_filter = (u8 *)argv[curarg]; + curarg ++; + continue; + } + fatal("Missing filter string after --filter\n"); + } + + + usage: + fprintf(stderr, + "cpelstate --input-file [--output-file ]\n"); + fprintf(stderr, + " [--state-event ] [--verbose]\n"); + fprintf(stderr, + " [--max-time-sort(default) | --max-occurrence-sort |\n"); + + fprintf(stderr, + " --name-sort-sort] [--kernel-included]\n"); + + fprintf(stderr, + " [--summary-stats-only] [--scatterplot]\n"); + + fprintf(stderr, "%s\n", version); + exit(1); + } + + if (cpel_file == 0) + goto usage; + + cpel = mapfile(cpel_file); + if (cpel == 0) { + fprintf(stderr, "Couldn't map %s...\n", cpel_file); + exit(1); + } + + if (!outputfile) { + ofp = fdopen(1, "w"); + if (ofp == NULL) { + fprintf(stderr, "Couldn't fdopen(1)?\n"); + exit(1); + } + } else { + ofp = fopen(outputfile, "w"); + if (ofp == NULL) { + fprintf(stderr, "Couldn't create %s...\n", outputfile); + exit(1); + } + } + + the_strtab_hash = hash_create_string (0, sizeof (uword)); + the_evtdef_hash = hash_create (0, sizeof (uword)); + the_trackdef_hash = hash_create (0, sizeof (uword)); + + if (cpel_dump((u8 *) cpel, verbose, ofp)) { + if (outputfile) + unlink(outputfile); + } + + compute_state_statistics(verbose, ofp); + sort_state_statistics(sort_type, ofp); + print_state_statistics(verbose, ofp); + + fclose(ofp); + return(0); +} diff --git a/src/tools/perftool/delsvec.c b/src/tools/perftool/delsvec.c new file mode 100644 index 00000000..724935d3 --- /dev/null +++ b/src/tools/perftool/delsvec.c @@ -0,0 +1,315 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2006-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Break up a delimited string into a vector of substrings */ + +#include +#include +#include +#include +#include + +/* + * #define UNIT_TESTS 1 + * #define MATCH_TRACE 1 + */ + +/* + * delsvec + * break up an input string into a vector of [null-terminated] u8 *'s + * + * Each supplied delimiter character results in a string in the output + * vector, unless the delimiters occur back-to-back. When matched, + * a whitespace character in the delimiter consumes an arbitrary + * run of whitespace. See the unit tests at the end of this file + * for a set of examples. + * + * Returns a u8 **, or NULL if the input fails to match. It is assumed + * that both input and fmt are C strings, not necessarily vectors. + * + * Output strings are both vectors and proper C strings. + */ + +static u8 **string_cache; +static u8 **svec_cache; + +void delsvec_recycle_this_string (u8 *s) +{ + if (s) { + _vec_len (s) = 0; + vec_add1(string_cache, s); + } +} + +void delsvec_recycle_this_svec (u8 **svec) +{ + if (svec) { + if (svec_cache) { + vec_free (svec_cache); + } + _vec_len (svec) = 0; + svec_cache = svec; + } +} + +int pvl (char *a) +{ + return vec_len(a); +} + +u8 **delsvec(void *input_arg, char *fmt) +{ + u8 **rv = 0; + int input_index=0; + u8 *this; + int dirflag=0; + int i; + u8 *input = input_arg; + + if (svec_cache) { + rv = svec_cache; + svec_cache = 0; + } + + while (fmt) { + dirflag=0; + if (vec_len (string_cache) > 0) { + this = string_cache [vec_len(string_cache)-1]; + _vec_len (string_cache) = vec_len (string_cache) - 1; + } else + this = 0; + /* + * '*' means one of two things: match the rest of the input, + * or match as many characters as possible + */ + if (fmt[0] == '*') { + fmt++; + dirflag=1; + /* + * no more format: eat rest of string... + */ + if (!fmt[0]) { + for (;input[input_index]; input_index++) + vec_add1(this, input[input_index]); + if (vec_len(this)) { + vec_add1(this, 0); +#ifdef MATCH_TRACE + printf("final star-match adds: '%s'\n", this); +#endif + vec_add1(rv, this); + } else { + vec_add1(string_cache, this); + } + + return(rv); + } + } + /* + * Left-to-right scan, adding chars until next delimiter char + * appears. + */ + if (!dirflag) { + while (input[input_index]) { + if (input[input_index] == fmt[0]) { + /* If we just (exact) matched a whitespace delimiter */ + if (fmt[0] == ' '){ + /* scan forward eating whitespace */ + while (input[input_index] == ' ' || + input[input_index] == '\t' || + input[input_index] == '\n') + input_index++; + input_index--; + } + goto found; + } + /* If we're looking for whitespace */ + if (fmt[0] == ' ') { + /* and we have whitespace */ + if (input[input_index] == ' ' || + input[input_index] == '\t' || + input[input_index] == '\n') { + /* scan forward eating whitespace */ + while (input[input_index] == ' ' || + input[input_index] == '\t' || + input[input_index] == '\n') { + input_index++; + } + input_index--; + goto found; + } + } + /* Not a delimiter, save it */ + vec_add1(this, input[input_index]); + input_index++; + } + /* + * Fell off the wagon, clean up and bail out + */ + bail: + +#ifdef MATCH_TRACE + printf("failed, fmt[0] = '%c', input[%d]='%s'\n", + fmt[0], input_index, &input[input_index]); +#endif + delsvec_recycle_this_string(this); + for (i = 0; i < vec_len(rv); i++) + delsvec_recycle_this_string(rv[i]); + delsvec_recycle_this_svec(rv); + return(0); + + found: + /* + * Delimiter matched + */ + input_index++; + fmt++; + /* + * If we actually accumulated non-delimiter characters, + * add them to the result vector + */ + if (vec_len(this)) { + vec_add1(this, 0); +#ifdef MATCH_TRACE + printf("match: add '%s'\n", this); +#endif + vec_add1(rv, this); + } else { + vec_add1(string_cache, this); + } + } else { + /* + * right-to-left scan, '*' not at + * the end of the delimiter string + */ + i = input_index; + while (input[++i]) + ; /* scan forward */ + i--; + while (i > input_index) { + if (input[i] == fmt[0]) + goto found2; + + if (fmt[0] == ' ' || fmt[0] == '\t' || + fmt[0] == '\n') { + if (input[i] == ' ' || + input[i] == '\t' || + input[i] == '\n') + goto found2; + } + i--; + } + goto bail; + + found2: + for (; input_index < i; input_index++) { + vec_add1(this, input[input_index]); + } + input_index++; + fmt++; + vec_add1(this, 0); +#ifdef MATCH_TRACE + printf("inner '*' match: add '%s'\n", this); +#endif + vec_add1(rv, this); + } + } + return (rv); +} + +#ifdef UNIT_TESTS + +typedef struct utest_ { + char *string; + char *fmt; +} utest_t; + +utest_t tests[] = { +#ifdef NOTDEF + {"Dec 7 08:56", + " :*"}, + {"Dec 17 08:56", + " :*"}, + {"Dec 7 08:56:41.239 install/inst_repl 0/9/CPU0 t1 [40989] File List:Successfully blobbified file list. Took 1 milliseconds", + " ::. / // [] *"}, + {"RP/0/9/CPU0:Dec 7 08:55:28.550 : sam_server[291]: SAM backs up digest list to memory file", + "///: ::. : []: *"}, + /* Expected to fail */ + {"Dec 7 08:56:41.239 install/inst_repl 0/9/CPU0 t1 [40989] File List:Successfully blobbified file list. Took 1 milliseconds", + "///: ::. : : *"}, + /* Expected to fail */ + {"RP/0/9/CPU0:Dec 7 08:55:28.550 : sam_server[291]: SAM backs up digest list to memory file", + " ::. / // [] *"}, + {"THIS that and + theother", "*+ *"}, + {"Dec 12 15:33:07.103 ifmgr/errors 0/RP0/CPU0 3# t2 Failed to open IM connection: No such file or directory", " ::. / // *"}, + {"Dec 16 21:43:47.328 ifmgr/bulk 0/3/CPU0 t8 Bulk DPC async download complete. Partitions 1, node_count 1, total_out 0, out_offset 0, out_expected 0: No error"," ::. / // *"}, + {"t:0x53034bd6 CPU:00 PROCESS :PROCCREATE_NAME", + ": : :*"}, + {" pid:1", " *"}, + {"t:0x53034cbb CPU:00 THREAD :THCREATE pid:1 tid:1", + ": : : pid: tid:*"}, + {"t:0x5303f950 CPU:00 COMM :REC_PULSE scoid:0x40000003 pid:364659", + ": : : *"}, + {"/hfr-base-3.3.85/lib/libttyconnection.dll 0xfc000000 0x0000306c 0xfc027000 0x000001c8 1", + " *"}, + {"Feb 28 02:38:26.123 seqtrace 0/1/CPU0 t8 :msg_receive:ifmgr/t8:IMC_MSG_MTU_UPDATE:ppp_ma/t1", + " ::. // ::::*"}, + + {"Feb 28 02:38:26.123 seqtrace 0/1/CPU0 t8 :msg_send_event:call:ifmgr/t8:124/0:cdp/t1", + " ::. // :msg_send_event::::*"}, + + {"Feb 28 02:38:26.125 seqtrace 0/1/CPU0 t1 :msg_receive_event:cdp/t1:124/0", + " ::. // :msg_receive_event::*"} + {"t:0x645dd86d CPU:00 USREVENT:EVENT:100, d0:0x00000002 d1:0x00000000", + ": : USREVENT:EVENT:, d0: *"} + {"t:0x5303f950 CPU:00 COMM :REC_PULSE scoid:0x40000003 pid:364659", + ": : : *"}, + {"t:0x2ccf9f5a CPU:00 INT_ENTR:0x80000000 (-2147483648) IP:0x002d8b18", + ": : INT_ENTR: IP:*"} + {"t:0xd473951c CPU:00 KER_EXIT:SCHED_GET/88 ret_val:2 sched_priority:10", + ": : KER_EXIT:SCHED_GET : sched_priority:*"} + {"t:0x00000123 CPU:01 SYSTEM :FUNC_ENTER thisfn:0x40e62048 call_site:0x00000000", + ": : SYSTEM :FUNC_ thisfn: *"}, + {"t:0x5af8de95 CPU:00 INT_HANDLER_ENTR:0x0000004d (77) PID:8200 IP:0x00000000 AREA:0x0bf9b290", ": : INT_HANDLER_*"}, +#endif + {"t:0x6d1ff92f CPU:00 CONTROL: BUFFER sequence = 1053, num_events = 714", + ": : CONTROL*"}, + {"t:0x6d1ff92f CPU:00 CONTROL :TIME msb:0x0000003c lsb(offset):0x6d1ff921", + ": : CONTROL*"}, +}; + +int main (int argc, char **argv) +{ + int i, j; + u8 **svec; + + for (j = 0; j < ARRAY_LEN(tests); j++) { + printf ("input string: '%s'\n", tests[j].string); + printf ("delimiter arg: '%s'\n", tests[j].fmt); + printf ("parse trace:\n"); + svec = delsvec(tests[j].string, tests[j].fmt); + if (!svec) { + printf("index %d failed\n", j); + continue; + } + printf("%d substring vectors\n", vec_len(svec)); + for (i = 0; i < vec_len(svec); i++) { + printf("[%d]: '%s'\n", i, svec[i]); + } + printf ("-------------------\n"); + } + exit(0); +} +#endif diff --git a/src/tools/perftool/linreg.c b/src/tools/perftool/linreg.c new file mode 100644 index 00000000..084091bb --- /dev/null +++ b/src/tools/perftool/linreg.c @@ -0,0 +1,78 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2006-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* see "Numerical Recipies in C, 2nd ed." p 665 */ + +#include +#include + +/* + * linreg + * Linear regression of (xi, yi), returns parameters for least-squares + * fit y = a + bx. Also, compute Pearson's R. + */ +void linreg (double *x, double *y, int nitems, double *a, double *b, + double *minp, double *maxp, double *meanp, double *r) +{ + double sx = 0.0; + double sy = 0.0; + double st2 = 0.0; + double min = y[0]; + double max = 0.0; + double ss, meanx, meany, t; + double errx, erry, prodsum, sqerrx, sqerry; + int i; + + *b = 0.0; + + for (i = 0; i < nitems; i++) { + sx += x[i]; + sy += y[i]; + if (y[i] < min) + min = y[i]; + if (y[i] > max) + max = y[i]; + } + ss = nitems; + meanx = sx / ss; + meany = *meanp = sy / ss; + *minp = min; + *maxp = max; + + for (i = 0; i < nitems; i++) { + t = x[i] - meanx; + st2 += t*t; + *b += t*y[i]; + } + + *b /= st2; + *a = (sy-sx*(*b))/ss; + + prodsum = 0.0; + sqerrx = 0.0; + sqerry = 0.0; + + /* Compute numerator of Pearson's R */ + for (i = 0; i < nitems; i++) { + errx = x[i] - meanx; + erry = y[i] - meany; + prodsum += errx * erry; + sqerrx += errx*errx; + sqerry += erry*erry; + } + + *r = prodsum / (sqrt(sqerrx)*sqrt(sqerry)); +} diff --git a/src/tools/perftool/new.cpel b/src/tools/perftool/new.cpel new file mode 100644 index 00000000..b0f35958 Binary files /dev/null and b/src/tools/perftool/new.cpel differ diff --git a/src/tools/perftool/new.elog b/src/tools/perftool/new.elog new file mode 100644 index 00000000..2d99bb16 Binary files /dev/null and b/src/tools/perftool/new.elog differ diff --git a/src/tools/perftool/props.c b/src/tools/perftool/props.c new file mode 100644 index 00000000..84af5b1c --- /dev/null +++ b/src/tools/perftool/props.c @@ -0,0 +1,280 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2006-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 + +static char *sxerox (char *s); + +#define NBUCKETS 97 + +typedef struct prop_ { + struct prop_ *next; + char *name; + char *value; +} prop_t; + +static prop_t *buckets [NBUCKETS]; +static int hash_shifts[4] = {24, 16, 8, 0}; + +/* + * getprop + */ + +char *getprop (char *name) +{ + unsigned char *cp; + unsigned long hash=0; + prop_t *bp; + int i=0; + + for (cp = (unsigned char *) name; *cp; cp++) + hash ^= (*cp)<<(hash_shifts[(i++)&0x3]); + + bp = buckets [hash%NBUCKETS]; + + while (bp && strcmp(bp->name, name)) { + bp = bp->next; + } + + if (bp == NULL) + return (0); + else + return (bp->value); +} + +/* + * getprop_default + */ + +char *getprop_default (char *name, char *def) +{ + char *rv; + rv = getprop (name); + if (rv) + return (rv); + else + return (def); +} + +/* + * addprop + */ + +void addprop (char *name, char *value) +{ + unsigned char *cp; + unsigned long hash=0; + prop_t **bpp; + prop_t *bp; + int i=0; + + bp = (prop_t *)malloc (sizeof (prop_t)); + + bp->next = 0; + bp->name = sxerox (name); + bp->value = sxerox (value); + + for (cp = (unsigned char *)name; *cp; cp++) + hash ^= (*cp)<<(hash_shifts[(i++)&0x3]); + + bpp = &buckets [hash%NBUCKETS]; + + if (*bpp == NULL) + *bpp = bp; + else { + bp->next = *bpp; + *bpp = bp; + } +} + +/* + * sxerox + */ + +static char *sxerox (char *s) +{ + char *rv = (char *) malloc (strlen (s) + 1); + strcpy (rv, s); + return rv; +} + +/* + * readprops + */ + +#define START 0 +#define READNAME 1 +#define READVALUE 2 +#define C_COMMENT 3 +#define CPP_COMMENT 4 + +int readprops (char *filename) +{ + FILE *ifp; + unsigned char c; + int state=START; + int linenum=1; + char namebuf [128]; + char valbuf [512]; + int i; + + ifp = fopen (filename, "r"); + + if (ifp == NULL) + return (-1); + + while (1) { + + readchar: + c = getc (ifp); + + again: + switch (state) { + case START: + if (feof (ifp)) { + fclose (ifp); + return (0); + } + + if (c == ' ' || c == '\t') + goto readchar; + + if (c == '\n') { + linenum++; + goto readchar; + } + if (isalpha (c) || (c == '_')) { + state = READNAME; + goto again; + } + if (c == '/') { + c = getc (ifp); + if (c == '/') { + state = CPP_COMMENT; + goto readchar; + } else if (c == '*') { + state = C_COMMENT; + goto readchar; + } else { + fprintf (stderr, "unknown token '/' line %d\n", + linenum); + exit(1); + } + } + fprintf (stderr, "unknown token '%c' line %d\n", + c, linenum); + exit (1); + break; + + case CPP_COMMENT: + while (1) { + c = getc (ifp); + if (feof (ifp)) + return (0); + if (c == '\n') { + linenum++; + state = START; + goto readchar; + } + } + break; + + case C_COMMENT: + while (1) { + c = getc (ifp); + if (feof (ifp)) { + fprintf (stderr, "unterminated comment, line %d\n", + linenum); + exit (1); + } + if (c == '*') { + staragain: + c = getc (ifp); + if (c == '/') { + state = START; + goto readchar; + } + if (c == '*') + goto staragain; + } + } + break; + + case READNAME: + i = 0; + namebuf[i++] = c; + while (1) { + c = getc (ifp); + if (feof (ifp)) { + fprintf (stderr, "EOF while reading a name, line %d\n", + linenum); + exit (1); + } + if ((!isalnum (c)) && (c != '_')) { + namebuf [i] = 0; + state = READVALUE; + goto again; + } + namebuf [i++] = c; + } + break; + + case READVALUE: + i = 0; + while ((c == ' ') || (c == '\t') || (c == '=')) { + c = getc (ifp); + if (feof (ifp)) { + fprintf (stderr, "EOF while reading a value, line %d\n", + linenum); + exit (1); + } + } + goto firsttime; + while (1) { + c = getc (ifp); + + firsttime: + if (c == '\\') { + c = getc (ifp); + if (feof (ifp)) { + fprintf (stderr, "EOF after '\\', line %d\n", + linenum); + exit (1); + } + valbuf[i++] = c; + continue; + } + if (c == '\n') { + linenum++; + while (valbuf [i-1] == ' ' || valbuf[i-1] == '\t') + i--; + valbuf[i] = 0; + addprop (namebuf, valbuf); + state = START; + goto readchar; + } + valbuf[i++] = c; + } + + } + } +} diff --git a/src/tools/vppapigen/configure.ac b/src/tools/vppapigen/configure.ac new file mode 100644 index 00000000..16ad59d2 --- /dev/null +++ b/src/tools/vppapigen/configure.ac @@ -0,0 +1,14 @@ +# -*- 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/tools/vppapigen/gram.y b/src/tools/vppapigen/gram.y new file mode 100644 index 00000000..de26af8d --- /dev/null +++ b/src/tools/vppapigen/gram.y @@ -0,0 +1,90 @@ +%{ +/* + * gram.y - message definition language + * + * Copyright (c) 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. + */ + +extern void yyerror (char *s); +extern int yylex (void); + +#define YYSTYPE void * + +void generate (YYSTYPE); + YYSTYPE add_slist(YYSTYPE, YYSTYPE); + YYSTYPE add_define(YYSTYPE, YYSTYPE); + YYSTYPE suppress_version(void); + YYSTYPE add_defbody(YYSTYPE, YYSTYPE); + YYSTYPE add_primtype(YYSTYPE, YYSTYPE, YYSTYPE); + YYSTYPE add_complex(YYSTYPE, YYSTYPE); + YYSTYPE add_union(YYSTYPE, YYSTYPE); + YYSTYPE add_scalar_vbl(YYSTYPE); + YYSTYPE add_vector_vbl(YYSTYPE, YYSTYPE); + YYSTYPE add_variable_length_vector_vbl(YYSTYPE, YYSTYPE); + YYSTYPE set_flags(YYSTYPE, YYSTYPE); +%} + +%token NAME RPAR LPAR SEMI LBRACK RBRACK NUMBER PRIMTYPE BARF +%token TPACKED DEFINE LCURLY RCURLY STRING UNION +%token HELPER_STRING COMMA +%token NOVERSION MANUAL_PRINT MANUAL_ENDIAN TYPEONLY DONT_TRACE + +%% + +pgm: slist {generate ($1);} + ; + +slist: slist stmt {$$ = add_slist ($1, $2);} + | stmt {$$ = $1;} + ; + +stmt: flist defn {$$ = set_flags($1, $2);} + | defn {$$ = $1;} + ; + +flist: flist flag {$$ = (YYSTYPE)(unsigned long long) + ((unsigned long long) $1 + | (unsigned long long) $2);} + | flag {$$ = $1;} + ; + +flag: + MANUAL_PRINT {$$ = $1;} + | MANUAL_ENDIAN {$$ = $1;} + | DONT_TRACE {$$ = $1;} + | TYPEONLY {$$ = $1;} + ; + +defn: DEFINE NAME LCURLY defbody RCURLY SEMI + {$$ = add_define($2, $4);} + + | NOVERSION SEMI + {$$ = suppress_version();} + ; + +defbody: defbody onedef {$$ = add_defbody($1, $2);} + | onedef {$$ = $1;} + ; + +onedef: PRIMTYPE vbl SEMI {$$ = add_primtype($1, $2, 0);} + | TPACKED PRIMTYPE vbl SEMI {$$ = add_primtype($1, $2, $3);} + | NAME vbl SEMI {$$ = add_complex($1, $2);} + | UNION NAME LCURLY defbody RCURLY SEMI + {$$ = add_union($2, $4);} + ; + +vbl: NAME {$$ = add_scalar_vbl($1);} + | NAME LBRACK NUMBER RBRACK {$$ = add_vector_vbl($1, $3);} + | NAME LBRACK NAME RBRACK {$$ = add_variable_length_vector_vbl($1, $3);} + ; diff --git a/src/tools/vppapigen/lex.c b/src/tools/vppapigen/lex.c new file mode 100644 index 00000000..733942ad --- /dev/null +++ b/src/tools/vppapigen/lex.c @@ -0,0 +1,1067 @@ +/* + *------------------------------------------------------------------ + * lex.c - API generator lexical analyzer + * + * Copyright (c) 1996-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. + *------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include +#include + +#include "lex.h" +#include "node.h" +#include "tools/vppapigen/gram.h" + +FILE *ifp, *ofp, *pythonfp, *jsonfp; +char *vlib_app_name = "vpp"; +int dump_tree; +time_t starttime; +char *input_filename; +char *current_filename; +int current_filename_allocated; +unsigned long input_crc; +unsigned long message_crc; +int yydebug; + +/* + * lexer variable definitions + */ + +static const char *version = "0.1"; +static int the_lexer_linenumber = 1; +static enum lex_state the_lexer_state = START_STATE; + +/* + * private prototypes + */ +static void usage (char *); +static int name_check (const char *, YYSTYPE *); +static int name_compare (const char *, const char *); +extern int yydebug; +extern YYSTYPE yylval; + +unsigned int crc32c_table[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 +}; + +static inline unsigned long CRC8 (unsigned long crc, + unsigned char d) +{ + return ((crc >> 8) ^ crc32c_table[(crc ^ d) & 0xFF]); +} +static inline unsigned long CRC16 (unsigned long crc, + unsigned short d) +{ + crc = CRC8 (crc, d & 0xff); + d = d >> 8; + crc = CRC8 (crc, d & 0xff); + return crc; +} + + +static unsigned long +crc_eliding_c_comments (const char *buf, unsigned long crc) +{ + const char *p; + enum { cOTHER, /* */ + cSTRING, /* "... */ + cSBACKSLASH, /* "...\ */ + cCHAR, /* '... */ + cCBACKSLASH, /* '...\ */ + cSLASH, /* / */ + cSLASH_SLASH, /* //... */ + cSLASH_STAR, /* / *... */ + cSTAR /* / *...* */ + } ss = cOTHER; + + for (p = buf; ;) { + unsigned char c = *p++; + + switch (c) { + case 0: + switch (ss) { + case cOTHER: + return (crc); + case cSTRING: case cSBACKSLASH: + case cCHAR: case cCBACKSLASH: + case cSLASH: case cSLASH_SLASH: case cSLASH_STAR: case cSTAR: + fprintf (stderr, "Inopportune EOF: %s\n", buf); + exit (1); + } + break; + case '\"': + switch (ss) { + case cOTHER: ss = cSTRING; break; /* start string */ + case cSTRING: ss = cOTHER; break; /* end string */ + case cSBACKSLASH: ss = cSTRING; break; + case cCHAR: break; + case cCBACKSLASH: ss = cCHAR; break; + case cSLASH: crc = CRC8 (crc, '/'); ss = cOTHER; break; + case cSLASH_SLASH: continue; /* in comment */ + case cSLASH_STAR: continue; /* in comment */ + case cSTAR: ss = cSLASH_STAR; continue; /* in comment */ + } + break; + case '\\': + switch (ss) { + case cOTHER: break; + case cSTRING: ss = cSBACKSLASH; break; + case cSBACKSLASH: ss = cSTRING; break; + case cCHAR: ss = cCBACKSLASH; break; + case cCBACKSLASH: ss = cCHAR; break; + case cSLASH: crc = CRC8 (crc, '/'); ; ss = cOTHER; break; + case cSLASH_SLASH: continue; /* in comment */ + case cSLASH_STAR: continue; /* in comment */ + case cSTAR: ss = cSLASH_STAR; continue; /* in comment */ + } + break; + case '/': + switch (ss) { + case cOTHER: ss = cSLASH; continue; /* potential comment */ + case cSTRING: break; + case cSBACKSLASH: ss = cSTRING; break; + case cCHAR: break; + case cCBACKSLASH: ss = cCHAR; break; + case cSLASH: ss = cSLASH_SLASH; continue; /* start comment */ + case cSLASH_SLASH: continue; /* in comment */ + case cSLASH_STAR: continue; /* in comment */ + case cSTAR: ss = cOTHER; continue; /* end of comment */ + } + break; + case '*': + switch (ss) { + case cOTHER: break; + case cSTRING: break; + case cSBACKSLASH: ss = cSTRING; break; + case cCHAR: break; + case cCBACKSLASH: ss = cCHAR; break; + case cSLASH: ss = cSLASH_STAR; continue; /* start comment */ + case cSLASH_SLASH: continue; /* in comment */ + case cSLASH_STAR: ss = cSTAR; continue; /* potential end */ + case cSTAR: continue; /* still potential end of comment */ + } + break; + case '\n': case '\r': case ' ': case '\t': case '\014': + switch (ss) { + case cOTHER: continue; /* ignore all whitespace */ + case cSTRING: break; + case cSBACKSLASH: ss = cSTRING; break; + case cCHAR: break; + case cCBACKSLASH: ss = cCHAR; break; + case cSLASH: c = '/'; ss = cOTHER; break; + case cSLASH_SLASH: + if (c == '\n' || c == '\r') ss = cOTHER; /* end comment */ + continue; + case cSLASH_STAR: continue; /* in comment */ + case cSTAR: ss = cSLASH_STAR; continue; /* in comment */ + } + default: + switch (ss) { + case cOTHER: break; + case cSTRING: break; + case cSBACKSLASH: ss = cSTRING; break; + case cCHAR: break; + case cCBACKSLASH: ss = cCHAR; break; + case cSLASH: crc = CRC8 (crc, '/'); ss = cOTHER; break; + case cSLASH_SLASH: continue; /* in comment */ + case cSLASH_STAR: continue; /* in comment */ + case cSTAR: ss = cSLASH_STAR; continue; /* in comment */ + } + } + crc = CRC8 (crc, c); + } +} + +/* + * main + */ +int main (int argc, char **argv) +{ + int curarg = 1; + char *ofile=0; + char *pythonfile=0; + char *jsonfile=0; + char *show_name=0; + + while (curarg < argc) { + if (!strncmp (argv [curarg], "--verbose", 3)) { + fprintf (stderr, "%s version %s\n", argv [0], version); + curarg++; + continue; + } + + if (!strncmp (argv [curarg], "--yydebug", 3)) { + yydebug = 1; + curarg++; + continue; + } + + if (!strncmp (argv [curarg], "--dump", 3)) { + dump_tree = 1; + curarg++; + continue; + } + + if (!strncmp (argv[curarg], "--show-name", 3)) { + curarg++; + if (curarg < argc) { + show_name = argv[curarg]; + curarg++; + continue; + } else { + fprintf(stderr, "Missing filename after --show-name \n"); + exit(1); + } + } + + if (!strncmp (argv [curarg], "--input", 3)) { + curarg++; + if (curarg < argc) { + input_filename = argv[curarg]; + if (!strcmp (argv [curarg], "-")) + ifp = stdin; + else + ifp = fopen (argv [curarg], "r"); + if (ifp == NULL) { + fprintf (stderr, "Couldn't open input file %s\n", + argv[curarg]); + exit (1); + } + curarg++; + } else { + fprintf(stderr, "Missing filename after --input\n"); + exit(1); + } + continue; + } + if (!strncmp (argv [curarg], "--output", 3)) { + curarg++; + if (curarg < argc) { + ofp = fopen (argv[curarg], "w"); + if (ofp == NULL) { + fprintf (stderr, "Couldn't open output file %s\n", + argv[curarg]); + exit (1); + } + ofile = argv[curarg]; + curarg++; + } else { + fprintf(stderr, "Missing filename after --output\n"); + exit(1); + } + continue; + } + if (!strncmp (argv [curarg], "--python", 8)) { + curarg++; + if (curarg < argc) { + if (!strcmp(argv[curarg], "-")) { + pythonfp = stdout; + } else { + pythonfp = fopen(argv[curarg], "w"); + pythonfile = argv[curarg]; + } + if (pythonfp == NULL) { + fprintf (stderr, "Couldn't open python output file %s\n", + argv[curarg]); + exit (1); + } + curarg++; + } else { + fprintf(stderr, "Missing filename after --python\n"); + exit(1); + } + continue; + } + if (!strncmp (argv [curarg], "--json", 6)) { + curarg++; + if (curarg < argc) { + if (!strcmp(argv[curarg], "-")) { + jsonfp = stdout; + } else { + jsonfp = fopen(argv[curarg], "w"); + jsonfile = argv[curarg]; + } + if (jsonfp == NULL) { + fprintf (stderr, "Couldn't open JSON output file %s\n", + argv[curarg]); + exit (1); + } + curarg++; + } else { + fprintf(stderr, "Missing filename after --json\n"); + exit(1); + } + continue; + } + if (!strncmp (argv [curarg], "--app", 4)) { + curarg++; + if (curarg < argc) { + vlib_app_name = argv[curarg]; + curarg++; + } else { + fprintf(stderr, "Missing app name after --app\n"); + exit(1); + } + continue; + } + + usage(argv[0]); + exit (1); + } + if (ofp == NULL) { + ofile = 0; + } + if (pythonfp == NULL) { + pythonfile = 0; + } + if (jsonfp == NULL) { + jsonfile = 0; + } + if (ifp == NULL) { + fprintf(stderr, "No input file specified...\n"); + exit(1); + } + if (show_name) { + input_filename = show_name; + } + + starttime = time (0); + + if (yyparse() == 0) { + fclose (ifp); + curarg -= 2; + if (ofile) { + printf ("Output written to %s\n", ofile); + fclose (ofp); + } + if (pythonfile) { + printf ("Python bindings written to %s\n", pythonfile); + fclose (pythonfp); + } + if (jsonfile) { + printf ("JSON bindings written to %s\n", jsonfile); + fclose (jsonfp); + } + } + else { + fclose (ifp); + if (ofp) + fclose (ofp); + if (ofile) { + printf ("Removing %s\n", ofile); + unlink (ofile); + } + if (pythonfile) { + printf ("Removing %s\n", pythonfile); + unlink (pythonfile); + } + if (jsonfile) { + printf ("Removing %s\n", jsonfile); + unlink (jsonfile); + } + exit (1); + } + exit (0); +} + +/* + * usage + */ +static void usage (char *progname) +{ + fprintf (stderr, + "usage: %s --input [--output ] " + "[--json ] [--python ]\n%s", + progname, + " [--yydebug] [--dump-tree]\n"); + exit (1); +} + +/* + * yyerror + */ +void yyerror (char *s) +{ + fprintf (stderr, "%s:%d %s\n", current_filename, the_lexer_linenumber, s); +} + +static char namebuf [MAXNAME]; + +static inline char +getc_char (FILE *ifp) +{ + return ((char)(getc(ifp) & 0x7f)); +} + +/* + * yylex (well, yylex_1: The real yylex below does crc-hackery) + */ +static int yylex_1 (void) +{ + int nameidx=0; + char c; + enum { LP_INITIAL_WHITESPACE, LP_LINE_NUMBER, + LP_PRE_FILENAME_WHITESPACE, LP_FILENAME, + LP_POST_FILENAME, + LP_OTHER + } lp_substate = LP_INITIAL_WHITESPACE; + + again: + switch (the_lexer_state) { + /* + * START state -- looking for something interesting + */ + case START_STATE: + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + + switch (c) { + case '\n': + the_lexer_linenumber++; + goto again; + + case '#': + the_lexer_state = LINE_PRAGMA_STATE; + lp_substate = LP_INITIAL_WHITESPACE; + goto again; + + /* FALLTHROUGH */ + case '\t': + case ' ': + goto again; + + case '(': + return (LPAR); + + case ')': + return (RPAR); + + case ';': + return (SEMI); + + case '[': + return (LBRACK); + + case ']': + return (RBRACK); + + case '{': + return (LCURLY); + + case '}': + return (RCURLY); + + case ',': + return (COMMA); + + case '"': + nameidx = 0; + the_lexer_state = STRING_STATE; + goto again; + + case '@': + nameidx = 0; + the_lexer_state = HELPER_STATE; + goto again; + + case '/': + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + + if (c == '/') { + the_lexer_state = CPP_COMMENT_STATE; + goto again; + } else if (c == '*') { + the_lexer_state = C_COMMENT_STATE; + goto again; + } else { + fprintf (stderr, "unknown token /%c at line %d\n", + c, the_lexer_linenumber); + return (BARF); + } + + case '\\': + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + + /* Note fallthrough... */ + + default: + if (isalpha (c) || c == '_') { + namebuf [0] = c; + nameidx = 1; + the_lexer_state = NAME_STATE; + goto again; + } else if (isdigit(c)) { + namebuf [0] = c; + nameidx = 1; + the_lexer_state = NUMBER_STATE; + goto again; + } + + fprintf (stderr, "unknown token %c at line %d\n", + c, the_lexer_linenumber); + return (BARF); + } + + /* + * NAME state -- eat the rest of a name + */ + case NAME_STATE: + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + + if (!isalnum (c) && c != '_') { + ungetc (c, ifp); + namebuf [nameidx] = 0; + the_lexer_state = START_STATE; + return (name_check (namebuf, &yylval)); + } + if (nameidx >= (MAXNAME-1)) { + fprintf(stderr, "lex input buffer overflow...\n"); + exit(1); + } + namebuf [nameidx++] = c; + goto again; + + /* + * NUMBER state -- eat the rest of a number + */ + case NUMBER_STATE: + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + + if (!isdigit (c)) { + ungetc (c, ifp); + namebuf [nameidx] = 0; + the_lexer_state = START_STATE; + yylval = (void *) atol(namebuf); + return (NUMBER); + } + if (nameidx >= (MAXNAME-1)) { + fprintf(stderr, "lex input buffer overflow...\n"); + exit(1); + } + namebuf [nameidx++] = c; + goto again; + + /* + * C_COMMENT state -- eat a peach + */ + case C_COMMENT_STATE: + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + if (c == '*') { + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + if (c == '/') { + the_lexer_state = START_STATE; + goto again; + } + } + if (c == '\n') + the_lexer_linenumber++; + goto again; + + /* + * CPP_COMMENT state -- eat a plum + */ + + case CPP_COMMENT_STATE: + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + if (c == '\n') { + the_lexer_linenumber++; + the_lexer_state = START_STATE; + goto again; + } + goto again; + + case STRING_STATE: + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + switch (c) { + case '\\': + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + namebuf[nameidx++] = c; + goto again; + + case '"': + namebuf[nameidx] = 0; + yylval = (YYSTYPE) sxerox (namebuf); + the_lexer_state = START_STATE; + return (STRING); + + default: + if (c == '\n') + the_lexer_linenumber++; + + if (nameidx >= (MAXNAME-1)) { + fprintf(stderr, "lex input buffer overflow...\n"); + exit(1); + } + namebuf[nameidx++] = c; + goto again; + } + break; + + case HELPER_STATE: + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + switch (c) { + case '\\': + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + namebuf[nameidx] = c; + goto again; + + case '@': + namebuf[nameidx] = 0; + yylval = (YYSTYPE) sxerox (namebuf); + the_lexer_state = START_STATE; + return (HELPER_STRING); + + default: + if (c == '\n') + the_lexer_linenumber++; + + /* + * CPP makes it approximately impossible to + * type "#define FOO 123", so we provide a + * lexical trick to achieve that result + */ + + if (c == '$') + c = '#'; + + if (nameidx >= (MAXNAME-1)) { + fprintf(stderr, "lex input buffer overflow...\n"); + exit(1); + } + namebuf[nameidx++] = c; + goto again; + } + break; + + case LINE_PRAGMA_STATE: + /* We're only interested in lines of the form # 259 "foo.c" 17 */ + + switch (lp_substate) { + + case LP_INITIAL_WHITESPACE: /* no number seen yet */ + c = getc_char(ifp); + if (feof(ifp)) + return(EOF); + if (c >= '0' && c <= '9') { + namebuf[nameidx++] = c; + lp_substate = LP_LINE_NUMBER; + } else if (c == '\n') { + goto lp_end_of_line; + } else if (c != ' ' && c != '\t') { + /* Nothing */ + } else { + lp_substate = LP_OTHER; + } + goto again; + + case LP_LINE_NUMBER: /* eating linenumber */ + c = getc_char(ifp); + if (feof(ifp)) + return(EOF); + if (c >= '0' && c <= '9') { + namebuf[nameidx++] = c; + } else if (c == ' ' || c == '\t') { + namebuf[nameidx++] = 0; + the_lexer_linenumber = atol(namebuf); + lp_substate = LP_PRE_FILENAME_WHITESPACE; + } else if (c == '\n') { + goto lp_end_of_line; + } else { + lp_substate = LP_OTHER; + } + goto again; + + case LP_PRE_FILENAME_WHITESPACE: /* awaiting filename */ + c = getc_char(ifp); + if (feof(ifp)) + return(EOF); + + if (c == '"') { + lp_substate = LP_FILENAME; + nameidx = 0; + } else if (c == ' ' || c == '\t') { + /* nothing */ + } else if (c == '\n') { + goto lp_end_of_line; + } else { + lp_substate = LP_OTHER; + } + goto again; + + case LP_FILENAME: /* eating filename */ + c = getc_char(ifp); + if (feof(ifp)) + return(EOF); + + if (c == '"') { + lp_substate = LP_POST_FILENAME; + namebuf[nameidx] = 0; + } else if (c == '\n') { + goto lp_end_of_line; /* syntax error... */ + } else { + namebuf[nameidx++] = c; + } + goto again; + + case LP_POST_FILENAME: /* ignoring rest of line */ + case LP_OTHER: + c = getc_char(ifp); + if (feof(ifp)) + return(EOF); + + if (c == '\n') { + if (lp_substate == LP_POST_FILENAME) { + if (current_filename_allocated) { + current_filename_allocated = 0; + free(current_filename); + } + + if (!strcmp(namebuf, "")) { + current_filename = input_filename; + } else { + current_filename = sxerox(namebuf); + current_filename_allocated = 1; + } + } + lp_end_of_line: + the_lexer_state = START_STATE; + nameidx = 0; + } + goto again; + } + break; + } + fprintf (stderr, "LEXER BUG!\n"); + exit (1); + /* NOTREACHED */ + return (0); +} + +/* + * Parse a token and side-effect input_crc + * in a whitespace- and comment-insensitive fashion. + */ +int yylex (void) +{ + /* + * Accumulate a crc32-based signature while processing the + * input file. The goal is to come up with a magic number + * which changes precisely when the original input file changes + * but which ignores whitespace changes. + */ + unsigned long crc = input_crc; + int node_type = yylex_1 (); + unsigned long crc2 = message_crc; + int use_helper_string = 0; + unsigned short code; + + switch (node_type) { + case PRIMTYPE: + case NAME: + case NUMBER: + case STRING: + case HELPER_STRING: + use_helper_string = 1; + break; + + /* Other node types have no "substate" */ + /* This code is written in this curious fashion because we + * want the generated CRC to be independent of the particular + * values a particular version of lex/bison assigned to various states. + */ + + case RPAR: code = 258; break; + case LPAR: code = 259; break; + case SEMI: code = 260; break; + case LBRACK: code = 261; break; + case RBRACK: code = 262; break; + case BARF: code = 265; break; + case TPACKED: code = 266; break; + case DEFINE: code = 267; break; + case LCURLY: code = 268; break; + case RCURLY: code = 269; break; + case UNION: code = 271; break; + case COMMA: code = 273; break; + case NOVERSION: code = 274; break; + case MANUAL_PRINT: code = 275; break; + case MANUAL_ENDIAN: code = 276; break; + case TYPEONLY: code = 278; break; + case DONT_TRACE: code = 279; break; + + case EOF: code = ~0; break; /* hysterical compatibility */ + + default: + fprintf(stderr, "yylex: node_type %d missing state CRC cookie\n", + node_type); + exit(1); + } + + if (use_helper_string) + { + /* We know these types accumulated token text into namebuf */ + /* HELPER_STRING may still contain C comments. Argh. */ + crc = crc_eliding_c_comments (namebuf, crc); + crc2 = crc_eliding_c_comments (namebuf, crc2); + } else + { + crc = CRC16 (crc, code); + crc2 = CRC16 (crc2, code); + } + + input_crc = crc; + message_crc = crc2; + return (node_type); +} + +/* + * name_check -- see if the name we just ate + * matches a known keyword. If so, set yylval + * to a new instance of , and return PARSER_MACRO + * + * Otherwise, set yylval to sxerox (s) and return NAME + */ + +static struct keytab { + char *name; + enum node_subclass subclass_id; +} keytab [] = +/* Keep the table sorted, binary search used below! */ +{ + {"define", NODE_DEFINE}, + {"dont_trace", NODE_DONT_TRACE}, + {"f64", NODE_F64}, + {"i16", NODE_I16}, + {"i32", NODE_I32}, + {"i64", NODE_I64}, + {"i8", NODE_I8}, + {"manual_endian", NODE_MANUAL_ENDIAN}, + {"manual_print", NODE_MANUAL_PRINT}, + {"noversion", NODE_NOVERSION}, + {"packed", NODE_PACKED}, + {"typeonly", NODE_TYPEONLY}, + {"u16", NODE_U16}, + {"u32", NODE_U32}, + {"u64", NODE_U64}, + {"u8", NODE_U8}, + {"union", NODE_UNION}, + {"uword", NODE_UWORD}, +}; + +static int name_check (const char *s, YYSTYPE *token_value) +{ + enum node_subclass subclass_id; + int top, bot, mid; + int result; + + for (top = 0, bot = (sizeof(keytab) / sizeof(struct keytab))-1; + bot >= top; ) { + mid = (top + bot) / 2; + result = name_compare (s, keytab[mid].name); + if (result < 0) + bot = mid - 1; + else if (result > 0) + top = mid + 1; + else { + subclass_id = keytab[mid].subclass_id; + + switch (subclass_id) { + case NODE_U8: + case NODE_U16: + case NODE_U32: + case NODE_U64: + case NODE_I8: + case NODE_I16: + case NODE_I32: + case NODE_I64: + case NODE_F64: + case NODE_UWORD: + *token_value = make_node(subclass_id); + return (PRIMTYPE); + + case NODE_PACKED: + *token_value = make_node(subclass_id); + return (TPACKED); + + case NODE_DEFINE: + message_crc = 0; + *token_value = make_node(subclass_id); + return(DEFINE); + + case NODE_MANUAL_PRINT: + *token_value = (YYSTYPE) NODE_FLAG_MANUAL_PRINT; + return (MANUAL_PRINT); + + case NODE_MANUAL_ENDIAN: + *token_value = (YYSTYPE) NODE_FLAG_MANUAL_ENDIAN; + return (MANUAL_ENDIAN); + + case NODE_TYPEONLY: + *token_value = (YYSTYPE) NODE_FLAG_TYPEONLY; + return(TYPEONLY); + + case NODE_DONT_TRACE: + *token_value = (YYSTYPE) NODE_FLAG_DONT_TRACE; + return(DONT_TRACE); + + case NODE_NOVERSION: + return(NOVERSION); + + case NODE_UNION: + return(UNION); + + default: + fprintf (stderr, "fatal: keytab botch!\n"); + exit (1); + } + } + } + *token_value = (YYSTYPE) sxerox (s); + return (NAME); +} + +/* + * sxerox + */ + +char *sxerox (const char *s) +{ + int len = strlen (s); + char *rv; + + rv = (char *) malloc (len+1); + if (rv == 0) { + fprintf(stderr, "Out of memory..."); + exit (1); + } + + strcpy (rv, s); + return (rv); +} + +/* + * name_compare + */ + +int name_compare (const char *s1, const char *s2) +{ + char c1, c2; + + while (*s1 && *s2) { + c1 = *s1++; + c2 = *s2++; + + c1 = tolower (c1); + c2 = tolower (c2); + if (c1 < c2) + return (-1); + else if (c1 > c2) + return (1); + } + if (*s1 < *s2) + return (-1); + else if (*s1 > *s2) + return (1); + return (0); +} diff --git a/src/tools/vppapigen/lex.h b/src/tools/vppapigen/lex.h new file mode 100644 index 00000000..a0fdc735 --- /dev/null +++ b/src/tools/vppapigen/lex.h @@ -0,0 +1,50 @@ +/* + *------------------------------------------------------------------ + * lex.h - definitions for the api generator's lexical + * analyzer. + * + * Copyright (c) 1996-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 _LEX_H_ +#define _LEX_H_ 1 + +extern int yylex (void); +extern void yyerror (char *); +extern int yyparse (void); + +#ifndef YYSTYPE +#define YYSTYPE void * +#endif + +#include "tools/vppapigen/gram.h" + +enum lex_state { + START_STATE = 1, + NAME_STATE, + NUMBER_STATE, + C_COMMENT_STATE, + CPP_COMMENT_STATE, + STRING_STATE, + HELPER_STATE, + LINE_PRAGMA_STATE, +}; + +#define MAXNAME 64000 + +extern unsigned long input_crc; +extern unsigned long message_crc; + +#endif /* _LEX_H_ */ diff --git a/src/tools/vppapigen/node.c b/src/tools/vppapigen/node.c new file mode 100644 index 00000000..260c6f2e --- /dev/null +++ b/src/tools/vppapigen/node.c @@ -0,0 +1,1527 @@ +/* + *------------------------------------------------------------------ + * node.c - the api generator's semantic back-end + * + * Copyright (c) 2004-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. + *------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lex.h" +#include "node.h" + +#define YYSTYPE void * + +FILE *ofp; +FILE *pythonfp; +FILE *jsonfp; +time_t starttime; +char *vlib_app_name; +char *input_filename; +node_vft_t *the_vft[NODE_N_TYPES]; +static int indent; +static int dont_output_version; +int dump_tree; +static char *fixed_name; +static char tmpbuf [MAXNAME]; +static char *current_def_name; +static char *current_union_name; +static char *current_type_fmt; +static char *current_type_cast; +static char current_id; +static char current_is_complex; +static char *current_endianfun; +static char *current_type_name; + +void indent_me(FILE *ofp) +{ + int i; + + for (i = 0; i < indent; i++) + putc(' ', ofp); +} + +char *uppercase (char *s) +{ + char *cp; + + cp = tmpbuf; + + while (*s && (cp < tmpbuf + (sizeof(tmpbuf)-1))) { + if (*s >= 'a' && *s <= 'z') + *cp++ = *s++ - ('a' - 'A'); + else + *cp++ = *s++; + } + *cp = 0; + return(tmpbuf); +} + +char *lowercase (char *s) +{ + char *cp; + + cp = tmpbuf; + + while (*s && (cp < tmpbuf + (sizeof(tmpbuf)-1))) { + if (*s >= 'A' && *s <= 'Z') + *cp++ = *s++ + ('a' - 'A'); + else + *cp++ = *s++; + } + *cp = 0; + return(tmpbuf); +} + +void primtype_recursive_print(node_t *this, i8 *fmt) +{ + fputs((char *)fmt, stdout); + + if (this->deeper) { + node_vft_t *vftp = the_vft[this->deeper->type]; + vftp->print(this->deeper); + } +} + +void primtype_recursive_generate(node_t *this, enum passid which, FILE *ofp, + i8 *type_name, i8 *type_fmt, i8 *type_cast) +{ + node_vft_t *vftp; + + current_type_name = (char *)type_name; + current_type_cast = (char *)type_cast; + + switch(which) { + case TYPEDEF_PASS: + fputs((char *)type_name, ofp); + fputs(" ", ofp); + break; + + case PRINTFUN_PASS: + current_type_fmt = (char *)type_fmt; + break; + + case ENDIANFUN_PASS: + vftp = the_vft[this->type]; + current_endianfun = vftp->endian_converter; + break; + + case PYTHON_PASS: + fputs("('", pythonfp); + fputs((char *)type_name, pythonfp); + fputs("', ", pythonfp); + break; + + case JSON_PASS: + fputs("[\"", jsonfp); + fputs((char *)type_name, jsonfp); + fputs("\", ", jsonfp); + break; + + default: + fprintf(stderr, "primtype_recursive_generate: unimp pass %d\n", which); + break; + } + + if (this->deeper) { + vftp = the_vft[this->deeper->type]; + vftp->generate(this->deeper, which, ofp); + } +} + +void node_illegal_print (node_t *this) +{ + fprintf(stderr, "node_illegal_print called\n"); + exit(0); +} + +void node_illegal_generate (node_t *this, enum passid notused, FILE *ofp) +{ + fprintf(stderr, "node_illegal_generate called\n"); + exit(0); +} + +node_vft_t node_illegal_vft = { + node_illegal_print, + node_illegal_generate, + "illegal" +}; + +void node_u8_print (node_t *this) +{ + primtype_recursive_print(this, "u8 "); +} + +void node_u8_generate (node_t *this, enum passid which, FILE *ofp) +{ + primtype_recursive_generate(this, which, ofp, "u8", "%u", "(unsigned)"); +} + +node_vft_t node_u8_vft = { + node_u8_print, + node_u8_generate, + NULL +}; + +void node_u16_print (node_t *this) +{ + primtype_recursive_print(this, "u16 "); +} + +void node_u16_generate (node_t *this, enum passid which, FILE *ofp) +{ + primtype_recursive_generate(this, which, ofp, "u16", "%u", "(unsigned)"); +} + +node_vft_t node_u16_vft = { + node_u16_print, + node_u16_generate, + "clib_net_to_host_u16" +}; + +void node_u32_print (node_t *this) +{ + primtype_recursive_print(this, "u32 "); +} + +void node_u32_generate (node_t *this, enum passid which, FILE *ofp) +{ + primtype_recursive_generate(this, which, ofp, "u32", "%u", "(unsigned)"); +} + +node_vft_t node_u32_vft = { + node_u32_print, + node_u32_generate, + "clib_net_to_host_u32", +}; + +void node_u64_print (node_t *this) +{ + primtype_recursive_print(this, "u64 "); +} + +void node_u64_generate (node_t *this, enum passid which, FILE *ofp) +{ + primtype_recursive_generate(this, which, ofp, "u64", "%llu", + "(long long)"); +} + +node_vft_t node_u64_vft = { + node_u64_print, + node_u64_generate, + "clib_net_to_host_u64" +}; + +void node_i8_print (node_t *this) +{ + primtype_recursive_print(this, "i8 "); +} + +void node_i8_generate (node_t *this, enum passid which, FILE *ofp) +{ + primtype_recursive_generate(this, which, ofp, "i8", "%d", "(int)"); +} + +node_vft_t node_i8_vft = { + node_i8_print, + node_i8_generate, + "" +}; + +void node_i16_print (node_t *this) +{ + primtype_recursive_print(this, "i16 "); +} + +void node_i16_generate (node_t *this, enum passid which, FILE *ofp) +{ + primtype_recursive_generate(this, which, ofp, "i16", "%d", "(int)"); +} + +node_vft_t node_i16_vft = { + node_i16_print, + node_i16_generate, + "clib_net_to_host_u16" +}; + +void node_i32_print (node_t *this) +{ + primtype_recursive_print(this, "i32 "); +} + +void node_i32_generate (node_t *this, enum passid which, FILE *ofp) +{ + primtype_recursive_generate(this, which, ofp, "i32", "%ld", "(long)"); +} + +node_vft_t node_i32_vft = { + node_i32_print, + node_i32_generate, + "clib_net_to_host_u32" +}; + +void node_i64_print (node_t *this) +{ + primtype_recursive_print(this, "i64 "); +} + +void node_i64_generate (node_t *this, enum passid which, FILE *ofp) +{ + primtype_recursive_generate(this, which, ofp, "i64", "%lld", + "(long long)"); +} + +node_vft_t node_i64_vft = { + node_i64_print, + node_i64_generate, + "clib_net_to_host_u64" +}; + +void node_f64_print (node_t *this) +{ + primtype_recursive_print(this, "f64 "); +} + +void node_f64_generate (node_t *this, enum passid which, FILE *ofp) +{ + primtype_recursive_generate(this, which, ofp, "f64", "%.2f", + "(double)"); +} + +node_vft_t node_f64_vft = { + node_f64_print, + node_f64_generate, + " ", /* FP numbers are sent in host byte order */ +}; + + +void node_packed_print (node_t *this) +{ + primtype_recursive_print (this, "packed "); +} + +void node_packed_generate (node_t *this, enum passid which, FILE *ofp) +{ + primtype_recursive_generate(this, which, ofp, "PACKED", "", ""); +} + +node_vft_t node_packed_vft = { + node_packed_print, + node_packed_generate, + 0, +}; + +void node_define_print (node_t *this) +{ + fprintf(stdout, "define %s {\n", CDATA0); + if (this->deeper) { + node_vft_t *vftp = the_vft[this->deeper->type]; + fprintf(stdout, " "); + vftp->print(this->deeper); + } + fprintf(stdout, "};\n"); +} + +void node_define_generate (node_t *this, enum passid which, FILE *fp) +{ + node_t *child; + + switch(which) { + case TYPEDEF_PASS: + fprintf(fp, "typedef VL_API_PACKED(struct _vl_api_%s {\n", CDATA0); + child = this->deeper; + indent += 4; + while (child) { + node_vft_t *vftp = the_vft[child->type]; + indent_me(fp); + vftp->generate(child, which, fp); + child = child->peer; + } + indent -= 4; + fprintf(fp, "}) vl_api_%s_t;\n\n", CDATA0); + break; + + case ENDIANFUN_PASS: + case PRINTFUN_PASS: + child = this->deeper; + while (child) { + node_vft_t *vftp = the_vft[child->type]; + vftp->generate(child, which, fp); + child = child->peer; + } + break; + + case PYTHON_PASS: + fprintf(fp, "('%s',\n", CDATA0); + child = this->deeper; + indent += 4; + while (child) { + node_vft_t *vftp = the_vft[child->type]; + indent_me(fp); + vftp->generate(child, which, fp); + child = child->peer; + } + indent -= 4; + fprintf(fp, "),\n\n"); + break; + + case JSON_PASS: + fprintf(fp, "[\"%s\",\n", CDATA0); + child = this->deeper; + indent += 4; + while (child) { + node_vft_t *vftp = the_vft[child->type]; + indent_me(fp); + vftp->generate(child, which, fp); + child = child->peer; + fprintf(fp, ",\n"); + } + indent_me(fp); + fprintf (fp, "{\"crc\" : \"0x%08x\"}\n", (u32)(u64)CDATA3); + indent -= 4; + indent_me(fp); + fprintf(fp, "]"); + break; + + default: + fprintf(stderr, "node_define_generate: unimp pass %d\n", which); + break; + } +} + +node_vft_t node_define_vft = { + node_define_print, + node_define_generate, + 0, +}; + +void node_union_print (node_t *this) +{ + primtype_recursive_print (this, "union "); +} + +void node_union_generate (node_t *this, enum passid which, FILE *fp) +{ + node_t *child; + node_t *uelem; + int case_id=1; + + switch(which) { + case TYPEDEF_PASS: + fprintf(fp, "u8 _%s_which;\n", CDATA0); + indent_me(fp); + fprintf(fp, "union _%s {\n", CDATA0); + child = this->deeper; + indent += 4; + + while (child) { + node_vft_t *vftp = the_vft[child->type]; + indent_me(fp); + vftp->generate(child, which, fp); + child = child->peer; + } + indent -= 4; + indent_me(fp); + fprintf(fp, "} %s;\n", CDATA0); + break; + + case PRINTFUN_PASS: + case ENDIANFUN_PASS: + uelem = this->deeper; + + indent_me(fp); + fprintf(fp, "switch(a->_%s_which) {\n", + CDATA0); + indent += 4; + current_union_name = CDATA0; + + /* Walk the list of objects in this union */ + while (uelem) { + node_vft_t *vftp = the_vft[uelem->type]; + indent -= 4; + indent_me(fp); + fprintf(fp, "case %d:\n", case_id); + case_id++; + indent += 4; + /* Drill down on each element */ + vftp->generate(uelem, which, fp); + indent_me(fp); + fprintf(fp, "break;\n"); + uelem = uelem->peer; + } + current_union_name = 0; + indent -= 4; + indent_me(fp); + fprintf(fp, "default:\n"); + indent += 4; + indent_me(fp); + if (which == PRINTFUN_PASS) { + fprintf(fp, + "vl_print(handle, \"WARNING: _%s_which not set.\\n\");\n", + CDATA0); + } + indent_me(fp); + fprintf(fp, "break;\n"); + indent -= 4; + indent_me(fp); + fprintf(fp, "}\n"); + break; + + default: + fprintf(stderr, "node_union_generate: unimp pass %d\n", which); + break; + } +} + + +node_vft_t node_union_vft = { + node_union_print, + node_union_generate, + 0, +}; + +void node_scalar_print (node_t *this) +{ + fprintf(stdout, "%s", CDATA0); + primtype_recursive_print (this, ""); +} + +void node_scalar_generate (node_t *this, enum passid which, FILE *fp) +{ + char *union_prefix = ""; + + if (current_union_name) { + sprintf(tmpbuf, "%s.", current_union_name); + union_prefix = tmpbuf; + } + + switch(which) { + case TYPEDEF_PASS: + fprintf(fp, "%s;\n", CDATA0); + break; + + case PRINTFUN_PASS: + indent_me(fp); + if (current_is_complex) { + fprintf(fp, "vl_api_%s_t_print(a->%s%s, handle);\n", + current_type_name, union_prefix, CDATA0); + } else { + if (!strcmp(current_type_fmt, "uword")) { + fprintf(fp, + "vl_print(handle, \"%s%s: \" _uword_fmt \"\\n\", %s a->%s%s);\n", + union_prefix, CDATA0, "(_uword_cast)", + union_prefix, CDATA0); + } else { + fprintf(fp, + "vl_print(handle, \"%s%s: %s\\n\", %s a->%s%s);\n", + union_prefix, CDATA0, + current_type_fmt, current_type_cast, + union_prefix, CDATA0); + } + } + break; + + case ENDIANFUN_PASS: + indent_me(fp); + if (current_is_complex) { + fprintf(fp, "vl_api%s_t_endian(a->%s%s);\n", + current_type_name, union_prefix, CDATA0); + } else { + /* Current_endianfun == NULL means e.g. it's a u8... */ + if (current_endianfun) { + fprintf(fp, "a->%s%s = %s(a->%s%s);\n", union_prefix, + CDATA0, current_endianfun, + union_prefix, CDATA0); + } else { + fprintf(fp, "/* a->%s%s = a->%s%s (no-op) */\n", + union_prefix, CDATA0, + union_prefix, CDATA0); + } + } + break; + case PYTHON_PASS: + fprintf(fp, "'%s'),\n", CDATA0); + break; + + case JSON_PASS: + fprintf(fp, "\"%s\"]", CDATA0); + break; + + default: + fprintf(stderr, "node_scalar_generate: unimp pass %d\n", which); + } + if (this->deeper) { + fprintf(stderr, "broken recursion in node_scalar_generate\n"); + } +} + + +node_vft_t node_scalar_vft = { + node_scalar_print, + node_scalar_generate, + 0, +}; + +void node_vector_print (node_t *this) +{ + primtype_recursive_print (this, "vector "); +} + +void node_vector_generate (node_t *this, enum passid which, FILE *fp) +{ + char *union_prefix = ""; + + if (current_union_name) { + sprintf(tmpbuf, "%s.", current_union_name); + union_prefix = tmpbuf; + } + + switch(which) { + case TYPEDEF_PASS: + fprintf(fp, "%s[%d];\n", CDATA0, IDATA1); + break; + + case PRINTFUN_PASS: + /* Don't bother about "u8 data [0];" et al. */ + if (IDATA1 == 0) + break; + + indent_me(fp); + fprintf(fp, "{\n"); + indent += 4; + indent_me(fp); + fprintf(fp, "int _i;\n"); + indent_me(fp); + fprintf(fp, "for (_i = 0; _i < %d; _i++) {\n", + IDATA1); + indent += 4; + indent_me(fp); + if (current_is_complex) { + fprintf(fp, "vl_print(handle, \"%s%s[%%d]: ", + union_prefix, CDATA0); + fprintf(fp, + "vl_print_%s (handle, a->%s%s[_i]);\n", + CDATA0, union_prefix, CDATA0); + } else { + fprintf(fp, + "vl_print(handle, \"%s%s[%%d]: %s\\n\", _i, a->%s%s[_i]);\n", + union_prefix, CDATA0, + current_type_fmt, + union_prefix, CDATA0); + } + indent -= 4; + indent_me(fp); + fprintf(fp, "}\n"); + indent -= 4; + indent_me(fp); + fprintf(fp, "}\n"); + break; + + case ENDIANFUN_PASS: + /* Don't bother about "u8 data [0];" et al. */ + if (IDATA1 == 0) + break; + /* If this is a simple endian swap, but the endian swap method is a no-op, + * then indicate this is a no-op in a comment. + */ + if (!current_is_complex && current_endianfun == NULL) { + indent_me(fp); + fprintf(fp, "/* a->%s%s[0..%d] = a->%s%s[0..%d] (no-op) */\n", + union_prefix, CDATA0, IDATA1 - 1, + union_prefix, CDATA0, IDATA1 - 1); + break; + } + + indent_me(fp); + fprintf(fp, "{\n"); + indent += 4; + indent_me(fp); + fprintf(fp, "int _i;\n"); + indent_me(fp); + fprintf(fp, "for (_i = 0; _i < %d; _i++) {\n", + IDATA1); + indent += 4; + indent_me(fp); + if (current_is_complex) { + fprintf(fp, + "vl_api_%s_t_endian (a->%s%s[_i]);\n", + current_type_name, union_prefix, CDATA0); + } else { + fprintf(fp, + "a->%s%s[_i] = %s(a->%s%s[_i]);\n", + union_prefix, CDATA0, + current_endianfun, + union_prefix, CDATA0); + } + indent -= 4; + indent_me(fp); + fprintf(fp, "}\n"); + indent -= 4; + indent_me(fp); + fprintf(fp, "}\n"); + break; + case PYTHON_PASS: + if (CDATA2 != 0) { // variable length vector + fprintf(fp, "'%s', '%d', '%s'),\n", CDATA0, IDATA1, CDATA2); + } else { + fprintf(fp, "'%s', '%d'),\n", CDATA0, IDATA1); + } + break; + + case JSON_PASS: + if (CDATA2 != 0) { /* variable length vector */ + fprintf(fp, "\"%s\", %d, \"%s\"]", CDATA0, IDATA1, CDATA2); + } else { + fprintf(fp, "\"%s\", %d]", CDATA0, IDATA1); + } + break; + + default: + fprintf(stderr, "node_vector_generate: unimp pass %d\n", which); + } + if (this->deeper) { + fprintf(stderr, "broken recursion in node_vector_generate\n"); + } +} + +node_vft_t node_vector_vft = { + node_vector_print, + node_vector_generate, + 0, +}; + +void node_complex_print (node_t *this) +{ + primtype_recursive_print (this, "complex "); +} + +void node_complex_generate (node_t *this, enum passid which, FILE *fp) +{ + node_t *deeper; + node_vft_t *vftp; + char *member_name = "broken!"; + char *union_prefix = ""; + + if (current_union_name) { + sprintf(tmpbuf, "%s.", current_union_name); + union_prefix = tmpbuf; + } + + current_is_complex++; + + switch(which) { + case TYPEDEF_PASS: + fprintf(fp, "%s ", CDATA0); + deeper = this->deeper; + if (deeper) { + vftp = the_vft[deeper->type]; + vftp->generate(deeper, which, fp); + } + break; + + case PRINTFUN_PASS: + deeper = this->deeper; + while (deeper) { + if (deeper->type == NODE_SCALAR || + deeper->type == NODE_VECTOR) { + member_name = deeper->data[0]; + break; + } + deeper = deeper->deeper; + } + indent_me(fp); + fprintf(fp, "vl_print(handle, \"%s%s ----- \\n\");\n", + union_prefix, member_name); + indent_me(fp); + fprintf(fp, "%s_print(&a->%s%s, handle);\n", + CDATA0, union_prefix, member_name); + indent_me(fp); + fprintf(fp, "vl_print(handle, \"%s%s ----- END \\n\");\n", + union_prefix, member_name); + break; + + case ENDIANFUN_PASS: + deeper = this->deeper; + while (deeper) { + if (deeper->type == NODE_SCALAR || + deeper->type == NODE_VECTOR) { + member_name = deeper->data[0]; + break; + } + deeper = deeper->deeper; + } + + indent_me(fp); + fprintf(fp, "%s_endian(&a->%s%s);\n", + CDATA0, union_prefix, member_name); + break; + case PYTHON_PASS: + fprintf(fp, "('%s',", CDATA0); + deeper = this->deeper; + if (deeper) { + vftp = the_vft[deeper->type]; + vftp->generate(deeper, which, fp); + } + break; + + case JSON_PASS: + fprintf(fp, "[\"%s\", ", CDATA0); + deeper = this->deeper; + if (deeper) { + vftp = the_vft[deeper->type]; + vftp->generate(deeper, which, fp); + } + break; + + default: + fprintf(stderr, "node_complex_generate unimp pass %d...\n", which); + break; + } + current_is_complex--; +} + +node_vft_t node_complex_vft = { + node_complex_print, + node_complex_generate, + 0, +}; + +void node_noversion_print (node_t *this) +{ + primtype_recursive_print (this, "noversion "); +} + +void node_noversion_generate (node_t *this, enum passid which, FILE *ofp) +{ + fprintf(stderr, "node_noversion_generate called...\n"); +} + +node_vft_t node_noversion_vft = { + node_noversion_print, + node_noversion_generate, + 0, +}; + +void node_uword_print (node_t *this) +{ + primtype_recursive_print(this, "uword "); +} + +void node_uword_generate (node_t *this, enum passid which, FILE *ofp) +{ + primtype_recursive_generate(this, which, ofp, "uword", "uword", ""); +} + +node_vft_t node_uword_vft = { + node_uword_print, + node_uword_generate, + "clib_net_to_host_uword", +}; + +node_vft_t *the_vft[NODE_N_TYPES] = { + &node_illegal_vft, + &node_u8_vft, + &node_u16_vft, + &node_u32_vft, + &node_u64_vft, + &node_i8_vft, + &node_i16_vft, + &node_i32_vft, + &node_i64_vft, + &node_f64_vft, + &node_packed_vft, + &node_define_vft, + &node_union_vft, + &node_scalar_vft, + &node_vector_vft, + &node_complex_vft, + &node_noversion_vft, + &node_uword_vft, +}; + +void *make_node (enum node_subclass type) +{ + node_t *rv; + + rv = (node_t *) malloc (sizeof (*rv)); + if (rv == 0) { + fprintf (stderr, "fatal: make_node out of memory\n"); + exit (1); + } + bzero (rv, sizeof (*rv)); + rv->type = type; + return ((void *) rv); +} + +YYSTYPE deeper (YYSTYPE arg1, YYSTYPE arg2) +{ + node_t *np1 = (node_t *) arg1; + node_t *np2 = (node_t *) arg2; + node_t *hook_point; + + hook_point = np1; + + while (hook_point->deeper) + hook_point = hook_point->deeper; + + hook_point->deeper = np2; + return (arg1); +} + +YYSTYPE addpeer (YYSTYPE arg1, YYSTYPE arg2) +{ + node_t *np1 = (node_t *) arg1; + node_t *np2 = (node_t *) arg2; + node_t *hook_point; + + hook_point = np1; + + while (hook_point->peer) + hook_point = hook_point->peer; + + hook_point->peer = np2; + return (arg1); +} + +/* + * add_slist (stmt_list, stmt) + */ + +YYSTYPE add_slist (YYSTYPE a1, YYSTYPE a2) +{ + if (a1 && a2) + return (addpeer(a1, a2)); + else if(a1) + return(a1); + else + return(a2); +} + +/* + * add_define (char *name, defn_list); + */ +YYSTYPE add_define (YYSTYPE a1, YYSTYPE a2) +{ + node_t *np; + + np = make_node(NODE_DEFINE); + np->data[0] = a1; + np->data[3] = (void *) message_crc; + deeper((YYSTYPE)np, a2); + return ((YYSTYPE) np); +} + +/* + * add_defbody (defn_list, new_defn) + */ +YYSTYPE add_defbody (YYSTYPE a1, YYSTYPE a2) +{ + return (addpeer(a1, a2)); +} + +/* + * add_primtype ([packed], primitive type, instance) + */ + +YYSTYPE add_primtype (YYSTYPE a1, YYSTYPE a2, YYSTYPE a3) +{ + /* Hook instance to type node */ + deeper (a1, a2); + if (a3) { + deeper(a1, a3); + } + return (a1); +} + +/* + * add_complex(char *type_name, instance) + */ + +YYSTYPE add_complex (YYSTYPE a1, YYSTYPE a2) +{ + node_t *np; + + np = make_node(NODE_COMPLEX); + np->data[0] = (void *) a1; + + deeper((YYSTYPE)np, a2); + return ((YYSTYPE) np); +} + +/* + * add_union(char *type_name, definition) + */ + +YYSTYPE add_union (YYSTYPE a1, YYSTYPE a2) +{ + node_t *np; + + np = make_node(NODE_UNION); + np->data[0] = (void *) a1; + + deeper((YYSTYPE)np, a2); + return ((YYSTYPE) np); +} + + +/* + * add_vector_vbl (node_t *variable, YYSTYPE size) + */ + +YYSTYPE add_vector_vbl (YYSTYPE a1, YYSTYPE a2) +{ + node_t *np; + + np = make_node(NODE_VECTOR); + np->data[0] = (void *) a1; + np->data[1] = (void *) a2; + return ((YYSTYPE) np); +} + +/* + * add_vector_vbl (char *vector_name, char *vector_length_var) + */ + +YYSTYPE add_variable_length_vector_vbl (YYSTYPE vector_name, YYSTYPE vector_length_var) +{ + node_t *np; + + np = make_node(NODE_VECTOR); + np->data[0] = (void *) vector_name; + np->data[1] = (void *) 0; // vector size used for vpe.api.h generation (array of length zero) + np->data[2] = (void *) vector_length_var; // name of the variable that stores vector length + return ((YYSTYPE) np); +} + +/* + * add_scalar_vbl (char *name) + */ +YYSTYPE add_scalar_vbl (YYSTYPE a1) +{ + node_t *np; + + np = make_node(NODE_SCALAR); + np->data[0] = (void *) a1; + return ((YYSTYPE) np); +} + +/* + * set_flags (int flags, msg(=0?)) + */ +YYSTYPE set_flags(YYSTYPE a1, YYSTYPE a2) +{ + node_t *np; + int flags; + + np = (node_t *)a2; + if (!np) + return(0); + + flags = (int)(uword) a1; + + np->flags |= flags; + return (a2); +} +/* + * suppress_version + */ +YYSTYPE suppress_version (void) +{ + dont_output_version = 1; + return (0); +} + +void dump(node_t *np) +{ + node_vft_t *vftp; + + while (np) { + vftp = the_vft[np->type]; + vftp->print(np); + np = np->peer; + } +} + +char *fixup_input_filename(void) +{ + char *cp; + + cp = (char *)input_filename; + + while (*cp) + cp++; + + cp--; + + while (cp > input_filename && *cp != '/') + cp--; + if (*cp == '/') + cp++; + + strncpy (tmpbuf, cp, sizeof(tmpbuf)-1); + + cp = tmpbuf; + + while (*cp) + cp++; + + cp--; + + while (cp > tmpbuf && *cp != '.') + cp--; + + if (*cp == '.') + *cp = 0; + + return (sxerox(tmpbuf)); +} + +void generate_top_boilerplate(FILE *fp) + +{ + char *datestring = ctime(&starttime); + fixed_name = fixup_input_filename(); + + datestring[24] = 0; + + fprintf (fp, "/*\n"); + fprintf (fp, " * VLIB API definitions %s\n", datestring); + fprintf (fp, " * Input file: %s\n", input_filename); + fprintf (fp, " * Automatically generated: please edit the input file "); + fprintf (fp, "NOT this file!\n"); + fprintf (fp, " */\n\n"); + fprintf (fp, "#if defined(vl_msg_id)||defined(vl_union_id)||"); + fprintf (fp, "defined(vl_printfun) \\\n ||defined(vl_endianfun)||"); + fprintf (fp, " defined(vl_api_version)||defined(vl_typedefs) \\\n"); + fprintf (fp, " ||defined(vl_msg_name)||defined(vl_msg_name_crc_list)\n"); + fprintf (fp, "/* ok, something was selected */\n"); + fprintf (fp, "#else\n"); + fprintf (fp, "#warning no content included from %s\n", input_filename); + fprintf (fp, "#endif\n\n"); + fprintf (fp, "#define VL_API_PACKED(x) x __attribute__ ((packed))\n\n"); +} + +void generate_bottom_boilerplate(FILE *fp) + +{ + fprintf (fp, "\n#ifdef vl_api_version\n"); + + if (dont_output_version) { + fprintf (fp, "/* WARNING: API FILE VERSION CHECK DISABLED */\n"); + input_crc = 0; + } + + fprintf (fp, "vl_api_version(%s, 0x%08x)\n\n", + fixed_name, (unsigned int)input_crc); + fprintf (fp, "#endif\n\n"); +} + +void generate_msg_ids(YYSTYPE a1, FILE *fp) +{ + node_t *np = (node_t *)a1; + + fprintf (fp, "\n/****** Message ID / handler enum ******/\n\n"); + fprintf (fp, "#ifdef vl_msg_id\n"); + + while (np) { + if (np->type == NODE_DEFINE) { + if (!(np->flags & NODE_FLAG_TYPEONLY)) { + fprintf (fp, "vl_msg_id(VL_API_%s, vl_api_%s_t_handler)\n", + uppercase(np->data[0]), (i8 *)np->data[0]); + } else { + fprintf (fp, "/* typeonly: %s */\n", (i8 *)np->data[0]); + } + } + np = np->peer; + } + fprintf (fp, "#endif\n"); + +} + +void generate_msg_names(YYSTYPE a1, FILE *fp) +{ + node_t *np = (node_t *)a1; + + fprintf (fp, "\n/****** Message names ******/\n\n"); + + fprintf (fp, "#ifdef vl_msg_name\n"); + + while (np) { + if (np->type == NODE_DEFINE) { + if (!(np->flags & NODE_FLAG_TYPEONLY)) { + fprintf (fp, "vl_msg_name(vl_api_%s_t, %d)\n", + (i8 *) np->data[0], + (np->flags & NODE_FLAG_DONT_TRACE ? 0 : 1)); + } else { + fprintf (fp, "/* typeonly: %s */\n", (i8 *)np->data[0]); + } + } + np = np->peer; + } + fprintf (fp, "#endif\n\n"); +} + +void generate_msg_name_crc_list (YYSTYPE a1, FILE *fp) +{ + node_t *np = (node_t *)a1; + char *unique_suffix, *cp; + + unique_suffix = sxerox(fixed_name); + + cp = unique_suffix; + while (*cp && (*cp != '.')) + cp++; + if (*cp == '.') + *cp = 0; + + fprintf (fp, "\n/****** Message name, crc list ******/\n\n"); + + fprintf (fp, "#ifdef vl_msg_name_crc_list\n"); + fprintf (fp, "#define foreach_vl_msg_name_crc_%s ", unique_suffix); + + while (np) { + if (np->type == NODE_DEFINE) { + if (!(np->flags & NODE_FLAG_TYPEONLY)) { + fprintf (fp, "\\\n_(VL_API_%s, %s, %08x) ", + uppercase (np->data[0]), (i8 *) np->data[0], + (u32)(u64)np->data[3]); + } + } + np = np->peer; + } + fprintf (fp, "\n#endif\n\n"); + free (unique_suffix); +} + +void generate_typedefs(YYSTYPE a1, FILE *fp) +{ + node_t *np = (node_t *)a1; + node_vft_t *vftp; + + fprintf(fp, "\n/****** Typedefs *****/\n\n"); + fprintf(fp, "#ifdef vl_typedefs\n\n"); + + /* Walk the top-level node-list */ + while (np) { + if (np->type == NODE_DEFINE) { + /* Yeah, this is pedantic */ + vftp = the_vft[np->type]; + vftp->generate(np, TYPEDEF_PASS, fp); + } + np = np->peer; + } + fprintf(fp, "#endif /* vl_typedefs */\n\n"); +} + +void union_walk_one_defn(node_t *np, FILE *fp) +{ + node_t *vblp; + node_t *uelem; + + /* Walk the list of typed objects in this msg def */ + while (np) { + if (np->type == NODE_UNION) { + current_union_name = np->data[0]; + uelem = np->deeper; + + /* Walk the list of objects in this union */ + while (uelem) { + vblp = uelem->deeper; + /* Drill down on each element, find the variable name */ + while(vblp) { + if (vblp->type == NODE_SCALAR || + vblp->type == NODE_VECTOR || + vblp->type == NODE_COMPLEX) { + fprintf(ofp, "#define %s_", + uppercase(current_def_name)); + fprintf(ofp, "%s_", uppercase(current_union_name)); + fprintf(ofp, "%s %d\n",uppercase(vblp->data[0]), + current_id); + current_id++; + break; + } + vblp = vblp->deeper; + } + uelem = uelem->peer; + } + current_union_name = 0; + current_id = 1; + } + np = np->peer; + } +} + +void generate_uniondefs(YYSTYPE a1, FILE *fp) +{ + node_t *np = (node_t *)a1; + + fprintf(fp, "/****** Discriminated Union Definitions *****/\n\n"); + fprintf(fp, "#ifdef vl_union_id\n\n"); + + /* Walk the top-level node-list */ + while (np) { + if (np->type == NODE_DEFINE) { + current_id = 1; + current_def_name = np->data[0]; + union_walk_one_defn(np->deeper, fp); + } + np = np->peer; + } + fprintf(fp, "\n#endif /* vl_union_id */\n\n"); +} + +void generate_printfun(YYSTYPE a1, FILE *fp) +{ + node_t *np = (node_t *)a1; + node_vft_t *vftp; + + fprintf(fp, "/****** Print functions *****/\n\n"); + fprintf(fp, "#ifdef vl_printfun\n\n"); + + fprintf(fp, "#ifdef LP64\n"); + fputs ("#define _uword_fmt \"%lld\"\n", fp); + fputs ("#define _uword_cast (long long)\n", fp); + fprintf(fp, "#else\n"); + fputs("#define _uword_fmt \"%ld\"\n", fp); + fputs ("#define _uword_cast long\n", fp); + fprintf(fp, "#endif\n\n"); + + /* Walk the top-level node-list */ + while (np) { + if (np->type == NODE_DEFINE) { + if (!(np->flags & NODE_FLAG_MANUAL_PRINT)) { + fprintf(fp, + "static inline void *vl_api_%s_t_print (vl_api_%s_t *a,", + (i8 *)np->data[0], (i8 *) np->data[0]); + fprintf(fp, "void *handle)\n{\n"); + /* output the message name */ + fprintf(fp, + " vl_print(handle, \"vl_api_%s_t:\\n\");\n", + (i8 *)np->data[0]); + + indent += 4; + /* Yeah, this is pedantic */ + vftp = the_vft[np->type]; + vftp->generate(np, PRINTFUN_PASS, fp); + fprintf(fp, " return handle;\n"); + fprintf(fp, "}\n\n"); + indent -= 4; + } else { + fprintf(fp, "/***** manual: vl_api_%s_t_print *****/\n\n", + (i8 *) np->data[0]); + } + } + np = np->peer; + } + fprintf(fp, "#endif /* vl_printfun */\n\n"); +} + +void generate_endianfun(YYSTYPE a1, FILE *fp) +{ + node_t *np = (node_t *)a1; + node_vft_t *vftp; + + fprintf(fp, "\n/****** Endian swap functions *****/\n\n"); + fprintf(fp, "#ifdef vl_endianfun\n\n"); + fprintf(fp, "#undef clib_net_to_host_uword\n"); + fprintf(fp, "#ifdef LP64\n"); + fprintf(fp, "#define clib_net_to_host_uword clib_net_to_host_u64\n"); + fprintf(fp, "#else\n"); + fprintf(fp, "#define clib_net_to_host_uword clib_net_to_host_u32\n"); + fprintf(fp, "#endif\n\n"); + + /* Walk the top-level node-list */ + while (np) { + if (np->type == NODE_DEFINE) { + if (!(np->flags & NODE_FLAG_MANUAL_ENDIAN)) { + fprintf(fp, + "static inline void vl_api_%s_t_endian (vl_api_%s_t *a)\n{\n", + (i8 *) np->data[0], (i8 *) np->data[0]); + indent += 4; + /* Yeah, this is pedantic */ + vftp = the_vft[np->type]; + vftp->generate(np, ENDIANFUN_PASS, fp); + fprintf(fp, "}\n\n"); + indent -= 4; + } else { + fprintf(fp, "/***** manual: vl_api_%s_t_endian *****/\n\n", + (i8 *) np->data[0]); + } + } + np = np->peer; + } + fprintf(fp, "#endif /* vl_endianfun */\n\n"); +} + +void add_msg_ids(YYSTYPE a1) +{ + node_t *np = (node_t *)a1; + node_t *new_u16; + node_t *new_vbl; + + /* Walk the top-level node-list */ + while (np) { + if (np->type == NODE_DEFINE) { + if (!(np->flags & NODE_FLAG_TYPEONLY)) { + /* add the parse tree for "u16 _vl_msg_id" */ + new_u16 = make_node(NODE_U16); + new_u16->peer = np->deeper; + np->deeper = new_u16; + new_vbl = make_node(NODE_SCALAR); + new_vbl->data[0] = sxerox("_vl_msg_id"); + new_u16->deeper = new_vbl; + } + } + np = np->peer; + } +} + +void generate_python_msg_definitions(YYSTYPE a1, FILE *fp) +{ + node_t *np = (node_t *)a1; + node_vft_t *vftp; + fprintf (fp, "messages = [\n"); + /* Walk the top-level node-list */ + while (np) { + if (np->type == NODE_DEFINE && !(np->flags & NODE_FLAG_TYPEONLY)) { + /* Yeah, this is pedantic */ + vftp = the_vft[np->type]; + vftp->generate(np, PYTHON_PASS, fp); + } + np = np->peer; + } + fprintf (fp, "\n]\n"); +} + +static bool +is_typeonly_check(node_t *np, bool typeonly) +{ + bool is_typeonly = (np->flags & NODE_FLAG_TYPEONLY); + return (is_typeonly == typeonly); +} + +static void +generate_json_definitions(YYSTYPE a1, FILE *fp, bool typeonly) +{ + node_t *np = (node_t *)a1; + node_vft_t *vftp; + indent_me(fp); + if (typeonly) + fprintf (fp, "\"types\" : [\n"); + else + fprintf (fp, "\"messages\" : [\n"); + + /* Walk the top-level node-list */ + bool comma = false; + indent += 4; + while (np) { + if (np->type == NODE_DEFINE && is_typeonly_check(np, typeonly)) { + /* Yeah, this is pedantic */ + vftp = the_vft[np->type]; + indent_me(fp); + vftp->generate(np, JSON_PASS, fp); + comma = true; + } + np = np->peer; + if (comma && np && + np->type == NODE_DEFINE && is_typeonly_check(np, typeonly)) + fprintf (fp, ",\n"); + + } + indent -= 4; + fprintf (fp, "\n"); + indent_me(fp); + fprintf(fp, "]"); +} + +void generate_python_typeonly_definitions(YYSTYPE a1, FILE *fp) +{ + node_t *np = (node_t *)a1; + node_vft_t *vftp; + fprintf (fp, "types = [\n"); + /* Walk the top-level node-list */ + while (np) { + if (np->type == NODE_DEFINE && (np->flags & NODE_FLAG_TYPEONLY)) { + vftp = the_vft[np->type]; + vftp->generate(np, PYTHON_PASS, fp); + } + np = np->peer; + } + fprintf (fp, "\n]\n"); +} + +void generate_python(YYSTYPE a1, FILE *fp) +{ + generate_python_typeonly_definitions(a1, fp); + generate_python_msg_definitions(a1, fp); + + /* + * API CRC signature + */ + fprintf (fp, "vl_api_version = 0x%08x\n\n", (unsigned int)input_crc); +} + +void generate_json(YYSTYPE a1, FILE *fp) +{ + fprintf (fp, "{\n"); + indent += 4; + generate_json_definitions(a1, fp, true); + fprintf (fp, ",\n"); + generate_json_definitions(a1, fp, false); + + /* + * API CRC signature + */ + fprintf (fp, ",\n\"vl_api_version\" :\"0x%08x\"\n", + (unsigned int)input_crc); + fprintf (fp, "}\n"); +} + +void generate(YYSTYPE a1) +{ + if (dump_tree) { + dump((node_t *)a1); + } + + add_msg_ids(a1); + + if (ofp) { + generate_top_boilerplate(ofp); + + generate_msg_ids(a1, ofp); + generate_msg_names(a1, ofp); + generate_msg_name_crc_list(a1, ofp); + generate_typedefs(a1, ofp); + generate_uniondefs(a1, ofp); + generate_printfun(a1, ofp); + generate_endianfun(a1, ofp); + + generate_bottom_boilerplate(ofp); + } + if (pythonfp) { + generate_python(a1, pythonfp); + } + if (jsonfp) { + generate_json(a1, jsonfp); + } +} diff --git a/src/tools/vppapigen/node.h b/src/tools/vppapigen/node.h new file mode 100644 index 00000000..297d6036 --- /dev/null +++ b/src/tools/vppapigen/node.h @@ -0,0 +1,94 @@ +/* + *------------------------------------------------------------------ + * node.h - definitions for an API generator + * + * Copyright (c) 2004-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 _node_h_ +#define _node_h_ + +/* + * Global prototypes + */ + +char *sxerox (const char *s); + +enum node_subclass { /* WARNING: indices must match the vft... */ + NODE_ILLEGAL=0, + NODE_U8, + NODE_U16, + NODE_U32, + NODE_U64, + NODE_I8, + NODE_I16, + NODE_I32, + NODE_I64, + NODE_F64, + NODE_PACKED, + NODE_DEFINE, + NODE_UNION, + NODE_SCALAR, + NODE_VECTOR, + NODE_COMPLEX, + NODE_NOVERSION, + NODE_UWORD, + NODE_N_TYPES, /* number of node types with VFT's */ + + /* pseudo-node(s) used in the lexer keyword table, but + NOT in need of a VFT... */ + NODE_TYPEONLY, + NODE_MANUAL_PRINT, + NODE_MANUAL_ENDIAN, + NODE_DONT_TRACE, +}; + +enum passid { + TYPEDEF_PASS=1, + UNION_DEF_PASS, + ENDIANFUN_PASS, + PRINTFUN_PASS, + PYTHON_PASS, + JSON_PASS, +}; + +extern void *make_node (enum node_subclass type); + +typedef struct node_ { + enum node_subclass type; + struct node_ *peer; + struct node_ *deeper; + int flags; + void *data[4]; +} node_t; + +/* To shut up gcc-4.2.x warnings */ +#define CDATA0 ((char *)(this->data[0])) +#define IDATA1 ((int)(uword)(this->data[1])) +#define CDATA2 ((char *)(this->data[2])) +#define CDATA3 ((char *)(this->data[3])) + +#define NODE_FLAG_MANUAL_PRINT (1<<0) +#define NODE_FLAG_MANUAL_ENDIAN (1<<1) +#define NODE_FLAG_TYPEONLY (1<<3) +#define NODE_FLAG_DONT_TRACE (1<<4) + +typedef struct node_vft_ { + void (*print)(struct node_ *); + void (*generate)(struct node_ *, enum passid id, FILE *ofp); + char *endian_converter; +} node_vft_t; + +#endif /* _node_h */ diff --git a/src/vat/api_format.c b/src/vat/api_format.c new file mode 100644 index 00000000..e6c0f244 --- /dev/null +++ b/src/vat/api_format.c @@ -0,0 +1,17829 @@ +/* + *------------------------------------------------------------------ + * api_format.c + * + * Copyright (c) 2014-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vat/json_format.h" + +#include +#include + +#define vl_typedefs /* define message structures */ +#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 + +static uword +api_unformat_sw_if_index (unformat_input_t * input, va_list * args) +{ + vat_main_t *vam = va_arg (*args, vat_main_t *); + u32 *result = va_arg (*args, u32 *); + u8 *if_name; + uword *p; + + if (!unformat (input, "%s", &if_name)) + return 0; + + p = hash_get_mem (vam->sw_if_index_by_interface_name, if_name); + if (p == 0) + return 0; + *result = p[0]; + return 1; +} + +void vat_suspend (vlib_main_t * vm, f64 interval); + +#if VPP_API_TEST_BUILTIN == 0 +/* Parse an IP4 address %d.%d.%d.%d. */ +uword +unformat_ip4_address (unformat_input_t * input, va_list * args) +{ + u8 *result = va_arg (*args, u8 *); + unsigned a[4]; + + if (!unformat (input, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3])) + return 0; + + if (a[0] >= 256 || a[1] >= 256 || a[2] >= 256 || a[3] >= 256) + return 0; + + result[0] = a[0]; + result[1] = a[1]; + result[2] = a[2]; + result[3] = a[3]; + + return 1; +} + +uword +unformat_ethernet_address (unformat_input_t * input, va_list * args) +{ + u8 *result = va_arg (*args, u8 *); + u32 i, a[6]; + + if (!unformat (input, "%_%x:%x:%x:%x:%x:%x%_", + &a[0], &a[1], &a[2], &a[3], &a[4], &a[5])) + return 0; + + /* Check range. */ + for (i = 0; i < 6; i++) + if (a[i] >= (1 << 8)) + return 0; + + for (i = 0; i < 6; i++) + result[i] = a[i]; + + return 1; +} + +/* Returns ethernet type as an int in host byte order. */ +uword +unformat_ethernet_type_host_byte_order (unformat_input_t * input, + va_list * args) +{ + u16 *result = va_arg (*args, u16 *); + int type; + + /* Numeric type. */ + if (unformat (input, "0x%x", &type) || unformat (input, "%d", &type)) + { + if (type >= (1 << 16)) + return 0; + *result = type; + return 1; + } + return 0; +} + +/* Parse an IP6 address. */ +uword +unformat_ip6_address (unformat_input_t * input, va_list * args) +{ + ip6_address_t *result = va_arg (*args, ip6_address_t *); + u16 hex_quads[8]; + uword hex_quad, n_hex_quads, hex_digit, n_hex_digits; + uword c, n_colon, double_colon_index; + + n_hex_quads = hex_quad = n_hex_digits = n_colon = 0; + double_colon_index = ARRAY_LEN (hex_quads); + while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT) + { + hex_digit = 16; + if (c >= '0' && c <= '9') + hex_digit = c - '0'; + else if (c >= 'a' && c <= 'f') + hex_digit = c + 10 - 'a'; + else if (c >= 'A' && c <= 'F') + hex_digit = c + 10 - 'A'; + else if (c == ':' && n_colon < 2) + n_colon++; + else + { + unformat_put_input (input); + break; + } + + /* Too many hex quads. */ + if (n_hex_quads >= ARRAY_LEN (hex_quads)) + return 0; + + if (hex_digit < 16) + { + hex_quad = (hex_quad << 4) | hex_digit; + + /* Hex quad must fit in 16 bits. */ + if (n_hex_digits >= 4) + return 0; + + n_colon = 0; + n_hex_digits++; + } + + /* Save position of :: */ + if (n_colon == 2) + { + /* More than one :: ? */ + if (double_colon_index < ARRAY_LEN (hex_quads)) + return 0; + double_colon_index = n_hex_quads; + } + + if (n_colon > 0 && n_hex_digits > 0) + { + hex_quads[n_hex_quads++] = hex_quad; + hex_quad = 0; + n_hex_digits = 0; + } + } + + if (n_hex_digits > 0) + hex_quads[n_hex_quads++] = hex_quad; + + { + word i; + + /* Expand :: to appropriate number of zero hex quads. */ + if (double_colon_index < ARRAY_LEN (hex_quads)) + { + word n_zero = ARRAY_LEN (hex_quads) - n_hex_quads; + + for (i = n_hex_quads - 1; i >= (signed) double_colon_index; i--) + hex_quads[n_zero + i] = hex_quads[i]; + + for (i = 0; i < n_zero; i++) + hex_quads[double_colon_index + i] = 0; + + n_hex_quads = ARRAY_LEN (hex_quads); + } + + /* Too few hex quads given. */ + if (n_hex_quads < ARRAY_LEN (hex_quads)) + return 0; + + for (i = 0; i < ARRAY_LEN (hex_quads); i++) + result->as_u16[i] = clib_host_to_net_u16 (hex_quads[i]); + + return 1; + } +} + +uword +unformat_ipsec_policy_action (unformat_input_t * input, va_list * args) +{ + u32 *r = va_arg (*args, u32 *); + + if (0); +#define _(v,f,s) else if (unformat (input, s)) *r = IPSEC_POLICY_ACTION_##f; + foreach_ipsec_policy_action +#undef _ + else + return 0; + return 1; +} + +uword +unformat_ipsec_crypto_alg (unformat_input_t * input, va_list * args) +{ + u32 *r = va_arg (*args, u32 *); + + if (0); +#define _(v,f,s) else if (unformat (input, s)) *r = IPSEC_CRYPTO_ALG_##f; + foreach_ipsec_crypto_alg +#undef _ + else + return 0; + return 1; +} + +u8 * +format_ipsec_crypto_alg (u8 * s, va_list * args) +{ + u32 i = va_arg (*args, u32); + u8 *t = 0; + + switch (i) + { +#define _(v,f,str) case IPSEC_CRYPTO_ALG_##f: t = (u8 *) str; break; + foreach_ipsec_crypto_alg +#undef _ + default: + return format (s, "unknown"); + } + return format (s, "%s", t); +} + +uword +unformat_ipsec_integ_alg (unformat_input_t * input, va_list * args) +{ + u32 *r = va_arg (*args, u32 *); + + if (0); +#define _(v,f,s) else if (unformat (input, s)) *r = IPSEC_INTEG_ALG_##f; + foreach_ipsec_integ_alg +#undef _ + else + return 0; + return 1; +} + +u8 * +format_ipsec_integ_alg (u8 * s, va_list * args) +{ + u32 i = va_arg (*args, u32); + u8 *t = 0; + + switch (i) + { +#define _(v,f,str) case IPSEC_INTEG_ALG_##f: t = (u8 *) str; break; + foreach_ipsec_integ_alg +#undef _ + default: + return format (s, "unknown"); + } + return format (s, "%s", t); +} + +uword +unformat_ikev2_auth_method (unformat_input_t * input, va_list * args) +{ + u32 *r = va_arg (*args, u32 *); + + if (0); +#define _(v,f,s) else if (unformat (input, s)) *r = IKEV2_AUTH_METHOD_##f; + foreach_ikev2_auth_method +#undef _ + else + return 0; + return 1; +} + +uword +unformat_ikev2_id_type (unformat_input_t * input, va_list * args) +{ + u32 *r = va_arg (*args, u32 *); + + if (0); +#define _(v,f,s) else if (unformat (input, s)) *r = IKEV2_ID_TYPE_##f; + foreach_ikev2_id_type +#undef _ + else + return 0; + return 1; +} +#endif /* VPP_API_TEST_BUILTIN */ + +static uword +unformat_policer_rate_type (unformat_input_t * input, va_list * args) +{ + u8 *r = va_arg (*args, u8 *); + + if (unformat (input, "kbps")) + *r = SSE2_QOS_RATE_KBPS; + else if (unformat (input, "pps")) + *r = SSE2_QOS_RATE_PPS; + else + return 0; + return 1; +} + +static uword +unformat_policer_round_type (unformat_input_t * input, va_list * args) +{ + u8 *r = va_arg (*args, u8 *); + + if (unformat (input, "closest")) + *r = SSE2_QOS_ROUND_TO_CLOSEST; + else if (unformat (input, "up")) + *r = SSE2_QOS_ROUND_TO_UP; + else if (unformat (input, "down")) + *r = SSE2_QOS_ROUND_TO_DOWN; + else + return 0; + return 1; +} + +static uword +unformat_policer_type (unformat_input_t * input, va_list * args) +{ + u8 *r = va_arg (*args, u8 *); + + if (unformat (input, "1r2c")) + *r = SSE2_QOS_POLICER_TYPE_1R2C; + else if (unformat (input, "1r3c")) + *r = SSE2_QOS_POLICER_TYPE_1R3C_RFC_2697; + else if (unformat (input, "2r3c-2698")) + *r = SSE2_QOS_POLICER_TYPE_2R3C_RFC_2698; + else if (unformat (input, "2r3c-4115")) + *r = SSE2_QOS_POLICER_TYPE_2R3C_RFC_4115; + else if (unformat (input, "2r3c-mef5cf1")) + *r = SSE2_QOS_POLICER_TYPE_2R3C_RFC_MEF5CF1; + else + return 0; + return 1; +} + +static uword +unformat_dscp (unformat_input_t * input, va_list * va) +{ + u8 *r = va_arg (*va, u8 *); + + if (0); +#define _(v,f,str) else if (unformat (input, str)) *r = VNET_DSCP_##f; + foreach_vnet_dscp +#undef _ + else + return 0; + return 1; +} + +static uword +unformat_policer_action_type (unformat_input_t * input, va_list * va) +{ + sse2_qos_pol_action_params_st *a + = va_arg (*va, sse2_qos_pol_action_params_st *); + + if (unformat (input, "drop")) + a->action_type = SSE2_QOS_ACTION_DROP; + else if (unformat (input, "transmit")) + a->action_type = SSE2_QOS_ACTION_TRANSMIT; + else if (unformat (input, "mark-and-transmit %U", unformat_dscp, &a->dscp)) + a->action_type = SSE2_QOS_ACTION_MARK_AND_TRANSMIT; + else + return 0; + return 1; +} + +static uword +unformat_policer_classify_table_type (unformat_input_t * input, va_list * va) +{ + u32 *r = va_arg (*va, u32 *); + u32 tid; + + if (unformat (input, "ip4")) + tid = POLICER_CLASSIFY_TABLE_IP4; + else if (unformat (input, "ip6")) + tid = POLICER_CLASSIFY_TABLE_IP6; + else if (unformat (input, "l2")) + tid = POLICER_CLASSIFY_TABLE_L2; + else + return 0; + + *r = tid; + return 1; +} + +static uword +unformat_flow_classify_table_type (unformat_input_t * input, va_list * va) +{ + u32 *r = va_arg (*va, u32 *); + u32 tid; + + if (unformat (input, "ip4")) + tid = FLOW_CLASSIFY_TABLE_IP4; + else if (unformat (input, "ip6")) + tid = FLOW_CLASSIFY_TABLE_IP6; + else + return 0; + + *r = tid; + return 1; +} + +#if (VPP_API_TEST_BUILTIN==0) +u8 * +format_ip4_address (u8 * s, va_list * args) +{ + u8 *a = va_arg (*args, u8 *); + return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]); +} + +u8 * +format_ip6_address (u8 * s, va_list * args) +{ + ip6_address_t *a = va_arg (*args, ip6_address_t *); + u32 i, i_max_n_zero, max_n_zeros, i_first_zero, n_zeros, last_double_colon; + + i_max_n_zero = ARRAY_LEN (a->as_u16); + max_n_zeros = 0; + i_first_zero = i_max_n_zero; + n_zeros = 0; + for (i = 0; i < ARRAY_LEN (a->as_u16); i++) + { + u32 is_zero = a->as_u16[i] == 0; + if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16)) + { + i_first_zero = i; + n_zeros = 0; + } + n_zeros += is_zero; + if ((!is_zero && n_zeros > max_n_zeros) + || (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros)) + { + i_max_n_zero = i_first_zero; + max_n_zeros = n_zeros; + i_first_zero = ARRAY_LEN (a->as_u16); + n_zeros = 0; + } + } + + last_double_colon = 0; + for (i = 0; i < ARRAY_LEN (a->as_u16); i++) + { + if (i == i_max_n_zero && max_n_zeros > 1) + { + s = format (s, "::"); + i += max_n_zeros - 1; + last_double_colon = 1; + } + else + { + s = format (s, "%s%x", + (last_double_colon || i == 0) ? "" : ":", + clib_net_to_host_u16 (a->as_u16[i])); + last_double_colon = 0; + } + } + + return s; +} + +/* Format an IP46 address. */ +u8 * +format_ip46_address (u8 * s, va_list * args) +{ + ip46_address_t *ip46 = va_arg (*args, ip46_address_t *); + ip46_type_t type = va_arg (*args, ip46_type_t); + int is_ip4 = 1; + + switch (type) + { + case IP46_TYPE_ANY: + is_ip4 = ip46_address_is_ip4 (ip46); + break; + case IP46_TYPE_IP4: + is_ip4 = 1; + break; + case IP46_TYPE_IP6: + is_ip4 = 0; + break; + } + + return is_ip4 ? + format (s, "%U", format_ip4_address, &ip46->ip4) : + format (s, "%U", format_ip6_address, &ip46->ip6); +} + +u8 * +format_ethernet_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]); +} +#endif + +static void +increment_v4_address (ip4_address_t * a) +{ + u32 v; + + v = ntohl (a->as_u32) + 1; + a->as_u32 = ntohl (v); +} + +static void +increment_v6_address (ip6_address_t * a) +{ + u64 v0, v1; + + v0 = clib_net_to_host_u64 (a->as_u64[0]); + v1 = clib_net_to_host_u64 (a->as_u64[1]); + + v1 += 1; + if (v1 == 0) + v0 += 1; + a->as_u64[0] = clib_net_to_host_u64 (v0); + a->as_u64[1] = clib_net_to_host_u64 (v1); +} + +static void +increment_mac_address (u64 * mac) +{ + u64 tmp = *mac; + + tmp = clib_net_to_host_u64 (tmp); + tmp += 1 << 16; /* skip unused (least significant) octets */ + tmp = clib_host_to_net_u64 (tmp); + *mac = tmp; +} + +static void vl_api_create_loopback_reply_t_handler + (vl_api_create_loopback_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + vam->retval = retval; + vam->regenerate_interface_table = 1; + vam->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; +} + +static void vl_api_create_loopback_reply_t_handler_json + (vl_api_create_loopback_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_af_packet_create_reply_t_handler + (vl_api_af_packet_create_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + vam->retval = retval; + vam->regenerate_interface_table = 1; + vam->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; +} + +static void vl_api_af_packet_create_reply_t_handler_json + (vl_api_af_packet_create_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_create_vlan_subif_reply_t_handler + (vl_api_create_vlan_subif_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + vam->retval = retval; + vam->regenerate_interface_table = 1; + vam->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; +} + +static void vl_api_create_vlan_subif_reply_t_handler_json + (vl_api_create_vlan_subif_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_create_subif_reply_t_handler + (vl_api_create_subif_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + vam->retval = retval; + vam->regenerate_interface_table = 1; + vam->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; +} + +static void vl_api_create_subif_reply_t_handler_json + (vl_api_create_subif_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_interface_name_renumber_reply_t_handler + (vl_api_interface_name_renumber_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + vam->retval = retval; + vam->regenerate_interface_table = 1; + vam->result_ready = 1; +} + +static void vl_api_interface_name_renumber_reply_t_handler_json + (vl_api_interface_name_renumber_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +/* + * Special-case: build the interface table, maintain + * the next loopback sw_if_index vbl. + */ +static void vl_api_sw_interface_details_t_handler + (vl_api_sw_interface_details_t * mp) +{ + vat_main_t *vam = &vat_main; + u8 *s = format (0, "%s%c", mp->interface_name, 0); + + hash_set_mem (vam->sw_if_index_by_interface_name, s, + ntohl (mp->sw_if_index)); + + /* In sub interface case, fill the sub interface table entry */ + if (mp->sw_if_index != mp->sup_sw_if_index) + { + sw_interface_subif_t *sub = NULL; + + vec_add2 (vam->sw_if_subif_table, sub, 1); + + vec_validate (sub->interface_name, strlen ((char *) s) + 1); + strncpy ((char *) sub->interface_name, (char *) s, + vec_len (sub->interface_name)); + sub->sw_if_index = ntohl (mp->sw_if_index); + sub->sub_id = ntohl (mp->sub_id); + + sub->sub_dot1ad = mp->sub_dot1ad; + sub->sub_number_of_tags = mp->sub_number_of_tags; + sub->sub_outer_vlan_id = ntohs (mp->sub_outer_vlan_id); + sub->sub_inner_vlan_id = ntohs (mp->sub_inner_vlan_id); + sub->sub_exact_match = mp->sub_exact_match; + sub->sub_default = mp->sub_default; + sub->sub_outer_vlan_id_any = mp->sub_outer_vlan_id_any; + sub->sub_inner_vlan_id_any = mp->sub_inner_vlan_id_any; + + /* vlan tag rewrite */ + sub->vtr_op = ntohl (mp->vtr_op); + sub->vtr_push_dot1q = ntohl (mp->vtr_push_dot1q); + sub->vtr_tag1 = ntohl (mp->vtr_tag1); + sub->vtr_tag2 = ntohl (mp->vtr_tag2); + } +} + +static void vl_api_sw_interface_details_t_handler_json + (vl_api_sw_interface_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + vat_json_object_add_uint (node, "sup_sw_if_index", + ntohl (mp->sup_sw_if_index)); + vat_json_object_add_uint (node, "l2_address_length", + ntohl (mp->l2_address_length)); + vat_json_object_add_bytes (node, "l2_address", mp->l2_address, + sizeof (mp->l2_address)); + vat_json_object_add_string_copy (node, "interface_name", + mp->interface_name); + vat_json_object_add_uint (node, "admin_up_down", mp->admin_up_down); + vat_json_object_add_uint (node, "link_up_down", mp->link_up_down); + vat_json_object_add_uint (node, "link_duplex", mp->link_duplex); + vat_json_object_add_uint (node, "link_speed", mp->link_speed); + vat_json_object_add_uint (node, "mtu", ntohs (mp->link_mtu)); + vat_json_object_add_uint (node, "sub_id", ntohl (mp->sub_id)); + vat_json_object_add_uint (node, "sub_dot1ad", mp->sub_dot1ad); + vat_json_object_add_uint (node, "sub_number_of_tags", + mp->sub_number_of_tags); + vat_json_object_add_uint (node, "sub_outer_vlan_id", + ntohs (mp->sub_outer_vlan_id)); + vat_json_object_add_uint (node, "sub_inner_vlan_id", + ntohs (mp->sub_inner_vlan_id)); + vat_json_object_add_uint (node, "sub_exact_match", mp->sub_exact_match); + vat_json_object_add_uint (node, "sub_default", mp->sub_default); + vat_json_object_add_uint (node, "sub_outer_vlan_id_any", + mp->sub_outer_vlan_id_any); + vat_json_object_add_uint (node, "sub_inner_vlan_id_any", + mp->sub_inner_vlan_id_any); + vat_json_object_add_uint (node, "vtr_op", ntohl (mp->vtr_op)); + vat_json_object_add_uint (node, "vtr_push_dot1q", + ntohl (mp->vtr_push_dot1q)); + vat_json_object_add_uint (node, "vtr_tag1", ntohl (mp->vtr_tag1)); + vat_json_object_add_uint (node, "vtr_tag2", ntohl (mp->vtr_tag2)); +} + +static void vl_api_sw_interface_set_flags_t_handler + (vl_api_sw_interface_set_flags_t * mp) +{ + vat_main_t *vam = &vat_main; + if (vam->interface_event_display) + errmsg ("interface flags: sw_if_index %d %s %s", + ntohl (mp->sw_if_index), + mp->admin_up_down ? "admin-up" : "admin-down", + mp->link_up_down ? "link-up" : "link-down"); +} + +static void vl_api_sw_interface_set_flags_t_handler_json + (vl_api_sw_interface_set_flags_t * mp) +{ + /* JSON output not supported */ +} + +static void +vl_api_cli_reply_t_handler (vl_api_cli_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + vam->retval = retval; + vam->shmem_result = (u8 *) mp->reply_in_shmem; + vam->result_ready = 1; +} + +static void +vl_api_cli_reply_t_handler_json (vl_api_cli_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + api_main_t *am = &api_main; + void *oldheap; + u8 *reply; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "reply_in_shmem", + ntohl (mp->reply_in_shmem)); + /* Toss the shared-memory original... */ + pthread_mutex_lock (&am->vlib_rp->mutex); + oldheap = svm_push_data_heap (am->vlib_rp); + + reply = (u8 *) (mp->reply_in_shmem); + vec_free (reply); + + svm_pop_heap (oldheap); + pthread_mutex_unlock (&am->vlib_rp->mutex); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void +vl_api_cli_inband_reply_t_handler (vl_api_cli_inband_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + vam->retval = retval; + vam->cmd_reply = mp->reply; + vam->result_ready = 1; +} + +static void +vl_api_cli_inband_reply_t_handler_json (vl_api_cli_inband_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_string_copy (&node, "reply", mp->reply); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_classify_add_del_table_reply_t_handler + (vl_api_classify_add_del_table_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; + if (retval == 0 && + ((mp->new_table_index != 0xFFFFFFFF) || + (mp->skip_n_vectors != 0xFFFFFFFF) || + (mp->match_n_vectors != 0xFFFFFFFF))) + /* + * Note: this is just barely thread-safe, depends on + * the main thread spinning waiting for an answer... + */ + errmsg ("new index %d, skip_n_vectors %d, match_n_vectors %d", + ntohl (mp->new_table_index), + ntohl (mp->skip_n_vectors), ntohl (mp->match_n_vectors)); + vam->result_ready = 1; + } +} + +static void vl_api_classify_add_del_table_reply_t_handler_json + (vl_api_classify_add_del_table_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "new_table_index", + ntohl (mp->new_table_index)); + vat_json_object_add_uint (&node, "skip_n_vectors", + ntohl (mp->skip_n_vectors)); + vat_json_object_add_uint (&node, "match_n_vectors", + ntohl (mp->match_n_vectors)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_get_node_index_reply_t_handler + (vl_api_get_node_index_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; + if (retval == 0) + errmsg ("node index %d", ntohl (mp->node_index)); + vam->result_ready = 1; + } +} + +static void vl_api_get_node_index_reply_t_handler_json + (vl_api_get_node_index_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "node_index", ntohl (mp->node_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_get_next_index_reply_t_handler + (vl_api_get_next_index_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; + if (retval == 0) + errmsg ("next node index %d", ntohl (mp->next_index)); + vam->result_ready = 1; + } +} + +static void vl_api_get_next_index_reply_t_handler_json + (vl_api_get_next_index_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "next_index", ntohl (mp->next_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_add_node_next_reply_t_handler + (vl_api_add_node_next_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; + if (retval == 0) + errmsg ("next index %d", ntohl (mp->next_index)); + vam->result_ready = 1; + } +} + +static void vl_api_add_node_next_reply_t_handler_json + (vl_api_add_node_next_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "next_index", ntohl (mp->next_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_show_version_reply_t_handler + (vl_api_show_version_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + if (retval >= 0) + { + errmsg (" program: %s", mp->program); + errmsg (" version: %s", mp->version); + errmsg (" build date: %s", mp->build_date); + errmsg ("build directory: %s", mp->build_directory); + } + vam->retval = retval; + vam->result_ready = 1; +} + +static void vl_api_show_version_reply_t_handler_json + (vl_api_show_version_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_string_copy (&node, "program", mp->program); + vat_json_object_add_string_copy (&node, "version", mp->version); + vat_json_object_add_string_copy (&node, "build_date", mp->build_date); + vat_json_object_add_string_copy (&node, "build_directory", + mp->build_directory); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void +vl_api_ip4_arp_event_t_handler (vl_api_ip4_arp_event_t * mp) +{ + errmsg ("arp %s event: address %U new mac %U sw_if_index %d", + mp->mac_ip ? "mac/ip binding" : "address resolution", + format_ip4_address, &mp->address, + format_ethernet_address, mp->new_mac, mp->sw_if_index); +} + +static void +vl_api_ip4_arp_event_t_handler_json (vl_api_ip4_arp_event_t * mp) +{ + /* JSON output not supported */ +} + +static void +vl_api_ip6_nd_event_t_handler (vl_api_ip6_nd_event_t * mp) +{ + errmsg ("ip6 nd %s event: address %U new mac %U sw_if_index %d", + mp->mac_ip ? "mac/ip binding" : "address resolution", + format_ip6_address, mp->address, + format_ethernet_address, mp->new_mac, mp->sw_if_index); +} + +static void +vl_api_ip6_nd_event_t_handler_json (vl_api_ip6_nd_event_t * mp) +{ + /* JSON output not supported */ +} + +/* + * Special-case: build the bridge domain table, maintain + * the next bd id vbl. + */ +static void vl_api_bridge_domain_details_t_handler + (vl_api_bridge_domain_details_t * mp) +{ + vat_main_t *vam = &vat_main; + u32 n_sw_ifs = ntohl (mp->n_sw_ifs); + + print (vam->ofp, "\n%-3s %-3s %-3s %-3s %-3s %-3s", + " ID", "LRN", "FWD", "FLD", "BVI", "#IF"); + + print (vam->ofp, "%3d %3d %3d %3d %3d %3d", + ntohl (mp->bd_id), mp->learn, mp->forward, + mp->flood, ntohl (mp->bvi_sw_if_index), n_sw_ifs); + + if (n_sw_ifs) + print (vam->ofp, "\n\n%s %s %s", "sw_if_index", "SHG", "Interface Name"); +} + +static void vl_api_bridge_domain_details_t_handler_json + (vl_api_bridge_domain_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node, *array = NULL; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "bd_id", ntohl (mp->bd_id)); + vat_json_object_add_uint (node, "flood", mp->flood); + vat_json_object_add_uint (node, "forward", mp->forward); + vat_json_object_add_uint (node, "learn", mp->learn); + vat_json_object_add_uint (node, "bvi_sw_if_index", + ntohl (mp->bvi_sw_if_index)); + vat_json_object_add_uint (node, "n_sw_ifs", ntohl (mp->n_sw_ifs)); + array = vat_json_object_add (node, "sw_if"); + vat_json_init_array (array); +} + +/* + * Special-case: build the bridge domain sw if table. + */ +static void vl_api_bridge_domain_sw_if_details_t_handler + (vl_api_bridge_domain_sw_if_details_t * mp) +{ + vat_main_t *vam = &vat_main; + hash_pair_t *p; + u8 *sw_if_name = 0; + u32 sw_if_index; + + sw_if_index = ntohl (mp->sw_if_index); + /* *INDENT-OFF* */ + hash_foreach_pair (p, vam->sw_if_index_by_interface_name, + ({ + if ((u32) p->value[0] == sw_if_index) + { + sw_if_name = (u8 *)(p->key); + break; + } + })); + /* *INDENT-ON* */ + + print (vam->ofp, "%7d %3d %s", sw_if_index, + mp->shg, sw_if_name ? (char *) sw_if_name : + "sw_if_index not found!"); +} + +static void vl_api_bridge_domain_sw_if_details_t_handler_json + (vl_api_bridge_domain_sw_if_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + uword last_index = 0; + + ASSERT (VAT_JSON_ARRAY == vam->json_tree.type); + ASSERT (vec_len (vam->json_tree.array) >= 1); + last_index = vec_len (vam->json_tree.array) - 1; + node = &vam->json_tree.array[last_index]; + node = vat_json_object_get_element (node, "sw_if"); + ASSERT (NULL != node); + node = vat_json_array_add (node); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "bd_id", ntohl (mp->bd_id)); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + vat_json_object_add_uint (node, "shg", mp->shg); +} + +static void vl_api_control_ping_reply_t_handler + (vl_api_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_control_ping_reply_t_handler_json + (vl_api_control_ping_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + if (VAT_JSON_NONE != vam->json_tree.type) + { + vat_json_print (vam->ofp, &vam->json_tree); + vat_json_free (&vam->json_tree); + vam->json_tree.type = VAT_JSON_NONE; + } + else + { + /* just print [] */ + vat_json_init_array (&vam->json_tree); + vat_json_print (vam->ofp, &vam->json_tree); + vam->json_tree.type = VAT_JSON_NONE; + } + + vam->retval = retval; + vam->result_ready = 1; +} + +static void +vl_api_l2_flags_reply_t_handler (vl_api_l2_flags_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_l2_flags_reply_t_handler_json + (vl_api_l2_flags_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "resulting_feature_bitmap", + ntohl (mp->resulting_feature_bitmap)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_bridge_flags_reply_t_handler + (vl_api_bridge_flags_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_bridge_flags_reply_t_handler_json + (vl_api_bridge_flags_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "resulting_feature_bitmap", + ntohl (mp->resulting_feature_bitmap)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_tap_connect_reply_t_handler + (vl_api_tap_connect_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->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; + } + +} + +static void vl_api_tap_connect_reply_t_handler_json + (vl_api_tap_connect_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; + +} + +static void +vl_api_tap_modify_reply_t_handler (vl_api_tap_modify_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->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; + } +} + +static void vl_api_tap_modify_reply_t_handler_json + (vl_api_tap_modify_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void +vl_api_tap_delete_reply_t_handler (vl_api_tap_delete_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_tap_delete_reply_t_handler_json + (vl_api_tap_delete_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_mpls_tunnel_add_del_reply_t_handler + (vl_api_mpls_tunnel_add_del_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_mpls_tunnel_add_del_reply_t_handler_json + (vl_api_mpls_tunnel_add_del_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "tunnel_sw_if_index", + ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_l2tpv3_create_tunnel_reply_t_handler + (vl_api_l2tpv3_create_tunnel_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->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; + } +} + +static void vl_api_l2tpv3_create_tunnel_reply_t_handler_json + (vl_api_l2tpv3_create_tunnel_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + + +static void vl_api_lisp_add_del_locator_set_reply_t_handler + (vl_api_lisp_add_del_locator_set_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_lisp_add_del_locator_set_reply_t_handler_json + (vl_api_lisp_add_del_locator_set_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "locator_set_index", ntohl (mp->ls_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_vxlan_add_del_tunnel_reply_t_handler + (vl_api_vxlan_add_del_tunnel_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->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; + } +} + +static void vl_api_vxlan_add_del_tunnel_reply_t_handler_json + (vl_api_vxlan_add_del_tunnel_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_gre_add_del_tunnel_reply_t_handler + (vl_api_gre_add_del_tunnel_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->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; + } +} + +static void vl_api_gre_add_del_tunnel_reply_t_handler_json + (vl_api_gre_add_del_tunnel_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_create_vhost_user_if_reply_t_handler + (vl_api_create_vhost_user_if_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->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; + } +} + +static void vl_api_create_vhost_user_if_reply_t_handler_json + (vl_api_create_vhost_user_if_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_ip_address_details_t_handler + (vl_api_ip_address_details_t * mp) +{ + vat_main_t *vam = &vat_main; + static ip_address_details_t empty_ip_address_details = { {0} }; + ip_address_details_t *address = NULL; + ip_details_t *current_ip_details = NULL; + ip_details_t *details = NULL; + + details = vam->ip_details_by_sw_if_index[vam->is_ipv6]; + + if (!details || vam->current_sw_if_index >= vec_len (details) + || !details[vam->current_sw_if_index].present) + { + errmsg ("ip address details arrived but not stored"); + errmsg ("ip_dump should be called first"); + return; + } + + current_ip_details = vec_elt_at_index (details, vam->current_sw_if_index); + +#define addresses (current_ip_details->addr) + + vec_validate_init_empty (addresses, vec_len (addresses), + empty_ip_address_details); + + address = vec_elt_at_index (addresses, vec_len (addresses) - 1); + + clib_memcpy (&address->ip, &mp->ip, sizeof (address->ip)); + address->prefix_length = mp->prefix_length; +#undef addresses +} + +static void vl_api_ip_address_details_t_handler_json + (vl_api_ip_address_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + struct in6_addr ip6; + struct in_addr ip4; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + if (vam->is_ipv6) + { + clib_memcpy (&ip6, mp->ip, sizeof (ip6)); + vat_json_object_add_ip6 (node, "ip", ip6); + } + else + { + clib_memcpy (&ip4, mp->ip, sizeof (ip4)); + vat_json_object_add_ip4 (node, "ip", ip4); + } + vat_json_object_add_uint (node, "prefix_length", mp->prefix_length); +} + +static void +vl_api_ip_details_t_handler (vl_api_ip_details_t * mp) +{ + vat_main_t *vam = &vat_main; + static ip_details_t empty_ip_details = { 0 }; + ip_details_t *ip = NULL; + u32 sw_if_index = ~0; + + sw_if_index = ntohl (mp->sw_if_index); + + vec_validate_init_empty (vam->ip_details_by_sw_if_index[vam->is_ipv6], + sw_if_index, empty_ip_details); + + ip = vec_elt_at_index (vam->ip_details_by_sw_if_index[vam->is_ipv6], + sw_if_index); + + ip->present = 1; +} + +static void +vl_api_ip_details_t_handler_json (vl_api_ip_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + vat_json_array_add_uint (&vam->json_tree, + clib_net_to_host_u32 (mp->sw_if_index)); +} + +static void vl_api_map_domain_details_t_handler_json + (vl_api_map_domain_details_t * mp) +{ + vat_json_node_t *node = NULL; + vat_main_t *vam = &vat_main; + struct in6_addr ip6; + struct in_addr ip4; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + + node = vat_json_array_add (&vam->json_tree); + vat_json_init_object (node); + + vat_json_object_add_uint (node, "domain_index", + clib_net_to_host_u32 (mp->domain_index)); + clib_memcpy (&ip6, mp->ip6_prefix, sizeof (ip6)); + vat_json_object_add_ip6 (node, "ip6_prefix", ip6); + clib_memcpy (&ip4, mp->ip4_prefix, sizeof (ip4)); + vat_json_object_add_ip4 (node, "ip4_prefix", ip4); + clib_memcpy (&ip6, mp->ip6_src, sizeof (ip6)); + vat_json_object_add_ip6 (node, "ip6_src", ip6); + vat_json_object_add_int (node, "ip6_prefix_len", mp->ip6_prefix_len); + vat_json_object_add_int (node, "ip4_prefix_len", mp->ip4_prefix_len); + vat_json_object_add_int (node, "ip6_src_len", mp->ip6_src_len); + vat_json_object_add_int (node, "ea_bits_len", mp->ea_bits_len); + vat_json_object_add_int (node, "psid_offset", mp->psid_offset); + vat_json_object_add_int (node, "psid_length", mp->psid_length); + vat_json_object_add_uint (node, "flags", mp->flags); + vat_json_object_add_uint (node, "mtu", clib_net_to_host_u16 (mp->mtu)); + vat_json_object_add_int (node, "is_translation", mp->is_translation); +} + +static void vl_api_map_domain_details_t_handler + (vl_api_map_domain_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + if (mp->is_translation) + { + print (vam->ofp, + "* %U/%d (ipv4-prefix) %U/%d (ipv6-prefix) %U/%d (ip6-src) index: %u", + format_ip4_address, mp->ip4_prefix, mp->ip4_prefix_len, + format_ip6_address, mp->ip6_prefix, mp->ip6_prefix_len, + format_ip6_address, mp->ip6_src, mp->ip6_src_len, + clib_net_to_host_u32 (mp->domain_index)); + } + else + { + print (vam->ofp, + "* %U/%d (ipv4-prefix) %U/%d (ipv6-prefix) %U (ip6-src) index: %u", + format_ip4_address, mp->ip4_prefix, mp->ip4_prefix_len, + format_ip6_address, mp->ip6_prefix, mp->ip6_prefix_len, + format_ip6_address, mp->ip6_src, + clib_net_to_host_u32 (mp->domain_index)); + } + print (vam->ofp, " ea-len %d psid-offset %d psid-len %d mtu %d %s", + mp->ea_bits_len, mp->psid_offset, mp->psid_length, mp->mtu, + mp->is_translation ? "map-t" : ""); +} + +static void vl_api_map_rule_details_t_handler_json + (vl_api_map_rule_details_t * mp) +{ + struct in6_addr ip6; + vat_json_node_t *node = NULL; + vat_main_t *vam = &vat_main; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + + node = vat_json_array_add (&vam->json_tree); + vat_json_init_object (node); + + vat_json_object_add_uint (node, "psid", clib_net_to_host_u16 (mp->psid)); + clib_memcpy (&ip6, mp->ip6_dst, sizeof (ip6)); + vat_json_object_add_ip6 (node, "ip6_dst", ip6); +} + +static void +vl_api_map_rule_details_t_handler (vl_api_map_rule_details_t * mp) +{ + vat_main_t *vam = &vat_main; + print (vam->ofp, " %d (psid) %U (ip6-dst)", + clib_net_to_host_u16 (mp->psid), format_ip6_address, mp->ip6_dst); +} + +static void +vl_api_dhcp_compl_event_t_handler (vl_api_dhcp_compl_event_t * mp) +{ + errmsg ("DHCP compl event: pid %d %s hostname %s host_addr %U " + "router_addr %U host_mac %U", + mp->pid, mp->is_ipv6 ? "ipv6" : "ipv4", mp->hostname, + format_ip4_address, &mp->host_address, + format_ip4_address, &mp->router_address, + format_ethernet_address, mp->host_mac); +} + +static void vl_api_dhcp_compl_event_t_handler_json + (vl_api_dhcp_compl_event_t * mp) +{ + /* JSON output not supported */ +} + +static void +set_simple_interface_counter (u8 vnet_counter_type, u32 sw_if_index, + u32 counter) +{ + vat_main_t *vam = &vat_main; + static u64 default_counter = 0; + + vec_validate_init_empty (vam->simple_interface_counters, vnet_counter_type, + NULL); + vec_validate_init_empty (vam->simple_interface_counters[vnet_counter_type], + sw_if_index, default_counter); + vam->simple_interface_counters[vnet_counter_type][sw_if_index] = counter; +} + +static void +set_combined_interface_counter (u8 vnet_counter_type, u32 sw_if_index, + interface_counter_t counter) +{ + vat_main_t *vam = &vat_main; + static interface_counter_t default_counter = { 0, }; + + vec_validate_init_empty (vam->combined_interface_counters, + vnet_counter_type, NULL); + vec_validate_init_empty (vam->combined_interface_counters + [vnet_counter_type], sw_if_index, default_counter); + vam->combined_interface_counters[vnet_counter_type][sw_if_index] = counter; +} + +static void vl_api_vnet_interface_counters_t_handler + (vl_api_vnet_interface_counters_t * mp) +{ + /* not supported */ +} + +static void vl_api_vnet_interface_counters_t_handler_json + (vl_api_vnet_interface_counters_t * mp) +{ + interface_counter_t counter; + vlib_counter_t *v; + u64 *v_packets; + u64 packets; + u32 count; + u32 first_sw_if_index; + int i; + + count = ntohl (mp->count); + first_sw_if_index = ntohl (mp->first_sw_if_index); + + if (!mp->is_combined) + { + v_packets = (u64 *) & mp->data; + for (i = 0; i < count; i++) + { + packets = + clib_net_to_host_u64 (clib_mem_unaligned (v_packets, u64)); + set_simple_interface_counter (mp->vnet_counter_type, + first_sw_if_index + i, packets); + v_packets++; + } + } + else + { + v = (vlib_counter_t *) & mp->data; + for (i = 0; i < count; i++) + { + counter.packets = + clib_net_to_host_u64 (clib_mem_unaligned (&v->packets, u64)); + counter.bytes = + clib_net_to_host_u64 (clib_mem_unaligned (&v->bytes, u64)); + set_combined_interface_counter (mp->vnet_counter_type, + first_sw_if_index + i, counter); + v++; + } + } +} + +static u32 +ip4_fib_counters_get_vrf_index_by_vrf_id (u32 vrf_id) +{ + vat_main_t *vam = &vat_main; + u32 i; + + for (i = 0; i < vec_len (vam->ip4_fib_counters_vrf_id_by_index); i++) + { + if (vam->ip4_fib_counters_vrf_id_by_index[i] == vrf_id) + { + return i; + } + } + return ~0; +} + +static u32 +ip6_fib_counters_get_vrf_index_by_vrf_id (u32 vrf_id) +{ + vat_main_t *vam = &vat_main; + u32 i; + + for (i = 0; i < vec_len (vam->ip6_fib_counters_vrf_id_by_index); i++) + { + if (vam->ip6_fib_counters_vrf_id_by_index[i] == vrf_id) + { + return i; + } + } + return ~0; +} + +static void vl_api_vnet_ip4_fib_counters_t_handler + (vl_api_vnet_ip4_fib_counters_t * mp) +{ + /* not supported */ +} + +static void vl_api_vnet_ip4_fib_counters_t_handler_json + (vl_api_vnet_ip4_fib_counters_t * mp) +{ + vat_main_t *vam = &vat_main; + vl_api_ip4_fib_counter_t *v; + ip4_fib_counter_t *counter; + struct in_addr ip4; + u32 vrf_id; + u32 vrf_index; + u32 count; + int i; + + vrf_id = ntohl (mp->vrf_id); + vrf_index = ip4_fib_counters_get_vrf_index_by_vrf_id (vrf_id); + if (~0 == vrf_index) + { + vrf_index = vec_len (vam->ip4_fib_counters_vrf_id_by_index); + vec_validate (vam->ip4_fib_counters_vrf_id_by_index, vrf_index); + vam->ip4_fib_counters_vrf_id_by_index[vrf_index] = vrf_id; + vec_validate (vam->ip4_fib_counters, vrf_index); + vam->ip4_fib_counters[vrf_index] = NULL; + } + + vec_free (vam->ip4_fib_counters[vrf_index]); + v = (vl_api_ip4_fib_counter_t *) & mp->c; + count = ntohl (mp->count); + for (i = 0; i < count; i++) + { + vec_validate (vam->ip4_fib_counters[vrf_index], i); + counter = &vam->ip4_fib_counters[vrf_index][i]; + clib_memcpy (&ip4, &v->address, sizeof (ip4)); + counter->address = ip4; + counter->address_length = v->address_length; + counter->packets = clib_net_to_host_u64 (v->packets); + counter->bytes = clib_net_to_host_u64 (v->bytes); + v++; + } +} + +static void vl_api_vnet_ip6_fib_counters_t_handler + (vl_api_vnet_ip6_fib_counters_t * mp) +{ + /* not supported */ +} + +static void vl_api_vnet_ip6_fib_counters_t_handler_json + (vl_api_vnet_ip6_fib_counters_t * mp) +{ + vat_main_t *vam = &vat_main; + vl_api_ip6_fib_counter_t *v; + ip6_fib_counter_t *counter; + struct in6_addr ip6; + u32 vrf_id; + u32 vrf_index; + u32 count; + int i; + + vrf_id = ntohl (mp->vrf_id); + vrf_index = ip6_fib_counters_get_vrf_index_by_vrf_id (vrf_id); + if (~0 == vrf_index) + { + vrf_index = vec_len (vam->ip6_fib_counters_vrf_id_by_index); + vec_validate (vam->ip6_fib_counters_vrf_id_by_index, vrf_index); + vam->ip6_fib_counters_vrf_id_by_index[vrf_index] = vrf_id; + vec_validate (vam->ip6_fib_counters, vrf_index); + vam->ip6_fib_counters[vrf_index] = NULL; + } + + vec_free (vam->ip6_fib_counters[vrf_index]); + v = (vl_api_ip6_fib_counter_t *) & mp->c; + count = ntohl (mp->count); + for (i = 0; i < count; i++) + { + vec_validate (vam->ip6_fib_counters[vrf_index], i); + counter = &vam->ip6_fib_counters[vrf_index][i]; + clib_memcpy (&ip6, &v->address, sizeof (ip6)); + counter->address = ip6; + counter->address_length = v->address_length; + counter->packets = clib_net_to_host_u64 (v->packets); + counter->bytes = clib_net_to_host_u64 (v->bytes); + v++; + } +} + +static void vl_api_get_first_msg_id_reply_t_handler + (vl_api_get_first_msg_id_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; + } + if (retval >= 0) + { + errmsg ("first message id %d", ntohs (mp->first_msg_id)); + } +} + +static void vl_api_get_first_msg_id_reply_t_handler_json + (vl_api_get_first_msg_id_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "first_msg_id", + (uint) ntohs (mp->first_msg_id)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_get_node_graph_reply_t_handler + (vl_api_get_node_graph_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + api_main_t *am = &api_main; + i32 retval = ntohl (mp->retval); + u8 *pvt_copy, *reply; + void *oldheap; + vlib_node_t *node; + int i; + + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + vam->result_ready = 1; + } + + /* "Should never happen..." */ + if (retval != 0) + return; + + reply = (u8 *) (mp->reply_in_shmem); + pvt_copy = vec_dup (reply); + + /* Toss the shared-memory original... */ + pthread_mutex_lock (&am->vlib_rp->mutex); + oldheap = svm_push_data_heap (am->vlib_rp); + + vec_free (reply); + + svm_pop_heap (oldheap); + pthread_mutex_unlock (&am->vlib_rp->mutex); + + if (vam->graph_nodes) + { + hash_free (vam->graph_node_index_by_name); + + for (i = 0; i < vec_len (vam->graph_nodes); i++) + { + node = vam->graph_nodes[i]; + vec_free (node->name); + vec_free (node->next_nodes); + vec_free (node); + } + vec_free (vam->graph_nodes); + } + + vam->graph_node_index_by_name = hash_create_string (0, sizeof (uword)); + vam->graph_nodes = vlib_node_unserialize (pvt_copy); + vec_free (pvt_copy); + + for (i = 0; i < vec_len (vam->graph_nodes); i++) + { + node = vam->graph_nodes[i]; + hash_set_mem (vam->graph_node_index_by_name, node->name, i); + } +} + +static void vl_api_get_node_graph_reply_t_handler_json + (vl_api_get_node_graph_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + api_main_t *am = &api_main; + void *oldheap; + vat_json_node_t node; + u8 *reply; + + /* $$$$ make this real? */ + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "reply_in_shmem", mp->reply_in_shmem); + + reply = (u8 *) (mp->reply_in_shmem); + + /* Toss the shared-memory original... */ + pthread_mutex_lock (&am->vlib_rp->mutex); + oldheap = svm_push_data_heap (am->vlib_rp); + + vec_free (reply); + + svm_pop_heap (oldheap); + pthread_mutex_unlock (&am->vlib_rp->mutex); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void +vl_api_lisp_locator_details_t_handler (vl_api_lisp_locator_details_t * mp) +{ + vat_main_t *vam = &vat_main; + u8 *s = 0; + + if (mp->local) + { + s = format (s, "%=16d%=16d%=16d", + ntohl (mp->sw_if_index), mp->priority, mp->weight); + } + else + { + s = format (s, "%=16U%=16d%=16d", + mp->is_ipv6 ? format_ip6_address : + format_ip4_address, + mp->ip_address, mp->priority, mp->weight); + } + + print (vam->ofp, "%v", s); + vec_free (s); +} + +static void +vl_api_lisp_locator_details_t_handler_json (vl_api_lisp_locator_details_t * + mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + struct in6_addr ip6; + struct in_addr ip4; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + vat_json_init_object (node); + + vat_json_object_add_uint (node, "local", mp->local ? 1 : 0); + vat_json_object_add_uint (node, "priority", mp->priority); + vat_json_object_add_uint (node, "weight", mp->weight); + + if (mp->local) + vat_json_object_add_uint (node, "sw_if_index", + clib_net_to_host_u32 (mp->sw_if_index)); + else + { + if (mp->is_ipv6) + { + clib_memcpy (&ip6, mp->ip_address, sizeof (ip6)); + vat_json_object_add_ip6 (node, "address", ip6); + } + else + { + clib_memcpy (&ip4, mp->ip_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "address", ip4); + } + } +} + +static void +vl_api_lisp_locator_set_details_t_handler (vl_api_lisp_locator_set_details_t * + mp) +{ + vat_main_t *vam = &vat_main; + u8 *ls_name = 0; + + ls_name = format (0, "%s", mp->ls_name); + + print (vam->ofp, "%=10d%=15v", clib_net_to_host_u32 (mp->ls_index), + ls_name); + vec_free (ls_name); +} + +static void + vl_api_lisp_locator_set_details_t_handler_json + (vl_api_lisp_locator_set_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = 0; + u8 *ls_name = 0; + + ls_name = format (0, "%s", mp->ls_name); + vec_add1 (ls_name, 0); + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_string_copy (node, "ls_name", ls_name); + vat_json_object_add_uint (node, "ls_index", + clib_net_to_host_u32 (mp->ls_index)); + vec_free (ls_name); +} + +static u8 * +format_lisp_flat_eid (u8 * s, va_list * args) +{ + u32 type = va_arg (*args, u32); + u8 *eid = va_arg (*args, u8 *); + u32 eid_len = va_arg (*args, u32); + + switch (type) + { + case 0: + return format (s, "%U/%d", format_ip4_address, eid, eid_len); + case 1: + return format (s, "%U/%d", format_ip6_address, eid, eid_len); + case 2: + return format (s, "%U", format_ethernet_address, eid); + } + return 0; +} + +static u8 * +format_lisp_eid_vat (u8 * s, va_list * args) +{ + u32 type = va_arg (*args, u32); + u8 *eid = va_arg (*args, u8 *); + u32 eid_len = va_arg (*args, u32); + u8 *seid = va_arg (*args, u8 *); + u32 seid_len = va_arg (*args, u32); + u32 is_src_dst = va_arg (*args, u32); + + if (is_src_dst) + s = format (s, "%U|", format_lisp_flat_eid, type, seid, seid_len); + + s = format (s, "%U", format_lisp_flat_eid, type, eid, eid_len); + + return s; +} + +static void +vl_api_lisp_eid_table_details_t_handler (vl_api_lisp_eid_table_details_t * mp) +{ + vat_main_t *vam = &vat_main; + u8 *s = 0, *eid = 0; + + if (~0 == mp->locator_set_index) + s = format (0, "action: %d", mp->action); + else + s = format (0, "%d", clib_net_to_host_u32 (mp->locator_set_index)); + + eid = format (0, "%U", format_lisp_eid_vat, + mp->eid_type, + mp->eid, + mp->eid_prefix_len, + mp->seid, mp->seid_prefix_len, mp->is_src_dst); + vec_add1 (eid, 0); + + print (vam->ofp, "[%d] %-35s%-20s%-30s%-20d%-20d%-10d%-20s", + clib_net_to_host_u32 (mp->vni), + eid, + mp->is_local ? "local" : "remote", + s, clib_net_to_host_u32 (mp->ttl), mp->authoritative, + clib_net_to_host_u16 (mp->key_id), mp->key); + + vec_free (s); + vec_free (eid); +} + +static void +vl_api_lisp_eid_table_details_t_handler_json (vl_api_lisp_eid_table_details_t + * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = 0; + u8 *eid = 0; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + if (~0 == mp->locator_set_index) + vat_json_object_add_uint (node, "action", mp->action); + else + vat_json_object_add_uint (node, "locator_set_index", + clib_net_to_host_u32 (mp->locator_set_index)); + + vat_json_object_add_uint (node, "is_local", mp->is_local ? 1 : 0); + eid = format (0, "%U", format_lisp_eid_vat, + mp->eid_type, + mp->eid, + mp->eid_prefix_len, + mp->seid, mp->seid_prefix_len, mp->is_src_dst); + vec_add1 (eid, 0); + vat_json_object_add_string_copy (node, "eid", eid); + vat_json_object_add_uint (node, "vni", clib_net_to_host_u32 (mp->vni)); + vat_json_object_add_uint (node, "ttl", clib_net_to_host_u32 (mp->ttl)); + vat_json_object_add_uint (node, "authoritative", (mp->authoritative)); + + if (mp->key_id) + { + vat_json_object_add_uint (node, "key_id", + clib_net_to_host_u16 (mp->key_id)); + vat_json_object_add_string_copy (node, "key", mp->key); + } + vec_free (eid); +} + +static void + vl_api_lisp_eid_table_map_details_t_handler + (vl_api_lisp_eid_table_map_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + u8 *line = format (0, "%=10d%=10d", + clib_net_to_host_u32 (mp->vni), + clib_net_to_host_u32 (mp->dp_table)); + print (vam->ofp, "%v", line); + vec_free (line); +} + +static void + vl_api_lisp_eid_table_map_details_t_handler_json + (vl_api_lisp_eid_table_map_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + vat_json_init_object (node); + vat_json_object_add_uint (node, "dp_table", + clib_net_to_host_u32 (mp->dp_table)); + vat_json_object_add_uint (node, "vni", clib_net_to_host_u32 (mp->vni)); +} + +static void + vl_api_lisp_eid_table_vni_details_t_handler + (vl_api_lisp_eid_table_vni_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + u8 *line = format (0, "%d", clib_net_to_host_u32 (mp->vni)); + print (vam->ofp, "%v", line); + vec_free (line); +} + +static void + vl_api_lisp_eid_table_vni_details_t_handler_json + (vl_api_lisp_eid_table_vni_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + vat_json_init_object (node); + vat_json_object_add_uint (node, "vni", clib_net_to_host_u32 (mp->vni)); +} + +static u8 * +format_decap_next (u8 * s, va_list * args) +{ + u32 next_index = va_arg (*args, u32); + + switch (next_index) + { + case LISP_GPE_INPUT_NEXT_DROP: + return format (s, "drop"); + case LISP_GPE_INPUT_NEXT_IP4_INPUT: + return format (s, "ip4"); + case LISP_GPE_INPUT_NEXT_IP6_INPUT: + return format (s, "ip6"); + default: + return format (s, "unknown %d", next_index); + } + return s; +} + +static void +vl_api_lisp_gpe_tunnel_details_t_handler (vl_api_lisp_gpe_tunnel_details_t * + mp) +{ + vat_main_t *vam = &vat_main; + u8 *iid_str; + u8 *flag_str = NULL; + + iid_str = format (0, "%d (0x%x)", ntohl (mp->iid), ntohl (mp->iid)); + +#define _(n,v) if (mp->flags & v) flag_str = format (flag_str, "%s-bit ", #n); + foreach_lisp_gpe_flag_bit; +#undef _ + + print (vam->ofp, "%=20d%=30U%=16U%=16d%=16d%=16U" + "%=16d%=16d%=16sd=16d%=16s%=16s", + mp->tunnels, + mp->is_ipv6 ? format_ip6_address : format_ip4_address, + mp->source_ip, + mp->is_ipv6 ? format_ip6_address : format_ip4_address, + mp->destination_ip, + ntohl (mp->encap_fib_id), + ntohl (mp->decap_fib_id), + format_decap_next, ntohl (mp->dcap_next), + mp->ver_res >> 6, + flag_str, mp->next_protocol, mp->ver_res, mp->res, iid_str); + + vec_free (iid_str); +} + +static void + vl_api_lisp_gpe_tunnel_details_t_handler_json + (vl_api_lisp_gpe_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + struct in6_addr ip6; + struct in_addr ip4; + u8 *next_decap_str; + + next_decap_str = format (0, "%U", format_decap_next, htonl (mp->dcap_next)); + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "tunel", mp->tunnels); + if (mp->is_ipv6) + { + clib_memcpy (&ip6, mp->source_ip, sizeof (ip6)); + vat_json_object_add_ip6 (node, "source address", ip6); + clib_memcpy (&ip6, mp->destination_ip, sizeof (ip6)); + vat_json_object_add_ip6 (node, "destination address", ip6); + } + else + { + clib_memcpy (&ip4, mp->source_ip, sizeof (ip4)); + vat_json_object_add_ip4 (node, "source address", ip4); + clib_memcpy (&ip4, mp->destination_ip, sizeof (ip4)); + vat_json_object_add_ip4 (node, "destination address", ip4); + } + vat_json_object_add_uint (node, "fib encap", ntohl (mp->encap_fib_id)); + vat_json_object_add_uint (node, "fib decap", ntohl (mp->decap_fib_id)); + vat_json_object_add_string_copy (node, "decap next", next_decap_str); + vat_json_object_add_uint (node, "lisp version", mp->ver_res >> 6); + vat_json_object_add_uint (node, "flags", mp->flags); + vat_json_object_add_uint (node, "next protocol", mp->next_protocol); + vat_json_object_add_uint (node, "ver_res", mp->ver_res); + vat_json_object_add_uint (node, "res", mp->res); + vat_json_object_add_uint (node, "iid", ntohl (mp->iid)); + + vec_free (next_decap_str); +} + +static void + vl_api_show_lisp_map_register_state_reply_t_handler + (vl_api_show_lisp_map_register_state_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + int retval = clib_net_to_host_u32 (mp->retval); + + print (vam->ofp, "%s", mp->is_enabled ? "enabled" : "disabled"); + + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_show_lisp_map_register_state_reply_t_handler_json + (vl_api_show_lisp_map_register_state_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t _node, *node = &_node; + int retval = clib_net_to_host_u32 (mp->retval); + + u8 *s = format (0, "%s", mp->is_enabled ? "enabled" : "disabled"); + + vat_json_init_object (node); + vat_json_object_add_string_copy (node, "state", s); + + vat_json_print (vam->ofp, node); + vat_json_free (node); + + vam->retval = retval; + vam->result_ready = 1; + vec_free (s); +} + +static void + vl_api_show_lisp_rloc_probe_state_reply_t_handler + (vl_api_show_lisp_rloc_probe_state_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + int retval = clib_net_to_host_u32 (mp->retval); + + if (retval) + goto end; + + print (vam->ofp, "%s", mp->is_enabled ? "enabled" : "disabled"); +end: + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_show_lisp_rloc_probe_state_reply_t_handler_json + (vl_api_show_lisp_rloc_probe_state_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t _node, *node = &_node; + int retval = clib_net_to_host_u32 (mp->retval); + + u8 *s = format (0, "%s", mp->is_enabled ? "enabled" : "disabled"); + vat_json_init_object (node); + vat_json_object_add_string_copy (node, "state", s); + + vat_json_print (vam->ofp, node); + vat_json_free (node); + + vam->retval = retval; + vam->result_ready = 1; + vec_free (s); +} + +static void + vl_api_lisp_adjacencies_get_reply_t_handler + (vl_api_lisp_adjacencies_get_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + u32 i, n; + int retval = clib_net_to_host_u32 (mp->retval); + vl_api_lisp_adjacency_t *a; + + if (retval) + goto end; + + n = clib_net_to_host_u32 (mp->count); + + for (i = 0; i < n; i++) + { + a = &mp->adjacencies[i]; + print (vam->ofp, "%U %40U", + format_lisp_flat_eid, a->eid_type, a->leid, a->leid_prefix_len, + format_lisp_flat_eid, a->eid_type, a->reid, a->reid_prefix_len); + } + +end: + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_lisp_adjacencies_get_reply_t_handler_json + (vl_api_lisp_adjacencies_get_reply_t * mp) +{ + u8 *s = 0; + vat_main_t *vam = &vat_main; + vat_json_node_t *e = 0, root; + u32 i, n; + int retval = clib_net_to_host_u32 (mp->retval); + vl_api_lisp_adjacency_t *a; + + if (retval) + goto end; + + n = clib_net_to_host_u32 (mp->count); + vat_json_init_array (&root); + + for (i = 0; i < n; i++) + { + e = vat_json_array_add (&root); + a = &mp->adjacencies[i]; + + vat_json_init_object (e); + s = format (0, "%U", format_lisp_flat_eid, a->eid_type, a->leid, + a->leid_prefix_len); + vec_add1 (s, 0); + vat_json_object_add_string_copy (e, "leid", s); + vec_free (s); + + s = format (0, "%U", format_lisp_flat_eid, a->eid_type, a->reid, + a->reid_prefix_len); + vec_add1 (s, 0); + vat_json_object_add_string_copy (e, "reid", s); + vec_free (s); + } + + vat_json_print (vam->ofp, &root); + vat_json_free (&root); + +end: + vam->retval = retval; + vam->result_ready = 1; +} + +static void +vl_api_lisp_map_server_details_t_handler (vl_api_lisp_map_server_details_t + * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%=20U", + mp->is_ipv6 ? format_ip6_address : format_ip4_address, + mp->ip_address); +} + +static void + vl_api_lisp_map_server_details_t_handler_json + (vl_api_lisp_map_server_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + struct in6_addr ip6; + struct in_addr ip4; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + if (mp->is_ipv6) + { + clib_memcpy (&ip6, mp->ip_address, sizeof (ip6)); + vat_json_object_add_ip6 (node, "map-server", ip6); + } + else + { + clib_memcpy (&ip4, mp->ip_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "map-server", ip4); + } +} + +static void +vl_api_lisp_map_resolver_details_t_handler (vl_api_lisp_map_resolver_details_t + * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%=20U", + mp->is_ipv6 ? format_ip6_address : format_ip4_address, + mp->ip_address); +} + +static void + vl_api_lisp_map_resolver_details_t_handler_json + (vl_api_lisp_map_resolver_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + struct in6_addr ip6; + struct in_addr ip4; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + if (mp->is_ipv6) + { + clib_memcpy (&ip6, mp->ip_address, sizeof (ip6)); + vat_json_object_add_ip6 (node, "map resolver", ip6); + } + else + { + clib_memcpy (&ip4, mp->ip_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "map resolver", ip4); + } +} + +static void + vl_api_show_lisp_status_reply_t_handler + (vl_api_show_lisp_status_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + if (0 <= retval) + { + print (vam->ofp, "feature: %s\ngpe: %s", + mp->feature_status ? "enabled" : "disabled", + mp->gpe_status ? "enabled" : "disabled"); + } + + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_show_lisp_status_reply_t_handler_json + (vl_api_show_lisp_status_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + u8 *gpe_status = NULL; + u8 *feature_status = NULL; + + gpe_status = format (0, "%s", mp->gpe_status ? "enabled" : "disabled"); + feature_status = format (0, "%s", + mp->feature_status ? "enabled" : "disabled"); + vec_add1 (gpe_status, 0); + vec_add1 (feature_status, 0); + + vat_json_init_object (&node); + vat_json_object_add_string_copy (&node, "gpe_status", gpe_status); + vat_json_object_add_string_copy (&node, "feature_status", feature_status); + + vec_free (gpe_status); + vec_free (feature_status); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void + vl_api_lisp_get_map_request_itr_rlocs_reply_t_handler + (vl_api_lisp_get_map_request_itr_rlocs_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + if (retval >= 0) + { + print (vam->ofp, "%=20s", mp->locator_set_name); + } + + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_lisp_get_map_request_itr_rlocs_reply_t_handler_json + (vl_api_lisp_get_map_request_itr_rlocs_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_string_copy (node, "itr-rlocs", mp->locator_set_name); + + vat_json_print (vam->ofp, node); + vat_json_free (node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static u8 * +format_lisp_map_request_mode (u8 * s, va_list * args) +{ + u32 mode = va_arg (*args, u32); + + switch (mode) + { + case 0: + return format (0, "dst-only"); + case 1: + return format (0, "src-dst"); + } + return 0; +} + +static void + vl_api_show_lisp_map_request_mode_reply_t_handler + (vl_api_show_lisp_map_request_mode_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + if (0 <= retval) + { + u32 mode = mp->mode; + print (vam->ofp, "map_request_mode: %U", + format_lisp_map_request_mode, mode); + } + + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_show_lisp_map_request_mode_reply_t_handler_json + (vl_api_show_lisp_map_request_mode_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + u8 *s = 0; + u32 mode; + + mode = mp->mode; + s = format (0, "%U", format_lisp_map_request_mode, mode); + vec_add1 (s, 0); + + vat_json_init_object (&node); + vat_json_object_add_string_copy (&node, "map_request_mode", s); + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vec_free (s); + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void +vl_api_show_lisp_pitr_reply_t_handler (vl_api_show_lisp_pitr_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + if (0 <= retval) + { + print (vam->ofp, "%-20s%-16s", + mp->status ? "enabled" : "disabled", + mp->status ? (char *) mp->locator_set_name : ""); + } + + vam->retval = retval; + vam->result_ready = 1; +} + +static void +vl_api_show_lisp_pitr_reply_t_handler_json (vl_api_show_lisp_pitr_reply_t * + mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + u8 *status = 0; + + status = format (0, "%s", mp->status ? "enabled" : "disabled"); + vec_add1 (status, 0); + + vat_json_init_object (&node); + vat_json_object_add_string_copy (&node, "status", status); + if (mp->status) + { + vat_json_object_add_string_copy (&node, "locator_set", + mp->locator_set_name); + } + + vec_free (status); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static u8 * +format_policer_type (u8 * s, va_list * va) +{ + u32 i = va_arg (*va, u32); + + if (i == SSE2_QOS_POLICER_TYPE_1R2C) + s = format (s, "1r2c"); + else if (i == SSE2_QOS_POLICER_TYPE_1R3C_RFC_2697) + s = format (s, "1r3c"); + else if (i == SSE2_QOS_POLICER_TYPE_2R3C_RFC_2698) + s = format (s, "2r3c-2698"); + else if (i == SSE2_QOS_POLICER_TYPE_2R3C_RFC_4115) + s = format (s, "2r3c-4115"); + else if (i == SSE2_QOS_POLICER_TYPE_2R3C_RFC_MEF5CF1) + s = format (s, "2r3c-mef5cf1"); + else + s = format (s, "ILLEGAL"); + return s; +} + +static u8 * +format_policer_rate_type (u8 * s, va_list * va) +{ + u32 i = va_arg (*va, u32); + + if (i == SSE2_QOS_RATE_KBPS) + s = format (s, "kbps"); + else if (i == SSE2_QOS_RATE_PPS) + s = format (s, "pps"); + else + s = format (s, "ILLEGAL"); + return s; +} + +static u8 * +format_policer_round_type (u8 * s, va_list * va) +{ + u32 i = va_arg (*va, u32); + + if (i == SSE2_QOS_ROUND_TO_CLOSEST) + s = format (s, "closest"); + else if (i == SSE2_QOS_ROUND_TO_UP) + s = format (s, "up"); + else if (i == SSE2_QOS_ROUND_TO_DOWN) + s = format (s, "down"); + else + s = format (s, "ILLEGAL"); + return s; +} + +static u8 * +format_policer_action_type (u8 * s, va_list * va) +{ + u32 i = va_arg (*va, u32); + + if (i == SSE2_QOS_ACTION_DROP) + s = format (s, "drop"); + else if (i == SSE2_QOS_ACTION_TRANSMIT) + s = format (s, "transmit"); + else if (i == SSE2_QOS_ACTION_MARK_AND_TRANSMIT) + s = format (s, "mark-and-transmit"); + else + s = format (s, "ILLEGAL"); + return s; +} + +static u8 * +format_dscp (u8 * s, va_list * va) +{ + u32 i = va_arg (*va, u32); + char *t = 0; + + switch (i) + { +#define _(v,f,str) case VNET_DSCP_##f: t = str; break; + foreach_vnet_dscp +#undef _ + default: + return format (s, "ILLEGAL"); + } + s = format (s, "%s", t); + return s; +} + +static void +vl_api_policer_details_t_handler (vl_api_policer_details_t * mp) +{ + vat_main_t *vam = &vat_main; + u8 *conform_dscp_str, *exceed_dscp_str, *violate_dscp_str; + + if (mp->conform_action_type == SSE2_QOS_ACTION_MARK_AND_TRANSMIT) + conform_dscp_str = format (0, "%U", format_dscp, mp->conform_dscp); + else + conform_dscp_str = format (0, ""); + + if (mp->exceed_action_type == SSE2_QOS_ACTION_MARK_AND_TRANSMIT) + exceed_dscp_str = format (0, "%U", format_dscp, mp->exceed_dscp); + else + exceed_dscp_str = format (0, ""); + + if (mp->violate_action_type == SSE2_QOS_ACTION_MARK_AND_TRANSMIT) + violate_dscp_str = format (0, "%U", format_dscp, mp->violate_dscp); + else + violate_dscp_str = format (0, ""); + + print (vam->ofp, "Name \"%s\", type %U, cir %u, eir %u, cb %u, eb %u, " + "rate type %U, round type %U, %s rate, %s color-aware, " + "cir %u tok/period, pir %u tok/period, scale %u, cur lim %u, " + "cur bkt %u, ext lim %u, ext bkt %u, last update %llu" + "conform action %U%s, exceed action %U%s, violate action %U%s", + mp->name, + format_policer_type, mp->type, + ntohl (mp->cir), + ntohl (mp->eir), + clib_net_to_host_u64 (mp->cb), + clib_net_to_host_u64 (mp->eb), + format_policer_rate_type, mp->rate_type, + format_policer_round_type, mp->round_type, + mp->single_rate ? "single" : "dual", + mp->color_aware ? "is" : "not", + ntohl (mp->cir_tokens_per_period), + ntohl (mp->pir_tokens_per_period), + ntohl (mp->scale), + ntohl (mp->current_limit), + ntohl (mp->current_bucket), + ntohl (mp->extended_limit), + ntohl (mp->extended_bucket), + clib_net_to_host_u64 (mp->last_update_time), + format_policer_action_type, mp->conform_action_type, + conform_dscp_str, + format_policer_action_type, mp->exceed_action_type, + exceed_dscp_str, + format_policer_action_type, mp->violate_action_type, + violate_dscp_str); + + vec_free (conform_dscp_str); + vec_free (exceed_dscp_str); + vec_free (violate_dscp_str); +} + +static void vl_api_policer_details_t_handler_json + (vl_api_policer_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node; + u8 *rate_type_str, *round_type_str, *type_str; + u8 *conform_action_str, *exceed_action_str, *violate_action_str; + + rate_type_str = format (0, "%U", format_policer_rate_type, mp->rate_type); + round_type_str = + format (0, "%U", format_policer_round_type, mp->round_type); + type_str = format (0, "%U", format_policer_type, mp->type); + conform_action_str = format (0, "%U", format_policer_action_type, + mp->conform_action_type); + exceed_action_str = format (0, "%U", format_policer_action_type, + mp->exceed_action_type); + violate_action_str = format (0, "%U", format_policer_action_type, + mp->violate_action_type); + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_string_copy (node, "name", mp->name); + vat_json_object_add_uint (node, "cir", ntohl (mp->cir)); + vat_json_object_add_uint (node, "eir", ntohl (mp->eir)); + vat_json_object_add_uint (node, "cb", ntohl (mp->cb)); + vat_json_object_add_uint (node, "eb", ntohl (mp->eb)); + vat_json_object_add_string_copy (node, "rate_type", rate_type_str); + vat_json_object_add_string_copy (node, "round_type", round_type_str); + vat_json_object_add_string_copy (node, "type", type_str); + vat_json_object_add_uint (node, "single_rate", mp->single_rate); + vat_json_object_add_uint (node, "color_aware", mp->color_aware); + vat_json_object_add_uint (node, "scale", ntohl (mp->scale)); + vat_json_object_add_uint (node, "cir_tokens_per_period", + ntohl (mp->cir_tokens_per_period)); + vat_json_object_add_uint (node, "eir_tokens_per_period", + ntohl (mp->pir_tokens_per_period)); + vat_json_object_add_uint (node, "current_limit", ntohl (mp->current_limit)); + vat_json_object_add_uint (node, "current_bucket", + ntohl (mp->current_bucket)); + vat_json_object_add_uint (node, "extended_limit", + ntohl (mp->extended_limit)); + vat_json_object_add_uint (node, "extended_bucket", + ntohl (mp->extended_bucket)); + vat_json_object_add_uint (node, "last_update_time", + ntohl (mp->last_update_time)); + vat_json_object_add_string_copy (node, "conform_action", + conform_action_str); + if (mp->conform_action_type == SSE2_QOS_ACTION_MARK_AND_TRANSMIT) + { + u8 *dscp_str = format (0, "%U", format_dscp, mp->conform_dscp); + vat_json_object_add_string_copy (node, "conform_dscp", dscp_str); + vec_free (dscp_str); + } + vat_json_object_add_string_copy (node, "exceed_action", exceed_action_str); + if (mp->exceed_action_type == SSE2_QOS_ACTION_MARK_AND_TRANSMIT) + { + u8 *dscp_str = format (0, "%U", format_dscp, mp->exceed_dscp); + vat_json_object_add_string_copy (node, "exceed_dscp", dscp_str); + vec_free (dscp_str); + } + vat_json_object_add_string_copy (node, "violate_action", + violate_action_str); + if (mp->violate_action_type == SSE2_QOS_ACTION_MARK_AND_TRANSMIT) + { + u8 *dscp_str = format (0, "%U", format_dscp, mp->violate_dscp); + vat_json_object_add_string_copy (node, "violate_dscp", dscp_str); + vec_free (dscp_str); + } + + vec_free (rate_type_str); + vec_free (round_type_str); + vec_free (type_str); + vec_free (conform_action_str); + vec_free (exceed_action_str); + vec_free (violate_action_str); +} + +static void +vl_api_classify_table_ids_reply_t_handler (vl_api_classify_table_ids_reply_t * + mp) +{ + vat_main_t *vam = &vat_main; + int i, count = ntohl (mp->count); + + if (count > 0) + print (vam->ofp, "classify table ids (%d) : ", count); + for (i = 0; i < count; i++) + { + print (vam->ofp, "%d", ntohl (mp->ids[i])); + print (vam->ofp, (i < count - 1) ? "," : ""); + } + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void + vl_api_classify_table_ids_reply_t_handler_json + (vl_api_classify_table_ids_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + int i, count = ntohl (mp->count); + + if (count > 0) + { + vat_json_node_t node; + + vat_json_init_object (&node); + for (i = 0; i < count; i++) + { + vat_json_object_add_uint (&node, "table_id", ntohl (mp->ids[i])); + } + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + } + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void + vl_api_classify_table_by_interface_reply_t_handler + (vl_api_classify_table_by_interface_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + u32 table_id; + + table_id = ntohl (mp->l2_table_id); + if (table_id != ~0) + print (vam->ofp, "l2 table id : %d", table_id); + else + print (vam->ofp, "l2 table id : No input ACL tables configured"); + table_id = ntohl (mp->ip4_table_id); + if (table_id != ~0) + print (vam->ofp, "ip4 table id : %d", table_id); + else + print (vam->ofp, "ip4 table id : No input ACL tables configured"); + table_id = ntohl (mp->ip6_table_id); + if (table_id != ~0) + print (vam->ofp, "ip6 table id : %d", table_id); + else + print (vam->ofp, "ip6 table id : No input ACL tables configured"); + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void + vl_api_classify_table_by_interface_reply_t_handler_json + (vl_api_classify_table_by_interface_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + + vat_json_object_add_int (&node, "l2_table_id", ntohl (mp->l2_table_id)); + vat_json_object_add_int (&node, "ip4_table_id", ntohl (mp->ip4_table_id)); + vat_json_object_add_int (&node, "ip6_table_id", ntohl (mp->ip6_table_id)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_policer_add_del_reply_t_handler + (vl_api_policer_add_del_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; + if (retval == 0 && mp->policer_index != 0xFFFFFFFF) + /* + * Note: this is just barely thread-safe, depends on + * the main thread spinning waiting for an answer... + */ + errmsg ("policer index %d", ntohl (mp->policer_index)); + } +} + +static void vl_api_policer_add_del_reply_t_handler_json + (vl_api_policer_add_del_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "policer_index", + ntohl (mp->policer_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +/* Format hex dump. */ +u8 * +format_hex_bytes (u8 * s, va_list * va) +{ + u8 *bytes = va_arg (*va, u8 *); + int n_bytes = va_arg (*va, int); + uword i; + + /* Print short or long form depending on byte count. */ + uword short_form = n_bytes <= 32; + uword indent = format_get_indent (s); + + if (n_bytes == 0) + return s; + + for (i = 0; i < n_bytes; i++) + { + if (!short_form && (i % 32) == 0) + s = format (s, "%08x: ", i); + s = format (s, "%02x", bytes[i]); + if (!short_form && ((i + 1) % 32) == 0 && (i + 1) < n_bytes) + s = format (s, "\n%U", format_white_space, indent); + } + + return s; +} + +static void +vl_api_classify_table_info_reply_t_handler (vl_api_classify_table_info_reply_t + * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (retval == 0) + { + print (vam->ofp, "classify table info :"); + print (vam->ofp, "sessions: %d nexttbl: %d nextnode: %d", + ntohl (mp->active_sessions), ntohl (mp->next_table_index), + ntohl (mp->miss_next_index)); + print (vam->ofp, "nbuckets: %d skip: %d match: %d", + ntohl (mp->nbuckets), ntohl (mp->skip_n_vectors), + ntohl (mp->match_n_vectors)); + print (vam->ofp, "mask: %U", format_hex_bytes, mp->mask, + ntohl (mp->mask_length)); + } + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_classify_table_info_reply_t_handler_json + (vl_api_classify_table_info_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + i32 retval = ntohl (mp->retval); + if (retval == 0) + { + vat_json_init_object (&node); + + vat_json_object_add_int (&node, "sessions", + ntohl (mp->active_sessions)); + vat_json_object_add_int (&node, "nexttbl", + ntohl (mp->next_table_index)); + vat_json_object_add_int (&node, "nextnode", + ntohl (mp->miss_next_index)); + vat_json_object_add_int (&node, "nbuckets", ntohl (mp->nbuckets)); + vat_json_object_add_int (&node, "skip", ntohl (mp->skip_n_vectors)); + vat_json_object_add_int (&node, "match", ntohl (mp->match_n_vectors)); + u8 *s = format (0, "%U%c", format_hex_bytes, mp->mask, + ntohl (mp->mask_length), 0); + vat_json_object_add_string_copy (&node, "mask", s); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + } + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void +vl_api_classify_session_details_t_handler (vl_api_classify_session_details_t * + mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "next_index: %d advance: %d opaque: %d ", + ntohl (mp->hit_next_index), ntohl (mp->advance), + ntohl (mp->opaque_index)); + print (vam->ofp, "mask: %U", format_hex_bytes, mp->match, + ntohl (mp->match_length)); +} + +static void + vl_api_classify_session_details_t_handler_json + (vl_api_classify_session_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_int (node, "next_index", ntohl (mp->hit_next_index)); + vat_json_object_add_int (node, "advance", ntohl (mp->advance)); + vat_json_object_add_int (node, "opaque", ntohl (mp->opaque_index)); + u8 *s = + format (0, "%U%c", format_hex_bytes, mp->match, ntohl (mp->match_length), + 0); + vat_json_object_add_string_copy (node, "match", s); +} + +static void vl_api_pg_create_interface_reply_t_handler + (vl_api_pg_create_interface_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_pg_create_interface_reply_t_handler_json + (vl_api_pg_create_interface_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + i32 retval = ntohl (mp->retval); + if (retval == 0) + { + vat_json_init_object (&node); + + vat_json_object_add_int (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + } + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_policer_classify_details_t_handler + (vl_api_policer_classify_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%10d%20d", ntohl (mp->sw_if_index), + ntohl (mp->table_index)); +} + +static void vl_api_policer_classify_details_t_handler_json + (vl_api_policer_classify_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + vat_json_object_add_uint (node, "table_index", ntohl (mp->table_index)); +} + +static void vl_api_ipsec_gre_add_del_tunnel_reply_t_handler + (vl_api_ipsec_gre_add_del_tunnel_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->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; + } +} + +static void vl_api_ipsec_gre_add_del_tunnel_reply_t_handler_json + (vl_api_ipsec_gre_add_del_tunnel_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_flow_classify_details_t_handler + (vl_api_flow_classify_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%10d%20d", ntohl (mp->sw_if_index), + ntohl (mp->table_index)); +} + +static void vl_api_flow_classify_details_t_handler_json + (vl_api_flow_classify_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + vat_json_object_add_uint (node, "table_index", ntohl (mp->table_index)); +} + + + +#define vl_api_vnet_ip4_fib_counters_t_endian vl_noop_handler +#define vl_api_vnet_ip4_fib_counters_t_print vl_noop_handler +#define vl_api_vnet_ip6_fib_counters_t_endian vl_noop_handler +#define vl_api_vnet_ip6_fib_counters_t_print vl_noop_handler +#define vl_api_lisp_adjacencies_get_reply_t_endian vl_noop_handler +#define vl_api_lisp_adjacencies_get_reply_t_print vl_noop_handler + +/* + * Generate boilerplate reply handlers, which + * dig the return value out of the xxx_reply_t API message, + * stick it into vam->retval, and set vam->result_ready + * + * Could also do this by pointing N message decode slots at + * a single function, but that could break in subtle ways. + */ + +#define foreach_standard_reply_retval_handler \ +_(sw_interface_set_flags_reply) \ +_(sw_interface_add_del_address_reply) \ +_(sw_interface_set_table_reply) \ +_(sw_interface_set_mpls_enable_reply) \ +_(sw_interface_set_vpath_reply) \ +_(sw_interface_set_vxlan_bypass_reply) \ +_(sw_interface_set_l2_bridge_reply) \ +_(sw_interface_set_dpdk_hqos_pipe_reply) \ +_(sw_interface_set_dpdk_hqos_subport_reply) \ +_(sw_interface_set_dpdk_hqos_tctbl_reply) \ +_(bridge_domain_add_del_reply) \ +_(sw_interface_set_l2_xconnect_reply) \ +_(l2fib_add_del_reply) \ +_(ip_add_del_route_reply) \ +_(mpls_route_add_del_reply) \ +_(mpls_ip_bind_unbind_reply) \ +_(proxy_arp_add_del_reply) \ +_(proxy_arp_intfc_enable_disable_reply) \ +_(sw_interface_set_unnumbered_reply) \ +_(ip_neighbor_add_del_reply) \ +_(reset_vrf_reply) \ +_(oam_add_del_reply) \ +_(reset_fib_reply) \ +_(dhcp_proxy_config_reply) \ +_(dhcp_proxy_config_2_reply) \ +_(dhcp_proxy_set_vss_reply) \ +_(dhcp_client_config_reply) \ +_(set_ip_flow_hash_reply) \ +_(sw_interface_ip6_enable_disable_reply) \ +_(sw_interface_ip6_set_link_local_address_reply) \ +_(sw_interface_ip6nd_ra_prefix_reply) \ +_(sw_interface_ip6nd_ra_config_reply) \ +_(set_arp_neighbor_limit_reply) \ +_(l2_patch_add_del_reply) \ +_(sr_tunnel_add_del_reply) \ +_(sr_policy_add_del_reply) \ +_(sr_multicast_map_add_del_reply) \ +_(classify_add_del_session_reply) \ +_(classify_set_interface_ip_table_reply) \ +_(classify_set_interface_l2_tables_reply) \ +_(l2tpv3_set_tunnel_cookies_reply) \ +_(l2tpv3_interface_enable_disable_reply) \ +_(l2tpv3_set_lookup_key_reply) \ +_(l2_fib_clear_table_reply) \ +_(l2_interface_efp_filter_reply) \ +_(l2_interface_vlan_tag_rewrite_reply) \ +_(modify_vhost_user_if_reply) \ +_(delete_vhost_user_if_reply) \ +_(want_ip4_arp_events_reply) \ +_(want_ip6_nd_events_reply) \ +_(input_acl_set_interface_reply) \ +_(ipsec_spd_add_del_reply) \ +_(ipsec_interface_add_del_spd_reply) \ +_(ipsec_spd_add_del_entry_reply) \ +_(ipsec_sad_add_del_entry_reply) \ +_(ipsec_sa_set_key_reply) \ +_(ikev2_profile_add_del_reply) \ +_(ikev2_profile_set_auth_reply) \ +_(ikev2_profile_set_id_reply) \ +_(ikev2_profile_set_ts_reply) \ +_(ikev2_set_local_key_reply) \ +_(delete_loopback_reply) \ +_(bd_ip_mac_add_del_reply) \ +_(map_del_domain_reply) \ +_(map_add_del_rule_reply) \ +_(want_interface_events_reply) \ +_(want_stats_reply) \ +_(cop_interface_enable_disable_reply) \ +_(cop_whitelist_enable_disable_reply) \ +_(sw_interface_clear_stats_reply) \ +_(ioam_enable_reply) \ +_(ioam_disable_reply) \ +_(lisp_add_del_locator_reply) \ +_(lisp_add_del_local_eid_reply) \ +_(lisp_add_del_remote_mapping_reply) \ +_(lisp_add_del_adjacency_reply) \ +_(lisp_gpe_add_del_fwd_entry_reply) \ +_(lisp_add_del_map_resolver_reply) \ +_(lisp_add_del_map_server_reply) \ +_(lisp_gpe_enable_disable_reply) \ +_(lisp_gpe_add_del_iface_reply) \ +_(lisp_enable_disable_reply) \ +_(lisp_rloc_probe_enable_disable_reply) \ +_(lisp_map_register_enable_disable_reply) \ +_(lisp_pitr_set_locator_set_reply) \ +_(lisp_map_request_mode_reply) \ +_(lisp_add_del_map_request_itr_rlocs_reply) \ +_(lisp_eid_table_add_del_map_reply) \ +_(vxlan_gpe_add_del_tunnel_reply) \ +_(af_packet_delete_reply) \ +_(policer_classify_set_interface_reply) \ +_(netmap_create_reply) \ +_(netmap_delete_reply) \ +_(set_ipfix_exporter_reply) \ +_(set_ipfix_classify_stream_reply) \ +_(ipfix_classify_table_add_del_reply) \ +_(flow_classify_set_interface_reply) \ +_(sw_interface_span_enable_disable_reply) \ +_(pg_capture_reply) \ +_(pg_enable_disable_reply) \ +_(ip_source_and_port_range_check_add_del_reply) \ +_(ip_source_and_port_range_check_interface_add_del_reply)\ +_(delete_subif_reply) \ +_(l2_interface_pbb_tag_rewrite_reply) \ +_(punt_reply) \ +_(feature_enable_disable_reply) \ +_(sw_interface_tag_add_del_reply) \ +_(sw_interface_set_mtu_reply) + +#define _(n) \ + static void vl_api_##n##_t_handler \ + (vl_api_##n##_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; \ + } \ + } +foreach_standard_reply_retval_handler; +#undef _ + +#define _(n) \ + static void vl_api_##n##_t_handler_json \ + (vl_api_##n##_t * mp) \ + { \ + vat_main_t * vam = &vat_main; \ + vat_json_node_t node; \ + vat_json_init_object(&node); \ + vat_json_object_add_int(&node, "retval", ntohl(mp->retval)); \ + vat_json_print(vam->ofp, &node); \ + vam->retval = ntohl(mp->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 \ +_(CREATE_LOOPBACK_REPLY, create_loopback_reply) \ +_(SW_INTERFACE_DETAILS, sw_interface_details) \ +_(SW_INTERFACE_SET_FLAGS, sw_interface_set_flags) \ +_(SW_INTERFACE_SET_FLAGS_REPLY, sw_interface_set_flags_reply) \ +_(CONTROL_PING_REPLY, control_ping_reply) \ +_(CLI_REPLY, cli_reply) \ +_(CLI_INBAND_REPLY, cli_inband_reply) \ +_(SW_INTERFACE_ADD_DEL_ADDRESS_REPLY, \ + sw_interface_add_del_address_reply) \ +_(SW_INTERFACE_SET_TABLE_REPLY, sw_interface_set_table_reply) \ +_(SW_INTERFACE_SET_MPLS_ENABLE_REPLY, sw_interface_set_mpls_enable_reply) \ +_(SW_INTERFACE_SET_VPATH_REPLY, sw_interface_set_vpath_reply) \ +_(SW_INTERFACE_SET_VXLAN_BYPASS_REPLY, sw_interface_set_vxlan_bypass_reply) \ +_(SW_INTERFACE_SET_L2_XCONNECT_REPLY, \ + sw_interface_set_l2_xconnect_reply) \ +_(SW_INTERFACE_SET_L2_BRIDGE_REPLY, \ + sw_interface_set_l2_bridge_reply) \ +_(SW_INTERFACE_SET_DPDK_HQOS_PIPE_REPLY, \ + sw_interface_set_dpdk_hqos_pipe_reply) \ +_(SW_INTERFACE_SET_DPDK_HQOS_SUBPORT_REPLY, \ + sw_interface_set_dpdk_hqos_subport_reply) \ +_(SW_INTERFACE_SET_DPDK_HQOS_TCTBL_REPLY, \ + sw_interface_set_dpdk_hqos_tctbl_reply) \ +_(BRIDGE_DOMAIN_ADD_DEL_REPLY, bridge_domain_add_del_reply) \ +_(BRIDGE_DOMAIN_DETAILS, bridge_domain_details) \ +_(BRIDGE_DOMAIN_SW_IF_DETAILS, bridge_domain_sw_if_details) \ +_(L2FIB_ADD_DEL_REPLY, l2fib_add_del_reply) \ +_(L2_FLAGS_REPLY, l2_flags_reply) \ +_(BRIDGE_FLAGS_REPLY, bridge_flags_reply) \ +_(TAP_CONNECT_REPLY, tap_connect_reply) \ +_(TAP_MODIFY_REPLY, tap_modify_reply) \ +_(TAP_DELETE_REPLY, tap_delete_reply) \ +_(SW_INTERFACE_TAP_DETAILS, sw_interface_tap_details) \ +_(IP_ADD_DEL_ROUTE_REPLY, ip_add_del_route_reply) \ +_(MPLS_ROUTE_ADD_DEL_REPLY, mpls_route_add_del_reply) \ +_(MPLS_IP_BIND_UNBIND_REPLY, mpls_ip_bind_unbind_reply) \ +_(PROXY_ARP_ADD_DEL_REPLY, proxy_arp_add_del_reply) \ +_(PROXY_ARP_INTFC_ENABLE_DISABLE_REPLY, \ + proxy_arp_intfc_enable_disable_reply) \ +_(MPLS_TUNNEL_ADD_DEL_REPLY, mpls_tunnel_add_del_reply) \ +_(SW_INTERFACE_SET_UNNUMBERED_REPLY, \ + sw_interface_set_unnumbered_reply) \ +_(IP_NEIGHBOR_ADD_DEL_REPLY, ip_neighbor_add_del_reply) \ +_(RESET_VRF_REPLY, reset_vrf_reply) \ +_(CREATE_VLAN_SUBIF_REPLY, create_vlan_subif_reply) \ +_(CREATE_SUBIF_REPLY, create_subif_reply) \ +_(OAM_ADD_DEL_REPLY, oam_add_del_reply) \ +_(RESET_FIB_REPLY, reset_fib_reply) \ +_(DHCP_PROXY_CONFIG_REPLY, dhcp_proxy_config_reply) \ +_(DHCP_PROXY_CONFIG_2_REPLY, dhcp_proxy_config_2_reply) \ +_(DHCP_PROXY_SET_VSS_REPLY, dhcp_proxy_set_vss_reply) \ +_(DHCP_CLIENT_CONFIG_REPLY, dhcp_client_config_reply) \ +_(SET_IP_FLOW_HASH_REPLY, set_ip_flow_hash_reply) \ +_(SW_INTERFACE_IP6_ENABLE_DISABLE_REPLY, \ + sw_interface_ip6_enable_disable_reply) \ +_(SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS_REPLY, \ + sw_interface_ip6_set_link_local_address_reply) \ +_(SW_INTERFACE_IP6ND_RA_PREFIX_REPLY, \ + sw_interface_ip6nd_ra_prefix_reply) \ +_(SW_INTERFACE_IP6ND_RA_CONFIG_REPLY, \ + sw_interface_ip6nd_ra_config_reply) \ +_(SET_ARP_NEIGHBOR_LIMIT_REPLY, set_arp_neighbor_limit_reply) \ +_(L2_PATCH_ADD_DEL_REPLY, l2_patch_add_del_reply) \ +_(SR_TUNNEL_ADD_DEL_REPLY, sr_tunnel_add_del_reply) \ +_(SR_POLICY_ADD_DEL_REPLY, sr_policy_add_del_reply) \ +_(SR_MULTICAST_MAP_ADD_DEL_REPLY, sr_multicast_map_add_del_reply) \ +_(CLASSIFY_ADD_DEL_TABLE_REPLY, classify_add_del_table_reply) \ +_(CLASSIFY_ADD_DEL_SESSION_REPLY, classify_add_del_session_reply) \ +_(CLASSIFY_SET_INTERFACE_IP_TABLE_REPLY, \ +classify_set_interface_ip_table_reply) \ +_(CLASSIFY_SET_INTERFACE_L2_TABLES_REPLY, \ + classify_set_interface_l2_tables_reply) \ +_(GET_NODE_INDEX_REPLY, get_node_index_reply) \ +_(ADD_NODE_NEXT_REPLY, add_node_next_reply) \ +_(L2TPV3_CREATE_TUNNEL_REPLY, l2tpv3_create_tunnel_reply) \ +_(L2TPV3_SET_TUNNEL_COOKIES_REPLY, l2tpv3_set_tunnel_cookies_reply) \ +_(L2TPV3_INTERFACE_ENABLE_DISABLE_REPLY, \ + l2tpv3_interface_enable_disable_reply) \ +_(L2TPV3_SET_LOOKUP_KEY_REPLY, l2tpv3_set_lookup_key_reply) \ +_(SW_IF_L2TPV3_TUNNEL_DETAILS, sw_if_l2tpv3_tunnel_details) \ +_(VXLAN_ADD_DEL_TUNNEL_REPLY, vxlan_add_del_tunnel_reply) \ +_(VXLAN_TUNNEL_DETAILS, vxlan_tunnel_details) \ +_(GRE_ADD_DEL_TUNNEL_REPLY, gre_add_del_tunnel_reply) \ +_(GRE_TUNNEL_DETAILS, gre_tunnel_details) \ +_(L2_FIB_CLEAR_TABLE_REPLY, l2_fib_clear_table_reply) \ +_(L2_INTERFACE_EFP_FILTER_REPLY, l2_interface_efp_filter_reply) \ +_(L2_INTERFACE_VLAN_TAG_REWRITE_REPLY, l2_interface_vlan_tag_rewrite_reply) \ +_(SW_INTERFACE_VHOST_USER_DETAILS, sw_interface_vhost_user_details) \ +_(CREATE_VHOST_USER_IF_REPLY, create_vhost_user_if_reply) \ +_(MODIFY_VHOST_USER_IF_REPLY, modify_vhost_user_if_reply) \ +_(DELETE_VHOST_USER_IF_REPLY, delete_vhost_user_if_reply) \ +_(SHOW_VERSION_REPLY, show_version_reply) \ +_(L2_FIB_TABLE_ENTRY, l2_fib_table_entry) \ +_(VXLAN_GPE_ADD_DEL_TUNNEL_REPLY, vxlan_gpe_add_del_tunnel_reply) \ +_(VXLAN_GPE_TUNNEL_DETAILS, vxlan_gpe_tunnel_details) \ +_(INTERFACE_NAME_RENUMBER_REPLY, interface_name_renumber_reply) \ +_(WANT_IP4_ARP_EVENTS_REPLY, want_ip4_arp_events_reply) \ +_(IP4_ARP_EVENT, ip4_arp_event) \ +_(WANT_IP6_ND_EVENTS_REPLY, want_ip6_nd_events_reply) \ +_(IP6_ND_EVENT, ip6_nd_event) \ +_(INPUT_ACL_SET_INTERFACE_REPLY, input_acl_set_interface_reply) \ +_(IP_ADDRESS_DETAILS, ip_address_details) \ +_(IP_DETAILS, ip_details) \ +_(IPSEC_SPD_ADD_DEL_REPLY, ipsec_spd_add_del_reply) \ +_(IPSEC_INTERFACE_ADD_DEL_SPD_REPLY, ipsec_interface_add_del_spd_reply) \ +_(IPSEC_SPD_ADD_DEL_ENTRY_REPLY, ipsec_spd_add_del_entry_reply) \ +_(IPSEC_SAD_ADD_DEL_ENTRY_REPLY, ipsec_sad_add_del_entry_reply) \ +_(IPSEC_SA_SET_KEY_REPLY, ipsec_sa_set_key_reply) \ +_(IKEV2_PROFILE_ADD_DEL_REPLY, ikev2_profile_add_del_reply) \ +_(IKEV2_PROFILE_SET_AUTH_REPLY, ikev2_profile_set_auth_reply) \ +_(IKEV2_PROFILE_SET_ID_REPLY, ikev2_profile_set_id_reply) \ +_(IKEV2_PROFILE_SET_TS_REPLY, ikev2_profile_set_ts_reply) \ +_(IKEV2_SET_LOCAL_KEY_REPLY, ikev2_set_local_key_reply) \ +_(DELETE_LOOPBACK_REPLY, delete_loopback_reply) \ +_(BD_IP_MAC_ADD_DEL_REPLY, bd_ip_mac_add_del_reply) \ +_(DHCP_COMPL_EVENT, dhcp_compl_event) \ +_(VNET_INTERFACE_COUNTERS, vnet_interface_counters) \ +_(VNET_IP4_FIB_COUNTERS, vnet_ip4_fib_counters) \ +_(VNET_IP6_FIB_COUNTERS, vnet_ip6_fib_counters) \ +_(MAP_ADD_DOMAIN_REPLY, map_add_domain_reply) \ +_(MAP_DEL_DOMAIN_REPLY, map_del_domain_reply) \ +_(MAP_ADD_DEL_RULE_REPLY, map_add_del_rule_reply) \ +_(MAP_DOMAIN_DETAILS, map_domain_details) \ +_(MAP_RULE_DETAILS, map_rule_details) \ +_(WANT_INTERFACE_EVENTS_REPLY, want_interface_events_reply) \ +_(WANT_STATS_REPLY, want_stats_reply) \ +_(GET_FIRST_MSG_ID_REPLY, get_first_msg_id_reply) \ +_(COP_INTERFACE_ENABLE_DISABLE_REPLY, cop_interface_enable_disable_reply) \ +_(COP_WHITELIST_ENABLE_DISABLE_REPLY, cop_whitelist_enable_disable_reply) \ +_(GET_NODE_GRAPH_REPLY, get_node_graph_reply) \ +_(SW_INTERFACE_CLEAR_STATS_REPLY, sw_interface_clear_stats_reply) \ +_(IOAM_ENABLE_REPLY, ioam_enable_reply) \ +_(IOAM_DISABLE_REPLY, ioam_disable_reply) \ +_(LISP_ADD_DEL_LOCATOR_SET_REPLY, lisp_add_del_locator_set_reply) \ +_(LISP_ADD_DEL_LOCATOR_REPLY, lisp_add_del_locator_reply) \ +_(LISP_ADD_DEL_LOCAL_EID_REPLY, lisp_add_del_local_eid_reply) \ +_(LISP_ADD_DEL_REMOTE_MAPPING_REPLY, lisp_add_del_remote_mapping_reply) \ +_(LISP_ADD_DEL_ADJACENCY_REPLY, lisp_add_del_adjacency_reply) \ +_(LISP_GPE_ADD_DEL_FWD_ENTRY_REPLY, lisp_gpe_add_del_fwd_entry_reply) \ +_(LISP_ADD_DEL_MAP_RESOLVER_REPLY, lisp_add_del_map_resolver_reply) \ +_(LISP_ADD_DEL_MAP_SERVER_REPLY, lisp_add_del_map_server_reply) \ +_(LISP_GPE_ENABLE_DISABLE_REPLY, lisp_gpe_enable_disable_reply) \ +_(LISP_ENABLE_DISABLE_REPLY, lisp_enable_disable_reply) \ +_(LISP_MAP_REGISTER_ENABLE_DISABLE_REPLY, \ + lisp_map_register_enable_disable_reply) \ +_(LISP_RLOC_PROBE_ENABLE_DISABLE_REPLY, \ + lisp_rloc_probe_enable_disable_reply) \ +_(LISP_PITR_SET_LOCATOR_SET_REPLY, lisp_pitr_set_locator_set_reply) \ +_(LISP_MAP_REQUEST_MODE_REPLY, lisp_map_request_mode_reply) \ +_(LISP_EID_TABLE_ADD_DEL_MAP_REPLY, lisp_eid_table_add_del_map_reply) \ +_(LISP_GPE_ADD_DEL_IFACE_REPLY, lisp_gpe_add_del_iface_reply) \ +_(LISP_LOCATOR_SET_DETAILS, lisp_locator_set_details) \ +_(LISP_LOCATOR_DETAILS, lisp_locator_details) \ +_(LISP_EID_TABLE_DETAILS, lisp_eid_table_details) \ +_(LISP_EID_TABLE_MAP_DETAILS, lisp_eid_table_map_details) \ +_(LISP_EID_TABLE_VNI_DETAILS, lisp_eid_table_vni_details) \ +_(LISP_GPE_TUNNEL_DETAILS, lisp_gpe_tunnel_details) \ +_(LISP_MAP_RESOLVER_DETAILS, lisp_map_resolver_details) \ +_(LISP_MAP_SERVER_DETAILS, lisp_map_server_details) \ +_(LISP_ADJACENCIES_GET_REPLY, lisp_adjacencies_get_reply) \ +_(SHOW_LISP_STATUS_REPLY, show_lisp_status_reply) \ +_(LISP_ADD_DEL_MAP_REQUEST_ITR_RLOCS_REPLY, \ + lisp_add_del_map_request_itr_rlocs_reply) \ +_(LISP_GET_MAP_REQUEST_ITR_RLOCS_REPLY, \ + lisp_get_map_request_itr_rlocs_reply) \ +_(SHOW_LISP_PITR_REPLY, show_lisp_pitr_reply) \ +_(SHOW_LISP_MAP_REQUEST_MODE_REPLY, show_lisp_map_request_mode_reply) \ +_(SHOW_LISP_RLOC_PROBE_STATE_REPLY, show_lisp_rloc_probe_state_reply) \ +_(SHOW_LISP_MAP_REGISTER_STATE_REPLY, \ + show_lisp_map_register_state_reply) \ +_(AF_PACKET_CREATE_REPLY, af_packet_create_reply) \ +_(AF_PACKET_DELETE_REPLY, af_packet_delete_reply) \ +_(POLICER_ADD_DEL_REPLY, policer_add_del_reply) \ +_(POLICER_DETAILS, policer_details) \ +_(POLICER_CLASSIFY_SET_INTERFACE_REPLY, policer_classify_set_interface_reply) \ +_(POLICER_CLASSIFY_DETAILS, policer_classify_details) \ +_(NETMAP_CREATE_REPLY, netmap_create_reply) \ +_(NETMAP_DELETE_REPLY, netmap_delete_reply) \ +_(MPLS_TUNNEL_DETAILS, mpls_tunnel_details) \ +_(MPLS_FIB_DETAILS, mpls_fib_details) \ +_(CLASSIFY_TABLE_IDS_REPLY, classify_table_ids_reply) \ +_(CLASSIFY_TABLE_BY_INTERFACE_REPLY, classify_table_by_interface_reply) \ +_(CLASSIFY_TABLE_INFO_REPLY, classify_table_info_reply) \ +_(CLASSIFY_SESSION_DETAILS, classify_session_details) \ +_(SET_IPFIX_EXPORTER_REPLY, set_ipfix_exporter_reply) \ +_(IPFIX_EXPORTER_DETAILS, ipfix_exporter_details) \ +_(SET_IPFIX_CLASSIFY_STREAM_REPLY, set_ipfix_classify_stream_reply) \ +_(IPFIX_CLASSIFY_STREAM_DETAILS, ipfix_classify_stream_details) \ +_(IPFIX_CLASSIFY_TABLE_ADD_DEL_REPLY, ipfix_classify_table_add_del_reply) \ +_(IPFIX_CLASSIFY_TABLE_DETAILS, ipfix_classify_table_details) \ +_(FLOW_CLASSIFY_SET_INTERFACE_REPLY, flow_classify_set_interface_reply) \ +_(FLOW_CLASSIFY_DETAILS, flow_classify_details) \ +_(SW_INTERFACE_SPAN_ENABLE_DISABLE_REPLY, sw_interface_span_enable_disable_reply) \ +_(SW_INTERFACE_SPAN_DETAILS, sw_interface_span_details) \ +_(GET_NEXT_INDEX_REPLY, get_next_index_reply) \ +_(PG_CREATE_INTERFACE_REPLY, pg_create_interface_reply) \ +_(PG_CAPTURE_REPLY, pg_capture_reply) \ +_(PG_ENABLE_DISABLE_REPLY, pg_enable_disable_reply) \ +_(IP_SOURCE_AND_PORT_RANGE_CHECK_ADD_DEL_REPLY, \ + ip_source_and_port_range_check_add_del_reply) \ +_(IP_SOURCE_AND_PORT_RANGE_CHECK_INTERFACE_ADD_DEL_REPLY, \ + ip_source_and_port_range_check_interface_add_del_reply) \ +_(IPSEC_GRE_ADD_DEL_TUNNEL_REPLY, ipsec_gre_add_del_tunnel_reply) \ +_(IPSEC_GRE_TUNNEL_DETAILS, ipsec_gre_tunnel_details) \ +_(DELETE_SUBIF_REPLY, delete_subif_reply) \ +_(L2_INTERFACE_PBB_TAG_REWRITE_REPLY, l2_interface_pbb_tag_rewrite_reply) \ +_(PUNT_REPLY, punt_reply) \ +_(IP_FIB_DETAILS, ip_fib_details) \ +_(IP6_FIB_DETAILS, ip6_fib_details) \ +_(FEATURE_ENABLE_DISABLE_REPLY, feature_enable_disable_reply) \ +_(SW_INTERFACE_TAG_ADD_DEL_REPLY, sw_interface_tag_add_del_reply) \ +_(L2_XCONNECT_DETAILS, l2_xconnect_details) \ +_(SW_INTERFACE_SET_MTU_REPLY, sw_interface_set_mtu_reply) \ +_(IP_NEIGHBOR_DETAILS, ip_neighbor_details) \ +_(SW_INTERFACE_GET_TABLE_REPLY, sw_interface_get_table_reply) + +/* M: construct, but don't yet send a message */ + +#define M(T,t) \ +do { \ + vam->result_ready = 0; \ + mp = vl_msg_api_alloc_as_if_client(sizeof(*mp)); \ + memset (mp, 0, sizeof (*mp)); \ + mp->_vl_msg_id = ntohs (VL_API_##T); \ + mp->client_index = vam->my_client_index; \ +} while(0); + +#define M2(T,t,n) \ +do { \ + vam->result_ready = 0; \ + mp = vl_msg_api_alloc_as_if_client(sizeof(*mp)+(n)); \ + memset (mp, 0, sizeof (*mp)); \ + mp->_vl_msg_id = ntohs (VL_API_##T); \ + 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); \ + } \ + vat_suspend (vam->vlib_main, 1e-3); \ + } \ + return -99; \ +} while(0); + +/* W2: wait for results, with timeout */ +#define W2(body) \ +do { \ + timeout = vat_time_now (vam) + 1.0; \ + \ + while (vat_time_now (vam) < timeout) { \ + if (vam->result_ready == 1) { \ + (body); \ + return (vam->retval); \ + } \ + vat_suspend (vam->vlib_main, 1e-3); \ + } \ + return -99; \ +} while(0); + +typedef struct +{ + u8 *name; + u32 value; +} name_sort_t; + + +#define STR_VTR_OP_CASE(op) \ + case L2_VTR_ ## op: \ + return "" # op; + +static const char * +str_vtr_op (u32 vtr_op) +{ + switch (vtr_op) + { + STR_VTR_OP_CASE (DISABLED); + STR_VTR_OP_CASE (PUSH_1); + STR_VTR_OP_CASE (PUSH_2); + STR_VTR_OP_CASE (POP_1); + STR_VTR_OP_CASE (POP_2); + STR_VTR_OP_CASE (TRANSLATE_1_1); + STR_VTR_OP_CASE (TRANSLATE_1_2); + STR_VTR_OP_CASE (TRANSLATE_2_1); + STR_VTR_OP_CASE (TRANSLATE_2_2); + } + + return "UNKNOWN"; +} + +static int +dump_sub_interface_table (vat_main_t * vam) +{ + const sw_interface_subif_t *sub = NULL; + + if (vam->json_output) + { + clib_warning + ("JSON output supported only for VPE API calls and dump_stats_table"); + return -99; + } + + print (vam->ofp, + "%-30s%-12s%-11s%-7s%-5s%-9s%-9s%-6s%-8s%-10s%-10s", + "Interface", "sw_if_index", + "sub id", "dot1ad", "tags", "outer id", + "inner id", "exact", "default", "outer any", "inner any"); + + vec_foreach (sub, vam->sw_if_subif_table) + { + print (vam->ofp, + "%-30s%-12d%-11d%-7s%-5d%-9d%-9d%-6d%-8d%-10d%-10d", + sub->interface_name, + sub->sw_if_index, + sub->sub_id, sub->sub_dot1ad ? "dot1ad" : "dot1q", + sub->sub_number_of_tags, sub->sub_outer_vlan_id, + sub->sub_inner_vlan_id, sub->sub_exact_match, sub->sub_default, + sub->sub_outer_vlan_id_any, sub->sub_inner_vlan_id_any); + if (sub->vtr_op != L2_VTR_DISABLED) + { + print (vam->ofp, + " vlan-tag-rewrite - op: %-14s [ dot1q: %d " + "tag1: %d tag2: %d ]", + str_vtr_op (sub->vtr_op), sub->vtr_push_dot1q, + sub->vtr_tag1, sub->vtr_tag2); + } + } + + return 0; +} + +static int +name_sort_cmp (void *a1, void *a2) +{ + name_sort_t *n1 = a1; + name_sort_t *n2 = a2; + + return strcmp ((char *) n1->name, (char *) n2->name); +} + +static int +dump_interface_table (vat_main_t * vam) +{ + hash_pair_t *p; + name_sort_t *nses = 0, *ns; + + if (vam->json_output) + { + clib_warning + ("JSON output supported only for VPE API calls and dump_stats_table"); + return -99; + } + + /* *INDENT-OFF* */ + hash_foreach_pair (p, vam->sw_if_index_by_interface_name, + ({ + vec_add2 (nses, ns, 1); + ns->name = (u8 *)(p->key); + ns->value = (u32) p->value[0]; + })); + /* *INDENT-ON* */ + + vec_sort_with_function (nses, name_sort_cmp); + + print (vam->ofp, "%-25s%-15s", "Interface", "sw_if_index"); + vec_foreach (ns, nses) + { + print (vam->ofp, "%-25s%-15d", ns->name, ns->value); + } + vec_free (nses); + return 0; +} + +static int +dump_ip_table (vat_main_t * vam, int is_ipv6) +{ + const ip_details_t *det = NULL; + const ip_address_details_t *address = NULL; + u32 i = ~0; + + print (vam->ofp, "%-12s", "sw_if_index"); + + vec_foreach (det, vam->ip_details_by_sw_if_index[is_ipv6]) + { + i++; + if (!det->present) + { + continue; + } + print (vam->ofp, "%-12d", i); + print (vam->ofp, " %-30s%-13s", "Address", "Prefix length"); + if (!det->addr) + { + continue; + } + vec_foreach (address, det->addr) + { + print (vam->ofp, + " %-30U%-13d", + is_ipv6 ? format_ip6_address : format_ip4_address, + address->ip, address->prefix_length); + } + } + + return 0; +} + +static int +dump_ipv4_table (vat_main_t * vam) +{ + if (vam->json_output) + { + clib_warning + ("JSON output supported only for VPE API calls and dump_stats_table"); + return -99; + } + + return dump_ip_table (vam, 0); +} + +static int +dump_ipv6_table (vat_main_t * vam) +{ + if (vam->json_output) + { + clib_warning + ("JSON output supported only for VPE API calls and dump_stats_table"); + return -99; + } + + return dump_ip_table (vam, 1); +} + +static char * +counter_type_to_str (u8 counter_type, u8 is_combined) +{ + if (!is_combined) + { + switch (counter_type) + { + case VNET_INTERFACE_COUNTER_DROP: + return "drop"; + case VNET_INTERFACE_COUNTER_PUNT: + return "punt"; + case VNET_INTERFACE_COUNTER_IP4: + return "ip4"; + case VNET_INTERFACE_COUNTER_IP6: + return "ip6"; + case VNET_INTERFACE_COUNTER_RX_NO_BUF: + return "rx-no-buf"; + case VNET_INTERFACE_COUNTER_RX_MISS: + return "rx-miss"; + case VNET_INTERFACE_COUNTER_RX_ERROR: + return "rx-error"; + case VNET_INTERFACE_COUNTER_TX_ERROR: + return "tx-error"; + default: + return "INVALID-COUNTER-TYPE"; + } + } + else + { + switch (counter_type) + { + case VNET_INTERFACE_COUNTER_RX: + return "rx"; + case VNET_INTERFACE_COUNTER_TX: + return "tx"; + default: + return "INVALID-COUNTER-TYPE"; + } + } +} + +static int +dump_stats_table (vat_main_t * vam) +{ + vat_json_node_t node; + vat_json_node_t *msg_array; + vat_json_node_t *msg; + vat_json_node_t *counter_array; + vat_json_node_t *counter; + interface_counter_t c; + u64 packets; + ip4_fib_counter_t *c4; + ip6_fib_counter_t *c6; + int i, j; + + if (!vam->json_output) + { + clib_warning ("dump_stats_table supported only in JSON format"); + return -99; + } + + vat_json_init_object (&node); + + /* interface counters */ + msg_array = vat_json_object_add (&node, "interface_counters"); + vat_json_init_array (msg_array); + for (i = 0; i < vec_len (vam->simple_interface_counters); i++) + { + msg = vat_json_array_add (msg_array); + vat_json_init_object (msg); + vat_json_object_add_string_copy (msg, "vnet_counter_type", + (u8 *) counter_type_to_str (i, 0)); + vat_json_object_add_int (msg, "is_combined", 0); + counter_array = vat_json_object_add (msg, "data"); + vat_json_init_array (counter_array); + for (j = 0; j < vec_len (vam->simple_interface_counters[i]); j++) + { + packets = vam->simple_interface_counters[i][j]; + vat_json_array_add_uint (counter_array, packets); + } + } + for (i = 0; i < vec_len (vam->combined_interface_counters); i++) + { + msg = vat_json_array_add (msg_array); + vat_json_init_object (msg); + vat_json_object_add_string_copy (msg, "vnet_counter_type", + (u8 *) counter_type_to_str (i, 1)); + vat_json_object_add_int (msg, "is_combined", 1); + counter_array = vat_json_object_add (msg, "data"); + vat_json_init_array (counter_array); + for (j = 0; j < vec_len (vam->combined_interface_counters[i]); j++) + { + c = vam->combined_interface_counters[i][j]; + counter = vat_json_array_add (counter_array); + vat_json_init_object (counter); + vat_json_object_add_uint (counter, "packets", c.packets); + vat_json_object_add_uint (counter, "bytes", c.bytes); + } + } + + /* ip4 fib counters */ + msg_array = vat_json_object_add (&node, "ip4_fib_counters"); + vat_json_init_array (msg_array); + for (i = 0; i < vec_len (vam->ip4_fib_counters); i++) + { + msg = vat_json_array_add (msg_array); + vat_json_init_object (msg); + vat_json_object_add_uint (msg, "vrf_id", + vam->ip4_fib_counters_vrf_id_by_index[i]); + counter_array = vat_json_object_add (msg, "c"); + vat_json_init_array (counter_array); + for (j = 0; j < vec_len (vam->ip4_fib_counters[i]); j++) + { + counter = vat_json_array_add (counter_array); + vat_json_init_object (counter); + c4 = &vam->ip4_fib_counters[i][j]; + vat_json_object_add_ip4 (counter, "address", c4->address); + vat_json_object_add_uint (counter, "address_length", + c4->address_length); + vat_json_object_add_uint (counter, "packets", c4->packets); + vat_json_object_add_uint (counter, "bytes", c4->bytes); + } + } + + /* ip6 fib counters */ + msg_array = vat_json_object_add (&node, "ip6_fib_counters"); + vat_json_init_array (msg_array); + for (i = 0; i < vec_len (vam->ip6_fib_counters); i++) + { + msg = vat_json_array_add (msg_array); + vat_json_init_object (msg); + vat_json_object_add_uint (msg, "vrf_id", + vam->ip6_fib_counters_vrf_id_by_index[i]); + counter_array = vat_json_object_add (msg, "c"); + vat_json_init_array (counter_array); + for (j = 0; j < vec_len (vam->ip6_fib_counters[i]); j++) + { + counter = vat_json_array_add (counter_array); + vat_json_init_object (counter); + c6 = &vam->ip6_fib_counters[i][j]; + vat_json_object_add_ip6 (counter, "address", c6->address); + vat_json_object_add_uint (counter, "address_length", + c6->address_length); + vat_json_object_add_uint (counter, "packets", c6->packets); + vat_json_object_add_uint (counter, "bytes", c6->bytes); + } + } + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + return 0; +} + +int +exec (vat_main_t * vam) +{ + api_main_t *am = &api_main; + vl_api_cli_request_t *mp; + f64 timeout; + void *oldheap; + u8 *cmd = 0; + unformat_input_t *i = vam->input; + + if (vec_len (i->buffer) == 0) + return -1; + + if (vam->exec_mode == 0 && unformat (i, "mode")) + { + vam->exec_mode = 1; + return 0; + } + if (vam->exec_mode == 1 && (unformat (i, "exit") || unformat (i, "quit"))) + { + vam->exec_mode = 0; + return 0; + } + + + M (CLI_REQUEST, cli_request); + + /* + * Copy cmd into shared memory. + * In order for the CLI command to work, it + * must be a vector ending in \n, not a C-string ending + * in \n\0. + */ + pthread_mutex_lock (&am->vlib_rp->mutex); + oldheap = svm_push_data_heap (am->vlib_rp); + + vec_validate (cmd, vec_len (vam->input->buffer) - 1); + clib_memcpy (cmd, vam->input->buffer, vec_len (vam->input->buffer)); + + svm_pop_heap (oldheap); + pthread_mutex_unlock (&am->vlib_rp->mutex); + + mp->cmd_in_shmem = (u64) cmd; + S; + timeout = vat_time_now (vam) + 10.0; + + while (vat_time_now (vam) < timeout) + { + if (vam->result_ready == 1) + { + u8 *free_me; + if (vam->shmem_result != NULL) + print (vam->ofp, "%s", vam->shmem_result); + pthread_mutex_lock (&am->vlib_rp->mutex); + oldheap = svm_push_data_heap (am->vlib_rp); + + free_me = (u8 *) vam->shmem_result; + vec_free (free_me); + + svm_pop_heap (oldheap); + pthread_mutex_unlock (&am->vlib_rp->mutex); + return 0; + } + } + return -99; +} + +/* + * Future replacement of exec() that passes CLI buffers directly in + * the API messages instead of an additional shared memory area. + */ +static int +exec_inband (vat_main_t * vam) +{ + vl_api_cli_inband_t *mp; + f64 timeout; + unformat_input_t *i = vam->input; + + if (vec_len (i->buffer) == 0) + return -1; + + if (vam->exec_mode == 0 && unformat (i, "mode")) + { + vam->exec_mode = 1; + return 0; + } + if (vam->exec_mode == 1 && (unformat (i, "exit") || unformat (i, "quit"))) + { + vam->exec_mode = 0; + return 0; + } + + /* + * In order for the CLI command to work, it + * must be a vector ending in \n, not a C-string ending + * in \n\0. + */ + u32 len = vec_len (vam->input->buffer); + M2 (CLI_INBAND, cli_inband, len); + clib_memcpy (mp->cmd, vam->input->buffer, len); + mp->length = htonl (len); + + S; + W2 (print (vam->ofp, "%s", vam->cmd_reply)); +} + +static int +api_create_loopback (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_create_loopback_t *mp; + f64 timeout; + u8 mac_address[6]; + u8 mac_set = 0; + + memset (mac_address, 0, sizeof (mac_address)); + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "mac %U", unformat_ethernet_address, mac_address)) + mac_set = 1; + else + break; + } + + /* Construct the API message */ + M (CREATE_LOOPBACK, create_loopback); + if (mac_set) + clib_memcpy (mp->mac_address, mac_address, sizeof (mac_address)); + + S; + W; +} + +static int +api_delete_loopback (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_delete_loopback_t *mp; + f64 timeout; + u32 sw_if_index = ~0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("missing sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (DELETE_LOOPBACK, delete_loopback); + mp->sw_if_index = ntohl (sw_if_index); + + S; + W; +} + +static int +api_want_stats (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_want_stats_t *mp; + f64 timeout; + int enable = -1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "enable")) + enable = 1; + else if (unformat (i, "disable")) + enable = 0; + else + break; + } + + if (enable == -1) + { + errmsg ("missing enable|disable"); + return -99; + } + + M (WANT_STATS, want_stats); + mp->enable_disable = enable; + + S; + W; +} + +static int +api_want_interface_events (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_want_interface_events_t *mp; + f64 timeout; + int enable = -1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "enable")) + enable = 1; + else if (unformat (i, "disable")) + enable = 0; + else + break; + } + + if (enable == -1) + { + errmsg ("missing enable|disable"); + return -99; + } + + M (WANT_INTERFACE_EVENTS, want_interface_events); + mp->enable_disable = enable; + + vam->interface_event_display = enable; + + S; + W; +} + + +/* Note: non-static, called once to set up the initial intfc table */ +int +api_sw_interface_dump (vat_main_t * vam) +{ + vl_api_sw_interface_dump_t *mp; + f64 timeout; + hash_pair_t *p; + name_sort_t *nses = 0, *ns; + sw_interface_subif_t *sub = NULL; + + /* Toss the old name table */ + /* *INDENT-OFF* */ + hash_foreach_pair (p, vam->sw_if_index_by_interface_name, + ({ + vec_add2 (nses, ns, 1); + ns->name = (u8 *)(p->key); + ns->value = (u32) p->value[0]; + })); + /* *INDENT-ON* */ + + hash_free (vam->sw_if_index_by_interface_name); + + vec_foreach (ns, nses) vec_free (ns->name); + + vec_free (nses); + + vec_foreach (sub, vam->sw_if_subif_table) + { + vec_free (sub->interface_name); + } + vec_free (vam->sw_if_subif_table); + + /* recreate the interface name hash table */ + vam->sw_if_index_by_interface_name = hash_create_string (0, sizeof (uword)); + + /* Get list of ethernets */ + M (SW_INTERFACE_DUMP, sw_interface_dump); + mp->name_filter_valid = 1; + strncpy ((char *) mp->name_filter, "Ether", sizeof (mp->name_filter) - 1); + S; + + /* and local / loopback interfaces */ + M (SW_INTERFACE_DUMP, sw_interface_dump); + mp->name_filter_valid = 1; + strncpy ((char *) mp->name_filter, "lo", sizeof (mp->name_filter) - 1); + S; + + /* and packet-generator interfaces */ + M (SW_INTERFACE_DUMP, sw_interface_dump); + mp->name_filter_valid = 1; + strncpy ((char *) mp->name_filter, "pg", sizeof (mp->name_filter) - 1); + S; + + /* and vxlan-gpe tunnel interfaces */ + M (SW_INTERFACE_DUMP, sw_interface_dump); + mp->name_filter_valid = 1; + strncpy ((char *) mp->name_filter, "vxlan_gpe", + sizeof (mp->name_filter) - 1); + S; + + /* and vxlan tunnel interfaces */ + M (SW_INTERFACE_DUMP, sw_interface_dump); + mp->name_filter_valid = 1; + strncpy ((char *) mp->name_filter, "vxlan", sizeof (mp->name_filter) - 1); + S; + + /* and host (af_packet) interfaces */ + M (SW_INTERFACE_DUMP, sw_interface_dump); + mp->name_filter_valid = 1; + strncpy ((char *) mp->name_filter, "host", sizeof (mp->name_filter) - 1); + S; + + /* and l2tpv3 tunnel interfaces */ + M (SW_INTERFACE_DUMP, sw_interface_dump); + mp->name_filter_valid = 1; + strncpy ((char *) mp->name_filter, "l2tpv3_tunnel", + sizeof (mp->name_filter) - 1); + S; + + /* and GRE tunnel interfaces */ + M (SW_INTERFACE_DUMP, sw_interface_dump); + mp->name_filter_valid = 1; + strncpy ((char *) mp->name_filter, "gre", sizeof (mp->name_filter) - 1); + S; + + /* and LISP-GPE interfaces */ + M (SW_INTERFACE_DUMP, sw_interface_dump); + mp->name_filter_valid = 1; + strncpy ((char *) mp->name_filter, "lisp_gpe", + sizeof (mp->name_filter) - 1); + S; + + /* and IPSEC tunnel interfaces */ + M (SW_INTERFACE_DUMP, sw_interface_dump); + mp->name_filter_valid = 1; + strncpy ((char *) mp->name_filter, "ipsec", sizeof (mp->name_filter) - 1); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static int +api_sw_interface_set_flags (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_flags_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 admin_up = 0, link_up = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "admin-up")) + admin_up = 1; + else if (unformat (i, "admin-down")) + admin_up = 0; + else if (unformat (i, "link-up")) + link_up = 1; + else if (unformat (i, "link-down")) + link_up = 0; + else + if (unformat (i, "%U", api_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 + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (SW_INTERFACE_SET_FLAGS, sw_interface_set_flags); + mp->sw_if_index = ntohl (sw_if_index); + mp->admin_up_down = admin_up; + mp->link_up_down = link_up; + + /* send it... */ + S; + + /* Wait for a reply, return the good/bad news... */ + W; +} + +static int +api_sw_interface_clear_stats (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_clear_stats_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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 + break; + } + + /* Construct the API message */ + M (SW_INTERFACE_CLEAR_STATS, sw_interface_clear_stats); + + if (sw_if_index_set == 1) + mp->sw_if_index = ntohl (sw_if_index); + else + mp->sw_if_index = ~0; + + /* send it... */ + S; + + /* Wait for a reply, return the good/bad news... */ + W; +} + +static int +api_sw_interface_set_dpdk_hqos_pipe (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_dpdk_hqos_pipe_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u32 subport; + u8 subport_set = 0; + u32 pipe; + u8 pipe_set = 0; + u32 profile; + u8 profile_set = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "rx %U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %u", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "subport %u", &subport)) + subport_set = 1; + else + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "pipe %u", &pipe)) + pipe_set = 1; + else if (unformat (i, "profile %u", &profile)) + profile_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (subport_set == 0) + { + errmsg ("missing subport "); + return -99; + } + + if (pipe_set == 0) + { + errmsg ("missing pipe"); + return -99; + } + + if (profile_set == 0) + { + errmsg ("missing profile"); + return -99; + } + + M (SW_INTERFACE_SET_DPDK_HQOS_PIPE, sw_interface_set_dpdk_hqos_pipe); + + mp->sw_if_index = ntohl (sw_if_index); + mp->subport = ntohl (subport); + mp->pipe = ntohl (pipe); + mp->profile = ntohl (profile); + + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_sw_interface_set_dpdk_hqos_subport (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_dpdk_hqos_subport_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u32 subport; + u8 subport_set = 0; + u32 tb_rate = 1250000000; /* 10GbE */ + u32 tb_size = 1000000; + u32 tc_rate[] = { 1250000000, 1250000000, 1250000000, 1250000000 }; + u32 tc_period = 10; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "rx %U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %u", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "subport %u", &subport)) + subport_set = 1; + else + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "rate %u", &tb_rate)) + { + u32 tc_id; + + for (tc_id = 0; tc_id < (sizeof (tc_rate) / sizeof (tc_rate[0])); + tc_id++) + tc_rate[tc_id] = tb_rate; + } + else if (unformat (i, "bktsize %u", &tb_size)) + ; + else if (unformat (i, "tc0 %u", &tc_rate[0])) + ; + else if (unformat (i, "tc1 %u", &tc_rate[1])) + ; + else if (unformat (i, "tc2 %u", &tc_rate[2])) + ; + else if (unformat (i, "tc3 %u", &tc_rate[3])) + ; + else if (unformat (i, "period %u", &tc_period)) + ; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (subport_set == 0) + { + errmsg ("missing subport "); + return -99; + } + + M (SW_INTERFACE_SET_DPDK_HQOS_SUBPORT, sw_interface_set_dpdk_hqos_subport); + + mp->sw_if_index = ntohl (sw_if_index); + mp->subport = ntohl (subport); + mp->tb_rate = ntohl (tb_rate); + mp->tb_size = ntohl (tb_size); + mp->tc_rate[0] = ntohl (tc_rate[0]); + mp->tc_rate[1] = ntohl (tc_rate[1]); + mp->tc_rate[2] = ntohl (tc_rate[2]); + mp->tc_rate[3] = ntohl (tc_rate[3]); + mp->tc_period = ntohl (tc_period); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_sw_interface_set_dpdk_hqos_tctbl (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_dpdk_hqos_tctbl_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 entry_set = 0; + u8 tc_set = 0; + u8 queue_set = 0; + u32 entry, tc, queue; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "rx %U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %u", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "entry %d", &entry)) + entry_set = 1; + else if (unformat (i, "tc %d", &tc)) + tc_set = 1; + else if (unformat (i, "queue %d", &queue)) + queue_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (entry_set == 0) + { + errmsg ("missing entry "); + return -99; + } + + if (tc_set == 0) + { + errmsg ("missing traffic class "); + return -99; + } + + if (queue_set == 0) + { + errmsg ("missing queue "); + return -99; + } + + M (SW_INTERFACE_SET_DPDK_HQOS_TCTBL, sw_interface_set_dpdk_hqos_tctbl); + + mp->sw_if_index = ntohl (sw_if_index); + mp->entry = ntohl (entry); + mp->tc = ntohl (tc); + mp->queue = ntohl (queue); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_sw_interface_add_del_address (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_add_del_address_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 is_add = 1, del_all = 0; + u32 address_length = 0; + u8 v4_address_set = 0; + u8 v6_address_set = 0; + ip4_address_t v4address; + ip6_address_t v6address; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del-all")) + del_all = 1; + else if (unformat (i, "del")) + is_add = 0; + else + if (unformat (i, "%U", api_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, "%U/%d", + unformat_ip4_address, &v4address, &address_length)) + v4_address_set = 1; + else if (unformat (i, "%U/%d", + unformat_ip6_address, &v6address, &address_length)) + v6_address_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + if (v4_address_set && v6_address_set) + { + errmsg ("both v4 and v6 addresses set"); + return -99; + } + if (!v4_address_set && !v6_address_set && !del_all) + { + errmsg ("no addresses set"); + return -99; + } + + /* Construct the API message */ + M (SW_INTERFACE_ADD_DEL_ADDRESS, sw_interface_add_del_address); + + mp->sw_if_index = ntohl (sw_if_index); + mp->is_add = is_add; + mp->del_all = del_all; + if (v6_address_set) + { + mp->is_ipv6 = 1; + clib_memcpy (mp->address, &v6address, sizeof (v6address)); + } + else + { + clib_memcpy (mp->address, &v4address, sizeof (v4address)); + } + mp->address_length = address_length; + + /* send it... */ + S; + + /* Wait for a reply, return good/bad news */ + W; +} + +static int +api_sw_interface_set_mpls_enable (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_mpls_enable_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 enable = 1; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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, "disable")) + enable = 0; + else if (unformat (i, "dis")) + enable = 0; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (SW_INTERFACE_SET_MPLS_ENABLE, sw_interface_set_mpls_enable); + + mp->sw_if_index = ntohl (sw_if_index); + mp->enable = enable; + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int +api_sw_interface_set_table (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_table_t *mp; + f64 timeout; + u32 sw_if_index, vrf_id = 0; + u8 sw_if_index_set = 0; + u8 is_ipv6 = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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, "vrf %d", &vrf_id)) + ; + else if (unformat (i, "ipv6")) + is_ipv6 = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (SW_INTERFACE_SET_TABLE, sw_interface_set_table); + + mp->sw_if_index = ntohl (sw_if_index); + mp->is_ipv6 = is_ipv6; + mp->vrf_id = ntohl (vrf_id); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static void vl_api_sw_interface_get_table_reply_t_handler + (vl_api_sw_interface_get_table_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%d", ntohl (mp->vrf_id)); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; + +} + +static void vl_api_sw_interface_get_table_reply_t_handler_json + (vl_api_sw_interface_get_table_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_int (&node, "vrf_id", ntohl (mp->vrf_id)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static int +api_sw_interface_get_table (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_get_table_t *mp; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 is_ipv6 = 0; + f64 timeout; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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, "ipv6")) + is_ipv6 = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (SW_INTERFACE_GET_TABLE, sw_interface_get_table); + mp->sw_if_index = htonl (sw_if_index); + mp->is_ipv6 = is_ipv6; + + S; + W; +} + +static int +api_sw_interface_set_vpath (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_vpath_t *mp; + f64 timeout; + u32 sw_if_index = 0; + u8 sw_if_index_set = 0; + u8 is_enable = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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, "enable")) + is_enable = 1; + else if (unformat (i, "disable")) + is_enable = 0; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (SW_INTERFACE_SET_VPATH, sw_interface_set_vpath); + + mp->sw_if_index = ntohl (sw_if_index); + mp->enable = is_enable; + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int +api_sw_interface_set_vxlan_bypass (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_vxlan_bypass_t *mp; + f64 timeout; + u32 sw_if_index = 0; + u8 sw_if_index_set = 0; + u8 is_enable = 0; + u8 is_ipv6 = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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, "enable")) + is_enable = 1; + else if (unformat (i, "disable")) + is_enable = 0; + else if (unformat (i, "ip4")) + is_ipv6 = 0; + else if (unformat (i, "ip6")) + is_ipv6 = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (SW_INTERFACE_SET_VXLAN_BYPASS, sw_interface_set_vxlan_bypass); + + mp->sw_if_index = ntohl (sw_if_index); + mp->enable = is_enable; + mp->is_ipv6 = is_ipv6; + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int +api_sw_interface_set_l2_xconnect (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_l2_xconnect_t *mp; + f64 timeout; + u32 rx_sw_if_index; + u8 rx_sw_if_index_set = 0; + u32 tx_sw_if_index; + u8 tx_sw_if_index_set = 0; + u8 enable = 1; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "rx_sw_if_index %d", &rx_sw_if_index)) + rx_sw_if_index_set = 1; + else if (unformat (i, "tx_sw_if_index %d", &tx_sw_if_index)) + tx_sw_if_index_set = 1; + else if (unformat (i, "rx")) + { + if (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, + &rx_sw_if_index)) + rx_sw_if_index_set = 1; + } + else + break; + } + else if (unformat (i, "tx")) + { + if (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, + &tx_sw_if_index)) + tx_sw_if_index_set = 1; + } + else + break; + } + else if (unformat (i, "enable")) + enable = 1; + else if (unformat (i, "disable")) + enable = 0; + else + break; + } + + if (rx_sw_if_index_set == 0) + { + errmsg ("missing rx interface name or rx_sw_if_index"); + return -99; + } + + if (enable && (tx_sw_if_index_set == 0)) + { + errmsg ("missing tx interface name or tx_sw_if_index"); + return -99; + } + + M (SW_INTERFACE_SET_L2_XCONNECT, sw_interface_set_l2_xconnect); + + mp->rx_sw_if_index = ntohl (rx_sw_if_index); + mp->tx_sw_if_index = ntohl (tx_sw_if_index); + mp->enable = enable; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_sw_interface_set_l2_bridge (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_l2_bridge_t *mp; + f64 timeout; + u32 rx_sw_if_index; + u8 rx_sw_if_index_set = 0; + u32 bd_id; + u8 bd_id_set = 0; + u8 bvi = 0; + u32 shg = 0; + u8 enable = 1; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sw_if_index %d", &rx_sw_if_index)) + rx_sw_if_index_set = 1; + else if (unformat (i, "bd_id %d", &bd_id)) + bd_id_set = 1; + else + if (unformat + (i, "%U", api_unformat_sw_if_index, vam, &rx_sw_if_index)) + rx_sw_if_index_set = 1; + else if (unformat (i, "shg %d", &shg)) + ; + else if (unformat (i, "bvi")) + bvi = 1; + else if (unformat (i, "enable")) + enable = 1; + else if (unformat (i, "disable")) + enable = 0; + else + break; + } + + if (rx_sw_if_index_set == 0) + { + errmsg ("missing rx interface name or sw_if_index"); + return -99; + } + + if (enable && (bd_id_set == 0)) + { + errmsg ("missing bridge domain"); + return -99; + } + + M (SW_INTERFACE_SET_L2_BRIDGE, sw_interface_set_l2_bridge); + + mp->rx_sw_if_index = ntohl (rx_sw_if_index); + mp->bd_id = ntohl (bd_id); + mp->shg = (u8) shg; + mp->bvi = bvi; + mp->enable = enable; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_bridge_domain_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_bridge_domain_dump_t *mp; + f64 timeout; + u32 bd_id = ~0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "bd_id %d", &bd_id)) + ; + else + break; + } + + M (BRIDGE_DOMAIN_DUMP, bridge_domain_dump); + mp->bd_id = ntohl (bd_id); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + + W; + /* NOTREACHED */ + return 0; +} + +static int +api_bridge_domain_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_bridge_domain_add_del_t *mp; + f64 timeout; + u32 bd_id = ~0; + u8 is_add = 1; + u32 flood = 1, forward = 1, learn = 1, uu_flood = 1, arp_term = 0; + u32 mac_age = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "bd_id %d", &bd_id)) + ; + else if (unformat (i, "flood %d", &flood)) + ; + else if (unformat (i, "uu-flood %d", &uu_flood)) + ; + else if (unformat (i, "forward %d", &forward)) + ; + else if (unformat (i, "learn %d", &learn)) + ; + else if (unformat (i, "arp-term %d", &arp_term)) + ; + else if (unformat (i, "mac-age %d", &mac_age)) + ; + else if (unformat (i, "del")) + { + is_add = 0; + flood = uu_flood = forward = learn = 0; + } + else + break; + } + + if (bd_id == ~0) + { + errmsg ("missing bridge domain"); + return -99; + } + + if (mac_age > 255) + { + errmsg ("mac age must be less than 256 "); + return -99; + } + + M (BRIDGE_DOMAIN_ADD_DEL, bridge_domain_add_del); + + mp->bd_id = ntohl (bd_id); + mp->flood = flood; + mp->uu_flood = uu_flood; + mp->forward = forward; + mp->learn = learn; + mp->arp_term = arp_term; + mp->is_add = is_add; + mp->mac_age = (u8) mac_age; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_l2fib_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_l2fib_add_del_t *mp; + f64 timeout; + u64 mac = 0; + u8 mac_set = 0; + u32 bd_id; + u8 bd_id_set = 0; + u32 sw_if_index = ~0; + u8 sw_if_index_set = 0; + u8 is_add = 1; + u8 static_mac = 0; + u8 filter_mac = 0; + u8 bvi_mac = 0; + int count = 1; + f64 before = 0; + int j; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "mac %U", unformat_ethernet_address, &mac)) + mac_set = 1; + else if (unformat (i, "bd_id %d", &bd_id)) + bd_id_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if")) + { + if (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat + (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + } + else + break; + } + else if (unformat (i, "static")) + static_mac = 1; + else if (unformat (i, "filter")) + { + filter_mac = 1; + static_mac = 1; + } + else if (unformat (i, "bvi")) + { + bvi_mac = 1; + static_mac = 1; + } + else if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "count %d", &count)) + ; + else + break; + } + + if (mac_set == 0) + { + errmsg ("missing mac address"); + return -99; + } + + if (bd_id_set == 0) + { + errmsg ("missing bridge domain"); + return -99; + } + + if (is_add && sw_if_index_set == 0 && filter_mac == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (count > 1) + { + /* Turn on async mode */ + vam->async_mode = 1; + vam->async_errors = 0; + before = vat_time_now (vam); + } + + for (j = 0; j < count; j++) + { + M (L2FIB_ADD_DEL, l2fib_add_del); + + mp->mac = mac; + mp->bd_id = ntohl (bd_id); + mp->is_add = is_add; + + if (is_add) + { + mp->sw_if_index = ntohl (sw_if_index); + mp->static_mac = static_mac; + mp->filter_mac = filter_mac; + mp->bvi_mac = bvi_mac; + } + increment_mac_address (&mac); + /* send it... */ + S; + } + + if (count > 1) + { + vl_api_control_ping_t *mp; + f64 after; + + /* Shut off async mode */ + vam->async_mode = 0; + + M (CONTROL_PING, control_ping); + S; + + timeout = vat_time_now (vam) + 1.0; + while (vat_time_now (vam) < timeout) + if (vam->result_ready == 1) + goto out; + vam->retval = -99; + + out: + if (vam->retval == -99) + errmsg ("timeout"); + + if (vam->async_errors > 0) + { + errmsg ("%d asynchronous errors", vam->async_errors); + vam->retval = -98; + } + vam->async_errors = 0; + after = vat_time_now (vam); + + print (vam->ofp, "%d routes in %.6f secs, %.2f routes/sec", + count, after - before, count / (after - before)); + } + else + { + /* Wait for a reply... */ + W; + } + /* Return the good/bad news */ + return (vam->retval); +} + +static int +api_l2_flags (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_l2_flags_t *mp; + f64 timeout; + u32 sw_if_index; + u32 feature_bitmap = 0; + u8 sw_if_index_set = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if")) + { + if (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat + (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + } + else + break; + } + else if (unformat (i, "learn")) + feature_bitmap |= L2INPUT_FEAT_LEARN; + else if (unformat (i, "forward")) + feature_bitmap |= L2INPUT_FEAT_FWD; + else if (unformat (i, "flood")) + feature_bitmap |= L2INPUT_FEAT_FLOOD; + else if (unformat (i, "uu-flood")) + feature_bitmap |= L2INPUT_FEAT_UU_FLOOD; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (L2_FLAGS, l2_flags); + + mp->sw_if_index = ntohl (sw_if_index); + mp->feature_bitmap = ntohl (feature_bitmap); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_bridge_flags (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_bridge_flags_t *mp; + f64 timeout; + u32 bd_id; + u8 bd_id_set = 0; + u8 is_set = 1; + u32 flags = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "bd_id %d", &bd_id)) + bd_id_set = 1; + else if (unformat (i, "learn")) + flags |= L2_LEARN; + else if (unformat (i, "forward")) + flags |= L2_FWD; + else if (unformat (i, "flood")) + flags |= L2_FLOOD; + else if (unformat (i, "uu-flood")) + flags |= L2_UU_FLOOD; + else if (unformat (i, "arp-term")) + flags |= L2_ARP_TERM; + else if (unformat (i, "off")) + is_set = 0; + else if (unformat (i, "disable")) + is_set = 0; + else + break; + } + + if (bd_id_set == 0) + { + errmsg ("missing bridge domain"); + return -99; + } + + M (BRIDGE_FLAGS, bridge_flags); + + mp->bd_id = ntohl (bd_id); + mp->feature_bitmap = ntohl (flags); + mp->is_set = is_set; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_bd_ip_mac_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_bd_ip_mac_add_del_t *mp; + f64 timeout; + u32 bd_id; + u8 is_ipv6 = 0; + u8 is_add = 1; + u8 bd_id_set = 0; + u8 ip_set = 0; + u8 mac_set = 0; + ip4_address_t v4addr; + ip6_address_t v6addr; + u8 macaddr[6]; + + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "bd_id %d", &bd_id)) + { + bd_id_set++; + } + else if (unformat (i, "%U", unformat_ip4_address, &v4addr)) + { + ip_set++; + } + else if (unformat (i, "%U", unformat_ip6_address, &v6addr)) + { + ip_set++; + is_ipv6++; + } + else if (unformat (i, "%U", unformat_ethernet_address, macaddr)) + { + mac_set++; + } + else if (unformat (i, "del")) + is_add = 0; + else + break; + } + + if (bd_id_set == 0) + { + errmsg ("missing bridge domain"); + return -99; + } + else if (ip_set == 0) + { + errmsg ("missing IP address"); + return -99; + } + else if (mac_set == 0) + { + errmsg ("missing MAC address"); + return -99; + } + + M (BD_IP_MAC_ADD_DEL, bd_ip_mac_add_del); + + mp->bd_id = ntohl (bd_id); + mp->is_ipv6 = is_ipv6; + mp->is_add = is_add; + if (is_ipv6) + clib_memcpy (mp->ip_address, &v6addr, sizeof (v6addr)); + else + clib_memcpy (mp->ip_address, &v4addr, sizeof (v4addr)); + clib_memcpy (mp->mac_address, macaddr, 6); + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_tap_connect (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_tap_connect_t *mp; + f64 timeout; + u8 mac_address[6]; + u8 random_mac = 1; + u8 name_set = 0; + u8 *tap_name; + u8 *tag = 0; + + memset (mac_address, 0, sizeof (mac_address)); + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "mac %U", unformat_ethernet_address, mac_address)) + { + random_mac = 0; + } + else if (unformat (i, "random-mac")) + random_mac = 1; + else if (unformat (i, "tapname %s", &tap_name)) + name_set = 1; + else if (unformat (i, "tag %s", &tag)) + ; + else + break; + } + + if (name_set == 0) + { + errmsg ("missing tap name"); + return -99; + } + if (vec_len (tap_name) > 63) + { + errmsg ("tap name too long"); + return -99; + } + vec_add1 (tap_name, 0); + + if (vec_len (tag) > 63) + { + errmsg ("tag too long"); + return -99; + } + + /* Construct the API message */ + M (TAP_CONNECT, tap_connect); + + mp->use_random_mac = random_mac; + clib_memcpy (mp->mac_address, mac_address, 6); + clib_memcpy (mp->tap_name, tap_name, vec_len (tap_name)); + if (tag) + clib_memcpy (mp->tag, tag, vec_len (tag)); + + vec_free (tap_name); + vec_free (tag); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int +api_tap_modify (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_tap_modify_t *mp; + f64 timeout; + u8 mac_address[6]; + u8 random_mac = 1; + u8 name_set = 0; + u8 *tap_name; + u32 sw_if_index = ~0; + u8 sw_if_index_set = 0; + + memset (mac_address, 0, sizeof (mac_address)); + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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, "mac %U", unformat_ethernet_address, mac_address)) + { + random_mac = 0; + } + else if (unformat (i, "random-mac")) + random_mac = 1; + else if (unformat (i, "tapname %s", &tap_name)) + name_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing vpp interface name"); + return -99; + } + if (name_set == 0) + { + errmsg ("missing tap name"); + return -99; + } + if (vec_len (tap_name) > 63) + { + errmsg ("tap name too long"); + } + vec_add1 (tap_name, 0); + + /* Construct the API message */ + M (TAP_MODIFY, tap_modify); + + mp->use_random_mac = random_mac; + mp->sw_if_index = ntohl (sw_if_index); + clib_memcpy (mp->mac_address, mac_address, 6); + clib_memcpy (mp->tap_name, tap_name, vec_len (tap_name)); + vec_free (tap_name); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int +api_tap_delete (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_tap_delete_t *mp; + f64 timeout; + u32 sw_if_index = ~0; + u8 sw_if_index_set = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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 + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing vpp interface name"); + return -99; + } + + /* Construct the API message */ + M (TAP_DELETE, tap_delete); + + mp->sw_if_index = ntohl (sw_if_index); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int +api_ip_add_del_route (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ip_add_del_route_t *mp; + f64 timeout; + u32 sw_if_index = ~0, vrf_id = 0; + u8 is_ipv6 = 0; + u8 is_local = 0, is_drop = 0; + u8 is_unreach = 0, is_prohibit = 0; + u8 create_vrf_if_needed = 0; + u8 is_add = 1; + u32 next_hop_weight = 1; + u8 not_last = 0; + u8 is_multipath = 0; + u8 address_set = 0; + u8 address_length_set = 0; + u32 next_hop_table_id = 0; + u32 resolve_attempts = 0; + u32 dst_address_length = 0; + u8 next_hop_set = 0; + ip4_address_t v4_dst_address, v4_next_hop_address; + ip6_address_t v6_dst_address, v6_next_hop_address; + int count = 1; + int j; + f64 before = 0; + u32 random_add_del = 0; + u32 *random_vector = 0; + uword *random_hash; + u32 random_seed = 0xdeaddabe; + u32 classify_table_index = ~0; + u8 is_classify = 0; + u8 resolve_host = 0, resolve_attached = 0; + mpls_label_t *next_hop_out_label_stack = NULL; + mpls_label_t next_hop_out_label = MPLS_LABEL_INVALID; + mpls_label_t next_hop_via_label = MPLS_LABEL_INVALID; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (i, "%U", unformat_ip4_address, &v4_dst_address)) + { + address_set = 1; + is_ipv6 = 0; + } + else if (unformat (i, "%U", unformat_ip6_address, &v6_dst_address)) + { + address_set = 1; + is_ipv6 = 1; + } + else if (unformat (i, "/%d", &dst_address_length)) + { + address_length_set = 1; + } + + else if (is_ipv6 == 0 && unformat (i, "via %U", unformat_ip4_address, + &v4_next_hop_address)) + { + next_hop_set = 1; + } + else if (is_ipv6 == 1 && unformat (i, "via %U", unformat_ip6_address, + &v6_next_hop_address)) + { + next_hop_set = 1; + } + else if (unformat (i, "resolve-attempts %d", &resolve_attempts)) + ; + else if (unformat (i, "weight %d", &next_hop_weight)) + ; + else if (unformat (i, "drop")) + { + is_drop = 1; + } + else if (unformat (i, "null-send-unreach")) + { + is_unreach = 1; + } + else if (unformat (i, "null-send-prohibit")) + { + is_prohibit = 1; + } + else if (unformat (i, "local")) + { + is_local = 1; + } + else if (unformat (i, "classify %d", &classify_table_index)) + { + is_classify = 1; + } + else if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "add")) + is_add = 1; + else if (unformat (i, "not-last")) + not_last = 1; + else if (unformat (i, "resolve-via-host")) + resolve_host = 1; + else if (unformat (i, "resolve-via-attached")) + resolve_attached = 1; + else if (unformat (i, "multipath")) + is_multipath = 1; + else if (unformat (i, "vrf %d", &vrf_id)) + ; + else if (unformat (i, "create-vrf")) + create_vrf_if_needed = 1; + else if (unformat (i, "count %d", &count)) + ; + else if (unformat (i, "lookup-in-vrf %d", &next_hop_table_id)) + ; + else if (unformat (i, "next-hop-table %d", &next_hop_table_id)) + ; + else if (unformat (i, "out-label %d", &next_hop_out_label)) + vec_add1 (next_hop_out_label_stack, ntohl (next_hop_out_label)); + else if (unformat (i, "via-label %d", &next_hop_via_label)) + ; + else if (unformat (i, "random")) + random_add_del = 1; + else if (unformat (i, "seed %d", &random_seed)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!next_hop_set && !is_drop && !is_local && + !is_classify && !is_unreach && !is_prohibit && + MPLS_LABEL_INVALID == next_hop_via_label) + { + errmsg + ("next hop / local / drop / unreach / prohibit / classify not set"); + return -99; + } + + if (next_hop_set && MPLS_LABEL_INVALID != next_hop_via_label) + { + errmsg ("next hop and next-hop via label set"); + return -99; + } + if (address_set == 0) + { + errmsg ("missing addresses"); + return -99; + } + + if (address_length_set == 0) + { + errmsg ("missing address length"); + return -99; + } + + /* Generate a pile of unique, random routes */ + if (random_add_del) + { + u32 this_random_address; + random_hash = hash_create (count, sizeof (uword)); + + hash_set (random_hash, v4_next_hop_address.as_u32, 1); + for (j = 0; j <= count; j++) + { + do + { + this_random_address = random_u32 (&random_seed); + this_random_address = + clib_host_to_net_u32 (this_random_address); + } + while (hash_get (random_hash, this_random_address)); + vec_add1 (random_vector, this_random_address); + hash_set (random_hash, this_random_address, 1); + } + hash_free (random_hash); + v4_dst_address.as_u32 = random_vector[0]; + } + + if (count > 1) + { + /* Turn on async mode */ + vam->async_mode = 1; + vam->async_errors = 0; + before = vat_time_now (vam); + } + + for (j = 0; j < count; j++) + { + /* Construct the API message */ + M2 (IP_ADD_DEL_ROUTE, ip_add_del_route, + sizeof (mpls_label_t) * vec_len (next_hop_out_label_stack)); + + mp->next_hop_sw_if_index = ntohl (sw_if_index); + mp->table_id = ntohl (vrf_id); + mp->create_vrf_if_needed = create_vrf_if_needed; + + mp->is_add = is_add; + mp->is_drop = is_drop; + mp->is_unreach = is_unreach; + mp->is_prohibit = is_prohibit; + mp->is_ipv6 = is_ipv6; + mp->is_local = is_local; + mp->is_classify = is_classify; + mp->is_multipath = is_multipath; + mp->is_resolve_host = resolve_host; + mp->is_resolve_attached = resolve_attached; + mp->not_last = not_last; + mp->next_hop_weight = next_hop_weight; + mp->dst_address_length = dst_address_length; + mp->next_hop_table_id = ntohl (next_hop_table_id); + mp->classify_table_index = ntohl (classify_table_index); + mp->next_hop_via_label = ntohl (next_hop_via_label); + mp->next_hop_n_out_labels = vec_len (next_hop_out_label_stack); + if (0 != mp->next_hop_n_out_labels) + { + memcpy (mp->next_hop_out_label_stack, + next_hop_out_label_stack, + vec_len (next_hop_out_label_stack) * sizeof (mpls_label_t)); + vec_free (next_hop_out_label_stack); + } + + if (is_ipv6) + { + clib_memcpy (mp->dst_address, &v6_dst_address, + sizeof (v6_dst_address)); + if (next_hop_set) + clib_memcpy (mp->next_hop_address, &v6_next_hop_address, + sizeof (v6_next_hop_address)); + increment_v6_address (&v6_dst_address); + } + else + { + clib_memcpy (mp->dst_address, &v4_dst_address, + sizeof (v4_dst_address)); + if (next_hop_set) + clib_memcpy (mp->next_hop_address, &v4_next_hop_address, + sizeof (v4_next_hop_address)); + if (random_add_del) + v4_dst_address.as_u32 = random_vector[j + 1]; + else + increment_v4_address (&v4_dst_address); + } + /* send it... */ + S; + /* If we receive SIGTERM, stop now... */ + if (vam->do_exit) + break; + } + + /* When testing multiple add/del ops, use a control-ping to sync */ + if (count > 1) + { + vl_api_control_ping_t *mp; + f64 after; + + /* Shut off async mode */ + vam->async_mode = 0; + + M (CONTROL_PING, control_ping); + S; + + timeout = vat_time_now (vam) + 1.0; + while (vat_time_now (vam) < timeout) + if (vam->result_ready == 1) + goto out; + vam->retval = -99; + + out: + if (vam->retval == -99) + errmsg ("timeout"); + + if (vam->async_errors > 0) + { + errmsg ("%d asynchronous errors", vam->async_errors); + vam->retval = -98; + } + vam->async_errors = 0; + after = vat_time_now (vam); + + /* slim chance, but we might have eaten SIGTERM on the first iteration */ + if (j > 0) + count = j; + + print (vam->ofp, "%d routes in %.6f secs, %.2f routes/sec", + count, after - before, count / (after - before)); + } + else + { + /* Wait for a reply... */ + W; + } + + /* Return the good/bad news */ + return (vam->retval); +} + +static int +api_mpls_route_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_mpls_route_add_del_t *mp; + f64 timeout; + u32 sw_if_index = ~0, table_id = 0; + u8 create_table_if_needed = 0; + u8 is_add = 1; + u32 next_hop_weight = 1; + u8 is_multipath = 0; + u32 next_hop_table_id = 0; + u8 next_hop_set = 0; + ip4_address_t v4_next_hop_address = { + .as_u32 = 0, + }; + ip6_address_t v6_next_hop_address = { {0} }; + int count = 1; + int j; + f64 before = 0; + u32 classify_table_index = ~0; + u8 is_classify = 0; + u8 resolve_host = 0, resolve_attached = 0; + mpls_label_t next_hop_via_label = MPLS_LABEL_INVALID; + mpls_label_t next_hop_out_label = MPLS_LABEL_INVALID; + mpls_label_t *next_hop_out_label_stack = NULL; + mpls_label_t local_label = MPLS_LABEL_INVALID; + u8 is_eos = 0; + u8 next_hop_proto_is_ip4 = 1; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (i, "%d", &local_label)) + ; + else if (unformat (i, "eos")) + is_eos = 1; + else if (unformat (i, "non-eos")) + is_eos = 0; + else if (unformat (i, "via %U", unformat_ip4_address, + &v4_next_hop_address)) + { + next_hop_set = 1; + next_hop_proto_is_ip4 = 1; + } + else if (unformat (i, "via %U", unformat_ip6_address, + &v6_next_hop_address)) + { + next_hop_set = 1; + next_hop_proto_is_ip4 = 0; + } + else if (unformat (i, "weight %d", &next_hop_weight)) + ; + else if (unformat (i, "create-table")) + create_table_if_needed = 1; + else if (unformat (i, "classify %d", &classify_table_index)) + { + is_classify = 1; + } + else if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "add")) + is_add = 1; + else if (unformat (i, "resolve-via-host")) + resolve_host = 1; + else if (unformat (i, "resolve-via-attached")) + resolve_attached = 1; + else if (unformat (i, "multipath")) + is_multipath = 1; + else if (unformat (i, "count %d", &count)) + ; + else if (unformat (i, "lookup-in-ip4-table %d", &next_hop_table_id)) + { + next_hop_set = 1; + next_hop_proto_is_ip4 = 1; + } + else if (unformat (i, "lookup-in-ip6-table %d", &next_hop_table_id)) + { + next_hop_set = 1; + next_hop_proto_is_ip4 = 0; + } + else if (unformat (i, "next-hop-table %d", &next_hop_table_id)) + ; + else if (unformat (i, "via-label %d", &next_hop_via_label)) + ; + else if (unformat (i, "out-label %d", &next_hop_out_label)) + vec_add1 (next_hop_out_label_stack, ntohl (next_hop_out_label)); + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!next_hop_set && !is_classify) + { + errmsg ("next hop / classify not set"); + return -99; + } + + if (MPLS_LABEL_INVALID == local_label) + { + errmsg ("missing label"); + return -99; + } + + if (count > 1) + { + /* Turn on async mode */ + vam->async_mode = 1; + vam->async_errors = 0; + before = vat_time_now (vam); + } + + for (j = 0; j < count; j++) + { + /* Construct the API message */ + M2 (MPLS_ROUTE_ADD_DEL, mpls_route_add_del, + sizeof (mpls_label_t) * vec_len (next_hop_out_label_stack)); + + mp->mr_next_hop_sw_if_index = ntohl (sw_if_index); + mp->mr_table_id = ntohl (table_id); + mp->mr_create_table_if_needed = create_table_if_needed; + + mp->mr_is_add = is_add; + mp->mr_next_hop_proto_is_ip4 = next_hop_proto_is_ip4; + mp->mr_is_classify = is_classify; + mp->mr_is_multipath = is_multipath; + mp->mr_is_resolve_host = resolve_host; + mp->mr_is_resolve_attached = resolve_attached; + mp->mr_next_hop_weight = next_hop_weight; + mp->mr_next_hop_table_id = ntohl (next_hop_table_id); + mp->mr_classify_table_index = ntohl (classify_table_index); + mp->mr_next_hop_via_label = ntohl (next_hop_via_label); + mp->mr_label = ntohl (local_label); + mp->mr_eos = is_eos; + + mp->mr_next_hop_n_out_labels = vec_len (next_hop_out_label_stack); + if (0 != mp->mr_next_hop_n_out_labels) + { + memcpy (mp->mr_next_hop_out_label_stack, + next_hop_out_label_stack, + vec_len (next_hop_out_label_stack) * sizeof (mpls_label_t)); + vec_free (next_hop_out_label_stack); + } + + if (next_hop_set) + { + if (next_hop_proto_is_ip4) + { + clib_memcpy (mp->mr_next_hop, + &v4_next_hop_address, + sizeof (v4_next_hop_address)); + } + else + { + clib_memcpy (mp->mr_next_hop, + &v6_next_hop_address, + sizeof (v6_next_hop_address)); + } + } + local_label++; + + /* send it... */ + S; + /* If we receive SIGTERM, stop now... */ + if (vam->do_exit) + break; + } + + /* When testing multiple add/del ops, use a control-ping to sync */ + if (count > 1) + { + vl_api_control_ping_t *mp; + f64 after; + + /* Shut off async mode */ + vam->async_mode = 0; + + M (CONTROL_PING, control_ping); + S; + + timeout = vat_time_now (vam) + 1.0; + while (vat_time_now (vam) < timeout) + if (vam->result_ready == 1) + goto out; + vam->retval = -99; + + out: + if (vam->retval == -99) + errmsg ("timeout"); + + if (vam->async_errors > 0) + { + errmsg ("%d asynchronous errors", vam->async_errors); + vam->retval = -98; + } + vam->async_errors = 0; + after = vat_time_now (vam); + + /* slim chance, but we might have eaten SIGTERM on the first iteration */ + if (j > 0) + count = j; + + print (vam->ofp, "%d routes in %.6f secs, %.2f routes/sec", + count, after - before, count / (after - before)); + } + else + { + /* Wait for a reply... */ + W; + } + + /* Return the good/bad news */ + return (vam->retval); +} + +static int +api_mpls_ip_bind_unbind (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_mpls_ip_bind_unbind_t *mp; + f64 timeout; + u32 ip_table_id = 0; + u8 create_table_if_needed = 0; + u8 is_bind = 1; + u8 is_ip4 = 1; + ip4_address_t v4_address; + ip6_address_t v6_address; + u32 address_length; + u8 address_set = 0; + mpls_label_t local_label = MPLS_LABEL_INVALID; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U/%d", unformat_ip4_address, + &v4_address, &address_length)) + { + is_ip4 = 1; + address_set = 1; + } + else if (unformat (i, "%U/%d", unformat_ip6_address, + &v6_address, &address_length)) + { + is_ip4 = 0; + address_set = 1; + } + else if (unformat (i, "%d", &local_label)) + ; + else if (unformat (i, "create-table")) + create_table_if_needed = 1; + else if (unformat (i, "table-id %d", &ip_table_id)) + ; + else if (unformat (i, "unbind")) + is_bind = 0; + else if (unformat (i, "bind")) + is_bind = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!address_set) + { + errmsg ("IP addres not set"); + return -99; + } + + if (MPLS_LABEL_INVALID == local_label) + { + errmsg ("missing label"); + return -99; + } + + /* Construct the API message */ + M (MPLS_IP_BIND_UNBIND, mpls_ip_bind_unbind); + + mp->mb_create_table_if_needed = create_table_if_needed; + mp->mb_is_bind = is_bind; + mp->mb_is_ip4 = is_ip4; + mp->mb_ip_table_id = ntohl (ip_table_id); + mp->mb_mpls_table_id = 0; + mp->mb_label = ntohl (local_label); + mp->mb_address_length = address_length; + + if (is_ip4) + clib_memcpy (mp->mb_address, &v4_address, sizeof (v4_address)); + else + clib_memcpy (mp->mb_address, &v6_address, sizeof (v6_address)); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int +api_proxy_arp_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_proxy_arp_add_del_t *mp; + f64 timeout; + u32 vrf_id = 0; + u8 is_add = 1; + ip4_address_t lo, hi; + u8 range_set = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "vrf %d", &vrf_id)) + ; + else if (unformat (i, "%U - %U", unformat_ip4_address, &lo, + unformat_ip4_address, &hi)) + range_set = 1; + else if (unformat (i, "del")) + is_add = 0; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (range_set == 0) + { + errmsg ("address range not set"); + return -99; + } + + M (PROXY_ARP_ADD_DEL, proxy_arp_add_del); + + mp->vrf_id = ntohl (vrf_id); + mp->is_add = is_add; + clib_memcpy (mp->low_address, &lo, sizeof (mp->low_address)); + clib_memcpy (mp->hi_address, &hi, sizeof (mp->hi_address)); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_proxy_arp_intfc_enable_disable (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_proxy_arp_intfc_enable_disable_t *mp; + f64 timeout; + u32 sw_if_index; + u8 enable = 1; + u8 sw_if_index_set = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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, "enable")) + enable = 1; + else if (unformat (i, "disable")) + enable = 0; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (PROXY_ARP_INTFC_ENABLE_DISABLE, proxy_arp_intfc_enable_disable); + + mp->sw_if_index = ntohl (sw_if_index); + mp->enable_disable = enable; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_mpls_tunnel_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_mpls_tunnel_add_del_t *mp; + f64 timeout; + + u8 is_add = 1; + u8 l2_only = 0; + u32 sw_if_index = ~0; + u32 next_hop_sw_if_index = ~0; + u32 next_hop_proto_is_ip4 = 1; + + u32 next_hop_table_id = 0; + ip4_address_t v4_next_hop_address = { + .as_u32 = 0, + }; + ip6_address_t v6_next_hop_address = { {0} }; + mpls_label_t next_hop_out_label = MPLS_LABEL_INVALID, *labels = NULL; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "add")) + is_add = 1; + else if (unformat (i, "del sw_if_index %d", &sw_if_index)) + is_add = 0; + else if (unformat (i, "sw_if_index %d", &next_hop_sw_if_index)) + ; + else if (unformat (i, "via %U", + unformat_ip4_address, &v4_next_hop_address)) + { + next_hop_proto_is_ip4 = 1; + } + else if (unformat (i, "via %U", + unformat_ip6_address, &v6_next_hop_address)) + { + next_hop_proto_is_ip4 = 0; + } + else if (unformat (i, "l2-only")) + l2_only = 1; + else if (unformat (i, "next-hop-table %d", &next_hop_table_id)) + ; + else if (unformat (i, "out-label %d", &next_hop_out_label)) + vec_add1 (labels, ntohl (next_hop_out_label)); + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + M2 (MPLS_TUNNEL_ADD_DEL, mpls_tunnel_add_del, + sizeof (mpls_label_t) * vec_len (labels)); + + mp->mt_next_hop_sw_if_index = ntohl (next_hop_sw_if_index); + mp->mt_sw_if_index = ntohl (sw_if_index); + mp->mt_is_add = is_add; + mp->mt_l2_only = l2_only; + mp->mt_next_hop_table_id = ntohl (next_hop_table_id); + mp->mt_next_hop_proto_is_ip4 = next_hop_proto_is_ip4; + + mp->mt_next_hop_n_out_labels = vec_len (labels); + + if (0 != mp->mt_next_hop_n_out_labels) + { + clib_memcpy (mp->mt_next_hop_out_label_stack, labels, + sizeof (mpls_label_t) * mp->mt_next_hop_n_out_labels); + vec_free (labels); + } + + if (next_hop_proto_is_ip4) + { + clib_memcpy (mp->mt_next_hop, + &v4_next_hop_address, sizeof (v4_next_hop_address)); + } + else + { + clib_memcpy (mp->mt_next_hop, + &v6_next_hop_address, sizeof (v6_next_hop_address)); + } + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_sw_interface_set_unnumbered (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_unnumbered_t *mp; + f64 timeout; + u32 sw_if_index; + u32 unnum_sw_index = ~0; + u8 is_add = 1; + u8 sw_if_index_set = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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, "unnum_if_index %d", &unnum_sw_index)) + ; + else if (unformat (i, "del")) + is_add = 0; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (SW_INTERFACE_SET_UNNUMBERED, sw_interface_set_unnumbered); + + mp->sw_if_index = ntohl (sw_if_index); + mp->unnumbered_sw_if_index = ntohl (unnum_sw_index); + mp->is_add = is_add; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ip_neighbor_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ip_neighbor_add_del_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u32 vrf_id = 0; + u8 is_add = 1; + u8 is_static = 0; + u8 mac_address[6]; + u8 mac_set = 0; + u8 v4_address_set = 0; + u8 v6_address_set = 0; + ip4_address_t v4address; + ip6_address_t v6address; + + memset (mac_address, 0, sizeof (mac_address)); + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "mac %U", unformat_ethernet_address, mac_address)) + { + mac_set = 1; + } + else if (unformat (i, "del")) + is_add = 0; + else + if (unformat (i, "%U", api_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, "is_static")) + is_static = 1; + else if (unformat (i, "vrf %d", &vrf_id)) + ; + else if (unformat (i, "dst %U", unformat_ip4_address, &v4address)) + v4_address_set = 1; + else if (unformat (i, "dst %U", unformat_ip6_address, &v6address)) + v6_address_set = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + if (v4_address_set && v6_address_set) + { + errmsg ("both v4 and v6 addresses set"); + return -99; + } + if (!v4_address_set && !v6_address_set) + { + errmsg ("no address set"); + return -99; + } + + /* Construct the API message */ + M (IP_NEIGHBOR_ADD_DEL, ip_neighbor_add_del); + + mp->sw_if_index = ntohl (sw_if_index); + mp->is_add = is_add; + mp->vrf_id = ntohl (vrf_id); + mp->is_static = is_static; + if (mac_set) + clib_memcpy (mp->mac_address, mac_address, 6); + if (v6_address_set) + { + mp->is_ipv6 = 1; + clib_memcpy (mp->dst_address, &v6address, sizeof (v6address)); + } + else + { + /* mp->is_ipv6 = 0; via memset in M macro above */ + clib_memcpy (mp->dst_address, &v4address, sizeof (v4address)); + } + + /* send it... */ + S; + + /* Wait for a reply, return good/bad news */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_reset_vrf (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_reset_vrf_t *mp; + f64 timeout; + u32 vrf_id = 0; + u8 is_ipv6 = 0; + u8 vrf_id_set = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "vrf %d", &vrf_id)) + vrf_id_set = 1; + else if (unformat (i, "ipv6")) + is_ipv6 = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (vrf_id_set == 0) + { + errmsg ("missing vrf id"); + return -99; + } + + M (RESET_VRF, reset_vrf); + + mp->vrf_id = ntohl (vrf_id); + mp->is_ipv6 = is_ipv6; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_create_vlan_subif (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_create_vlan_subif_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u32 vlan_id; + u8 vlan_id_set = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "vlan %d", &vlan_id)) + vlan_id_set = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (vlan_id_set == 0) + { + errmsg ("missing vlan_id"); + return -99; + } + M (CREATE_VLAN_SUBIF, create_vlan_subif); + + mp->sw_if_index = ntohl (sw_if_index); + mp->vlan_id = ntohl (vlan_id); + + S; + W; + /* NOTREACHED */ + return 0; +} + +#define foreach_create_subif_bit \ +_(no_tags) \ +_(one_tag) \ +_(two_tags) \ +_(dot1ad) \ +_(exact_match) \ +_(default_sub) \ +_(outer_vlan_id_any) \ +_(inner_vlan_id_any) + +static int +api_create_subif (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_create_subif_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u32 sub_id; + u8 sub_id_set = 0; + u32 no_tags = 0; + u32 one_tag = 0; + u32 two_tags = 0; + u32 dot1ad = 0; + u32 exact_match = 0; + u32 default_sub = 0; + u32 outer_vlan_id_any = 0; + u32 inner_vlan_id_any = 0; + u32 tmp; + u16 outer_vlan_id = 0; + u16 inner_vlan_id = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sub_id %d", &sub_id)) + sub_id_set = 1; + else if (unformat (i, "outer_vlan_id %d", &tmp)) + outer_vlan_id = tmp; + else if (unformat (i, "inner_vlan_id %d", &tmp)) + inner_vlan_id = tmp; + +#define _(a) else if (unformat (i, #a)) a = 1 ; + foreach_create_subif_bit +#undef _ + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (sub_id_set == 0) + { + errmsg ("missing sub_id"); + return -99; + } + M (CREATE_SUBIF, create_subif); + + mp->sw_if_index = ntohl (sw_if_index); + mp->sub_id = ntohl (sub_id); + +#define _(a) mp->a = a; + foreach_create_subif_bit; +#undef _ + + mp->outer_vlan_id = ntohs (outer_vlan_id); + mp->inner_vlan_id = ntohs (inner_vlan_id); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_oam_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_oam_add_del_t *mp; + f64 timeout; + u32 vrf_id = 0; + u8 is_add = 1; + ip4_address_t src, dst; + u8 src_set = 0; + u8 dst_set = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "vrf %d", &vrf_id)) + ; + else if (unformat (i, "src %U", unformat_ip4_address, &src)) + src_set = 1; + else if (unformat (i, "dst %U", unformat_ip4_address, &dst)) + dst_set = 1; + else if (unformat (i, "del")) + is_add = 0; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (src_set == 0) + { + errmsg ("missing src addr"); + return -99; + } + + if (dst_set == 0) + { + errmsg ("missing dst addr"); + return -99; + } + + M (OAM_ADD_DEL, oam_add_del); + + mp->vrf_id = ntohl (vrf_id); + mp->is_add = is_add; + clib_memcpy (mp->src_address, &src, sizeof (mp->src_address)); + clib_memcpy (mp->dst_address, &dst, sizeof (mp->dst_address)); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_reset_fib (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_reset_fib_t *mp; + f64 timeout; + u32 vrf_id = 0; + u8 is_ipv6 = 0; + u8 vrf_id_set = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "vrf %d", &vrf_id)) + vrf_id_set = 1; + else if (unformat (i, "ipv6")) + is_ipv6 = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (vrf_id_set == 0) + { + errmsg ("missing vrf id"); + return -99; + } + + M (RESET_FIB, reset_fib); + + mp->vrf_id = ntohl (vrf_id); + mp->is_ipv6 = is_ipv6; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_dhcp_proxy_config (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_dhcp_proxy_config_t *mp; + f64 timeout; + u32 vrf_id = 0; + u8 is_add = 1; + u8 insert_cid = 1; + u8 v4_address_set = 0; + u8 v6_address_set = 0; + ip4_address_t v4address; + ip6_address_t v6address; + u8 v4_src_address_set = 0; + u8 v6_src_address_set = 0; + ip4_address_t v4srcaddress; + ip6_address_t v6srcaddress; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "vrf %d", &vrf_id)) + ; + else if (unformat (i, "insert-cid %d", &insert_cid)) + ; + else if (unformat (i, "svr %U", unformat_ip4_address, &v4address)) + v4_address_set = 1; + else if (unformat (i, "svr %U", unformat_ip6_address, &v6address)) + v6_address_set = 1; + else if (unformat (i, "src %U", unformat_ip4_address, &v4srcaddress)) + v4_src_address_set = 1; + else if (unformat (i, "src %U", unformat_ip6_address, &v6srcaddress)) + v6_src_address_set = 1; + else + break; + } + + if (v4_address_set && v6_address_set) + { + errmsg ("both v4 and v6 server addresses set"); + return -99; + } + if (!v4_address_set && !v6_address_set) + { + errmsg ("no server addresses set"); + return -99; + } + + if (v4_src_address_set && v6_src_address_set) + { + errmsg ("both v4 and v6 src addresses set"); + return -99; + } + if (!v4_src_address_set && !v6_src_address_set) + { + errmsg ("no src addresses set"); + return -99; + } + + if (!(v4_src_address_set && v4_address_set) && + !(v6_src_address_set && v6_address_set)) + { + errmsg ("no matching server and src addresses set"); + return -99; + } + + /* Construct the API message */ + M (DHCP_PROXY_CONFIG, dhcp_proxy_config); + + mp->insert_circuit_id = insert_cid; + mp->is_add = is_add; + mp->vrf_id = ntohl (vrf_id); + if (v6_address_set) + { + mp->is_ipv6 = 1; + clib_memcpy (mp->dhcp_server, &v6address, sizeof (v6address)); + clib_memcpy (mp->dhcp_src_address, &v6srcaddress, sizeof (v6address)); + } + else + { + clib_memcpy (mp->dhcp_server, &v4address, sizeof (v4address)); + clib_memcpy (mp->dhcp_src_address, &v4srcaddress, sizeof (v4address)); + } + + /* send it... */ + S; + + /* Wait for a reply, return good/bad news */ + W; + /* NOTREACHED */ + return 0; +} + +static int +api_dhcp_proxy_config_2 (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_dhcp_proxy_config_2_t *mp; + f64 timeout; + u32 rx_vrf_id = 0; + u32 server_vrf_id = 0; + u8 is_add = 1; + u8 insert_cid = 1; + u8 v4_address_set = 0; + u8 v6_address_set = 0; + ip4_address_t v4address; + ip6_address_t v6address; + u8 v4_src_address_set = 0; + u8 v6_src_address_set = 0; + ip4_address_t v4srcaddress; + ip6_address_t v6srcaddress; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "rx_vrf_id %d", &rx_vrf_id)) + ; + else if (unformat (i, "server_vrf_id %d", &server_vrf_id)) + ; + else if (unformat (i, "insert-cid %d", &insert_cid)) + ; + else if (unformat (i, "svr %U", unformat_ip4_address, &v4address)) + v4_address_set = 1; + else if (unformat (i, "svr %U", unformat_ip6_address, &v6address)) + v6_address_set = 1; + else if (unformat (i, "src %U", unformat_ip4_address, &v4srcaddress)) + v4_src_address_set = 1; + else if (unformat (i, "src %U", unformat_ip6_address, &v6srcaddress)) + v6_src_address_set = 1; + else + break; + } + + if (v4_address_set && v6_address_set) + { + errmsg ("both v4 and v6 server addresses set"); + return -99; + } + if (!v4_address_set && !v6_address_set) + { + errmsg ("no server addresses set"); + return -99; + } + + if (v4_src_address_set && v6_src_address_set) + { + errmsg ("both v4 and v6 src addresses set"); + return -99; + } + if (!v4_src_address_set && !v6_src_address_set) + { + errmsg ("no src addresses set"); + return -99; + } + + if (!(v4_src_address_set && v4_address_set) && + !(v6_src_address_set && v6_address_set)) + { + errmsg ("no matching server and src addresses set"); + return -99; + } + + /* Construct the API message */ + M (DHCP_PROXY_CONFIG_2, dhcp_proxy_config_2); + + mp->insert_circuit_id = insert_cid; + mp->is_add = is_add; + mp->rx_vrf_id = ntohl (rx_vrf_id); + mp->server_vrf_id = ntohl (server_vrf_id); + if (v6_address_set) + { + mp->is_ipv6 = 1; + clib_memcpy (mp->dhcp_server, &v6address, sizeof (v6address)); + clib_memcpy (mp->dhcp_src_address, &v6srcaddress, sizeof (v6address)); + } + else + { + clib_memcpy (mp->dhcp_server, &v4address, sizeof (v4address)); + clib_memcpy (mp->dhcp_src_address, &v4srcaddress, sizeof (v4address)); + } + + /* send it... */ + S; + + /* Wait for a reply, return good/bad news */ + W; + /* NOTREACHED */ + return 0; +} + +static int +api_dhcp_proxy_set_vss (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_dhcp_proxy_set_vss_t *mp; + f64 timeout; + u8 is_ipv6 = 0; + u8 is_add = 1; + u32 tbl_id; + u8 tbl_id_set = 0; + u32 oui; + u8 oui_set = 0; + u32 fib_id; + u8 fib_id_set = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "tbl_id %d", &tbl_id)) + tbl_id_set = 1; + if (unformat (i, "fib_id %d", &fib_id)) + fib_id_set = 1; + if (unformat (i, "oui %d", &oui)) + oui_set = 1; + else if (unformat (i, "ipv6")) + is_ipv6 = 1; + else if (unformat (i, "del")) + is_add = 0; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (tbl_id_set == 0) + { + errmsg ("missing tbl id"); + return -99; + } + + if (fib_id_set == 0) + { + errmsg ("missing fib id"); + return -99; + } + if (oui_set == 0) + { + errmsg ("missing oui"); + return -99; + } + + M (DHCP_PROXY_SET_VSS, dhcp_proxy_set_vss); + mp->tbl_id = ntohl (tbl_id); + mp->fib_id = ntohl (fib_id); + mp->oui = ntohl (oui); + mp->is_ipv6 = is_ipv6; + mp->is_add = is_add; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_dhcp_client_config (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_dhcp_client_config_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 is_add = 1; + u8 *hostname = 0; + u8 disable_event = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_add = 0; + else + if (unformat (i, "%U", api_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, "hostname %s", &hostname)) + ; + else if (unformat (i, "disable_event")) + disable_event = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (vec_len (hostname) > 63) + { + errmsg ("hostname too long"); + } + vec_add1 (hostname, 0); + + /* Construct the API message */ + M (DHCP_CLIENT_CONFIG, dhcp_client_config); + + mp->sw_if_index = ntohl (sw_if_index); + clib_memcpy (mp->hostname, hostname, vec_len (hostname)); + vec_free (hostname); + mp->is_add = is_add; + mp->want_dhcp_event = disable_event ? 0 : 1; + mp->pid = getpid (); + + /* send it... */ + S; + + /* Wait for a reply, return good/bad news */ + W; + /* NOTREACHED */ + return 0; +} + +static int +api_set_ip_flow_hash (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_set_ip_flow_hash_t *mp; + f64 timeout; + u32 vrf_id = 0; + u8 is_ipv6 = 0; + u8 vrf_id_set = 0; + u8 src = 0; + u8 dst = 0; + u8 sport = 0; + u8 dport = 0; + u8 proto = 0; + u8 reverse = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "vrf %d", &vrf_id)) + vrf_id_set = 1; + else if (unformat (i, "ipv6")) + is_ipv6 = 1; + else if (unformat (i, "src")) + src = 1; + else if (unformat (i, "dst")) + dst = 1; + else if (unformat (i, "sport")) + sport = 1; + else if (unformat (i, "dport")) + dport = 1; + else if (unformat (i, "proto")) + proto = 1; + else if (unformat (i, "reverse")) + reverse = 1; + + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (vrf_id_set == 0) + { + errmsg ("missing vrf id"); + return -99; + } + + M (SET_IP_FLOW_HASH, set_ip_flow_hash); + mp->src = src; + mp->dst = dst; + mp->sport = sport; + mp->dport = dport; + mp->proto = proto; + mp->reverse = reverse; + mp->vrf_id = ntohl (vrf_id); + mp->is_ipv6 = is_ipv6; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_sw_interface_ip6_enable_disable (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_ip6_enable_disable_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 enable = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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, "enable")) + enable = 1; + else if (unformat (i, "disable")) + enable = 0; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (SW_INTERFACE_IP6_ENABLE_DISABLE, sw_interface_ip6_enable_disable); + + mp->sw_if_index = ntohl (sw_if_index); + mp->enable = enable; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_sw_interface_ip6_set_link_local_address (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_ip6_set_link_local_address_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u32 address_length = 0; + u8 v6_address_set = 0; + ip6_address_t v6address; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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, "%U/%d", + unformat_ip6_address, &v6address, &address_length)) + v6_address_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + if (!v6_address_set) + { + errmsg ("no address set"); + return -99; + } + + /* Construct the API message */ + M (SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS, + sw_interface_ip6_set_link_local_address); + + mp->sw_if_index = ntohl (sw_if_index); + clib_memcpy (mp->address, &v6address, sizeof (v6address)); + mp->address_length = address_length; + + /* send it... */ + S; + + /* Wait for a reply, return good/bad news */ + W; + + /* NOTREACHED */ + return 0; +} + + +static int +api_sw_interface_ip6nd_ra_prefix (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_ip6nd_ra_prefix_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u32 address_length = 0; + u8 v6_address_set = 0; + ip6_address_t v6address; + u8 use_default = 0; + u8 no_advertise = 0; + u8 off_link = 0; + u8 no_autoconfig = 0; + u8 no_onlink = 0; + u8 is_no = 0; + u32 val_lifetime = 0; + u32 pref_lifetime = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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, "%U/%d", + unformat_ip6_address, &v6address, &address_length)) + v6_address_set = 1; + else if (unformat (i, "val_life %d", &val_lifetime)) + ; + else if (unformat (i, "pref_life %d", &pref_lifetime)) + ; + else if (unformat (i, "def")) + use_default = 1; + else if (unformat (i, "noadv")) + no_advertise = 1; + else if (unformat (i, "offl")) + off_link = 1; + else if (unformat (i, "noauto")) + no_autoconfig = 1; + else if (unformat (i, "nolink")) + no_onlink = 1; + else if (unformat (i, "isno")) + is_no = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + if (!v6_address_set) + { + errmsg ("no address set"); + return -99; + } + + /* Construct the API message */ + M (SW_INTERFACE_IP6ND_RA_PREFIX, sw_interface_ip6nd_ra_prefix); + + mp->sw_if_index = ntohl (sw_if_index); + clib_memcpy (mp->address, &v6address, sizeof (v6address)); + mp->address_length = address_length; + mp->use_default = use_default; + mp->no_advertise = no_advertise; + mp->off_link = off_link; + mp->no_autoconfig = no_autoconfig; + mp->no_onlink = no_onlink; + mp->is_no = is_no; + mp->val_lifetime = ntohl (val_lifetime); + mp->pref_lifetime = ntohl (pref_lifetime); + + /* send it... */ + S; + + /* Wait for a reply, return good/bad news */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_sw_interface_ip6nd_ra_config (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_ip6nd_ra_config_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 suppress = 0; + u8 managed = 0; + u8 other = 0; + u8 ll_option = 0; + u8 send_unicast = 0; + u8 cease = 0; + u8 is_no = 0; + u8 default_router = 0; + u32 max_interval = 0; + u32 min_interval = 0; + u32 lifetime = 0; + u32 initial_count = 0; + u32 initial_interval = 0; + + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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, "maxint %d", &max_interval)) + ; + else if (unformat (i, "minint %d", &min_interval)) + ; + else if (unformat (i, "life %d", &lifetime)) + ; + else if (unformat (i, "count %d", &initial_count)) + ; + else if (unformat (i, "interval %d", &initial_interval)) + ; + else if (unformat (i, "suppress") || unformat (i, "surpress")) + suppress = 1; + else if (unformat (i, "managed")) + managed = 1; + else if (unformat (i, "other")) + other = 1; + else if (unformat (i, "ll")) + ll_option = 1; + else if (unformat (i, "send")) + send_unicast = 1; + else if (unformat (i, "cease")) + cease = 1; + else if (unformat (i, "isno")) + is_no = 1; + else if (unformat (i, "def")) + default_router = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (SW_INTERFACE_IP6ND_RA_CONFIG, sw_interface_ip6nd_ra_config); + + mp->sw_if_index = ntohl (sw_if_index); + mp->max_interval = ntohl (max_interval); + mp->min_interval = ntohl (min_interval); + mp->lifetime = ntohl (lifetime); + mp->initial_count = ntohl (initial_count); + mp->initial_interval = ntohl (initial_interval); + mp->suppress = suppress; + mp->managed = managed; + mp->other = other; + mp->ll_option = ll_option; + mp->send_unicast = send_unicast; + mp->cease = cease; + mp->is_no = is_no; + mp->default_router = default_router; + + /* send it... */ + S; + + /* Wait for a reply, return good/bad news */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_set_arp_neighbor_limit (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_set_arp_neighbor_limit_t *mp; + f64 timeout; + u32 arp_nbr_limit; + u8 limit_set = 0; + u8 is_ipv6 = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "arp_nbr_limit %d", &arp_nbr_limit)) + limit_set = 1; + else if (unformat (i, "ipv6")) + is_ipv6 = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (limit_set == 0) + { + errmsg ("missing limit value"); + return -99; + } + + M (SET_ARP_NEIGHBOR_LIMIT, set_arp_neighbor_limit); + + mp->arp_neighbor_limit = ntohl (arp_nbr_limit); + mp->is_ipv6 = is_ipv6; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_l2_patch_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_l2_patch_add_del_t *mp; + f64 timeout; + u32 rx_sw_if_index; + u8 rx_sw_if_index_set = 0; + u32 tx_sw_if_index; + u8 tx_sw_if_index_set = 0; + u8 is_add = 1; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "rx_sw_if_index %d", &rx_sw_if_index)) + rx_sw_if_index_set = 1; + else if (unformat (i, "tx_sw_if_index %d", &tx_sw_if_index)) + tx_sw_if_index_set = 1; + else if (unformat (i, "rx")) + { + if (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, + &rx_sw_if_index)) + rx_sw_if_index_set = 1; + } + else + break; + } + else if (unformat (i, "tx")) + { + if (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, + &tx_sw_if_index)) + tx_sw_if_index_set = 1; + } + else + break; + } + else if (unformat (i, "del")) + is_add = 0; + else + break; + } + + if (rx_sw_if_index_set == 0) + { + errmsg ("missing rx interface name or rx_sw_if_index"); + return -99; + } + + if (tx_sw_if_index_set == 0) + { + errmsg ("missing tx interface name or tx_sw_if_index"); + return -99; + } + + M (L2_PATCH_ADD_DEL, l2_patch_add_del); + + mp->rx_sw_if_index = ntohl (rx_sw_if_index); + mp->tx_sw_if_index = ntohl (tx_sw_if_index); + mp->is_add = is_add; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ioam_enable (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_ioam_enable_t *mp; + f64 timeout; + u32 id = 0; + int has_trace_option = 0; + int has_pot_option = 0; + int has_seqno_option = 0; + int has_analyse_option = 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, "seqno")) + has_seqno_option = 1; + else if (unformat (input, "analyse")) + has_analyse_option = 1; + else + break; + } + M (IOAM_ENABLE, ioam_enable); + mp->id = htons (id); + mp->seqno = has_seqno_option; + mp->analyse = has_analyse_option; + mp->pot_enable = has_pot_option; + mp->trace_enable = has_trace_option; + + S; + W; + + return (0); + +} + + +static int +api_ioam_disable (vat_main_t * vam) +{ + vl_api_ioam_disable_t *mp; + f64 timeout; + + M (IOAM_DISABLE, ioam_disable); + S; + W; + return 0; +} + +static int +api_sr_tunnel_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sr_tunnel_add_del_t *mp; + f64 timeout; + int is_del = 0; + int pl_index; + ip6_address_t src_address; + int src_address_set = 0; + ip6_address_t dst_address; + u32 dst_mask_width; + int dst_address_set = 0; + u16 flags = 0; + u32 rx_table_id = 0; + u32 tx_table_id = 0; + ip6_address_t *segments = 0; + ip6_address_t *this_seg; + ip6_address_t *tags = 0; + ip6_address_t *this_tag; + ip6_address_t next_address, tag; + u8 *name = 0; + u8 *policy_name = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_del = 1; + else if (unformat (i, "name %s", &name)) + ; + else if (unformat (i, "policy %s", &policy_name)) + ; + else if (unformat (i, "rx_fib_id %d", &rx_table_id)) + ; + else if (unformat (i, "tx_fib_id %d", &tx_table_id)) + ; + else if (unformat (i, "src %U", unformat_ip6_address, &src_address)) + src_address_set = 1; + else if (unformat (i, "dst %U/%d", + unformat_ip6_address, &dst_address, &dst_mask_width)) + dst_address_set = 1; + else if (unformat (i, "next %U", unformat_ip6_address, &next_address)) + { + vec_add2 (segments, this_seg, 1); + clib_memcpy (this_seg->as_u8, next_address.as_u8, + sizeof (*this_seg)); + } + else if (unformat (i, "tag %U", unformat_ip6_address, &tag)) + { + vec_add2 (tags, this_tag, 1); + clib_memcpy (this_tag->as_u8, tag.as_u8, sizeof (*this_tag)); + } + else if (unformat (i, "clean")) + flags |= IP6_SR_HEADER_FLAG_CLEANUP; + else if (unformat (i, "protected")) + flags |= IP6_SR_HEADER_FLAG_PROTECTED; + else if (unformat (i, "InPE %d", &pl_index)) + { + if (pl_index <= 0 || pl_index > 4) + { + pl_index_range_error: + errmsg ("pl index %d out of range", pl_index); + return -99; + } + flags |= + IP6_SR_HEADER_FLAG_PL_ELT_INGRESS_PE << (3 * (pl_index - 1)); + } + else if (unformat (i, "EgPE %d", &pl_index)) + { + if (pl_index <= 0 || pl_index > 4) + goto pl_index_range_error; + flags |= + IP6_SR_HEADER_FLAG_PL_ELT_EGRESS_PE << (3 * (pl_index - 1)); + } + else if (unformat (i, "OrgSrc %d", &pl_index)) + { + if (pl_index <= 0 || pl_index > 4) + goto pl_index_range_error; + flags |= + IP6_SR_HEADER_FLAG_PL_ELT_ORIG_SRC_ADDR << (3 * (pl_index - 1)); + } + else + break; + } + + if (!src_address_set) + { + errmsg ("src address required"); + return -99; + } + + if (!dst_address_set) + { + errmsg ("dst address required"); + return -99; + } + + if (!segments) + { + errmsg ("at least one sr segment required"); + return -99; + } + + M2 (SR_TUNNEL_ADD_DEL, sr_tunnel_add_del, + vec_len (segments) * sizeof (ip6_address_t) + + vec_len (tags) * sizeof (ip6_address_t)); + + clib_memcpy (mp->src_address, &src_address, sizeof (mp->src_address)); + clib_memcpy (mp->dst_address, &dst_address, sizeof (mp->dst_address)); + mp->dst_mask_width = dst_mask_width; + mp->flags_net_byte_order = clib_host_to_net_u16 (flags); + mp->n_segments = vec_len (segments); + mp->n_tags = vec_len (tags); + mp->is_add = is_del == 0; + clib_memcpy (mp->segs_and_tags, segments, + vec_len (segments) * sizeof (ip6_address_t)); + clib_memcpy (mp->segs_and_tags + + vec_len (segments) * sizeof (ip6_address_t), tags, + vec_len (tags) * sizeof (ip6_address_t)); + + mp->outer_vrf_id = ntohl (rx_table_id); + mp->inner_vrf_id = ntohl (tx_table_id); + memcpy (mp->name, name, vec_len (name)); + memcpy (mp->policy_name, policy_name, vec_len (policy_name)); + + vec_free (segments); + vec_free (tags); + + S; + W; + /* NOTREACHED */ +} + +static int +api_sr_policy_add_del (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_sr_policy_add_del_t *mp; + f64 timeout; + int is_del = 0; + u8 *name = 0; + u8 *tunnel_name = 0; + u8 **tunnel_names = 0; + + int name_set = 0; + int tunnel_set = 0; + int j = 0; + int tunnel_names_length = 1; // Init to 1 to offset the #tunnel_names counter byte + int tun_name_len = 0; // Different naming convention used as confusing these would be "bad" (TM) + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + is_del = 1; + else if (unformat (input, "name %s", &name)) + name_set = 1; + else if (unformat (input, "tunnel %s", &tunnel_name)) + { + if (tunnel_name) + { + vec_add1 (tunnel_names, tunnel_name); + /* For serializer: + - length = #bytes to store in serial vector + - +1 = byte to store that length + */ + tunnel_names_length += (vec_len (tunnel_name) + 1); + tunnel_set = 1; + tunnel_name = 0; + } + } + else + break; + } + + if (!name_set) + { + errmsg ("policy name required"); + return -99; + } + + if ((!tunnel_set) && (!is_del)) + { + errmsg ("tunnel name required"); + return -99; + } + + M2 (SR_POLICY_ADD_DEL, sr_policy_add_del, tunnel_names_length); + + + + mp->is_add = !is_del; + + memcpy (mp->name, name, vec_len (name)); + // Since mp->tunnel_names is of type u8[0] and not a u8 *, u8 ** needs to be serialized + u8 *serial_orig = 0; + vec_validate (serial_orig, tunnel_names_length); + *serial_orig = vec_len (tunnel_names); // Store the number of tunnels as length in first byte of serialized vector + serial_orig += 1; // Move along one byte to store the length of first tunnel_name + + for (j = 0; j < vec_len (tunnel_names); j++) + { + tun_name_len = vec_len (tunnel_names[j]); + *serial_orig = tun_name_len; // Store length of tunnel name in first byte of Length/Value pair + serial_orig += 1; // Move along one byte to store the actual tunnel name + memcpy (serial_orig, tunnel_names[j], tun_name_len); + serial_orig += tun_name_len; // Advance past the copy + } + memcpy (mp->tunnel_names, serial_orig - tunnel_names_length, tunnel_names_length); // Regress serial_orig to head then copy fwd + + vec_free (tunnel_names); + vec_free (tunnel_name); + + S; + W; + /* NOTREACHED */ +} + +static int +api_sr_multicast_map_add_del (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_sr_multicast_map_add_del_t *mp; + f64 timeout; + int is_del = 0; + ip6_address_t multicast_address; + u8 *policy_name = 0; + int multicast_address_set = 0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + is_del = 1; + else + if (unformat + (input, "address %U", unformat_ip6_address, &multicast_address)) + multicast_address_set = 1; + else if (unformat (input, "sr-policy %s", &policy_name)) + ; + else + break; + } + + if (!is_del && !policy_name) + { + errmsg ("sr-policy name required"); + return -99; + } + + + if (!multicast_address_set) + { + errmsg ("address required"); + return -99; + } + + M (SR_MULTICAST_MAP_ADD_DEL, sr_multicast_map_add_del); + + mp->is_add = !is_del; + memcpy (mp->policy_name, policy_name, vec_len (policy_name)); + clib_memcpy (mp->multicast_address, &multicast_address, + sizeof (mp->multicast_address)); + + + vec_free (policy_name); + + S; + W; + /* NOTREACHED */ +} + + +#define foreach_tcp_proto_field \ +_(src_port) \ +_(dst_port) + +#define foreach_udp_proto_field \ +_(src_port) \ +_(dst_port) + +#define foreach_ip4_proto_field \ +_(src_address) \ +_(dst_address) \ +_(tos) \ +_(length) \ +_(fragment_id) \ +_(ttl) \ +_(protocol) \ +_(checksum) + +uword +unformat_tcp_mask (unformat_input_t * input, va_list * args) +{ + u8 **maskp = va_arg (*args, u8 **); + u8 *mask = 0; + u8 found_something = 0; + tcp_header_t *tcp; + +#define _(a) u8 a=0; + foreach_tcp_proto_field; +#undef _ + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (0); +#define _(a) else if (unformat (input, #a)) a=1; + foreach_tcp_proto_field +#undef _ + else + break; + } + +#define _(a) found_something += a; + foreach_tcp_proto_field; +#undef _ + + if (found_something == 0) + return 0; + + vec_validate (mask, sizeof (*tcp) - 1); + + tcp = (tcp_header_t *) mask; + +#define _(a) if (a) memset (&tcp->a, 0xff, sizeof (tcp->a)); + foreach_tcp_proto_field; +#undef _ + + *maskp = mask; + return 1; +} + +uword +unformat_udp_mask (unformat_input_t * input, va_list * args) +{ + u8 **maskp = va_arg (*args, u8 **); + u8 *mask = 0; + u8 found_something = 0; + udp_header_t *udp; + +#define _(a) u8 a=0; + foreach_udp_proto_field; +#undef _ + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (0); +#define _(a) else if (unformat (input, #a)) a=1; + foreach_udp_proto_field +#undef _ + else + break; + } + +#define _(a) found_something += a; + foreach_udp_proto_field; +#undef _ + + if (found_something == 0) + return 0; + + vec_validate (mask, sizeof (*udp) - 1); + + udp = (udp_header_t *) mask; + +#define _(a) if (a) memset (&udp->a, 0xff, sizeof (udp->a)); + foreach_udp_proto_field; +#undef _ + + *maskp = mask; + return 1; +} + +typedef struct +{ + u16 src_port, dst_port; +} tcpudp_header_t; + +uword +unformat_l4_mask (unformat_input_t * input, va_list * args) +{ + u8 **maskp = va_arg (*args, u8 **); + u16 src_port = 0, dst_port = 0; + tcpudp_header_t *tcpudp; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "tcp %U", unformat_tcp_mask, maskp)) + return 1; + else if (unformat (input, "udp %U", unformat_udp_mask, maskp)) + return 1; + else if (unformat (input, "src_port")) + src_port = 0xFFFF; + else if (unformat (input, "dst_port")) + dst_port = 0xFFFF; + else + return 0; + } + + if (!src_port && !dst_port) + return 0; + + u8 *mask = 0; + vec_validate (mask, sizeof (tcpudp_header_t) - 1); + + tcpudp = (tcpudp_header_t *) mask; + tcpudp->src_port = src_port; + tcpudp->dst_port = dst_port; + + *maskp = mask; + + return 1; +} + +uword +unformat_ip4_mask (unformat_input_t * input, va_list * args) +{ + u8 **maskp = va_arg (*args, u8 **); + u8 *mask = 0; + u8 found_something = 0; + ip4_header_t *ip; + +#define _(a) u8 a=0; + foreach_ip4_proto_field; +#undef _ + u8 version = 0; + u8 hdr_length = 0; + + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "version")) + version = 1; + else if (unformat (input, "hdr_length")) + hdr_length = 1; + else if (unformat (input, "src")) + src_address = 1; + else if (unformat (input, "dst")) + dst_address = 1; + else if (unformat (input, "proto")) + protocol = 1; + +#define _(a) else if (unformat (input, #a)) a=1; + foreach_ip4_proto_field +#undef _ + else + break; + } + +#define _(a) found_something += a; + foreach_ip4_proto_field; +#undef _ + + if (found_something == 0) + return 0; + + vec_validate (mask, sizeof (*ip) - 1); + + ip = (ip4_header_t *) mask; + +#define _(a) if (a) memset (&ip->a, 0xff, sizeof (ip->a)); + foreach_ip4_proto_field; +#undef _ + + ip->ip_version_and_header_length = 0; + + if (version) + ip->ip_version_and_header_length |= 0xF0; + + if (hdr_length) + ip->ip_version_and_header_length |= 0x0F; + + *maskp = mask; + return 1; +} + +#define foreach_ip6_proto_field \ +_(src_address) \ +_(dst_address) \ +_(payload_length) \ +_(hop_limit) \ +_(protocol) + +uword +unformat_ip6_mask (unformat_input_t * input, va_list * args) +{ + u8 **maskp = va_arg (*args, u8 **); + u8 *mask = 0; + u8 found_something = 0; + ip6_header_t *ip; + u32 ip_version_traffic_class_and_flow_label; + +#define _(a) u8 a=0; + foreach_ip6_proto_field; +#undef _ + u8 version = 0; + u8 traffic_class = 0; + u8 flow_label = 0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "version")) + version = 1; + else if (unformat (input, "traffic-class")) + traffic_class = 1; + else if (unformat (input, "flow-label")) + flow_label = 1; + else if (unformat (input, "src")) + src_address = 1; + else if (unformat (input, "dst")) + dst_address = 1; + else if (unformat (input, "proto")) + protocol = 1; + +#define _(a) else if (unformat (input, #a)) a=1; + foreach_ip6_proto_field +#undef _ + else + break; + } + +#define _(a) found_something += a; + foreach_ip6_proto_field; +#undef _ + + if (found_something == 0) + return 0; + + vec_validate (mask, sizeof (*ip) - 1); + + ip = (ip6_header_t *) mask; + +#define _(a) if (a) memset (&ip->a, 0xff, sizeof (ip->a)); + foreach_ip6_proto_field; +#undef _ + + ip_version_traffic_class_and_flow_label = 0; + + if (version) + ip_version_traffic_class_and_flow_label |= 0xF0000000; + + if (traffic_class) + ip_version_traffic_class_and_flow_label |= 0x0FF00000; + + if (flow_label) + ip_version_traffic_class_and_flow_label |= 0x000FFFFF; + + ip->ip_version_traffic_class_and_flow_label = + clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label); + + *maskp = mask; + return 1; +} + +uword +unformat_l3_mask (unformat_input_t * input, va_list * args) +{ + u8 **maskp = va_arg (*args, u8 **); + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "ip4 %U", unformat_ip4_mask, maskp)) + return 1; + else if (unformat (input, "ip6 %U", unformat_ip6_mask, maskp)) + return 1; + else + break; + } + return 0; +} + +uword +unformat_l2_mask (unformat_input_t * input, va_list * args) +{ + u8 **maskp = va_arg (*args, u8 **); + u8 *mask = 0; + u8 src = 0; + u8 dst = 0; + u8 proto = 0; + u8 tag1 = 0; + u8 tag2 = 0; + u8 ignore_tag1 = 0; + u8 ignore_tag2 = 0; + u8 cos1 = 0; + u8 cos2 = 0; + u8 dot1q = 0; + u8 dot1ad = 0; + int len = 14; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "src")) + src = 1; + else if (unformat (input, "dst")) + dst = 1; + else if (unformat (input, "proto")) + proto = 1; + else if (unformat (input, "tag1")) + tag1 = 1; + else if (unformat (input, "tag2")) + tag2 = 1; + else if (unformat (input, "ignore-tag1")) + ignore_tag1 = 1; + else if (unformat (input, "ignore-tag2")) + ignore_tag2 = 1; + else if (unformat (input, "cos1")) + cos1 = 1; + else if (unformat (input, "cos2")) + cos2 = 1; + else if (unformat (input, "dot1q")) + dot1q = 1; + else if (unformat (input, "dot1ad")) + dot1ad = 1; + else + break; + } + if ((src + dst + proto + tag1 + tag2 + dot1q + dot1ad + + ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0) + return 0; + + if (tag1 || ignore_tag1 || cos1 || dot1q) + len = 18; + if (tag2 || ignore_tag2 || cos2 || dot1ad) + len = 22; + + vec_validate (mask, len - 1); + + if (dst) + memset (mask, 0xff, 6); + + if (src) + memset (mask + 6, 0xff, 6); + + if (tag2 || dot1ad) + { + /* inner vlan tag */ + if (tag2) + { + mask[19] = 0xff; + mask[18] = 0x0f; + } + if (cos2) + mask[18] |= 0xe0; + if (proto) + mask[21] = mask[20] = 0xff; + if (tag1) + { + mask[15] = 0xff; + mask[14] = 0x0f; + } + if (cos1) + mask[14] |= 0xe0; + *maskp = mask; + return 1; + } + if (tag1 | dot1q) + { + if (tag1) + { + mask[15] = 0xff; + mask[14] = 0x0f; + } + if (cos1) + mask[14] |= 0xe0; + if (proto) + mask[16] = mask[17] = 0xff; + + *maskp = mask; + return 1; + } + if (cos2) + mask[18] |= 0xe0; + if (cos1) + mask[14] |= 0xe0; + if (proto) + mask[12] = mask[13] = 0xff; + + *maskp = mask; + return 1; +} + +uword +unformat_classify_mask (unformat_input_t * input, va_list * args) +{ + u8 **maskp = va_arg (*args, u8 **); + u32 *skipp = va_arg (*args, u32 *); + u32 *matchp = va_arg (*args, u32 *); + u32 match; + u8 *mask = 0; + u8 *l2 = 0; + u8 *l3 = 0; + u8 *l4 = 0; + int i; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "hex %U", unformat_hex_string, &mask)) + ; + else if (unformat (input, "l2 %U", unformat_l2_mask, &l2)) + ; + else if (unformat (input, "l3 %U", unformat_l3_mask, &l3)) + ; + else if (unformat (input, "l4 %U", unformat_l4_mask, &l4)) + ; + else + break; + } + + if (l4 && !l3) + { + vec_free (mask); + vec_free (l2); + vec_free (l4); + return 0; + } + + if (mask || l2 || l3 || l4) + { + if (l2 || l3 || l4) + { + /* "With a free Ethernet header in every package" */ + if (l2 == 0) + vec_validate (l2, 13); + mask = l2; + if (vec_len (l3)) + { + vec_append (mask, l3); + vec_free (l3); + } + if (vec_len (l4)) + { + vec_append (mask, l4); + vec_free (l4); + } + } + + /* Scan forward looking for the first significant mask octet */ + for (i = 0; i < vec_len (mask); i++) + if (mask[i]) + break; + + /* compute (skip, match) params */ + *skipp = i / sizeof (u32x4); + vec_delete (mask, *skipp * sizeof (u32x4), 0); + + /* Pad mask to an even multiple of the vector size */ + while (vec_len (mask) % sizeof (u32x4)) + vec_add1 (mask, 0); + + match = vec_len (mask) / sizeof (u32x4); + + for (i = match * sizeof (u32x4); i > 0; i -= sizeof (u32x4)) + { + u64 *tmp = (u64 *) (mask + (i - sizeof (u32x4))); + if (*tmp || *(tmp + 1)) + break; + match--; + } + if (match == 0) + clib_warning ("BUG: match 0"); + + _vec_len (mask) = match * sizeof (u32x4); + + *matchp = match; + *maskp = mask; + + return 1; + } + + return 0; +} + +#define foreach_l2_next \ +_(drop, DROP) \ +_(ethernet, ETHERNET_INPUT) \ +_(ip4, IP4_INPUT) \ +_(ip6, IP6_INPUT) + +uword +unformat_l2_next_index (unformat_input_t * input, va_list * args) +{ + u32 *miss_next_indexp = va_arg (*args, u32 *); + u32 next_index = 0; + u32 tmp; + +#define _(n,N) \ + if (unformat (input, #n)) { next_index = L2_INPUT_CLASSIFY_NEXT_##N; goto out;} + foreach_l2_next; +#undef _ + + if (unformat (input, "%d", &tmp)) + { + next_index = tmp; + goto out; + } + + return 0; + +out: + *miss_next_indexp = next_index; + return 1; +} + +#define foreach_ip_next \ +_(drop, DROP) \ +_(local, LOCAL) \ +_(rewrite, REWRITE) + +uword +unformat_ip_next_index (unformat_input_t * input, va_list * args) +{ + u32 *miss_next_indexp = va_arg (*args, u32 *); + u32 next_index = 0; + u32 tmp; + +#define _(n,N) \ + if (unformat (input, #n)) { next_index = IP_LOOKUP_NEXT_##N; goto out;} + foreach_ip_next; +#undef _ + + if (unformat (input, "%d", &tmp)) + { + next_index = tmp; + goto out; + } + + return 0; + +out: + *miss_next_indexp = next_index; + return 1; +} + +#define foreach_acl_next \ +_(deny, DENY) + +uword +unformat_acl_next_index (unformat_input_t * input, va_list * args) +{ + u32 *miss_next_indexp = va_arg (*args, u32 *); + u32 next_index = 0; + u32 tmp; + +#define _(n,N) \ + if (unformat (input, #n)) { next_index = ACL_NEXT_INDEX_##N; goto out;} + foreach_acl_next; +#undef _ + + if (unformat (input, "permit")) + { + next_index = ~0; + goto out; + } + else if (unformat (input, "%d", &tmp)) + { + next_index = tmp; + goto out; + } + + return 0; + +out: + *miss_next_indexp = next_index; + return 1; +} + +uword +unformat_policer_precolor (unformat_input_t * input, va_list * args) +{ + u32 *r = va_arg (*args, u32 *); + + if (unformat (input, "conform-color")) + *r = POLICE_CONFORM; + else if (unformat (input, "exceed-color")) + *r = POLICE_EXCEED; + else + return 0; + + return 1; +} + +static int +api_classify_add_del_table (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_classify_add_del_table_t *mp; + + u32 nbuckets = 2; + u32 skip = ~0; + u32 match = ~0; + int is_add = 1; + int del_chain = 0; + u32 table_index = ~0; + u32 next_table_index = ~0; + u32 miss_next_index = ~0; + u32 memory_size = 32 << 20; + u8 *mask = 0; + f64 timeout; + u32 current_data_flag = 0; + int current_data_offset = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "del-chain")) + { + is_add = 0; + del_chain = 1; + } + else if (unformat (i, "buckets %d", &nbuckets)) + ; + else if (unformat (i, "memory_size %d", &memory_size)) + ; + else if (unformat (i, "skip %d", &skip)) + ; + else if (unformat (i, "match %d", &match)) + ; + else if (unformat (i, "table %d", &table_index)) + ; + else if (unformat (i, "mask %U", unformat_classify_mask, + &mask, &skip, &match)) + ; + else if (unformat (i, "next-table %d", &next_table_index)) + ; + else if (unformat (i, "miss-next %U", unformat_ip_next_index, + &miss_next_index)) + ; + else if (unformat (i, "l2-miss-next %U", unformat_l2_next_index, + &miss_next_index)) + ; + else if (unformat (i, "acl-miss-next %U", unformat_acl_next_index, + &miss_next_index)) + ; + else if (unformat (i, "current-data-flag %d", ¤t_data_flag)) + ; + else if (unformat (i, "current-data-offset %d", ¤t_data_offset)) + ; + else + break; + } + + if (is_add && mask == 0) + { + errmsg ("Mask required"); + return -99; + } + + if (is_add && skip == ~0) + { + errmsg ("skip count required"); + return -99; + } + + if (is_add && match == ~0) + { + errmsg ("match count required"); + return -99; + } + + if (!is_add && table_index == ~0) + { + errmsg ("table index required for delete"); + return -99; + } + + M2 (CLASSIFY_ADD_DEL_TABLE, classify_add_del_table, vec_len (mask)); + + mp->is_add = is_add; + mp->del_chain = del_chain; + mp->table_index = ntohl (table_index); + mp->nbuckets = ntohl (nbuckets); + mp->memory_size = ntohl (memory_size); + mp->skip_n_vectors = ntohl (skip); + mp->match_n_vectors = ntohl (match); + mp->next_table_index = ntohl (next_table_index); + mp->miss_next_index = ntohl (miss_next_index); + mp->current_data_flag = ntohl (current_data_flag); + mp->current_data_offset = ntohl (current_data_offset); + clib_memcpy (mp->mask, mask, vec_len (mask)); + + vec_free (mask); + + S; + W; + /* NOTREACHED */ +} + +uword +unformat_l4_match (unformat_input_t * input, va_list * args) +{ + u8 **matchp = va_arg (*args, u8 **); + + u8 *proto_header = 0; + int src_port = 0; + int dst_port = 0; + + tcpudp_header_t h; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "src_port %d", &src_port)) + ; + else if (unformat (input, "dst_port %d", &dst_port)) + ; + else + return 0; + } + + h.src_port = clib_host_to_net_u16 (src_port); + h.dst_port = clib_host_to_net_u16 (dst_port); + vec_validate (proto_header, sizeof (h) - 1); + memcpy (proto_header, &h, sizeof (h)); + + *matchp = proto_header; + + return 1; +} + +uword +unformat_ip4_match (unformat_input_t * input, va_list * args) +{ + u8 **matchp = va_arg (*args, u8 **); + u8 *match = 0; + ip4_header_t *ip; + int version = 0; + u32 version_val; + int hdr_length = 0; + u32 hdr_length_val; + int src = 0, dst = 0; + ip4_address_t src_val, dst_val; + int proto = 0; + u32 proto_val; + int tos = 0; + u32 tos_val; + int length = 0; + u32 length_val; + int fragment_id = 0; + u32 fragment_id_val; + int ttl = 0; + int ttl_val; + int checksum = 0; + u32 checksum_val; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "version %d", &version_val)) + version = 1; + else if (unformat (input, "hdr_length %d", &hdr_length_val)) + hdr_length = 1; + else if (unformat (input, "src %U", unformat_ip4_address, &src_val)) + src = 1; + else if (unformat (input, "dst %U", unformat_ip4_address, &dst_val)) + dst = 1; + else if (unformat (input, "proto %d", &proto_val)) + proto = 1; + else if (unformat (input, "tos %d", &tos_val)) + tos = 1; + else if (unformat (input, "length %d", &length_val)) + length = 1; + else if (unformat (input, "fragment_id %d", &fragment_id_val)) + fragment_id = 1; + else if (unformat (input, "ttl %d", &ttl_val)) + ttl = 1; + else if (unformat (input, "checksum %d", &checksum_val)) + checksum = 1; + else + break; + } + + if (version + hdr_length + src + dst + proto + tos + length + fragment_id + + ttl + checksum == 0) + return 0; + + /* + * Aligned because we use the real comparison functions + */ + vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4)); + + ip = (ip4_header_t *) match; + + /* These are realistically matched in practice */ + if (src) + ip->src_address.as_u32 = src_val.as_u32; + + if (dst) + ip->dst_address.as_u32 = dst_val.as_u32; + + if (proto) + ip->protocol = proto_val; + + + /* These are not, but they're included for completeness */ + if (version) + ip->ip_version_and_header_length |= (version_val & 0xF) << 4; + + if (hdr_length) + ip->ip_version_and_header_length |= (hdr_length_val & 0xF); + + if (tos) + ip->tos = tos_val; + + if (length) + ip->length = clib_host_to_net_u16 (length_val); + + if (ttl) + ip->ttl = ttl_val; + + if (checksum) + ip->checksum = clib_host_to_net_u16 (checksum_val); + + *matchp = match; + return 1; +} + +uword +unformat_ip6_match (unformat_input_t * input, va_list * args) +{ + u8 **matchp = va_arg (*args, u8 **); + u8 *match = 0; + ip6_header_t *ip; + int version = 0; + u32 version_val; + u8 traffic_class = 0; + u32 traffic_class_val = 0; + u8 flow_label = 0; + u8 flow_label_val; + int src = 0, dst = 0; + ip6_address_t src_val, dst_val; + int proto = 0; + u32 proto_val; + int payload_length = 0; + u32 payload_length_val; + int hop_limit = 0; + int hop_limit_val; + u32 ip_version_traffic_class_and_flow_label; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "version %d", &version_val)) + version = 1; + else if (unformat (input, "traffic_class %d", &traffic_class_val)) + traffic_class = 1; + else if (unformat (input, "flow_label %d", &flow_label_val)) + flow_label = 1; + else if (unformat (input, "src %U", unformat_ip6_address, &src_val)) + src = 1; + else if (unformat (input, "dst %U", unformat_ip6_address, &dst_val)) + dst = 1; + else if (unformat (input, "proto %d", &proto_val)) + proto = 1; + else if (unformat (input, "payload_length %d", &payload_length_val)) + payload_length = 1; + else if (unformat (input, "hop_limit %d", &hop_limit_val)) + hop_limit = 1; + else + break; + } + + if (version + traffic_class + flow_label + src + dst + proto + + payload_length + hop_limit == 0) + return 0; + + /* + * Aligned because we use the real comparison functions + */ + vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4)); + + ip = (ip6_header_t *) match; + + if (src) + clib_memcpy (&ip->src_address, &src_val, sizeof (ip->src_address)); + + if (dst) + clib_memcpy (&ip->dst_address, &dst_val, sizeof (ip->dst_address)); + + if (proto) + ip->protocol = proto_val; + + ip_version_traffic_class_and_flow_label = 0; + + if (version) + ip_version_traffic_class_and_flow_label |= (version_val & 0xF) << 28; + + if (traffic_class) + ip_version_traffic_class_and_flow_label |= + (traffic_class_val & 0xFF) << 20; + + if (flow_label) + ip_version_traffic_class_and_flow_label |= (flow_label_val & 0xFFFFF); + + ip->ip_version_traffic_class_and_flow_label = + clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label); + + if (payload_length) + ip->payload_length = clib_host_to_net_u16 (payload_length_val); + + if (hop_limit) + ip->hop_limit = hop_limit_val; + + *matchp = match; + return 1; +} + +uword +unformat_l3_match (unformat_input_t * input, va_list * args) +{ + u8 **matchp = va_arg (*args, u8 **); + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "ip4 %U", unformat_ip4_match, matchp)) + return 1; + else if (unformat (input, "ip6 %U", unformat_ip6_match, matchp)) + return 1; + else + break; + } + return 0; +} + +uword +unformat_vlan_tag (unformat_input_t * input, va_list * args) +{ + u8 *tagp = va_arg (*args, u8 *); + u32 tag; + + if (unformat (input, "%d", &tag)) + { + tagp[0] = (tag >> 8) & 0x0F; + tagp[1] = tag & 0xFF; + return 1; + } + + return 0; +} + +uword +unformat_l2_match (unformat_input_t * input, va_list * args) +{ + u8 **matchp = va_arg (*args, u8 **); + u8 *match = 0; + u8 src = 0; + u8 src_val[6]; + u8 dst = 0; + u8 dst_val[6]; + u8 proto = 0; + u16 proto_val; + u8 tag1 = 0; + u8 tag1_val[2]; + u8 tag2 = 0; + u8 tag2_val[2]; + int len = 14; + u8 ignore_tag1 = 0; + u8 ignore_tag2 = 0; + u8 cos1 = 0; + u8 cos2 = 0; + u32 cos1_val = 0; + u32 cos2_val = 0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "src %U", unformat_ethernet_address, &src_val)) + src = 1; + else + if (unformat (input, "dst %U", unformat_ethernet_address, &dst_val)) + dst = 1; + else if (unformat (input, "proto %U", + unformat_ethernet_type_host_byte_order, &proto_val)) + proto = 1; + else if (unformat (input, "tag1 %U", unformat_vlan_tag, tag1_val)) + tag1 = 1; + else if (unformat (input, "tag2 %U", unformat_vlan_tag, tag2_val)) + tag2 = 1; + else if (unformat (input, "ignore-tag1")) + ignore_tag1 = 1; + else if (unformat (input, "ignore-tag2")) + ignore_tag2 = 1; + else if (unformat (input, "cos1 %d", &cos1_val)) + cos1 = 1; + else if (unformat (input, "cos2 %d", &cos2_val)) + cos2 = 1; + else + break; + } + if ((src + dst + proto + tag1 + tag2 + + ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0) + return 0; + + if (tag1 || ignore_tag1 || cos1) + len = 18; + if (tag2 || ignore_tag2 || cos2) + len = 22; + + vec_validate_aligned (match, len - 1, sizeof (u32x4)); + + if (dst) + clib_memcpy (match, dst_val, 6); + + if (src) + clib_memcpy (match + 6, src_val, 6); + + if (tag2) + { + /* inner vlan tag */ + match[19] = tag2_val[1]; + match[18] = tag2_val[0]; + if (cos2) + match[18] |= (cos2_val & 0x7) << 5; + if (proto) + { + match[21] = proto_val & 0xff; + match[20] = proto_val >> 8; + } + if (tag1) + { + match[15] = tag1_val[1]; + match[14] = tag1_val[0]; + } + if (cos1) + match[14] |= (cos1_val & 0x7) << 5; + *matchp = match; + return 1; + } + if (tag1) + { + match[15] = tag1_val[1]; + match[14] = tag1_val[0]; + if (proto) + { + match[17] = proto_val & 0xff; + match[16] = proto_val >> 8; + } + if (cos1) + match[14] |= (cos1_val & 0x7) << 5; + + *matchp = match; + return 1; + } + if (cos2) + match[18] |= (cos2_val & 0x7) << 5; + if (cos1) + match[14] |= (cos1_val & 0x7) << 5; + if (proto) + { + match[13] = proto_val & 0xff; + match[12] = proto_val >> 8; + } + + *matchp = match; + return 1; +} + + +uword +unformat_classify_match (unformat_input_t * input, va_list * args) +{ + u8 **matchp = va_arg (*args, u8 **); + u32 skip_n_vectors = va_arg (*args, u32); + u32 match_n_vectors = va_arg (*args, u32); + + u8 *match = 0; + u8 *l2 = 0; + u8 *l3 = 0; + u8 *l4 = 0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "hex %U", unformat_hex_string, &match)) + ; + else if (unformat (input, "l2 %U", unformat_l2_match, &l2)) + ; + else if (unformat (input, "l3 %U", unformat_l3_match, &l3)) + ; + else if (unformat (input, "l4 %U", unformat_l4_match, &l4)) + ; + else + break; + } + + if (l4 && !l3) + { + vec_free (match); + vec_free (l2); + vec_free (l4); + return 0; + } + + if (match || l2 || l3 || l4) + { + if (l2 || l3 || l4) + { + /* "Win a free Ethernet header in every packet" */ + if (l2 == 0) + vec_validate_aligned (l2, 13, sizeof (u32x4)); + match = l2; + if (vec_len (l3)) + { + vec_append_aligned (match, l3, sizeof (u32x4)); + vec_free (l3); + } + if (vec_len (l4)) + { + vec_append_aligned (match, l4, sizeof (u32x4)); + vec_free (l4); + } + } + + /* Make sure the vector is big enough even if key is all 0's */ + vec_validate_aligned + (match, ((match_n_vectors + skip_n_vectors) * sizeof (u32x4)) - 1, + sizeof (u32x4)); + + /* Set size, include skipped vectors */ + _vec_len (match) = (match_n_vectors + skip_n_vectors) * sizeof (u32x4); + + *matchp = match; + + return 1; + } + + return 0; +} + +static int +api_classify_add_del_session (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_classify_add_del_session_t *mp; + int is_add = 1; + u32 table_index = ~0; + u32 hit_next_index = ~0; + u32 opaque_index = ~0; + u8 *match = 0; + i32 advance = 0; + f64 timeout; + u32 skip_n_vectors = 0; + u32 match_n_vectors = 0; + u32 action = 0; + u32 metadata = 0; + + /* + * Warning: you have to supply skip_n and match_n + * because the API client cant simply look at the classify + * table object. + */ + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "hit-next %U", unformat_ip_next_index, + &hit_next_index)) + ; + else if (unformat (i, "l2-hit-next %U", unformat_l2_next_index, + &hit_next_index)) + ; + else if (unformat (i, "acl-hit-next %U", unformat_acl_next_index, + &hit_next_index)) + ; + else if (unformat (i, "policer-hit-next %d", &hit_next_index)) + ; + else if (unformat (i, "%U", unformat_policer_precolor, &opaque_index)) + ; + else if (unformat (i, "opaque-index %d", &opaque_index)) + ; + else if (unformat (i, "skip_n %d", &skip_n_vectors)) + ; + else if (unformat (i, "match_n %d", &match_n_vectors)) + ; + else if (unformat (i, "match %U", unformat_classify_match, + &match, skip_n_vectors, match_n_vectors)) + ; + else if (unformat (i, "advance %d", &advance)) + ; + else if (unformat (i, "table-index %d", &table_index)) + ; + else if (unformat (i, "action set-ip4-fib-id %d", &metadata)) + action = 1; + else if (unformat (i, "action set-ip6-fib-id %d", &metadata)) + action = 2; + else if (unformat (i, "action %d", &action)) + ; + else if (unformat (i, "metadata %d", &metadata)) + ; + else + break; + } + + if (table_index == ~0) + { + errmsg ("Table index required"); + return -99; + } + + if (is_add && match == 0) + { + errmsg ("Match value required"); + return -99; + } + + M2 (CLASSIFY_ADD_DEL_SESSION, classify_add_del_session, vec_len (match)); + + mp->is_add = is_add; + mp->table_index = ntohl (table_index); + mp->hit_next_index = ntohl (hit_next_index); + mp->opaque_index = ntohl (opaque_index); + mp->advance = ntohl (advance); + mp->action = action; + mp->metadata = ntohl (metadata); + clib_memcpy (mp->match, match, vec_len (match)); + vec_free (match); + + S; + W; + /* NOTREACHED */ +} + +static int +api_classify_set_interface_ip_table (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_classify_set_interface_ip_table_t *mp; + f64 timeout; + u32 sw_if_index; + int sw_if_index_set; + u32 table_index = ~0; + u8 is_ipv6 = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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, "table %d", &table_index)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + + M (CLASSIFY_SET_INTERFACE_IP_TABLE, classify_set_interface_ip_table); + + mp->sw_if_index = ntohl (sw_if_index); + mp->table_index = ntohl (table_index); + mp->is_ipv6 = is_ipv6; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_classify_set_interface_l2_tables (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_classify_set_interface_l2_tables_t *mp; + f64 timeout; + u32 sw_if_index; + int sw_if_index_set; + u32 ip4_table_index = ~0; + u32 ip6_table_index = ~0; + u32 other_table_index = ~0; + u32 is_input = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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, "ip4-table %d", &ip4_table_index)) + ; + else if (unformat (i, "ip6-table %d", &ip6_table_index)) + ; + else if (unformat (i, "other-table %d", &other_table_index)) + ; + else if (unformat (i, "is-input %d", &is_input)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + + M (CLASSIFY_SET_INTERFACE_L2_TABLES, classify_set_interface_l2_tables); + + mp->sw_if_index = ntohl (sw_if_index); + mp->ip4_table_index = ntohl (ip4_table_index); + mp->ip6_table_index = ntohl (ip6_table_index); + mp->other_table_index = ntohl (other_table_index); + mp->is_input = (u8) is_input; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_set_ipfix_exporter (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_set_ipfix_exporter_t *mp; + ip4_address_t collector_address; + u8 collector_address_set = 0; + u32 collector_port = ~0; + ip4_address_t src_address; + u8 src_address_set = 0; + u32 vrf_id = ~0; + u32 path_mtu = ~0; + u32 template_interval = ~0; + u8 udp_checksum = 0; + f64 timeout; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "collector_address %U", unformat_ip4_address, + &collector_address)) + collector_address_set = 1; + else if (unformat (i, "collector_port %d", &collector_port)) + ; + else if (unformat (i, "src_address %U", unformat_ip4_address, + &src_address)) + src_address_set = 1; + else if (unformat (i, "vrf_id %d", &vrf_id)) + ; + else if (unformat (i, "path_mtu %d", &path_mtu)) + ; + else if (unformat (i, "template_interval %d", &template_interval)) + ; + else if (unformat (i, "udp_checksum")) + udp_checksum = 1; + else + break; + } + + if (collector_address_set == 0) + { + errmsg ("collector_address required"); + return -99; + } + + if (src_address_set == 0) + { + errmsg ("src_address required"); + return -99; + } + + M (SET_IPFIX_EXPORTER, set_ipfix_exporter); + + memcpy (mp->collector_address, collector_address.data, + sizeof (collector_address.data)); + mp->collector_port = htons ((u16) collector_port); + memcpy (mp->src_address, src_address.data, sizeof (src_address.data)); + mp->vrf_id = htonl (vrf_id); + mp->path_mtu = htonl (path_mtu); + mp->template_interval = htonl (template_interval); + mp->udp_checksum = udp_checksum; + + S; + W; + /* NOTREACHED */ +} + +static int +api_set_ipfix_classify_stream (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_set_ipfix_classify_stream_t *mp; + u32 domain_id = 0; + u32 src_port = UDP_DST_PORT_ipfix; + f64 timeout; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "domain %d", &domain_id)) + ; + else if (unformat (i, "src_port %d", &src_port)) + ; + else + { + errmsg ("unknown input `%U'", format_unformat_error, i); + return -99; + } + } + + M (SET_IPFIX_CLASSIFY_STREAM, set_ipfix_classify_stream); + + mp->domain_id = htonl (domain_id); + mp->src_port = htons ((u16) src_port); + + S; + W; + /* NOTREACHED */ +} + +static int +api_ipfix_classify_table_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ipfix_classify_table_add_del_t *mp; + int is_add = -1; + u32 classify_table_index = ~0; + u8 ip_version = 0; + u8 transport_protocol = 255; + f64 timeout; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "add")) + is_add = 1; + else if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "table %d", &classify_table_index)) + ; + else if (unformat (i, "ip4")) + ip_version = 4; + else if (unformat (i, "ip6")) + ip_version = 6; + else if (unformat (i, "tcp")) + transport_protocol = 6; + else if (unformat (i, "udp")) + transport_protocol = 17; + else + { + errmsg ("unknown input `%U'", format_unformat_error, i); + return -99; + } + } + + if (is_add == -1) + { + errmsg ("expecting: add|del"); + return -99; + } + if (classify_table_index == ~0) + { + errmsg ("classifier table not specified"); + return -99; + } + if (ip_version == 0) + { + errmsg ("IP version not specified"); + return -99; + } + + M (IPFIX_CLASSIFY_TABLE_ADD_DEL, ipfix_classify_table_add_del); + + mp->is_add = is_add; + mp->table_id = htonl (classify_table_index); + mp->ip_version = ip_version; + mp->transport_protocol = transport_protocol; + + S; + W; + /* NOTREACHED */ +} + +static int +api_get_node_index (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_get_node_index_t *mp; + f64 timeout; + u8 *name = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "node %s", &name)) + ; + else + break; + } + if (name == 0) + { + errmsg ("node name required"); + return -99; + } + if (vec_len (name) >= ARRAY_LEN (mp->node_name)) + { + errmsg ("node name too long, max %d", ARRAY_LEN (mp->node_name)); + return -99; + } + + M (GET_NODE_INDEX, get_node_index); + clib_memcpy (mp->node_name, name, vec_len (name)); + vec_free (name); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_get_next_index (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_get_next_index_t *mp; + f64 timeout; + u8 *node_name = 0, *next_node_name = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "node-name %s", &node_name)) + ; + else if (unformat (i, "next-node-name %s", &next_node_name)) + break; + } + + if (node_name == 0) + { + errmsg ("node name required"); + return -99; + } + if (vec_len (node_name) >= ARRAY_LEN (mp->node_name)) + { + errmsg ("node name too long, max %d", ARRAY_LEN (mp->node_name)); + return -99; + } + + if (next_node_name == 0) + { + errmsg ("next node name required"); + return -99; + } + if (vec_len (next_node_name) >= ARRAY_LEN (mp->next_name)) + { + errmsg ("next node name too long, max %d", ARRAY_LEN (mp->next_name)); + return -99; + } + + M (GET_NEXT_INDEX, get_next_index); + clib_memcpy (mp->node_name, node_name, vec_len (node_name)); + clib_memcpy (mp->next_name, next_node_name, vec_len (next_node_name)); + vec_free (node_name); + vec_free (next_node_name); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_add_node_next (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_add_node_next_t *mp; + f64 timeout; + u8 *name = 0; + u8 *next = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "node %s", &name)) + ; + else if (unformat (i, "next %s", &next)) + ; + else + break; + } + if (name == 0) + { + errmsg ("node name required"); + return -99; + } + if (vec_len (name) >= ARRAY_LEN (mp->node_name)) + { + errmsg ("node name too long, max %d", ARRAY_LEN (mp->node_name)); + return -99; + } + if (next == 0) + { + errmsg ("next node required"); + return -99; + } + if (vec_len (next) >= ARRAY_LEN (mp->next_name)) + { + errmsg ("next name too long, max %d", ARRAY_LEN (mp->next_name)); + return -99; + } + + M (ADD_NODE_NEXT, add_node_next); + clib_memcpy (mp->node_name, name, vec_len (name)); + clib_memcpy (mp->next_name, next, vec_len (next)); + vec_free (name); + vec_free (next); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_l2tpv3_create_tunnel (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + ip6_address_t client_address, our_address; + int client_address_set = 0; + int our_address_set = 0; + u32 local_session_id = 0; + u32 remote_session_id = 0; + u64 local_cookie = 0; + u64 remote_cookie = 0; + u8 l2_sublayer_present = 0; + vl_api_l2tpv3_create_tunnel_t *mp; + f64 timeout; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "client_address %U", unformat_ip6_address, + &client_address)) + client_address_set = 1; + else if (unformat (i, "our_address %U", unformat_ip6_address, + &our_address)) + our_address_set = 1; + else if (unformat (i, "local_session_id %d", &local_session_id)) + ; + else if (unformat (i, "remote_session_id %d", &remote_session_id)) + ; + else if (unformat (i, "local_cookie %lld", &local_cookie)) + ; + else if (unformat (i, "remote_cookie %lld", &remote_cookie)) + ; + else if (unformat (i, "l2-sublayer-present")) + l2_sublayer_present = 1; + else + break; + } + + if (client_address_set == 0) + { + errmsg ("client_address required"); + return -99; + } + + if (our_address_set == 0) + { + errmsg ("our_address required"); + return -99; + } + + M (L2TPV3_CREATE_TUNNEL, l2tpv3_create_tunnel); + + clib_memcpy (mp->client_address, client_address.as_u8, + sizeof (mp->client_address)); + + clib_memcpy (mp->our_address, our_address.as_u8, sizeof (mp->our_address)); + + mp->local_session_id = ntohl (local_session_id); + mp->remote_session_id = ntohl (remote_session_id); + mp->local_cookie = clib_host_to_net_u64 (local_cookie); + mp->remote_cookie = clib_host_to_net_u64 (remote_cookie); + mp->l2_sublayer_present = l2_sublayer_present; + mp->is_ipv6 = 1; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_l2tpv3_set_tunnel_cookies (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u64 new_local_cookie = 0; + u64 new_remote_cookie = 0; + vl_api_l2tpv3_set_tunnel_cookies_t *mp; + f64 timeout; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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, "new_local_cookie %lld", &new_local_cookie)) + ; + else if (unformat (i, "new_remote_cookie %lld", &new_remote_cookie)) + ; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (L2TPV3_SET_TUNNEL_COOKIES, l2tpv3_set_tunnel_cookies); + + mp->sw_if_index = ntohl (sw_if_index); + mp->new_local_cookie = clib_host_to_net_u64 (new_local_cookie); + mp->new_remote_cookie = clib_host_to_net_u64 (new_remote_cookie); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_l2tpv3_interface_enable_disable (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_l2tpv3_interface_enable_disable_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 enable_disable = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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, "enable")) + enable_disable = 1; + else if (unformat (i, "disable")) + enable_disable = 0; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (L2TPV3_INTERFACE_ENABLE_DISABLE, l2tpv3_interface_enable_disable); + + mp->sw_if_index = ntohl (sw_if_index); + mp->enable_disable = enable_disable; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_l2tpv3_set_lookup_key (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_l2tpv3_set_lookup_key_t *mp; + f64 timeout; + u8 key = ~0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "lookup_v6_src")) + key = L2T_LOOKUP_SRC_ADDRESS; + else if (unformat (i, "lookup_v6_dst")) + key = L2T_LOOKUP_DST_ADDRESS; + else if (unformat (i, "lookup_session_id")) + key = L2T_LOOKUP_SESSION_ID; + else + break; + } + + if (key == (u8) ~ 0) + { + errmsg ("l2tp session lookup key unset"); + return -99; + } + + M (L2TPV3_SET_LOOKUP_KEY, l2tpv3_set_lookup_key); + + mp->key = key; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static void vl_api_sw_if_l2tpv3_tunnel_details_t_handler + (vl_api_sw_if_l2tpv3_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "* %U (our) %U (client) (sw_if_index %d)", + format_ip6_address, mp->our_address, + format_ip6_address, mp->client_address, + clib_net_to_host_u32 (mp->sw_if_index)); + + print (vam->ofp, + " local cookies %016llx %016llx remote cookie %016llx", + clib_net_to_host_u64 (mp->local_cookie[0]), + clib_net_to_host_u64 (mp->local_cookie[1]), + clib_net_to_host_u64 (mp->remote_cookie)); + + print (vam->ofp, " local session-id %d remote session-id %d", + clib_net_to_host_u32 (mp->local_session_id), + clib_net_to_host_u32 (mp->remote_session_id)); + + print (vam->ofp, " l2 specific sublayer %s\n", + mp->l2_sublayer_present ? "preset" : "absent"); + +} + +static void vl_api_sw_if_l2tpv3_tunnel_details_t_handler_json + (vl_api_sw_if_l2tpv3_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + struct in6_addr addr; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + + clib_memcpy (&addr, mp->our_address, sizeof (addr)); + vat_json_object_add_ip6 (node, "our_address", addr); + clib_memcpy (&addr, mp->client_address, sizeof (addr)); + vat_json_object_add_ip6 (node, "client_address", addr); + + vat_json_node_t *lc = vat_json_object_add (node, "local_cookie"); + vat_json_init_array (lc); + vat_json_array_add_uint (lc, clib_net_to_host_u64 (mp->local_cookie[0])); + vat_json_array_add_uint (lc, clib_net_to_host_u64 (mp->local_cookie[1])); + vat_json_object_add_uint (node, "remote_cookie", + clib_net_to_host_u64 (mp->remote_cookie)); + + printf ("local id: %u", clib_net_to_host_u32 (mp->local_session_id)); + vat_json_object_add_uint (node, "local_session_id", + clib_net_to_host_u32 (mp->local_session_id)); + vat_json_object_add_uint (node, "remote_session_id", + clib_net_to_host_u32 (mp->remote_session_id)); + vat_json_object_add_string_copy (node, "l2_sublayer", + mp->l2_sublayer_present ? (u8 *) "present" + : (u8 *) "absent"); +} + +static int +api_sw_if_l2tpv3_tunnel_dump (vat_main_t * vam) +{ + vl_api_sw_if_l2tpv3_tunnel_dump_t *mp; + f64 timeout; + + /* Get list of l2tpv3-tunnel interfaces */ + M (SW_IF_L2TPV3_TUNNEL_DUMP, sw_if_l2tpv3_tunnel_dump); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + + +static void vl_api_sw_interface_tap_details_t_handler + (vl_api_sw_interface_tap_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%-16s %d", + mp->dev_name, clib_net_to_host_u32 (mp->sw_if_index)); +} + +static void vl_api_sw_interface_tap_details_t_handler_json + (vl_api_sw_interface_tap_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + vat_json_object_add_string_copy (node, "dev_name", mp->dev_name); +} + +static int +api_sw_interface_tap_dump (vat_main_t * vam) +{ + vl_api_sw_interface_tap_dump_t *mp; + f64 timeout; + + print (vam->ofp, "\n%-16s %s", "dev_name", "sw_if_index"); + /* Get list of tap interfaces */ + M (SW_INTERFACE_TAP_DUMP, sw_interface_tap_dump); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static uword unformat_vxlan_decap_next + (unformat_input_t * input, va_list * args) +{ + u32 *result = va_arg (*args, u32 *); + u32 tmp; + + if (unformat (input, "l2")) + *result = VXLAN_INPUT_NEXT_L2_INPUT; + else if (unformat (input, "%d", &tmp)) + *result = tmp; + else + return 0; + return 1; +} + +static int +api_vxlan_add_del_tunnel (vat_main_t * vam) +{ + unformat_input_t *line_input = vam->input; + vl_api_vxlan_add_del_tunnel_t *mp; + f64 timeout; + ip46_address_t src, dst; + u8 is_add = 1; + u8 ipv4_set = 0, ipv6_set = 0; + u8 src_set = 0; + u8 dst_set = 0; + u8 grp_set = 0; + u32 mcast_sw_if_index = ~0; + u32 encap_vrf_id = 0; + u32 decap_next_index = ~0; + u32 vni = 0; + + /* Can't "universally zero init" (={0}) due to GCC bug 53119 */ + memset (&src, 0, sizeof src); + memset (&dst, 0, sizeof dst); + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "del")) + is_add = 0; + else + if (unformat (line_input, "src %U", unformat_ip4_address, &src.ip4)) + { + ipv4_set = 1; + src_set = 1; + } + else + if (unformat (line_input, "dst %U", unformat_ip4_address, &dst.ip4)) + { + ipv4_set = 1; + dst_set = 1; + } + else + if (unformat (line_input, "src %U", unformat_ip6_address, &src.ip6)) + { + ipv6_set = 1; + src_set = 1; + } + else + if (unformat (line_input, "dst %U", unformat_ip6_address, &dst.ip6)) + { + ipv6_set = 1; + dst_set = 1; + } + else if (unformat (line_input, "group %U %U", + unformat_ip4_address, &dst.ip4, + api_unformat_sw_if_index, vam, &mcast_sw_if_index)) + { + grp_set = dst_set = 1; + ipv4_set = 1; + } + else if (unformat (line_input, "group %U", + unformat_ip4_address, &dst.ip4)) + { + grp_set = dst_set = 1; + ipv4_set = 1; + } + else if (unformat (line_input, "group %U %U", + unformat_ip6_address, &dst.ip6, + api_unformat_sw_if_index, vam, &mcast_sw_if_index)) + { + grp_set = dst_set = 1; + ipv6_set = 1; + } + else if (unformat (line_input, "group %U", + unformat_ip6_address, &dst.ip6)) + { + grp_set = dst_set = 1; + ipv6_set = 1; + } + else + if (unformat (line_input, "mcast_sw_if_index %u", &mcast_sw_if_index)) + ; + else if (unformat (line_input, "encap-vrf-id %d", &encap_vrf_id)) + ; + else if (unformat (line_input, "decap-next %U", + unformat_vxlan_decap_next, &decap_next_index)) + ; + else if (unformat (line_input, "vni %d", &vni)) + ; + else + { + errmsg ("parse error '%U'", format_unformat_error, line_input); + return -99; + } + } + + if (src_set == 0) + { + errmsg ("tunnel src address not specified"); + return -99; + } + if (dst_set == 0) + { + errmsg ("tunnel dst address not specified"); + return -99; + } + + if (grp_set && !ip46_address_is_multicast (&dst)) + { + errmsg ("tunnel group address not multicast"); + return -99; + } + if (grp_set && mcast_sw_if_index == ~0) + { + errmsg ("tunnel nonexistent multicast device"); + return -99; + } + if (grp_set == 0 && ip46_address_is_multicast (&dst)) + { + errmsg ("tunnel dst address must be unicast"); + return -99; + } + + + if (ipv4_set && ipv6_set) + { + errmsg ("both IPv4 and IPv6 addresses specified"); + return -99; + } + + if ((vni == 0) || (vni >> 24)) + { + errmsg ("vni not specified or out of range"); + return -99; + } + + M (VXLAN_ADD_DEL_TUNNEL, vxlan_add_del_tunnel); + + if (ipv6_set) + { + clib_memcpy (mp->src_address, &src.ip6, sizeof (src.ip6)); + clib_memcpy (mp->dst_address, &dst.ip6, sizeof (dst.ip6)); + } + else + { + clib_memcpy (mp->src_address, &src.ip4, sizeof (src.ip4)); + clib_memcpy (mp->dst_address, &dst.ip4, sizeof (dst.ip4)); + } + mp->encap_vrf_id = ntohl (encap_vrf_id); + mp->decap_next_index = ntohl (decap_next_index); + mp->mcast_sw_if_index = ntohl (mcast_sw_if_index); + mp->vni = ntohl (vni); + mp->is_add = is_add; + mp->is_ipv6 = ipv6_set; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static void vl_api_vxlan_tunnel_details_t_handler + (vl_api_vxlan_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + ip46_address_t src, dst; + + ip46_from_addr_buf (mp->is_ipv6, mp->src_address, &src); + ip46_from_addr_buf (mp->is_ipv6, mp->dst_address, &dst); + + print (vam->ofp, "%11d%24U%24U%14d%18d%13d%19d", + ntohl (mp->sw_if_index), + format_ip46_address, &src, IP46_TYPE_ANY, + format_ip46_address, &dst, IP46_TYPE_ANY, + ntohl (mp->encap_vrf_id), + ntohl (mp->decap_next_index), ntohl (mp->vni), + ntohl (mp->mcast_sw_if_index)); +} + +static void vl_api_vxlan_tunnel_details_t_handler_json + (vl_api_vxlan_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + if (mp->is_ipv6) + { + struct in6_addr ip6; + + clib_memcpy (&ip6, mp->src_address, sizeof (ip6)); + vat_json_object_add_ip6 (node, "src_address", ip6); + clib_memcpy (&ip6, mp->dst_address, sizeof (ip6)); + vat_json_object_add_ip6 (node, "dst_address", ip6); + } + else + { + struct in_addr ip4; + + clib_memcpy (&ip4, mp->src_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "src_address", ip4); + clib_memcpy (&ip4, mp->dst_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "dst_address", ip4); + } + vat_json_object_add_uint (node, "encap_vrf_id", ntohl (mp->encap_vrf_id)); + vat_json_object_add_uint (node, "decap_next_index", + ntohl (mp->decap_next_index)); + vat_json_object_add_uint (node, "vni", ntohl (mp->vni)); + vat_json_object_add_uint (node, "is_ipv6", mp->is_ipv6 ? 1 : 0); + vat_json_object_add_uint (node, "mcast_sw_if_index", + ntohl (mp->mcast_sw_if_index)); +} + +static int +api_vxlan_tunnel_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_vxlan_tunnel_dump_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + sw_if_index = ~0; + } + + if (!vam->json_output) + { + print (vam->ofp, "%11s%24s%24s%14s%18s%13s%19s", + "sw_if_index", "src_address", "dst_address", + "encap_vrf_id", "decap_next_index", "vni", "mcast_sw_if_index"); + } + + /* Get list of vxlan-tunnel interfaces */ + M (VXLAN_TUNNEL_DUMP, vxlan_tunnel_dump); + + mp->sw_if_index = htonl (sw_if_index); + + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static int +api_gre_add_del_tunnel (vat_main_t * vam) +{ + unformat_input_t *line_input = vam->input; + vl_api_gre_add_del_tunnel_t *mp; + f64 timeout; + ip4_address_t src4, dst4; + u8 is_add = 1; + u8 teb = 0; + u8 src_set = 0; + u8 dst_set = 0; + u32 outer_fib_id = 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "del")) + is_add = 0; + else if (unformat (line_input, "src %U", unformat_ip4_address, &src4)) + src_set = 1; + else if (unformat (line_input, "dst %U", unformat_ip4_address, &dst4)) + dst_set = 1; + else if (unformat (line_input, "outer-fib-id %d", &outer_fib_id)) + ; + else if (unformat (line_input, "teb")) + teb = 1; + else + { + errmsg ("parse error '%U'", format_unformat_error, line_input); + return -99; + } + } + + if (src_set == 0) + { + errmsg ("tunnel src address not specified"); + return -99; + } + if (dst_set == 0) + { + errmsg ("tunnel dst address not specified"); + return -99; + } + + + M (GRE_ADD_DEL_TUNNEL, gre_add_del_tunnel); + + clib_memcpy (&mp->src_address, &src4, sizeof (src4)); + clib_memcpy (&mp->dst_address, &dst4, sizeof (dst4)); + mp->outer_fib_id = ntohl (outer_fib_id); + mp->is_add = is_add; + mp->teb = teb; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static void vl_api_gre_tunnel_details_t_handler + (vl_api_gre_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%11d%15U%15U%6d%14d", + ntohl (mp->sw_if_index), + format_ip4_address, &mp->src_address, + format_ip4_address, &mp->dst_address, + mp->teb, ntohl (mp->outer_fib_id)); +} + +static void vl_api_gre_tunnel_details_t_handler_json + (vl_api_gre_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + struct in_addr ip4; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + clib_memcpy (&ip4, &mp->src_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "src_address", ip4); + clib_memcpy (&ip4, &mp->dst_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "dst_address", ip4); + vat_json_object_add_uint (node, "teb", mp->teb); + vat_json_object_add_uint (node, "outer_fib_id", ntohl (mp->outer_fib_id)); +} + +static int +api_gre_tunnel_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_gre_tunnel_dump_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + sw_if_index = ~0; + } + + if (!vam->json_output) + { + print (vam->ofp, "%11s%15s%15s%6s%14s", + "sw_if_index", "src_address", "dst_address", "teb", + "outer_fib_id"); + } + + /* Get list of gre-tunnel interfaces */ + M (GRE_TUNNEL_DUMP, gre_tunnel_dump); + + mp->sw_if_index = htonl (sw_if_index); + + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static int +api_l2_fib_clear_table (vat_main_t * vam) +{ +// unformat_input_t * i = vam->input; + vl_api_l2_fib_clear_table_t *mp; + f64 timeout; + + M (L2_FIB_CLEAR_TABLE, l2_fib_clear_table); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_l2_interface_efp_filter (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_l2_interface_efp_filter_t *mp; + f64 timeout; + u32 sw_if_index; + u8 enable = 1; + u8 sw_if_index_set = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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, "enable")) + enable = 1; + else if (unformat (i, "disable")) + enable = 0; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing sw_if_index"); + return -99; + } + + M (L2_INTERFACE_EFP_FILTER, l2_interface_efp_filter); + + mp->sw_if_index = ntohl (sw_if_index); + mp->enable_disable = enable; + + S; + W; + /* NOTREACHED */ + return 0; +} + +#define foreach_vtr_op \ +_("disable", L2_VTR_DISABLED) \ +_("push-1", L2_VTR_PUSH_1) \ +_("push-2", L2_VTR_PUSH_2) \ +_("pop-1", L2_VTR_POP_1) \ +_("pop-2", L2_VTR_POP_2) \ +_("translate-1-1", L2_VTR_TRANSLATE_1_1) \ +_("translate-1-2", L2_VTR_TRANSLATE_1_2) \ +_("translate-2-1", L2_VTR_TRANSLATE_2_1) \ +_("translate-2-2", L2_VTR_TRANSLATE_2_2) + +static int +api_l2_interface_vlan_tag_rewrite (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_l2_interface_vlan_tag_rewrite_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 vtr_op_set = 0; + u32 vtr_op = 0; + u32 push_dot1q = 1; + u32 tag1 = ~0; + u32 tag2 = ~0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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, "vtr_op %d", &vtr_op)) + vtr_op_set = 1; +#define _(n,v) else if (unformat(i, n)) {vtr_op = v; vtr_op_set = 1;} + foreach_vtr_op +#undef _ + else if (unformat (i, "push_dot1q %d", &push_dot1q)) + ; + else if (unformat (i, "tag1 %d", &tag1)) + ; + else if (unformat (i, "tag2 %d", &tag2)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if ((sw_if_index_set == 0) || (vtr_op_set == 0)) + { + errmsg ("missing vtr operation or sw_if_index"); + return -99; + } + + M (L2_INTERFACE_VLAN_TAG_REWRITE, l2_interface_vlan_tag_rewrite) + mp->sw_if_index = ntohl (sw_if_index); + mp->vtr_op = ntohl (vtr_op); + mp->push_dot1q = ntohl (push_dot1q); + mp->tag1 = ntohl (tag1); + mp->tag2 = ntohl (tag2); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_create_vhost_user_if (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_create_vhost_user_if_t *mp; + f64 timeout; + u8 *file_name; + u8 is_server = 0; + u8 file_name_set = 0; + u32 custom_dev_instance = ~0; + u8 hwaddr[6]; + u8 use_custom_mac = 0; + u8 *tag = 0; + + /* Shut up coverity */ + memset (hwaddr, 0, sizeof (hwaddr)); + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "socket %s", &file_name)) + { + file_name_set = 1; + } + else if (unformat (i, "renumber %" PRIu32, &custom_dev_instance)) + ; + else if (unformat (i, "mac %U", unformat_ethernet_address, hwaddr)) + use_custom_mac = 1; + else if (unformat (i, "server")) + is_server = 1; + else if (unformat (i, "tag %s", &tag)) + ; + else + break; + } + + if (file_name_set == 0) + { + errmsg ("missing socket file name"); + return -99; + } + + if (vec_len (file_name) > 255) + { + errmsg ("socket file name too long"); + return -99; + } + vec_add1 (file_name, 0); + + M (CREATE_VHOST_USER_IF, create_vhost_user_if); + + mp->is_server = is_server; + clib_memcpy (mp->sock_filename, file_name, vec_len (file_name)); + vec_free (file_name); + if (custom_dev_instance != ~0) + { + mp->renumber = 1; + mp->custom_dev_instance = ntohl (custom_dev_instance); + } + mp->use_custom_mac = use_custom_mac; + clib_memcpy (mp->mac_address, hwaddr, 6); + if (tag) + strncpy ((char *) mp->tag, (char *) tag, ARRAY_LEN (mp->tag) - 1); + vec_free (tag); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_modify_vhost_user_if (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_modify_vhost_user_if_t *mp; + f64 timeout; + u8 *file_name; + u8 is_server = 0; + u8 file_name_set = 0; + u32 custom_dev_instance = ~0; + u8 sw_if_index_set = 0; + u32 sw_if_index = (u32) ~ 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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, "socket %s", &file_name)) + { + file_name_set = 1; + } + else if (unformat (i, "renumber %" PRIu32, &custom_dev_instance)) + ; + else if (unformat (i, "server")) + is_server = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing sw_if_index or interface name"); + return -99; + } + + if (file_name_set == 0) + { + errmsg ("missing socket file name"); + return -99; + } + + if (vec_len (file_name) > 255) + { + errmsg ("socket file name too long"); + return -99; + } + vec_add1 (file_name, 0); + + M (MODIFY_VHOST_USER_IF, modify_vhost_user_if); + + mp->sw_if_index = ntohl (sw_if_index); + mp->is_server = is_server; + clib_memcpy (mp->sock_filename, file_name, vec_len (file_name)); + vec_free (file_name); + if (custom_dev_instance != ~0) + { + mp->renumber = 1; + mp->custom_dev_instance = ntohl (custom_dev_instance); + } + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_delete_vhost_user_if (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_delete_vhost_user_if_t *mp; + f64 timeout; + u32 sw_if_index = ~0; + u8 sw_if_index_set = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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 + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing sw_if_index or interface name"); + return -99; + } + + + M (DELETE_VHOST_USER_IF, delete_vhost_user_if); + + mp->sw_if_index = ntohl (sw_if_index); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static void vl_api_sw_interface_vhost_user_details_t_handler + (vl_api_sw_interface_vhost_user_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%-25s %3" PRIu32 " %6" PRIu32 " %8x %6d %7d %s", + (char *) mp->interface_name, + ntohl (mp->sw_if_index), ntohl (mp->virtio_net_hdr_sz), + clib_net_to_host_u64 (mp->features), mp->is_server, + ntohl (mp->num_regions), (char *) mp->sock_filename); + print (vam->ofp, " Status: '%s'", strerror (ntohl (mp->sock_errno))); +} + +static void vl_api_sw_interface_vhost_user_details_t_handler_json + (vl_api_sw_interface_vhost_user_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + vat_json_object_add_string_copy (node, "interface_name", + mp->interface_name); + vat_json_object_add_uint (node, "virtio_net_hdr_sz", + ntohl (mp->virtio_net_hdr_sz)); + vat_json_object_add_uint (node, "features", + clib_net_to_host_u64 (mp->features)); + vat_json_object_add_uint (node, "is_server", mp->is_server); + vat_json_object_add_string_copy (node, "sock_filename", mp->sock_filename); + vat_json_object_add_uint (node, "num_regions", ntohl (mp->num_regions)); + vat_json_object_add_uint (node, "sock_errno", ntohl (mp->sock_errno)); +} + +static int +api_sw_interface_vhost_user_dump (vat_main_t * vam) +{ + vl_api_sw_interface_vhost_user_dump_t *mp; + f64 timeout; + print (vam->ofp, + "Interface name idx hdr_sz features server regions filename"); + + /* Get list of vhost-user interfaces */ + M (SW_INTERFACE_VHOST_USER_DUMP, sw_interface_vhost_user_dump); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static int +api_show_version (vat_main_t * vam) +{ + vl_api_show_version_t *mp; + f64 timeout; + + M (SHOW_VERSION, show_version); + + S; + W; + /* NOTREACHED */ + return 0; +} + + +static int +api_vxlan_gpe_add_del_tunnel (vat_main_t * vam) +{ + unformat_input_t *line_input = vam->input; + vl_api_vxlan_gpe_add_del_tunnel_t *mp; + f64 timeout; + ip4_address_t local4, remote4; + ip6_address_t local6, remote6; + u8 is_add = 1; + u8 ipv4_set = 0, ipv6_set = 0; + u8 local_set = 0; + u8 remote_set = 0; + u32 encap_vrf_id = 0; + u32 decap_vrf_id = 0; + u8 protocol = ~0; + u32 vni; + u8 vni_set = 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "del")) + is_add = 0; + else 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, "encap-vrf-id %d", &encap_vrf_id)) + ; + else if (unformat (line_input, "decap-vrf-id %d", &decap_vrf_id)) + ; + else if (unformat (line_input, "vni %d", &vni)) + vni_set = 1; + else if (unformat (line_input, "next-ip4")) + protocol = 1; + else if (unformat (line_input, "next-ip6")) + protocol = 2; + else if (unformat (line_input, "next-ethernet")) + protocol = 3; + else if (unformat (line_input, "next-nsh")) + protocol = 4; + else + { + errmsg ("parse error '%U'", format_unformat_error, line_input); + return -99; + } + } + + if (local_set == 0) + { + errmsg ("tunnel local address not specified"); + return -99; + } + if (remote_set == 0) + { + errmsg ("tunnel remote address not specified"); + return -99; + } + if (ipv4_set && ipv6_set) + { + errmsg ("both IPv4 and IPv6 addresses specified"); + return -99; + } + + if (vni_set == 0) + { + errmsg ("vni not specified"); + return -99; + } + + M (VXLAN_GPE_ADD_DEL_TUNNEL, vxlan_gpe_add_del_tunnel); + + + 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->encap_vrf_id = ntohl (encap_vrf_id); + mp->decap_vrf_id = ntohl (decap_vrf_id); + mp->protocol = protocol; + mp->vni = ntohl (vni); + mp->is_add = is_add; + mp->is_ipv6 = ipv6_set; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static void vl_api_vxlan_gpe_tunnel_details_t_handler + (vl_api_vxlan_gpe_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%11d%24U%24U%13d%12d%14d%14d", + ntohl (mp->sw_if_index), + format_ip46_address, &(mp->local[0]), + format_ip46_address, &(mp->remote[0]), + ntohl (mp->vni), + ntohl (mp->protocol), + ntohl (mp->encap_vrf_id), ntohl (mp->decap_vrf_id)); +} + +static void vl_api_vxlan_gpe_tunnel_details_t_handler_json + (vl_api_vxlan_gpe_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + struct in_addr ip4; + struct in6_addr ip6; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + if (mp->is_ipv6) + { + clib_memcpy (&ip6, &(mp->local[0]), sizeof (ip6)); + vat_json_object_add_ip6 (node, "local", ip6); + clib_memcpy (&ip6, &(mp->remote[0]), sizeof (ip6)); + vat_json_object_add_ip6 (node, "remote", ip6); + } + else + { + clib_memcpy (&ip4, &(mp->local[0]), sizeof (ip4)); + vat_json_object_add_ip4 (node, "local", ip4); + clib_memcpy (&ip4, &(mp->remote[0]), sizeof (ip4)); + vat_json_object_add_ip4 (node, "remote", ip4); + } + vat_json_object_add_uint (node, "vni", ntohl (mp->vni)); + vat_json_object_add_uint (node, "protocol", ntohl (mp->protocol)); + vat_json_object_add_uint (node, "encap_vrf_id", ntohl (mp->encap_vrf_id)); + vat_json_object_add_uint (node, "decap_vrf_id", ntohl (mp->decap_vrf_id)); + vat_json_object_add_uint (node, "is_ipv6", mp->is_ipv6 ? 1 : 0); +} + +static int +api_vxlan_gpe_tunnel_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_vxlan_gpe_tunnel_dump_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + sw_if_index = ~0; + } + + if (!vam->json_output) + { + print (vam->ofp, "%11s%24s%24s%13s%15s%14s%14s", + "sw_if_index", "local", "remote", "vni", + "protocol", "encap_vrf_id", "decap_vrf_id"); + } + + /* Get list of vxlan-tunnel interfaces */ + M (VXLAN_GPE_TUNNEL_DUMP, vxlan_gpe_tunnel_dump); + + mp->sw_if_index = htonl (sw_if_index); + + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +u8 * +format_l2_fib_mac_address (u8 * s, va_list * args) +{ + u8 *a = va_arg (*args, u8 *); + + return format (s, "%02x:%02x:%02x:%02x:%02x:%02x", + a[2], a[3], a[4], a[5], a[6], a[7]); +} + +static void vl_api_l2_fib_table_entry_t_handler + (vl_api_l2_fib_table_entry_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%3" PRIu32 " %U %3" PRIu32 + " %d %d %d", + ntohl (mp->bd_id), format_l2_fib_mac_address, &mp->mac, + ntohl (mp->sw_if_index), mp->static_mac, mp->filter_mac, + mp->bvi_mac); +} + +static void vl_api_l2_fib_table_entry_t_handler_json + (vl_api_l2_fib_table_entry_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "bd_id", ntohl (mp->bd_id)); + vat_json_object_add_uint (node, "mac", clib_net_to_host_u64 (mp->mac)); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + vat_json_object_add_uint (node, "static_mac", mp->static_mac); + vat_json_object_add_uint (node, "filter_mac", mp->filter_mac); + vat_json_object_add_uint (node, "bvi_mac", mp->bvi_mac); +} + +static int +api_l2_fib_table_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_l2_fib_table_dump_t *mp; + f64 timeout; + u32 bd_id; + u8 bd_id_set = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "bd_id %d", &bd_id)) + bd_id_set = 1; + else + break; + } + + if (bd_id_set == 0) + { + errmsg ("missing bridge domain"); + return -99; + } + + print (vam->ofp, "BD-ID Mac Address sw-ndx Static Filter BVI"); + + /* Get list of l2 fib entries */ + M (L2_FIB_TABLE_DUMP, l2_fib_table_dump); + + mp->bd_id = ntohl (bd_id); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + + +static int +api_interface_name_renumber (vat_main_t * vam) +{ + unformat_input_t *line_input = vam->input; + vl_api_interface_name_renumber_t *mp; + u32 sw_if_index = ~0; + f64 timeout; + u32 new_show_dev_instance = ~0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "%U", api_unformat_sw_if_index, vam, + &sw_if_index)) + ; + else if (unformat (line_input, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (line_input, "new_show_dev_instance %d", + &new_show_dev_instance)) + ; + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (new_show_dev_instance == ~0) + { + errmsg ("missing new_show_dev_instance"); + return -99; + } + + M (INTERFACE_NAME_RENUMBER, interface_name_renumber); + + mp->sw_if_index = ntohl (sw_if_index); + mp->new_show_dev_instance = ntohl (new_show_dev_instance); + + S; + W; +} + +static int +api_want_ip4_arp_events (vat_main_t * vam) +{ + unformat_input_t *line_input = vam->input; + vl_api_want_ip4_arp_events_t *mp; + f64 timeout; + ip4_address_t address; + int address_set = 0; + u32 enable_disable = 1; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "address %U", unformat_ip4_address, &address)) + address_set = 1; + else if (unformat (line_input, "del")) + enable_disable = 0; + else + break; + } + + if (address_set == 0) + { + errmsg ("missing addresses"); + return -99; + } + + M (WANT_IP4_ARP_EVENTS, want_ip4_arp_events); + mp->enable_disable = enable_disable; + mp->pid = getpid (); + mp->address = address.as_u32; + + S; + W; +} + +static int +api_want_ip6_nd_events (vat_main_t * vam) +{ + unformat_input_t *line_input = vam->input; + vl_api_want_ip6_nd_events_t *mp; + f64 timeout; + ip6_address_t address; + int address_set = 0; + u32 enable_disable = 1; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "address %U", unformat_ip6_address, &address)) + address_set = 1; + else if (unformat (line_input, "del")) + enable_disable = 0; + else + break; + } + + if (address_set == 0) + { + errmsg ("missing addresses"); + return -99; + } + + M (WANT_IP6_ND_EVENTS, want_ip6_nd_events); + mp->enable_disable = enable_disable; + mp->pid = getpid (); + clib_memcpy (mp->address, &address, sizeof (ip6_address_t)); + + S; + W; +} + +static int +api_input_acl_set_interface (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_input_acl_set_interface_t *mp; + f64 timeout; + u32 sw_if_index; + int sw_if_index_set; + u32 ip4_table_index = ~0; + u32 ip6_table_index = ~0; + u32 l2_table_index = ~0; + u8 is_add = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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, "del")) + is_add = 0; + else if (unformat (i, "ip4-table %d", &ip4_table_index)) + ; + else if (unformat (i, "ip6-table %d", &ip6_table_index)) + ; + else if (unformat (i, "l2-table %d", &l2_table_index)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (INPUT_ACL_SET_INTERFACE, input_acl_set_interface); + + mp->sw_if_index = ntohl (sw_if_index); + mp->ip4_table_index = ntohl (ip4_table_index); + mp->ip6_table_index = ntohl (ip6_table_index); + mp->l2_table_index = ntohl (l2_table_index); + mp->is_add = is_add; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ip_address_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ip_address_dump_t *mp; + u32 sw_if_index = ~0; + u8 sw_if_index_set = 0; + u8 ipv4_set = 0; + u8 ipv6_set = 0; + f64 timeout; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "ipv4")) + ipv4_set = 1; + else if (unformat (i, "ipv6")) + ipv6_set = 1; + else + break; + } + + if (ipv4_set && ipv6_set) + { + errmsg ("ipv4 and ipv6 flags cannot be both set"); + return -99; + } + + if ((!ipv4_set) && (!ipv6_set)) + { + errmsg ("no ipv4 nor ipv6 flag set"); + return -99; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + vam->current_sw_if_index = sw_if_index; + vam->is_ipv6 = ipv6_set; + + M (IP_ADDRESS_DUMP, ip_address_dump); + mp->sw_if_index = ntohl (sw_if_index); + mp->is_ipv6 = ipv6_set; + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static int +api_ip_dump (vat_main_t * vam) +{ + vl_api_ip_dump_t *mp; + unformat_input_t *in = vam->input; + int ipv4_set = 0; + int ipv6_set = 0; + int is_ipv6; + f64 timeout; + int i; + + while (unformat_check_input (in) != UNFORMAT_END_OF_INPUT) + { + if (unformat (in, "ipv4")) + ipv4_set = 1; + else if (unformat (in, "ipv6")) + ipv6_set = 1; + else + break; + } + + if (ipv4_set && ipv6_set) + { + errmsg ("ipv4 and ipv6 flags cannot be both set"); + return -99; + } + + if ((!ipv4_set) && (!ipv6_set)) + { + errmsg ("no ipv4 nor ipv6 flag set"); + return -99; + } + + is_ipv6 = ipv6_set; + vam->is_ipv6 = is_ipv6; + + /* free old data */ + for (i = 0; i < vec_len (vam->ip_details_by_sw_if_index[is_ipv6]); i++) + { + vec_free (vam->ip_details_by_sw_if_index[is_ipv6][i].addr); + } + vec_free (vam->ip_details_by_sw_if_index[is_ipv6]); + + M (IP_DUMP, ip_dump); + mp->is_ipv6 = ipv6_set; + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static int +api_ipsec_spd_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ipsec_spd_add_del_t *mp; + f64 timeout; + u32 spd_id = ~0; + u8 is_add = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "spd_id %d", &spd_id)) + ; + else if (unformat (i, "del")) + is_add = 0; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + if (spd_id == ~0) + { + errmsg ("spd_id must be set"); + return -99; + } + + M (IPSEC_SPD_ADD_DEL, ipsec_spd_add_del); + + mp->spd_id = ntohl (spd_id); + mp->is_add = is_add; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ipsec_interface_add_del_spd (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ipsec_interface_add_del_spd_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u32 spd_id = (u32) ~ 0; + u8 is_add = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "spd_id %d", &spd_id)) + ; + else + if (unformat (i, "%U", api_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 + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + + } + + if (spd_id == (u32) ~ 0) + { + errmsg ("spd_id must be set"); + return -99; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (IPSEC_INTERFACE_ADD_DEL_SPD, ipsec_interface_add_del_spd); + + mp->spd_id = ntohl (spd_id); + mp->sw_if_index = ntohl (sw_if_index); + mp->is_add = is_add; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ipsec_spd_add_del_entry (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ipsec_spd_add_del_entry_t *mp; + f64 timeout; + u8 is_add = 1, is_outbound = 0, is_ipv6 = 0, is_ip_any = 1; + u32 spd_id = 0, sa_id = 0, protocol = 0, policy = 0; + i32 priority = 0; + u32 rport_start = 0, rport_stop = (u32) ~ 0; + u32 lport_start = 0, lport_stop = (u32) ~ 0; + ip4_address_t laddr4_start, laddr4_stop, raddr4_start, raddr4_stop; + ip6_address_t laddr6_start, laddr6_stop, raddr6_start, raddr6_stop; + + laddr4_start.as_u32 = raddr4_start.as_u32 = 0; + laddr4_stop.as_u32 = raddr4_stop.as_u32 = (u32) ~ 0; + laddr6_start.as_u64[0] = raddr6_start.as_u64[0] = 0; + laddr6_start.as_u64[1] = raddr6_start.as_u64[1] = 0; + laddr6_stop.as_u64[0] = raddr6_stop.as_u64[0] = (u64) ~ 0; + laddr6_stop.as_u64[1] = raddr6_stop.as_u64[1] = (u64) ~ 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_add = 0; + if (unformat (i, "outbound")) + is_outbound = 1; + if (unformat (i, "inbound")) + is_outbound = 0; + else if (unformat (i, "spd_id %d", &spd_id)) + ; + else if (unformat (i, "sa_id %d", &sa_id)) + ; + else if (unformat (i, "priority %d", &priority)) + ; + else if (unformat (i, "protocol %d", &protocol)) + ; + else if (unformat (i, "lport_start %d", &lport_start)) + ; + else if (unformat (i, "lport_stop %d", &lport_stop)) + ; + else if (unformat (i, "rport_start %d", &rport_start)) + ; + else if (unformat (i, "rport_stop %d", &rport_stop)) + ; + else + if (unformat + (i, "laddr_start %U", unformat_ip4_address, &laddr4_start)) + { + is_ipv6 = 0; + is_ip_any = 0; + } + else + if (unformat (i, "laddr_stop %U", unformat_ip4_address, &laddr4_stop)) + { + is_ipv6 = 0; + is_ip_any = 0; + } + else + if (unformat + (i, "raddr_start %U", unformat_ip4_address, &raddr4_start)) + { + is_ipv6 = 0; + is_ip_any = 0; + } + else + if (unformat (i, "raddr_stop %U", unformat_ip4_address, &raddr4_stop)) + { + is_ipv6 = 0; + is_ip_any = 0; + } + else + if (unformat + (i, "laddr_start %U", unformat_ip6_address, &laddr6_start)) + { + is_ipv6 = 1; + is_ip_any = 0; + } + else + if (unformat (i, "laddr_stop %U", unformat_ip6_address, &laddr6_stop)) + { + is_ipv6 = 1; + is_ip_any = 0; + } + else + if (unformat + (i, "raddr_start %U", unformat_ip6_address, &raddr6_start)) + { + is_ipv6 = 1; + is_ip_any = 0; + } + else + if (unformat (i, "raddr_stop %U", unformat_ip6_address, &raddr6_stop)) + { + is_ipv6 = 1; + is_ip_any = 0; + } + else + if (unformat (i, "action %U", unformat_ipsec_policy_action, &policy)) + { + if (policy == IPSEC_POLICY_ACTION_RESOLVE) + { + clib_warning ("unsupported action: 'resolve'"); + return -99; + } + } + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + + } + + M (IPSEC_SPD_ADD_DEL_ENTRY, ipsec_spd_add_del_entry); + + mp->spd_id = ntohl (spd_id); + mp->priority = ntohl (priority); + mp->is_outbound = is_outbound; + + mp->is_ipv6 = is_ipv6; + if (is_ipv6 || is_ip_any) + { + clib_memcpy (mp->remote_address_start, &raddr6_start, + sizeof (ip6_address_t)); + clib_memcpy (mp->remote_address_stop, &raddr6_stop, + sizeof (ip6_address_t)); + clib_memcpy (mp->local_address_start, &laddr6_start, + sizeof (ip6_address_t)); + clib_memcpy (mp->local_address_stop, &laddr6_stop, + sizeof (ip6_address_t)); + } + else + { + clib_memcpy (mp->remote_address_start, &raddr4_start, + sizeof (ip4_address_t)); + clib_memcpy (mp->remote_address_stop, &raddr4_stop, + sizeof (ip4_address_t)); + clib_memcpy (mp->local_address_start, &laddr4_start, + sizeof (ip4_address_t)); + clib_memcpy (mp->local_address_stop, &laddr4_stop, + sizeof (ip4_address_t)); + } + mp->protocol = (u8) protocol; + mp->local_port_start = ntohs ((u16) lport_start); + mp->local_port_stop = ntohs ((u16) lport_stop); + mp->remote_port_start = ntohs ((u16) rport_start); + mp->remote_port_stop = ntohs ((u16) rport_stop); + mp->policy = (u8) policy; + mp->sa_id = ntohl (sa_id); + mp->is_add = is_add; + mp->is_ip_any = is_ip_any; + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ipsec_sad_add_del_entry (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ipsec_sad_add_del_entry_t *mp; + f64 timeout; + u32 sad_id = 0, spi = 0; + u8 *ck = 0, *ik = 0; + u8 is_add = 1; + + u8 protocol = IPSEC_PROTOCOL_AH; + u8 is_tunnel = 0, is_tunnel_ipv6 = 0; + u32 crypto_alg = 0, integ_alg = 0; + ip4_address_t tun_src4; + ip4_address_t tun_dst4; + ip6_address_t tun_src6; + ip6_address_t tun_dst6; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "sad_id %d", &sad_id)) + ; + else if (unformat (i, "spi %d", &spi)) + ; + else if (unformat (i, "esp")) + protocol = IPSEC_PROTOCOL_ESP; + else if (unformat (i, "tunnel_src %U", unformat_ip4_address, &tun_src4)) + { + is_tunnel = 1; + is_tunnel_ipv6 = 0; + } + else if (unformat (i, "tunnel_dst %U", unformat_ip4_address, &tun_dst4)) + { + is_tunnel = 1; + is_tunnel_ipv6 = 0; + } + else if (unformat (i, "tunnel_src %U", unformat_ip6_address, &tun_src6)) + { + is_tunnel = 1; + is_tunnel_ipv6 = 1; + } + else if (unformat (i, "tunnel_dst %U", unformat_ip6_address, &tun_dst6)) + { + is_tunnel = 1; + is_tunnel_ipv6 = 1; + } + else + if (unformat + (i, "crypto_alg %U", unformat_ipsec_crypto_alg, &crypto_alg)) + { + if (crypto_alg < IPSEC_CRYPTO_ALG_AES_CBC_128 || + crypto_alg >= IPSEC_CRYPTO_N_ALG) + { + clib_warning ("unsupported crypto-alg: '%U'", + format_ipsec_crypto_alg, crypto_alg); + return -99; + } + } + else if (unformat (i, "crypto_key %U", unformat_hex_string, &ck)) + ; + else + if (unformat + (i, "integ_alg %U", unformat_ipsec_integ_alg, &integ_alg)) + { +#if DPDK_CRYPTO==1 + if (integ_alg < IPSEC_INTEG_ALG_NONE || +#else + if (integ_alg < IPSEC_INTEG_ALG_SHA1_96 || +#endif + integ_alg >= IPSEC_INTEG_N_ALG) + { + clib_warning ("unsupported integ-alg: '%U'", + format_ipsec_integ_alg, integ_alg); + return -99; + } + } + else if (unformat (i, "integ_key %U", unformat_hex_string, &ik)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + + } + +#if DPDK_CRYPTO==1 + /*Special cases, aes-gcm-128 encryption */ + if (crypto_alg == IPSEC_CRYPTO_ALG_AES_GCM_128) + { + if (integ_alg != IPSEC_INTEG_ALG_NONE + && integ_alg != IPSEC_INTEG_ALG_AES_GCM_128) + { + clib_warning + ("unsupported: aes-gcm-128 crypto-alg needs none as integ-alg"); + return -99; + } + else /*set integ-alg internally to aes-gcm-128 */ + integ_alg = IPSEC_INTEG_ALG_AES_GCM_128; + } + else if (integ_alg == IPSEC_INTEG_ALG_AES_GCM_128) + { + clib_warning ("unsupported integ-alg: aes-gcm-128"); + return -99; + } + else if (integ_alg == IPSEC_INTEG_ALG_NONE) + { + clib_warning ("unsupported integ-alg: none"); + return -99; + } +#endif + + + M (IPSEC_SAD_ADD_DEL_ENTRY, ipsec_sad_add_del_entry); + + mp->sad_id = ntohl (sad_id); + mp->is_add = is_add; + mp->protocol = protocol; + mp->spi = ntohl (spi); + mp->is_tunnel = is_tunnel; + mp->is_tunnel_ipv6 = is_tunnel_ipv6; + mp->crypto_algorithm = crypto_alg; + mp->integrity_algorithm = integ_alg; + mp->crypto_key_length = vec_len (ck); + mp->integrity_key_length = vec_len (ik); + + if (mp->crypto_key_length > sizeof (mp->crypto_key)) + mp->crypto_key_length = sizeof (mp->crypto_key); + + if (mp->integrity_key_length > sizeof (mp->integrity_key)) + mp->integrity_key_length = sizeof (mp->integrity_key); + + if (ck) + clib_memcpy (mp->crypto_key, ck, mp->crypto_key_length); + if (ik) + clib_memcpy (mp->integrity_key, ik, mp->integrity_key_length); + + if (is_tunnel) + { + if (is_tunnel_ipv6) + { + clib_memcpy (mp->tunnel_src_address, &tun_src6, + sizeof (ip6_address_t)); + clib_memcpy (mp->tunnel_dst_address, &tun_dst6, + sizeof (ip6_address_t)); + } + else + { + clib_memcpy (mp->tunnel_src_address, &tun_src4, + sizeof (ip4_address_t)); + clib_memcpy (mp->tunnel_dst_address, &tun_dst4, + sizeof (ip4_address_t)); + } + } + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ipsec_sa_set_key (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ipsec_sa_set_key_t *mp; + f64 timeout; + u32 sa_id; + u8 *ck = 0, *ik = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sa_id %d", &sa_id)) + ; + else if (unformat (i, "crypto_key %U", unformat_hex_string, &ck)) + ; + else if (unformat (i, "integ_key %U", unformat_hex_string, &ik)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + M (IPSEC_SA_SET_KEY, ipsec_set_sa_key); + + mp->sa_id = ntohl (sa_id); + mp->crypto_key_length = vec_len (ck); + mp->integrity_key_length = vec_len (ik); + + if (mp->crypto_key_length > sizeof (mp->crypto_key)) + mp->crypto_key_length = sizeof (mp->crypto_key); + + if (mp->integrity_key_length > sizeof (mp->integrity_key)) + mp->integrity_key_length = sizeof (mp->integrity_key); + + if (ck) + clib_memcpy (mp->crypto_key, ck, mp->crypto_key_length); + if (ik) + clib_memcpy (mp->integrity_key, ik, mp->integrity_key_length); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ikev2_profile_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ikev2_profile_add_del_t *mp; + f64 timeout; + u8 is_add = 1; + u8 *name = 0; + + const char *valid_chars = "a-zA-Z0-9_"; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "name %U", unformat_token, valid_chars, &name)) + vec_add1 (name, 0); + else + { + errmsg ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!vec_len (name)) + { + errmsg ("profile name must be specified"); + return -99; + } + + if (vec_len (name) > 64) + { + errmsg ("profile name too long"); + return -99; + } + + M (IKEV2_PROFILE_ADD_DEL, ikev2_profile_add_del); + + clib_memcpy (mp->name, name, vec_len (name)); + mp->is_add = is_add; + vec_free (name); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ikev2_profile_set_auth (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ikev2_profile_set_auth_t *mp; + f64 timeout; + u8 *name = 0; + u8 *data = 0; + u32 auth_method = 0; + u8 is_hex = 0; + + const char *valid_chars = "a-zA-Z0-9_"; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "name %U", unformat_token, valid_chars, &name)) + vec_add1 (name, 0); + else if (unformat (i, "auth_method %U", + unformat_ikev2_auth_method, &auth_method)) + ; + else if (unformat (i, "auth_data 0x%U", unformat_hex_string, &data)) + is_hex = 1; + else if (unformat (i, "auth_data %v", &data)) + ; + else + { + errmsg ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!vec_len (name)) + { + errmsg ("profile name must be specified"); + return -99; + } + + if (vec_len (name) > 64) + { + errmsg ("profile name too long"); + return -99; + } + + if (!vec_len (data)) + { + errmsg ("auth_data must be specified"); + return -99; + } + + if (!auth_method) + { + errmsg ("auth_method must be specified"); + return -99; + } + + M (IKEV2_PROFILE_SET_AUTH, ikev2_profile_set_auth); + + mp->is_hex = is_hex; + mp->auth_method = (u8) auth_method; + mp->data_len = vec_len (data); + clib_memcpy (mp->name, name, vec_len (name)); + clib_memcpy (mp->data, data, vec_len (data)); + vec_free (name); + vec_free (data); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ikev2_profile_set_id (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ikev2_profile_set_id_t *mp; + f64 timeout; + u8 *name = 0; + u8 *data = 0; + u8 is_local = 0; + u32 id_type = 0; + ip4_address_t ip4; + + const char *valid_chars = "a-zA-Z0-9_"; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "name %U", unformat_token, valid_chars, &name)) + vec_add1 (name, 0); + else if (unformat (i, "id_type %U", unformat_ikev2_id_type, &id_type)) + ; + else if (unformat (i, "id_data %U", unformat_ip4_address, &ip4)) + { + data = vec_new (u8, 4); + clib_memcpy (data, ip4.as_u8, 4); + } + else if (unformat (i, "id_data 0x%U", unformat_hex_string, &data)) + ; + else if (unformat (i, "id_data %v", &data)) + ; + else if (unformat (i, "local")) + is_local = 1; + else if (unformat (i, "remote")) + is_local = 0; + else + { + errmsg ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!vec_len (name)) + { + errmsg ("profile name must be specified"); + return -99; + } + + if (vec_len (name) > 64) + { + errmsg ("profile name too long"); + return -99; + } + + if (!vec_len (data)) + { + errmsg ("id_data must be specified"); + return -99; + } + + if (!id_type) + { + errmsg ("id_type must be specified"); + return -99; + } + + M (IKEV2_PROFILE_SET_ID, ikev2_profile_set_id); + + mp->is_local = is_local; + mp->id_type = (u8) id_type; + mp->data_len = vec_len (data); + clib_memcpy (mp->name, name, vec_len (name)); + clib_memcpy (mp->data, data, vec_len (data)); + vec_free (name); + vec_free (data); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ikev2_profile_set_ts (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ikev2_profile_set_ts_t *mp; + f64 timeout; + u8 *name = 0; + u8 is_local = 0; + u32 proto = 0, start_port = 0, end_port = (u32) ~ 0; + ip4_address_t start_addr, end_addr; + + const char *valid_chars = "a-zA-Z0-9_"; + + start_addr.as_u32 = 0; + end_addr.as_u32 = (u32) ~ 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "name %U", unformat_token, valid_chars, &name)) + vec_add1 (name, 0); + else if (unformat (i, "protocol %d", &proto)) + ; + else if (unformat (i, "start_port %d", &start_port)) + ; + else if (unformat (i, "end_port %d", &end_port)) + ; + else + if (unformat (i, "start_addr %U", unformat_ip4_address, &start_addr)) + ; + else if (unformat (i, "end_addr %U", unformat_ip4_address, &end_addr)) + ; + else if (unformat (i, "local")) + is_local = 1; + else if (unformat (i, "remote")) + is_local = 0; + else + { + errmsg ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!vec_len (name)) + { + errmsg ("profile name must be specified"); + return -99; + } + + if (vec_len (name) > 64) + { + errmsg ("profile name too long"); + return -99; + } + + M (IKEV2_PROFILE_SET_TS, ikev2_profile_set_ts); + + mp->is_local = is_local; + mp->proto = (u8) proto; + mp->start_port = (u16) start_port; + mp->end_port = (u16) end_port; + mp->start_addr = start_addr.as_u32; + mp->end_addr = end_addr.as_u32; + clib_memcpy (mp->name, name, vec_len (name)); + vec_free (name); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ikev2_set_local_key (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ikev2_set_local_key_t *mp; + f64 timeout; + u8 *file = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "file %v", &file)) + vec_add1 (file, 0); + else + { + errmsg ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!vec_len (file)) + { + errmsg ("RSA key file must be specified"); + return -99; + } + + if (vec_len (file) > 256) + { + errmsg ("file name too long"); + return -99; + } + + M (IKEV2_SET_LOCAL_KEY, ikev2_set_local_key); + + clib_memcpy (mp->key_file, file, vec_len (file)); + vec_free (file); + + S; + W; + /* NOTREACHED */ + return 0; +} + +/* + * MAP + */ +static int +api_map_add_domain (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_map_add_domain_t *mp; + f64 timeout; + + ip4_address_t ip4_prefix; + ip6_address_t ip6_prefix; + ip6_address_t ip6_src; + u32 num_m_args = 0; + u32 ip6_prefix_len = 0, ip4_prefix_len = 0, ea_bits_len = 0, psid_offset = + 0, psid_length = 0; + u8 is_translation = 0; + u32 mtu = 0; + u32 ip6_src_len = 128; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "ip4-pfx %U/%d", unformat_ip4_address, + &ip4_prefix, &ip4_prefix_len)) + num_m_args++; + else if (unformat (i, "ip6-pfx %U/%d", unformat_ip6_address, + &ip6_prefix, &ip6_prefix_len)) + num_m_args++; + else + if (unformat + (i, "ip6-src %U/%d", unformat_ip6_address, &ip6_src, + &ip6_src_len)) + num_m_args++; + else if (unformat (i, "ip6-src %U", unformat_ip6_address, &ip6_src)) + num_m_args++; + else if (unformat (i, "ea-bits-len %d", &ea_bits_len)) + num_m_args++; + else if (unformat (i, "psid-offset %d", &psid_offset)) + num_m_args++; + else if (unformat (i, "psid-len %d", &psid_length)) + num_m_args++; + else if (unformat (i, "mtu %d", &mtu)) + num_m_args++; + else if (unformat (i, "map-t")) + is_translation = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (num_m_args < 3) + { + errmsg ("mandatory argument(s) missing"); + return -99; + } + + /* Construct the API message */ + M (MAP_ADD_DOMAIN, map_add_domain); + + clib_memcpy (mp->ip4_prefix, &ip4_prefix, sizeof (ip4_prefix)); + mp->ip4_prefix_len = ip4_prefix_len; + + clib_memcpy (mp->ip6_prefix, &ip6_prefix, sizeof (ip6_prefix)); + mp->ip6_prefix_len = ip6_prefix_len; + + clib_memcpy (mp->ip6_src, &ip6_src, sizeof (ip6_src)); + mp->ip6_src_prefix_len = ip6_src_len; + + mp->ea_bits_len = ea_bits_len; + mp->psid_offset = psid_offset; + mp->psid_length = psid_length; + mp->is_translation = is_translation; + mp->mtu = htons (mtu); + + /* send it... */ + S; + + /* Wait for a reply, return good/bad news */ + W; +} + +static int +api_map_del_domain (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_map_del_domain_t *mp; + f64 timeout; + + u32 num_m_args = 0; + u32 index; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "index %d", &index)) + num_m_args++; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (num_m_args != 1) + { + errmsg ("mandatory argument(s) missing"); + return -99; + } + + /* Construct the API message */ + M (MAP_DEL_DOMAIN, map_del_domain); + + mp->index = ntohl (index); + + /* send it... */ + S; + + /* Wait for a reply, return good/bad news */ + W; +} + +static int +api_map_add_del_rule (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_map_add_del_rule_t *mp; + f64 timeout; + u8 is_add = 1; + ip6_address_t ip6_dst; + u32 num_m_args = 0, index, psid = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "index %d", &index)) + num_m_args++; + else if (unformat (i, "psid %d", &psid)) + num_m_args++; + else if (unformat (i, "dst %U", unformat_ip6_address, &ip6_dst)) + num_m_args++; + else if (unformat (i, "del")) + { + is_add = 0; + } + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + /* Construct the API message */ + M (MAP_ADD_DEL_RULE, map_add_del_rule); + + mp->index = ntohl (index); + mp->is_add = is_add; + clib_memcpy (mp->ip6_dst, &ip6_dst, sizeof (ip6_dst)); + mp->psid = ntohs (psid); + + /* send it... */ + S; + + /* Wait for a reply, return good/bad news */ + W; +} + +static int +api_map_domain_dump (vat_main_t * vam) +{ + vl_api_map_domain_dump_t *mp; + f64 timeout; + + /* Construct the API message */ + M (MAP_DOMAIN_DUMP, map_domain_dump); + + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static int +api_map_rule_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_map_rule_dump_t *mp; + f64 timeout; + u32 domain_index = ~0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "index %u", &domain_index)) + ; + else + break; + } + + if (domain_index == ~0) + { + clib_warning ("parse error: domain index expected"); + return -99; + } + + /* Construct the API message */ + M (MAP_RULE_DUMP, map_rule_dump); + + mp->domain_index = htonl (domain_index); + + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static void vl_api_map_add_domain_reply_t_handler + (vl_api_map_add_domain_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_map_add_domain_reply_t_handler_json + (vl_api_map_add_domain_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "index", ntohl (mp->index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static int +api_get_first_msg_id (vat_main_t * vam) +{ + vl_api_get_first_msg_id_t *mp; + f64 timeout; + unformat_input_t *i = vam->input; + u8 *name; + u8 name_set = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "client %s", &name)) + name_set = 1; + else + break; + } + + if (name_set == 0) + { + errmsg ("missing client name"); + return -99; + } + vec_add1 (name, 0); + + if (vec_len (name) > 63) + { + errmsg ("client name too long"); + return -99; + } + + M (GET_FIRST_MSG_ID, get_first_msg_id); + clib_memcpy (mp->name, name, vec_len (name)); + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_cop_interface_enable_disable (vat_main_t * vam) +{ + unformat_input_t *line_input = vam->input; + vl_api_cop_interface_enable_disable_t *mp; + f64 timeout; + u32 sw_if_index = ~0; + u8 enable_disable = 1; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "disable")) + enable_disable = 0; + if (unformat (line_input, "enable")) + enable_disable = 1; + else if (unformat (line_input, "%U", api_unformat_sw_if_index, + vam, &sw_if_index)) + ; + else if (unformat (line_input, "sw_if_index %d", &sw_if_index)) + ; + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (COP_INTERFACE_ENABLE_DISABLE, cop_interface_enable_disable); + mp->sw_if_index = ntohl (sw_if_index); + mp->enable_disable = enable_disable; + + /* send it... */ + S; + /* Wait for the reply */ + W; +} + +static int +api_cop_whitelist_enable_disable (vat_main_t * vam) +{ + unformat_input_t *line_input = vam->input; + vl_api_cop_whitelist_enable_disable_t *mp; + f64 timeout; + u32 sw_if_index = ~0; + u8 ip4 = 0, ip6 = 0, default_cop = 0; + u32 fib_id = 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "ip4")) + ip4 = 1; + else if (unformat (line_input, "ip6")) + ip6 = 1; + else if (unformat (line_input, "default")) + default_cop = 1; + else if (unformat (line_input, "%U", api_unformat_sw_if_index, + vam, &sw_if_index)) + ; + else if (unformat (line_input, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (line_input, "fib-id %d", &fib_id)) + ; + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (COP_WHITELIST_ENABLE_DISABLE, cop_whitelist_enable_disable); + mp->sw_if_index = ntohl (sw_if_index); + mp->fib_id = ntohl (fib_id); + mp->ip4 = ip4; + mp->ip6 = ip6; + mp->default_cop = default_cop; + + /* send it... */ + S; + /* Wait for the reply */ + W; +} + +static int +api_get_node_graph (vat_main_t * vam) +{ + vl_api_get_node_graph_t *mp; + f64 timeout; + + M (GET_NODE_GRAPH, get_node_graph); + + /* send it... */ + S; + /* Wait for the reply */ + W; +} + +/* *INDENT-OFF* */ +/** Used for parsing LISP eids */ +typedef CLIB_PACKED(struct{ + u8 addr[16]; /**< eid address */ + u32 len; /**< prefix length if IP */ + u8 type; /**< type of eid */ +}) lisp_eid_vat_t; +/* *INDENT-ON* */ + +static uword +unformat_lisp_eid_vat (unformat_input_t * input, va_list * args) +{ + lisp_eid_vat_t *a = va_arg (*args, lisp_eid_vat_t *); + + memset (a, 0, sizeof (a[0])); + + if (unformat (input, "%U/%d", unformat_ip4_address, a->addr, &a->len)) + { + a->type = 0; /* ipv4 type */ + } + else if (unformat (input, "%U/%d", unformat_ip6_address, a->addr, &a->len)) + { + a->type = 1; /* ipv6 type */ + } + else if (unformat (input, "%U", unformat_ethernet_address, a->addr)) + { + a->type = 2; /* mac type */ + } + else + { + return 0; + } + + if ((a->type == 0 && a->len > 32) || (a->type == 1 && a->len > 128)) + { + return 0; + } + + return 1; +} + +static int +lisp_eid_size_vat (u8 type) +{ + switch (type) + { + case 0: + return 4; + case 1: + return 16; + case 2: + return 6; + } + return 0; +} + +static void +lisp_eid_put_vat (u8 * dst, u8 eid[16], u8 type) +{ + clib_memcpy (dst, eid, lisp_eid_size_vat (type)); +} + +/* *INDENT-OFF* */ +/** Used for transferring locators via VPP API */ +typedef CLIB_PACKED(struct +{ + u32 sw_if_index; /**< locator sw_if_index */ + u8 priority; /**< locator priority */ + u8 weight; /**< locator weight */ +}) ls_locator_t; +/* *INDENT-ON* */ + +static int +api_lisp_add_del_locator_set (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_add_del_locator_set_t *mp; + f64 timeout = ~0; + u8 is_add = 1; + u8 *locator_set_name = NULL; + u8 locator_set_name_set = 0; + ls_locator_t locator, *locators = 0; + u32 sw_if_index, priority, weight; + u32 data_len = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + { + is_add = 0; + } + else if (unformat (input, "locator-set %s", &locator_set_name)) + { + locator_set_name_set = 1; + } + else if (unformat (input, "sw_if_index %u p %u w %u", + &sw_if_index, &priority, &weight)) + { + locator.sw_if_index = htonl (sw_if_index); + locator.priority = priority; + locator.weight = weight; + vec_add1 (locators, locator); + } + else + if (unformat + (input, "iface %U p %u w %u", api_unformat_sw_if_index, vam, + &sw_if_index, &priority, &weight)) + { + locator.sw_if_index = htonl (sw_if_index); + locator.priority = priority; + locator.weight = weight; + vec_add1 (locators, locator); + } + else + break; + } + + if (locator_set_name_set == 0) + { + errmsg ("missing locator-set name"); + vec_free (locators); + return -99; + } + + if (vec_len (locator_set_name) > 64) + { + errmsg ("locator-set name too long"); + vec_free (locator_set_name); + vec_free (locators); + return -99; + } + vec_add1 (locator_set_name, 0); + + data_len = sizeof (ls_locator_t) * vec_len (locators); + + /* Construct the API message */ + M2 (LISP_ADD_DEL_LOCATOR_SET, lisp_add_del_locator_set, data_len); + + mp->is_add = is_add; + clib_memcpy (mp->locator_set_name, locator_set_name, + vec_len (locator_set_name)); + vec_free (locator_set_name); + + mp->locator_num = clib_host_to_net_u32 (vec_len (locators)); + if (locators) + clib_memcpy (mp->locators, locators, data_len); + vec_free (locators); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_add_del_locator (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_add_del_locator_t *mp; + f64 timeout = ~0; + u32 tmp_if_index = ~0; + u32 sw_if_index = ~0; + u8 sw_if_index_set = 0; + u8 sw_if_index_if_name_set = 0; + u32 priority = ~0; + u8 priority_set = 0; + u32 weight = ~0; + u8 weight_set = 0; + u8 is_add = 1; + u8 *locator_set_name = NULL; + u8 locator_set_name_set = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + { + is_add = 0; + } + else if (unformat (input, "locator-set %s", &locator_set_name)) + { + locator_set_name_set = 1; + } + else if (unformat (input, "iface %U", api_unformat_sw_if_index, vam, + &tmp_if_index)) + { + sw_if_index_if_name_set = 1; + sw_if_index = tmp_if_index; + } + else if (unformat (input, "sw_if_index %d", &tmp_if_index)) + { + sw_if_index_set = 1; + sw_if_index = tmp_if_index; + } + else if (unformat (input, "p %d", &priority)) + { + priority_set = 1; + } + else if (unformat (input, "w %d", &weight)) + { + weight_set = 1; + } + else + break; + } + + if (locator_set_name_set == 0) + { + errmsg ("missing locator-set name"); + return -99; + } + + if (sw_if_index_set == 0 && sw_if_index_if_name_set == 0) + { + errmsg ("missing sw_if_index"); + vec_free (locator_set_name); + return -99; + } + + if (sw_if_index_set != 0 && sw_if_index_if_name_set != 0) + { + errmsg ("cannot use both params interface name and sw_if_index"); + vec_free (locator_set_name); + return -99; + } + + if (priority_set == 0) + { + errmsg ("missing locator-set priority"); + vec_free (locator_set_name); + return -99; + } + + if (weight_set == 0) + { + errmsg ("missing locator-set weight"); + vec_free (locator_set_name); + return -99; + } + + if (vec_len (locator_set_name) > 64) + { + errmsg ("locator-set name too long"); + vec_free (locator_set_name); + return -99; + } + vec_add1 (locator_set_name, 0); + + /* Construct the API message */ + M (LISP_ADD_DEL_LOCATOR, lisp_add_del_locator); + + mp->is_add = is_add; + mp->sw_if_index = ntohl (sw_if_index); + mp->priority = priority; + mp->weight = weight; + clib_memcpy (mp->locator_set_name, locator_set_name, + vec_len (locator_set_name)); + vec_free (locator_set_name); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +uword +unformat_hmac_key_id (unformat_input_t * input, va_list * args) +{ + u32 *key_id = va_arg (*args, u32 *); + u8 *s = 0; + + if (unformat (input, "%s", &s)) + { + if (!strcmp ((char *) s, "sha1")) + key_id[0] = HMAC_SHA_1_96; + else if (!strcmp ((char *) s, "sha256")) + key_id[0] = HMAC_SHA_256_128; + else + { + clib_warning ("invalid key_id: '%s'", s); + key_id[0] = HMAC_NO_KEY; + } + } + else + return 0; + + vec_free (s); + return 1; +} + +static int +api_lisp_add_del_local_eid (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_add_del_local_eid_t *mp; + f64 timeout = ~0; + u8 is_add = 1; + u8 eid_set = 0; + lisp_eid_vat_t _eid, *eid = &_eid; + u8 *locator_set_name = 0; + u8 locator_set_name_set = 0; + u32 vni = 0; + u16 key_id = 0; + u8 *key = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + { + is_add = 0; + } + else if (unformat (input, "vni %d", &vni)) + { + ; + } + else if (unformat (input, "eid %U", unformat_lisp_eid_vat, eid)) + { + eid_set = 1; + } + else if (unformat (input, "locator-set %s", &locator_set_name)) + { + locator_set_name_set = 1; + } + else if (unformat (input, "key-id %U", unformat_hmac_key_id, &key_id)) + ; + else if (unformat (input, "secret-key %_%v%_", &key)) + ; + else + break; + } + + if (locator_set_name_set == 0) + { + errmsg ("missing locator-set name"); + return -99; + } + + if (0 == eid_set) + { + errmsg ("EID address not set!"); + vec_free (locator_set_name); + return -99; + } + + if (key && (0 == key_id)) + { + errmsg ("invalid key_id!"); + return -99; + } + + if (vec_len (key) > 64) + { + errmsg ("key too long"); + vec_free (key); + return -99; + } + + if (vec_len (locator_set_name) > 64) + { + errmsg ("locator-set name too long"); + vec_free (locator_set_name); + return -99; + } + vec_add1 (locator_set_name, 0); + + /* Construct the API message */ + M (LISP_ADD_DEL_LOCAL_EID, lisp_add_del_local_eid); + + mp->is_add = is_add; + lisp_eid_put_vat (mp->eid, eid->addr, eid->type); + mp->eid_type = eid->type; + mp->prefix_len = eid->len; + mp->vni = clib_host_to_net_u32 (vni); + mp->key_id = clib_host_to_net_u16 (key_id); + clib_memcpy (mp->locator_set_name, locator_set_name, + vec_len (locator_set_name)); + clib_memcpy (mp->key, key, vec_len (key)); + + vec_free (locator_set_name); + vec_free (key); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +/* *INDENT-OFF* */ +/** Used for transferring locators via VPP API */ +typedef CLIB_PACKED(struct +{ + u8 is_ip4; /**< is locator an IPv4 address? */ + u8 priority; /**< locator priority */ + u8 weight; /**< locator weight */ + u8 addr[16]; /**< IPv4/IPv6 address */ +}) rloc_t; +/* *INDENT-ON* */ + +static int +api_lisp_gpe_add_del_fwd_entry (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_gpe_add_del_fwd_entry_t *mp; + f64 timeout = ~0; + u8 is_add = 1; + lisp_eid_vat_t _rmt_eid, *rmt_eid = &_rmt_eid; + lisp_eid_vat_t _lcl_eid, *lcl_eid = &_lcl_eid; + u8 rmt_eid_set = 0, lcl_eid_set = 0; + u32 action = ~0, p, w; + ip4_address_t rmt_rloc4, lcl_rloc4; + ip6_address_t rmt_rloc6, lcl_rloc6; + rloc_t *rmt_locs = 0, *lcl_locs = 0, rloc, *curr_rloc = 0; + + memset (&rloc, 0, sizeof (rloc)); + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + { + is_add = 0; + } + else if (unformat (input, "rmt_eid %U", unformat_lisp_eid_vat, rmt_eid)) + { + rmt_eid_set = 1; + } + else if (unformat (input, "lcl_eid %U", unformat_lisp_eid_vat, lcl_eid)) + { + lcl_eid_set = 1; + } + else if (unformat (input, "p %d w %d", &p, &w)) + { + if (!curr_rloc) + { + errmsg ("No RLOC configured for setting priority/weight!"); + return -99; + } + curr_rloc->priority = p; + curr_rloc->weight = w; + } + else if (unformat (input, "loc-pair %U %U", unformat_ip4_address, + &lcl_rloc4, unformat_ip4_address, &rmt_rloc4)) + { + rloc.is_ip4 = 1; + + clib_memcpy (&rloc.addr, &lcl_rloc4, sizeof (lcl_rloc4)); + rloc.priority = rloc.weight = 0; + vec_add1 (lcl_locs, rloc); + + clib_memcpy (&rloc.addr, &rmt_rloc4, sizeof (rmt_rloc4)); + vec_add1 (rmt_locs, rloc); + /* priority and weight saved in rmt loc */ + curr_rloc = &rmt_locs[vec_len (rmt_locs) - 1]; + } + else if (unformat (input, "loc-pair %U %U", unformat_ip6_address, + &lcl_rloc6, unformat_ip6_address, &rmt_rloc6)) + { + rloc.is_ip4 = 0; + clib_memcpy (&rloc.addr, &lcl_rloc6, sizeof (lcl_rloc6)); + rloc.priority = rloc.weight = 0; + vec_add1 (lcl_locs, rloc); + + clib_memcpy (&rloc.addr, &rmt_rloc6, sizeof (rmt_rloc6)); + vec_add1 (rmt_locs, rloc); + /* priority and weight saved in rmt loc */ + curr_rloc = &rmt_locs[vec_len (rmt_locs) - 1]; + } + else if (unformat (input, "action %d", &action)) + { + ; + } + else + { + clib_warning ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (!rmt_eid_set) + { + errmsg ("remote eid addresses not set"); + return -99; + } + + if (lcl_eid_set && rmt_eid->type != lcl_eid->type) + { + errmsg ("eid types don't match"); + return -99; + } + + if (0 == rmt_locs && (u32) ~ 0 == action) + { + errmsg ("action not set for negative mapping"); + return -99; + } + + /* Construct the API message */ + M (LISP_GPE_ADD_DEL_FWD_ENTRY, lisp_gpe_add_del_fwd_entry); + + mp->is_add = is_add; + lisp_eid_put_vat (mp->rmt_eid, rmt_eid->addr, rmt_eid->type); + lisp_eid_put_vat (mp->lcl_eid, lcl_eid->addr, lcl_eid->type); + mp->eid_type = rmt_eid->type; + mp->rmt_len = rmt_eid->len; + mp->lcl_len = lcl_eid->len; + mp->action = action; + + if (0 != rmt_locs && 0 != lcl_locs) + { + mp->loc_num = vec_len (rmt_locs); + clib_memcpy (mp->lcl_locs, lcl_locs, + (sizeof (rloc_t) * vec_len (lcl_locs))); + clib_memcpy (mp->rmt_locs, rmt_locs, + (sizeof (rloc_t) * vec_len (rmt_locs))); + } + vec_free (lcl_locs); + vec_free (rmt_locs); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_add_del_map_server (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_add_del_map_server_t *mp; + f64 timeout = ~0; + u8 is_add = 1; + u8 ipv4_set = 0; + u8 ipv6_set = 0; + ip4_address_t ipv4; + ip6_address_t ipv6; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + { + is_add = 0; + } + else if (unformat (input, "%U", unformat_ip4_address, &ipv4)) + { + ipv4_set = 1; + } + else if (unformat (input, "%U", unformat_ip6_address, &ipv6)) + { + ipv6_set = 1; + } + else + break; + } + + if (ipv4_set && ipv6_set) + { + errmsg ("both eid v4 and v6 addresses set"); + return -99; + } + + if (!ipv4_set && !ipv6_set) + { + errmsg ("eid addresses not set"); + return -99; + } + + /* Construct the API message */ + M (LISP_ADD_DEL_MAP_SERVER, lisp_add_del_map_server); + + mp->is_add = is_add; + if (ipv6_set) + { + mp->is_ipv6 = 1; + clib_memcpy (mp->ip_address, &ipv6, sizeof (ipv6)); + } + else + { + mp->is_ipv6 = 0; + clib_memcpy (mp->ip_address, &ipv4, sizeof (ipv4)); + } + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_add_del_map_resolver (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_add_del_map_resolver_t *mp; + f64 timeout = ~0; + u8 is_add = 1; + u8 ipv4_set = 0; + u8 ipv6_set = 0; + ip4_address_t ipv4; + ip6_address_t ipv6; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + { + is_add = 0; + } + else if (unformat (input, "%U", unformat_ip4_address, &ipv4)) + { + ipv4_set = 1; + } + else if (unformat (input, "%U", unformat_ip6_address, &ipv6)) + { + ipv6_set = 1; + } + else + break; + } + + if (ipv4_set && ipv6_set) + { + errmsg ("both eid v4 and v6 addresses set"); + return -99; + } + + if (!ipv4_set && !ipv6_set) + { + errmsg ("eid addresses not set"); + return -99; + } + + /* Construct the API message */ + M (LISP_ADD_DEL_MAP_RESOLVER, lisp_add_del_map_resolver); + + mp->is_add = is_add; + if (ipv6_set) + { + mp->is_ipv6 = 1; + clib_memcpy (mp->ip_address, &ipv6, sizeof (ipv6)); + } + else + { + mp->is_ipv6 = 0; + clib_memcpy (mp->ip_address, &ipv4, sizeof (ipv4)); + } + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_gpe_enable_disable (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_gpe_enable_disable_t *mp; + f64 timeout = ~0; + u8 is_set = 0; + u8 is_en = 1; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "enable")) + { + is_set = 1; + is_en = 1; + } + else if (unformat (input, "disable")) + { + is_set = 1; + is_en = 0; + } + else + break; + } + + if (is_set == 0) + { + errmsg ("Value not set"); + return -99; + } + + /* Construct the API message */ + M (LISP_GPE_ENABLE_DISABLE, lisp_gpe_enable_disable); + + mp->is_en = is_en; + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_rloc_probe_enable_disable (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_rloc_probe_enable_disable_t *mp; + f64 timeout = ~0; + u8 is_set = 0; + u8 is_en = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "enable")) + { + is_set = 1; + is_en = 1; + } + else if (unformat (input, "disable")) + is_set = 1; + else + break; + } + + if (!is_set) + { + errmsg ("Value not set"); + return -99; + } + + /* Construct the API message */ + M (LISP_RLOC_PROBE_ENABLE_DISABLE, lisp_rloc_probe_enable_disable); + + mp->is_enabled = is_en; + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_map_register_enable_disable (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_map_register_enable_disable_t *mp; + f64 timeout = ~0; + u8 is_set = 0; + u8 is_en = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "enable")) + { + is_set = 1; + is_en = 1; + } + else if (unformat (input, "disable")) + is_set = 1; + else + break; + } + + if (!is_set) + { + errmsg ("Value not set"); + return -99; + } + + /* Construct the API message */ + M (LISP_MAP_REGISTER_ENABLE_DISABLE, lisp_map_register_enable_disable); + + mp->is_enabled = is_en; + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_enable_disable (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_enable_disable_t *mp; + f64 timeout = ~0; + u8 is_set = 0; + u8 is_en = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "enable")) + { + is_set = 1; + is_en = 1; + } + else if (unformat (input, "disable")) + { + is_set = 1; + } + else + break; + } + + if (!is_set) + { + errmsg ("Value not set"); + return -99; + } + + /* Construct the API message */ + M (LISP_ENABLE_DISABLE, lisp_enable_disable); + + mp->is_en = is_en; + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_show_lisp_map_register_state (vat_main_t * vam) +{ + f64 timeout = ~0; + vl_api_show_lisp_map_register_state_t *mp; + + M (SHOW_LISP_MAP_REGISTER_STATE, show_lisp_map_register_state); + + /* send */ + S; + + /* wait for reply */ + W; + + return 0; +} + +static int +api_show_lisp_rloc_probe_state (vat_main_t * vam) +{ + f64 timeout = ~0; + vl_api_show_lisp_rloc_probe_state_t *mp; + + M (SHOW_LISP_RLOC_PROBE_STATE, show_lisp_rloc_probe_state); + + /* send */ + S; + + /* wait for reply */ + W; + + return 0; +} + +static int +api_show_lisp_map_request_mode (vat_main_t * vam) +{ + f64 timeout = ~0; + vl_api_show_lisp_map_request_mode_t *mp; + + M (SHOW_LISP_MAP_REQUEST_MODE, show_lisp_map_request_mode); + + /* send */ + S; + + /* wait for reply */ + W; + + return 0; +} + +static int +api_lisp_map_request_mode (vat_main_t * vam) +{ + f64 timeout = ~0; + unformat_input_t *input = vam->input; + vl_api_lisp_map_request_mode_t *mp; + u8 mode = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "dst-only")) + mode = 0; + else if (unformat (input, "src-dst")) + mode = 1; + else + { + errmsg ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + M (LISP_MAP_REQUEST_MODE, lisp_map_request_mode); + + mp->mode = mode; + + /* send */ + S; + + /* wait for reply */ + W; + + /* notreached */ + return 0; +} + +/** + * Enable/disable LISP proxy ITR. + * + * @param vam vpp API test context + * @return return code + */ +static int +api_lisp_pitr_set_locator_set (vat_main_t * vam) +{ + f64 timeout = ~0; + u8 ls_name_set = 0; + unformat_input_t *input = vam->input; + vl_api_lisp_pitr_set_locator_set_t *mp; + u8 is_add = 1; + u8 *ls_name = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + is_add = 0; + else if (unformat (input, "locator-set %s", &ls_name)) + ls_name_set = 1; + else + { + errmsg ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (!ls_name_set) + { + errmsg ("locator-set name not set!"); + return -99; + } + + M (LISP_PITR_SET_LOCATOR_SET, lisp_pitr_set_locator_set); + + mp->is_add = is_add; + clib_memcpy (mp->ls_name, ls_name, vec_len (ls_name)); + vec_free (ls_name); + + /* send */ + S; + + /* wait for reply */ + W; + + /* notreached */ + return 0; +} + +static int +api_show_lisp_pitr (vat_main_t * vam) +{ + vl_api_show_lisp_pitr_t *mp; + f64 timeout = ~0; + + if (!vam->json_output) + { + print (vam->ofp, "%=20s", "lisp status:"); + } + + M (SHOW_LISP_PITR, show_lisp_pitr); + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +/** + * Add/delete mapping between vni and vrf + */ +static int +api_lisp_eid_table_add_del_map (vat_main_t * vam) +{ + f64 timeout = ~0; + unformat_input_t *input = vam->input; + vl_api_lisp_eid_table_add_del_map_t *mp; + u8 is_add = 1, vni_set = 0, vrf_set = 0, bd_index_set = 0; + u32 vni, vrf, bd_index; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + is_add = 0; + else if (unformat (input, "vrf %d", &vrf)) + vrf_set = 1; + else if (unformat (input, "bd_index %d", &bd_index)) + bd_index_set = 1; + else if (unformat (input, "vni %d", &vni)) + vni_set = 1; + else + break; + } + + if (!vni_set || (!vrf_set && !bd_index_set)) + { + errmsg ("missing arguments!"); + return -99; + } + + if (vrf_set && bd_index_set) + { + errmsg ("error: both vrf and bd entered!"); + return -99; + } + + M (LISP_EID_TABLE_ADD_DEL_MAP, lisp_eid_table_add_del_map); + + mp->is_add = is_add; + mp->vni = htonl (vni); + mp->dp_table = vrf_set ? htonl (vrf) : htonl (bd_index); + mp->is_l2 = bd_index_set; + + /* send */ + S; + + /* wait for reply */ + W; + + /* notreached */ + return 0; +} + +uword +unformat_negative_mapping_action (unformat_input_t * input, va_list * args) +{ + u32 *action = va_arg (*args, u32 *); + u8 *s = 0; + + if (unformat (input, "%s", &s)) + { + if (!strcmp ((char *) s, "no-action")) + action[0] = 0; + else if (!strcmp ((char *) s, "natively-forward")) + action[0] = 1; + else if (!strcmp ((char *) s, "send-map-request")) + action[0] = 2; + else if (!strcmp ((char *) s, "drop")) + action[0] = 3; + else + { + clib_warning ("invalid action: '%s'", s); + action[0] = 3; + } + } + else + return 0; + + vec_free (s); + return 1; +} + +/** + * Add/del remote mapping to/from LISP control plane + * + * @param vam vpp API test context + * @return return code + */ +static int +api_lisp_add_del_remote_mapping (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_add_del_remote_mapping_t *mp; + f64 timeout = ~0; + u32 vni = 0; + lisp_eid_vat_t _eid, *eid = &_eid; + lisp_eid_vat_t _seid, *seid = &_seid; + u8 is_add = 1, del_all = 0, eid_set = 0, seid_set = 0; + u32 action = ~0, p, w, data_len; + ip4_address_t rloc4; + ip6_address_t rloc6; + rloc_t *rlocs = 0, rloc, *curr_rloc = 0; + + memset (&rloc, 0, sizeof (rloc)); + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del-all")) + { + del_all = 1; + } + else if (unformat (input, "del")) + { + is_add = 0; + } + else if (unformat (input, "add")) + { + is_add = 1; + } + else if (unformat (input, "eid %U", unformat_lisp_eid_vat, eid)) + { + eid_set = 1; + } + else if (unformat (input, "seid %U", unformat_lisp_eid_vat, seid)) + { + seid_set = 1; + } + else if (unformat (input, "vni %d", &vni)) + { + ; + } + else if (unformat (input, "p %d w %d", &p, &w)) + { + if (!curr_rloc) + { + errmsg ("No RLOC configured for setting priority/weight!"); + return -99; + } + curr_rloc->priority = p; + curr_rloc->weight = w; + } + else if (unformat (input, "rloc %U", unformat_ip4_address, &rloc4)) + { + rloc.is_ip4 = 1; + clib_memcpy (&rloc.addr, &rloc4, sizeof (rloc4)); + vec_add1 (rlocs, rloc); + curr_rloc = &rlocs[vec_len (rlocs) - 1]; + } + else if (unformat (input, "rloc %U", unformat_ip6_address, &rloc6)) + { + rloc.is_ip4 = 0; + clib_memcpy (&rloc.addr, &rloc6, sizeof (rloc6)); + vec_add1 (rlocs, rloc); + curr_rloc = &rlocs[vec_len (rlocs) - 1]; + } + else if (unformat (input, "action %U", + unformat_negative_mapping_action, &action)) + { + ; + } + else + { + clib_warning ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (0 == eid_set) + { + errmsg ("missing params!"); + return -99; + } + + if (is_add && (~0 == action) && 0 == vec_len (rlocs)) + { + errmsg ("no action set for negative map-reply!"); + return -99; + } + + data_len = vec_len (rlocs) * sizeof (rloc_t); + + M2 (LISP_ADD_DEL_REMOTE_MAPPING, lisp_add_del_remote_mapping, data_len); + mp->is_add = is_add; + mp->vni = htonl (vni); + mp->action = (u8) action; + mp->is_src_dst = seid_set; + mp->eid_len = eid->len; + mp->seid_len = seid->len; + mp->del_all = del_all; + mp->eid_type = eid->type; + lisp_eid_put_vat (mp->eid, eid->addr, eid->type); + lisp_eid_put_vat (mp->seid, seid->addr, seid->type); + + mp->rloc_num = clib_host_to_net_u32 (vec_len (rlocs)); + clib_memcpy (mp->rlocs, rlocs, data_len); + vec_free (rlocs); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +/** + * Add/del LISP adjacency. Saves mapping in LISP control plane and updates + * forwarding entries in data-plane accordingly. + * + * @param vam vpp API test context + * @return return code + */ +static int +api_lisp_add_del_adjacency (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_add_del_adjacency_t *mp; + f64 timeout = ~0; + u32 vni = 0; + ip4_address_t leid4, reid4; + ip6_address_t leid6, reid6; + u8 reid_mac[6] = { 0 }; + u8 leid_mac[6] = { 0 }; + u8 reid_type, leid_type; + u32 leid_len = 0, reid_len = 0, len; + u8 is_add = 1; + + leid_type = reid_type = (u8) ~ 0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + { + is_add = 0; + } + else if (unformat (input, "add")) + { + is_add = 1; + } + else if (unformat (input, "reid %U/%d", unformat_ip4_address, + &reid4, &len)) + { + reid_type = 0; /* ipv4 */ + reid_len = len; + } + else if (unformat (input, "reid %U/%d", unformat_ip6_address, + &reid6, &len)) + { + reid_type = 1; /* ipv6 */ + reid_len = len; + } + else if (unformat (input, "reid %U", unformat_ethernet_address, + reid_mac)) + { + reid_type = 2; /* mac */ + } + else if (unformat (input, "leid %U/%d", unformat_ip4_address, + &leid4, &len)) + { + leid_type = 0; /* ipv4 */ + leid_len = len; + } + else if (unformat (input, "leid %U/%d", unformat_ip6_address, + &leid6, &len)) + { + leid_type = 1; /* ipv6 */ + leid_len = len; + } + else if (unformat (input, "leid %U", unformat_ethernet_address, + leid_mac)) + { + leid_type = 2; /* mac */ + } + else if (unformat (input, "vni %d", &vni)) + { + ; + } + else + { + errmsg ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if ((u8) ~ 0 == reid_type) + { + errmsg ("missing params!"); + return -99; + } + + if (leid_type != reid_type) + { + errmsg ("remote and local EIDs are of different types!"); + return -99; + } + + M (LISP_ADD_DEL_ADJACENCY, lisp_add_del_adjacency); + mp->is_add = is_add; + mp->vni = htonl (vni); + mp->leid_len = leid_len; + mp->reid_len = reid_len; + mp->eid_type = reid_type; + + switch (mp->eid_type) + { + case 0: + clib_memcpy (mp->leid, &leid4, sizeof (leid4)); + clib_memcpy (mp->reid, &reid4, sizeof (reid4)); + break; + case 1: + clib_memcpy (mp->leid, &leid6, sizeof (leid6)); + clib_memcpy (mp->reid, &reid6, sizeof (reid6)); + break; + case 2: + clib_memcpy (mp->leid, leid_mac, 6); + clib_memcpy (mp->reid, reid_mac, 6); + break; + default: + errmsg ("unknown EID type %d!", mp->eid_type); + return 0; + } + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_gpe_add_del_iface (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_gpe_add_del_iface_t *mp; + f64 timeout = ~0; + u8 action_set = 0, is_add = 1, is_l2 = 0, dp_table_set = 0, vni_set = 0; + u32 dp_table = 0, vni = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "up")) + { + action_set = 1; + is_add = 1; + } + else if (unformat (input, "down")) + { + action_set = 1; + is_add = 0; + } + else if (unformat (input, "table_id %d", &dp_table)) + { + dp_table_set = 1; + } + else if (unformat (input, "bd_id %d", &dp_table)) + { + dp_table_set = 1; + is_l2 = 1; + } + else if (unformat (input, "vni %d", &vni)) + { + vni_set = 1; + } + else + break; + } + + if (action_set == 0) + { + errmsg ("Action not set"); + return -99; + } + if (dp_table_set == 0 || vni_set == 0) + { + errmsg ("vni and dp_table must be set"); + return -99; + } + + /* Construct the API message */ + M (LISP_GPE_ADD_DEL_IFACE, lisp_gpe_add_del_iface); + + mp->is_add = is_add; + mp->dp_table = dp_table; + mp->is_l2 = is_l2; + mp->vni = vni; + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +/** + * Add/del map request itr rlocs from LISP control plane and updates + * + * @param vam vpp API test context + * @return return code + */ +static int +api_lisp_add_del_map_request_itr_rlocs (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_add_del_map_request_itr_rlocs_t *mp; + f64 timeout = ~0; + u8 *locator_set_name = 0; + u8 locator_set_name_set = 0; + u8 is_add = 1; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + { + is_add = 0; + } + else if (unformat (input, "%_%v%_", &locator_set_name)) + { + locator_set_name_set = 1; + } + else + { + clib_warning ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (is_add && !locator_set_name_set) + { + errmsg ("itr-rloc is not set!"); + return -99; + } + + if (is_add && vec_len (locator_set_name) > 64) + { + errmsg ("itr-rloc locator-set name too long"); + vec_free (locator_set_name); + return -99; + } + + M (LISP_ADD_DEL_MAP_REQUEST_ITR_RLOCS, lisp_add_del_map_request_itr_rlocs); + mp->is_add = is_add; + if (is_add) + { + clib_memcpy (mp->locator_set_name, locator_set_name, + vec_len (locator_set_name)); + } + else + { + memset (mp->locator_set_name, 0, sizeof (mp->locator_set_name)); + } + vec_free (locator_set_name); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_locator_dump (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_locator_dump_t *mp; + f64 timeout = ~0; + u8 is_index_set = 0, is_name_set = 0; + u8 *ls_name = 0; + u32 ls_index = ~0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "ls_name %_%v%_", &ls_name)) + { + is_name_set = 1; + } + else if (unformat (input, "ls_index %d", &ls_index)) + { + is_index_set = 1; + } + else + { + errmsg ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (!is_index_set && !is_name_set) + { + errmsg ("error: expected one of index or name!"); + return -99; + } + + if (is_index_set && is_name_set) + { + errmsg ("error: only one param expected!"); + return -99; + } + + if (vec_len (ls_name) > 62) + { + errmsg ("error: locator set name too long!"); + return -99; + } + + if (!vam->json_output) + { + print (vam->ofp, "%=16s%=16s%=16s", "locator", "priority", "weight"); + } + + M (LISP_LOCATOR_DUMP, lisp_locator_dump); + mp->is_index_set = is_index_set; + + if (is_index_set) + mp->ls_index = clib_host_to_net_u32 (ls_index); + else + { + vec_add1 (ls_name, 0); + strncpy ((char *) mp->ls_name, (char *) ls_name, + sizeof (mp->ls_name) - 1); + } + + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_locator_set_dump (vat_main_t * vam) +{ + vl_api_lisp_locator_set_dump_t *mp; + unformat_input_t *input = vam->input; + f64 timeout = ~0; + u8 filter = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "local")) + { + filter = 1; + } + else if (unformat (input, "remote")) + { + filter = 2; + } + else + { + errmsg ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (!vam->json_output) + { + print (vam->ofp, "%=10s%=15s", "ls_index", "ls_name"); + } + + M (LISP_LOCATOR_SET_DUMP, lisp_locator_set_dump); + + mp->filter = filter; + + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_eid_table_map_dump (vat_main_t * vam) +{ + u8 is_l2 = 0; + u8 mode_set = 0; + unformat_input_t *input = vam->input; + vl_api_lisp_eid_table_map_dump_t *mp; + f64 timeout = ~0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "l2")) + { + is_l2 = 1; + mode_set = 1; + } + else if (unformat (input, "l3")) + { + is_l2 = 0; + mode_set = 1; + } + else + { + errmsg ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (!mode_set) + { + errmsg ("expected one of 'l2' or 'l3' parameter!"); + return -99; + } + + if (!vam->json_output) + { + print (vam->ofp, "%=10s%=10s", "VNI", is_l2 ? "BD" : "VRF"); + } + + M (LISP_EID_TABLE_MAP_DUMP, lisp_eid_table_map_dump); + mp->is_l2 = is_l2; + + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_eid_table_vni_dump (vat_main_t * vam) +{ + vl_api_lisp_eid_table_vni_dump_t *mp; + f64 timeout = ~0; + + if (!vam->json_output) + { + print (vam->ofp, "VNI"); + } + + M (LISP_EID_TABLE_VNI_DUMP, lisp_eid_table_vni_dump); + + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_eid_table_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_lisp_eid_table_dump_t *mp; + f64 timeout = ~0; + struct in_addr ip4; + struct in6_addr ip6; + u8 mac[6]; + u8 eid_type = ~0, eid_set = 0; + u32 prefix_length = ~0, t, vni = 0; + u8 filter = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "eid %U/%d", unformat_ip4_address, &ip4, &t)) + { + eid_set = 1; + eid_type = 0; + prefix_length = t; + } + else if (unformat (i, "eid %U/%d", unformat_ip6_address, &ip6, &t)) + { + eid_set = 1; + eid_type = 1; + prefix_length = t; + } + else if (unformat (i, "eid %U", unformat_ethernet_address, mac)) + { + eid_set = 1; + eid_type = 2; + } + else if (unformat (i, "vni %d", &t)) + { + vni = t; + } + else if (unformat (i, "local")) + { + filter = 1; + } + else if (unformat (i, "remote")) + { + filter = 2; + } + else + { + errmsg ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!vam->json_output) + { + print (vam->ofp, "%-35s%-20s%-30s%-20s%-20s%-10s%-20s", "EID", + "type", "ls_index", "ttl", "authoritative", "key_id", "key"); + } + + M (LISP_EID_TABLE_DUMP, lisp_eid_table_dump); + + mp->filter = filter; + if (eid_set) + { + mp->eid_set = 1; + mp->vni = htonl (vni); + mp->eid_type = eid_type; + switch (eid_type) + { + case 0: + mp->prefix_length = prefix_length; + clib_memcpy (mp->eid, &ip4, sizeof (ip4)); + break; + case 1: + mp->prefix_length = prefix_length; + clib_memcpy (mp->eid, &ip6, sizeof (ip6)); + break; + case 2: + clib_memcpy (mp->eid, mac, sizeof (mac)); + break; + default: + errmsg ("unknown EID type %d!", eid_type); + return -99; + } + } + + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_gpe_tunnel_dump (vat_main_t * vam) +{ + vl_api_lisp_gpe_tunnel_dump_t *mp; + f64 timeout = ~0; + + if (!vam->json_output) + { + print (vam->ofp, "%=20s%=30s%=16s%=16s%=16s%=16s" + "%=16s%=16s%=16s%=16s%=16s", + "Tunel", "Source", "Destination", "Fib encap", "Fib decap", + "Decap next", "Lisp version", "Flags", "Next protocol", + "ver_res", "res", "iid"); + } + + M (LISP_GPE_TUNNEL_DUMP, lisp_gpe_tunnel_dump); + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_adjacencies_get (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_lisp_adjacencies_get_t *mp; + f64 timeout = ~0; + u8 vni_set = 0; + u32 vni = ~0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "vni %d", &vni)) + { + vni_set = 1; + } + else + { + errmsg ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!vni_set) + { + errmsg ("vni not set!"); + return -99; + } + + if (!vam->json_output) + { + print (vam->ofp, "%s %40s", "leid", "reid"); + } + + M (LISP_ADJACENCIES_GET, lisp_adjacencies_get); + mp->vni = clib_host_to_net_u32 (vni); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_map_server_dump (vat_main_t * vam) +{ + vl_api_lisp_map_server_dump_t *mp; + f64 timeout = ~0; + + if (!vam->json_output) + { + print (vam->ofp, "%=20s", "Map server"); + } + + M (LISP_MAP_SERVER_DUMP, lisp_map_server_dump); + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_map_resolver_dump (vat_main_t * vam) +{ + vl_api_lisp_map_resolver_dump_t *mp; + f64 timeout = ~0; + + if (!vam->json_output) + { + print (vam->ofp, "%=20s", "Map resolver"); + } + + M (LISP_MAP_RESOLVER_DUMP, lisp_map_resolver_dump); + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_show_lisp_status (vat_main_t * vam) +{ + vl_api_show_lisp_status_t *mp; + f64 timeout = ~0; + + if (!vam->json_output) + { + print (vam->ofp, "%-20s%-16s", "lisp status", "locator-set"); + } + + M (SHOW_LISP_STATUS, show_lisp_status); + /* send it... */ + S; + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_get_map_request_itr_rlocs (vat_main_t * vam) +{ + vl_api_lisp_get_map_request_itr_rlocs_t *mp; + f64 timeout = ~0; + + if (!vam->json_output) + { + print (vam->ofp, "%=20s", "itr-rlocs:"); + } + + M (LISP_GET_MAP_REQUEST_ITR_RLOCS, lisp_get_map_request_itr_rlocs); + /* send it... */ + S; + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_af_packet_create (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_af_packet_create_t *mp; + f64 timeout; + u8 *host_if_name = 0; + u8 hw_addr[6]; + u8 random_hw_addr = 1; + + memset (hw_addr, 0, sizeof (hw_addr)); + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "name %s", &host_if_name)) + vec_add1 (host_if_name, 0); + else if (unformat (i, "hw_addr %U", unformat_ethernet_address, hw_addr)) + random_hw_addr = 0; + else + break; + } + + if (!vec_len (host_if_name)) + { + errmsg ("host-interface name must be specified"); + return -99; + } + + if (vec_len (host_if_name) > 64) + { + errmsg ("host-interface name too long"); + return -99; + } + + M (AF_PACKET_CREATE, af_packet_create); + + clib_memcpy (mp->host_if_name, host_if_name, vec_len (host_if_name)); + clib_memcpy (mp->hw_addr, hw_addr, 6); + mp->use_random_hw_addr = random_hw_addr; + vec_free (host_if_name); + + S; + W2 (fprintf (vam->ofp, " new sw_if_index = %d ", vam->sw_if_index)); + /* NOTREACHED */ + return 0; +} + +static int +api_af_packet_delete (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_af_packet_delete_t *mp; + f64 timeout; + u8 *host_if_name = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "name %s", &host_if_name)) + vec_add1 (host_if_name, 0); + else + break; + } + + if (!vec_len (host_if_name)) + { + errmsg ("host-interface name must be specified"); + return -99; + } + + if (vec_len (host_if_name) > 64) + { + errmsg ("host-interface name too long"); + return -99; + } + + M (AF_PACKET_DELETE, af_packet_delete); + + clib_memcpy (mp->host_if_name, host_if_name, vec_len (host_if_name)); + vec_free (host_if_name); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_policer_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_policer_add_del_t *mp; + f64 timeout; + u8 is_add = 1; + u8 *name = 0; + u32 cir = 0; + u32 eir = 0; + u64 cb = 0; + u64 eb = 0; + u8 rate_type = 0; + u8 round_type = 0; + u8 type = 0; + u8 color_aware = 0; + sse2_qos_pol_action_params_st conform_action, exceed_action, violate_action; + + conform_action.action_type = SSE2_QOS_ACTION_TRANSMIT; + conform_action.dscp = 0; + exceed_action.action_type = SSE2_QOS_ACTION_MARK_AND_TRANSMIT; + exceed_action.dscp = 0; + violate_action.action_type = SSE2_QOS_ACTION_DROP; + violate_action.dscp = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "name %s", &name)) + vec_add1 (name, 0); + else if (unformat (i, "cir %u", &cir)) + ; + else if (unformat (i, "eir %u", &eir)) + ; + else if (unformat (i, "cb %u", &cb)) + ; + else if (unformat (i, "eb %u", &eb)) + ; + else if (unformat (i, "rate_type %U", unformat_policer_rate_type, + &rate_type)) + ; + else if (unformat (i, "round_type %U", unformat_policer_round_type, + &round_type)) + ; + else if (unformat (i, "type %U", unformat_policer_type, &type)) + ; + else if (unformat (i, "conform_action %U", unformat_policer_action_type, + &conform_action)) + ; + else if (unformat (i, "exceed_action %U", unformat_policer_action_type, + &exceed_action)) + ; + else if (unformat (i, "violate_action %U", unformat_policer_action_type, + &violate_action)) + ; + else if (unformat (i, "color-aware")) + color_aware = 1; + else + break; + } + + if (!vec_len (name)) + { + errmsg ("policer name must be specified"); + return -99; + } + + if (vec_len (name) > 64) + { + errmsg ("policer name too long"); + return -99; + } + + M (POLICER_ADD_DEL, policer_add_del); + + clib_memcpy (mp->name, name, vec_len (name)); + vec_free (name); + mp->is_add = is_add; + mp->cir = cir; + mp->eir = eir; + mp->cb = cb; + mp->eb = eb; + mp->rate_type = rate_type; + mp->round_type = round_type; + mp->type = type; + mp->conform_action_type = conform_action.action_type; + mp->conform_dscp = conform_action.dscp; + mp->exceed_action_type = exceed_action.action_type; + mp->exceed_dscp = exceed_action.dscp; + mp->violate_action_type = violate_action.action_type; + mp->violate_dscp = violate_action.dscp; + mp->color_aware = color_aware; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_policer_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_policer_dump_t *mp; + f64 timeout = ~0; + u8 *match_name = 0; + u8 match_name_valid = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "name %s", &match_name)) + { + vec_add1 (match_name, 0); + match_name_valid = 1; + } + else + break; + } + + M (POLICER_DUMP, policer_dump); + mp->match_name_valid = match_name_valid; + clib_memcpy (mp->match_name, match_name, vec_len (match_name)); + vec_free (match_name); + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_policer_classify_set_interface (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_policer_classify_set_interface_t *mp; + f64 timeout; + u32 sw_if_index; + int sw_if_index_set; + u32 ip4_table_index = ~0; + u32 ip6_table_index = ~0; + u32 l2_table_index = ~0; + u8 is_add = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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, "del")) + is_add = 0; + else if (unformat (i, "ip4-table %d", &ip4_table_index)) + ; + else if (unformat (i, "ip6-table %d", &ip6_table_index)) + ; + else if (unformat (i, "l2-table %d", &l2_table_index)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (POLICER_CLASSIFY_SET_INTERFACE, policer_classify_set_interface); + + mp->sw_if_index = ntohl (sw_if_index); + mp->ip4_table_index = ntohl (ip4_table_index); + mp->ip6_table_index = ntohl (ip6_table_index); + mp->l2_table_index = ntohl (l2_table_index); + mp->is_add = is_add; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_policer_classify_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_policer_classify_dump_t *mp; + f64 timeout = ~0; + u8 type = POLICER_CLASSIFY_N_TABLES; + + if (unformat (i, "type %U", unformat_policer_classify_table_type, &type)) + ; + else + { + errmsg ("classify table type must be specified"); + return -99; + } + + if (!vam->json_output) + { + print (vam->ofp, "%10s%20s", "Intfc idx", "Classify table"); + } + + M (POLICER_CLASSIFY_DUMP, policer_classify_dump); + mp->type = type; + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_netmap_create (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_netmap_create_t *mp; + f64 timeout; + u8 *if_name = 0; + u8 hw_addr[6]; + u8 random_hw_addr = 1; + u8 is_pipe = 0; + u8 is_master = 0; + + memset (hw_addr, 0, sizeof (hw_addr)); + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "name %s", &if_name)) + vec_add1 (if_name, 0); + else if (unformat (i, "hw_addr %U", unformat_ethernet_address, hw_addr)) + random_hw_addr = 0; + else if (unformat (i, "pipe")) + is_pipe = 1; + else if (unformat (i, "master")) + is_master = 1; + else if (unformat (i, "slave")) + is_master = 0; + else + break; + } + + if (!vec_len (if_name)) + { + errmsg ("interface name must be specified"); + return -99; + } + + if (vec_len (if_name) > 64) + { + errmsg ("interface name too long"); + return -99; + } + + M (NETMAP_CREATE, netmap_create); + + clib_memcpy (mp->netmap_if_name, if_name, vec_len (if_name)); + clib_memcpy (mp->hw_addr, hw_addr, 6); + mp->use_random_hw_addr = random_hw_addr; + mp->is_pipe = is_pipe; + mp->is_master = is_master; + vec_free (if_name); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_netmap_delete (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_netmap_delete_t *mp; + f64 timeout; + u8 *if_name = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "name %s", &if_name)) + vec_add1 (if_name, 0); + else + break; + } + + if (!vec_len (if_name)) + { + errmsg ("interface name must be specified"); + return -99; + } + + if (vec_len (if_name) > 64) + { + errmsg ("interface name too long"); + return -99; + } + + M (NETMAP_DELETE, netmap_delete); + + clib_memcpy (mp->netmap_if_name, if_name, vec_len (if_name)); + vec_free (if_name); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static void vl_api_mpls_tunnel_details_t_handler + (vl_api_mpls_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 len = mp->mt_next_hop_n_labels; + i32 i; + + print (vam->ofp, "[%d]: via %U %d labels ", + mp->tunnel_index, + format_ip4_address, mp->mt_next_hop, + ntohl (mp->mt_next_hop_sw_if_index)); + for (i = 0; i < len; i++) + { + print (vam->ofp, "%u ", ntohl (mp->mt_next_hop_out_labels[i])); + } + print (vam->ofp, ""); +} + +static void vl_api_mpls_tunnel_details_t_handler_json + (vl_api_mpls_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + struct in_addr ip4; + i32 i; + i32 len = mp->mt_next_hop_n_labels; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "tunnel_index", ntohl (mp->tunnel_index)); + clib_memcpy (&ip4, &(mp->mt_next_hop), sizeof (ip4)); + vat_json_object_add_ip4 (node, "next_hop", ip4); + vat_json_object_add_uint (node, "next_hop_sw_if_index", + ntohl (mp->mt_next_hop_sw_if_index)); + vat_json_object_add_uint (node, "l2_only", ntohl (mp->mt_l2_only)); + vat_json_object_add_uint (node, "label_count", len); + for (i = 0; i < len; i++) + { + vat_json_object_add_uint (node, "label", + ntohl (mp->mt_next_hop_out_labels[i])); + } +} + +static int +api_mpls_tunnel_dump (vat_main_t * vam) +{ + vl_api_mpls_tunnel_dump_t *mp; + f64 timeout; + i32 index = -1; + + /* Parse args required to build the message */ + while (unformat_check_input (vam->input) != UNFORMAT_END_OF_INPUT) + { + if (!unformat (vam->input, "tunnel_index %d", &index)) + { + index = -1; + break; + } + } + + print (vam->ofp, " tunnel_index %d", index); + + M (MPLS_TUNNEL_DUMP, mpls_tunnel_dump); + mp->tunnel_index = htonl (index); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +#define vl_api_mpls_fib_details_t_endian vl_noop_handler +#define vl_api_mpls_fib_details_t_print vl_noop_handler + +static void +vl_api_mpls_fib_details_t_handler (vl_api_mpls_fib_details_t * mp) +{ + vat_main_t *vam = &vat_main; + int count = ntohl (mp->count); + vl_api_fib_path2_t *fp; + int i; + + print (vam->ofp, + "table-id %d, label %u, ess_bit %u", + ntohl (mp->table_id), ntohl (mp->label), mp->eos_bit); + fp = mp->path; + for (i = 0; i < count; i++) + { + if (fp->afi == IP46_TYPE_IP6) + print (vam->ofp, + " weight %d, sw_if_index %d, is_local %d, is_drop %d, " + "is_unreach %d, is_prohitbit %d, afi %d, next_hop %U", + ntohl (fp->weight), ntohl (fp->sw_if_index), fp->is_local, + fp->is_drop, fp->is_unreach, fp->is_prohibit, fp->afi, + format_ip6_address, fp->next_hop); + else if (fp->afi == IP46_TYPE_IP4) + print (vam->ofp, + " weight %d, sw_if_index %d, is_local %d, is_drop %d, " + "is_unreach %d, is_prohitbit %d, afi %d, next_hop %U", + ntohl (fp->weight), ntohl (fp->sw_if_index), fp->is_local, + fp->is_drop, fp->is_unreach, fp->is_prohibit, fp->afi, + format_ip4_address, fp->next_hop); + fp++; + } +} + +static void vl_api_mpls_fib_details_t_handler_json + (vl_api_mpls_fib_details_t * mp) +{ + vat_main_t *vam = &vat_main; + int count = ntohl (mp->count); + vat_json_node_t *node = NULL; + struct in_addr ip4; + struct in6_addr ip6; + vl_api_fib_path2_t *fp; + int i; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "table", ntohl (mp->table_id)); + vat_json_object_add_uint (node, "s_bit", mp->eos_bit); + vat_json_object_add_uint (node, "label", ntohl (mp->label)); + vat_json_object_add_uint (node, "path_count", count); + fp = mp->path; + for (i = 0; i < count; i++) + { + vat_json_object_add_uint (node, "weight", ntohl (fp->weight)); + vat_json_object_add_uint (node, "sw_if_index", ntohl (fp->sw_if_index)); + vat_json_object_add_uint (node, "is_local", fp->is_local); + vat_json_object_add_uint (node, "is_drop", fp->is_drop); + vat_json_object_add_uint (node, "is_unreach", fp->is_unreach); + vat_json_object_add_uint (node, "is_prohibit", fp->is_prohibit); + vat_json_object_add_uint (node, "next_hop_afi", fp->afi); + if (fp->afi == IP46_TYPE_IP4) + { + clib_memcpy (&ip4, &fp->next_hop, sizeof (ip4)); + vat_json_object_add_ip4 (node, "next_hop", ip4); + } + else if (fp->afi == IP46_TYPE_IP6) + { + clib_memcpy (&ip6, &fp->next_hop, sizeof (ip6)); + vat_json_object_add_ip6 (node, "next_hop", ip6); + } + } +} + +static int +api_mpls_fib_dump (vat_main_t * vam) +{ + vl_api_mpls_fib_dump_t *mp; + f64 timeout; + + M (MPLS_FIB_DUMP, mpls_fib_dump); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +#define vl_api_ip_fib_details_t_endian vl_noop_handler +#define vl_api_ip_fib_details_t_print vl_noop_handler + +static void +vl_api_ip_fib_details_t_handler (vl_api_ip_fib_details_t * mp) +{ + vat_main_t *vam = &vat_main; + int count = ntohl (mp->count); + vl_api_fib_path_t *fp; + int i; + + print (vam->ofp, + "table-id %d, prefix %U/%d", + ntohl (mp->table_id), format_ip4_address, mp->address, + mp->address_length); + fp = mp->path; + for (i = 0; i < count; i++) + { + if (fp->afi == IP46_TYPE_IP6) + print (vam->ofp, + " weight %d, sw_if_index %d, is_local %d, is_drop %d, " + "is_unreach %d, is_prohitbit %d, afi %d, next_hop %U", + ntohl (fp->weight), ntohl (fp->sw_if_index), fp->is_local, + fp->is_drop, fp->is_unreach, fp->is_prohibit, fp->afi, + format_ip6_address, fp->next_hop); + else if (fp->afi == IP46_TYPE_IP4) + print (vam->ofp, + " weight %d, sw_if_index %d, is_local %d, is_drop %d, " + "is_unreach %d, is_prohitbit %d, afi %d, next_hop %U", + ntohl (fp->weight), ntohl (fp->sw_if_index), fp->is_local, + fp->is_drop, fp->is_unreach, fp->is_prohibit, fp->afi, + format_ip4_address, fp->next_hop); + fp++; + } +} + +static void vl_api_ip_fib_details_t_handler_json + (vl_api_ip_fib_details_t * mp) +{ + vat_main_t *vam = &vat_main; + int count = ntohl (mp->count); + vat_json_node_t *node = NULL; + struct in_addr ip4; + struct in6_addr ip6; + vl_api_fib_path_t *fp; + int i; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "table", ntohl (mp->table_id)); + clib_memcpy (&ip4, &mp->address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "prefix", ip4); + vat_json_object_add_uint (node, "mask_length", mp->address_length); + vat_json_object_add_uint (node, "path_count", count); + fp = mp->path; + for (i = 0; i < count; i++) + { + vat_json_object_add_uint (node, "weight", ntohl (fp->weight)); + vat_json_object_add_uint (node, "sw_if_index", ntohl (fp->sw_if_index)); + vat_json_object_add_uint (node, "is_local", fp->is_local); + vat_json_object_add_uint (node, "is_drop", fp->is_drop); + vat_json_object_add_uint (node, "is_unreach", fp->is_unreach); + vat_json_object_add_uint (node, "is_prohibit", fp->is_prohibit); + vat_json_object_add_uint (node, "next_hop_afi", fp->afi); + if (fp->afi == IP46_TYPE_IP4) + { + clib_memcpy (&ip4, &fp->next_hop, sizeof (ip4)); + vat_json_object_add_ip4 (node, "next_hop", ip4); + } + else if (fp->afi == IP46_TYPE_IP6) + { + clib_memcpy (&ip6, &fp->next_hop, sizeof (ip6)); + vat_json_object_add_ip6 (node, "next_hop", ip6); + } + } +} + +static int +api_ip_fib_dump (vat_main_t * vam) +{ + vl_api_ip_fib_dump_t *mp; + f64 timeout; + + M (IP_FIB_DUMP, ip_fib_dump); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static void vl_api_ip_neighbor_details_t_handler + (vl_api_ip_neighbor_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%c %U %U", + (mp->is_static) ? 'S' : 'D', + format_ethernet_address, &mp->mac_address, + (mp->is_ipv6) ? format_ip6_address : format_ip4_address, + &mp->ip_address); +} + +static void vl_api_ip_neighbor_details_t_handler_json + (vl_api_ip_neighbor_details_t * mp) +{ + + vat_main_t *vam = &vat_main; + vat_json_node_t *node; + struct in_addr ip4; + struct in6_addr ip6; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_string_copy (node, "flag", + (mp->is_static) ? (u8 *) "static" : (u8 *) + "dynamic"); + + vat_json_object_add_string_copy (node, "link_layer", + format (0, "%U", format_ethernet_address, + &mp->mac_address)); + + if (mp->is_ipv6) + { + clib_memcpy (&ip6, &mp->ip_address, sizeof (ip6)); + vat_json_object_add_ip6 (node, "ip_address", ip6); + } + else + { + clib_memcpy (&ip4, &mp->ip_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "ip_address", ip4); + } +} + +static int +api_ip_neighbor_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ip_neighbor_dump_t *mp; + f64 timeout; + u8 is_ipv6 = 0; + u32 sw_if_index = ~0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (i, "ip6")) + is_ipv6 = 1; + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (IP_NEIGHBOR_DUMP, ip_neighbor_dump); + mp->is_ipv6 = (u8) is_ipv6; + mp->sw_if_index = ntohl (sw_if_index); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +#define vl_api_ip6_fib_details_t_endian vl_noop_handler +#define vl_api_ip6_fib_details_t_print vl_noop_handler + +static void +vl_api_ip6_fib_details_t_handler (vl_api_ip6_fib_details_t * mp) +{ + vat_main_t *vam = &vat_main; + int count = ntohl (mp->count); + vl_api_fib_path_t *fp; + int i; + + print (vam->ofp, + "table-id %d, prefix %U/%d", + ntohl (mp->table_id), format_ip6_address, mp->address, + mp->address_length); + fp = mp->path; + for (i = 0; i < count; i++) + { + if (fp->afi == IP46_TYPE_IP6) + print (vam->ofp, + " weight %d, sw_if_index %d, is_local %d, is_drop %d, " + "is_unreach %d, is_prohitbit %d, afi %d, next_hop %U", + ntohl (fp->weight), ntohl (fp->sw_if_index), fp->is_local, + fp->is_drop, fp->is_unreach, fp->is_prohibit, fp->afi, + format_ip6_address, fp->next_hop); + else if (fp->afi == IP46_TYPE_IP4) + print (vam->ofp, + " weight %d, sw_if_index %d, is_local %d, is_drop %d, " + "is_unreach %d, is_prohitbit %d, afi %d, next_hop %U", + ntohl (fp->weight), ntohl (fp->sw_if_index), fp->is_local, + fp->is_drop, fp->is_unreach, fp->is_prohibit, fp->afi, + format_ip4_address, fp->next_hop); + fp++; + } +} + +static void vl_api_ip6_fib_details_t_handler_json + (vl_api_ip6_fib_details_t * mp) +{ + vat_main_t *vam = &vat_main; + int count = ntohl (mp->count); + vat_json_node_t *node = NULL; + struct in_addr ip4; + struct in6_addr ip6; + vl_api_fib_path_t *fp; + int i; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "table", ntohl (mp->table_id)); + clib_memcpy (&ip6, &mp->address, sizeof (ip6)); + vat_json_object_add_ip6 (node, "prefix", ip6); + vat_json_object_add_uint (node, "mask_length", mp->address_length); + vat_json_object_add_uint (node, "path_count", count); + fp = mp->path; + for (i = 0; i < count; i++) + { + vat_json_object_add_uint (node, "weight", ntohl (fp->weight)); + vat_json_object_add_uint (node, "sw_if_index", ntohl (fp->sw_if_index)); + vat_json_object_add_uint (node, "is_local", fp->is_local); + vat_json_object_add_uint (node, "is_drop", fp->is_drop); + vat_json_object_add_uint (node, "is_unreach", fp->is_unreach); + vat_json_object_add_uint (node, "is_prohibit", fp->is_prohibit); + vat_json_object_add_uint (node, "next_hop_afi", fp->afi); + if (fp->afi == IP46_TYPE_IP4) + { + clib_memcpy (&ip4, &fp->next_hop, sizeof (ip4)); + vat_json_object_add_ip4 (node, "next_hop", ip4); + } + else if (fp->afi == IP46_TYPE_IP6) + { + clib_memcpy (&ip6, &fp->next_hop, sizeof (ip6)); + vat_json_object_add_ip6 (node, "next_hop", ip6); + } + } +} + +static int +api_ip6_fib_dump (vat_main_t * vam) +{ + vl_api_ip6_fib_dump_t *mp; + f64 timeout; + + M (IP6_FIB_DUMP, ip6_fib_dump); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +int +api_classify_table_ids (vat_main_t * vam) +{ + vl_api_classify_table_ids_t *mp; + f64 timeout; + + /* Construct the API message */ + M (CLASSIFY_TABLE_IDS, classify_table_ids); + mp->context = 0; + + S; + W; + /* NOTREACHED */ + return 0; +} + +int +api_classify_table_by_interface (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_classify_table_by_interface_t *mp; + f64 timeout; + + u32 sw_if_index = ~0; + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (input, "sw_if_index %d", &sw_if_index)) + ; + else + break; + } + if (sw_if_index == ~0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (CLASSIFY_TABLE_BY_INTERFACE, classify_table_by_interface); + mp->context = 0; + mp->sw_if_index = ntohl (sw_if_index); + + S; + W; + /* NOTREACHED */ + return 0; +} + +int +api_classify_table_info (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_classify_table_info_t *mp; + f64 timeout; + + u32 table_id = ~0; + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "table_id %d", &table_id)) + ; + else + break; + } + if (table_id == ~0) + { + errmsg ("missing table id"); + return -99; + } + + /* Construct the API message */ + M (CLASSIFY_TABLE_INFO, classify_table_info); + mp->context = 0; + mp->table_id = ntohl (table_id); + + S; + W; + /* NOTREACHED */ + return 0; +} + +int +api_classify_session_dump (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_classify_session_dump_t *mp; + f64 timeout; + + u32 table_id = ~0; + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "table_id %d", &table_id)) + ; + else + break; + } + if (table_id == ~0) + { + errmsg ("missing table id"); + return -99; + } + + /* Construct the API message */ + M (CLASSIFY_SESSION_DUMP, classify_session_dump); + mp->context = 0; + mp->table_id = ntohl (table_id); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; + /* NOTREACHED */ + return 0; +} + +static void +vl_api_ipfix_exporter_details_t_handler (vl_api_ipfix_exporter_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "collector_address %U, collector_port %d, " + "src_address %U, vrf_id %d, path_mtu %u, " + "template_interval %u, udp_checksum %d", + format_ip4_address, mp->collector_address, + ntohs (mp->collector_port), + format_ip4_address, mp->src_address, + ntohl (mp->vrf_id), ntohl (mp->path_mtu), + ntohl (mp->template_interval), mp->udp_checksum); + + vam->retval = 0; + vam->result_ready = 1; +} + +static void + vl_api_ipfix_exporter_details_t_handler_json + (vl_api_ipfix_exporter_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + struct in_addr collector_address; + struct in_addr src_address; + + vat_json_init_object (&node); + clib_memcpy (&collector_address, &mp->collector_address, + sizeof (collector_address)); + vat_json_object_add_ip4 (&node, "collector_address", collector_address); + vat_json_object_add_uint (&node, "collector_port", + ntohs (mp->collector_port)); + clib_memcpy (&src_address, &mp->src_address, sizeof (src_address)); + vat_json_object_add_ip4 (&node, "src_address", src_address); + vat_json_object_add_int (&node, "vrf_id", ntohl (mp->vrf_id)); + vat_json_object_add_uint (&node, "path_mtu", ntohl (mp->path_mtu)); + vat_json_object_add_uint (&node, "template_interval", + ntohl (mp->template_interval)); + vat_json_object_add_int (&node, "udp_checksum", mp->udp_checksum); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + vam->retval = 0; + vam->result_ready = 1; +} + +int +api_ipfix_exporter_dump (vat_main_t * vam) +{ + vl_api_ipfix_exporter_dump_t *mp; + f64 timeout; + + /* Construct the API message */ + M (IPFIX_EXPORTER_DUMP, ipfix_exporter_dump); + mp->context = 0; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ipfix_classify_stream_dump (vat_main_t * vam) +{ + vl_api_ipfix_classify_stream_dump_t *mp; + f64 timeout; + + /* Construct the API message */ + M (IPFIX_CLASSIFY_STREAM_DUMP, ipfix_classify_stream_dump); + mp->context = 0; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static void + vl_api_ipfix_classify_stream_details_t_handler + (vl_api_ipfix_classify_stream_details_t * mp) +{ + vat_main_t *vam = &vat_main; + print (vam->ofp, "domain_id %d, src_port %d", + ntohl (mp->domain_id), ntohs (mp->src_port)); + vam->retval = 0; + vam->result_ready = 1; +} + +static void + vl_api_ipfix_classify_stream_details_t_handler_json + (vl_api_ipfix_classify_stream_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_uint (&node, "domain_id", ntohl (mp->domain_id)); + vat_json_object_add_uint (&node, "src_port", ntohs (mp->src_port)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + vam->retval = 0; + vam->result_ready = 1; +} + +static int +api_ipfix_classify_table_dump (vat_main_t * vam) +{ + vl_api_ipfix_classify_table_dump_t *mp; + f64 timeout; + + if (!vam->json_output) + { + print (vam->ofp, "%15s%15s%20s", "table_id", "ip_version", + "transport_protocol"); + } + + /* Construct the API message */ + M (IPFIX_CLASSIFY_TABLE_DUMP, ipfix_classify_table_dump); + + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static void + vl_api_ipfix_classify_table_details_t_handler + (vl_api_ipfix_classify_table_details_t * mp) +{ + vat_main_t *vam = &vat_main; + print (vam->ofp, "%15d%15d%20d", ntohl (mp->table_id), mp->ip_version, + mp->transport_protocol); +} + +static void + vl_api_ipfix_classify_table_details_t_handler_json + (vl_api_ipfix_classify_table_details_t * mp) +{ + vat_json_node_t *node = NULL; + vat_main_t *vam = &vat_main; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + + node = vat_json_array_add (&vam->json_tree); + vat_json_init_object (node); + + vat_json_object_add_uint (node, "table_id", ntohl (mp->table_id)); + vat_json_object_add_uint (node, "ip_version", mp->ip_version); + vat_json_object_add_uint (node, "transport_protocol", + mp->transport_protocol); +} + +static int +api_sw_interface_span_enable_disable (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_span_enable_disable_t *mp; + f64 timeout; + u32 src_sw_if_index = ~0; + u32 dst_sw_if_index = ~0; + u8 state = 3; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat + (i, "src %U", api_unformat_sw_if_index, vam, &src_sw_if_index)) + ; + else if (unformat (i, "src_sw_if_index %d", &src_sw_if_index)) + ; + else + if (unformat + (i, "dst %U", api_unformat_sw_if_index, vam, &dst_sw_if_index)) + ; + else if (unformat (i, "dst_sw_if_index %d", &dst_sw_if_index)) + ; + else if (unformat (i, "disable")) + state = 0; + else if (unformat (i, "rx")) + state = 1; + else if (unformat (i, "tx")) + state = 2; + else if (unformat (i, "both")) + state = 3; + else + break; + } + + M (SW_INTERFACE_SPAN_ENABLE_DISABLE, sw_interface_span_enable_disable); + + mp->sw_if_index_from = htonl (src_sw_if_index); + mp->sw_if_index_to = htonl (dst_sw_if_index); + mp->state = state; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static void +vl_api_sw_interface_span_details_t_handler (vl_api_sw_interface_span_details_t + * mp) +{ + vat_main_t *vam = &vat_main; + u8 *sw_if_from_name = 0; + u8 *sw_if_to_name = 0; + u32 sw_if_index_from = ntohl (mp->sw_if_index_from); + u32 sw_if_index_to = ntohl (mp->sw_if_index_to); + char *states[] = { "none", "rx", "tx", "both" }; + hash_pair_t *p; + + /* *INDENT-OFF* */ + hash_foreach_pair (p, vam->sw_if_index_by_interface_name, + ({ + if ((u32) p->value[0] == sw_if_index_from) + { + sw_if_from_name = (u8 *)(p->key); + if (sw_if_to_name) + break; + } + if ((u32) p->value[0] == sw_if_index_to) + { + sw_if_to_name = (u8 *)(p->key); + if (sw_if_from_name) + break; + } + })); + /* *INDENT-ON* */ + print (vam->ofp, "%20s => %20s (%s)", + sw_if_from_name, sw_if_to_name, states[mp->state]); +} + +static void + vl_api_sw_interface_span_details_t_handler_json + (vl_api_sw_interface_span_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + u8 *sw_if_from_name = 0; + u8 *sw_if_to_name = 0; + u32 sw_if_index_from = ntohl (mp->sw_if_index_from); + u32 sw_if_index_to = ntohl (mp->sw_if_index_to); + hash_pair_t *p; + + /* *INDENT-OFF* */ + hash_foreach_pair (p, vam->sw_if_index_by_interface_name, + ({ + if ((u32) p->value[0] == sw_if_index_from) + { + sw_if_from_name = (u8 *)(p->key); + if (sw_if_to_name) + break; + } + if ((u32) p->value[0] == sw_if_index_to) + { + sw_if_to_name = (u8 *)(p->key); + if (sw_if_from_name) + break; + } + })); + /* *INDENT-ON* */ + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "src-if-index", sw_if_index_from); + vat_json_object_add_string_copy (node, "src-if-name", sw_if_from_name); + vat_json_object_add_uint (node, "dst-if-index", sw_if_index_to); + vat_json_object_add_string_copy (node, "dst-if-name", sw_if_to_name); + vat_json_object_add_uint (node, "state", mp->state); +} + +static int +api_sw_interface_span_dump (vat_main_t * vam) +{ + vl_api_sw_interface_span_dump_t *mp; + f64 timeout; + + M (SW_INTERFACE_SPAN_DUMP, sw_interface_span_dump); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +int +api_pg_create_interface (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_pg_create_interface_t *mp; + f64 timeout; + + u32 if_id = ~0; + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "if_id %d", &if_id)) + ; + else + break; + } + if (if_id == ~0) + { + errmsg ("missing pg interface index"); + return -99; + } + + /* Construct the API message */ + M (PG_CREATE_INTERFACE, pg_create_interface); + mp->context = 0; + mp->interface_id = ntohl (if_id); + + S; + W; + /* NOTREACHED */ + return 0; +} + +int +api_pg_capture (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_pg_capture_t *mp; + f64 timeout; + + u32 if_id = ~0; + u8 enable = 1; + u32 count = 1; + u8 pcap_file_set = 0; + u8 *pcap_file = 0; + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "if_id %d", &if_id)) + ; + else if (unformat (input, "pcap %s", &pcap_file)) + pcap_file_set = 1; + else if (unformat (input, "count %d", &count)) + ; + else if (unformat (input, "disable")) + enable = 0; + else + break; + } + if (if_id == ~0) + { + errmsg ("missing pg interface index"); + return -99; + } + if (pcap_file_set > 0) + { + if (vec_len (pcap_file) > 255) + { + errmsg ("pcap file name is too long"); + return -99; + } + } + + u32 name_len = vec_len (pcap_file); + /* Construct the API message */ + M (PG_CAPTURE, pg_capture); + mp->context = 0; + mp->interface_id = ntohl (if_id); + mp->is_enabled = enable; + mp->count = ntohl (count); + mp->pcap_name_length = ntohl (name_len); + if (pcap_file_set != 0) + { + clib_memcpy (mp->pcap_file_name, pcap_file, name_len); + } + vec_free (pcap_file); + + S; + W; + /* NOTREACHED */ + return 0; +} + +int +api_pg_enable_disable (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_pg_enable_disable_t *mp; + f64 timeout; + + u8 enable = 1; + u8 stream_name_set = 0; + u8 *stream_name = 0; + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "stream %s", &stream_name)) + stream_name_set = 1; + else if (unformat (input, "disable")) + enable = 0; + else + break; + } + + if (stream_name_set > 0) + { + if (vec_len (stream_name) > 255) + { + errmsg ("stream name too long"); + return -99; + } + } + + u32 name_len = vec_len (stream_name); + /* Construct the API message */ + M (PG_ENABLE_DISABLE, pg_enable_disable); + mp->context = 0; + mp->is_enabled = enable; + if (stream_name_set != 0) + { + mp->stream_name_length = ntohl (name_len); + clib_memcpy (mp->stream_name, stream_name, name_len); + } + vec_free (stream_name); + + S; + W; + /* NOTREACHED */ + return 0; +} + +int +api_ip_source_and_port_range_check_add_del (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_ip_source_and_port_range_check_add_del_t *mp; + f64 timeout; + + u16 *low_ports = 0; + u16 *high_ports = 0; + u16 this_low; + u16 this_hi; + ip4_address_t ip4_addr; + ip6_address_t ip6_addr; + u32 length; + u32 tmp, tmp2; + u8 prefix_set = 0; + u32 vrf_id = ~0; + u8 is_add = 1; + u8 is_ipv6 = 0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "%U/%d", unformat_ip4_address, &ip4_addr, &length)) + { + prefix_set = 1; + } + else + if (unformat + (input, "%U/%d", unformat_ip6_address, &ip6_addr, &length)) + { + prefix_set = 1; + is_ipv6 = 1; + } + else if (unformat (input, "vrf %d", &vrf_id)) + ; + else if (unformat (input, "del")) + is_add = 0; + else if (unformat (input, "port %d", &tmp)) + { + if (tmp == 0 || tmp > 65535) + { + errmsg ("port %d out of range", tmp); + return -99; + } + this_low = tmp; + this_hi = this_low + 1; + vec_add1 (low_ports, this_low); + vec_add1 (high_ports, this_hi); + } + else if (unformat (input, "range %d - %d", &tmp, &tmp2)) + { + if ((tmp > tmp2) || (tmp == 0) || (tmp2 > 65535)) + { + errmsg ("incorrect range parameters"); + return -99; + } + this_low = tmp; + /* Note: in debug CLI +1 is added to high before + passing to real fn that does "the work" + (ip_source_and_port_range_check_add_del). + This fn is a wrapper around the binary API fn a + control plane will call, which expects this increment + to have occurred. Hence letting the binary API control + plane fn do the increment for consistency between VAT + and other control planes. + */ + this_hi = tmp2; + vec_add1 (low_ports, this_low); + vec_add1 (high_ports, this_hi); + } + else + break; + } + + if (prefix_set == 0) + { + errmsg ("
/ not specified"); + return -99; + } + + if (vrf_id == ~0) + { + errmsg ("VRF ID required, not specified"); + return -99; + } + + if (vrf_id == 0) + { + errmsg + ("VRF ID should not be default. Should be distinct VRF for this purpose."); + return -99; + } + + if (vec_len (low_ports) == 0) + { + errmsg ("At least one port or port range required"); + return -99; + } + + M (IP_SOURCE_AND_PORT_RANGE_CHECK_ADD_DEL, + ip_source_and_port_range_check_add_del); + + mp->is_add = is_add; + + if (is_ipv6) + { + mp->is_ipv6 = 1; + clib_memcpy (mp->address, &ip6_addr, sizeof (ip6_addr)); + } + else + { + mp->is_ipv6 = 0; + clib_memcpy (mp->address, &ip4_addr, sizeof (ip4_addr)); + } + + mp->mask_length = length; + mp->number_of_ranges = vec_len (low_ports); + + clib_memcpy (mp->low_ports, low_ports, vec_len (low_ports)); + vec_free (low_ports); + + clib_memcpy (mp->high_ports, high_ports, vec_len (high_ports)); + vec_free (high_ports); + + mp->vrf_id = ntohl (vrf_id); + + S; + W; + /* NOTREACHED */ + return 0; +} + +int +api_ip_source_and_port_range_check_interface_add_del (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_ip_source_and_port_range_check_interface_add_del_t *mp; + f64 timeout; + u32 sw_if_index = ~0; + int vrf_set = 0; + u32 tcp_out_vrf_id = ~0, udp_out_vrf_id = ~0; + u32 tcp_in_vrf_id = ~0, udp_in_vrf_id = ~0; + u8 is_add = 1; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (input, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (input, "tcp-out-vrf %d", &tcp_out_vrf_id)) + vrf_set = 1; + else if (unformat (input, "udp-out-vrf %d", &udp_out_vrf_id)) + vrf_set = 1; + else if (unformat (input, "tcp-in-vrf %d", &tcp_in_vrf_id)) + vrf_set = 1; + else if (unformat (input, "udp-in-vrf %d", &udp_in_vrf_id)) + vrf_set = 1; + else if (unformat (input, "del")) + is_add = 0; + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("Interface required but not specified"); + return -99; + } + + if (vrf_set == 0) + { + errmsg ("VRF ID required but not specified"); + return -99; + } + + if (tcp_out_vrf_id == 0 + || udp_out_vrf_id == 0 || tcp_in_vrf_id == 0 || udp_in_vrf_id == 0) + { + errmsg + ("VRF ID should not be default. Should be distinct VRF for this purpose."); + return -99; + } + + /* Construct the API message */ + M (IP_SOURCE_AND_PORT_RANGE_CHECK_INTERFACE_ADD_DEL, + ip_source_and_port_range_check_interface_add_del); + + mp->sw_if_index = ntohl (sw_if_index); + mp->is_add = is_add; + mp->tcp_out_vrf_id = ntohl (tcp_out_vrf_id); + mp->udp_out_vrf_id = ntohl (udp_out_vrf_id); + mp->tcp_in_vrf_id = ntohl (tcp_in_vrf_id); + mp->udp_in_vrf_id = ntohl (udp_in_vrf_id); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int +api_ipsec_gre_add_del_tunnel (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ipsec_gre_add_del_tunnel_t *mp; + f64 timeout; + u32 local_sa_id = 0; + u32 remote_sa_id = 0; + ip4_address_t src_address; + ip4_address_t dst_address; + u8 is_add = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "local_sa %d", &local_sa_id)) + ; + else if (unformat (i, "remote_sa %d", &remote_sa_id)) + ; + else if (unformat (i, "src %U", unformat_ip4_address, &src_address)) + ; + else if (unformat (i, "dst %U", unformat_ip4_address, &dst_address)) + ; + else if (unformat (i, "del")) + is_add = 0; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + M (IPSEC_GRE_ADD_DEL_TUNNEL, ipsec_gre_add_del_tunnel); + + mp->local_sa_id = ntohl (local_sa_id); + mp->remote_sa_id = ntohl (remote_sa_id); + clib_memcpy (mp->src_address, &src_address, sizeof (src_address)); + clib_memcpy (mp->dst_address, &dst_address, sizeof (dst_address)); + mp->is_add = is_add; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_punt (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_punt_t *mp; + f64 timeout; + u32 ipv = ~0; + u32 protocol = ~0; + u32 port = ~0; + int is_add = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "ip %d", &ipv)) + ; + else if (unformat (i, "protocol %d", &protocol)) + ; + else if (unformat (i, "port %d", &port)) + ; + else if (unformat (i, "del")) + is_add = 0; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + M (PUNT, punt); + + mp->is_add = (u8) is_add; + mp->ipv = (u8) ipv; + mp->l4_protocol = (u8) protocol; + mp->l4_port = htons ((u16) port); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static void vl_api_ipsec_gre_tunnel_details_t_handler + (vl_api_ipsec_gre_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%11d%15U%15U%14d%14d", + ntohl (mp->sw_if_index), + format_ip4_address, &mp->src_address, + format_ip4_address, &mp->dst_address, + ntohl (mp->local_sa_id), ntohl (mp->remote_sa_id)); +} + +static void vl_api_ipsec_gre_tunnel_details_t_handler_json + (vl_api_ipsec_gre_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + struct in_addr ip4; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + clib_memcpy (&ip4, &mp->src_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "src_address", ip4); + clib_memcpy (&ip4, &mp->dst_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "dst_address", ip4); + vat_json_object_add_uint (node, "local_sa_id", ntohl (mp->local_sa_id)); + vat_json_object_add_uint (node, "remote_sa_id", ntohl (mp->remote_sa_id)); +} + +static int +api_ipsec_gre_tunnel_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ipsec_gre_tunnel_dump_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + sw_if_index = ~0; + } + + if (!vam->json_output) + { + print (vam->ofp, "%11s%15s%15s%14s%14s", + "sw_if_index", "src_address", "dst_address", + "local_sa_id", "remote_sa_id"); + } + + /* Get list of gre-tunnel interfaces */ + M (IPSEC_GRE_TUNNEL_DUMP, ipsec_gre_tunnel_dump); + + mp->sw_if_index = htonl (sw_if_index); + + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static int +api_delete_subif (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_delete_subif_t *mp; + f64 timeout; + u32 sw_if_index = ~0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + ; + if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("missing sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (DELETE_SUBIF, delete_subif); + mp->sw_if_index = ntohl (sw_if_index); + + S; + W; +} + +#define foreach_pbb_vtr_op \ +_("disable", L2_VTR_DISABLED) \ +_("pop", L2_VTR_POP_2) \ +_("push", L2_VTR_PUSH_2) + +static int +api_l2_interface_pbb_tag_rewrite (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_l2_interface_pbb_tag_rewrite_t *mp; + f64 timeout; + u32 sw_if_index = ~0, vtr_op = ~0; + u16 outer_tag = ~0; + u8 dmac[6], smac[6]; + u8 dmac_set = 0, smac_set = 0; + u16 vlanid = 0; + u32 sid = ~0; + u32 tmp; + + /* Shut up coverity */ + memset (dmac, 0, sizeof (dmac)); + memset (smac, 0, sizeof (smac)); + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (i, "vtr_op %d", &vtr_op)) + ; +#define _(n,v) else if (unformat(i, n)) {vtr_op = v;} + foreach_pbb_vtr_op +#undef _ + else if (unformat (i, "translate_pbb_stag")) + { + if (unformat (i, "%d", &tmp)) + { + vtr_op = L2_VTR_TRANSLATE_2_1; + outer_tag = tmp; + } + else + { + errmsg + ("translate_pbb_stag operation requires outer tag definition"); + return -99; + } + } + else if (unformat (i, "dmac %U", unformat_ethernet_address, dmac)) + dmac_set++; + else if (unformat (i, "smac %U", unformat_ethernet_address, smac)) + smac_set++; + else if (unformat (i, "sid %d", &sid)) + ; + else if (unformat (i, "vlanid %d", &tmp)) + vlanid = tmp; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if ((sw_if_index == ~0) || (vtr_op == ~0)) + { + errmsg ("missing sw_if_index or vtr operation"); + return -99; + } + if (((vtr_op == L2_VTR_PUSH_2) || (vtr_op == L2_VTR_TRANSLATE_2_2)) + && ((dmac_set == 0) || (smac_set == 0) || (sid == ~0))) + { + errmsg + ("push and translate_qinq operations require dmac, smac, sid and optionally vlanid"); + return -99; + } + + M (L2_INTERFACE_PBB_TAG_REWRITE, l2_interface_pbb_tag_rewrite); + mp->sw_if_index = ntohl (sw_if_index); + mp->vtr_op = ntohl (vtr_op); + mp->outer_tag = ntohs (outer_tag); + clib_memcpy (mp->b_dmac, dmac, sizeof (dmac)); + clib_memcpy (mp->b_smac, smac, sizeof (smac)); + mp->b_vlanid = ntohs (vlanid); + mp->i_sid = ntohl (sid); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_flow_classify_set_interface (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_flow_classify_set_interface_t *mp; + f64 timeout; + u32 sw_if_index; + int sw_if_index_set; + u32 ip4_table_index = ~0; + u32 ip6_table_index = ~0; + u8 is_add = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_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, "del")) + is_add = 0; + else if (unformat (i, "ip4-table %d", &ip4_table_index)) + ; + else if (unformat (i, "ip6-table %d", &ip6_table_index)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (FLOW_CLASSIFY_SET_INTERFACE, flow_classify_set_interface); + + mp->sw_if_index = ntohl (sw_if_index); + mp->ip4_table_index = ntohl (ip4_table_index); + mp->ip6_table_index = ntohl (ip6_table_index); + mp->is_add = is_add; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_flow_classify_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_flow_classify_dump_t *mp; + f64 timeout = ~0; + u8 type = FLOW_CLASSIFY_N_TABLES; + + if (unformat (i, "type %U", unformat_flow_classify_table_type, &type)) + ; + else + { + errmsg ("classify table type must be specified"); + return -99; + } + + if (!vam->json_output) + { + print (vam->ofp, "%10s%20s", "Intfc idx", "Classify table"); + } + + M (FLOW_CLASSIFY_DUMP, flow_classify_dump); + mp->type = type; + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_feature_enable_disable (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_feature_enable_disable_t *mp; + f64 timeout; + u8 *arc_name = 0; + u8 *feature_name = 0; + u32 sw_if_index = ~0; + u8 enable = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "arc_name %s", &arc_name)) + ; + else if (unformat (i, "feature_name %s", &feature_name)) + ; + else + if (unformat (i, "%U", api_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 = 0; + else + break; + } + + if (arc_name == 0) + { + errmsg ("missing arc name"); + return -99; + } + if (vec_len (arc_name) > 63) + { + errmsg ("arc name too long"); + } + + if (feature_name == 0) + { + errmsg ("missing feature name"); + return -99; + } + if (vec_len (feature_name) > 63) + { + errmsg ("feature name too long"); + } + + if (sw_if_index == ~0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (FEATURE_ENABLE_DISABLE, feature_enable_disable); + mp->sw_if_index = ntohl (sw_if_index); + mp->enable = enable; + clib_memcpy (mp->arc_name, arc_name, vec_len (arc_name)); + clib_memcpy (mp->feature_name, feature_name, vec_len (feature_name)); + vec_free (arc_name); + vec_free (feature_name); + + S; + W; +} + +static int +api_sw_interface_tag_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_tag_add_del_t *mp; + f64 timeout; + u32 sw_if_index = ~0; + u8 *tag = 0; + u8 enable = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "tag %s", &tag)) + ; + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (i, "del")) + enable = 0; + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (enable && (tag == 0)) + { + errmsg ("no tag specified"); + return -99; + } + + /* Construct the API message */ + M (SW_INTERFACE_TAG_ADD_DEL, sw_interface_tag_add_del); + mp->sw_if_index = ntohl (sw_if_index); + mp->is_add = enable; + if (enable) + strncpy ((char *) mp->tag, (char *) tag, ARRAY_LEN (mp->tag) - 1); + vec_free (tag); + + S; + W; +} + +static void vl_api_l2_xconnect_details_t_handler + (vl_api_l2_xconnect_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%15d%15d", + ntohl (mp->rx_sw_if_index), ntohl (mp->tx_sw_if_index)); +} + +static void vl_api_l2_xconnect_details_t_handler_json + (vl_api_l2_xconnect_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "rx_sw_if_index", + ntohl (mp->rx_sw_if_index)); + vat_json_object_add_uint (node, "tx_sw_if_index", + ntohl (mp->tx_sw_if_index)); +} + +static int +api_l2_xconnect_dump (vat_main_t * vam) +{ + vl_api_l2_xconnect_dump_t *mp; + f64 timeout; + + if (!vam->json_output) + { + print (vam->ofp, "%15s%15s", "rx_sw_if_index", "tx_sw_if_index"); + } + + M (L2_XCONNECT_DUMP, l2_xconnect_dump); + + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static int +api_sw_interface_set_mtu (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_mtu_t *mp; + f64 timeout; + u32 sw_if_index = ~0; + u32 mtu = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "mtu %d", &mtu)) + ; + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (mtu == 0) + { + errmsg ("no mtu specified"); + return -99; + } + + /* Construct the API message */ + M (SW_INTERFACE_SET_MTU, sw_interface_set_mtu); + mp->sw_if_index = ntohl (sw_if_index); + mp->mtu = ntohs ((u16) mtu); + + S; + W; +} + + +static int +q_or_quit (vat_main_t * vam) +{ + longjmp (vam->jump_buf, 1); + return 0; /* not so much */ +} + +static int +q (vat_main_t * vam) +{ + return q_or_quit (vam); +} + +static int +quit (vat_main_t * vam) +{ + return q_or_quit (vam); +} + +static int +comment (vat_main_t * vam) +{ + return 0; +} + +static int +cmd_cmp (void *a1, void *a2) +{ + u8 **c1 = a1; + u8 **c2 = a2; + + return strcmp ((char *) (c1[0]), (char *) (c2[0])); +} + +static int +help (vat_main_t * vam) +{ + u8 **cmds = 0; + u8 *name = 0; + hash_pair_t *p; + unformat_input_t *i = vam->input; + int j; + + if (unformat (i, "%s", &name)) + { + uword *hs; + + vec_add1 (name, 0); + + hs = hash_get_mem (vam->help_by_name, name); + if (hs) + print (vam->ofp, "usage: %s %s", name, hs[0]); + else + print (vam->ofp, "No such msg / command '%s'", name); + vec_free (name); + return 0; + } + + print (vam->ofp, "Help is available for the following:"); + + /* *INDENT-OFF* */ + hash_foreach_pair (p, vam->function_by_name, + ({ + vec_add1 (cmds, (u8 *)(p->key)); + })); + /* *INDENT-ON* */ + + vec_sort_with_function (cmds, cmd_cmp); + + for (j = 0; j < vec_len (cmds); j++) + print (vam->ofp, "%s", cmds[j]); + + vec_free (cmds); + return 0; +} + +static int +set (vat_main_t * vam) +{ + u8 *name = 0, *value = 0; + unformat_input_t *i = vam->input; + + if (unformat (i, "%s", &name)) + { + /* The input buffer is a vector, not a string. */ + value = vec_dup (i->buffer); + vec_delete (value, i->index, 0); + /* Almost certainly has a trailing newline */ + if (value[vec_len (value) - 1] == '\n') + value[vec_len (value) - 1] = 0; + /* Make sure it's a proper string, one way or the other */ + vec_add1 (value, 0); + (void) clib_macro_set_value (&vam->macro_main, + (char *) name, (char *) value); + } + else + errmsg ("usage: set "); + + vec_free (name); + vec_free (value); + return 0; +} + +static int +unset (vat_main_t * vam) +{ + u8 *name = 0; + + if (unformat (vam->input, "%s", &name)) + if (clib_macro_unset (&vam->macro_main, (char *) name) == 1) + errmsg ("unset: %s wasn't set", name); + vec_free (name); + return 0; +} + +typedef struct +{ + u8 *name; + u8 *value; +} macro_sort_t; + + +static int +macro_sort_cmp (void *a1, void *a2) +{ + macro_sort_t *s1 = a1; + macro_sort_t *s2 = a2; + + return strcmp ((char *) (s1->name), (char *) (s2->name)); +} + +static int +dump_macro_table (vat_main_t * vam) +{ + macro_sort_t *sort_me = 0, *sm; + int i; + hash_pair_t *p; + + /* *INDENT-OFF* */ + hash_foreach_pair (p, vam->macro_main.the_value_table_hash, + ({ + vec_add2 (sort_me, sm, 1); + sm->name = (u8 *)(p->key); + sm->value = (u8 *) (p->value[0]); + })); + /* *INDENT-ON* */ + + vec_sort_with_function (sort_me, macro_sort_cmp); + + if (vec_len (sort_me)) + print (vam->ofp, "%-15s%s", "Name", "Value"); + else + print (vam->ofp, "The macro table is empty..."); + + for (i = 0; i < vec_len (sort_me); i++) + print (vam->ofp, "%-15s%s", sort_me[i].name, sort_me[i].value); + return 0; +} + +static int +dump_node_table (vat_main_t * vam) +{ + int i, j; + vlib_node_t *node, *next_node; + + if (vec_len (vam->graph_nodes) == 0) + { + print (vam->ofp, "Node table empty, issue get_node_graph..."); + return 0; + } + + for (i = 0; i < vec_len (vam->graph_nodes); i++) + { + node = vam->graph_nodes[i]; + print (vam->ofp, "[%d] %s", i, node->name); + for (j = 0; j < vec_len (node->next_nodes); j++) + { + if (node->next_nodes[j] != ~0) + { + next_node = vam->graph_nodes[node->next_nodes[j]]; + print (vam->ofp, " [%d] %s", j, next_node->name); + } + } + } + return 0; +} + +static int +value_sort_cmp (void *a1, void *a2) +{ + name_sort_t *n1 = a1; + name_sort_t *n2 = a2; + + if (n1->value < n2->value) + return -1; + if (n1->value > n2->value) + return 1; + return 0; +} + + +static int +dump_msg_api_table (vat_main_t * vam) +{ + api_main_t *am = &api_main; + name_sort_t *nses = 0, *ns; + hash_pair_t *hp; + int i; + + /* *INDENT-OFF* */ + hash_foreach_pair (hp, am->msg_index_by_name_and_crc, + ({ + vec_add2 (nses, ns, 1); + ns->name = (u8 *)(hp->key); + ns->value = (u32) hp->value[0]; + })); + /* *INDENT-ON* */ + + vec_sort_with_function (nses, value_sort_cmp); + + for (i = 0; i < vec_len (nses); i++) + print (vam->ofp, " [%d]: %s", nses[i].value, nses[i].name); + vec_free (nses); + return 0; +} + +static int +get_msg_id (vat_main_t * vam) +{ + u8 *name_and_crc; + u32 message_index; + + if (unformat (vam->input, "%s", &name_and_crc)) + { + message_index = vl_api_get_msg_index (name_and_crc); + if (message_index == ~0) + { + print (vam->ofp, " '%s' not found", name_and_crc); + return 0; + } + print (vam->ofp, " '%s' has message index %d", + name_and_crc, message_index); + return 0; + } + errmsg ("name_and_crc required..."); + return 0; +} + +static int +search_node_table (vat_main_t * vam) +{ + unformat_input_t *line_input = vam->input; + u8 *node_to_find; + int j; + vlib_node_t *node, *next_node; + uword *p; + + if (vam->graph_node_index_by_name == 0) + { + print (vam->ofp, "Node table empty, issue get_node_graph..."); + return 0; + } + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "%s", &node_to_find)) + { + vec_add1 (node_to_find, 0); + p = hash_get_mem (vam->graph_node_index_by_name, node_to_find); + if (p == 0) + { + print (vam->ofp, "%s not found...", node_to_find); + goto out; + } + node = vam->graph_nodes[p[0]]; + print (vam->ofp, "[%d] %s", p[0], node->name); + for (j = 0; j < vec_len (node->next_nodes); j++) + { + if (node->next_nodes[j] != ~0) + { + next_node = vam->graph_nodes[node->next_nodes[j]]; + print (vam->ofp, " [%d] %s", j, next_node->name); + } + } + } + + else + { + clib_warning ("parse error '%U'", format_unformat_error, + line_input); + return -99; + } + + out: + vec_free (node_to_find); + + } + + return 0; +} + + +static int +script (vat_main_t * vam) +{ +#if (VPP_API_TEST_BUILTIN==0) + u8 *s = 0; + char *save_current_file; + unformat_input_t save_input; + jmp_buf save_jump_buf; + u32 save_line_number; + + FILE *new_fp, *save_ifp; + + if (unformat (vam->input, "%s", &s)) + { + new_fp = fopen ((char *) s, "r"); + if (new_fp == 0) + { + errmsg ("Couldn't open script file %s", s); + vec_free (s); + return -99; + } + } + else + { + errmsg ("Missing script name"); + return -99; + } + + clib_memcpy (&save_input, &vam->input, sizeof (save_input)); + clib_memcpy (&save_jump_buf, &vam->jump_buf, sizeof (save_jump_buf)); + save_ifp = vam->ifp; + save_line_number = vam->input_line_number; + save_current_file = (char *) vam->current_file; + + vam->input_line_number = 0; + vam->ifp = new_fp; + vam->current_file = s; + do_one_file (vam); + + clib_memcpy (&vam->input, &save_input, sizeof (vam->input)); + clib_memcpy (&vam->jump_buf, &save_jump_buf, sizeof (save_jump_buf)); + vam->ifp = save_ifp; + vam->input_line_number = save_line_number; + vam->current_file = (u8 *) save_current_file; + vec_free (s); + + return 0; +#else + clib_warning ("use the exec command..."); + return -99; +#endif +} + +static int +echo (vat_main_t * vam) +{ + print (vam->ofp, "%v", vam->input->buffer); + return 0; +} + +/* List of API message constructors, CLI names map to api_xxx */ +#define foreach_vpe_api_msg \ +_(create_loopback,"[mac ]") \ +_(sw_interface_dump,"") \ +_(sw_interface_set_flags, \ + " | sw_if_index admin-up | admin-down link-up | link down") \ +_(sw_interface_add_del_address, \ + " | sw_if_index | [del] [del-all] ") \ +_(sw_interface_set_table, \ + " | sw_if_index vrf [ipv6]") \ +_(sw_interface_set_mpls_enable, \ + " | sw_if_index [disable | dis]") \ +_(sw_interface_set_vpath, \ + " | sw_if_index enable | disable") \ +_(sw_interface_set_vxlan_bypass, \ + " | sw_if_index [ip4 | ip6] enable | disable") \ +_(sw_interface_set_l2_xconnect, \ + "rx | rx_sw_if_index tx | tx_sw_if_index \n" \ + "enable | disable") \ +_(sw_interface_set_l2_bridge, \ + " | sw_if_index bd_id \n" \ + "[shg ] [bvi]\n" \ + "enable | disable") \ +_(sw_interface_set_dpdk_hqos_pipe, \ + "rx | sw_if_index subport pipe \n" \ + "profile \n") \ +_(sw_interface_set_dpdk_hqos_subport, \ + "rx | sw_if_index subport [rate ]\n" \ + "[bktsize ] [tc0 ] [tc1 ] [tc2 ] [tc3 ] [period ]\n") \ +_(sw_interface_set_dpdk_hqos_tctbl, \ + "rx | sw_if_index entry tc queue \n") \ +_(bridge_domain_add_del, \ + "bd_id [flood 1|0] [uu-flood 1|0] [forward 1|0] [learn 1|0] [arp-term 1|0] [del]\n") \ +_(bridge_domain_dump, "[bd_id ]\n") \ +_(l2fib_add_del, \ + "mac bd_id [del] | sw_if | sw_if_index [static] [filter] [bvi] [count ]\n") \ +_(l2_flags, \ + "sw_if | sw_if_index [learn] [forward] [uu-flood] [flood]\n") \ +_(bridge_flags, \ + "bd_id [learn] [forward] [uu-flood] [flood] [arp-term] [disable]\n") \ +_(tap_connect, \ + "tapname mac | random-mac [tag ]") \ +_(tap_modify, \ + " | sw_if_index tapname mac | random-mac") \ +_(tap_delete, \ + " | sw_if_index ") \ +_(sw_interface_tap_dump, "") \ +_(ip_add_del_route, \ + "/ via [table-id ]\n" \ + "[ | sw_if_index ] [resolve-attempts ]\n" \ + "[weight ] [drop] [local] [classify ] [del]\n" \ + "[multipath] [count ]") \ +_(mpls_route_add_del, \ + "