Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.img
*.qcow2
209 changes: 205 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,49 @@ name: Build YANET
on:
push:
branches: ["main"]
paths: ["**.h", "**.c", "**/meson.build", "**.go", "go.mod", "go.sum"]
paths:
- "**.h"
- "**.c"
- "**/meson.build"
- "**.go"
- "go.mod"
- "go.sum"
- "Makefile"
pull_request:
branches: ["main"]
paths: ["**.h", "**.c", "**/meson.build", "**.go", "go.mod", "go.sum"]
paths:
- "**.h"
- "**.c"
- "**/meson.build"
- "**.go"
- "go.mod"
- "go.sum"
- "Makefile"

jobs:
build:
runs-on: ubuntu-24.04
env:
cache_name: build-and-test

steps:
steps:
- name: update apt (act hack)
if: ${{ env.ACT }}
run: |
apt-get update

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
- name: Cache rust
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- uses: awalsh128/cache-apt-pkgs-action@latest
with:
packages: meson clang python3-pyelftools libnuma-dev libpcap-dev git protobuf-compiler
Expand Down Expand Up @@ -66,7 +97,16 @@ jobs:
- name: Build YANET (dataplane -> modules -> controlplane)
run: |
meson setup build -Dbuildtype=debug
meson compile -C build
make dataplane cli

- name: Upload YANET binaries
uses: actions/upload-artifact@v4
with:
name: yanet2-binaries
path: |
build/dataplane/yanet-dataplane
build/controlplane/yanet-controlplane
target/release/yanet-cli*

- name: Build and run tests
run: |
Expand Down Expand Up @@ -95,3 +135,164 @@ jobs:
- name: Check code style violation
if: steps.linter.outputs.clang-tidy-checks-failed > 0
run: exit 1

functional-tests:
name: Run Functional Tests
runs-on: ubuntu-24.04
timeout-minutes: 150
needs: build

steps:
- uses: actions/checkout@v4
with:
submodules: true

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.24.x'
cache: true

- name: update apt (act hack)
if: ${{ env.ACT }}
run: |
apt-get update
- uses: awalsh128/cache-apt-pkgs-action@latest
with:
packages: qemu-system-x86 qemu-utils genisoimage cloud-image-utils wget curl jq
version: 1.1

- name: Configure system for QEMU
run: |
# Enable KVM access if available
if [ -e /dev/kvm ]; then
echo "KVM is available, configuring KVM access"
sudo usermod -aG kvm $USER || true
sudo chmod 666 /dev/kvm || true
else
echo "KVM is not available, will use TCG emulation"
fi

# Configure 9P filesystem support
sudo modprobe 9p || true
sudo modprobe 9pnet_virtio || true

# Check QEMU capabilities
qemu-system-x86_64 --version

- name: Cache Ubuntu cloud image
uses: actions/cache@v4
with:
path: tests/functional/ubuntu-24.04-minimal-cloudimg-amd64.img
key: ${{ runner.os }}-ubuntu-image-${{ hashFiles('tests/functional/Makefile') }}
restore-keys: |
${{ runner.os }}-ubuntu-image-

