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: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Galactic is the SRv6 data plane for multi-cloud VPC networking. It consists of a
**Non-obvious decisions:**
- VPC identifiers are 48-bit hex; VPCAttachment identifiers are 16-bit hex. These are embedded into IPv6 SRv6 endpoint addresses for deterministic route lookups. Both are supplied by an external operator via the CNI config.
- Identifiers are also Base62-encoded for interface naming (VRF: `vrfX-Y`, veth host side: `galX-Y`) to keep kernel interface name length within limits.
- The binary auto-detects CNI mode via the `CNI_COMMAND` env var; otherwise runs as a Cobra CLI with `agent`, `cni`, and `version` subcommands.
- `galactic-cni` is a pure CNI plugin; `main()` calls `cni.RunPlugin()` directly with no CLI layer. `galactic-agent` uses flag parsing for its configuration flags.
- The Kubernetes operator, VPC/VPCAttachment CRDs, and webhook code have been removed from this repository. They live in a separate companion operator project.

## Tech Stack
Expand Down
8 changes: 4 additions & 4 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ enabling automatic cross-node path import without explicit RT configuration.
```
galactic/
├── cmd/
│ ├── galactic/ # CNI binary
│ ├── galactic-cni/ # CNI binary
│ └── galactic-agent/ # Agent binary
├── internal/
│ ├── agent/ # Agent run loop; wires GoBGP, health, metrics, bootstrap
Expand Down Expand Up @@ -83,8 +83,8 @@ See [docs/agent-startup.md](docs/agent-startup.md) for the agent startup sequenc
| `internal/bootstrap` | `galactic-agent` | BGPProvider CR lifecycle |
| `internal/gobgp` | `galactic-agent` | Embedded GoBGP server |
| `internal/metrics` | `galactic-agent` | Prometheus metrics |
| `internal/cni` | `galactic` | CNI cmdAdd / cmdDel |
| `internal/cni/bgp` | `galactic` | L3VPN path injection into GoBGP |
| `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 |

Expand All @@ -95,7 +95,7 @@ See [docs/agent-startup.md](docs/agent-startup.md) for the agent startup sequenc
- **Identifiers in the SID.** VPC (48-bit) and VPCAttachment (16-bit) identifiers are packed into the low 64 bits of the SRv6 SID, making forwarding state fully self-describing without a lookup table.
- **Base62 interface names.** Kernel interface names are Base62-encoded to stay within the 15-character limit (`vrfX-Y`, `galX-Y`). The hex form is used for BGP and SRv6; base62 for kernel interfaces.
- **GoBGP embedded, not sidecar.** GoBGP runs in-process so the agent owns its lifecycle and can gate readiness on BGP availability. Peer and policy config is applied by the cosmos operator via `BGPProvider` / `BGPInstance` / `BGPPeer` CRDs.
- **CNI binary auto-detects mode.** The `galactic` binary runs as both the CNI plugin (when `CNI_COMMAND` is set) and a CLI tool. This avoids shipping two separate binaries on the node.
- **CNI binary auto-detects mode.** The `galactic-cni` binary runs as both the CNI plugin (when `CNI_COMMAND` is set) and a CLI tool. This avoids shipping two separate binaries on the node.

---

Expand Down
5 changes: 3 additions & 2 deletions CONVENTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ This document defines the coding standards, naming rules, error handling pattern
### Module and package layout

- Module: `go.datum.net/galactic`
- `cmd/galactic/main.go` — binary entry point; all Cobra subcommands registered here
- `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/cni/` — CNI plugin (cmdAdd / cmdDel implementation)
- `internal/cmd/` — one sub-package per Cobra subcommand (`cni`, `version`)
- `internal/cmd/version/` — ldflags variables (Version, GitCommit, etc.) set at build time
- `internal/gobgp/` — embedded GoBGP server lifecycle
- `internal/bootstrap/` — agent startup sequencing (BGPProvider resource management)
- `internal/metrics/` — Prometheus metrics registration
Expand Down
3 changes: 1 addition & 2 deletions Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,8 @@ tasks:
desc: Build binary
deps: [fmt, vet]
cmds:
- go build -o bin/galactic-cni cmd/galactic/main.go
- go build -o bin/galactic-cni cmd/galactic-cni/main.go
- file bin/galactic-cni
- ./bin/galactic-cni version

docker-build:
desc: Build container image
Expand Down
11 changes: 11 additions & 0 deletions cmd/galactic-cni/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright 2025 Datum Cloud, Inc.
//
// SPDX-License-Identifier: AGPL-3.0-or-later

package main

import "go.datum.net/galactic/internal/cni"

func main() {
cni.RunPlugin()
}
47 changes: 0 additions & 47 deletions cmd/galactic/main.go

This file was deleted.

2 changes: 1 addition & 1 deletion containers/galactic/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build \
-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}" \
-o galactic-cni cmd/galactic/main.go
-o galactic-cni cmd/galactic-cni/main.go

# Use distroless as minimal base image to package the binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ FROM golang:1.26 AS builder
WORKDIR /src
COPY . .
RUN go mod download
RUN CGO_ENABLED=0 GOOS=linux go build -o bin/galactic-cni cmd/galactic/main.go
RUN CGO_ENABLED=0 GOOS=linux go build -o bin/galactic-cni cmd/galactic-cni/main.go

FROM kindest/node:${KINDEST_VER}

