Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ build
.DS_Store
.idea
compile_commands.json
config/
17 changes: 11 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ include_directories(${ProtobufIncludePath})

SET(VNET_SOURCE_FILES
src/common/socket_utils.cpp
src/common/tun.cpp

src/protocol/header.cpp
src/protocol/types.cpp
src/protocol/dispatch.cpp
Expand Down Expand Up @@ -72,11 +74,14 @@ add_subdirectory(src/agent)
######################## GOOGLE TEST ########################
#############################################################

include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/refs/tags/v1.17.0.zip
)
FetchContent_MakeAvailable(googletest)
find_package(GTest QUIET)
if (NOT GTest_FOUND)
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/refs/tags/v1.17.0.zip
)
FetchContent_MakeAvailable(googletest)
endif()
enable_testing()
add_subdirectory(tests)
4 changes: 3 additions & 1 deletion docker/Dockerfile.agent
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ RUN apt-get update && apt-get install -y \
cmake \
protobuf-compiler \
libprotobuf-dev \
libgtest-dev \
libgmock-dev \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app
Expand All @@ -16,7 +18,7 @@ RUN cmake -S . -B build -DCMAKE_BUILD_TYPE=Release && \
FROM ubuntu:24.04

RUN apt-get update && apt-get install -y --no-install-recommends \
libprotobuf32t64 bash \
libprotobuf32t64 bash iproute2 \
&& rm -rf /var/lib/apt/lists/*

COPY --from=builder /app/build/agent /usr/local/bin/agent
Expand Down
2 changes: 2 additions & 0 deletions docker/Dockerfile.conductor
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ RUN apt-get update && apt-get install -y \
cmake \
protobuf-compiler \
libprotobuf-dev \
libgtest-dev \
libgmock-dev \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app
Expand Down
7 changes: 6 additions & 1 deletion docker/Dockerfile.switch
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ RUN apt-get update && apt-get install -y \
cmake \
protobuf-compiler \
libprotobuf-dev \
libgtest-dev \
libgmock-dev \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app
Expand All @@ -16,9 +18,12 @@ RUN cmake -S . -B build -DCMAKE_BUILD_TYPE=Release && \
FROM ubuntu:24.04

RUN apt-get update && apt-get install -y --no-install-recommends \
libprotobuf32t64 bash \
libprotobuf32t64 bash iproute2 \
&& rm -rf /var/lib/apt/lists/*

COPY --from=builder /app/build/switch /usr/local/bin/switch
COPY docker/switch-entrypoint.sh /usr/local/bin/switch-entrypoint.sh
RUN chmod +x /usr/local/bin/switch-entrypoint.sh

ENTRYPOINT [ "/usr/local/bin/switch-entrypoint.sh" ]
CMD ["/usr/local/bin/switch"]
25 changes: 25 additions & 0 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ services:
environment:
- CONDUCTOR_IP=vnet-conductor
- CONDUCTOR_PORT=5000
- VNET_CONFIG_PATH=/etc/vnet/config.txt
volumes:
- ../config/switch1.txt:/etc/vnet/config.txt:ro
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
command: ["/usr/local/bin/switch", "switch1", "authkey1", "6000"]
healthcheck:
test: ["CMD", "bash", "-c", "timeout 1 bash -c 'echo > /dev/tcp/127.0.0.1/6000' || exit 1"]
Expand All @@ -55,6 +62,13 @@ services:
environment:
- CONDUCTOR_IP=vnet-conductor
- CONDUCTOR_PORT=5000
- VNET_CONFIG_PATH=/etc/vnet/config.txt
volumes:
- ../config/switch2.txt:/etc/vnet/config.txt:ro
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
command: ["/usr/local/bin/switch", "switch2", "authkey2", "6001"]
healthcheck:
test: ["CMD", "bash", "-c", "timeout 1 bash -c 'echo > /dev/tcp/127.0.0.1/6001' || exit 1"]
Expand All @@ -80,6 +94,13 @@ services:
environment:
- CONDUCTOR_IP=vnet-conductor
- CONDUCTOR_PORT=5000
- VNET_CONFIG_PATH=/etc/vnet/config.txt
volumes:
- ../config/switch3.txt:/etc/vnet/config.txt:ro
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
command: ["/usr/local/bin/switch", "switch3", "authkey3", "6002"]
healthcheck:
test: ["CMD", "bash", "-c", "timeout 1 bash -c 'echo > /dev/tcp/127.0.0.1/6002' || exit 1"]
Expand Down Expand Up @@ -109,6 +130,10 @@ services:
environment:
- CONDUCTOR_IP=vnet-conductor
- CONDUCTOR_PORT=5000
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
command: ["/usr/local/bin/agent", "agent1", "agentkey1"]
logging:
driver: "json-file"
Expand Down
9 changes: 9 additions & 0 deletions docker/switch-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash
set -e

if [ ! -f "${VNET_CONFIG_PATH:-/etc/vnet/config.txt}" ]; then
echo "[Switch] ERROR: config file not found or is a directory: ${VNET_CONFIG_PATH:-/etc/vnet/config.txt}"
exit 1
fi

exec "$@"
22 changes: 22 additions & 0 deletions include/common/tun.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include <string>
#include <cstdint>

/**
* @brief Open a TUN device and configure it.
*
* Creates a TUN interface with the given name, assigns the given
* IPv4 address with a /24 prefix, and brings the interface up.
*
* @param name Interface name (e.g. "vnet0"). Max 15 chars.
* @param ipv4 Virtual IPv4 address in network order.
* @param prefix_len Subnet prefix length (default 24 = /24).
* @return File descriptor for the TUN device, or -1 on failure.
*/
int tun_open(const std::string& name, uint32_t ipv4, uint8_t prefix_len = 24);

