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
10 changes: 5 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ See [ARCHITECTURE.md](ARCHITECTURE.md) for a full architecture reference includi

## Purpose & Architecture

Galactic is the SRv6 data plane for multi-cloud VPC networking. It consists of a DaemonSet agent (`internal/agent/srv6/`) that manages kernel SRv6 routes and VRFs per node, and a CNI plugin (`internal/cni/`) that registers container endpoints with the agent via gRPC. VPC and VPCAttachment CRD management lives in a separate operator project; Galactic receives pre-populated identifiers through the CNI config and acts on them. BGP is used as the control plane for distributing SRv6 routes between agents.
Galactic is the SRv6 data plane for multi-cloud VPC networking. It consists of a DaemonSet agent (`internal/agent/`) that manages kernel SRv6 routes and VRFs per node, and a CNI plugin (`internal/cni/`) that wires containers into VPC networks. VPC and VPCAttachment CRD management lives in a separate operator project; Galactic receives pre-populated identifiers through the CNI config and acts on them. BGP is used as the control plane for distributing SRv6 routes between agents.

**Data flow:** CNI invoked with pre-populated VPC/VPCAttachment identifiers → gRPC registers endpoint with agent → agent manages SRv6 ingress routes locally → BGP distributes SRv6 routes between agents.

Expand All @@ -20,7 +20,7 @@ Galactic is the SRv6 data plane for multi-cloud VPC networking. It consists of a

- **Go 1.26** — agent and CNI plugin
- **Multus CNI** — multi-network for pods; NAD generation is handled by the external operator
- **gRPC + protobuf** — CNI-to-agent local communication (`pkg/proto/local/`)
- **gRPC + protobuf** — CNI-to-agent local communication
- **SRv6 + netlink** — kernel-level routing; `github.com/vishvananda/netlink`
- **BGP** — control plane for SRv6 route distribution between agents (in progress)

Expand Down Expand Up @@ -54,6 +54,6 @@ Summary:

1. Run `task build` to verify toolchain; run `task test` to confirm unit tests pass.
2. Read `internal/cni/cni.go` (cmdAdd/cmdDel) to understand the container attach path.
3. Read `internal/agent/srv6/srv6.go` to understand the agent entry point and how it manages SRv6 routes and VRFs.
4. Read `pkg/proto/local/local.go` to understand the gRPC interface between the CNI and the agent.
5. Explore `pkg/common/` for shared utilities (VRF management, sysctl helpers, CNI types).
3. Read `internal/plumbing/intf/intf.go` to understand SRv6 endpoint encoding, interface naming, and base62↔hex conversion.
4. Read `internal/plumbing/srv6/srv6.go` to understand kernel SRv6 ingress route management.
5. Explore `internal/plumbing/` for shared kernel and network primitives (VRF, sysctl, interface naming, SRv6).
26 changes: 12 additions & 14 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,17 @@ galactic/
│ └── galactic-agent/ # Agent binary
├── internal/
│ ├── agent/ # Agent run loop; wires GoBGP, health, metrics, bootstrap
│ │ └── srv6/ # Kernel SRv6 ingress route add/del (END.DT46)
│ ├── bootstrap/ # BGPProvider CR lifecycle (create on start, delete on stop)
│ ├── cni/ # CNI cmdAdd / cmdDel
│ │ ├── bgp/ # L3VPN path injection into local GoBGP
│ │ ├── route/ # Host-side static routes via netlink
│ │ └── veth/ # veth pair management
│ ├── gobgp/ # Embedded GoBGP server lifecycle
── metrics/ # Prometheus metrics (galactic_agent_*)
── pkg/common/
│ ├── cni/ # Shared CNI config types
│ ├── sysctl/ # Interface sysctl helpers
│ ├── util/ # SRv6 encoding, interface naming, base62↔hex
│ └── vrf/ # Linux VRF create/delete/lookup
── metrics/ # Prometheus metrics (galactic_agent_*)
│ └── plumbing/ # Low-level kernel and network primitives
├── intf/ # Interface naming, base62↔hex encoding, SRv6 endpoint encode/decode
├── srv6/ # SRv6 ingress route add/del (END.DT46)
├── sysctl/ # Interface sysctl helpers
└── vrf/ # Linux VRF create/delete/lookup
├── deploy/
│ ├── galactic-agent/ # Kustomize: DaemonSet, RBAC, ServiceAccount
│ └── containerlab/ # ContainerLab lab topology and scripts
Expand All @@ -78,15 +76,15 @@ See [docs/agent-startup.md](docs/agent-startup.md) for the agent startup sequenc

