diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 000000000..94329968e --- /dev/null +++ b/.bazelrc @@ -0,0 +1,16 @@ +# C++17 standard (required by BMv2) +build --cxxopt=-std=c++17 +build --host_cxxopt=-std=c++17 + +# Position-independent code (required for shared libs) +build --copt=-fPIC + +# Compiler warnings (match CMake config) +build --copt=-Wall +build --copt=-Wextra + +# Feature flags (match CMake defaults) +build --copt=-DLOG_DEBUG_ON +build --copt=-DLOG_TRACE_ON +build --copt=-DWP4_16_STACKS +build --per_file_copt=external/.*@-Wno-error diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 000000000..6d2890793 --- /dev/null +++ b/.bazelversion @@ -0,0 +1 @@ +8.5.0 diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml new file mode 100644 index 000000000..7c80e1699 --- /dev/null +++ b/.github/workflows/bazel.yml @@ -0,0 +1,42 @@ +name: Bazel + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + build-and-test: + runs-on: ubuntu-22.04 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Fix expired p4lang GPG key + run: | + sudo sed -i "s|deb http://download.opensuse.org/repositories/home:/p4lang/xUbuntu_22.04/|deb [trusted=yes] http://download.opensuse.org/repositories/home:/p4lang/xUbuntu_22.04/|g" install_deps_ubuntu_22.04.sh + sudo sed -i '/curl -fsSL https:\/\/download.opensuse.org\/repositories\/home:\/p4lang/d' install_deps_ubuntu_22.04.sh + - name: Install dependencies + run: sudo ./install_deps_ubuntu_22.04.sh + + - name: Cache Bazel + uses: actions/cache@v3 + with: + path: | + ~/.cache/bazel + key: ${{ runner.os }}-bazel-${{ hashFiles('.bazelversion', '.bazelrc', 'MODULE.bazel') }} + restore-keys: | + ${{ runner.os }}-bazel- + + - name: Build simple_switch_grpc + run: | + bazel build //targets/simple_switch_grpc:simple_switch_grpc + + - name: Run simple_switch_grpc tests + run: | + bazel test //targets/simple_switch_grpc/tests/... \ No newline at end of file diff --git a/.gitignore b/.gitignore index fa3f77839..dff18510c 100644 --- a/.gitignore +++ b/.gitignore @@ -104,3 +104,7 @@ VERSION-build core vgcore* + +# Bazel +bazel-* +*.lock diff --git a/BUILD.bazel b/BUILD.bazel new file mode 100644 index 000000000..876315a6e --- /dev/null +++ b/BUILD.bazel @@ -0,0 +1 @@ +exports_files(["VERSION"]) diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 000000000..c75047207 --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,15 @@ +module( + name = "behavioral-model", + version = "1.0.0", +) +# C++ rules for Bazel +bazel_dep(name = "rules_cc", version = "0.1.1") + +# Google Test for running the unit tests +bazel_dep(name = "googletest", version = "1.17.0") + +bazel_dep(name = "rules_proto", version = "7.1.0") + +# gRPC and Protobuf for the simple_switch_grpc server +bazel_dep(name = "grpc", version = "1.78.0") +bazel_dep(name = "protobuf", version = "31.1") diff --git a/PI/BUILD.bazel b/PI/BUILD.bazel new file mode 100644 index 000000000..48a4616b7 --- /dev/null +++ b/PI/BUILD.bazel @@ -0,0 +1,21 @@ +load("@rules_cc//cc:defs.bzl", "cc_library") + +cc_library( + name = "bmpi", + srcs = glob([ + "src/*.cpp", + ]), + hdrs = glob([ + "src/*.h", + "bm/PI/*.h", + ]), + includes = [".", "../targets/simple_switch"], + defines = ["WITH_SIMPLE_SWITCH"], + deps = [ + "//include:bm_headers", + "//src/bm_sim:bmsim", + "//targets/simple_switch:simpleswitch_headers", + ], + alwayslink = True, + visibility = ["//visibility:public"], +) diff --git a/PI/pi_system_libs.BUILD b/PI/pi_system_libs.BUILD new file mode 100644 index 000000000..a5dc77fcd --- /dev/null +++ b/PI/pi_system_libs.BUILD @@ -0,0 +1,31 @@ +load("@rules_cc//cc:defs.bzl", "cc_import") + +cc_import( + name = "pi_lib", + static_library = "/usr/local/lib/libpi.a", + visibility = ["//visibility:public"], +) + +cc_import( + name = "pip4info_lib", + static_library = "/usr/local/lib/libpip4info.a", + visibility = ["//visibility:public"], +) + +cc_import( + name = "pifrontend_lib", + static_library = "/usr/local/lib/libpifrontend.a", + visibility = ["//visibility:public"], +) + +cc_import( + name = "pifeproto_lib", + static_library = "/usr/local/lib/libpifeproto.a", + visibility = ["//visibility:public"], +) + +cc_import( + name = "pigrpcserver_lib", + static_library = "/usr/local/lib/libpigrpcserver.a", + visibility = ["//visibility:public"], +) diff --git a/include/BUILD.bazel b/include/BUILD.bazel new file mode 100644 index 000000000..fcb15ddee --- /dev/null +++ b/include/BUILD.bazel @@ -0,0 +1,15 @@ +load("@rules_cc//cc:defs.bzl", "cc_library") + +genrule( + name = "bm_config_h", + srcs = ["bm/config.h.in"], + outs = ["bm/config.h"], + cmd = "sed -e 's/#cmakedefine/#undef/g' $< > $@", +) + +cc_library( + name = "bm_headers", + hdrs = glob(["bm/**/*.h"]) + [":bm_config_h"], + includes = ["."], + visibility = ["//visibility:public"], +) diff --git a/install_deps_ubuntu_22.04.sh b/install_deps_ubuntu_22.04.sh index 9ac35b871..19a62ca2a 100755 --- a/install_deps_ubuntu_22.04.sh +++ b/install_deps_ubuntu_22.04.sh @@ -1,19 +1,21 @@ #!/bin/bash set -e - apt-get update apt-get install -y curl gnupg -echo 'deb http://download.opensuse.org/repositories/home:/p4lang/xUbuntu_22.04/ /' | tee /etc/apt/sources.list.d/home:p4lang.list -curl -fsSL https://download.opensuse.org/repositories/home:p4lang/xUbuntu_22.04/Release.key | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/home_p4lang.gpg > /dev/null -apt-get update +# Add p4lang repo with trusted=yes to bypass expired GPG key +echo 'deb [trusted=yes] http://download.opensuse.org/repositories/home:/p4lang/xUbuntu_22.04/ /' \ + | tee /etc/apt/sources.list.d/home:p4lang.list +apt-get update apt-get install -qq --no-install-recommends \ automake \ build-essential \ cmake \ git \ g++ \ + libabsl-dev \ + libc-ares-dev \ libboost-dev \ libboost-filesystem-dev \ libboost-program-options-dev \ @@ -27,10 +29,12 @@ apt-get install -qq --no-install-recommends \ libpcap-dev \ libprotobuf-dev \ libprotoc-dev \ + libre2-dev \ libssl-dev \ libthrift-0.16.0 \ libthrift-dev \ libtool \ + libupb-dev \ pkg-config \ protobuf-compiler \ protobuf-compiler-grpc \ @@ -40,5 +44,4 @@ apt-get install -qq --no-install-recommends \ thrift-compiler \ libreadline-dev \ p4lang-pi - -ldconfig +ldconfig \ No newline at end of file diff --git a/pkgconfig_grpc.bzl b/pkgconfig_grpc.bzl new file mode 100644 index 000000000..1dfabed9f --- /dev/null +++ b/pkgconfig_grpc.bzl @@ -0,0 +1,8 @@ +def get_grpc_linkopts(): + return [ + "-lgrpc++", "-lgrpc", "-lprotobuf", "-lgpr", + "-labsl_cord", "-labsl_strings", "-labsl_base", + "-labsl_synchronization", "-labsl_status", + "-labsl_statusor", "-labsl_time", + "-lre2", "-lcares", "-lupb" + ] \ No newline at end of file diff --git a/services/BUILD.bazel b/services/BUILD.bazel new file mode 100644 index 000000000..b75d164d2 --- /dev/null +++ b/services/BUILD.bazel @@ -0,0 +1,29 @@ +load("@rules_cc//cc:defs.bzl", "cc_library") +load("//:pkgconfig_grpc.bzl", "get_grpc_linkopts") + +genrule( + name = "dataplane_interface_codegen", + srcs = ["p4/bm/dataplane_interface.proto"], + outs = [ + "p4/bm/dataplane_interface.pb.h", + "p4/bm/dataplane_interface.pb.cc", + "p4/bm/dataplane_interface.grpc.pb.h", + "p4/bm/dataplane_interface.grpc.pb.cc", + ], + cmd = "protoc -Iservices --cpp_out=$(RULEDIR) --grpc_out=$(RULEDIR) --plugin=protoc-gen-grpc=/usr/bin/grpc_cpp_plugin $(location p4/bm/dataplane_interface.proto)", +) + +cc_library( + name = "bm_grpc_dataplane", + srcs = [ + "p4/bm/dataplane_interface.pb.cc", + "p4/bm/dataplane_interface.grpc.pb.cc", + ], + hdrs = [ + "p4/bm/dataplane_interface.pb.h", + "p4/bm/dataplane_interface.grpc.pb.h", + ], + includes = ["."], + linkopts = get_grpc_linkopts(), + visibility = ["//visibility:public"], +) diff --git a/src/BMI/BUILD.bazel b/src/BMI/BUILD.bazel new file mode 100644 index 000000000..d894d9795 --- /dev/null +++ b/src/BMI/BUILD.bazel @@ -0,0 +1,13 @@ +load("@rules_cc//cc:defs.bzl", "cc_library") + +cc_library( + name = "bmi", + srcs = [ + "bmi_interface.c", + "bmi_port.c", + ], + hdrs = glob(["*.h", "BMI/*.h"]), + includes = ["."], + visibility = ["//visibility:public"], + linkopts = ["-lpcap"], +) diff --git a/src/bm_sim/BUILD.bazel b/src/bm_sim/BUILD.bazel new file mode 100644 index 000000000..605bdbc26 --- /dev/null +++ b/src/bm_sim/BUILD.bazel @@ -0,0 +1,24 @@ +load("@rules_cc//cc:defs.bzl", "cc_library") + +# Generate version.cpp from template +genrule( + name = "version_cpp", + srcs = ["version.cpp.in", "//:VERSION"], + outs = ["version.cpp"], + cmd = "sed 's/@BM_VERSION@/1.13.0/g' $(location version.cpp.in) > $@", +) + +cc_library( + name = "bmsim", + srcs = glob(["*.cpp", "*.c", "core/*.cpp"]) + [":version_cpp"], + hdrs = glob(["*.h"]), + includes = ["."], + deps = [ + "//include:bm_headers", + "//third_party:jsoncpp", + "//third_party:spdlog", + "//src/BMI:bmi", + ], + linkopts = ["-lgmp", "-lpcap", "-lnanomsg", "-lpthread", "-ldl", "-lboost_program_options", "-lboost_system", "-lboost_filesystem", "-lboost_thread"], + visibility = ["//visibility:public"], +) diff --git a/targets/simple_switch/BUILD.bazel b/targets/simple_switch/BUILD.bazel new file mode 100644 index 000000000..89450ed12 --- /dev/null +++ b/targets/simple_switch/BUILD.bazel @@ -0,0 +1,22 @@ +load("@rules_cc//cc:defs.bzl", "cc_library") + +cc_library( + name = "simpleswitch", + srcs = glob(["*.cpp"], exclude=["main.cpp"]), + hdrs = glob(["*.h", "bm/**/*.h"]), + includes = ["."], + deps = [ + "//include:bm_headers", + "//src/bm_sim:bmsim", + "//src/BMI:bmi", + ], + visibility = ["//visibility:public"], +) + +# Also expose headers as a separate target for PI, or just let PI depend on simpleswitch. +# PI depends on simpleswitch_headers, so let's keep it or alias it. +alias( + name = "simpleswitch_headers", + actual = ":simpleswitch", + visibility = ["//visibility:public"], +) diff --git a/targets/simple_switch_grpc/BUILD.bazel b/targets/simple_switch_grpc/BUILD.bazel new file mode 100644 index 000000000..525fc48c0 --- /dev/null +++ b/targets/simple_switch_grpc/BUILD.bazel @@ -0,0 +1,43 @@ +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") +load("//:pkgconfig_grpc.bzl", "get_grpc_linkopts") + +_PI_LINKOPTS = [ + "-L/usr/local/lib", + "-Wl,-rpath=/usr/local/lib", + "-lpigrpcserver", + "-lpifeproto", + "-lpiprotogrpc", + "-lpiprotobuf", + "-lpifecpp", + "-lpiconvertproto", + "-lpi", + "-lpip4info", + "-lpifegeneric", +] + get_grpc_linkopts() + ["-lgrpc++_reflection"] + +# Library for starting the gRPC server attached to the switch +cc_library( + name = "switch_runner", + srcs = ["switch_runner.cpp"], + hdrs = ["switch_runner.h"], + includes = ["."], + deps = [ + "//targets/simple_switch:simpleswitch", + "//PI:bmpi", + "//services:bm_grpc_dataplane", + ], + linkopts = _PI_LINKOPTS, + visibility = ["//visibility:public"], +) + +# The main executable target +cc_binary( + name = "simple_switch_grpc", + srcs = ["main.cpp"], + deps = [ + ":switch_runner", + "//targets/simple_switch:simpleswitch", + ], + linkopts = _PI_LINKOPTS, + visibility = ["//visibility:public"], +) \ No newline at end of file diff --git a/targets/simple_switch_grpc/tests/BUILD.bazel b/targets/simple_switch_grpc/tests/BUILD.bazel new file mode 100644 index 000000000..88fc167d3 --- /dev/null +++ b/targets/simple_switch_grpc/tests/BUILD.bazel @@ -0,0 +1,67 @@ +load("@rules_cc//cc:defs.bzl", "cc_test", "cc_library") +load("//:pkgconfig_grpc.bzl", "get_grpc_linkopts") + +_PI_LINKOPTS = [ + "-L/usr/local/lib", + "-lpigrpcserver", + "-lpifeproto", + "-lpiprotogrpc", + "-lpiprotobuf", + "-lpifecpp", + "-lpiconvertproto", + "-lpi", + "-lpip4info", + "-lpifegeneric", +] + get_grpc_linkopts() + ["-lgrpc++_reflection"] + +cc_library( + name = "test_common", + srcs = [ + "base_test.cpp", + "utils.cpp", + ], + hdrs = [ + "base_test.h", + "utils.h", + ], + deps = [ + "//targets/simple_switch_grpc:switch_runner", + "//targets/simple_switch:simpleswitch", + "//services:bm_grpc_dataplane", + "@googletest//:gtest", + ], + linkopts = _PI_LINKOPTS, + defines = ["TESTDATADIR=\\\"targets/simple_switch_grpc/tests/testdata\\\""], + copts = ["-Wno-error=unused-result", "-Wno-error=deprecated-declarations"], +) + +[ + cc_test( + name = test_name, + srcs = [ + test_name + ".cpp", + "main.cpp", + ], + deps = [ + ":test_common", + "@googletest//:gtest", + ], + data = glob(["testdata/**"]), + linkopts = _PI_LINKOPTS, + linkstatic = True, + tags = ["exclusive"], + ) + for test_name in [ + "test_basic", + "test_grpc_dp", + "test_packet_io", + "test_counter", + "test_meter", + "test_ternary", + "test_pre", + "test_digest", + "test_idle_timeout", + "test_action_profile", + "test_optional", + ] +] diff --git a/third_party/BUILD.bazel b/third_party/BUILD.bazel new file mode 100644 index 000000000..883592e6e --- /dev/null +++ b/third_party/BUILD.bazel @@ -0,0 +1,16 @@ +load("@rules_cc//cc:defs.bzl", "cc_library") + +cc_library( + name = "jsoncpp", + srcs = ["jsoncpp/src/jsoncpp.cpp"], + hdrs = ["jsoncpp/include/jsoncpp/json.h"], + includes = ["jsoncpp/include"], + visibility = ["//visibility:public"], +) + +cc_library( + name = "spdlog", + hdrs = glob(["spdlog/bm/spdlog/**/*.h", "spdlog/bm/spdlog/**/*.cc"]), + includes = ["spdlog"], + visibility = ["//visibility:public"], +)