Container Network Interface (CNI)

repository·main·Indexed 26 days ago

https://github.com/containernetworking/cni

A CNCF project providing a standardized specification and Go libraries for configuring network interfaces in Linux containers. It enables container runtimes to use pluggable networking solutions from third-party vendors. Includes cnitool, a utility for managing network interfaces (add, check, del, gc, status) within network namespaces, and support for a debug plugin to troubleshoot CNI plugin development.

Tokens
12.2K
Snippets
22
Records
69
Agent score
91%

What's inside CNI

  1. Overview of the CNI specification components

    main

    The CNI specification defines five primary components:

    1. A format for administrators to define network configuration.
    2. A protocol for container runtimes to make requests to network plugins.
    3. A procedure for executing plugins based on a supplied configuration.
    4. A procedure for plugins to delegate functionality to other plugins.
    5. Data types for plugins to return their results to the runtime.
  2. Overview of CNI (Container Network Interface)

    main

    CNI is a Cloud Native Computing Foundation (CNCF) project that provides a specification and libraries for writing plugins to configure network interfaces in Linux containers. It focuses exclusively on container network connectivity and the removal of allocated resources when containers are deleted.

    Key components include:

    • Specification: Defines how container runtimes and network plugins interact.
    • Go Libraries: For integrating CNI into applications.
    • Reference Plugins: A set of implementation examples (maintained in a separate repository).
    • cnitool: An example command-line tool for executing CNI plugins.
  3. Use the debug plugin for CNI troubleshooting

    main
    The debug plugin is designed to assist in debugging or troubleshooting during CNI plugin development. It can capture the CNI request to a file and execute arbitrary commands within the container network namespace during specific lifecycle events (ADD, DEL, or CHECK).
  4. Understand the CNI core concepts

    main

    The Container Network Interface (CNI) is a plugin-based networking solution for application containers on Linux. It defines the interface between runtimes and plugins using four key terms:

    • container: A network isolation domain (e.g., a network namespace or a virtual machine).
    • network: A group of uniquely addressable endpoints that can communicate with each other (e.g., a container, a machine, or a router).
    • runtime: The program responsible for executing CNI plugins.
    • plugin: A program that applies a specified network configuration.
  5. Understand the CNI Execution Protocol

    main

    The CNI protocol is a binary-based execution model where a container runtime invokes CNI plugin binaries.

    Plugin Categories:

    • Interface plugins: Create a network interface inside the container and ensure connectivity.
    • Chained plugins: Adjust the configuration of an existing interface (and may create additional interfaces).

    Communication Flow:

    1. Runtime to Plugin: The runtime passes parameters via OS environment variables and provides configuration via stdin (JSON-encoded).
    2. Plugin to Runtime: On success, the plugin outputs a JSON-encoded result to stdout. On failure, it outputs an error structure to stderr and exits with a non-zero return code.
  6. Upgrade to CNI Specification v1.0

    main

    CNI v1.0 introduces the following breaking changes:

    • Non-List configurations are removed.
    • The version field within the interfaces array has been removed as it was redundant.

    libcni Changes

    The package /pkg/types/current no longer exists. Runtimes must now explicitly select a version they support to reduce code breakage and allow plugin authors to decide which spec versions their plugins support.

    import (
        cniv1 "github.com/containernetworking/cni/pkg/types/100"
    )
  7. Implement CNI Plugin Execution Protocol

    main

    CNI plugins are executed by a container runtime using specific commands and environment variables. To implement a plugin, you must handle the following operations:

    • ADD: Create a network attachment. Executed in the order defined in the configuration.
    • DEL: Remove a network attachment. Executed in reverse order of the configuration.
    • CHECK: Verify if an attachment is functional. Uses the same parameters as ADD and the prevResult from the initial ADD operation.
    • GC (Garbage Collection): Clean up stale resources. Unlike other commands, GC does not receive attachment parameters and must continue execution even if a plugin returns an error.

    If a plugin returns an error during ADD, DEL, or CHECK, the runtime must halt execution and return the error. During GC, the runtime must collect all errors and return them after attempting all plugins.

  8. Use cnitool to manage network interfaces

    main

    cnitool is a utility to execute CNI configurations to add, check, remove, garbage collect, or get the status of an interface within an existing network namespace.

    Usage Pattern: cnitool [command] [network-name] [network-namespace-path]

    Available Commands:

    • add: Add network interface to a network namespace.
    • check: Check network interface in a network namespace (Note: Only for spec v0.4.0+).
    • del: Delete network interface from a network namespace.
    • gc: Garbage collect network interfaces.
    • status: Get status of network interfaces.
    • completion: Generate autocompletion scripts.
    • help: Show help for a command.
  9. Implement CNI plugins in Go

    main

    Go-based plugins can use the cni library to handle multiple spec versions easily. In recent versions, types.Result is an interface, and concrete implementations reside in subpackages like types/100, types/040, and types/020.

    Implementation Pattern:

    1. Use the latest spec version structs (e.g., types/100) for internal plugin logic.
    2. Use types.PrintResult(result, cniVersion) to convert and print the result to stdout in the format requested by the cniVersion in the configuration.
    3. Advertise supported versions via the third argument to skel.PluginMain().
    import (
    	 "github.com/containernetworking/cni/pkg/skel"
    	 "github.com/containernetworking/cni/pkg/types"
    	 current "github.com/containernetworking/cni/pkg/types/100"
    	 "github.com/containernetworking/cni/pkg/version"
    )
    
    func cmdAdd(args *skel.CmdArgs) error {
    	// determine spec version to use
    	var netConf struct {
    		types.NetConf
    		// other plugin-specific configuration goes here
    	}
    	err := json.Unmarshal(args.StdinData, &netConf)
    	cniVersion := netConf.CNIVersion
    
    	// plugin does its work...
    	//   set up interfaces
    	//   assign addresses, etc
    	
    	// construct the result
    	result := &current.Result{
    		Interfaces: []*current.Interface{ ... },
    		IPs: []*current.IPs{ ... },
    		...
    	}
    	
    	// print result to stdout, in the format defined by the requested cniVersion
    	return types.PrintResult(result, cniVersion)
    }
    
    func main() {
    	skel.PluginMain(cmdAdd, cmdDel, version.All)
    }