| Component | Binary | Role |
|-----------|--------|------|
| `internal/agent` | `galactic-agent` | Run loop; wires all agent subsystems |
| `internal/agent/srv6` | `galactic-agent` | Kernel SRv6 route add/del |
| `internal/agent` | `galactic-agent` | Run loop; wires GoBGP, health, metrics, bootstrap |
| `internal/bootstrap` | `galactic-agent` | BGPProvider CR lifecycle |
| `internal/gobgp` | `galactic-agent` | Embedded GoBGP server |
| `internal/metrics` | `galactic-agent` | Prometheus metrics |
| `internal/cni` | `galactic-cni` | CNI cmdAdd / cmdDel |
| `internal/cni/bgp` | `galactic-cni` | L3VPN path injection into GoBGP |
| `pkg/common/vrf` | both | Linux VRF management |
| `pkg/common/util` | both | SRv6 encoding, interface naming |
| `internal/plumbing/intf` | both | Interface naming, base62↔hex encoding, SRv6 endpoint encode/decode |
| `internal/plumbing/srv6` | both | SRv6 ingress route add/del (END.DT46) |
| `internal/plumbing/vrf` | both | Linux VRF create/delete/lookup |
| `internal/plumbing/sysctl` | both | Interface sysctl helpers |

---

Expand All @@ -102,4 +100,4 @@ See [docs/agent-startup.md](docs/agent-startup.md) for the agent startup sequenc
## Known Constraints

