diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 000000000..81ee5fa94 --- /dev/null +++ b/.bazelrc @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: 2026 Yuao Ma +# +# SPDX-License-Identifier: Apache-2.0 + +# Use Bzlmod (`MODULE.bazel`) instead of `WORKSPACE.bazel`. +common --enable_bzlmod +common --noenable_workspace + +# In Bazel 9, native C++ rules are no longer injected into the global namespace +# by default. Two files in grpc 1.76.0 still use native.cc_*: +# bazel/cython_library.bzl (native.cc_binary) +# third_party/address_sorting/address_sorting.bzl (native.cc_library) +# Restore the autoload until grpc 1.76.0.bcr.2 lands. No-op on Bazel 7/8. +build --incompatible_autoload_externally=+cc_library,+cc_binary + +build --conlyopt='-std=gnu11' --cxxopt='-std=c++17' +build --host_cxxopt='-std=c++17' diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 000000000..f7ee06693 --- /dev/null +++ b/.bazelversion @@ -0,0 +1 @@ +9.0.0 diff --git a/.bazelversion.license b/.bazelversion.license new file mode 100644 index 000000000..8949742c5 --- /dev/null +++ b/.bazelversion.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2026 Yuao Ma + +SPDX-License-Identifier: Apache-2.0 diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml new file mode 100644 index 000000000..79508432d --- /dev/null +++ b/.github/workflows/bazel.yml @@ -0,0 +1,64 @@ +# SPDX-FileCopyrightText: 2026 Yuao Ma +# +# SPDX-License-Identifier: Apache-2.0 + +name: "Test Bazel Build" + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + env: + BAZEL: bazelisk-linux-amd64 + BUILDIFIER: buildifier-linux-amd64 + steps: + - uses: actions/checkout@v6 + with: + submodules: recursive + + - name: Mount bazel cache + uses: actions/cache@v5 + with: + # See https://docs.bazel.build/versions/master/output_directories.html + path: "~/.cache/bazel" + # Create a new cache entry whenever Bazel files change. + # See https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows + key: bazel-${{ runner.os }}-build-${{ hashFiles('**/*.bzl', '**/*.bazel') }} + restore-keys: | + bazel-${{ runner.os }}-build- + + - name: Install Buildifier + run: | + curl -LO "https://github.com/bazelbuild/buildtools/releases/download/v8.5.1/$BUILDIFIER" + chmod +x $BUILDIFIER + sudo mv $BUILDIFIER /usr/local/bin/buildifier + + - name: Run Buildifier + run: | + BZL_FILES=$(git ls-files | grep -E 'BUILD.*|\.bzl$|\.bazel$') + if ! buildifier --mode=check $BZL_FILES; then + echo "::error::Buildifier formatting issues found." + echo "::group::Buildifier Diff" + buildifier --mode=diff $BZL_FILES + echo "::endgroup::" + exit 1 + else + echo "All files are formatted correctly." + fi + + - name: Install bazelisk + run: | + curl -LO "https://github.com/bazelbuild/bazelisk/releases/download/v1.29.0/$BAZEL" + chmod +x $BAZEL + sudo mv $BAZEL /usr/local/bin/bazel + + - name: Build + run: bazel build //targets/simple_switch_grpc:simple_switch_grpc + + - name: Test + run: bazel test //targets/simple_switch_grpc/tests/... diff --git a/BUILD.bazel b/BUILD.bazel new file mode 100644 index 000000000..2ff1ee800 --- /dev/null +++ b/BUILD.bazel @@ -0,0 +1,70 @@ +# SPDX-FileCopyrightText: 2026 Yuao Ma +# +# SPDX-License-Identifier: Apache-2.0 + +load("@bazel_skylib//rules:expand_template.bzl", "expand_template") +load("@package_metadata//licenses:defs.bzl", "license") +load("@rules_cc//cc:cc_library.bzl", "cc_library") + +package( + default_applicable_licenses = ["//:license"], + default_visibility = ["//visibility:public"], +) + +license( + name = "license", + kind = "@package_metadata//licenses/spdx:Apache-2.0", + text = "LICENSE", +) + +exports_files([ + "LICENSE", + "VERSION", +]) + +expand_template( + name = "config_h", + out = "include/bm/config.h", + substitutions = { + # disabled + "#cmakedefine BM_DEBUG_ON @BM_DEBUG_ON@": "/* #undef BM_DEBUG_ON */", + "#cmakedefine BM_ELOG_ON @BM_ELOG_ON@": "/* #undef BM_ELOG_ON */", + # enabled + "#cmakedefine BM_ENABLE_MODULES @BM_ENABLE_MODULES@": "#define BM_ENABLE_MODULES 1", + "#cmakedefine BM_HAVE_ALGORITHM @BM_HAVE_ALGORITHM@": "#define BM_HAVE_ALGORITHM 1", + "#cmakedefine BM_HAVE_ARRAY @BM_HAVE_ARRAY@": "#define BM_HAVE_ARRAY 1", + "#cmakedefine BM_HAVE_CASSERT @BM_HAVE_CASSERT@": "#define BM_HAVE_CASSERT 1", + "#cmakedefine BM_HAVE_CMATH @BM_HAVE_CMATH@": "#define BM_HAVE_CMATH 1", + "#cmakedefine BM_HAVE_CSTDIO @BM_HAVE_CSTDIO@": "#define BM_HAVE_CSTDIO 1", + "#cmakedefine BM_HAVE_CTIME @BM_HAVE_CTIME@": "#define BM_HAVE_CTIME 1", + "#cmakedefine BM_HAVE_DLFCN_H @BM_HAVE_DLFCN_H@": "#define BM_HAVE_DLFCN_H 1", + "#cmakedefine BM_HAVE_DLOPEN @BM_HAVE_DLOPEN@": "#define BM_HAVE_DLOPEN 1", + "#cmakedefine BM_HAVE_QUEUE @BM_HAVE_QUEUE@": "#define BM_HAVE_QUEUE 1", + "#cmakedefine BM_HAVE_STRING @BM_HAVE_STRING@": "#define BM_HAVE_STRING 1", + "#cmakedefine BM_HAVE_SYS_STAT_H @BM_HAVE_SYS_STAT_H@": "#define BM_HAVE_SYS_STAT_H 1", + "#cmakedefine BM_HAVE_SYS_TYPES_H @BM_HAVE_SYS_TYPES_H@": "#define BM_HAVE_SYS_TYPES_H 1", + # disabled + "#cmakedefine BM_HAVE_THRIFT_STDCXX_H @BM_HAVE_THRIFT_STDCXX_H@": "/* #undef BM_HAVE_THRIFT_STDCXX_H */", + # enabled + "#cmakedefine BM_HAVE_TUPLE @BM_HAVE_TUPLE@": "#define BM_HAVE_TUPLE 1", + "#cmakedefine BM_HAVE_UNISTD_H @BM_HAVE_UNISTD_H@": "#define BM_HAVE_UNISTD_H 1", + "#cmakedefine BM_HAVE_UNORDERED_MAP @BM_HAVE_UNORDERED_MAP@": "#define BM_HAVE_UNORDERED_MAP 1", + "#cmakedefine BM_HAVE_UTILITY @BM_HAVE_UTILITY@": "#define BM_HAVE_UTILITY 1", + "#cmakedefine BM_HAVE_VECTOR @BM_HAVE_VECTOR@": "#define BM_HAVE_VECTOR 1", + "#cmakedefine BM_LOG_DEBUG_ON @BM_LOG_DEBUG_ON@": "#define BM_LOG_DEBUG_ON 1", + "#cmakedefine BM_LOG_TRACE_ON @BM_LOG_TRACE_ON@": "#define BM_LOG_TRACE_ON 1", + # disabled + "#cmakedefine BM_NANOMSG_ON @BM_NANOMSG_ON@": "/* #undef BM_NANOMSG_ON */", + "#cmakedefine BM_THRIFT_ON @BM_THRIFT_ON@": "/* #undef BM_THRIFT_ON */", + "#cmakedefine BM_THRIFT_VERSION @BM_THRIFT_VERSION@": "/* #undef BM_THRIFT_VERSION */", + # enabled + "#cmakedefine BM_WP4_16_STACKS @BM_WP4_16_STACKS@": "#define BM_WP4_16_STACKS 1", + }, + template = "include/bm/config.h.in", +) + +cc_library( + name = "bm_headers", + hdrs = glob(["include/bm/**/*.h"]) + [":config_h"], + includes = ["include"], +) diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 000000000..2c86ba411 --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,37 @@ +# SPDX-FileCopyrightText: 2026 Yuao Ma +# +# SPDX-License-Identifier: Apache-2.0 + +module( + name = "behavioral_model", + version = "1.15.3", + bazel_compatibility = [">=7.0.0"], +) + +bazel_dep(name = "bazel_skylib", version = "1.9.0") +bazel_dep(name = "boost.container", version = "1.90.0.bcr.1") +bazel_dep(name = "boost.container_hash", version = "1.90.0.bcr.1") +bazel_dep(name = "boost.multiprecision", version = "1.90.0.bcr.1") +bazel_dep(name = "boost.program_options", version = "1.90.0.bcr.1") +bazel_dep(name = "boost.thread", version = "1.90.0.bcr.1") +bazel_dep(name = "boringssl", version = "0.20260508.0") +bazel_dep(name = "com_github_p4lang_pi", version = "head") +bazel_dep(name = "gmp", version = "6.3.0.bcr.1") +bazel_dep(name = "googleapis", version = "0.0.0-20260130-c0fcb356", repo_name = "com_google_googleapis") +bazel_dep(name = "grpc", version = "1.76.0", repo_name = "com_github_grpc_grpc") +bazel_dep(name = "jsoncpp", version = "1.9.6.bcr.2") +bazel_dep(name = "libpcap", version = "1.10.5.bcr.3") +bazel_dep(name = "p4runtime", version = "1.5.0.bcr.1", repo_name = "com_github_p4lang_p4runtime") +bazel_dep(name = "package_metadata", version = "0.0.10") +bazel_dep(name = "protobuf", version = "33.5", repo_name = "com_google_protobuf") +bazel_dep(name = "rules_cc", version = "0.2.17") +bazel_dep(name = "xxhash", version = "0.8.3.bcr.1") + +bazel_dep(name = "googletest", version = "1.17.0.bcr.2", dev_dependency = True) + +git_override( + module_name = "com_github_p4lang_pi", + commit = "0aa6c69140045b8a74575dbb7818664dd1066504", + init_submodules = True, + remote = "https://github.com/p4lang/PI.git", +) diff --git a/PI/BUILD.bazel b/PI/BUILD.bazel new file mode 100644 index 000000000..ed103de68 --- /dev/null +++ b/PI/BUILD.bazel @@ -0,0 +1,27 @@ +# SPDX-FileCopyrightText: 2026 Yuao Ma +# +# SPDX-License-Identifier: Apache-2.0 + +load("@rules_cc//cc:cc_library.bzl", "cc_library") + +package( + default_visibility = ["//visibility:public"], + licenses = ["notice"], +) + +cc_library( + name = "bmpi", + srcs = glob([ + "src/*.cpp", + "src/*.h", + ]), + hdrs = ["bm/PI/pi.h"], + includes = ["."], + local_defines = ["WITH_SIMPLE_SWITCH"], + deps = [ + "//:bm_headers", + "//targets/simple_switch:simpleswitch", + "@com_github_p4lang_pi//:pi", + ], + alwayslink = True, +) diff --git a/services/BUILD.bazel b/services/BUILD.bazel new file mode 100644 index 000000000..9b58ac5c6 --- /dev/null +++ b/services/BUILD.bazel @@ -0,0 +1,30 @@ +# SPDX-FileCopyrightText: 2026 Yuao Ma +# +# SPDX-License-Identifier: Apache-2.0 + +load("@com_github_grpc_grpc//bazel:cc_grpc_library.bzl", "cc_grpc_library") +load("@com_google_protobuf//bazel:cc_proto_library.bzl", "cc_proto_library") +load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library") + +package( + default_visibility = ["//visibility:public"], + licenses = ["notice"], +) + +proto_library( + name = "dataplane_interface_proto", + srcs = ["p4/bm/dataplane_interface.proto"], + strip_import_prefix = "", +) + +cc_proto_library( + name = "dataplane_interface_cc_proto", + deps = [":dataplane_interface_proto"], +) + +cc_grpc_library( + name = "bm_grpc_dataplane", + srcs = [":dataplane_interface_proto"], + grpc_only = True, + deps = [":dataplane_interface_cc_proto"], +) diff --git a/src/BMI/BUILD.bazel b/src/BMI/BUILD.bazel new file mode 100644 index 000000000..9c0a6c7a0 --- /dev/null +++ b/src/BMI/BUILD.bazel @@ -0,0 +1,25 @@ +# SPDX-FileCopyrightText: 2026 Yuao Ma +# +# SPDX-License-Identifier: Apache-2.0 + +load("@rules_cc//cc:cc_library.bzl", "cc_library") + +package( + default_visibility = ["//visibility:public"], + licenses = ["notice"], +) + +cc_library( + name = "bmi", + srcs = [ + "bmi_interface.c", + "bmi_port.c", + ], + hdrs = [ + "BMI/bmi_port.h", + "bmi_interface.h", + ], + includes = ["."], + local_defines = ["WITH_PCAP_FIX"], + deps = ["@libpcap"], +) diff --git a/src/bm_sim/BUILD.bazel b/src/bm_sim/BUILD.bazel new file mode 100644 index 000000000..a412ef63b --- /dev/null +++ b/src/bm_sim/BUILD.bazel @@ -0,0 +1,51 @@ +# SPDX-FileCopyrightText: 2026 Yuao Ma +# +# SPDX-License-Identifier: Apache-2.0 + +load("@rules_cc//cc:cc_library.bzl", "cc_library") + +package( + default_visibility = ["//visibility:public"], + licenses = ["notice"], +) + +genrule( + name = "version_cpp", + srcs = [ + "version.cpp.in", + "//:VERSION", + ], + outs = ["version.cpp"], + cmd = "sed \"s/@BM_VERSION@/$$(cat $(rootpath //:VERSION))/\" $(location version.cpp.in) > $@", +) + +cc_library( + name = "bmsim", + srcs = glob( + [ + "*.cpp", + "*.c", + "*.h", + "core/*.cpp", + ], + exclude = ["md5.c"], + ) + [":version_cpp"], + copts = ["-Isrc/bm_sim"], + defines = ["HAVE_OPENSSL"], + linkopts = ["-ldl"], + deps = [ + "//:bm_headers", + "//src/BMI:bmi", + "//third_party:spdlog", + "@boost.container", + "@boost.container_hash", + "@boost.multiprecision", + "@boost.program_options", + "@boost.thread", + "@boringssl//:crypto", + "@gmp", + "@jsoncpp", + "@libpcap", + "@xxhash", + ], +) diff --git a/targets/simple_switch/BUILD.bazel b/targets/simple_switch/BUILD.bazel new file mode 100644 index 000000000..aecfa436e --- /dev/null +++ b/targets/simple_switch/BUILD.bazel @@ -0,0 +1,29 @@ +# SPDX-FileCopyrightText: 2026 Yuao Ma +# +# SPDX-License-Identifier: Apache-2.0 + +load("@rules_cc//cc:cc_library.bzl", "cc_library") + +package( + default_visibility = ["//visibility:public"], + licenses = ["notice"], +) + +cc_library( + name = "simpleswitch", + srcs = [ + "primitives.cpp", + "simple_switch.cpp", + ], + hdrs = [ + "register_access.h", + "simple_switch.h", + ], + includes = ["."], + deps = [ + "//:bm_headers", + "//src/BMI:bmi", + "//src/bm_sim:bmsim", + "@jsoncpp", + ], +) diff --git a/targets/simple_switch_grpc/BUILD.bazel b/targets/simple_switch_grpc/BUILD.bazel new file mode 100644 index 000000000..0b8b03a85 --- /dev/null +++ b/targets/simple_switch_grpc/BUILD.bazel @@ -0,0 +1,39 @@ +# SPDX-FileCopyrightText: 2026 Yuao Ma +# +# SPDX-License-Identifier: Apache-2.0 + +load("@rules_cc//cc:cc_binary.bzl", "cc_binary") +load("@rules_cc//cc:cc_library.bzl", "cc_library") + +package( + default_visibility = ["//visibility:public"], + licenses = ["notice"], +) + +cc_library( + name = "simpleswitchgrpc", + srcs = ["switch_runner.cpp"], + hdrs = ["switch_runner.h"], + includes = ["."], + deps = [ + "//:bm_headers", + "//PI:bmpi", + "//services:bm_grpc_dataplane", + "//services:dataplane_interface_cc_proto", + "//targets/simple_switch:simpleswitch", + "@com_github_grpc_grpc//:grpc++", + "@com_github_p4lang_pi//:pi", + "@com_github_p4lang_pi//:pip4info", + "@com_github_p4lang_pi//proto/frontend:pifeproto", + "@com_github_p4lang_pi//proto/server:piserver", + ], +) + +cc_binary( + name = "simple_switch_grpc", + srcs = ["main.cpp"], + deps = [ + ":simpleswitchgrpc", + "//:bm_headers", + ], +) diff --git a/targets/simple_switch_grpc/tests/BUILD.bazel b/targets/simple_switch_grpc/tests/BUILD.bazel new file mode 100644 index 000000000..d5ebdf7a2 --- /dev/null +++ b/targets/simple_switch_grpc/tests/BUILD.bazel @@ -0,0 +1,66 @@ +# SPDX-FileCopyrightText: 2026 Yuao Ma +# +# SPDX-License-Identifier: Apache-2.0 + +load("@rules_cc//cc:cc_library.bzl", "cc_library") +load("@rules_cc//cc:cc_test.bzl", "cc_test") + +package( + default_visibility = ["//visibility:public"], + licenses = ["notice"], +) + +cc_library( + name = "test_common", + srcs = [ + "base_test.cpp", + "main.cpp", + "utils.cpp", + ], + hdrs = [ + "base_test.h", + "utils.h", + ], + defines = ["TESTDATADIR=\\\"" + package_name() + "/testdata\\\""], + deps = [ + "//services:bm_grpc_dataplane", + "//services:dataplane_interface_cc_proto", + "//targets/simple_switch:simpleswitch", + "//targets/simple_switch_grpc:simpleswitchgrpc", + "@com_github_grpc_grpc//:grpc++", + "@com_github_p4lang_p4runtime//proto/p4/config/v1:p4info_cc_proto", + "@com_github_p4lang_p4runtime//proto/p4/v1:p4runtime_cc_grpc", + "@com_github_p4lang_pi//:pi", + "@com_github_p4lang_pi//:pip4info", + "@com_github_p4lang_pi//proto/frontend:pifeproto", + "@com_github_p4lang_pi//proto/server:piserver", + "@com_google_googleapis//google/rpc:code_cc_proto", + "@com_google_protobuf//:protobuf", + "@googletest//:gtest", + ], +) + +_TESTS = [ + "test_action_profile", + "test_basic", + "test_counter", + "test_digest", + "test_grpc_dp", + "test_idle_timeout", + "test_meter", + "test_optional", + "test_packet_io", + "test_pre", + "test_ternary", +] + +[ + cc_test( + name = test, + srcs = [test + ".cpp"], + data = glob(["testdata/**"]), + tags = ["exclusive"], # tests share a gRPC port; must not run in parallel + deps = [":test_common"], + ) + for test in _TESTS +] diff --git a/third_party/BUILD.bazel b/third_party/BUILD.bazel new file mode 100644 index 000000000..cce73b9bd --- /dev/null +++ b/third_party/BUILD.bazel @@ -0,0 +1,20 @@ +# SPDX-FileCopyrightText: 2026 Yuao Ma +# +# SPDX-License-Identifier: Apache-2.0 + +load("@rules_cc//cc:cc_library.bzl", "cc_library") + +package( + default_visibility = ["//visibility:public"], + licenses = ["notice"], +) + +cc_library( + name = "spdlog", + hdrs = glob([ + "spdlog/bm/spdlog/*.h", + "spdlog/bm/spdlog/**/*.h", + "spdlog/bm/spdlog/**/*.cc", + ]), + includes = ["spdlog"], +)