Skip to content

Commit 1193a7f

Browse files
authored
Merge pull request #118 from datum-cloud/refactor/internal-plumbing
refactor: consolidate shared primitives into internal/plumbing
2 parents abf0b97 + 18aa07c commit 1193a7f

23 files changed

Lines changed: 614 additions & 402 deletions

File tree

AGENTS.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ See [ARCHITECTURE.md](ARCHITECTURE.md) for a full architecture reference includi
66

77
## Purpose & Architecture
88

9-
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.
9+
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.
1010

1111
**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.
1212

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

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

@@ -54,6 +54,6 @@ Summary:
5454

5555
1. Run `task build` to verify toolchain; run `task test` to confirm unit tests pass.
5656
2. Read `internal/cni/cni.go` (cmdAdd/cmdDel) to understand the container attach path.
57-
3. Read `internal/agent/srv6/srv6.go` to understand the agent entry point and how it manages SRv6 routes and VRFs.
58-
4. Read `pkg/proto/local/local.go` to understand the gRPC interface between the CNI and the agent.
59-
5. Explore `pkg/common/` for shared utilities (VRF management, sysctl helpers, CNI types).
57+
3. Read `internal/plumbing/intf/intf.go` to understand SRv6 endpoint encoding, interface naming, and base62↔hex conversion.
58+
4. Read `internal/plumbing/srv6/srv6.go` to understand kernel SRv6 ingress route management.
59+
5. Explore `internal/plumbing/` for shared kernel and network primitives (VRF, sysctl, interface naming, SRv6).

ARCHITECTURE.md

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,19 +44,17 @@ galactic/
4444
│ └── galactic-agent/ # Agent binary
4545
├── internal/
4646
│ ├── agent/ # Agent run loop; wires GoBGP, health, metrics, bootstrap
47-
│ │ └── srv6/ # Kernel SRv6 ingress route add/del (END.DT46)
4847
│ ├── bootstrap/ # BGPProvider CR lifecycle (create on start, delete on stop)
4948
│ ├── cni/ # CNI cmdAdd / cmdDel
50-
│ │ ├── bgp/ # L3VPN path injection into local GoBGP
5149
│ │ ├── route/ # Host-side static routes via netlink
5250
│ │ └── veth/ # veth pair management
5351
│ ├── gobgp/ # Embedded GoBGP server lifecycle
54-
── metrics/ # Prometheus metrics (galactic_agent_*)
55-
── pkg/common/
56-
│ ├── cni/ # Shared CNI config types
57-
│ ├── sysctl/ # Interface sysctl helpers
58-
│ ├── util/ # SRv6 encoding, interface naming, base62↔hex
59-
│ └── vrf/ # Linux VRF create/delete/lookup
52+
── metrics/ # Prometheus metrics (galactic_agent_*)
53+
│ └── plumbing/ # Low-level kernel and network primitives
54+
├── intf/ # Interface naming, base62↔hex encoding, SRv6 endpoint encode/decode
55+
├── srv6/ # SRv6 ingress route add/del (END.DT46)
56+
├── sysctl/ # Interface sysctl helpers
57+
└── vrf/ # Linux VRF create/delete/lookup
6058
├── deploy/
6159
│ ├── galactic-agent/ # Kustomize: DaemonSet, RBAC, ServiceAccount
6260
│ └── containerlab/ # ContainerLab lab topology and scripts
@@ -78,15 +76,15 @@ See [docs/agent-startup.md](docs/agent-startup.md) for the agent startup sequenc
7876

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

9189
---
9290

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

104102
- **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.
105-
- **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.
103+
- **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.

