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 Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ tasks:
-X go.datum.net/galactic/internal/metadata.GitURL={{.GIT_URL}}
cmds:
- go build -ldflags "{{.LDFLAGS}}" -o bin/galactic-cni ./cmd/galactic-cni
- go build -ldflags "{{.LDFLAGS}}" -o bin/galactic-tap-cni ./cmd/galactic-tap-cni
- go build -ldflags "{{.LDFLAGS}}" -o bin/galactic-router ./cmd/galactic-router
- go build -ldflags "{{.LDFLAGS}}" -o bin/vmtap-cni ./cmd/vmtap-cni
- GOBIN={{.LOCALBIN}} go install github.com/containernetworking/plugins/plugins/main/host-device@v1.9.1
Expand Down
103 changes: 103 additions & 0 deletions cmd/galactic-tap-cni/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Copyright 2026 Datum Cloud, Inc.
//
// SPDX-License-Identifier: AGPL-3.0-or-later

package main

import (
"fmt"
"io"
"log"
"os"
"strings"

"github.com/containernetworking/cni/pkg/version"
"github.com/spf13/cobra"
"golang.org/x/term"

"go.datum.net/galactic/internal/cnitap"
"go.datum.net/galactic/internal/metadata"
)

const (
appName = "galactic-tap-cni"

appDesc = `Galactic tap CNI Plugin

The tap master plugin in the galactic CNI chain, for VM-based workloads
(Kata, Firecracker, kraftlet/Unikraft) attaching directly to a galactic VPC
network. Unrelated to vmtap-cni, which is chained after Cilium's own CNI
plugin for a different purpose entirely (see its own doc comment).

Find more information at: https://www.datum.net/docs`
)

func newRootCommand() *cobra.Command {
cmd := &cobra.Command{
Use: appName,
Short: strings.Split(appDesc, "\n")[0],
Long: appDesc,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
cnitap.InitCNIConfig()
confFile, _ := cmd.Flags().GetString("conf-file")
if confFile != "" {
cnitap.ConfFile = confFile
}
return nil
},
RunE: func(cmd *cobra.Command, _ []string) error {
if ok, _ := cmd.Flags().GetBool("build-info"); ok {
fmt.Println(metadata.BuildInfo(appName))
return nil
}
if ok, _ := cmd.Flags().GetBool("version"); ok {
fmt.Printf("%s version %s\n", appName, metadata.Version)
return nil
}
if os.Getenv("CNI_COMMAND") == "VERSION" {
return version.All.Encode(os.Stdout)
}

// Real CNI runtimes always pipe the network config JSON on
// stdin and close it. If stdin is an interactive terminal
// instead, no config will ever arrive and skel's blocking
// stdin read would hang forever — print version info instead.
if term.IsTerminal(int(os.Stdin.Fd())) {
fmt.Printf("%s version %s\n", appName, metadata.Version)
fmt.Printf("CNI protocol versions supported: %s\n", strings.Join(version.All.SupportedVersions(), ", "))
return nil
}

// Tap mode never enters a network namespace — all operations
// are host-side. Set the override so the CNI library skips its
// same-netns rejection check, which would otherwise reject
// kraftlet workloads that pass the host netns.
stdinData, _ := io.ReadAll(os.Stdin)
r, w, _ := os.Pipe()
go func() {
_, _ = w.Write(stdinData)
_ = w.Close()
}()
oldStdin := os.Stdin
os.Stdin = r
defer func() { os.Stdin = oldStdin }()

_ = os.Setenv("CNI_NETNS_OVERRIDE", "true")

cnitap.RunPlugin()
return nil
},
}

cmd.PersistentFlags().String("conf-file", cnitap.ConfFile, "Path to CNI conflist file")
cmd.Flags().Bool("build-info", false, "Print build information and exit")
cmd.Flags().BoolP("version", "V", false, "Print version and exit")

return cmd
}

func main() {
if err := newRootCommand().Execute(); err != nil {
log.Fatalf("error: %v", err)
}
}
16 changes: 16 additions & 0 deletions containers/galactic-cni/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,20 @@ RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build \
-X go.datum.net/galactic/internal/metadata.GitURL=${GIT_URL}" \
-o galactic-cni cmd/galactic-cni/main.go

# Build galactic-tap-cni, the tap master plugin in the galactic CNI chain
# (VM workloads: Kata, Firecracker, kraftlet/Unikraft). Ships in this same
# image/binary set since every plugin in the chain is staged onto the host
# by the same galactic-cni init container (installer.Bootstrap).
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build \
-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} \
-X go.datum.net/galactic/internal/metadata.SPDXLicense=${SPDX_LICENSE} \
-X go.datum.net/galactic/internal/metadata.GitURL=${GIT_URL}" \
-o galactic-tap-cni cmd/galactic-tap-cni/main.go

# Build vmtap-cni. It ships in this image rather than one of its own so the
# vmtap DaemonSet (config/vmtap/) can reference the same published
# ghcr.io/datum-cloud/galactic-cni image instead of a second, separately
Expand Down Expand Up @@ -82,6 +96,7 @@ FROM gcr.io/distroless/static:nonroot AS production

# Copy binaries from builder into the distroless production image
COPY --from=builder /workspace/galactic-cni /galactic-cni
COPY --from=builder /workspace/galactic-tap-cni /galactic-tap-cni
COPY --from=builder /workspace/vmtap-cni /vmtap-cni
COPY --from=builder /workspace/host-device /host-device
COPY --from=builder /var/run/galactic-cni /var/run/galactic-cni
Expand All @@ -94,6 +109,7 @@ FROM docker.io/library/alpine:latest

# Copy binaries from the production (distroless) image
COPY --from=production /galactic-cni /galactic-cni
COPY --from=production /galactic-tap-cni /galactic-tap-cni
COPY --from=production /vmtap-cni /vmtap-cni
COPY --from=production /host-device /host-device
COPY --from=production /var/run/galactic-cni /var/run/galactic-cni
Expand Down
Loading