- name: Cache QEMU image
uses: actions/cache@v4
with:
path: |
tests/functional/yanet-test.qcow2
tests/functional/*.iso
key: ${{ runner.os }}-qemu-image-${{ hashFiles('tests/functional/Makefile') }}-${{ hashFiles('tests/functional/cloud-init-user-data.yaml') }}
restore-keys: |
${{ runner.os }}-qemu-image-

- name: Download YANET binaries from build job
uses: actions/download-artifact@v4
with:
name: yanet2-binaries
path: ./

- name: Display structure of downloaded files
run: |
echo "=== Downloaded files structure ==="
ls -la ./
echo "=== Build directory ==="
ls -la build/ || echo "Build directory not found"
echo "=== Target directory ==="
ls -la target/ || echo "Target directory not found"

# Ensure directories exist
mkdir -p build/dataplane build/controlplane
mkdir -p target/release

# Move binaries to correct locations if they were downloaded to root
if [ -f "./yanet-dataplane" ]; then
mv ./yanet-dataplane build/dataplane/
fi
if [ -f "./yanet-controlplane" ]; then
mv ./yanet-controlplane build/controlplane/
fi
if [ -f "./yanet-cli-nat64" ]; then
mv ./yanet-cli-* target/release/
fi

# Make binaries executable
chmod +x build/dataplane/yanet-dataplane || true
chmod +x build/controlplane/yanet-controlplane || true
chmod +x target/release/yanet-cli* || true

- name: Prepare test environment
working-directory: tests/functional
run: |
make check-deps

echo "=== Starting QEMU VM preparation ==="

# Run with timeout and monitoring
timeout 7200 make prepare-vm &
QEMU_PID=$!

# Monitor QEMU progress
for i in {1..120}; do
echo "=== QEMU status check $i/120 ==="
ps aux | grep qemu | grep -v grep || echo "QEMU process not found"

if [ -f qemu_debug.log ]; then
echo "=== QEMU log size: $(wc -l < qemu_debug.log) lines ==="
echo "=== Last 10 lines of QEMU log ==="
tail -10 qemu_debug.log
fi

sleep 60

# Check if QEMU is still running
if ! kill -0 $QEMU_PID 2>/dev/null; then
echo "QEMU process finished"
break
fi
done

# Wait for QEMU to finish
wait $QEMU_PID
QEMU_EXIT_CODE=$?

echo "=== QEMU exit code: $QEMU_EXIT_CODE ==="

if [ -f qemu_debug.log ]; then
echo "=== Final QEMU log (last 50 lines) ==="
tail -50 qemu_debug.log
fi

if [ $QEMU_EXIT_CODE -ne 0 ]; then
echo "QEMU preparation failed with exit code $QEMU_EXIT_CODE"
exit $QEMU_EXIT_CODE
fi

timeout-minutes: 130

- name: Run functional tests
working-directory: tests/functional
run: |
export YANET_TEST_DEBUG=1
make test
timeout-minutes: 35

- name: Upload functional test logs
uses: actions/upload-artifact@v4
if: always()
with:
name: functional-test-logs
path: |
tests/functional/test.log
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,5 @@ default.profraw
# Application launch artifacts
stat.log
.gdb_history
/tests/functional/ubuntu-24.04-minimal-cloudimg-amd64.img
/tests/functional/yanet-test.qcow2
10 changes: 9 additions & 1 deletion Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ setup COVERAGE_MODE="false":
test: build
@meson test -C build --print-errorlogs

# Run functional tests
test-functional: build
@echo "Running functional tests..."
@cd tests/functional && make test

# Run all tests (unit + functional)
test-all: test test-functional

# Clean coverage data
# clean *.gcno file manually after remove c file
covclean:
Expand Down Expand Up @@ -123,7 +131,7 @@ dcoverage:
dcontrolplane:
@just _docker_run -q "make controlplane"

# Build controlplane in Docker
# Build CLI in Docker
dcli:
@just _docker_run -q "make cli"

Expand Down
8 changes: 6 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: all dataplane test cli cli-install fuzz clean $(foreach module,$(MODULES),cli/$(module) cli-install/$(module))
.PHONY: all dataplane test test-functional cli cli-install fuzz clean $(foreach module,$(MODULES),cli/$(module) cli-install/$(module))

# Define the list of modules to avoid repetition
MODULES := decap dscp route forward nat64
Expand Down Expand Up @@ -29,9 +29,13 @@ cli-clean/%:
$(MAKE) -C modules/$*/cli clean

test: dataplane
go test ./...
go test $$(go list ./... | grep -v 'tests/functional')
meson test -C build

test-functional:
@echo "Running functional tests..."
cd tests/functional && $(MAKE) test

fuzz:
env CC=clang CXX=clang++ meson setup -Dfuzzing=enabled buildfuzz
env CC=clang CXX=clang++ meson compile -C buildfuzz
Expand Down
5 changes: 5 additions & 0 deletions api/agent.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#pragma once

// FIXME: double declare
#define CP_DEVICE_NAME_LEN 80