- **GoBGP RIB is ephemeral.** All BGP state is in-process memory. On restart, sessions and paths must be re-established. The cosmos operator is responsible for re-applying config.
- **No kernel-path unit tests.** `internal/cni`, `internal/agent/srv6`, and `pkg/common/vrf` require `CAP_NET_ADMIN` and a real kernel. Coverage comes from the e2e suite (`task ci:e2etest`), which only runs on `main` and release tags.
- **No kernel-path unit tests.** `internal/cni`, `internal/plumbing/srv6`, and `internal/plumbing/vrf` require `CAP_NET_ADMIN` and a real kernel. `internal/plumbing/intf` is fully unit-testable (pure functions only). Coverage comes from the e2e suite (`task ci:e2etest`), which only runs on `main` and release tags.
14 changes: 6 additions & 8 deletions CONVENTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ This document defines the coding standards, naming rules, error handling pattern
- Module: `go.datum.net/galactic`
- `cmd/galactic-cni/main.go` — CNI plugin entry point; calls `cni.RunPlugin()` directly
- `cmd/galactic-agent/main.go` — agent entry point; parses flags and calls `agent.Run()`
- `pkg/common/` — utilities shared between agent and CNI
- `pkg/proto/local/` — gRPC / protobuf generated files plus hand-written convenience wrapper for CNI-to-agent communication
- `internal/agent/` — agent entry point and gRPC server; `srv6/` subdirectory owns kernel SRv6 route and VRF management
- `internal/plumbing/` — low-level kernel and network primitives shared between agent and CNI (`intf`, `srv6`, `sysctl`, `vrf`)
- `internal/agent/` — agent entry point and gRPC server
- `internal/cni/` — CNI plugin (cmdAdd / cmdDel implementation)
- `internal/cmd/version/` — ldflags variables (Version, GitCommit, etc.) set at build time
- `internal/gobgp/` — embedded GoBGP server lifecycle
Expand All @@ -39,7 +38,7 @@ import (

"google.golang.org/grpc"

"go.datum.net/galactic/pkg/proto/local"
"go.datum.net/galactic/internal/plumbing/intf"
)
```

Expand Down Expand Up @@ -87,7 +86,7 @@ const MaxVPCAttachment uint64 = 0xFFFF

### Code generation

Generated protobuf files (`*.pb.go`, `*_grpc.pb.go` in `pkg/proto/local/`) must never be hand-edited. Regenerate them using the `protoc` toolchain when `.proto` files change. Generated files are committed to version control.
Generated protobuf files (`*.pb.go`, `*_grpc.pb.go`) must never be hand-edited. Regenerate them using the `protoc` toolchain when `.proto` files change. Generated files are committed to version control.

### Linting

Expand Down Expand Up @@ -135,15 +134,14 @@ for _, tt := range tests {
### What not to test

- Do not write tests for generated code (`*.pb.go`, `*_grpc.pb.go`).
- Agent and CNI kernel-path code (`internal/agent/srv6/`, `internal/cni/`) currently has no unit coverage; new code in those paths should prefer integration/e2e over fragile mock-heavy unit tests.
- Agent and CNI kernel-path code (`internal/plumbing/srv6/`, `internal/cni/`) currently has no unit coverage; new code in those paths should prefer integration/e2e over fragile mock-heavy unit tests.

---

## Protobuf / gRPC

- `.proto` files live in `pkg/proto/local/` (CNI-to-agent local gRPC).
- Generated `*.pb.go` / `*_grpc.pb.go` files must never be hand-edited.
- Each proto package has a hand-written convenience wrapper (`local.go`) that exposes a cleaner Go API over the generated types. Add helpers there rather than importing generated types directly in application code.
- Each proto package has a hand-written convenience wrapper that exposes a cleaner Go API over the generated types. Add helpers there rather than importing generated types directly in application code.

---

Expand Down
25 changes: 20 additions & 5 deletions Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,26 @@ tasks:
##

build:
desc: Build binary
desc: Build binaries
deps: [fmt, vet]
vars:
VERSION:
sh: git describe --tags --always --dirty 2>/dev/null || echo "dev"
GIT_COMMIT:
sh: git rev-parse --short HEAD
GIT_TREE_STATE:
sh: git diff --quiet && echo "clean" || echo "dirty"
BUILD_DATE:
sh: date -u +%Y-%m-%dT%H:%M:%SZ
LDFLAGS: >-
-s -w
-X go.datum.net/galactic/internal/metadata.Version={{.VERSION}}
-X go.datum.net/galactic/internal/metadata.GitCommit={{.GIT_COMMIT}}
-X go.datum.net/galactic/internal/metadata.GitTreeState={{.GIT_TREE_STATE}}
-X go.datum.net/galactic/internal/metadata.BuildDate={{.BUILD_DATE}}
cmds:
- go build -o bin/galactic-cni cmd/galactic-cni/main.go
- file bin/galactic-cni
- go build -ldflags "{{.LDFLAGS}}" -o bin/galactic-cni cmd/galactic-cni/main.go
- go build -ldflags "{{.LDFLAGS}}" -o bin/galactic-agent cmd/galactic-agent/main.go

docker-build:
desc: Build container image
Expand Down Expand Up @@ -156,8 +171,8 @@ tasks:
run: once
cmds:
- |
if find . -name "*.yml" -not -path "./.git/*" | grep -q .; then
find . -name "*.yml" -not -path "./.git/*"
if find . -name "*.yml" -not -path "./.git/*" -not -path "./deploy/containerlab/clab-gvpc/*" | grep -q .; then
find . -name "*.yml" -not -path "./.git/*" -not -path "./deploy/containerlab/clab-gvpc/*"
echo "ERROR: .yml files found; rename to .yaml"
exit 1
fi
Expand Down
7 changes: 5 additions & 2 deletions cmd/galactic-agent/main.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
// Command galactic-agent is the node-local execution agent for Galactic.
// Copyright 2025 Datum Cloud, Inc.
//
// SPDX-License-Identifier: AGPL-3.0-or-later

package main

import (
Expand All @@ -23,7 +26,7 @@ func newRootCommand() *cobra.Command {

cmd := &cobra.Command{
Use: "galactic-agent",
Short: "Node-local execution agent for Galactic VPC networking",
Short: "BGP Provider implementation for Cosmos",
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
return agent.Run(cmd.Context(), *opts)
Expand Down
9 changes: 4 additions & 5 deletions containers/galactic/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ RUN go mod download

# Copy the go source
COPY cmd/ cmd/
COPY pkg/ pkg/
COPY internal/ internal/

# Build
Expand All @@ -27,10 +26,10 @@ COPY internal/ internal/
# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build \
-ldflags "-s -w \
-X go.datum.net/galactic/internal/cmd/version.Version=${VERSION} \
-X go.datum.net/galactic/internal/cmd/version.GitCommit=${GIT_COMMIT} \
-X go.datum.net/galactic/internal/cmd/version.GitTreeState=${GIT_TREE_STATE} \
-X go.datum.net/galactic/internal/cmd/version.BuildDate=${BUILD_DATE}" \
-X go.datum.net/galactic/internal/metadata.Version=${VERSION} \
-X go.datum.net/galactic/internal/metadata.GitCommit=${GIT_COMMIT} \
-X go.datum.net/galactic/internal/metadata.GitTreeState=${GIT_TREE_STATE} \
-X go.datum.net/galactic/internal/metadata.BuildDate=${BUILD_DATE}" \
-o galactic-cni cmd/galactic-cni/main.go

# Use distroless as minimal base image to package the binary
Expand Down
58 changes: 0 additions & 58 deletions internal/agent/srv6/routeingress/routeingress.go

This file was deleted.

62 changes: 0 additions & 62 deletions internal/agent/srv6/srv6.go

This file was deleted.

20 changes: 0 additions & 20 deletions internal/cmd/version/version.go

This file was deleted.

Loading
Loading