/**
* @brief Close a TUN device and bring the interface down.
*/
void tun_close(int fd, const std::string& name);
5 changes: 5 additions & 0 deletions include/vnet/protocol/dispatch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ namespace vnet::protocol {
/** Reconnection */
virtual void onAgentMRP (netqueue::socket_data data, mip::PacketAgentMRP &packet);

/** Routing */
virtual void onPrepareRouteForTarget(netqueue::socket_data data, mip::PacketPrepareRouteForTarget &packet);
virtual void onNextForTarget(netqueue::socket_data data, mip::PacketNextForTarget &packet);
virtual void onIPv4Raw(netqueue::socket_data data, mip::PacketIPv4Raw &packet);

virtual ~Dispatch() = default;
};

Expand Down
9 changes: 8 additions & 1 deletion include/vnet/protocol/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace vnet::protocol {
enum PacketType : uint16_t {
HEARTBEAT = 0,

// MIP
SWITCH_MIP,
AGENT_MIP,

Expand All @@ -16,7 +17,13 @@ namespace vnet::protocol {
AUTH_CONNECT_TO_SWITCH,
CONNECTION_ACCEPTED,

AGENT_MRP
// Reconnection
AGENT_MRP,

// Routing
PREPARE_ROUTE_FOR_TARGET,
NEXT_FOR_TARGET,
IPV4_RAW
};

PacketType ntoh_packet_type (uint_packet_t type);
Expand Down
22 changes: 21 additions & 1 deletion proto/mip.proto
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,29 @@ message PacketAuthConnectToSwitch {
fixed64 connection_token = 1;
}

message PacketConnectionAccepted {}
message PacketConnectionAccepted {
fixed32 virtual_ipv4 = 1;
}

message PacketAgentMRP {
string name = 1;
string auth_key = 2;
}

message PacketPrepareRouteForTarget {
fixed32 dest_ipv4 = 1;
}

message PacketNextForTarget {
fixed32 dest_ipv4 = 1;

// next_switch_ipv4 = 0 means the target disconnected, remove the route
fixed32 next_switch_ipv4 = 2;

uint32 next_switch_port = 3;
string next_switch_name = 4;
}

message PacketIPv4Raw {
bytes payload = 1;
}
24 changes: 21 additions & 3 deletions src/agent/setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <netinet/tcp.h>
#include <unistd.h>

#include "common/tun.h"
#include "mip.pb.h"
#include "common/config.h"
#include "common/socket_utils.h"
Expand Down Expand Up @@ -206,11 +207,25 @@ int main(int argc, char** argv) {
return 1;
}

std::cout << "[Agent] Authenticated with switch "
<< assignment.switch_name() << "!\n";
uint32_t virtual_ipv4 = ack.virtual_ipv4();
std::cout << "[Agent] Authenticated with switch " << assignment.switch_name()
<< ", virtual IP: " << ipv4_to_string(virtual_ipv4) << "\n";

// ===================================================================
// STEP 4 — Switch both fds to non-blocking, enter event loop
// STEP 4 — Open TUN device with assigned virtual IP
// ===================================================================

std::string tun_name = "vnet-" + agent_name;
int tun_fd = tun_open(tun_name, virtual_ipv4);
if (tun_fd < 0) {
std::cerr << "[Agent] Failed to open TUN device\n";
close(sw_sock);
close(cdt_sock);
return 1;
}

// ===================================================================
// STEP 5 — Switch both fds to non-blocking, enter event loop
// ===================================================================
set_nonblocking(cdt_sock);
set_nonblocking(sw_sock);
Expand All @@ -235,6 +250,8 @@ int main(int argc, char** argv) {
g_state.sw = sw_info;
queue.put_sck(sw_sock, sw_info);

queue.put_tun(tun_fd, nullptr);

std::cout << "[Agent] Entering event loop.\n";

while (g_running) {
Expand All @@ -243,6 +260,7 @@ int main(int argc, char** argv) {
}

std::cout << "[Agent] Shutting down.\n";
tun_close(tun_fd, tun_name);
google::protobuf::ShutdownProtobufLibrary();
return 0;
}
Loading
Loading