#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
Expand Down Expand Up @@ -248,12 +251,14 @@ struct cp_device_pipeline_info {

struct cp_device_info {
uint64_t pipeline_count;
char name[CP_DEVICE_NAME_LEN];
struct cp_device_pipeline_info pipelines[];
};

struct cp_device_list_info {
uint64_t gen;
uint64_t device_count;

struct cp_device_info *devices[];
};

Expand Down
2 changes: 2 additions & 0 deletions controlplane/ffi/shm.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ type DevicePipelineInfo struct {
// DeviceInfo represents information about a device.
type DeviceInfo struct {
DeviceID uint16
Name string
Pipelines []DevicePipelineInfo
}

Expand Down Expand Up @@ -310,6 +311,7 @@ func (m *DPConfig) Devices() []DeviceInfo {

out[idx] = DeviceInfo{
DeviceID: uint16(idx),
Name: C.GoString(&deviceInfo.name[0]),
Pipelines: pipelines,
}
}
Expand Down
2 changes: 2 additions & 0 deletions dataplane/dataplane.c
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,8 @@ dataplane_init(

instance->dp_config->dp_topology.device_count =
config->device_count;
instance->dp_config->instance_idx = instance_idx;
instance->dp_config->instance_count = dataplane->instance_count;

// FIXME: load modules into dp memory
rc = dataplane_load_module(
Expand Down
8 changes: 8 additions & 0 deletions docs/act.org
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,12 @@ From the repository root, run:
act --container-architecture linux/amd64 --artifact-server-path ./artifacts
#+end_src

or

#+begin_src shell
act --container-architecture linux/amd64 --artifact-server-path ./artifacts -j build-deb
#+end_src

for run only =build-deb= job.

Note: --container-architecture linux/amd64 is usually only needed on macOS.
5 changes: 4 additions & 1 deletion lib/controlplane/agent/agent.c
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,7 @@ yanet_build_device_info(struct cp_device *device) {
memset(device_info, 0, device_info_size);

device_info->pipeline_count = pipeline_count;
strtcpy(device_info->name, device->name, CP_DEVICE_NAME_LEN);
prev_pipeline_id = -1;
pipeline_count = 0;
for (uint64_t link_idx = 0; link_idx < device->pipeline_map_size;
Expand Down Expand Up @@ -648,7 +649,9 @@ yanet_get_cp_device_list_info(struct dp_config *dp_config) {
goto unlock;
}

device_list_info->devices[idx] = device_info;
device_list_info->devices[device_list_info->device_count] =
device_info;
device_list_info->device_count++;
}

unlock:
Expand Down
3 changes: 3 additions & 0 deletions modules/nat64/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,9 @@ pub fn print_tree(configs: Vec<ShowConfigResponse>) -> Result<(), Box<dyn Error>
tree.add_empty_child(format!("IPv6: {}", mtu.ipv6_mtu));
tree.end_child();
}

tree.add_empty_child(format!("DropUnknownPrefix: {}", config.drop_unknown_prefix));
tree.add_empty_child(format!("DropUnknownMapping: {}", config.drop_unknown_mapping));
}

tree.end_child();
Expand Down
2 changes: 2 additions & 0 deletions modules/nat64/controlplane/nat64pb/nat64.proto
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ message Config {
repeated Prefix prefixes = 1;
repeated Mapping mappings = 2;
MTUConfig mtu = 3;
bool drop_unknown_prefix = 4; // Drop packets with unknown prefix
bool drop_unknown_mapping = 5; // Drop packets with unknown mapping
}

// ShowConfigResponse contains the current configuration
Expand Down
2 changes: 2 additions & 0 deletions modules/nat64/controlplane/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ func (s *NAT64Service) ShowConfig(ctx context.Context, req *nat64pb.ShowConfigRe
Ipv4Mtu: config.MTU.IPv4MTU,
Ipv6Mtu: config.MTU.IPv6MTU,
},
DropUnknownPrefix: config.DropUnknownPrefix,
DropUnknownMapping: config.DropUnknownMapping,
}

for _, prefix := range config.Prefixes {
Expand Down
Loading
Loading