CNI插件初始化
// ocicni.go
1、func InitCNI(pluginDir string) (CNIPlugin, error)
(1)、先调用plugin := probeNetworkingPluginsWithVendorCNIDirPrefix(pluginDir, "")
先初步创建一个默认的cniNetworkPlugin的结构,并调用plugin.nsenterPath, err = exec.LookPath("nsenter")
(2)、调用err = getDefaultCNINetwork(plugin.pluginDir, plugin.vendorCNIDirPrefix),检查默认的network
是否存在,若不存在,则停止CNI插件的搜索,直接返回一个&cniNoOp{}结构
(3)、生成一个goroutine,调用plugin.SyncNetworConfig()周期性地和pluginDir进行同步,从而检查网络状态的更新
(4)、最后,return plugin, nil
cniNetworkPlugin结构如下所示:
type cniNetworkPlugin struct { loNetwork *cniNetwork sync.RWMutex defaultNetwork *cniNetwork
nsenterPath string pluginDir string vendorCNIDirPrefix string }
cniNetwork结构如下所示:
type cniNetwork struct { name string NetworkConfig *libcni.NetworkConfig CNIConfig libcni.CNI }
// ocicni.go
2、func probeNetworkPluginsWithVendorCNIDirPrefix(pluginDir, vendorCNIDirPrefix string) (*cniNetworkPlugin)
(1)、创建plugin := &cniNetworkPlugin{
defaultNetwork: nil,
loNetwork: getLoNetwork(vendorCNIDirPrefix),
pluginDir: pluginDir,
vendorCNIDirPrefix: vendorCNIDirPrefix,
}
(2)、调用plugin.syncNetworkConfig() ---> sync NetworkConfig in best effort during probing
(3)、最后,return plugin
// ocicni.go
3、func getLoNetwork(vendorDirPrefix string) *cniNetwork
(1)、调用loConfig,err := libcni.ConfFromBytes([]byte(`{"cniVersion": "0.1.0", "name": "cni-loopback", "type": "loopback"}`))
(2)、调用cninet := &libcni.CNIConfig{Path: []string{vendorCNIDir(vendorDirPrefix, loConfig.Network.Type), DefaultCNIDir}},其中vendorCNIDir返回的就是这样一个目录:$vendorDirPrefix/opt/$type/bin
(3)、创建loNetwork := cniNetwork{
name: "lo"
NetworkConfig: loConfig,
CNIConfig: cninet
}
再return loNetwork
// ocicni.go
4、func (plugin *cniNetworkPlugin) syncNetworkConfig()
该函数仅仅调用network, err := getDefaultCNINetwork(plugin.pluginDir, plugin.vendorCNIDirPrefix)
再调用plugin.setDefaultNetwork(network)
// ocicni.go
5、func getDefaultCNINetwork(pluginDir, vendorCNIDirPrefix string) (*cniNetwork, error)
(1)、当pluginDir为""时,设置pluginDir = DefaultNetDir
(2)、调用files, err := libcni.ConfFiles(pluginDir),从pluginDir中加载文件,若err不为nil,或者len(files) == 0,则报错
(3)、遍历files,调用conf, err := libcni.ConfFromFile(confFile),加载CNI config file
再设置cninet := &libcni.CNIConfig{Path: []string{DefaultCNIDir, vendorDir},}
最后设置network := &cniNetwork{name: conf.Network.Name, NetworkConfig: conf, CNIConfig: cninet}
// ocicni.go
6、func setDefaultNetwork(n *cniNetwork)
该函数仅仅设置plugin.defaultNetwork = n而已
CNI插件创建POD
// cri-o端的调用为: podNamespace := "" s.netPlugin.SetUpPod(netNsPath, podNamespace, id, containerName)
// ocicni.go
1、func (plugin *cniNetworkPlugin) SetUpPod(netnsPath string, namespace string, name string, id string) error
(1)、首先调用plugin.checkInitialized(),该函数确定plugin.defaultNetwork是否为nil,若为nil则报错
(2)、调用plugin.loNetwork.addToNetwork(name, namespace, id, netnsPath)
(3)、调用plugin.getDefaultNetwork().addToNetwork(name, namespace, id, netnsPath)
// ocicni.go
2、func (network *cniNetwork) addToNetwork(podName string, podNamespace string, podInfraContainerID string, podNetnsPath string) (*cnitypes.Result, error)
(1)、调用rt, err := buildCNIRuntimeConf(podName, podNamespace, podInfraContainerID, podNetnsPath)
(2)、调用netconf, cninet := network.NetworkConfig, network.CNIConfig
(3)、调用res, err := cninet.AddNetwork(netconf, rt)
(4)、最后return res, nil
// ocicni.go
3、func buildCNIRuntimeConf(podName string, podNs string, podInfraContainerID string, podNetnsPath string) (*libcni.RuntimeConf, error)
该函数仅仅创建rt := &libcni.RuntimeConf{
ContainerID: podInfraContainerID,
NetNS: podNetnsPath,
IfName: DefaultInterfaceName,
Args: [][2]string{
{"IgnoreUnknown", "1"},
{"K8S_POD_NAMESPACE", podNs},
{"K8S_POD_NAME", podName},
{"K8S_POD_INFRA_CONTAINER_ID", podInfraContainerID},
}
}
最后,return rt, nil
获取pod的网络状态
1、func (plugin *cniNetworkPlugin) GetContainerNetworkStatus(netnsPath string, namespace string, name string, id string) (string, error)
该函数先调用ip, err := getContainerIP(plugin.nsenterPath, netnsPath, DefaultInterfaceName, "-4")
最后return ip.String(), nil