kedge/internal/cni/routes.go
Tyler King 6058e62348 Initial commit: Kedge network automation platform
Go-based network automation with YANG models, gRPC, Ansible,
Terraform, and Kubernetes integration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:09:30 -05:00

84 lines
2.1 KiB
Go

package cni
import (
"fmt"
"net"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
"github.com/guildhouse-co/kedge/internal/topology"
)
// programPodRoutes programs routes inside the pod's network namespace for
// both overlay and underlay destinations.
func programPodRoutes(podNetnsPath string, ifName string, overlay, underlay []SubnetRoute) error {
ns, err := netns.GetFromPath(podNetnsPath)
if err != nil {
return fmt.Errorf("failed to get pod netns: %w", err)
}
defer ns.Close()
return inNamespace(ns, func() error {
link, err := netlink.LinkByName(ifName)
if err != nil {
return fmt.Errorf("interface %s not found: %w", ifName, err)
}
allRoutes := append(overlay, underlay...)
for _, sr := range allRoutes {
_, dst, err := net.ParseCIDR(sr.Dst)
if err != nil {
return fmt.Errorf("invalid CIDR %s: %w", sr.Dst, err)
}
route := &netlink.Route{
LinkIndex: link.Attrs().Index,
Dst: dst,
}
if err := netlink.RouteAdd(route); err != nil {
return fmt.Errorf("failed to add route %s: %w", sr.Dst, err)
}
}
return nil
})
}
// verifyRoutes checks that expected routes exist in the pod's network namespace.
func verifyRoutes(podNetnsPath string, overlay, underlay []SubnetRoute) error {
ns, err := netns.GetFromPath(podNetnsPath)
if err != nil {
return fmt.Errorf("failed to get pod netns: %w", err)
}
defer ns.Close()
return inNamespace(ns, func() error {
routes, err := netlink.RouteList(nil, netlink.FAMILY_V4)
if err != nil {
return fmt.Errorf("failed to list routes: %w", err)
}
routeMap := make(map[string]bool)
for _, r := range routes {
if r.Dst != nil {
routeMap[r.Dst.String()] = true
}
}
allExpected := append(overlay, underlay...)
for _, sr := range allExpected {
if !routeMap[sr.Dst] {
return fmt.Errorf("missing route: %s", sr.Dst)
}
}
return nil
})
}
// loadMeshTopology reads the mesh topology file written by the DaemonSet.
func loadMeshTopology(meshConfigPath string) (*topology.MeshTopology, error) {
if meshConfigPath == "" {
meshConfigPath = "/etc/kedge/mesh.json"
}
return topology.LoadFromFile(meshConfigPath)
}