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
122 changes: 117 additions & 5 deletions plugins/main/host-device/host-device.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ type NetConf struct {
RuntimeConfig struct {
DeviceID string `json:"deviceID,omitempty"`
} `json:"runtimeConfig,omitempty"`
UseInterfaceNetwork bool `json:"useInterfaceNetwork,omitempty"`

// for internal use
auxDevice string `json:"-"` // Auxiliary device name as appears on Auxiliary bus (/sys/bus/auxiliary)
Expand Down Expand Up @@ -125,6 +126,12 @@ func cmdAdd(args *skel.CmdArgs) error {
if err != nil {
return err
}

interfaceNetworkEnabled := useInterfaceNetwork(cfg)
if interfaceNetworkEnabled && cfg.DPDKMode {
return fmt.Errorf("useInterfaceNetwork is not supported for dpdk-bound devices")
}

containerNs, err := ns.GetNS(args.Netns)
if err != nil {
return fmt.Errorf("failed to open netns %q: %v", args.Netns, err)
Expand All @@ -138,12 +145,24 @@ func cmdAdd(args *skel.CmdArgs) error {
}}

var contDev netlink.Link
var networkState *HostNetworkStateFile
if !cfg.DPDKMode {
hostDev, err := getLink(cfg.Device, cfg.HWAddr, cfg.KernelPath, cfg.PCIAddr, cfg.auxDevice)
if err != nil {
return fmt.Errorf("failed to find host device: %v", err)
}

networkState = &HostNetworkStateFile{
HostIfName: hostDev.Attrs().Name,
HostLinkWasUp: hostDev.Attrs().Flags&net.FlagUp == net.FlagUp,
}
if interfaceNetworkEnabled {
err = captureHostNetworkState(networkState, hostDev)
if err != nil {
return err
}
}

contDev, err = moveLinkIn(hostDev, containerNs, args.IfName)
if err != nil {
return fmt.Errorf("failed to move link %v", err)
Expand All @@ -153,6 +172,15 @@ func cmdAdd(args *skel.CmdArgs) error {
result.Interfaces[0].Name = contDev.Attrs().Name
// Set the MAC address of the interface
result.Interfaces[0].Mac = contDev.Attrs().HardwareAddr.String()

if interfaceNetworkEnabled {
if err := applyNetworkStateToPod(containerNs, contDev, networkState); err != nil {
return err
}
if cfg.IPAM.Type == "" {
return printLinkWithNetworkState(contDev, cfg.CNIVersion, containerNs, networkState)
}
}
}

if cfg.IPAM.Type == "" {
Expand Down Expand Up @@ -181,7 +209,7 @@ func cmdAdd(args *skel.CmdArgs) error {
return err
}

if len(newResult.IPs) == 0 {
if !interfaceNetworkEnabled && len(newResult.IPs) == 0 {
return errors.New("IPAM plugin returned missing IP config")
}

Expand All @@ -201,6 +229,10 @@ func cmdAdd(args *skel.CmdArgs) error {
}
}

if interfaceNetworkEnabled {
mergeNetworkStateIntoResult(newResult, networkState)
}

newResult.DNS = cfg.DNS

return types.PrintResult(newResult, cfg.CNIVersion)
Expand Down Expand Up @@ -496,6 +528,82 @@ func printLink(dev netlink.Link, cniVersion string, containerNs ns.NetNS) error
return types.PrintResult(&result, cniVersion)
}

// routeStateToCNIRoute converts an internal routeState to a CNI types.Route.
// Returns nil if the destination cannot be parsed.
func routeStateToCNIRoute(route routeState) *types.Route {
var dst net.IPNet
if route.Destination == "default" {
var gw net.IP
if route.Gateway != "" {
gw = net.ParseIP(route.Gateway)
}
dst = net.IPNet{IP: net.IPv4zero, Mask: net.CIDRMask(0, 32)}
if gw != nil && gw.To4() == nil {
dst = net.IPNet{IP: net.IPv6zero, Mask: net.CIDRMask(0, 128)}
}
} else {
_, parsedDst, err := net.ParseCIDR(route.Destination)
if err != nil {
return nil
}
dst = *parsedDst
}

cniRoute := &types.Route{Dst: dst}
if route.Gateway != "" {
cniRoute.GW = net.ParseIP(route.Gateway)
}
if route.Table != 0 {
cniRoute.Table = current.Int(route.Table)
}
if route.Scope != 0 {
cniRoute.Scope = current.Int(int(route.Scope))
}
cniRoute.Priority = route.Metric
return cniRoute
}

// mergeNetworkStateIntoResult appends host-captured IPs and routes into an
// existing CNI result so the final output reflects both IPAM and host state.
func mergeNetworkStateIntoResult(result *current.Result, state *HostNetworkStateFile) {
if state == nil {
return
}
for _, addr := range state.Addresses {
hostIP, ipNet, err := net.ParseCIDR(addr)
if err != nil {
continue
}
ipNet.IP = hostIP
result.IPs = append(result.IPs, &current.IPConfig{
Interface: current.Int(0),
Address: *ipNet,
})
}
for _, route := range state.Routes {
if cniRoute := routeStateToCNIRoute(route); cniRoute != nil {
result.Routes = append(result.Routes, cniRoute)
}
}
}

// printLinkWithNetworkState prints a CNI result including IP and route information
// derived from the captured host network state applied to the container interface.
func printLinkWithNetworkState(dev netlink.Link, cniVersion string, containerNs ns.NetNS, state *HostNetworkStateFile) error {
result := &current.Result{
CNIVersion: current.ImplementedSpecVersion,
Interfaces: []*current.Interface{
{
Name: dev.Attrs().Name,
Mac: dev.Attrs().HardwareAddr.String(),
Sandbox: containerNs.Path(),
},
},
}
mergeNetworkStateIntoResult(result, state)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imo if user decides to keep network config from the host then we should ignore IPAM or block the combination witt IPAM in the config. I think is either IPAM, or host network config (no ip is also valid config)

return types.PrintResult(result, cniVersion)
}

func linkFromPath(path string) (netlink.Link, error) {
entries, err := os.ReadDir(path)
if err != nil {
Expand Down Expand Up @@ -670,9 +778,9 @@ func validateCniContainerInterface(intf current.Interface) error {
}

func cmdStatus(args *skel.CmdArgs) error {
conf := NetConf{}
if err := json.Unmarshal(args.StdinData, &conf); err != nil {
return fmt.Errorf("failed to load netconf: %w", err)
conf, err := loadConf(args.StdinData)
if err != nil {
return err
}

if conf.IPAM.Type != "" {
Expand All @@ -681,7 +789,11 @@ func cmdStatus(args *skel.CmdArgs) error {
}
}

// TODO: Check if host device exists.
if !conf.DPDKMode {
if _, err := getLink(conf.Device, conf.HWAddr, conf.KernelPath, conf.PCIAddr, conf.auxDevice); err != nil {
return fmt.Errorf("failed to find host device: %v", err)
}
}

return nil
}
Loading
Loading