CONVENTIONS.md

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@ This document defines the coding standards, naming rules, error handling pattern
1111
- Module: `go.datum.net/galactic`
1212
- `cmd/galactic-cni/main.go` — CNI plugin entry point; calls `cni.RunPlugin()` directly
1313
- `cmd/galactic-agent/main.go` — agent entry point; parses flags and calls `agent.Run()`
14-
- `pkg/common/` — utilities shared between agent and CNI
15-
- `pkg/proto/local/` — gRPC / protobuf generated files plus hand-written convenience wrapper for CNI-to-agent communication
16-
- `internal/agent/` — agent entry point and gRPC server; `srv6/` subdirectory owns kernel SRv6 route and VRF management
14+
- `internal/plumbing/` — low-level kernel and network primitives shared between agent and CNI (`intf`, `srv6`, `sysctl`, `vrf`)
15+
- `internal/agent/` — agent entry point and gRPC server
1716
- `internal/cni/` — CNI plugin (cmdAdd / cmdDel implementation)
1817
- `internal/cmd/version/` — ldflags variables (Version, GitCommit, etc.) set at build time
1918
- `internal/gobgp/` — embedded GoBGP server lifecycle
@@ -39,7 +38,7 @@ import (
3938

4039
"google.golang.org/grpc"
4140

42-
"go.datum.net/galactic/pkg/proto/local"
41+
"go.datum.net/galactic/internal/plumbing/intf"
4342
)
4443
```
4544

@@ -87,7 +86,7 @@ const MaxVPCAttachment uint64 = 0xFFFF
8786

8887
### Code generation
8988

90-
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.
89+
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.
9190

9291
### Linting
9392

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

137136
- Do not write tests for generated code (`*.pb.go`, `*_grpc.pb.go`).
138-
- 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.
137+
- 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.
139138

140139
---
141140

142141
## Protobuf / gRPC
143142

144-
- `.proto` files live in `pkg/proto/local/` (CNI-to-agent local gRPC).
145143
- Generated `*.pb.go` / `*_grpc.pb.go` files must never be hand-edited.
146-
- 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.
144+
- 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.
147145

148146
---
149147

Taskfile.yaml

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,26 @@ tasks:
7777
##
7878

7979
build:
80-
desc: Build binary
80+
desc: Build binaries
8181
deps: [fmt, vet]
82+
vars:
83+
VERSION:
84+
sh: git describe --tags --always --dirty 2>/dev/null || echo "dev"
85+
GIT_COMMIT:
86+
sh: git rev-parse --short HEAD
87+
GIT_TREE_STATE:
88+
sh: git diff --quiet && echo "clean" || echo "dirty"
89+
BUILD_DATE:
90+
sh: date -u +%Y-%m-%dT%H:%M:%SZ
91+
LDFLAGS: >-
92+
-s -w
93+
-X go.datum.net/galactic/internal/metadata.Version={{.VERSION}}
94+
-X go.datum.net/galactic/internal/metadata.GitCommit={{.GIT_COMMIT}}
95+
-X go.datum.net/galactic/internal/metadata.GitTreeState={{.GIT_TREE_STATE}}
96+
-X go.datum.net/galactic/internal/metadata.BuildDate={{.BUILD_DATE}}
8297
cmds:
83-
- go build -o bin/galactic-cni cmd/galactic-cni/main.go
84-
- file bin/galactic-cni
98+
- go build -ldflags "{{.LDFLAGS}}" -o bin/galactic-cni cmd/galactic-cni/main.go
99+
- go build -ldflags "{{.LDFLAGS}}" -o bin/galactic-agent cmd/galactic-agent/main.go
85100

86101
docker-build:
87102
desc: Build container image
@@ -156,8 +171,8 @@ tasks:
156171
run: once
157172
cmds:
158173
- |
159-
if find . -name "*.yml" -not -path "./.git/*" | grep -q .; then
160-
find . -name "*.yml" -not -path "./.git/*"
174+
if find . -name "*.yml" -not -path "./.git/*" -not -path "./deploy/containerlab/clab-gvpc/*" | grep -q .; then
175+
find . -name "*.yml" -not -path "./.git/*" -not -path "./deploy/containerlab/clab-gvpc/*"
161176
echo "ERROR: .yml files found; rename to .yaml"
162177
exit 1
163178
fi

cmd/galactic-agent/main.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
// Command galactic-agent is the node-local execution agent for Galactic.
1+
// Copyright 2025 Datum Cloud, Inc.
2+
//
3+
// SPDX-License-Identifier: AGPL-3.0-or-later
4+
25
package main
36

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

2427
cmd := &cobra.Command{
2528
Use: "galactic-agent",
26-
Short: "Node-local execution agent for Galactic VPC networking",
29+
Short: "BGP Provider implementation for Cosmos",
2730
SilenceUsage: true,
2831
RunE: func(cmd *cobra.Command, args []string) error {
2932
return agent.Run(cmd.Context(), *opts)

containers/galactic/Dockerfile

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ RUN go mod download
1717

1818
# Copy the go source
1919
COPY cmd/ cmd/
20-
COPY pkg/ pkg/
2120
COPY internal/ internal/
2221

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

3635
# Use distroless as minimal base image to package the binary

internal/agent/srv6/routeingress/routeingress.go

Lines changed: 0 additions & 58 deletions
This file was deleted.

internal/agent/srv6/srv6.go

Lines changed: 0 additions & 62 deletions
This file was deleted.

internal/cmd/version/version.go

Lines changed: 0 additions & 20 deletions
This file was deleted.

0 commit comments

Comments
 (0)