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-root/scripts/find-dev-contents | 31 ++++++++++++++++++++++++ build-root/scripts/generate-deb-changelog | 37 ++++++++++++++++++++++++++++ build-root/scripts/make-plugin-toolkit | 40 +++++++++++++++++++++++++++++++ build-root/scripts/version | 22 +++++++++++++++++ 4 files changed, 130 insertions(+) create mode 100755 build-root/scripts/find-dev-contents create mode 100755 build-root/scripts/generate-deb-changelog create mode 100755 build-root/scripts/make-plugin-toolkit create mode 100755 build-root/scripts/version (limited to 'build-root/scripts') diff --git a/build-root/scripts/find-dev-contents b/build-root/scripts/find-dev-contents new file mode 100755 index 00000000..77028af0 --- /dev/null +++ b/build-root/scripts/find-dev-contents @@ -0,0 +1,31 @@ +#!/bin/bash + +# includes +paths=`find $1/*/include -type f -print | grep -v '/dpdk/include/'` +rm -f $2 + +for path in $paths +do + relpath=`echo $path | sed -e 's:.*/include/::'` + dir=`dirname $relpath` + if [ $dir = "." ] ; then + echo ../$path /usr/include >> $2 + else + echo ../$path /usr/include/$dir >> $2 + fi +done + +# sample plugin +paths=`(cd ..; find sample-plugin -type f -print | grep -v autom4te)` + +for path in $paths +do + relpath=`echo $path | sed -e 's:.*/sample-plugin/::'` + dir=`dirname $relpath` + if [ $dir = "sample-plugin" ] ; then + echo ../../$path /usr/share/doc/vpp/examples/sample-plugin >> $2 + else + echo ../../$path \ + /usr/share/doc/vpp/examples/$dir >> $2 + fi +done diff --git a/build-root/scripts/generate-deb-changelog b/build-root/scripts/generate-deb-changelog new file mode 100755 index 00000000..a1434312 --- /dev/null +++ b/build-root/scripts/generate-deb-changelog @@ -0,0 +1,37 @@ +#!/bin/bash + +CHANGELOG=deb/debian/changelog +DIST=unstable +FIRST=1 + +print_changelog_item() { + DATE=$(git log -1 --format=%cD ${TAG}) + DEBFULLNAME=$(git log -1 --format=%an ${TAG}) + DEBEMAIL=$(git log -1 --format=%ae ${TAG}) + + if [ ${FIRST} = 0 ]; then echo >> ${CHANGELOG}; fi + FIRST=0 + + echo "vpp (${VER}) ${DIST}; urgency=low" >> ${CHANGELOG} + echo >> ${CHANGELOG} + echo "${DESC}" >> ${CHANGELOG} + echo >> ${CHANGELOG} + echo " -- ${DEBFULLNAME} <${DEBEMAIL}> ${DATE}" >> ${CHANGELOG} +} + +VER=$(scripts/version) +TAG=HEAD +ADDS=$(echo ${VER} | sed -e 's/~.*//'| cut -s -d- -f2) + +rm -f ${CHANGELOG} + +if [ -n "${ADDS}" ]; then + DESC=" * includes ${ADDS} commits after $(echo ${VER}| cut -d- -f1) release" + print_changelog_item +fi + +for TAG in $(git tag -l 'v[0-9].[0-9].[0-9]' | sort -r ); do + VER=$(echo ${TAG}| sed -e 's/^v//') + DESC=$(git tag -l -n20 ${TAG} | tail -n+2 | sed -e 's/^ */ /') + print_changelog_item +done diff --git a/build-root/scripts/make-plugin-toolkit b/build-root/scripts/make-plugin-toolkit new file mode 100755 index 00000000..14e9eda2 --- /dev/null +++ b/build-root/scripts/make-plugin-toolkit @@ -0,0 +1,40 @@ +#!/bin/bash + +set -eux + +build_tarball() { + for dir in vppinfra dpdk svm vlib-api vlib vnet vpp vpp-api-test + do + tar -C install-$1/$dir/include -cf - . | tar -C $tmp_dir/include -xf - + done + tar -C ../sample-plugin -cf - . \ + | tar -C $tmp_dir/src/sample-plugin -xf - + cp tools/bin/vppapigen $tmp_dir/tools/bin + echo Created by `id -u -n` on `hostname` at `date` > \ + $tmp_dir/toolkit-version-stamp + cp scripts/vpp-plugin-toolkit-readme $tmp_dir/README + tar -C $tmp_dir -zcf $PWD/vpp-plugin-toolkit-$1.tar.gz . +} + +if [ `basename $PWD` != "build-root" ] ; then + echo Please run this script from build-root + exit 1 +fi + +echo Pull additional tookit repos +make PLATFORM=vpp sample-plugin-find-source + +make PLATFORM=vpp TAG=vpp wipe-all +echo Build vpp forwarder production package +make PLATFORM=vpp TAG=vpp V=0 strip_sumbols=yes install-packages + +tmp_dir="`mktemp -d /tmp/plugin-XXXXXX`" +trap "rm -rf $tmp_dir" err + +echo Create vpp forwarder production plugin toolkit tarball +mkdir -p $tmp_dir/tools/bin $tmp_dir/include $tmp_dir/lib64 \ + $tmp_dir/src/sample-plugin +build_tarball vpp-native +rm -rf $tmp_dir + +exit 0 diff --git a/build-root/scripts/version b/build-root/scripts/version new file mode 100755 index 00000000..9d236bc2 --- /dev/null +++ b/build-root/scripts/version @@ -0,0 +1,22 @@ +#!/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) + +if [ "$1" = "rpm-version" ]; then + echo ${TAG} + exit +fi + +if [ "$1" = "rpm-release" ]; then + [ -z "${ADD}" ] && echo release && exit + echo ${ADD}~${CMT} + exit +fi + +if [ -n "${ADD}" ]; then + echo ${TAG}-${ADD}~${CMT} +else + echo ${TAG} +fi -- cgit 1.2.3-korg From 0e5e3c3b62f2e4edbd9a8cdaccd5ad838545dd00 Mon Sep 17 00:00:00 2001 From: Dave Barach Date: Mon, 25 Jan 2016 08:28:22 -0500 Subject: Fix rpm packaging bit-rot Change-Id: Ia710b0773984891ee18c6c0558cc09b984043e38 Signed-off-by: Dave Barach --- build-root/rpm/vpp.spec | 1 + build-root/scripts/version | 1 + 2 files changed, 2 insertions(+) (limited to 'build-root/scripts') diff --git a/build-root/rpm/vpp.spec b/build-root/rpm/vpp.spec index fbadf07c..85b1286c 100644 --- a/build-root/rpm/vpp.spec +++ b/build-root/rpm/vpp.spec @@ -113,6 +113,7 @@ sysctl --system %{_unitdir}/vpp.service /usr/bin/vpp* /usr/bin/svm* +/usr/bin/elftool %config /etc/sysctl.d/80-vpp.conf %config /etc/vpp/startup.conf diff --git a/build-root/scripts/version b/build-root/scripts/version index 9d236bc2..bbafb9bb 100755 --- a/build-root/scripts/version +++ b/build-root/scripts/version @@ -11,6 +11,7 @@ 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} exit fi -- 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-root/scripts') 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 6b1d7c55d694fc6c0a262d6e1279fe207164e1b5 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Tue, 26 Apr 2016 18:19:47 +0200 Subject: Make automake silent rules default Change-Id: Ia504ccdac1deac20f20cf7fb76f78b2d8c505474 Signed-off-by: Damjan Marion --- Makefile | 3 +-- build-root/scripts/make-plugin-toolkit | 2 +- svm/configure.ac | 2 +- vlib-api/configure.ac | 2 +- vlib/configure.ac | 2 +- vnet/configure.ac | 2 +- vpp-api/configure.ac | 2 +- vpp-api/java/configure.ac | 2 +- vpp/configure.ac | 2 +- vppinfra/configure.ac | 2 +- 10 files changed, 10 insertions(+), 11 deletions(-) (limited to 'build-root/scripts') diff --git a/Makefile b/Makefile index fd1d0ff9..a222567e 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,6 @@ WS_ROOT=$(CURDIR) BR=$(WS_ROOT)/build-root CCACHE_DIR?=$(BR)/.ccache -V?=0 GDB?=gdb PLATFORM?=vpp @@ -119,7 +118,7 @@ else endif define make - @make -C $(BR) V=$(V) PLATFORM=$(PLATFORM) TAG=$(1) $(2) + @make -C $(BR) PLATFORM=$(PLATFORM) TAG=$(1) $(2) endef build: $(BR)/.bootstrap.ok diff --git a/build-root/scripts/make-plugin-toolkit b/build-root/scripts/make-plugin-toolkit index 14e9eda2..e1d6fcfb 100755 --- a/build-root/scripts/make-plugin-toolkit +++ b/build-root/scripts/make-plugin-toolkit @@ -26,7 +26,7 @@ make PLATFORM=vpp sample-plugin-find-source make PLATFORM=vpp TAG=vpp wipe-all echo Build vpp forwarder production package -make PLATFORM=vpp TAG=vpp V=0 strip_sumbols=yes install-packages +make PLATFORM=vpp TAG=vpp strip_sumbols=yes install-packages tmp_dir="`mktemp -d /tmp/plugin-XXXXXX`" trap "rm -rf $tmp_dir" err diff --git a/svm/configure.ac b/svm/configure.ac index 8db58214..b3948176 100644 --- a/svm/configure.ac +++ b/svm/configure.ac @@ -2,7 +2,7 @@ AC_INIT(svm, 1.0) LT_INIT AM_INIT_AUTOMAKE -AM_SILENT_RULES +AM_SILENT_RULES([yes]) AM_PROG_AS AC_PROG_CC_C_O diff --git a/vlib-api/configure.ac b/vlib-api/configure.ac index b5f3157a..ab21f894 100644 --- a/vlib-api/configure.ac +++ b/vlib-api/configure.ac @@ -2,7 +2,7 @@ AC_INIT(vlibapi, 1.0) LT_INIT AM_INIT_AUTOMAKE -AM_SILENT_RULES +AM_SILENT_RULES([yes]) AC_PROG_CC AM_PROG_CC_C_O diff --git a/vlib/configure.ac b/vlib/configure.ac index 1a45d33e..4f32a21c 100644 --- a/vlib/configure.ac +++ b/vlib/configure.ac @@ -1,7 +1,7 @@ AC_INIT(vlib, 1.1) LT_INIT AM_INIT_AUTOMAKE -AM_SILENT_RULES +AM_SILENT_RULES([yes]) AC_PROG_CC AM_PROG_CC_C_O diff --git a/vnet/configure.ac b/vnet/configure.ac index bc1922b9..8f8b91f7 100644 --- a/vnet/configure.ac +++ b/vnet/configure.ac @@ -3,7 +3,7 @@ AC_CONFIG_AUX_DIR(config) AC_CONFIG_HEADERS(config/config.h) LT_INIT AM_INIT_AUTOMAKE -AM_SILENT_RULES +AM_SILENT_RULES([yes]) AC_PROG_CC AM_PROG_CC_C_O diff --git a/vpp-api/configure.ac b/vpp-api/configure.ac index 31ee6656..9f8c3ed3 100644 --- a/vpp-api/configure.ac +++ b/vpp-api/configure.ac @@ -3,7 +3,7 @@ LT_INIT AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SUBDIRS([java]) AM_INIT_AUTOMAKE -AM_SILENT_RULES +AM_SILENT_RULES([yes]) AM_PROG_AS AC_PROG_CC diff --git a/vpp-api/java/configure.ac b/vpp-api/java/configure.ac index 1607061d..02f25702 100644 --- a/vpp-api/java/configure.ac +++ b/vpp-api/java/configure.ac @@ -2,7 +2,7 @@ AC_INIT(vpp-japi, 1.0.0) LT_INIT AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE -AM_SILENT_RULES +AM_SILENT_RULES([yes]) AM_PROG_AS AC_PROG_CC diff --git a/vpp/configure.ac b/vpp/configure.ac index 5b72eea6..3eb7bb7c 100644 --- a/vpp/configure.ac +++ b/vpp/configure.ac @@ -1,6 +1,6 @@ AC_INIT(vpp, 1.1) AM_INIT_AUTOMAKE -AM_SILENT_RULES +AM_SILENT_RULES([yes]) AM_PROG_AS AC_PROG_CC diff --git a/vppinfra/configure.ac b/vppinfra/configure.ac index 712186af..88720f71 100644 --- a/vppinfra/configure.ac +++ b/vppinfra/configure.ac @@ -5,7 +5,7 @@ AC_CONFIG_HEADERS(config/config.h) AC_CANONICAL_BUILD AC_CANONICAL_HOST AM_INIT_AUTOMAKE([gnu no-dist-gzip dist-bzip2]) -AM_SILENT_RULES +AM_SILENT_RULES([yes]) # Checks for programs. AC_PROG_CC -- cgit 1.2.3-korg From 9c5b2b301c1a2cc39b76c4a9570ce18a5eaa37be Mon Sep 17 00:00:00 2001 From: Dave Wallace Date: Fri, 13 May 2016 22:49:36 -0400 Subject: VPP-64: Fix top-level "make pkg-deb" which breaks if CDPATH is set in the user's bash environment. Change-Id: Ib13e6fdafa67175937e57fad4e75e553cb1e08a3 Signed-off-by: Dave Wallace --- build-root/scripts/find-dpdk-contents | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'build-root/scripts') diff --git a/build-root/scripts/find-dpdk-contents b/build-root/scripts/find-dpdk-contents index f8c80b5b..c7065139 100755 --- a/build-root/scripts/find-dpdk-contents +++ b/build-root/scripts/find-dpdk-contents @@ -5,6 +5,15 @@ rm -rf dpdk-includes mkdir dpdk-includes (cd $1/dpdk/include; tar cfh - . | (cd ../../../dpdk-includes; tar xf -)) +# If CDPATH is set, the "Change Directory" builtin (cd) will output the +# destination directory when a relative path is passed as an argument. +# In this case, this has the negative side effect of polluting the "paths" +# variable with the destination directory, breaking the package generation. +# +# Patient: Doctor! Doctor! It hurts when I do this... +# Doctor: Don't do that! +# +unset CDPATH paths=`cd dpdk-includes; find . -type f -print` rm -f $2 -- cgit 1.2.3-korg From 4e6be6847fb9ccc45440e37d4343a68634915b23 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Mon, 16 May 2016 15:55:36 +0200 Subject: Add build number to VPP version if BUILD_NUMBER var is set Change-Id: I73ecc12224fdfb08b7aa6118761b368577ce33d5 Signed-off-by: Damjan Marion --- build-root/scripts/version | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/version b/build-root/scripts/version index bbafb9bb..bf7e3155 100755 --- a/build-root/scripts/version +++ b/build-root/scripts/version @@ -4,6 +4,10 @@ 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) +if [ -n "${BUILD_NUMBER}" ]; then + BLD="~b${BUILD_NUMBER}" +fi + if [ "$1" = "rpm-version" ]; then echo ${TAG} exit @@ -12,12 +16,12 @@ 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} + echo ${ADD}~${CMT}${BLD} exit fi if [ -n "${ADD}" ]; then - echo ${TAG}-${ADD}~${CMT} + echo ${TAG}-${ADD}~${CMT}${BLD} else echo ${TAG} fi -- cgit 1.2.3-korg From 750c62548eb10e79ff35a963df248ccfb064ec24 Mon Sep 17 00:00:00 2001 From: Ed Warnicke Date: Tue, 31 May 2016 14:04:16 -0700 Subject: Fix build-root/scripts/version to not have spurious ~ Change-Id: Id28f134e3a4aa19c5756014d53004501db0d0c88 Signed-off-by: Ed Warnicke --- build-root/scripts/version | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/version b/build-root/scripts/version index bf7e3155..8724ced3 100755 --- a/build-root/scripts/version +++ b/build-root/scripts/version @@ -15,13 +15,12 @@ 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}${BLD} + echo ${ADD}${CMT:+~${CMT}}${BLD} exit fi if [ -n "${ADD}" ]; then - echo ${TAG}-${ADD}~${CMT}${BLD} + echo ${TAG}-${ADD}${CMT:+~${CMT}}${BLD} else echo ${TAG} fi -- cgit 1.2.3-korg From 227fe26987738d69cdc58fbee0b2ccbecf3ae97b Mon Sep 17 00:00:00 2001 From: Ed Warnicke Date: Thu, 2 Jun 2016 17:38:22 -0500 Subject: VPP-107 Fix for mistake that breaks pkg-rpm in https://gerrit.fd.io/r/#/c/1338/ Change-Id: I8b7fffe24cbeb435b18faaada9ef1cea9fd93d39 Signed-off-by: Ed Warnicke --- build-root/scripts/version | 1 + 1 file changed, 1 insertion(+) (limited to 'build-root/scripts') diff --git a/build-root/scripts/version b/build-root/scripts/version index 8724ced3..84ee5dbe 100755 --- a/build-root/scripts/version +++ b/build-root/scripts/version @@ -15,6 +15,7 @@ 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} exit fi -- cgit 1.2.3-korg From 2b54e996d43a1b72337acdcc636d813598553fd8 Mon Sep 17 00:00:00 2001 From: Dave Barach Date: Fri, 3 Jun 2016 15:27:05 -0400 Subject: Sample plugin moved to .../plugins/sample-plugin Change-Id: I6de20c9883d6918899c4b5b03e900814961e824d Signed-off-by: Dave Barach --- build-root/scripts/find-dev-contents | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/find-dev-contents b/build-root/scripts/find-dev-contents index 77028af0..2dc6cc4d 100755 --- a/build-root/scripts/find-dev-contents +++ b/build-root/scripts/find-dev-contents @@ -16,16 +16,16 @@ do done # sample plugin -paths=`(cd ..; find sample-plugin -type f -print | grep -v autom4te)` +paths=`(cd ..; find plugins/sample-plugin -type f -print | grep -v autom4te)` for path in $paths do - relpath=`echo $path | sed -e 's:.*/sample-plugin/::'` + relpath=`echo $path | sed -e 's:.*plugins/::'` dir=`dirname $relpath` if [ $dir = "sample-plugin" ] ; then - echo ../../$path /usr/share/doc/vpp/examples/sample-plugin >> $2 + echo ../../$path /usr/share/doc/vpp/examples/plugins/sample-plugin >> $2 else echo ../../$path \ - /usr/share/doc/vpp/examples/$dir >> $2 + /usr/share/doc/vpp/examples/plugins/$dir >> $2 fi done -- cgit 1.2.3-korg From f9618ee4843da063d33974c69ebd8e63845aedf6 Mon Sep 17 00:00:00 2001 From: Ed Warnicke Date: Wed, 1 Jun 2016 09:55:52 -0500 Subject: VPP-129: Add build-root/scripts/csit-test-branch script This script returns the csit branch that should be used for testing and verification. Related to csit patch: https://gerrit.fd.io/r/#/c/1344/ Change-Id: I51e44e4ba4dc433056ac8a870f8b7c7f9518189b Signed-off-by: Ed Warnicke --- build-root/scripts/csit-test-branch | 2 ++ 1 file changed, 2 insertions(+) create mode 100755 build-root/scripts/csit-test-branch (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch new file mode 100755 index 00000000..639f3dc2 --- /dev/null +++ b/build-root/scripts/csit-test-branch @@ -0,0 +1,2 @@ +#!/bin/sh +echo csit-verified -- cgit 1.2.3-korg From 45050f8781a4ceb8b99068c75604b81a32b9cf84 Mon Sep 17 00:00:00 2001 From: Ed Warnicke Date: Wed, 15 Jun 2016 23:17:07 -0500 Subject: Fix generate-deb-changelog to handle YY.MM release generate-deb-changelog was only properly handling x.y.z releases. This patch fixes it to handle YY.MM. Change-Id: Iaaee8ff747abd6754d021535c889f67ad2c9998f Signed-off-by: Ed Warnicke (cherry picked from commit 693f4358deef7db06b3d3cae0d881924dd9cf9fa) --- build-root/scripts/generate-deb-changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/generate-deb-changelog b/build-root/scripts/generate-deb-changelog index a1434312..7bdc6337 100755 --- a/build-root/scripts/generate-deb-changelog +++ b/build-root/scripts/generate-deb-changelog @@ -30,7 +30,7 @@ if [ -n "${ADDS}" ]; then print_changelog_item fi -for TAG in $(git tag -l 'v[0-9].[0-9].[0-9]' | sort -r ); do +for TAG in $(git tag -l 'v[0-9][0-9].[0-9][0-9]' | sort -r ); do VER=$(echo ${TAG}| sed -e 's/^v//') DESC=$(git tag -l -n20 ${TAG} | tail -n+2 | sed -e 's/^ */ /') print_changelog_item -- 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-root/scripts') 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 4575fb2df7ba69e0ed85b30d49730845dbb9f966 Mon Sep 17 00:00:00 2001 From: Miroslav Miklus Date: Fri, 15 Jul 2016 09:22:48 +0200 Subject: Use oper-160710 CSIT branch for 'verify' jobs Change-Id: I798a1f4168a6d3e60fc9f115b33cd7a5b2782df6 Signed-off-by: Miroslav Miklus --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index 639f3dc2..23e36f09 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo csit-verified +echo oper-160710 -- cgit 1.2.3-korg From 829c51a2f59f4b2a9a7546433cc12a9419b18d14 Mon Sep 17 00:00:00 2001 From: Andrej Kozemcak Date: Thu, 28 Jul 2016 09:26:23 +0200 Subject: Update CSIT test 160710 -> 160727 Change-Id: Ia6e4e951a409a3b8caef16bb62d9969ae030b667 Signed-off-by: Andrej Kozemcak --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index 23e36f09..f48ecfbf 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo oper-160710 +echo oper-160727 -- cgit 1.2.3-korg From cb34a1fb3bb055e132237f4c6f36340c11261e85 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 1 Aug 2016 17:37:37 +0200 Subject: Update CSIT test 160727 -> 160731 - update of CSIT operational branch to be user for VPP-patch test Change-Id: I4c5200fbf0fcdc2f8fef2913a9b9a5981a6ecec1 Signed-off-by: Jan --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index f48ecfbf..b209a9a4 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo oper-160727 +echo oper-160731 -- cgit 1.2.3-korg From da62e1a1d84728094c427a4a7ec03e76e2df988c Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 8 Aug 2016 13:26:49 +0200 Subject: Update CSIT tests 160731 -> 160807 - update of CSIT operational branch to be used for VPP-patch test Change-Id: If21641bfa958f06a61e5b3534ed1fe809de4eca3 Signed-off-by: Jan --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index b209a9a4..1d3570d3 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo oper-160731 +echo oper-160807 -- cgit 1.2.3-korg From be053b87cf321c34d780e9c79ad455513fb98395 Mon Sep 17 00:00:00 2001 From: Ed Warnicke Date: Fri, 5 Aug 2016 11:43:58 -0700 Subject: VPP-237: Checkstyle script to check for new checkstyle breakage indent is... cantankerous It sometimes happens that if you run indent A resulting in A' and then indent A' you get back A. Since the check here is premised on being able to run indent and not see any changed... we have to run it twice to be sure. Change-Id: I5b73e02f5996d8a01ec2e46741affbc6d62da6c9 Signed-off-by: Ed Warnicke --- .gitignore | 3 ++ build-root/scripts/checkstyle.sh | 73 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100755 build-root/scripts/checkstyle.sh (limited to 'build-root/scripts') diff --git a/.gitignore b/.gitignore index b5673ae0..250532aa 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,6 @@ GTAGS # Generated documentation /build-root/docs + +# indent backup files +*.BAK diff --git a/build-root/scripts/checkstyle.sh b/build-root/scripts/checkstyle.sh new file mode 100755 index 00000000..44534d48 --- /dev/null +++ b/build-root/scripts/checkstyle.sh @@ -0,0 +1,73 @@ +#!/bin/bash + +VPP_DIR=`dirname $0`/../../ +EXIT_CODE=0 +FIX="0" +CHECKSTYLED_FILES="" +UNCHECKSTYLED_FILES="" + +# If the user provides --fix, then actually fix things +# Note: this is meant for use outside of the CI Jobs, by users cleaning things up + +if [ $# -gt 0 ] && [ ${1} == '--fix' ]; then + FIX="1" +fi + +# Check to make sure we have indent. Exit if we don't with an error message, but +# don't *fail*. +command -v indent > /dev/null +if [ $? != 0 ]; then + echo "Cound not find required commend \"indent\". Checkstyle aborted" + exit ${EXIT_CODE} +fi +indent --version + +cd ${VPP_DIR} +git status +for i in `git ls-tree -r HEAD --name-only`;do + if [ -f ${i} ] && [ ${i} != "build-root/scripts/checkstyle.sh" ] && [ ${i} != "build-root/emacs-lisp/fix-coding-style.el" ]; then + grep -q "fd.io coding-style-patch-verification: ON" ${i} + if [ $? == 0 ]; then + CHECKSTYLED_FILES="${CHECKSTYLED_FILES} ${i}" + if [ ${FIX} == 0 ]; then + indent ${i} -o ${i}.out1 > /dev/null 2>&1 + indent ${i}.out1 -o ${i}.out2 > /dev/null 2>&1 + diff -q ${i} ${i}.out2 + else + indent ${i} + indent ${i} + fi + if [ $? != 0 ]; then + EXIT_CODE=1 + echo + echo "Checkstyle failed for ${i}." + echo "Run indent (twice!) as shown to fix the problem:" + echo "indent ${VPP_DIR}${i}" + echo "indent ${VPP_DIR}${i}" + fi + if [ -f ${i}.out1 ]; then + rm ${i}.out1 + fi + if [ -f ${i}.out2 ]; then + rm ${i}.out2 + fi + else + UNCHECKSTYLED_FILES="${UNCHECKSTYLED_FILES} ${i}" + fi + else + UNCHECKSTYLED_FILES="${UNCHECKSTYLED_FILES} ${i}" + fi +done + +if [ ${EXIT_CODE} == 0 ]; then + echo "*******************************************************************" + echo "* VPP CHECKSTYLE SUCCESSFULLY COMPLETED" + echo "*******************************************************************" +else + echo "*******************************************************************" + echo "* VPP CHECKSTYLE FAILED" + echo "* CONSULT FAILURE LOG ABOVE" + echo "* NOTE: Running 'build-root/scripts/checkstyle.sh --fix' *MAY* fix the issue" + echo "*******************************************************************" +fi +exit ${EXIT_CODE} -- cgit 1.2.3-korg From 161b2c6a833f2b53d684ae4a18119c26b825fe73 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 15 Aug 2016 16:56:42 +0200 Subject: Update CSIT tests 160807 -> 160815 - update of CSIT operational branch to be used for VPP-patch test Change-Id: Ia9cb275d9471f3c25a02f943d0ace65aec425f8d Signed-off-by: Jan --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index 1d3570d3..b9887c26 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo oper-160807 +echo oper-160815 -- cgit 1.2.3-korg From 607de1a0638fa45db49295f9ed51a7f9a5e38706 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Tue, 16 Aug 2016 22:53:54 +0200 Subject: Coding standards cleanup - remove trailing whitespace, fixes VPP-332 Change-Id: I649a17f8fa47599faf438b2e596f53761790d10c Signed-off-by: Damjan Marion --- build-root/scripts/checkstyle.sh | 4 ++ vlib/vlib/node_funcs.h | 2 +- vlib/vlib/vlib_process_doc.h | 18 ++++---- vnet/vnet/cdp/cdp_input.c | 16 +++---- vnet/vnet/cdp/cdp_node.c | 18 ++++---- vnet/vnet/cdp/cdp_periodic.c | 14 +++--- vnet/vnet/cdp/cdp_protocol.h | 12 ++--- vnet/vnet/ethernet/arp.c | 28 ++++++------ vnet/vnet/ethernet/ethernet.h | 6 +-- vnet/vnet/ethernet/init.c | 2 +- vnet/vnet/ethernet/interface.c | 4 +- vnet/vnet/ethernet/mac_swap.c | 8 ++-- vnet/vnet/ethernet/node.c | 14 +++--- vnet/vnet/ipsec/ikev2_cli.c | 30 ++++++------- vnet/vnet/ipsec/ipsec.c | 4 +- vnet/vnet/l2tp/l2tp.c | 34 +++++++------- vnet/vnet/l2tp/packet.h | 6 +-- vnet/vnet/map/ip4_map.c | 4 +- vnet/vnet/map/ip6_map.c | 2 +- vnet/vnet/map/map.c | 16 +++---- vnet/vnet/sr/sr.c | 96 ++++++++++++++++++++-------------------- vnet/vnet/sr/sr.h | 2 +- vnet/vnet/sr/sr_packet.h | 4 +- vppinfra/vppinfra/mheap.c | 2 +- 24 files changed, 175 insertions(+), 171 deletions(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/checkstyle.sh b/build-root/scripts/checkstyle.sh index 44534d48..df72cdb2 100755 --- a/build-root/scripts/checkstyle.sh +++ b/build-root/scripts/checkstyle.sh @@ -32,10 +32,14 @@ for i in `git ls-tree -r HEAD --name-only`;do if [ ${FIX} == 0 ]; then indent ${i} -o ${i}.out1 > /dev/null 2>&1 indent ${i}.out1 -o ${i}.out2 > /dev/null 2>&1 + # Remove trailing whitespace + sed -i -e 's/[[:space:]]*$//' ${i}.out2 diff -q ${i} ${i}.out2 else indent ${i} indent ${i} + # Remove trailing whitespace + sed -i -e 's/[[:space:]]*$//' ${i} fi if [ $? != 0 ]; then EXIT_CODE=1 diff --git a/vlib/vlib/node_funcs.h b/vlib/vlib/node_funcs.h index 265b897e..bd199fa5 100644 --- a/vlib/vlib/node_funcs.h +++ b/vlib/vlib/node_funcs.h @@ -674,7 +674,7 @@ vlib_process_wait_for_event_with_type (vlib_main_t * vm, /** Suspend a cooperative multi-tasking thread Waits for an event, or for the indicated number of seconds to elapse @param vm - vlib_main_t pointer - @param dt - timeout, in seconds. + @param dt - timeout, in seconds. @returns the remaining time interval */ diff --git a/vlib/vlib/vlib_process_doc.h b/vlib/vlib/vlib_process_doc.h index 953eb0c4..43a51b57 100644 --- a/vlib/vlib/vlib_process_doc.h +++ b/vlib/vlib/vlib_process_doc.h @@ -61,7 +61,7 @@ #define EXAMPLE_POLL_PERIOD 10.0 static uword - example_process (vlib_main_t * vm, vlib_node_runtime_t * rt, + example_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) { f64 poll_time_remaining; @@ -72,8 +72,8 @@ { int i; - // Sleep until next periodic call due, - // or until we receive event(s) + // Sleep until next periodic call due, + // or until we receive event(s) // poll_time_remaining = vlib_process_wait_for_event_or_clock (vm, poll_time_remaining); @@ -94,26 +94,26 @@ handle_event2 (vm, event_data[i]); break; - // ... and so forth for each event type + // ... and so forth for each event type default: - // This should never happen... - clib_warning ("BUG: unhandled event type %d", + // This should never happen... + clib_warning ("BUG: unhandled event type %d", event_type); break; } vec_reset_length (event_data); - // Timer expired, call periodic function + // Timer expired, call periodic function if (vlib_process_suspend_time_is_zero (poll_time_remaining)) { example_periodic (vm); poll_time_remaining = EXAMPLE_POLL_PERIOD; } } - // NOTREACHED + // NOTREACHED return 0; - } + } static VLIB_REGISTER_NODE (example_node) = { .function = example_process, diff --git a/vnet/vnet/cdp/cdp_input.c b/vnet/vnet/cdp/cdp_input.c index 0a4fb773..3574de68 100644 --- a/vnet/vnet/cdp/cdp_input.c +++ b/vnet/vnet/cdp/cdp_input.c @@ -325,9 +325,9 @@ cdp_input (vlib_main_t * vm, vlib_buffer_t * b0, u32 bi0) n = pool_elt_at_index (cm->neighbors, p[0]); } - /* + /* * typical clib idiom. Don't repeatedly allocate and free - * the per-neighbor rx buffer. Reset its apparent length to zero + * the per-neighbor rx buffer. Reset its apparent length to zero * and reuse it. */ @@ -338,20 +338,20 @@ cdp_input (vlib_main_t * vm, vlib_buffer_t * b0, u32 bi0) if (n->disabled) return CDP_ERROR_DISABLED; - /* + /* * Make sure the per-neighbor rx buffer is big enough to hold * the data we're about to copy */ vec_validate (n->last_rx_pkt, vlib_buffer_length_in_chain (vm, b0) - 1); - /* + /* * Coalesce / copy e the buffer chain into the per-neighbor - * rx buffer + * rx buffer */ nbytes = vlib_buffer_contents (vm, bi0, n->last_rx_pkt); ASSERT (nbytes <= vec_len (n->last_rx_pkt)); - /* + /* * Compute Jenkins hash of the new packet, decide if we need to * actually parse through the TLV's. CDP packets are all identical, * so unless we time out the peer, we don't need to process the packet. @@ -422,9 +422,9 @@ format_cdp_neighbors (u8 * s, va_list * va) pool_foreach (n, cm->neighbors, ({ hw = vnet_get_sup_hw_interface (vnm, n->sw_if_index); - + if (n->disabled == 0) - s = format (s, "%=25s %=15s %=25s %=10.1f\n", + s = format (s, "%=25s %=15s %=25s %=10.1f\n", hw->name, n->device_name, n->port_id, n->last_heard); })); diff --git a/vnet/vnet/cdp/cdp_node.c b/vnet/vnet/cdp/cdp_node.c index de62d4c7..39ac4a90 100644 --- a/vnet/vnet/cdp/cdp_node.c +++ b/vnet/vnet/cdp/cdp_node.c @@ -31,7 +31,7 @@ static vlib_node_registration_t cdp_process_node; /* * packet counter strings - * Dump these counters via the "show error" CLI command + * Dump these counters via the "show error" CLI command */ static char *cdp_error_strings[] = { #define _(sym,string) string, @@ -51,8 +51,8 @@ typedef enum } cdp_next_t; /* - * Process a frame of cdp packets - * Expect 1 packet / frame + * Process a frame of cdp packets + * Expect 1 packet / frame */ static uword cdp_node_fn (vlib_main_t * vm, @@ -100,7 +100,7 @@ cdp_node_fn (vlib_main_t * vm, } /* - * cdp input graph node declaration + * cdp input graph node declaration */ /* *INDENT-OFF* */ VLIB_REGISTER_NODE (cdp_input_node, static) = { @@ -108,12 +108,12 @@ VLIB_REGISTER_NODE (cdp_input_node, static) = { .name = "cdp-input", .vector_size = sizeof (u32), .type = VLIB_NODE_TYPE_INTERNAL, - + .n_errors = CDP_N_ERROR, .error_strings = cdp_error_strings, - + .format_trace = cdp_input_format_trace, - + .n_next_nodes = CDP_INPUT_N_NEXT, .next_nodes = { [CDP_INPUT_NEXT_NORMAL] = "error-drop", @@ -122,7 +122,7 @@ VLIB_REGISTER_NODE (cdp_input_node, static) = { /* *INDENT-ON* */ /* - * cdp periodic function + * cdp periodic function */ static uword cdp_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) @@ -184,7 +184,7 @@ cdp_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) } /* - * cdp periodic node declaration + * cdp periodic node declaration */ /* *INDENT-OFF* */ VLIB_REGISTER_NODE (cdp_process_node, static) = { diff --git a/vnet/vnet/cdp/cdp_periodic.c b/vnet/vnet/cdp/cdp_periodic.c index 8a000c7f..de111079 100644 --- a/vnet/vnet/cdp/cdp_periodic.c +++ b/vnet/vnet/cdp/cdp_periodic.c @@ -118,9 +118,9 @@ send_ethernet_hello (cdp_main_t * cm, cdp_neighbor_t * n, int count) for (i = 0; i < count; i++) { - /* + /* * see cdp_periodic_init() to understand what's already painted - * into the buffer by the packet template mechanism + * into the buffer by the packet template mechanism */ h0 = vlib_packet_template_get_packet (vm, &cm->packet_templates[n->packet_template_index], &bi0); @@ -185,9 +185,9 @@ send_hdlc_hello (cdp_main_t * cm, cdp_neighbor_t * n, int count) for (i = 0; i < count; i++) { - /* + /* * see cdp_periodic_init() to understand what's already painted - * into the buffer by the packet template mechanism + * into the buffer by the packet template mechanism */ h0 = vlib_packet_template_get_packet (vm, &cm->packet_templates[n->packet_template_index], &bi0); @@ -241,9 +241,9 @@ send_srp_hello (cdp_main_t * cm, cdp_neighbor_t * n, int count) for (i = 0; i < count; i++) { - /* + /* * see cdp_periodic_init() to understand what's already painted - * into the buffer by the packet template mechanism + * into the buffer by the packet template mechanism */ h0 = vlib_packet_template_get_packet (vm, &cm->packet_templates[n->packet_template_index], &bi0); @@ -349,7 +349,7 @@ cdp_periodic (vlib_main_t * vm) static cdp_neighbor_t **n_list = 0; /* *INDENT-OFF* */ - pool_foreach (n, cm->neighbors, + pool_foreach (n, cm->neighbors, ({ vec_add1 (n_list, n); })); diff --git a/vnet/vnet/cdp/cdp_protocol.h b/vnet/vnet/cdp/cdp_protocol.h index c68f7ca3..dc6c66d5 100644 --- a/vnet/vnet/cdp/cdp_protocol.h +++ b/vnet/vnet/cdp/cdp_protocol.h @@ -60,7 +60,7 @@ typedef CLIB_PACKED (struct }) cdp_tlv_t; /* - * TLV codes. + * TLV codes. */ #define foreach_cdp_tlv_type \ _(unused) \ @@ -120,11 +120,11 @@ typedef enum | Address length | Address (variable) ... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - PT: Protocol type - 1 = NLPID format + PT: Protocol type + 1 = NLPID format 2 = 802.2 format - PT Length: + PT Length: Length of protocol field, 1 for PT = 1, and either 3 or 8 for 802.2 format depending if SNAP is used for PT = 2. @@ -133,11 +133,11 @@ typedef enum field: <-------OUI------> | | | | | | | | | bytes: 0 1 2 3 4 5 6 7 8 - + where the first 3 bytes are 0xAAAA03 for SNAP encoded addresses. The OUI is 000000 for ethernet and is the assigned Ethernet type code for the particular protocol. - e.g. for DECnet the encoding is AAAA03 000000 6003. + e.g. for DECnet the encoding is AAAA03 000000 6003. for IPv6 the encoding is AAAA03 000000 86DD */ diff --git a/vnet/vnet/ethernet/arp.c b/vnet/vnet/ethernet/arp.c index 1346d605..c0b06e0f 100644 --- a/vnet/vnet/ethernet/arp.c +++ b/vnet/vnet/ethernet/arp.c @@ -512,7 +512,7 @@ vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm, if (fp) rv = (*fp) (mc->data, a->ethernet, sw_if_index, 0); - /* + /* * Signal the resolver process, as long as the user * says they want to be notified */ @@ -1095,9 +1095,9 @@ arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) proxy_src.as_u32 = arp0->ip4_over_ethernet[1].ip4.data_u32; - /* + /* * Rewind buffer, direct code above not to - * think too hard about it. + * think too hard about it. * $$$ is the answer ever anything other than * vlib_buffer_reset(..)? */ @@ -1476,16 +1476,16 @@ vnet_arp_unset_ip4_over_ethernet_internal (vnet_main_t * vnm, memset (&args, 0, sizeof (args)); - /* + /* * Make sure that the route actually exists before we try to delete it, * and make sure that it's a rewrite adjacency. * - * If we point 1-N unnumbered interfaces at a loopback interface and - * shut down the loopback before shutting down 1-N unnumbered - * interfaces, the ARP cache will still have an entry, + * If we point 1-N unnumbered interfaces at a loopback interface and + * shut down the loopback before shutting down 1-N unnumbered + * interfaces, the ARP cache will still have an entry, * but the route will have disappeared. - * - * See also ip4_del_interface_routes (...) + * + * See also ip4_del_interface_routes (...) * -> ip4_delete_matching_routes (...). */ @@ -1496,7 +1496,7 @@ vnet_arp_unset_ip4_over_ethernet_internal (vnet_main_t * vnm, if (adj_index != lm->miss_adj_index) { adj = ip_get_adjacency (lm, adj_index); - /* + /* * Stupid control-plane trick: * admin down an interface (removes arp routes from fib), * bring the interface back up (does not reinstall them) @@ -1582,7 +1582,7 @@ vnet_proxy_arp_add_del (ip4_address_t * lo_addr, } /* - * Remove any proxy arp entries asdociated with the + * Remove any proxy arp entries asdociated with the * specificed fib. */ int @@ -1964,7 +1964,7 @@ arp_term_l2bd (vlib_main_t * vm, macp0 = (u8 *) hash_get (last_bd_config->mac_by_ip4, ip0); if (PREDICT_FALSE (!macp0)) - goto next_l2_feature; // MAC not found + goto next_l2_feature; // MAC not found // MAC found, send ARP reply - // Convert ARP request packet to ARP reply @@ -1976,7 +1976,7 @@ arp_term_l2bd (vlib_main_t * vm, clib_memcpy (eth0->src_address, macp0, 6); n_replies_sent += 1; - // For BVI, need to use l2-fwd node to send ARP reply as + // For BVI, need to use l2-fwd node to send ARP reply as // l2-output node cannot output packet to BVI properly cfg0 = vec_elt_at_index (l2im->configs, sw_if_index0); if (PREDICT_FALSE (cfg0->bvi)) @@ -2052,7 +2052,7 @@ VLIB_REGISTER_NODE (arp_term_l2bd_node, static) = { clib_error_t * arp_term_init (vlib_main_t * vm) -{ // Initialize the feature next-node indexes +{ // Initialize the feature next-node indexes feat_bitmap_init_next_nodes (vm, arp_term_l2bd_node.index, L2INPUT_N_FEAT, diff --git a/vnet/vnet/ethernet/ethernet.h b/vnet/vnet/ethernet/ethernet.h index be5b99c7..d0eec1fc 100644 --- a/vnet/vnet/ethernet/ethernet.h +++ b/vnet/vnet/ethernet/ethernet.h @@ -444,7 +444,7 @@ eth_identify_subint (vnet_hw_interface_t * hi, // Each comparison is checking both the valid flag and the number of tags // (incorporating exact-match/non-exact-match). - // check for specific double tag + // check for specific double tag subint = &qinq_intf->subint; if ((subint->flags & match_flags) == match_flags) goto matched; @@ -454,7 +454,7 @@ eth_identify_subint (vnet_hw_interface_t * hi, if ((subint->flags & match_flags) == match_flags) goto matched; - // check for specific single tag + // check for specific single tag subint = &vlan_intf->single_tag_subint; if ((subint->flags & match_flags) == match_flags) goto matched; @@ -464,7 +464,7 @@ eth_identify_subint (vnet_hw_interface_t * hi, if ((subint->flags & match_flags) == match_flags) goto matched; - // check for default interface + // check for default interface subint = &main_intf->default_subint; if ((subint->flags & match_flags) == match_flags) goto matched; diff --git a/vnet/vnet/ethernet/init.c b/vnet/vnet/ethernet/init.c index b561a361..86597c4f 100644 --- a/vnet/vnet/ethernet/init.c +++ b/vnet/vnet/ethernet/init.c @@ -66,7 +66,7 @@ ethernet_init (vlib_main_t * vm) ethernet_main_t *em = ðernet_main; clib_error_t *error; - /* + /* * Set up the L2 path now, or we'll wipe out the L2 ARP * registration set up by ethernet_arp_init. */ diff --git a/vnet/vnet/ethernet/interface.c b/vnet/vnet/ethernet/interface.c index 9723ad9f..88daa347 100644 --- a/vnet/vnet/ethernet/interface.c +++ b/vnet/vnet/ethernet/interface.c @@ -298,7 +298,7 @@ simulated_ethernet_interface_tx (vlib_main_t * vm, vlib_buffer_t *b; // check tx node index, it is ethernet-input on loopback create - // but can be changed to l2-input if loopback is configured as + // but can be changed to l2-input if loopback is configured as // BVI of a BD (Bridge Domain). loop_node = vec_elt (nm->nodes, node->node_index); next_node_index = loop_node->next_nodes[next_index]; @@ -322,7 +322,7 @@ simulated_ethernet_interface_tx (vlib_main_t * vm, while (1) { // Set up RX and TX indices as if received from a real driver - // unless loopback is used as a BVI. For BVI case, leave TX index + // unless loopback is used as a BVI. For BVI case, leave TX index // and update l2_len in packet as required for l2 forwarding path vnet_buffer (b)->sw_if_index[VLIB_RX] = sw_if_index; if (bvi_flag) diff --git a/vnet/vnet/ethernet/mac_swap.c b/vnet/vnet/ethernet/mac_swap.c index 34dfdf7e..c0fec12e 100644 --- a/vnet/vnet/ethernet/mac_swap.c +++ b/vnet/vnet/ethernet/mac_swap.c @@ -81,9 +81,9 @@ static char *mac_swap_error_strings[] = { #undef _ }; -/* +/* * To drop a pkt and increment one of the previous counters: - * + * * set b0->error = error_node->errors[RANDOM_ERROR_SAMPLE]; * set next0 to a disposition index bound to "error-drop". * @@ -93,7 +93,7 @@ static char *mac_swap_error_strings[] = { * u32 node_counter_base_index = n->error_heap_index; * vlib_error_main_t * em = &vm->error_main; * em->counters[node_counter_base_index + MAC_SWAP_ERROR_SAMPLE] += 1; - * + * */ typedef enum @@ -348,7 +348,7 @@ VLIB_REGISTER_NODE (mac_swap_node,static) = { .vector_size = sizeof (u32), .format_trace = format_swap_trace, .type = VLIB_NODE_TYPE_INTERNAL, - + .n_errors = ARRAY_LEN(mac_swap_error_strings), .error_strings = mac_swap_error_strings, diff --git a/vnet/vnet/ethernet/node.c b/vnet/vnet/ethernet/node.c index 0261815a..74d4f476 100644 --- a/vnet/vnet/ethernet/node.c +++ b/vnet/vnet/ethernet/node.c @@ -273,7 +273,7 @@ determine_next_node (ethernet_main_t * em, SPARSE_VEC_INVALID_INDEX ? ETHERNET_ERROR_UNKNOWN_TYPE : *error0; // The table is not populated with LLC values, so check that now. - // If variant is variant_ethernet then we came from LLC processing. Don't + // If variant is variant_ethernet then we came from LLC processing. Don't // go back there; drop instead using by keeping the drop/bad table result. if ((type0 < 0x600) && (variant == ETHERNET_INPUT_VARIANT_ETHERNET)) { @@ -561,7 +561,7 @@ ethernet_input_inline (vlib_main_t * vm, // prior to calling this function. Thus only subinterface counters // are incremented here. // - // Interface level counters include packets received on the main + // Interface level counters include packets received on the main // interface and all subinterfaces. Subinterface level counters // include only those packets received on that subinterface // Increment stats if the subint is valid and it is not the main intf @@ -576,7 +576,7 @@ ethernet_input_inline (vlib_main_t * vm, stats_n_bytes += len0; // Batch stat increments from the same subinterface so counters - // don't need to be incremented for every packet. + // don't need to be incremented for every packet. if (PREDICT_FALSE (new_sw_if_index0 != stats_sw_if_index)) { stats_n_packets -= 1; @@ -956,7 +956,7 @@ ethernet_sw_interface_add_del (vnet_main_t * vnm, // not implemented yet or not ethernet if (unsupported) { - // this is the NYI case + // this is the NYI case error = clib_error_return (0, "not implemented yet"); } goto done; @@ -1089,8 +1089,8 @@ next_by_ethertype_init (next_by_ethertype_t * l3_next) l3_next->sparse_index_by_input_next_index[ETHERNET_INPUT_NEXT_PUNT] = SPARSE_VEC_INVALID_INDEX; - /* - * Make sure we don't wipe out an ethernet registration by mistake + /* + * Make sure we don't wipe out an ethernet registration by mistake * Can happen if init function ordering constraints are missing. */ if (CLIB_DEBUG > 0) @@ -1218,7 +1218,7 @@ ethernet_register_l2_input (vlib_main_t * vm, u32 node_index) em->l2_next = vlib_node_add_next (vm, ethernet_input_node.index, node_index); - /* + /* * Even if we never use these arcs, we have to align the next indices... */ i = vlib_node_add_next (vm, ethernet_input_type_node.index, node_index); diff --git a/vnet/vnet/ipsec/ikev2_cli.c b/vnet/vnet/ipsec/ikev2_cli.c index bbd9a573..6b2937fb 100644 --- a/vnet/vnet/ipsec/ikev2_cli.c +++ b/vnet/vnet/ipsec/ikev2_cli.c @@ -65,26 +65,26 @@ show_ikev2_sa_command_fn (vlib_main_t * vm, vlib_cli_output(vm, " iip %U ispi %lx rip %U rspi %lx", format_ip4_address, &sa->iaddr, sa->ispi, format_ip4_address, &sa->raddr, sa->rspi); - + tr = ikev2_sa_get_td_for_type(sa->r_proposals, IKEV2_TRANSFORM_TYPE_ENCR); s = format(s, "%U ", format_ikev2_sa_transform, tr); - + tr = ikev2_sa_get_td_for_type(sa->r_proposals, IKEV2_TRANSFORM_TYPE_PRF); s = format(s, "%U ", format_ikev2_sa_transform, tr); - + tr = ikev2_sa_get_td_for_type(sa->r_proposals, IKEV2_TRANSFORM_TYPE_INTEG); s = format(s, "%U ", format_ikev2_sa_transform, tr); - + tr = ikev2_sa_get_td_for_type(sa->r_proposals, IKEV2_TRANSFORM_TYPE_DH); s = format(s, "%U ", format_ikev2_sa_transform, tr); - + vlib_cli_output(vm, " %v", s); vec_free(s); - + vlib_cli_output(vm, " nonce i:%U\n r:%U", format_hex_bytes, sa->i_nonce, vec_len(sa->i_nonce), format_hex_bytes, sa->r_nonce, vec_len(sa->r_nonce)); - + vlib_cli_output(vm, " SK_d %U", format_hex_bytes, sa->sk_d, vec_len(sa->sk_d)); vlib_cli_output(vm, " SK_a i:%U\n r:%U", @@ -96,32 +96,32 @@ show_ikev2_sa_command_fn (vlib_main_t * vm, vlib_cli_output(vm, " SK_p i:%U\n r:%U", format_hex_bytes, sa->sk_pi, vec_len(sa->sk_pi), format_hex_bytes, sa->sk_pr, vec_len(sa->sk_pr)); - + vlib_cli_output(vm, " identifier (i) %U", format_ikev2_id_type_and_data, &sa->i_id); vlib_cli_output(vm, " identifier (r) %U", format_ikev2_id_type_and_data, &sa->r_id); - + vec_foreach(child, sa->childs) { vlib_cli_output(vm, " child sa %u:", child - sa->childs); - + tr = ikev2_sa_get_td_for_type(child->r_proposals, IKEV2_TRANSFORM_TYPE_ENCR); s = format(s, "%U ", format_ikev2_sa_transform, tr); - + tr = ikev2_sa_get_td_for_type(child->r_proposals, IKEV2_TRANSFORM_TYPE_INTEG); s = format(s, "%U ", format_ikev2_sa_transform, tr); - + tr = ikev2_sa_get_td_for_type(child->r_proposals, IKEV2_TRANSFORM_TYPE_ESN); s = format(s, "%U ", format_ikev2_sa_transform, tr); - + vlib_cli_output(vm, " %v", s); vec_free(s); - + vlib_cli_output(vm, " spi(i) %lx spi(r) %lx", child->i_proposals ? child->i_proposals[0].spi : 0, child->r_proposals ? child->r_proposals[0].spi : 0); - + vlib_cli_output(vm, " SK_e i:%U\n r:%U", format_hex_bytes, child->sk_ei, vec_len(child->sk_ei), format_hex_bytes, child->sk_er, vec_len(child->sk_er)); diff --git a/vnet/vnet/ipsec/ipsec.c b/vnet/vnet/ipsec/ipsec.c index 42b8f29d..bf9dd973 100644 --- a/vnet/vnet/ipsec/ipsec.c +++ b/vnet/vnet/ipsec/ipsec.c @@ -265,7 +265,7 @@ ipsec_add_del_policy (vlib_main_t * vm, ipsec_policy_t * policy, int is_add) u32 i, j; /* *INDENT-OFF* */ pool_foreach_index(i, spd->policies, ({ - vp = pool_elt_at_index(spd->policies, i); + vp = pool_elt_at_index(spd->policies, i); if (vp->priority != policy->priority) continue; if (vp->is_outbound != policy->is_outbound) @@ -352,7 +352,7 @@ ipsec_add_del_policy (vlib_main_t * vm, ipsec_policy_t * policy, int is_add) vec_del1 (spd->ipv4_outbound_policies, j); break; } - } + } } else { diff --git a/vnet/vnet/l2tp/l2tp.c b/vnet/vnet/l2tp/l2tp.c index 3439c60c..99443ce4 100644 --- a/vnet/vnet/l2tp/l2tp.c +++ b/vnet/vnet/l2tp/l2tp.c @@ -130,7 +130,7 @@ show_l2tp_command_fn (vlib_main_t * vm, vlib_cli_output (vm, "L2tp session lookup on %s", keystr); /* *INDENT-OFF* */ - pool_foreach (session, lm->sessions, + pool_foreach (session, lm->sessions, ({ vlib_cli_output (vm, "%U", format_l2t_session, session); })); @@ -160,22 +160,22 @@ test_counters_command_fn (vlib_main_t * vm, u32 cpu_index = os_get_cpu_number (); /* *INDENT-OFF* */ - pool_foreach (session, lm->sessions, + pool_foreach (session, lm->sessions, ({ session_index = session - lm->sessions; - counter_index = - session_index_to_counter_index (session_index, + counter_index = + session_index_to_counter_index (session_index, SESSION_COUNTER_USER_TO_NETWORK); vlib_increment_combined_counter (&lm->counter_main, - cpu_index, - counter_index, + cpu_index, + counter_index, 1/*pkt*/, 1111 /*bytes*/); vlib_increment_combined_counter (&lm->counter_main, - cpu_index, - counter_index+1, + cpu_index, + counter_index+1, 1/*pkt*/, 2222 /*bytes*/); nincr++; - + })); /* *INDENT-ON* */ vlib_cli_output (vm, "Incremented %d active counters\n", nincr); @@ -202,11 +202,11 @@ clear_counters_command_fn (vlib_main_t * vm, u32 nincr = 0; /* *INDENT-OFF* */ - pool_foreach (session, lm->sessions, + pool_foreach (session, lm->sessions, ({ session_index = session - lm->sessions; - counter_index = - session_index_to_counter_index (session_index, + counter_index = + session_index_to_counter_index (session_index, SESSION_COUNTER_USER_TO_NETWORK); vlib_zero_combined_counter (&lm->counter_main, counter_index); vlib_zero_combined_counter (&lm->counter_main, counter_index+1); @@ -518,10 +518,10 @@ create_l2tpv3_tunnel_command_fn (vlib_main_t * vm, } /* *INDENT-OFF* */ -VLIB_CLI_COMMAND (create_l2tpv3_tunnel_command, static) = +VLIB_CLI_COMMAND (create_l2tpv3_tunnel_command, static) = { .path = "create l2tpv3 tunnel", - .short_help = + .short_help = "create l2tpv3 tunnel client our local-cookie remote-cookie local-session remote-session ", .function = create_l2tpv3_tunnel_command_fn, }; @@ -601,10 +601,10 @@ set_l2tp_tunnel_cookie_command_fn (vlib_main_t * vm, } /* *INDENT-OFF* */ -VLIB_CLI_COMMAND (set_l2tp_tunnel_cookie_command, static) = +VLIB_CLI_COMMAND (set_l2tp_tunnel_cookie_command, static) = { .path = "set l2tpv3 tunnel cookie", - .short_help = + .short_help = "set l2tpv3 tunnel cookie local remote ", .function = set_l2tp_tunnel_cookie_command_fn, }; @@ -679,7 +679,7 @@ set_ip6_l2tpv3 (vlib_main_t * vm, } /* *INDENT-OFF* */ -VLIB_CLI_COMMAND (set_interface_ip6_l2tpv3, static) = +VLIB_CLI_COMMAND (set_interface_ip6_l2tpv3, static) = { .path = "set interface ip6 l2tpv3", .function = set_ip6_l2tpv3, diff --git a/vnet/vnet/l2tp/packet.h b/vnet/vnet/l2tp/packet.h index 0bb2f23c..66dfea21 100644 --- a/vnet/vnet/l2tp/packet.h +++ b/vnet/vnet/l2tp/packet.h @@ -18,7 +18,7 @@ #ifndef __included_l2tp_packet_h__ #define __included_l2tp_packet_h__ -/* +/* * See RFC4719 for packet format. * Note: the l2_specific_sublayer is present in current Linux l2tpv3 * tunnels. It is not present in IOS XR l2tpv3 tunnels. @@ -27,8 +27,8 @@ /* *INDENT-OFF* */ typedef CLIB_PACKED (struct { - u32 session_id; - u64 cookie; u32 + u32 session_id; + u64 cookie; u32 l2_specific_sublayer; /* set to 0 (if present) */ }) l2tpv3_header_t; /* *INDENT-ON* */ diff --git a/vnet/vnet/map/ip4_map.c b/vnet/vnet/map/ip4_map.c index b2795ace..9fd10f62 100644 --- a/vnet/vnet/map/ip4_map.c +++ b/vnet/vnet/map/ip4_map.c @@ -765,7 +765,7 @@ VLIB_REGISTER_NODE(ip4_map_node) = { .vector_size = sizeof(u32), .format_trace = format_map_trace, .type = VLIB_NODE_TYPE_INTERNAL, - + .n_errors = MAP_N_ERROR, .error_strings = map_error_strings, @@ -791,7 +791,7 @@ VLIB_REGISTER_NODE(ip4_map_reass_node) = { .vector_size = sizeof(u32), .format_trace = format_ip4_map_reass_trace, .type = VLIB_NODE_TYPE_INTERNAL, - + .n_errors = MAP_N_ERROR, .error_strings = map_error_strings, diff --git a/vnet/vnet/map/ip6_map.c b/vnet/vnet/map/ip6_map.c index 44f0e5dd..2e38b0db 100644 --- a/vnet/vnet/map/ip6_map.c +++ b/vnet/vnet/map/ip6_map.c @@ -1062,7 +1062,7 @@ ip6_map_icmp_relay (vlib_main_t * vm, /* * In: * IPv6 header (40) - * ICMPv6 header (8) + * ICMPv6 header (8) * IPv6 header (40) * Original IPv4 header / packet * Out: diff --git a/vnet/vnet/map/map.c b/vnet/vnet/map/map.c index fdd56ee4..0108c7b0 100644 --- a/vnet/vnet/map/map.c +++ b/vnet/vnet/map/map.c @@ -30,7 +30,7 @@ crc_u32 (u32 data, u32 value) /* * This code supports the following MAP modes: - * + * * Algorithmic Shared IPv4 address (ea_bits_len > 0): * ea_bits_len + ip4_prefix > 32 * psid_length > 0, ip6_prefix < 64, ip4_prefix <= 32 @@ -1851,7 +1851,7 @@ VLIB_CLI_COMMAND(map_ip4_reass_lifetime_command, static) = { /* *INDENT-OFF* */ VLIB_CLI_COMMAND(map_traffic_class_command, static) = { .path = "map params traffic-class", - .short_help = + .short_help = "traffic-class {0x0-0xff | copy}", .function = map_traffic_class_command_fn, }; @@ -1860,7 +1860,7 @@ VLIB_CLI_COMMAND(map_traffic_class_command, static) = { /* *INDENT-OFF* */ VLIB_CLI_COMMAND(map_pre_resolve_command, static) = { .path = "map params pre-resolve", - .short_help = + .short_help = "pre-resolve {ip4-nh
} | {ip6-nh
}", .function = map_pre_resolve_command_fn, }; @@ -1869,7 +1869,7 @@ VLIB_CLI_COMMAND(map_pre_resolve_command, static) = { /* *INDENT-OFF* */ VLIB_CLI_COMMAND(map_security_check_command, static) = { .path = "map params security-check", - .short_help = + .short_help = "security-check on|off", .function = map_security_check_command_fn, }; @@ -1910,7 +1910,7 @@ VLIB_CLI_COMMAND(map_fragment_df_command, static) = { /* *INDENT-OFF* */ VLIB_CLI_COMMAND(map_security_check_frag_command, static) = { .path = "map params security-check fragments", - .short_help = + .short_help = "fragments on|off", .function = map_security_check_frag_command_fn, }; @@ -1919,7 +1919,7 @@ VLIB_CLI_COMMAND(map_security_check_frag_command, static) = { /* *INDENT-OFF* */ VLIB_CLI_COMMAND(map_add_domain_command, static) = { .path = "map add domain", - .short_help = + .short_help = "map add domain ip4-pfx ip6-pfx ip6-src " "ea-bits-len psid-offset psid-len [map-t] [mtu ]", .function = map_add_domain_command_fn, @@ -1929,7 +1929,7 @@ VLIB_CLI_COMMAND(map_add_domain_command, static) = { /* *INDENT-OFF* */ VLIB_CLI_COMMAND(map_add_rule_command, static) = { .path = "map add rule", - .short_help = + .short_help = "map add rule index psid ip6-dst ", .function = map_add_rule_command_fn, }; @@ -1938,7 +1938,7 @@ VLIB_CLI_COMMAND(map_add_rule_command, static) = { /* *INDENT-OFF* */ VLIB_CLI_COMMAND(map_del_command, static) = { .path = "map del domain", - .short_help = + .short_help = "map del domain index ", .function = map_del_domain_command_fn, }; diff --git a/vnet/vnet/sr/sr.c b/vnet/vnet/sr/sr.c index 484099d5..0ae462ac 100644 --- a/vnet/vnet/sr/sr.c +++ b/vnet/vnet/sr/sr.c @@ -154,7 +154,7 @@ format_ip6_sr_header (u8 * s, va_list * args) s = format (s, "\n flags %U", format_ip6_sr_header_flags, flags_host_byte_order, 0 /* bswap needed */ ); - /* + /* * Header length is in 8-byte units (minus one), so * divide by 2 to ascertain the number of ip6 addresses in the * segment list @@ -347,7 +347,7 @@ sr_rewrite (vlib_main_t * vm, b0 = vlib_get_buffer (vm, bi0); b1 = vlib_get_buffer (vm, bi1); - /* + /* * $$$ parse through header(s) to pick the point * where we punch in the SR extention header */ @@ -372,10 +372,10 @@ sr_rewrite (vlib_main_t * vm, ip0 = vlib_buffer_get_current (b0); ip1 = vlib_buffer_get_current (b1); - /* + /* * SR-unaware service chaining case: pkt coming back from * service has the original dst address, and will already - * have an SR header. If so, send it to sr-local + * have an SR header. If so, send it to sr-local */ if (PREDICT_FALSE (ip0->protocol == IPPROTO_IPV6_ROUTE)) { @@ -386,9 +386,9 @@ sr_rewrite (vlib_main_t * vm, } else { - /* - * Copy data before the punch-in point left by the - * required amount. Assume (for the moment) that only + /* + * Copy data before the punch-in point left by the + * required amount. Assume (for the moment) that only * the main packet header needs to be copied. */ clib_memcpy (((u8 *) ip0) - vec_len (t0->rewrite), @@ -418,7 +418,7 @@ sr_rewrite (vlib_main_t * vm, next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) : next0; - /* + /* * Ignore "do not rewrite" shtik in this path */ if (PREDICT_FALSE (next0 & 0x80000000)) @@ -463,7 +463,7 @@ sr_rewrite (vlib_main_t * vm, next1 = sr_local_cb ? sr_local_cb (vm, node, b1, ip1, sr1) : next1; - /* + /* * Ignore "do not rewrite" shtik in this path */ if (PREDICT_FALSE (next1 & 0x80000000)) @@ -526,7 +526,7 @@ sr_rewrite (vlib_main_t * vm, b0 = vlib_get_buffer (vm, bi0); - /* + /* * $$$ parse through header(s) to pick the point * where we punch in the SR extention header */ @@ -553,10 +553,10 @@ sr_rewrite (vlib_main_t * vm, ip0 = vlib_buffer_get_current (b0); - /* + /* * SR-unaware service chaining case: pkt coming back from * service has the original dst address, and will already - * have an SR header. If so, send it to sr-local + * have an SR header. If so, send it to sr-local */ if (PREDICT_FALSE (ip0->protocol == IPPROTO_IPV6_ROUTE)) { @@ -567,9 +567,9 @@ sr_rewrite (vlib_main_t * vm, } else { - /* - * Copy data before the punch-in point left by the - * required amount. Assume (for the moment) that only + /* + * Copy data before the punch-in point left by the + * required amount. Assume (for the moment) that only * the main packet header needs to be copied. */ clib_memcpy (((u8 *) ip0) - vec_len (t0->rewrite), @@ -599,7 +599,7 @@ sr_rewrite (vlib_main_t * vm, next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) : next0; - /* + /* * Ignore "do not rewrite" shtik in this path */ if (PREDICT_FALSE (next0 & 0x80000000)) @@ -903,7 +903,7 @@ ip6_sr_add_del_tunnel (ip6_sr_add_del_tunnel_args_t * a) /* The first specified hop goes right into the dst address */ clib_memcpy (&t->first_hop, &a->segments[0], sizeof (ip6_address_t)); - /* + /* * Create the sr header rewrite string * The list of segments needs an extra slot for the ultimate destination * which is taken from the packet we add the SRH to. @@ -986,14 +986,14 @@ ip6_sr_add_del_tunnel (ip6_sr_add_del_tunnel_args_t * a) ap = ip_add_adjacency (lm, &adj, 1 /* one adj */ , &adj_index); - /* + /* * Stick the tunnel index into the rewrite header. - * + * * Unfortunately, inserting an SR header according to the various * RFC's requires parsing through the ip6 header, perhaps consing a * buffer onto the head of the vlib_buffer_t, etc. We don't use the * normal reverse bcopy rewrite code. - * + * * We don't handle ugly RFC-related cases yet, but I'm sure PL will complain * at some point... */ @@ -1208,7 +1208,7 @@ sr_add_del_tunnel_command_fn (vlib_main_t * vm, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (sr_tunnel_command, static) = { .path = "sr tunnel", - .short_help = + .short_help = "sr tunnel [del] [name ] src dst [next ] " "[clean] [reroute] [key ] [policy ]" "[rx-fib-id ] [tx-fib-id ]", @@ -1281,7 +1281,7 @@ show_sr_tunnel_fn (vlib_main_t * vm, if (!p) /* Either name parm not passed or no tunnel with that name found, show all */ { /* *INDENT-OFF* */ - pool_foreach (t, sm->tunnels, + pool_foreach (t, sm->tunnels, ({ vec_add1 (tunnels, t); })); @@ -1371,7 +1371,7 @@ ip6_sr_add_del_policy (ip6_sr_add_del_policy_args_t * a) policy - sm->policies); /* Yes, this could be construed as overkill but the last thing you should do is set - the policy_index on the tunnel after everything is set in ip6_sr_main_t. + the policy_index on the tunnel after everything is set in ip6_sr_main_t. If this is deemed overly cautious, could set this in the vec_len(tunnel_names) loop. */ for (i = 0; i < vec_len (policy->tunnel_indices); i++) @@ -1460,7 +1460,7 @@ sr_add_del_policy_command_fn (vlib_main_t * vm, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (sr_policy_command, static) = { .path = "sr policy", - .short_help = + .short_help = "sr policy [del] name tunnel [tunnel ]*", .function = sr_add_del_policy_command_fn, }; @@ -1497,7 +1497,7 @@ show_sr_policy_fn (vlib_main_t * vm, if (!p) /* Either name parm not passed or no policy with that name found, show all */ { /* *INDENT-OFF* */ - pool_foreach (policy, sm->policies, + pool_foreach (policy, sm->policies, ({ vec_add1 (policies, policy); })); @@ -1568,7 +1568,7 @@ ip6_sr_add_del_multicastmap (ip6_sr_add_del_multicastmap_args_t * a) pt = pool_elt_at_index (sm->policies, p[0]); - /* + /* Get the first tunnel associated with policy populate the fib adjacency. From there, since this tunnel will have it's policy_index != ~0 it will be the trigger in the dual_loop to pull up the policy and make a copy-rewrite @@ -1587,14 +1587,14 @@ ip6_sr_add_del_multicastmap (ip6_sr_add_del_multicastmap_args_t * a) ap = ip_add_adjacency (lm, &adj, 1 /* one adj */ , &adj_index); - /* + /* * Stick the tunnel index into the rewrite header. - * + * * Unfortunately, inserting an SR header according to the various * RFC's requires parsing through the ip6 header, perhaps consing a * buffer onto the head of the vlib_buffer_t, etc. We don't use the * normal reverse bcopy rewrite code. - * + * * We don't handle ugly RFC-related cases yet, but I'm sure PL will complain * at some point... */ @@ -1710,7 +1710,7 @@ sr_add_del_multicast_map_command_fn (vlib_main_t * vm, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (sr_multicast_map_command, static) = { .path = "sr multicast-map", - .short_help = + .short_help = "sr multicast-map address sr-policy [del]", .function = sr_add_del_multicast_map_command_fn, }; @@ -1733,21 +1733,21 @@ show_sr_multicast_map_fn (vlib_main_t * vm, ({ if (!key) vlib_cli_output (vm, "no multicast maps configured"); - else + else { multicast_address = *((ip6_address_t *)key); pt = pool_elt_at_index (sm->policies, value); if (pt) { - vlib_cli_output (vm, "address: %U policy: %s", + vlib_cli_output (vm, "address: %U policy: %s", format_ip6_address, &multicast_address, pt->name); } else - vlib_cli_output (vm, "BUG: policy not found for address: %U with policy index %d", + vlib_cli_output (vm, "BUG: policy not found for address: %U with policy index %d", format_ip6_address, &multicast_address, value); - + } })); @@ -1925,7 +1925,7 @@ sr_fix_dst_addr (vlib_main_t * vm, } else { - /* + /* * We get here from sr_rewrite or sr_local, with * sr->segments_left pointing at the (copy of the original) dst * address. Use it, then increment sr0->segments_left. @@ -1938,9 +1938,9 @@ sr_fix_dst_addr (vlib_main_t * vm, goto do_trace0; } - /* - * Rewrite the packet with the original dst address - * We assume that the last segment (in processing order) contains + /* + * Rewrite the packet with the original dst address + * We assume that the last segment (in processing order) contains * the original dst address. The list is reversed, so sr0->segments * contains the original dst address. */ @@ -2301,8 +2301,8 @@ sr_local (vlib_main_t * vm, next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) : next0; - /* - * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx + /* + * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx */ if (PREDICT_FALSE (next0 & 0x80000000)) { @@ -2333,7 +2333,7 @@ sr_local (vlib_main_t * vm, { u64 *copy_dst0, *copy_src0; u16 new_l0; - /* + /* * Copy the ip6 header right by the (real) length of the * sr header. Here's another place which assumes that * the sr header is the only extention header. @@ -2406,8 +2406,8 @@ sr_local (vlib_main_t * vm, next1 = sr_local_cb ? sr_local_cb (vm, node, b1, ip1, sr1) : next1; - /* - * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx + /* + * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx */ if (PREDICT_FALSE (next1 & 0x80000000)) { @@ -2438,7 +2438,7 @@ sr_local (vlib_main_t * vm, { u64 *copy_dst1, *copy_src1; u16 new_l1; - /* + /* * Copy the ip6 header right by the (real) length of the * sr header. Here's another place which assumes that * the sr header is the only extention header. @@ -2532,8 +2532,8 @@ sr_local (vlib_main_t * vm, next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) : next0; - /* - * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx + /* + * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx */ if (PREDICT_FALSE (next0 & 0x80000000)) { @@ -2564,7 +2564,7 @@ sr_local (vlib_main_t * vm, { u64 *copy_dst0, *copy_src0; u16 new_l0; - /* + /* * Copy the ip6 header right by the (real) length of the * sr header. Here's another place which assumes that * the sr header is the only extention header. @@ -2864,7 +2864,7 @@ show_sr_hmac_fn (vlib_main_t * vm, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_sr_hmac, static) = { .path = "show sr hmac", - .short_help = "show sr hmac", + .short_help = "show sr hmac", .function = show_sr_hmac_fn, }; /* *INDENT-ON* */ diff --git a/vnet/vnet/sr/sr.h b/vnet/vnet/sr/sr.h index 66135f74..1ac70bd8 100644 --- a/vnet/vnet/sr/sr.h +++ b/vnet/vnet/sr/sr.h @@ -83,7 +83,7 @@ typedef struct /* segment list, when inserting an ip6 SR header */ ip6_address_t *segments; - /* + /* * "Tag" list, aka segments inserted at the end of the list, * past last_seg */ diff --git a/vnet/vnet/sr/sr_packet.h b/vnet/vnet/sr/sr_packet.h index 5d8fee2f..fc0d5eec 100644 --- a/vnet/vnet/sr/sr_packet.h +++ b/vnet/vnet/sr/sr_packet.h @@ -174,7 +174,7 @@ typedef struct /* Protocol for next header. */ u8 protocol; /* - * Length of routing header in 8 octet units, + * Length of routing header in 8 octet units, * not including the first 8 octets */ u8 length; @@ -185,7 +185,7 @@ typedef struct /* Next segment in the segment list */ u8 segments_left; - /* + /* * Policy list pointer: offset in the SRH of the policy * list - in 16-octet units - not including the first 8 octets. */ diff --git a/vppinfra/vppinfra/mheap.c b/vppinfra/vppinfra/mheap.c index 211cda60..b8828f9e 100644 --- a/vppinfra/vppinfra/mheap.c +++ b/vppinfra/vppinfra/mheap.c @@ -1545,7 +1545,7 @@ mheap_get_trace (void *v, uword offset, uword size) hash_pair_t *p; mheap_trace_t *q; /* *INDENT-OFF* */ - hash_foreach_pair (p, tm->trace_by_callers, + hash_foreach_pair (p, tm->trace_by_callers, ({ q = uword_to_pointer (p->key, mheap_trace_t *); ASSERT (q >= old_start && q < old_end); -- cgit 1.2.3-korg From aa88697b71878b0d28fd497e97300067aea735a1 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 22 Aug 2016 10:38:35 +0200 Subject: Update CSIT tests 160815 -> 160821 - update of CSIT operational branch to be used for VPP-patch test Change-Id: I4791551fa0b161ac0347d992bcda4bc1fb8c74d2 Signed-off-by: Jan --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index b9887c26..37050487 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo oper-160815 +echo oper-160821 -- cgit 1.2.3-korg From 0c6a6750daae0008f29c17be766514fdfe848b72 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 5 Sep 2016 11:32:30 +0200 Subject: Update CSIT tests 160821 -> 160904 - update of CSIT operational branch to be used for VPP-patch test Change-Id: I5159d0a320305fd3a8ca927fa742ddd4df87b271 Signed-off-by: Jan Gelety --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index 37050487..9070b359 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo oper-160821 +echo oper-160904 -- cgit 1.2.3-korg From 24704851584a2b1db4545a2a3cd3fc73dff2ce5f Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Wed, 7 Sep 2016 13:10:50 +0200 Subject: checkstyle: improve speed by checking only recently changed files This change makes checkstyle much faster by checking only recently changed files. It only checks files changed in last commit and files which are localy modified. Old behavior is preserved by specifying argument "--full" when invoking script. In addition "make checkstyle" and "make "fixstyle" actions are added to the top-level Makefile. Change-Id: I7d86225bd282f32ee508e7f52692a3778ac8dcda Signed-off-by: Damjan Marion --- Makefile | 7 +++++++ build-root/scripts/checkstyle.sh | 21 ++++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) (limited to 'build-root/scripts') diff --git a/Makefile b/Makefile index f218cb08..b3bd8d3c 100644 --- a/Makefile +++ b/Makefile @@ -80,6 +80,8 @@ help: @echo " ctags - (re)generate ctags database" @echo " gtags - (re)generate gtags database" @echo " cscope - (re)generate cscope database" + @echo " checkstyle - check coding style" + @echo " fixstyle - fix coding style" @echo " doxygen - (re)generate documentation" @echo " bootstrap-doxygen - setup Doxygen dependencies" @echo " wipe-doxygen - wipe all generated documentation" @@ -233,6 +235,11 @@ gtags: ctags cscope: cscope.files @cscope -b -q -v +checkstyle: + @build-root/scripts/checkstyle.sh + +fixstyle: + @build-root/scripts/checkstyle.sh --fix # # Build the documentation diff --git a/build-root/scripts/checkstyle.sh b/build-root/scripts/checkstyle.sh index df72cdb2..60129676 100755 --- a/build-root/scripts/checkstyle.sh +++ b/build-root/scripts/checkstyle.sh @@ -3,14 +3,29 @@ VPP_DIR=`dirname $0`/../../ EXIT_CODE=0 FIX="0" +FULL="0" CHECKSTYLED_FILES="" UNCHECKSTYLED_FILES="" # If the user provides --fix, then actually fix things # Note: this is meant for use outside of the CI Jobs, by users cleaning things up -if [ $# -gt 0 ] && [ ${1} == '--fix' ]; then - FIX="1" +while true; do + case ${1} in + --fix) + FIX="1" + ;; + --full) + FULL="1" + ;; + esac + shift || break +done + +if [ "${FULL}" == "1" ]; then + FILELIST=$(git ls-tree -r HEAD --name-only) +else + FILELIST=$((git diff HEAD~1.. --name-only; git ls-files -m ) | sort -u) fi # Check to make sure we have indent. Exit if we don't with an error message, but @@ -24,7 +39,7 @@ indent --version cd ${VPP_DIR} git status -for i in `git ls-tree -r HEAD --name-only`;do +for i in ${FILELIST}; do if [ -f ${i} ] && [ ${i} != "build-root/scripts/checkstyle.sh" ] && [ ${i} != "build-root/emacs-lisp/fix-coding-style.el" ]; then grep -q "fd.io coding-style-patch-verification: ON" ${i} if [ $? == 0 ]; then -- cgit 1.2.3-korg From 4802501f4d26ccc82344de483b033bc6ac96cc8a Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 12 Sep 2016 22:34:29 +0200 Subject: Update CSIT tests 160904 -> 160912 - update of CSIT operational branch to be used for VPP-patch test Change-Id: I7a8024378dee33c89b58835af1b7de020fac3e5e Signed-off-by: Jan --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index 9070b359..976ab81d 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo oper-160904 +echo oper-160912 -- cgit 1.2.3-korg From 3bb0c504621ba300e843cc4c9f5fe433375b22b7 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 19 Sep 2016 12:32:59 +0200 Subject: Update CSIT tests 160912 -> 160919 - update of CSIT operational branch to be used for VPP-patch test Change-Id: Ibcc937f68311a9809cc31965633f2d21f111e2c7 Signed-off-by: Jan --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index 976ab81d..0306bd89 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo oper-160912 +echo oper-160919 -- cgit 1.2.3-korg From 271ad32d25bbc4e6ebc7aa113f04610112819f34 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 26 Sep 2016 12:13:34 +0200 Subject: Update CSIT tests 160919 -> 160925 - update of CSIT operational branch to be used for VPP-patch test Change-Id: I5daf02786185159cd2a156144f247d3b45369c33 Signed-off-by: Jan Gelety --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index 0306bd89..25c57d89 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo oper-160919 +echo oper-160925 -- cgit 1.2.3-korg From ac09280947dcf035f51cb394b88de3c7b66a6320 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 4 Oct 2016 16:23:49 +0200 Subject: Update CSIT tests 160925 -> 161002 - update of CSIT operational branch to be used for VPP-patch test Change-Id: I45f35e14e162bc1e8c69bd632f8813dde9f8270b Signed-off-by: Jan Gelety --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index 25c57d89..2b08b9b6 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo oper-160925 +echo oper-161002 -- cgit 1.2.3-korg From f0ccbb02fd48325c3ccab66993b277f95bdbe2c1 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Thu, 6 Oct 2016 16:53:32 +0200 Subject: Add some useful scripts Change-Id: Ic7ae9b43020ab4d26214bfab71b19ee259771c52 Signed-off-by: Damjan Marion --- build-root/scripts/lsnet | 20 +++++++ build-root/scripts/pci-nic-bind | 94 +++++++++++++++++++++++++++++++ build-root/scripts/pci-nic-bind-to-kernel | 19 +++++++ 3 files changed, 133 insertions(+) create mode 100755 build-root/scripts/lsnet create mode 100755 build-root/scripts/pci-nic-bind create mode 100755 build-root/scripts/pci-nic-bind-to-kernel (limited to 'build-root/scripts') diff --git a/build-root/scripts/lsnet b/build-root/scripts/lsnet new file mode 100755 index 00000000..ed590e53 --- /dev/null +++ b/build-root/scripts/lsnet @@ -0,0 +1,20 @@ +#!/bin/bash + +echo "PCI Address MAC address Device Name Driver State Speed Port Type" +echo "============ ================= ============== ========== ======== ========== ====================" + +for f in /sys/class/net/*; do + dev=$(basename ${f}) + if [ -e $f/device ] ; then + dev=$(basename ${f}) + pci_addr=$(basename $(readlink $f/device)) + mac=$(cat $f/address) + driver=$(basename $(readlink $f/device/driver)) + oper=$(cat $f/operstate) + speed=$(sudo ethtool $dev | grep Speed | cut -d" " -f2) + port=$(ethtool $dev 2> /dev/null | sed -ne 's/.*Port: \(.*\)/\1/p') + printf "%-12s %-14s %-14s %-10s %-8s %-10s %-20s\n" $pci_addr $mac $dev $driver $oper $speed "$port" + # ethtool $dev | grep Port: + fi +done + diff --git a/build-root/scripts/pci-nic-bind b/build-root/scripts/pci-nic-bind new file mode 100755 index 00000000..f3a0c264 --- /dev/null +++ b/build-root/scripts/pci-nic-bind @@ -0,0 +1,94 @@ +#!/bin/bash + +uio_drivers="igb_uio uio_pci_generic vfio-pci" +tmpfile=$(mktemp) + + +function bind_drv() { + addr=$1 + modalias=$(cat $selection/modalias) + native_drv=$(modprobe -R $modalias) + array=() + + for drv in $native_drv $uio_drivers; do + if [ -e /sys/bus/pci/drivers/$drv ]; then + echo driver $drv + drv_desc=$(modinfo $drv | grep description: | sed -e 's/.*:[[:space:]]\+//' ) + array+=("${drv}") + array+=("${drv_desc}") + fi + done + dialog --backtitle "PCI NIC Bind Utility" \ + --clear \ + --menu "Select kernel driver" 18 100 12 \ + "${array[@]}" 2> $tmpfile + retval=$? + selection=$(cat $tmpfile) + rm $tmpfile + if [ $retval -ne 0 ]; then + return + fi + vd=$(cat /sys/bus/pci/devices/${addr}/vendor /sys/bus/pci/devices/${addr}/device) + echo $addr | tee /sys/bus/pci/devices/${addr}/driver/unbind > /dev/null 2> /dev/null + echo $vd | tee /sys/bus/pci/drivers/${selection}/new_id > /dev/null 2> /dev/null + echo $addr | tee /sys/bus/pci/drivers/${selection}/bind > /dev/null 2> /dev/null +} + +function find_pci_slot() { + addr=$1 + [ ! "$(ls -A /sys/bus/pci/slots )" ] && echo "No PCI slot data" && return + for slot in $(find /sys/bus/pci/slots/* -maxdepth 0 -exec basename {} \;); do + slot_addr=$(cat /sys/bus/pci/slots/$slot/address) + if [[ "${addr}" == *"${slot_addr}"* ]]; then + echo "PCI slot: ${slot}" + return + fi + done + echo "Unknown PCI slot" +} + +! type -ap dialog > /dev/null && echo "Please install dialog (apt-get install dialog)" && exit +if [ $USER != "root" ] ; then +echo "Restarting script with sudo..." + sudo $0 ${*} + exit +fi + +cd /sys/bus/pci/devices + +while true; do + array=() + for addr in *; do + class=$(cat ${addr}/class) + if [ "$class" = "0x020000" ]; then + name=$(lspci -s $addr | sed -e 's/.*: //') + if [ -e "/sys/bus/pci/devices/$addr/driver" ]; then + drv=$(basename $(readlink -f /sys/bus/pci/devices/$addr/driver)) + else + drv=" " + fi + slot=$(find_pci_slot ${addr}) + array+=("${addr}") + array+=("${drv}|${name}") + array+=("${slot}") + fi + done + + dialog --backtitle "PCI NIC Bind Utility" \ + --item-help \ + --clear \ + --column-separator '|' \ + --menu "Select NIC" 18 100 12 \ + "${array[@]}" 2> $tmpfile + + retval=$? + selection=$(cat $tmpfile) + rm $tmpfile + if [ $retval -ne 0 ]; then + exit + fi + bind_drv $selection +done + + + diff --git a/build-root/scripts/pci-nic-bind-to-kernel b/build-root/scripts/pci-nic-bind-to-kernel new file mode 100755 index 00000000..3d8559e3 --- /dev/null +++ b/build-root/scripts/pci-nic-bind-to-kernel @@ -0,0 +1,19 @@ +#!/bin/bash + +# Bind all unused PCI devices bound to uio drivers +# back to default kernel driver + +if [ $USER != "root" ] ; then + echo "Restarting script with sudo..." + sudo $0 ${*} + exit +fi + +for f in /sys/bus/pci/drivers/{igb_uio,uio_pci_generic,vfio-pci}/*; do + [ -e ${f}/config ] || continue + fuser -s ${f}/config && continue + echo 1 > ${f}/remove + removed=y +done + +[ -n ${removed} ] && echo 1 > /sys/bus/pci/rescan -- cgit 1.2.3-korg From 2b39a00795232bdbe68487d2eb9bccf0435b886e Mon Sep 17 00:00:00 2001 From: pmikus Date: Mon, 17 Oct 2016 11:03:42 +0100 Subject: DO_NOT_MERGE: Update CSIT tests 161002 -> 161017 - Update of CSIT operational branch with 16.04 Change-Id: I47346a5756e0944f29bee7760540912eb36081fa Signed-off-by: pmikus --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index 2b08b9b6..1616b568 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo oper-161002 +echo oper-161017 -- cgit 1.2.3-korg From dc5aac5c392c977d011233c374154cd83dcebf36 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 24 Oct 2016 23:17:45 +0200 Subject: Update CSIT tests 161017 -> 161024 - update of CSIT operational branch to be used for VPP-patch test Change-Id: Icb36e5a68f6c1ef5edbc5159f2af3d255cecbdeb Signed-off-by: Jan --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index 1616b568..827213af 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo oper-161017 +echo oper-161024 -- 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-root/scripts') 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 d7724759fdf74205107b86f8b0afb2dc32d75733 Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 2 Nov 2016 16:29:05 +0100 Subject: Update CSIT tests 161024 -> 161030 - update of CSIT operational branch to be used for VPP-patch test Change-Id: I9f7418a2161e6411375c2d7ff1f3f686b991fb87 Signed-off-by: Jan --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index 827213af..927683d5 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo oper-161024 +echo oper-161030 -- 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-root/scripts') 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 8c83ef01c42ad218ec2803a790625085702cd38a Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 9 Nov 2016 15:06:18 +0100 Subject: Update CSIT tests 161030 -> 161106 - update of CSIT operational branch to be used for VPP-patch test Change-Id: I5e705f4a4d1f843ff0041930399f707e59d01b05 Signed-off-by: Jan --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index 927683d5..13fe471e 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo oper-161030 +echo oper-161106 -- cgit 1.2.3-korg From b7c3f2c61c25e3a9e729c5ea7e4a0117f717a2c5 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 14 Nov 2016 09:53:37 +0100 Subject: Update CSIT tests 161106 -> 161113 - update of CSIT operational branch to be used for VPP-patch test Change-Id: I3a475b34764cfe3e433ce7ab8cfc5501f6131690 Signed-off-by: Jan --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index 13fe471e..f75ccc49 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo oper-161106 +echo oper-161113 -- cgit 1.2.3-korg From fca670b0ec9f74aa977fe479a5517ad6367ee898 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 21 Nov 2016 14:34:05 +0100 Subject: Update CSIT tests 161113 -> 161120 - update of CSIT operational branch to be used for VPP-patch test Change-Id: Ib8472f0a6eb4c8add5ca8ba51bccd9ba59938636 Signed-off-by: Jan --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index f75ccc49..853e01d9 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo oper-161113 +echo oper-161120 -- cgit 1.2.3-korg From f8c94313a3ec2e3dfdf7b308516cce315f69f548 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 29 Nov 2016 10:08:34 +0100 Subject: Update CSIT tests 161120 -> 161128 - update of CSIT operational branch to be used for VPP-patch test Change-Id: Ib0325dde7bd9f9769660d9c5c72f0fda5e752eaf Signed-off-by: Jan --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index 853e01d9..329e549b 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo oper-161120 +echo oper-161128 -- cgit 1.2.3-korg From b5388a5319ad7da519280afccbdf63f61833122b Mon Sep 17 00:00:00 2001 From: Ed Warnicke Date: Wed, 30 Nov 2016 22:57:34 +0000 Subject: Revert "Update CSIT tests 161120 -> 161128" This revert is to probe to see if CSIT tests are being broken by this patch. This reverts gerrit https://gerrit.fd.io/r/#/c/3985/ This reverts commit f8c94313a3ec2e3dfdf7b308516cce315f69f548. Change-Id: I6e1a7285ab077823a5d0350b8eda6bb26609f70c Signed-off-by: Ed Warnicke --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index 329e549b..853e01d9 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo oper-161128 +echo oper-161120 -- cgit 1.2.3-korg From e245d5ecef9a7b0969d160943b0a817c46e09f71 Mon Sep 17 00:00:00 2001 From: Peter Mikus Date: Thu, 1 Dec 2016 19:54:49 +0000 Subject: "Update CSIT tests 161120 -> 161128"" This reverts commit b5388a5319ad7da519280afccbdf63f61833122b. Change-Id: I07160d08e469417933b3da3466ce856ab673e955 Signed-off-by: Peter Mikus --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index 853e01d9..329e549b 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo oper-161120 +echo oper-161128 -- 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-root/scripts') 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 cf3658da71d926e3a9c9b916a87d12905cc5bbfa Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 5 Dec 2016 16:25:39 +0100 Subject: Update CSIT tests 161128 -> 161204 - update of CSIT operational branch to be used for VPP-patch test Change-Id: I84bfb828403a32087de3341f27c3e9a04292ca8b Signed-off-by: Jan --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index 329e549b..4293d9a8 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo oper-161128 +echo oper-161204 -- cgit 1.2.3-korg From abd98b2c88ec127c38ff804a0c2f2a6d6f018830 Mon Sep 17 00:00:00 2001 From: Jan Gelety Date: Mon, 12 Dec 2016 10:16:03 +0100 Subject: Update CSIT tests 161204 -> 161211 - update of CSIT operational branch to be used for VPP-patch test Change-Id: I141dad311139d2b819352fab6038d440f76c7fc2 Signed-off-by: Jan Gelety --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index 4293d9a8..9ea87a75 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo oper-161204 +echo oper-161211 -- cgit 1.2.3-korg From 71ce4a4bc5e21a29088ead51c76d7e6a09701678 Mon Sep 17 00:00:00 2001 From: Jan Gelety Date: Mon, 19 Dec 2016 10:01:55 +0100 Subject: Update CSIT tests 161211 -> 161218 - update of CSIT operational branch to be used for VPP-patch test Change-Id: I2942502803e1fc6edaf35fc08dee4e7848594f96 Signed-off-by: Jan Gelety --- build-root/scripts/csit-test-branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'build-root/scripts') diff --git a/build-root/scripts/csit-test-branch b/build-root/scripts/csit-test-branch index 9ea87a75..f4e6f1ab 100755 --- a/build-root/scripts/csit-test-branch +++ b/build-root/scripts/csit-test-branch @@ -1,2 +1,2 @@ #!/bin/sh -echo oper-161211 +echo oper-161218 -- cgit 1.2.3-korg From a1bd0230d2412223141486192ee0d4632bfe8710 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Mon, 19 Dec 2016 19:08:11 +0100 Subject: Remove RPATH from binaries before creating .deb and .rpm packages Change-Id: I684d4eabac03e049524204864c985e14eea8d92e Signed-off-by: Damjan Marion --- Makefile | 4 ++-- build-root/deb/debian/control | 2 +- build-root/deb/debian/rules | 1 + build-root/rpm/vpp.spec | 7 ++++++- build-root/scripts/remove-rpath | 24 ++++++++++++++++++++++++ 5 files changed, 34 insertions(+), 4 deletions(-) create mode 100755 build-root/scripts/remove-rpath (limited to 'build-root/scripts') diff --git a/Makefile b/Makefile index 1c7534cf..b3ffaf30 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,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 += python-dev python-virtualenv python-pip lcov +DEB_DEPENDS += python-dev python-virtualenv python-pip lcov chrpath ifeq ($(OS_VERSION_ID),14.04) DEB_DEPENDS += openjdk-8-jdk-headless else @@ -43,7 +43,7 @@ endif RPM_DEPENDS_GROUPS = 'Development Tools' RPM_DEPENDS = redhat-lsb glibc-static java-1.8.0-openjdk-devel yum-utils RPM_DEPENDS += openssl-devel https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm apr-devel -RPM_DEPENDS += python-devel python-virtualenv lcov +RPM_DEPENDS += python-devel python-virtualenv lcov chrpath EPEL_DEPENDS = libconfuse-devel ganglia-devel ifneq ($(wildcard $(STARTUP_DIR)/startup.conf),) diff --git a/build-root/deb/debian/control b/build-root/deb/debian/control index 988d2764..643774e3 100644 --- a/build-root/deb/debian/control +++ b/build-root/deb/debian/control @@ -2,7 +2,7 @@ Source: vpp Section: net Priority: extra Maintainer: Cisco OpenVPP Packaging Team -Build-Depends: debhelper (>= 9), dkms, dh-systemd +Build-Depends: debhelper (>= 9), dkms, dh-systemd, chrpath Standards-Version: 3.9.4 Package: vpp diff --git a/build-root/deb/debian/rules b/build-root/deb/debian/rules index 4ecd38f7..186fa840 100755 --- a/build-root/deb/debian/rules +++ b/build-root/deb/debian/rules @@ -22,6 +22,7 @@ include /usr/share/dpkg/default.mk override_dh_install: dh_install --exclude .git + ../scripts/remove-rpath . override_dh_strip: dh_strip --dbg-package=vpp-dbg diff --git a/build-root/rpm/vpp.spec b/build-root/rpm/vpp.spec index 4a351348..ed382349 100644 --- a/build-root/rpm/vpp.spec +++ b/build-root/rpm/vpp.spec @@ -26,7 +26,7 @@ License: MIT Version: %{_version} Release: %{_release} Requires: vpp-lib = %{_version}-%{_release}, net-tools, pciutils, python -BuildRequires: systemd +BuildRequires: systemd, chrpath Source: %{name}-%{_version}-%{_release}.tar.gz @@ -189,6 +189,11 @@ do install -p -m 644 $file %{buildroot}/usr/share/vpp/api done +# +# remove RPATH from ELF binaries +# +%{_mu_build_dir}/scripts/remove-rpath %{buildroot} + %post sysctl --system %systemd_post vpp.service diff --git a/build-root/scripts/remove-rpath b/build-root/scripts/remove-rpath new file mode 100755 index 00000000..bda3d60d --- /dev/null +++ b/build-root/scripts/remove-rpath @@ -0,0 +1,24 @@ +#!/bin/bash + +if [ -z $1 ]; then + echo "Please specify path" + exit 1 +fi + +which chrpath &> /dev/null + +if [ $? -ne 0 ] ; then + echo "Please install chrpath tool" + exit 1 +fi + +libs=$(find $1 -type f -name \*.so) +execs=$(find $1 -type f -path \*/bin/\* ) + +for i in $libs $execs; do + chrpath $i 2> /dev/null | grep -q build-root + if [ $? -eq 0 ] ; then + chrpath $i + fi +done + -- 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-root/scripts') 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, \ + "