diff --git a/bessctl/commands.py b/bessctl/commands.py index 0d39867af..eb18836e4 100644 --- a/bessctl/commands.py +++ b/bessctl/commands.py @@ -1,4 +1,4 @@ -# Copyright (c) 2014-2016, The Regents of the University of California. +# Copyright (c) 2014-2017, The Regents of the University of California. # Copyright (c) 2016-2017, Nefeli Networks, Inc. # Copyright (c) 2017, Cloudigo. # All rights reserved. @@ -333,7 +333,7 @@ def get_var_attrs(cli, var_token, partial_word): var_candidates = complete_filename(partial_word, suffix='.so', skip_suffix=True) - if var_token == '[DIRECTION]': + elif var_token == '[DIRECTION]': var_type = 'name' var_desc = 'gate direction discriminator (default "out")' var_candidates = ['in', 'out'] @@ -1417,12 +1417,22 @@ def show_mclass_list(cli, cls_names): @cmd('import plugin PLUGIN_FILE', 'Import the specified plugin (*.so)') def import_plugin(cli, plugin): - cli.bess.import_plugin(plugin) + cli.bess.pause_all() + try: + cli.bess.import_plugin(plugin) + finally: + cli.bess.resume_all() @cmd('unload plugin PLUGIN_FILE', 'Unload the specified plugin (*.so)') def unload_plugin(cli, plugin): - cli.bess.unload_plugin(plugin) + # FIXME check whether the plugin is being used + # currently this command can crash the BESS daemon + cli.bess.pause_all() + try: + cli.bess.unload_plugin(plugin) + finally: + cli.bess.resume_all() @cmd('show plugin', 'Show all imported plugins') diff --git a/build.py b/build.py index b5fe3ea26..c1184e98e 100755 --- a/build.py +++ b/build.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (c) 2014-2016, The Regents of the University of California. +# Copyright (c) 2014-2017, The Regents of the University of California. # Copyright (c) 2016-2017, Nefeli Networks, Inc. # All rights reserved. # @@ -309,14 +309,14 @@ def build_bess(): print('Generating protobuf codes for pybess...') cmd('protoc protobuf/*.proto \ - --proto_path=protobuf --python_out=pybess \ - --grpc_out=pybess \ + --proto_path=protobuf --python_out=pybess/builtin_pb \ + --grpc_out=pybess/builtin_pb \ --plugin=protoc-gen-grpc=`which grpc_python_plugin`') cmd('protoc protobuf/tests/*.proto \ - --proto_path=protobuf/tests/ --python_out=pybess \ - --grpc_out=pybess \ + --proto_path=protobuf/tests/ --python_out=pybess/builtin_pb \ + --grpc_out=pybess/builtin_pb \ --plugin=protoc-gen-grpc=`which grpc_python_plugin`') - cmd('2to3 -wn pybess/*_pb2.py') + cmd('2to3 -wn pybess/builtin_pb/*_pb2.py') print('Building BESS daemon...') cmd('bin/bessctl daemon stop 2> /dev/null || true') @@ -355,7 +355,10 @@ def do_clean(): cmd('make -C core clean') cmd('rm -f bin/bessd') cmd('make -C core/kmod clean') - cmd('rm -rf pybess/*_pb2.py') + cmd('rm -rf pybess/builtin_pb/*_pb2.py*') + cmd('rm -rf pybess/builtin_pb/*_pb2_grpc.py*') + cmd('rm -rf pybess/plugin_pb/*_pb2.py*') + cmd('rm -rf pybess/plugin_pb/*_pb2_grpc.py*') cmd('rm -rf %s/build' % DPDK_DIR) @@ -403,7 +406,7 @@ def main(): nargs=1, help='Location of benchmark library') parser.add_argument('-v', '--verbose', action='store_true', - help='enable verbose builds (same as env V=1)') + help='enable verbose builds (same as env V=1)') args = parser.parse_args() if args.verbose: diff --git a/core/Makefile b/core/Makefile index 37a59c0cc..c0346b57a 100644 --- a/core/Makefile +++ b/core/Makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2014-2016, The Regents of the University of California. +# Copyright (c) 2014-2017, The Regents of the University of California. # Copyright (c) 2016-2017, Nefeli Networks, Inc. # All rights reserved. # @@ -44,6 +44,7 @@ $(shell mkdir -p $(DEPDIR)/utils >/dev/null) $(shell mkdir -p $(DEPDIR)/modules >/dev/null) $(shell mkdir -p $(DEPDIR)/drivers >/dev/null) $(shell mkdir -p $(DEPDIR)/hooks >/dev/null) +$(shell mkdir -p $(DEPDIR)/pb >/dev/null) # 'clang' or 'g++' CXXCOMPILER := $(shell expr $(word 1, $(shell $(CXX) --version)) : '\(clang\|g++\)') @@ -52,7 +53,7 @@ CXXVERSION := $(shell $(CXX) -dumpversion) ifeq "$(CXXCOMPILER)" "g++" ifneq "$(shell printf '$(CXXVERSION)\n5' | sort -V | head -n1)" "5" - $(error g++ 5 or higher is required. Use container_build.py if newer g++ is not available.) +$(error g++ 5 or higher is required. Use container_build.py if newer g++ is not available.) endif endif @@ -127,10 +128,10 @@ endif PROTO_DIR := $(abspath ../protobuf) PROTOS := $(wildcard $(PROTO_DIR)/*.proto) -PROTO_SRCS := $(patsubst %.proto,%.pb.cc, $(notdir $(PROTOS))) -PROTO_SRCS += $(patsubst %.proto,%.grpc.pb.cc, $(notdir $(PROTOS))) +PROTO_SRCS := $(patsubst %.proto,pb/%.pb.cc, $(notdir $(PROTOS))) +PROTO_SRCS += $(patsubst %.proto,pb/%.grpc.pb.cc, $(notdir $(PROTOS))) PROTO_HEADERS := $(patsubst %.cc,%.h, $(PROTO_SRCS)) -PROTOCFLAGS += --proto_path=$(PROTO_DIR) --cpp_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` +PROTOCFLAGS += --proto_path=$(PROTO_DIR) --cpp_out=./pb --grpc_out=./pb --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` ALL_SRCS := $(wildcard *.cc utils/*.cc modules/*.cc drivers/*.cc hooks/*.cc) @@ -161,7 +162,7 @@ all: $(EXEC) modules tests benchmarks clean: rm -rf $(EXEC) .deps/*.d .deps/*/*.d *_test */*_test *_bench */*_bench \ - *.a *.pb.* *.o */*.o *.so */*.so *.gcov *.gcda *.gcno */*.gcda */*.gcno \ + *.a pb/*.pb.* *.o */*.o *.so */*.so *.gcov *.gcda *.gcno */*.gcda */*.gcno \ coverage.info coverage_html tags: @@ -218,14 +219,14 @@ endef $(eval $(call BUILD, \ PROTOC, \ - %.pb.cc %.pb.h %.grpc.pb.cc %.grpc.pb.h, \ + pb/%.pb.cc pb/%.pb.h pb/%.grpc.pb.cc pb/%.grpc.pb.h, \ $(PROTO_DIR)/%.proto, \ $(PROTOC) $$< $(PROTOCFLAGS))) $(eval $(call BUILD, \ CXX, \ - %.pb.o, \ - %.pb.cc, \ + pb/%.pb.o, \ + pb/%.pb.cc, \ $(CXX) -o $$@ -c $$< $(CXXFLAGS) $(PERMISSIVE) $$(DEPFLAGS))) $(eval $(call BUILD, \ diff --git a/core/bess_plugin.mk b/core/bess_plugin.mk new file mode 100644 index 000000000..8eff94dff --- /dev/null +++ b/core/bess_plugin.mk @@ -0,0 +1,116 @@ +# Copyright (c) 2017, The Regents of the University of California. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the names of the copyright holders nor the names of their +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +CXX ?= g++ +PROTOC ?= protoc + +# 'clang' or 'g++' +CXXCOMPILER := $(shell expr $(word 1, $(shell $(CXX) --version)) : '\(clang\|g++\)') + +CXXVERSION := $(shell $(CXX) -dumpversion) + + +ifeq "$(CXXCOMPILER)" "g++" +ifneq "$(shell printf '$(CXXVERSION)\n5' | sort -V | head -n1)" "5" +$(error g++ 5 or higher is required. Use container_build.py if newer g++ is not available.) +endif +endif + +RTE_SDK ?= $(BESS_HOME)/deps/dpdk-17.05 +RTE_TARGET ?= $(shell uname -m)-native-linuxapp-gcc +DPDK_LIB ?= dpdk + +ifneq ($(wildcard $(RTE_SDK)/$(RTE_TARGET)/*),) + DPDK_INC_DIR := $(RTE_SDK)/$(RTE_TARGET)/include +else ifneq ($(wildcard $(RTE_SDK)/build/*),) + # if the user didn't do "make install" for DPDK + DPDK_INC_DIR := $(RTE_SDK)/build/include +else ifeq ($(words $(MAKECMDGOALS)),1) + ifneq ($(MAKECMDGOALS),clean) + $(error DPDK is not available. \ + Make sure $(abspath $(RTE_SDK)) is available and built.) + endif +endif + +BESS_INC_DIR := $(BESS_HOME)/core + +CXXARCHFLAGS ?= -march=native +CXXFLAGS += -std=c++11 -g3 -ggdb3 $(CXXARCHFLAGS) \ + -Werror -isystem $(DPDK_INC_DIR) -isystem . -D_GNU_SOURCE \ + -isystem $(BESS_INC_DIR) \ + -Wall -Wextra -Wcast-align + +PERMISSIVE := -Wno-unused-parameter -Wno-missing-field-initializers \ + -Wno-unused-private-field + +# -Wshadow should not be used for g++ 4.x, as it has too many false positives +ifeq "$(shell expr $(CXXCOMPILER) = g++ \& $(CXXVERSION) \< 50000)" "0" + CXXFLAGS += -Wshadow +endif + +# Disable GNU_UNIQUE symbol for g++ +ifeq "$(shell expr $(CXXCOMPILER) = g++)" "1" + CXXFLAGS += -fno-gnu-unique +endif + +ifdef SANITIZE + CXXFLAGS += -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer + LDFLAGS += -fsanitize=address -fsanitize=undefined +endif + +ifdef DEBUG + CXXFLAGS += -O0 +else + CXXFLAGS += -Ofast -DNDEBUG +endif + +PROTOCFLAGS += --proto_path=$(PROTO_DIR) \ + --cpp_out=$(PROTO_DIR) --grpc_out=$(PROTO_DIR) \ + --plugin=protoc-gen-grpc=$(shell which grpc_cpp_plugin) + +PROTOPYFLAGS += --proto_path=$(PROTO_DIR) \ + --python_out=$(PROTO_DIR) --grpc_out=$(PROTO_DIR) \ + --plugin=protoc-gen-grpc=$(shell which grpc_python_plugin) + +%.pb.o: %.pb.cc + $(CXX) -o $@ -c $< $(CXXFLAGS) $(PERMISSIVE) -fPIC + +%.pb.cc: + $(PROTOC) $< $(PROTOCFLAGS) + +%_pb2.py: + protoc $< $(PROTOPYFLAGS) + 2to3 -wn $(PROTO_DIR)/*_pb2.py 2> /dev/null + mv $(PROTO_DIR)/*_pb2.py $(BESS_HOME)/pybess/plugin_pb/ + +%.o: %.cc + $(CXX) -o $@ -c $^ $(CXXFLAGS) $(MODULE_CXXFLAGS) -fPIC + +%.so: + $(CXX) -shared -o $@ $^ $(LDFLAGS) $(MODULE_LDFLAGS) diff --git a/core/bessctl.cc b/core/bessctl.cc index d43d44cd6..ad948be90 100644 --- a/core/bessctl.cc +++ b/core/bessctl.cc @@ -40,7 +40,7 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" -#include "service.grpc.pb.h" +#include "pb/service.grpc.pb.h" #pragma GCC diagnostic pop #include "bessd.h" diff --git a/core/bessd.cc b/core/bessd.cc index 50e0ead0f..8273eff2b 100644 --- a/core/bessd.cc +++ b/core/bessd.cc @@ -411,11 +411,13 @@ std::vector ListPlugins() { } bool LoadPlugin(const std::string &path) { + LOG(INFO) << "Loading module: " << path; void *handle = dlopen(path.c_str(), RTLD_NOW); if (handle != nullptr) { plugin_handles.emplace(path, handle); return true; } + LOG(WARNING) << "Error loading module " << path << ": " << dlerror(); return false; } @@ -443,10 +445,7 @@ bool LoadPlugins(const std::string &directory) { while ((entry = readdir(dir)) != nullptr) { if (entry->d_type == DT_REG && HasSuffix(entry->d_name, ".so")) { const std::string full_path = directory + "/" + entry->d_name; - LOG(INFO) << "Loading module: " << full_path; if (!LoadPlugin(full_path)) { - LOG(WARNING) << "Error loading module " << full_path << ": " - << dlerror(); closedir(dir); return false; } diff --git a/core/message.h b/core/message.h index b697bf9f2..4ced6c4c9 100644 --- a/core/message.h +++ b/core/message.h @@ -33,8 +33,9 @@ #include #include -#include "bess_msg.pb.h" -#include "error.pb.h" +#include "pb/bess_msg.pb.h" +#include "pb/error.pb.h" +#include "pb/module_msg.pb.h" typedef bess::pb::Error pb_error_t; diff --git a/core/modules/acl.h b/core/modules/acl.h index 708820d3f..4597dcac2 100644 --- a/core/modules/acl.h +++ b/core/modules/acl.h @@ -33,7 +33,7 @@ #include #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" #include "../utils/ip.h" using bess::utils::be16_t; diff --git a/core/modules/arp_responder.h b/core/modules/arp_responder.h index 2401f9ba0..367706efb 100644 --- a/core/modules/arp_responder.h +++ b/core/modules/arp_responder.h @@ -34,7 +34,7 @@ #include #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" #include "../utils/endian.h" #include "../utils/ether.h" #include "../utils/ip.h" diff --git a/core/modules/bpf.h b/core/modules/bpf.h index aa90c80ef..586a6898c 100644 --- a/core/modules/bpf.h +++ b/core/modules/bpf.h @@ -36,7 +36,7 @@ #include #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" using bpf_filter_func_t = u_int (*)(u_char *, u_int, u_int); diff --git a/core/modules/drr.h b/core/modules/drr.h index 3f822d810..fc6eb6aa8 100644 --- a/core/modules/drr.h +++ b/core/modules/drr.h @@ -37,7 +37,7 @@ #include "../kmod/llring.h" #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" #include "../pktbatch.h" #include "../utils/cuckoo_map.h" #include "../utils/ip.h" diff --git a/core/modules/dump.h b/core/modules/dump.h index 5bc385aaf..c7a2e8b47 100644 --- a/core/modules/dump.h +++ b/core/modules/dump.h @@ -32,7 +32,7 @@ #define BESS_MODULES_DUMP_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" class Dump final : public Module { public: diff --git a/core/modules/ether_encap.h b/core/modules/ether_encap.h index 839a3f8ed..e15d39382 100644 --- a/core/modules/ether_encap.h +++ b/core/modules/ether_encap.h @@ -32,7 +32,7 @@ #define BESS_MODULES_ETHERENCAP_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" class EtherEncap final : public Module { public: diff --git a/core/modules/exact_match.h b/core/modules/exact_match.h index eea909c21..7d1425d62 100644 --- a/core/modules/exact_match.h +++ b/core/modules/exact_match.h @@ -35,7 +35,7 @@ #include #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" #include "../utils/cuckoo_map.h" #define MAX_FIELDS 8 diff --git a/core/modules/flowgen.h b/core/modules/flowgen.h index 9fbd4ec5c..defb2303d 100644 --- a/core/modules/flowgen.h +++ b/core/modules/flowgen.h @@ -32,7 +32,7 @@ #define BESS_MODULES_FLOWGEN_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" #include #include diff --git a/core/modules/generic_decap.h b/core/modules/generic_decap.h index 6b3341ebc..5e32273a3 100644 --- a/core/modules/generic_decap.h +++ b/core/modules/generic_decap.h @@ -32,7 +32,7 @@ #define BESS_MODULES_GENERICDECAP_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" class GenericDecap final : public Module { public: diff --git a/core/modules/generic_encap.h b/core/modules/generic_encap.h index f8d4aeda2..cee15405e 100644 --- a/core/modules/generic_encap.h +++ b/core/modules/generic_encap.h @@ -32,7 +32,7 @@ #define BESS_MODULES_GENERICENCAP_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" #define MAX_FIELDS 8 #define MAX_FIELD_SIZE 8 diff --git a/core/modules/hash_lb.h b/core/modules/hash_lb.h index 0ca7cb210..904383293 100644 --- a/core/modules/hash_lb.h +++ b/core/modules/hash_lb.h @@ -32,7 +32,7 @@ #define BESS_MODULES_HASHLB_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" #define MAX_HLB_GATES 16384 diff --git a/core/modules/ip_encap.h b/core/modules/ip_encap.h index e63a6ae3c..592f92f18 100644 --- a/core/modules/ip_encap.h +++ b/core/modules/ip_encap.h @@ -32,7 +32,7 @@ #define BESS_MODULES_IPENCAP_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" class IPEncap final : public Module { public: diff --git a/core/modules/ip_lookup.h b/core/modules/ip_lookup.h index 6ba4e1e6d..a43cef352 100644 --- a/core/modules/ip_lookup.h +++ b/core/modules/ip_lookup.h @@ -32,7 +32,7 @@ #define BESS_MODULES_IPLOOKUP_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" class IPLookup final : public Module { public: diff --git a/core/modules/l2_forward.h b/core/modules/l2_forward.h index 4a749bf8f..49ce5e5fa 100644 --- a/core/modules/l2_forward.h +++ b/core/modules/l2_forward.h @@ -32,7 +32,7 @@ #define BESS_MODULES_L2FORWARD_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ #error this code assumes little endian architecture (x86) diff --git a/core/modules/measure.h b/core/modules/measure.h index eeb768fd9..4b7c6d3ef 100644 --- a/core/modules/measure.h +++ b/core/modules/measure.h @@ -32,7 +32,7 @@ #define BESS_MODULES_MEASURE_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" #include "../utils/histogram.h" #include "../utils/random.h" diff --git a/core/modules/mpls_pop.h b/core/modules/mpls_pop.h index 45e43cfc9..d5ffd6954 100644 --- a/core/modules/mpls_pop.h +++ b/core/modules/mpls_pop.h @@ -32,7 +32,7 @@ #define BESS_MODULES_MPLSPOP_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" #include "../utils/ether.h" using bess::utils::be16_t; diff --git a/core/modules/mttest.h b/core/modules/mttest.h index a59c1a531..7f97b3e4a 100644 --- a/core/modules/mttest.h +++ b/core/modules/mttest.h @@ -32,7 +32,7 @@ #define BESS_MODULES_MTTEST_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" using bess::metadata::Attribute; diff --git a/core/modules/nat.h b/core/modules/nat.h index 0dd5eb607..322ba8aba 100644 --- a/core/modules/nat.h +++ b/core/modules/nat.h @@ -31,7 +31,7 @@ #define BESS_MODULES_NAT_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" #include #include diff --git a/core/modules/noop.h b/core/modules/noop.h index 9d9f75173..d328b7616 100644 --- a/core/modules/noop.h +++ b/core/modules/noop.h @@ -32,13 +32,11 @@ #define BESS_MODULES_NOOP_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" class NoOP final : public Module { public: - NoOP() : Module() { - is_task_ = true; - }; + NoOP() : Module() { is_task_ = true; }; CommandResponse Init(const bess::pb::EmptyArg &arg); struct task_result RunTask(void *arg) override; diff --git a/core/modules/port_inc.h b/core/modules/port_inc.h index 3c146f1ae..d43090410 100644 --- a/core/modules/port_inc.h +++ b/core/modules/port_inc.h @@ -32,7 +32,7 @@ #define BESS_MODULES_PORTINC_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" #include "../port.h" class PortInc final : public Module { @@ -41,9 +41,7 @@ class PortInc final : public Module { static const Commands cmds; - PortInc() : Module(), port_(), prefetch_(), burst_() { - is_task_ = true; - } + PortInc() : Module(), port_(), prefetch_(), burst_() { is_task_ = true; } CommandResponse Init(const bess::pb::PortIncArg &arg); diff --git a/core/modules/port_out.h b/core/modules/port_out.h index 323ab51fe..49e48cb9b 100644 --- a/core/modules/port_out.h +++ b/core/modules/port_out.h @@ -32,7 +32,7 @@ #define BESS_MODULES_PORTOUT_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" #include "../port.h" class PortOut final : public Module { diff --git a/core/modules/queue.h b/core/modules/queue.h index e93d3708d..91a3cd53c 100644 --- a/core/modules/queue.h +++ b/core/modules/queue.h @@ -33,7 +33,7 @@ #include "../kmod/llring.h" #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" class Queue final : public Module { public: diff --git a/core/modules/queue_inc.h b/core/modules/queue_inc.h index 89a07ebdc..14508637d 100644 --- a/core/modules/queue_inc.h +++ b/core/modules/queue_inc.h @@ -32,7 +32,7 @@ #define BESS_MODULES_QUEUEINC_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" #include "../port.h" class QueueInc final : public Module { diff --git a/core/modules/queue_out.h b/core/modules/queue_out.h index ee208a02b..b0318a9e6 100644 --- a/core/modules/queue_out.h +++ b/core/modules/queue_out.h @@ -32,7 +32,7 @@ #define BESS_MODULES_QUEUEOUT_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" #include "../port.h" class QueueOut final : public Module { diff --git a/core/modules/random_drop.h b/core/modules/random_drop.h index b2522ca5f..79fed79e3 100644 --- a/core/modules/random_drop.h +++ b/core/modules/random_drop.h @@ -32,7 +32,7 @@ #define BESS_MODULES_RANDOM_DROP_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" #include "../utils/random.h" // RandomDrop drops packets with a specified probability [0, 1]. diff --git a/core/modules/random_update.cc b/core/modules/random_update.cc index 1fb3d1d69..694c656ec 100644 --- a/core/modules/random_update.cc +++ b/core/modules/random_update.cc @@ -44,10 +44,10 @@ CommandResponse RandomUpdate::Init(const bess::pb::RandomUpdateArg &arg) { } CommandResponse RandomUpdate::CommandAdd(const bess::pb::RandomUpdateArg &arg) { - int curr = num_vars_; - if (curr + arg.fields_size() > MAX_VARS) { - return CommandFailure(EINVAL, "max %d variables can be specified", - MAX_VARS); + size_t curr = num_vars_; + if (curr + arg.fields_size() > kMaxVariable) { + return CommandFailure(EINVAL, "max %zu variables can be specified", + kMaxVariable); } for (int i = 0; i < arg.fields_size(); i++) { @@ -116,7 +116,7 @@ CommandResponse RandomUpdate::CommandClear(const bess::pb::EmptyArg &) { void RandomUpdate::ProcessBatch(bess::PacketBatch *batch) { int cnt = batch->cnt(); - for (int i = 0; i < num_vars_; i++) { + for (size_t i = 0; i < num_vars_; i++) { const auto var = &vars_[i]; be32_t mask = var->mask; diff --git a/core/modules/random_update.h b/core/modules/random_update.h index e06415f29..2ba38ecbe 100644 --- a/core/modules/random_update.h +++ b/core/modules/random_update.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2016, The Regents of the University of California. +// Copyright (c) 2014-2017, The Regents of the University of California. // Copyright (c) 2016-2017, Nefeli Networks, Inc. // All rights reserved. // @@ -32,12 +32,12 @@ #define BESS_MODULES_RANDOMUPDATE_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" #include "../utils/endian.h" #include "../utils/random.h" -#define MAX_VARS 16 +static const size_t kMaxVariable = 16; class RandomUpdate final : public Module { public: @@ -53,7 +53,7 @@ class RandomUpdate final : public Module { CommandResponse CommandClear(const bess::pb::EmptyArg &arg); private: - int num_vars_; + size_t num_vars_; struct { bess::utils::be32_t mask; // bits with 1 won't be updated @@ -61,7 +61,7 @@ class RandomUpdate final : public Module { uint32_t range; // max - min + 1 size_t offset; size_t bit_shift; - } vars_[MAX_VARS]; + } vars_[kMaxVariable]; Random rng_; }; diff --git a/core/modules/replicate.h b/core/modules/replicate.h index 1df1141d6..3ac21d36d 100644 --- a/core/modules/replicate.h +++ b/core/modules/replicate.h @@ -31,7 +31,7 @@ #define BESS_MODULES_REPLICATE_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" class Replicate final : public Module { public: diff --git a/core/modules/rewrite.h b/core/modules/rewrite.h index 36536dba7..931e63efa 100644 --- a/core/modules/rewrite.h +++ b/core/modules/rewrite.h @@ -32,7 +32,7 @@ #define BESS_MODULES_REWRITE_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" class Rewrite final : public Module { public: diff --git a/core/modules/round_robin.h b/core/modules/round_robin.h index 4021a493c..ed9a1a183 100644 --- a/core/modules/round_robin.h +++ b/core/modules/round_robin.h @@ -32,7 +32,7 @@ #define BESS_MODULES_ROUNDROBIN_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" /*! * TODO: RoundRobin currently does not support multiple workers. diff --git a/core/modules/set_metadata.h b/core/modules/set_metadata.h index a081bf626..e7a560e20 100644 --- a/core/modules/set_metadata.h +++ b/core/modules/set_metadata.h @@ -32,7 +32,7 @@ #define BESS_MODULES_SETMETADATA_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" typedef struct { char bytes[bess::metadata::kMetadataAttrMaxSize]; } value_t; diff --git a/core/modules/source.h b/core/modules/source.h index 7272d78c9..5b6893048 100644 --- a/core/modules/source.h +++ b/core/modules/source.h @@ -32,7 +32,7 @@ #define BESS_MODULES_FLOWGEN_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" class Source final : public Module { public: @@ -40,9 +40,7 @@ class Source final : public Module { static const Commands cmds; - Source() : Module(), pkt_size_(), burst_() { - is_task_ = true; - } + Source() : Module(), pkt_size_(), burst_() { is_task_ = true; } CommandResponse Init(const bess::pb::SourceArg &arg); diff --git a/core/modules/split.h b/core/modules/split.h index 94a4640bc..6a0ccab8e 100644 --- a/core/modules/split.h +++ b/core/modules/split.h @@ -32,7 +32,7 @@ #define BESS_MODULES_SPLIT_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" class Split final : public Module { public: diff --git a/core/modules/timestamp.h b/core/modules/timestamp.h index ab1f6169b..3f1ed7b5f 100644 --- a/core/modules/timestamp.h +++ b/core/modules/timestamp.h @@ -32,7 +32,7 @@ #define BESS_MODULES_TIMESTAMP_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" class Timestamp final : public Module { public: diff --git a/core/modules/update.h b/core/modules/update.h index c43082b1b..440f7a259 100644 --- a/core/modules/update.h +++ b/core/modules/update.h @@ -32,7 +32,7 @@ #define BESS_MODULES_UPDATE_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" #include "../utils/endian.h" diff --git a/core/modules/url_filter.h b/core/modules/url_filter.h index 1848e9f87..afbcfb784 100644 --- a/core/modules/url_filter.h +++ b/core/modules/url_filter.h @@ -39,8 +39,8 @@ #include #include "../module.h" -#include "../module_msg.pb.h" #include "../packet.h" +#include "../pb/module_msg.pb.h" #include "../utils/tcp_flow_reconstruct.h" #include "../utils/trie.h" diff --git a/core/modules/vlan_push.h b/core/modules/vlan_push.h index 8e7a5250d..29310cfc7 100644 --- a/core/modules/vlan_push.h +++ b/core/modules/vlan_push.h @@ -32,7 +32,7 @@ #define BESS_MODULES_VLANPUSH_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" #include "../utils/endian.h" diff --git a/core/modules/vxlan_decap.h b/core/modules/vxlan_decap.h index 766f7418d..f5b50bc04 100644 --- a/core/modules/vxlan_decap.h +++ b/core/modules/vxlan_decap.h @@ -32,7 +32,7 @@ #define BESS_MODULES_VXLANDECAP_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" class VXLANDecap final : public Module { public: diff --git a/core/modules/vxlan_encap.h b/core/modules/vxlan_encap.h index adc752eba..529542314 100644 --- a/core/modules/vxlan_encap.h +++ b/core/modules/vxlan_encap.h @@ -32,7 +32,7 @@ #define BESS_MODULES_VXLANENCAP_H_ #include "../module.h" -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" #include "../utils/endian.h" diff --git a/core/modules/wildcard_match.h b/core/modules/wildcard_match.h index 5ed681e94..1dadffc8d 100644 --- a/core/modules/wildcard_match.h +++ b/core/modules/wildcard_match.h @@ -36,7 +36,7 @@ #include #include -#include "../module_msg.pb.h" +#include "../pb/module_msg.pb.h" #include "../utils/cuckoo_map.h" using bess::utils::HashResult; diff --git a/core/pb/.gitignore b/core/pb/.gitignore new file mode 100644 index 000000000..f935021a8 --- /dev/null +++ b/core/pb/.gitignore @@ -0,0 +1 @@ +!.gitignore diff --git a/core/port.h b/core/port.h index 29d18977c..410ad1ea6 100644 --- a/core/port.h +++ b/core/port.h @@ -43,7 +43,7 @@ #include "message.h" #include "module.h" #include "packet.h" -#include "port_msg.pb.h" +#include "pb/port_msg.pb.h" #include "utils/common.h" typedef uint8_t queue_t; diff --git a/protobuf/bess_msg.proto b/protobuf/bess_msg.proto index 80303f23a..b182c7859 100644 --- a/protobuf/bess_msg.proto +++ b/protobuf/bess_msg.proto @@ -1,4 +1,5 @@ // Copyright (c) 2016-2017, Nefeli Networks, Inc. +// Copyright (c) 2017, The Regents of the University of California. // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -41,9 +42,6 @@ import "error.proto"; package bess.pb; -message EmptyArg { -} - message EmptyRequest { } diff --git a/protobuf/module_msg.proto b/protobuf/module_msg.proto index f6499e5fd..539f92cc5 100644 --- a/protobuf/module_msg.proto +++ b/protobuf/module_msg.proto @@ -1,4 +1,5 @@ // Copyright (c) 2016-2017, Nefeli Networks, Inc. +// Copyright (c) 2017, The Regents of the University of California. // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -46,6 +47,8 @@ import "util_msg.proto"; /// is called on modules in bessd. This file lists all modules, their initialization parameters /// and any functions that may be called on them. +message EmptyArg { +} /** * The BPF module has a command `clear()` that takes no parameters. @@ -735,8 +738,8 @@ message RandomDropArg { } /** - * The RandomUpdate module rewrites a random field in a packet with a random value - * between a specified min and max values. + * The RandomUpdate module rewrites a specified field (`offset` and `size`) in a packet + * with a random value between a specified min and max values. * * __Input Gates__: 1 * __Output Gates__: 1 diff --git a/pybess/bess.py b/pybess/bess.py index fafe498f4..5c53d3575 100644 --- a/pybess/bess.py +++ b/pybess/bess.py @@ -1,4 +1,4 @@ -# Copyright (c) 2014-2016, The Regents of the University of California. +# Copyright (c) 2014-2017, The Regents of the University of California. # Copyright (c) 2016-2017, Nefeli Networks, Inc. # Copyright (c) 2017, Cloudigo. # All rights reserved. @@ -38,12 +38,14 @@ import pprint import time -from . import service_pb2 from . import protobuf_to_dict as pb_conv -from . import module_msg -from . import bess_msg_pb2 as bess_msg -from . import port_msg_pb2 as port_msg +from . import module_pb_loader as module_pb + +from .builtin_pb import service_pb2 +from .builtin_pb import bess_msg_pb2 as bess_msg +from .builtin_pb import module_msg_pb2 as module_msg +from .builtin_pb import port_msg_pb2 as port_msg def _constraints_to_list(constraint): @@ -294,7 +296,7 @@ def create_port(self, driver, name=None, arg=None): request.size_out_q = arg.pop('size_out_q', 0) request.mac_addr = arg.pop('mac_addr', '') - message_type = getattr(port_msg, driver + 'Arg', bess_msg.EmptyArg) + message_type = getattr(port_msg, driver + 'Arg', module_msg.EmptyArg) arg_msg = pb_conv.dict_to_protobuf(message_type, arg) request.arg.Pack(arg_msg) @@ -349,7 +351,7 @@ def create_module(self, mclass, name=None, arg=None): request.name = name or '' request.mclass = mclass - message_type = getattr(module_msg, mclass + 'Arg', bess_msg.EmptyArg) + message_type = getattr(module_pb, mclass + 'Arg', module_msg.EmptyArg) arg_msg = pb_conv.dict_to_protobuf(message_type, arg) request.arg.Pack(arg_msg) @@ -385,7 +387,7 @@ def run_module_command(self, name, cmd, arg_type, arg): request.cmd = cmd try: - message_type = getattr(module_msg, arg_type) + message_type = getattr(module_pb, arg_type) except AttributeError as e: raise self.APIError('Unknown arg "%s"' % arg_type) @@ -404,8 +406,8 @@ def run_module_command(self, name, cmd, arg_type, arg): if response.HasField('data'): response_type_str = response.data.type_url.split('.')[-1] - response_type = getattr(module_msg, response_type_str, - bess_msg.EmptyArg) + response_type = getattr(module_pb, response_type_str, + module_msg.EmptyArg) result = response_type() response.data.Unpack(result) return result diff --git a/pybess/builtin_pb/__init__.py b/pybess/builtin_pb/__init__.py new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/pybess/builtin_pb/__init__.py @@ -0,0 +1 @@ + diff --git a/pybess/module_pb_loader.py b/pybess/module_pb_loader.py new file mode 100644 index 000000000..2a2ba7253 --- /dev/null +++ b/pybess/module_pb_loader.py @@ -0,0 +1,65 @@ +# Copyright (c) 2014-2017, The Regents of the University of California. +# Copyright (c) 2016-2017, Nefeli Networks, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the names of the copyright holders nor the names of their +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import importlib +import glob +import os + +__all__ = [] + +blacklist = ['builtin_pb.bess_msg_pb2', 'builtin_pb.port_msg_pb2'] + + +def update_symbols(module, symbols): + globals().update({name: module.__dict__[name] for name in symbols}) + + +def import_module(module_name, update_symbol=True): + module = importlib.import_module('..' + module_name, __name__) + symbols = [n for n in module.__dict__ if + n.endswith('Arg') or n.endswith('Response')] + + if update_symbol: + update_symbols(module, symbols) + + +def import_package(package_name): + cur_path = os.path.dirname(os.path.relpath(__file__)) + module_files = glob.glob(cur_path + '/' + package_name + '/*_msg_pb2.py') + modules = [package_name + '.' + m + for m in [os.path.basename(m)[:-3] for m in module_files]] + + for module_name in modules: + if module_name not in blacklist: + import_module(module_name) + +import_package('builtin_pb') +import_package('plugin_pb') +import_module('builtin_pb.bess_msg_pb2', False) diff --git a/pybess/plugin_pb/__init__.py b/pybess/plugin_pb/__init__.py new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/pybess/plugin_pb/__init__.py @@ -0,0 +1 @@ + diff --git a/pybess/test_bess.py b/pybess/test_bess.py index 0ea8cec20..1559fd677 100644 --- a/pybess/test_bess.py +++ b/pybess/test_bess.py @@ -35,8 +35,8 @@ from concurrent import futures from . import bess -from . import bess_msg_pb2 as bess_msg -from . import service_pb2 +from .builtin_pb import bess_msg_pb2 as bess_msg +from .builtin_pb import service_pb2 class DummyServiceImpl(service_pb2.BESSControlServicer): @@ -141,5 +141,5 @@ def test_run_module_command(self): 'add', 'ExactMatchCommandAddArg', {'gate': 0, - 'fields': [{'value_bin':b'\x11'}, {'value_bin':b'\x22'}]}) + 'fields': [{'value_bin': b'\x11'}, {'value_bin': b'\x22'}]}) self.assertEqual(0, response.error.code) diff --git a/pybess/test_protobuf_to_dict.py b/pybess/test_protobuf_to_dict.py index 96c4e2576..229d4ef28 100644 --- a/pybess/test_protobuf_to_dict.py +++ b/pybess/test_protobuf_to_dict.py @@ -30,9 +30,9 @@ from __future__ import absolute_import import unittest -from . import bess_msg_pb2 as bess_msg from . import protobuf_to_dict as pb_conv -from . import test_msg_pb2 as test_msg +from .builtin_pb import bess_msg_pb2 as bess_msg +from .builtin_pb import test_msg_pb2 as test_msg class TestProtobufConvert(unittest.TestCase): diff --git a/sample_plugin/Makefile b/sample_plugin/Makefile new file mode 100644 index 000000000..c57a1d92a --- /dev/null +++ b/sample_plugin/Makefile @@ -0,0 +1,47 @@ +# BESS must be already built. +# Set your BESS_HOME environment variable to that directory. +#BESS_HOME ?= /your/bess/home + +ifeq ($(BESS_HOME),) +$(error BESS_HOME is not defined.) +endif + +# Library target +target_a := modules/sequential_update.so +# Objects for the target +objects_a := modules/sequential_update.o + +# Add all your targets here +all: $(target_a) # $(target_b) ... + +# You can specify per-target flags like this +#$(target): LDFLAGS+= + +# Protobuf file location in 'absolute path' +protobuf := $(abspath protobuf/supdate_msg.proto) + +#### You don't need to modify from here #### +proto_h := $(patsubst %.proto,%.pb.h, $(protobuf)) \ + $(patsubst %.proto,%.grpc.pb.h, $(protobuf)) +proto_cc := $(patsubst %.proto,%.pb.cc, $(protobuf)) \ + $(patsubst %.proto,%.grpc.pb.cc, $(protobuf)) +proto_o := $(patsubst %.cc,%.o, $(proto_cc)) +proto_py := $(patsubst %.proto, %_pb2.py, $(protobuf)) \ + $(patsubst %.proto, %_pb2_grpc.py, $(protobuf)) + +$(proto_cc): $(protobuf) $(proto_py) +$(proto_cc): PROTO_DIR=$(dir $(protobuf)) +$(proto_py): $(protobuf) +$(proto_py): PROTO_DIR=$(dir $(protobuf)) +#### up to here #### + +# Mapping between target library, protobuf, objects +# protobuf objects should appear before objects +$(target_a): $(proto_o) $(objects_a) +# $(target_b): $(proto_o) $(objects_b) + +clean: + rm -f $(proto_o) $(proto_cc) $(proto_h) $(proto_py) \ + $(target_a) $(objects_a) + +include $(BESS_HOME)/core/bess_plugin.mk diff --git a/pybess/module_msg.py b/sample_plugin/bessctl_conf/sequential_update.bess similarity index 63% rename from pybess/module_msg.py rename to sample_plugin/bessctl_conf/sequential_update.bess index eec0cc4fa..d5e12db6b 100644 --- a/pybess/module_msg.py +++ b/sample_plugin/bessctl_conf/sequential_update.bess @@ -1,4 +1,4 @@ -# Copyright (c) 2014-2016, The Regents of the University of California. +# Copyright (c) 2014-2017, The Regents of the University of California. # Copyright (c) 2016-2017, Nefeli Networks, Inc. # All rights reserved. # @@ -28,35 +28,24 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -import importlib -import glob -import os +import scapy.all as scapy -exclude_list = ['bess_msg_pb2', 'port_msg_pb2'] +eth = scapy.Ether(src='02:1e:67:9f:4d:ae', dst='06:16:3e:1b:72:32') +ip = scapy.IP(src='192.168.1.1', dst='10.0.0.1') +udp = scapy.UDP(sport=10001, dport=10002) +payload = 'helloworld' +pkt_bytes = bytes(eth/ip/udp/payload) +Source() -> Rewrite(templates=[pkt_bytes]) -> rr::RoundRobin(gates=[1, 2]) -def _load_symbols(mod, *symbols): - globals().update({name: mod.__dict__[name] for name in symbols}) +# src MAC address +rr:1 \ + -> Update(fields=[{'offset': 6, 'size': 6, 'value': 0x1234567890ab}]) \ + -> Sink() +# UDP src/dst ports +rr:2 \ + -> su::SequentialUpdate(fields=[{'offset': 34, 'size': 2, 'min': 20000, 'max': 30000}]) \ + -> Sink() -def load_symbol(mod_name, symbol): - mod = importlib.import_module('..' + mod_name, __name__) - _load_symbols(mod, symbol) - - -def load_symbols(mod_name): - mod = importlib.import_module('..' + mod_name, __name__) - symbols = [n for n in mod.__dict__ if - n.endswith('Arg') or n.endswith('Response')] - _load_symbols(mod, *symbols) - - -dir_path = os.path.dirname(os.path.realpath(__file__)) -mod_files = glob.glob(dir_path + '/*_msg_pb2.py') -mods = [m for m in [os.path.basename(m)[:-3] for m in mod_files] - if m not in exclude_list] - -for mod_name in mods: - load_symbols(mod_name) - -load_symbol('bess_msg_pb2', 'EmptyArg') +su.add(fields=[{'offset': 36, 'size': 2, 'min': 40000, 'max': 50000}]) diff --git a/sample_plugin/modules/sequential_update.cc b/sample_plugin/modules/sequential_update.cc new file mode 100644 index 000000000..a0358ac5a --- /dev/null +++ b/sample_plugin/modules/sequential_update.cc @@ -0,0 +1,150 @@ +// Copyright (c) 2014-2017, The Regents of the University of California. +// Copyright (c) 2016-2017, Nefeli Networks, Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the names of the copyright holders nor the names of their +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include "sequential_update.h" + +using bess::utils::be32_t; + +const Commands SequentialUpdate::cmds = { + {"add", "SequentialUpdateArg", + MODULE_CMD_FUNC(&SequentialUpdate::CommandAdd), Command::THREAD_UNSAFE}, + {"clear", "EmptyArg", MODULE_CMD_FUNC(&SequentialUpdate::CommandClear), + Command::THREAD_UNSAFE}, +}; + +CommandResponse +SequentialUpdate::Init(const sample::supdate::pb::SequentialUpdateArg &arg) { + return CommandAdd(arg); +} + +CommandResponse SequentialUpdate::CommandAdd( + const sample::supdate::pb::SequentialUpdateArg &arg) { + size_t curr = num_vars_; + if (curr + arg.fields_size() > kMaxVariable) { + return CommandFailure(EINVAL, "max %zu variables can be specified", + kMaxVariable); + } + + for (int i = 0; i < arg.fields_size(); i++) { + const auto &var = arg.fields(i); + + size_t size; + size_t offset; + be32_t mask; + uint32_t min; + uint32_t max; + + offset = var.offset(); + size = var.size(); + min = var.min(); + max = var.max(); + + switch (size) { + case 1: + mask = be32_t(0x00ffffff); + min = std::min(min, static_cast(0xff)); + max = std::min(max, static_cast(0xff)); + break; + + case 2: + mask = be32_t(0x0000ffff); + min = std::min(min, static_cast(0xffff)); + max = std::min(max, static_cast(0xffff)); + break; + + case 4: + mask = be32_t(0x00000000); + min = std::min(min, static_cast(0xffffffffu)); + max = std::min(max, static_cast(0xffffffffu)); + break; + + default: + return CommandFailure(EINVAL, "'size' must be 1, 2, or 4"); + } + + if (offset + size > SNBUF_DATA) { + return CommandFailure(EINVAL, "too large 'offset'"); + } + + if (min > max) { + return CommandFailure(EINVAL, "'min' should not be greater than 'max'"); + } + + vars_[curr + i].offset = offset; + vars_[curr + i].mask = mask; + vars_[curr + i].min = min; + + // avoid modulo 0 + vars_[curr + i].range = (max - min + 1) ?: 0xffffffff; + vars_[curr + i].cur = 0; + vars_[curr + i].bit_shift = (4 - size) * 8; + } + + num_vars_ = curr + arg.fields_size(); + return CommandSuccess(); +} + +CommandResponse SequentialUpdate::CommandClear(const bess::pb::EmptyArg &) { + num_vars_ = 0; + return CommandSuccess(); +} + +void SequentialUpdate::ProcessBatch(bess::PacketBatch *batch) { + int cnt = batch->cnt(); + + for (size_t i = 0; i < num_vars_; i++) { + const auto var = &vars_[i]; + + be32_t mask = var->mask; + uint32_t min = var->min; + uint32_t range = var->range; + uint32_t cur = var->cur; + size_t offset = var->offset; + size_t bit_shift = var->bit_shift; + + for (int j = 0; j < cnt; j++) { + be32_t *p = batch->pkts()[j]->head_data(offset); + uint32_t value = min + cur; + cur = cur + 1; + if (cur >= range) { + cur = 0; + } + + *p = (*p & mask) | (be32_t(value) << bit_shift); + } + + var->cur = cur; + } + + RunNextModule(batch); +} + +ADD_MODULE(SequentialUpdate, "supdate", + "updates packet data sequentially in a range") diff --git a/sample_plugin/modules/sequential_update.h b/sample_plugin/modules/sequential_update.h new file mode 100644 index 000000000..359f1148c --- /dev/null +++ b/sample_plugin/modules/sequential_update.h @@ -0,0 +1,68 @@ +// Copyright (c) 2014-2017, The Regents of the University of California. +// Copyright (c) 2016-2017, Nefeli Networks, Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the names of the copyright holders nor the names of their +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#ifndef BESS_MODULES_SEQUENTIALUPDATE_H_ +#define BESS_MODULES_SEQUENTIALUPDATE_H_ + +#include "module.h" +#include "utils/endian.h" + +#include "protobuf/supdate_msg.pb.h" + +static const size_t kMaxVariable = 16; + +class SequentialUpdate final : public Module { +public: + static const Commands cmds; + + SequentialUpdate() : Module(), num_vars_(), vars_() {} + + CommandResponse Init(const sample::supdate::pb::SequentialUpdateArg &arg); + + void ProcessBatch(bess::PacketBatch *batch) override; + + CommandResponse + CommandAdd(const sample::supdate::pb::SequentialUpdateArg &arg); + CommandResponse CommandClear(const bess::pb::EmptyArg &arg); + +private: + size_t num_vars_; + + struct { + bess::utils::be32_t mask; // bits with 1 won't be updated + uint32_t min; + uint32_t range; // max - min + 1 + uint32_t cur; + size_t offset; + size_t bit_shift; + } vars_[kMaxVariable]; +}; + +#endif // BESS_MODULES_SEQUENTIALUPDATE_H_ diff --git a/sample_plugin/protobuf/supdate_msg.proto b/sample_plugin/protobuf/supdate_msg.proto new file mode 100644 index 000000000..bca8070e3 --- /dev/null +++ b/sample_plugin/protobuf/supdate_msg.proto @@ -0,0 +1,60 @@ +// Copyright (c) 2017, The Regents of the University of California. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the names of the copyright holders nor the names of their +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package sample.supdate.pb; + +/** + * The function `clear()` for SequentialUpdate takes no parameters and clears all + * state in the module. + */ +message SequentialUpdateCommandClearArg { +} + +/** + * The SequentialUpdate module rewrites a specified field (`offset` and `size`) in a packet + * with a sequentially increased value from a specified min to max values. + * + * __Input Gates__: 1 + * __Output Gates__: 1 + */ +message SequentialUpdateArg { + /** + * SequentialUpdate's Field specifies where to rewrite, and what values to rewrite + * in each packet processed. + */ + message Field { + int64 offset = 1; /// Offset in bytes for where to rewrite. + uint64 size = 2; /// The number of bytes to write. + uint64 min = 3; /// The minimum value to insert into the packet. + uint64 max = 4; /// The maximum value to insert into the packet. + } + repeated Field fields = 1; /// A list of SequentialUpdate Fields. +}