Make port_listener buildable

Bug: 340126051
Test: cd build/debian/port_listener && sudo ./build.sh
Change-Id: I01d54c6f5ef7c1b2f4706eedfbfea7d8c3064bd5
diff --git a/build/debian/port_listener/build.sh b/build/debian/port_listener/build.sh
new file mode 100755
index 0000000..a1d0205
--- /dev/null
+++ b/build/debian/port_listener/build.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+
+set -e
+
+check_sudo() {
+	if [ "$EUID" -ne 0 ]; then
+		echo "Please run as root."
+		exit
+	fi
+}
+
+install_prerequisites() {
+    apt update
+    apt install --no-install-recommends --assume-yes \
+        bpftool \
+        clang \
+        libbpf-dev \
+        libgoogle-glog-dev \
+        libstdc++-14-dev
+}
+
+build_port_listener() {
+    cp $(dirname $0)/src/* ${workdir}
+    out_dir=${PWD}
+    pushd ${workdir}
+        bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
+        clang \
+            -O2 \
+            -Wall \
+            -target bpf \
+            -g \
+            -c listen_tracker.ebpf.c \
+            -o listen_tracker.ebpf.o
+        bpftool gen skeleton listen_tracker.ebpf.o > listen_tracker.skel.h
+        clang++ \
+            -O2 \
+            -Wall \
+            -lbpf \
+            -lglog \
+            -o port_listener \
+            main.cc
+        cp port_listener ${out_dir}
+    popd
+}
+
+clean_up() {
+	rm -rf ${workdir}
+}
+trap clean_up EXIT
+workdir=$(mktemp -d)
+
+check_sudo
+install_prerequisites
+build_port_listener
diff --git a/build/debian/port_listener/src/common.h b/build/debian/port_listener/src/common.h
index 05386a4..d6e507c 100644
--- a/build/debian/port_listener/src/common.h
+++ b/build/debian/port_listener/src/common.h
@@ -19,13 +19,13 @@
 #define VM_TOOLS_PORT_LISTENER_COMMON_H_
 
 enum State {
-  kPortListenerUp,
-  kPortListenerDown,
+    kPortListenerUp,
+    kPortListenerDown,
 };
 
 struct event {
-  enum State state;
-  uint16_t port;
+    enum State state;
+    uint16_t port;
 };
 
-#endif  // VM_TOOLS_PORT_LISTENER_COMMON_H_
+#endif // VM_TOOLS_PORT_LISTENER_COMMON_H_
diff --git a/build/debian/port_listener/src/listen_tracker.ebpf.c b/build/debian/port_listener/src/listen_tracker.ebpf.c
index 4ecc423..030ded0 100644
--- a/build/debian/port_listener/src/listen_tracker.ebpf.c
+++ b/build/debian/port_listener/src/listen_tracker.ebpf.c
@@ -16,11 +16,11 @@
 // src/platform2/vm_tools/port_listener/listen_tracker.ebpf.c
 
 // bpf_helpers.h uses types defined here
-#include "include/vm_tools/port_listener/vmlinux/vmlinux.h"
+#include "vmlinux.h"
 
 #include <bpf/bpf_helpers.h>
 
-#include "vm_tools/port_listener/common.h"
+#include "common.h"
 
 // For some reason 6.1 doesn't include these symbols in the debug build
 // so they don't get included in vmlinux.h. These features have existed since
@@ -29,55 +29,53 @@
 #define BPF_ANY 0
 
 struct {
-  __uint(type, BPF_MAP_TYPE_RINGBUF);
-  __uint(max_entries, 1 << 24);
+    __uint(type, BPF_MAP_TYPE_RINGBUF);
+    __uint(max_entries, 1 << 24);
 } events SEC(".maps");
 
 struct {
-  __uint(type, BPF_MAP_TYPE_HASH);
-  __type(key, struct sock*);
-  __type(value, __u8);
-  __uint(max_entries, 65535);
-  __uint(map_flags, BPF_F_NO_PREALLOC);
+    __uint(type, BPF_MAP_TYPE_HASH);
+    __type(key, struct sock*);
+    __type(value, __u8);
+    __uint(max_entries, 65535);
+    __uint(map_flags, BPF_F_NO_PREALLOC);
 } sockmap SEC(".maps");
 
 const __u8 set_value = 0;
 
 SEC("tp/sock/inet_sock_set_state")
-int tracepoint_inet_sock_set_state(
-    struct trace_event_raw_inet_sock_set_state* ctx) {
-  // We don't support anything other than TCP.
-  if (ctx->protocol != IPPROTO_TCP) {
-    return 0;
-  }
-  struct sock* sk = (struct sock*)ctx->skaddr;
-  // If we're transitioning away from LISTEN but we don't know about this
-  // socket yet then don't report anything.
-  if (ctx->oldstate == BPF_TCP_LISTEN &&
-      bpf_map_lookup_elem(&sockmap, &sk) == NULL) {
-    return 0;
-  }
-  // If we aren't transitioning to or from TCP_LISTEN then we don't care.
-  if (ctx->newstate != BPF_TCP_LISTEN && ctx->oldstate != BPF_TCP_LISTEN) {
-    return 0;
-  }
+int tracepoint_inet_sock_set_state(struct trace_event_raw_inet_sock_set_state* ctx) {
+    // We don't support anything other than TCP.
+    if (ctx->protocol != IPPROTO_TCP) {
+        return 0;
+    }
+    struct sock* sk = (struct sock*)ctx->skaddr;
+    // If we're transitioning away from LISTEN but we don't know about this
+    // socket yet then don't report anything.
+    if (ctx->oldstate == BPF_TCP_LISTEN && bpf_map_lookup_elem(&sockmap, &sk) == NULL) {
+        return 0;
+    }
+    // If we aren't transitioning to or from TCP_LISTEN then we don't care.
+    if (ctx->newstate != BPF_TCP_LISTEN && ctx->oldstate != BPF_TCP_LISTEN) {
+        return 0;
+    }
 
-  struct event* ev;
-  ev = bpf_ringbuf_reserve(&events, sizeof(*ev), 0);
-  if (!ev) {
+    struct event* ev;
+    ev = bpf_ringbuf_reserve(&events, sizeof(*ev), 0);
+    if (!ev) {
+        return 0;
+    }
+    ev->port = ctx->sport;
+
+    if (ctx->newstate == BPF_TCP_LISTEN) {
+        bpf_map_update_elem(&sockmap, &sk, &set_value, BPF_ANY);
+        ev->state = kPortListenerUp;
+    }
+    if (ctx->oldstate == BPF_TCP_LISTEN) {
+        bpf_map_delete_elem(&sockmap, &sk);
+        ev->state = kPortListenerDown;
+    }
+    bpf_ringbuf_submit(ev, 0);
+
     return 0;
-  }
-  ev->port = ctx->sport;
-
-  if (ctx->newstate == BPF_TCP_LISTEN) {
-    bpf_map_update_elem(&sockmap, &sk, &set_value, BPF_ANY);
-    ev->state = kPortListenerUp;
-  }
-  if (ctx->oldstate == BPF_TCP_LISTEN) {
-    bpf_map_delete_elem(&sockmap, &sk);
-    ev->state = kPortListenerDown;
-  }
-  bpf_ringbuf_submit(ev, 0);
-
-  return 0;
 }
diff --git a/build/debian/port_listener/src/main.cc b/build/debian/port_listener/src/main.cc
index cc1f91e..b0b0979 100644
--- a/build/debian/port_listener/src/main.cc
+++ b/build/debian/port_listener/src/main.cc
@@ -15,24 +15,18 @@
 // Copied from ChromiumOS with relicensing:
 // src/platform2/vm_tools/port_listener/main.cc
 
-#include <sys/socket.h>
-
-#include <linux/vm_sockets.h>  // Needs to come after sys/socket.h
-
-#include <memory>
-
-#include <base/logging.h>
-#include <base/memory/ptr_util.h>
-#include <base/strings/stringprintf.h>
 #include <bpf/libbpf.h>
 #include <bpf/libbpf_legacy.h>
-#include <chromeos/constants/vm_tools.h>
-#include <grpcpp/grpcpp.h>
-#include <vm_protos/proto_bindings/common.pb.h>
-#include <vm_protos/proto_bindings/tremplin.grpc.pb.h>
+#include <glog/logging.h>
+#include <sys/socket.h>
 
-#include "vm_tools/port_listener/bpf/generated/skeleton_listen_tracker.ebpf.h"
-#include "vm_tools/port_listener/common.h"
+#include <linux/vm_sockets.h> // Needs to come after sys/socket.h
+
+#include <memory>
+#include <unordered_map>
+
+#include "common.h"
+#include "listen_tracker.skel.h"
 
 typedef std::unordered_map<int, int> port_usage_map;
 
@@ -40,158 +34,135 @@
 namespace {
 
 int HandleEvent(void* ctx, void* const data, size_t size) {
-  port_usage_map* map = reinterpret_cast<port_usage_map*>(ctx);
-  const struct event* ev = (struct event*)data;
+    port_usage_map* map = reinterpret_cast<port_usage_map*>(ctx);
+    const struct event* ev = (struct event*)data;
 
-  switch (ev->state) {
-    case kPortListenerUp:
-      (*map)[ev->port]++;
-      break;
+    switch (ev->state) {
+        case kPortListenerUp:
+            (*map)[ev->port]++;
+            break;
 
-    case kPortListenerDown:
-      if ((*map)[ev->port] > 0) {
-        (*map)[ev->port]--;
-      } else {
-        LOG(INFO) << "Received down event while port count was 0; ignoring";
-      }
+        case kPortListenerDown:
+            if ((*map)[ev->port] > 0) {
+                (*map)[ev->port]--;
+            } else {
+                LOG(INFO) << "Received down event while port count was 0; ignoring";
+            }
 
-      break;
+            break;
 
-    default:
-      LOG(ERROR) << "Unknown event state " << ev->state;
-  }
+        default:
+            LOG(ERROR) << "Unknown event state " << ev->state;
+    }
 
-  LOG(INFO) << "Listen event: port=" << ev->port << " state=" << ev->state;
+    LOG(INFO) << "Listen event: port=" << ev->port << " state=" << ev->state;
 
-  return 0;
+    return 0;
 }
 
-typedef std::unique_ptr<struct ring_buffer, decltype(&ring_buffer__free)>
-    ring_buffer_ptr;
-typedef std::unique_ptr<listen_tracker_ebpf,
-                        decltype(&listen_tracker_ebpf__destroy)>
-    listen_tracker_ptr;
+typedef std::unique_ptr<struct ring_buffer, decltype(&ring_buffer__free)> ring_buffer_ptr;
+typedef std::unique_ptr<listen_tracker_ebpf, decltype(&listen_tracker_ebpf__destroy)>
+        listen_tracker_ptr;
 
 // BPFProgram tracks the state and resources of the listen_tracker BPF program.
 class BPFProgram {
- public:
-  // Default movable but not copyable.
-  BPFProgram(BPFProgram&& other) = default;
-  BPFProgram(const BPFProgram& other) = delete;
-  BPFProgram& operator=(BPFProgram&& other) = default;
-  BPFProgram& operator=(const BPFProgram& other) = delete;
+public:
+    // Default movable but not copyable.
+    BPFProgram(BPFProgram&& other) = default;
+    BPFProgram(const BPFProgram& other) = delete;
+    BPFProgram& operator=(BPFProgram&& other) = default;
+    BPFProgram& operator=(const BPFProgram& other) = delete;
 
-  // Load loads the listen_tracker BPF program and prepares it for polling. On
-  // error nullptr is returned.
-  static std::unique_ptr<BPFProgram> Load() {
-    auto* skel = listen_tracker_ebpf__open();
-    if (!skel) {
-      PLOG(ERROR) << "Failed to open listen_tracker BPF skeleton";
-      return nullptr;
-    }
-    listen_tracker_ptr skeleton(skel, listen_tracker_ebpf__destroy);
+    // Load loads the listen_tracker BPF program and prepares it for polling. On
+    // error nullptr is returned.
+    static std::unique_ptr<BPFProgram> Load() {
+        auto* skel = listen_tracker_ebpf__open();
+        if (!skel) {
+            PLOG(ERROR) << "Failed to open listen_tracker BPF skeleton";
+            return nullptr;
+        }
+        listen_tracker_ptr skeleton(skel, listen_tracker_ebpf__destroy);
 
-    int err = listen_tracker_ebpf__load(skeleton.get());
-    if (err) {
-      PLOG(ERROR) << "Failed to load listen_tracker BPF program";
-      return nullptr;
+        int err = listen_tracker_ebpf__load(skeleton.get());
+        if (err) {
+            PLOG(ERROR) << "Failed to load listen_tracker BPF program";
+            return nullptr;
+        }
+
+        auto map = std::make_unique<port_usage_map>();
+        auto* rb = ring_buffer__new(bpf_map__fd(skel->maps.events), HandleEvent, map.get(), NULL);
+        if (!rb) {
+            PLOG(ERROR) << "Failed to open ring buffer for listen_tracker";
+            return nullptr;
+        }
+        ring_buffer_ptr ringbuf(rb, ring_buffer__free);
+
+        err = listen_tracker_ebpf__attach(skeleton.get());
+        if (err) {
+            PLOG(ERROR) << "Failed to attach listen_tracker";
+            return nullptr;
+        }
+
+        return std::unique_ptr<BPFProgram>(
+                new BPFProgram(std::move(skeleton), std::move(ringbuf), std::move(map)));
     }
 
-    auto map = std::make_unique<port_usage_map>();
-    auto* rb = ring_buffer__new(bpf_map__fd(skel->maps.events), HandleEvent,
-                                map.get(), NULL);
-    if (!rb) {
-      PLOG(ERROR) << "Failed to open ring buffer for listen_tracker";
-      return nullptr;
-    }
-    ring_buffer_ptr ringbuf(rb, ring_buffer__free);
+    // Poll waits for the listen_tracker BPF program to post a new event to the
+    // ring buffer. BPFProgram handles integrating this new event into the
+    // port_usage map and callers should consult port_usage() after Poll returns
+    // for the latest data.
+    const bool Poll() {
+        int err = ring_buffer__poll(rb_.get(), -1);
+        if (err < 0) {
+            LOG(ERROR) << "Error polling ring buffer ret=" << err;
+            return false;
+        }
 
-    err = listen_tracker_ebpf__attach(skeleton.get());
-    if (err) {
-      PLOG(ERROR) << "Failed to attach listen_tracker";
-      return nullptr;
+        return true;
     }
 
-    return base::WrapUnique(new BPFProgram(std::move(skeleton),
-                                           std::move(ringbuf), std::move(map)));
-  }
+    const port_usage_map& port_usage() { return *port_usage_; }
 
-  // Poll waits for the listen_tracker BPF program to post a new event to the
-  // ring buffer. BPFProgram handles integrating this new event into the
-  // port_usage map and callers should consult port_usage() after Poll returns
-  // for the latest data.
-  const bool Poll() {
-    int err = ring_buffer__poll(rb_.get(), -1);
-    if (err < 0) {
-      LOG(ERROR) << "Error polling ring buffer ret=" << err;
-      return false;
-    }
+private:
+    BPFProgram(listen_tracker_ptr&& skeleton, ring_buffer_ptr&& rb,
+               std::unique_ptr<port_usage_map>&& port_usage)
+          : skeleton_(std::move(skeleton)),
+            rb_(std::move(rb)),
+            port_usage_(std::move(port_usage)) {}
 
-    return true;
-  }
-
-  const port_usage_map& port_usage() { return *port_usage_; }
-
- private:
-  BPFProgram(listen_tracker_ptr&& skeleton,
-             ring_buffer_ptr&& rb,
-             std::unique_ptr<port_usage_map>&& port_usage)
-      : skeleton_(std::move(skeleton)),
-        rb_(std::move(rb)),
-        port_usage_(std::move(port_usage)) {}
-
-  listen_tracker_ptr skeleton_;
-  ring_buffer_ptr rb_;
-  std::unique_ptr<port_usage_map> port_usage_;
+    listen_tracker_ptr skeleton_;
+    ring_buffer_ptr rb_;
+    std::unique_ptr<port_usage_map> port_usage_;
 };
 
-}  // namespace
-}  // namespace port_listener
+} // namespace
+} // namespace port_listener
 
 int main(int argc, char** argv) {
-  logging::InitLogging(logging::LoggingSettings());
-  libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+    google::InitGoogleLogging(argv[0]);
+    libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
 
-  // Load our BPF program.
-  auto program = port_listener::BPFProgram::Load();
-  if (program == nullptr) {
-    LOG(ERROR) << "Failed to load BPF program";
-    return EXIT_FAILURE;
-  }
-
-  // Connect back to TremplinListener
-  vm_tools::tremplin::TremplinListener::Stub tremplin_listener(
-      grpc::CreateChannel(base::StringPrintf("vsock:%u:%u", VMADDR_CID_HOST,
-                                             vm_tools::kTremplinListenerPort),
-                          grpc::InsecureChannelCredentials()));
-
-  // main loop: poll for listen updates, when an update comes send an rpc to
-  // tremplin listener letting it know.
-  for (;;) {
-    if (!program->Poll()) {
-      LOG(ERROR) << "Failure while polling BPF program";
-      return EXIT_FAILURE;
-    }
-    // port_usage will be updated with the latest usage data
-
-    vm_tools::tremplin::ListeningPortInfo_ContainerPortInfo cpi;
-    for (auto it : program->port_usage()) {
-      if (it.second <= 0) {
-        continue;
-      }
-      cpi.add_listening_tcp4_ports(it.first);
+    // Load our BPF program.
+    auto program = port_listener::BPFProgram::Load();
+    if (program == nullptr) {
+        LOG(ERROR) << "Failed to load BPF program";
+        return EXIT_FAILURE;
     }
 
-    vm_tools::tremplin::ListeningPortInfo lpi;
-    (*lpi.mutable_container_ports())["penguin"] = cpi;
+    // main loop: poll for listen updates
+    for (;;) {
+        if (!program->Poll()) {
+            LOG(ERROR) << "Failure while polling BPF program";
+            return EXIT_FAILURE;
+        }
+        // port_usage will be updated with the latest usage data
 
-    grpc::ClientContext ctx;
-    vm_tools::tremplin::EmptyMessage empty;
-    grpc::Status status =
-        tremplin_listener.UpdateListeningPorts(&ctx, lpi, &empty);
-    if (!status.ok()) {
-      LOG(WARNING) << "Failed to notify tremplin of new listening ports: "
-                   << status.error_message();
+        for (auto it : program->port_usage()) {
+            if (it.second <= 0) {
+                continue;
+            }
+            // TODO(b/340126051): Add listening TCP4 ports.
+        }
+        // TODO(b/340126051): Notify port information to the guest agent.
     }
-  }
 }