Expand Down
2 changes: 1 addition & 1 deletion deploy/containerlab/examples/nginx-vpc-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ spec:
{
"cniVersion": "0.3.1",
"name": "galactic-test",
"type": "galactic",
"type": "galactic-cni",
"vpc": "2",
"vpcattachment": "1",
"srv6_locator": "2001:db8:ff01::/48",
Expand Down
2 changes: 1 addition & 1 deletion deploy/containerlab/resources/overlay/dfw/nad.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ spec:
{
"cniVersion": "0.3.1",
"name": "galactic",
"type": "galactic",
"type": "galactic-cni",
"vpc": "1",
"vpcattachment": "1",
"srv6_locator": "2001:db8:ff01::/48",
Expand Down
2 changes: 1 addition & 1 deletion deploy/containerlab/resources/overlay/iad/nad.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ spec:
{
"cniVersion": "0.3.1",
"name": "galactic",
"type": "galactic",
"type": "galactic-cni",
"vpc": "1",
"vpcattachment": "1",
"srv6_locator": "2001:db8:ff03::/48",
Expand Down
2 changes: 1 addition & 1 deletion deploy/containerlab/resources/overlay/sjc/nad.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ spec:
{
"cniVersion": "0.3.1",
"name": "galactic",
"type": "galactic",
"type": "galactic-cni",
"vpc": "1",
"vpcattachment": "1",
"srv6_locator": "2001:db8:ff02::/48",
Expand Down
30 changes: 0 additions & 30 deletions internal/cmd/cni/cni.go

This file was deleted.

20 changes: 0 additions & 20 deletions internal/cmd/version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ package version
import (
"fmt"
"runtime"

"github.com/spf13/cobra"
)

var (
Expand All @@ -20,21 +18,3 @@ var (
GoVersion = runtime.Version()
Platform = fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)
)

func NewCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "version",
Short: "Print version information",
Long: `Print the version, git commit, build date, and platform information for this binary.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("Galactic Version: %s\n", Version)
fmt.Printf("Git Commit: %s\n", GitCommit)
fmt.Printf("Git Tree State: %s\n", GitTreeState)
fmt.Printf("Build Date: %s\n", BuildDate)
fmt.Printf("Go Version: %s\n", GoVersion)
fmt.Printf("Platform: %s\n", Platform)
},
}

return cmd
}
24 changes: 8 additions & 16 deletions internal/cni/cni.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ import (
"strings"
"time"

"github.com/spf13/cobra"

"github.com/containernetworking/cni/pkg/invoke"
"github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types"
Expand Down Expand Up @@ -65,21 +63,15 @@ type PluginConf struct {
SRv6Locator string `json:"srv6_locator"`
}

func NewCommand() *cobra.Command {
return &cobra.Command{
Use: "galactic",
Short: "Galactic CNI plugin",
Run: func(cmd *cobra.Command, args []string) {
skel.PluginMainFuncs(
skel.CNIFuncs{
Add: cmdAdd,
Del: cmdDel,
},
version.All,
fmt.Sprintf("CNI galactic plugin %s", galversion.Version),
)
func RunPlugin() {
skel.PluginMainFuncs(
skel.CNIFuncs{
Add: cmdAdd,
Del: cmdDel,
},
}
version.All,
fmt.Sprintf("CNI galactic plugin %s", galversion.Version),
)
}

func parseConf(data []byte) (*PluginConf, error) {
Expand Down
2 changes: 1 addition & 1 deletion internal/cni/cni_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func TestParseConf(t *testing.T) {
}{
{
name: "valid config",
input: `{"cniVersion":"1.0.0","name":"test","type":"galactic","vpc":"abc","vpcattachment":"def","srv6_locator":"2001:db8::/48"}`,
input: `{"cniVersion":"1.0.0","name":"test","type":"galactic-cni","vpc":"abc","vpcattachment":"def","srv6_locator":"2001:db8::/48"}`,
wantVPC: "abc",
},
{
Expand Down
35 changes: 0 additions & 35 deletions tests/e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,41 +50,6 @@ func TestMain(m *testing.M) {
os.Exit(m.Run())
}

// TestGalacticBinaryVersion runs the galactic binary with the "version"
// subcommand inside a pod and verifies the output contains the expected fields.
func TestGalacticBinaryVersion(t *testing.T) {
name := "e2e-version-check"
t.Cleanup(func() { deletePod(t, name) })
deletePod(t, name) // remove any leftover from a prior run

_, err := kubectl(
"run", name,
"--image="+image(),
"--image-pull-policy=Never",
"--restart=Never",
"--command", "--",
"/galactic-cni", "version",
)
if err != nil {
t.Fatalf("kubectl run failed: %v", err)
}

if err := waitForPodPhase(t, name, "Succeeded", podReadyTimeout); err != nil {
t.Fatalf("pod did not succeed: %v", err)
}

logs, err := kubectl("logs", name)
if err != nil {
t.Fatalf("kubectl logs failed: %v", err)
}

for _, field := range []string{"Galactic Version:", "Git Commit:", "Go Version:", "Platform:"} {
if !strings.Contains(logs, field) {
t.Errorf("expected %q in version output, got:\n%s", field, logs)
}
}
}

// TestCNIPluginVersionReport invokes the binary with CNI_COMMAND=VERSION, which
// causes it to report the CNI spec versions it supports. The response must be
// valid JSON containing a "cniVersion" key.
Expand Down
Loading