zoukankan      html  css  js  c++  java
  • cni 添加网络 流程分析

    cnitool: Add or remove network interfaces from a network namespace
    
      cnitool  add  <net>  <netns>
      cnitool  del  <net>  <netns>

    cnitool的使用方式如下:其中<net>是配置文件所在目录,一般为/etc/cni/net.d/*.conf文件,<netns>为network namespace的目录文件,一般为/var/run/netns/NS-ID

    1、cni/libcni/api.go

    // AddNetwork executes the plugin with ADD command

    func (c *CNIConfig) AddNetwork(net *NetworkConfig, rt *RuntimeConf) (types.Result, error)

    (1)、首先调用pluginPath, err := invoke.FindInPath(net.Network.Type, c.Path),该函数用于在c.Path中寻找对应插件的可执行文件,然后返回路径

    (2)、调用 return invoke.ExecPluginWithResult(pluginPath, net.Bytes, c.args("ADD", rt)),net.Bytes是配置文件的序列化二进制码,其中c.args函数主要的作用是填充并返回一个*invoke.Args类型:

    return &invoke.Args {
      Command:        action,
      ContainerID:      rt.ContainerID,
      NetNS:         rt.NetNS,
      PluginArgs:      rt.Args,
      IfName:        rt.IfName,
      Path:         strings.Join(c.Path, string(os.PathListSeparator)),
    }
    

      

    NetworkConfig的数据结构如下所示,用于表示容器要加入的网络:

    // libcni/api.go
    type NetworkConfig struct {
      Network   *types.NetConf
      Bytes    []byte      // 在初始化CNI的时候,会将配置文件写入Bytes
    }
    
    // pkg/types/types.go
    // NetConf describes a network
    type NetConf struct {
      CNIVersion   string
      Name       string
      IPAM  string {
        Type  string
      }
      DNS DNS
    }
    

      

    Runtime的数据结构如下所示,用于表示加入网络的容器的信息:

    type RuntimeConf struct {
      ContainerID   string
      NetNS       string
      IfName      string
      Args       [][2]string
    }
    

    CNIConfig的数据结构如下所示:CNIconfig包含的是bridge,dhcp等插件的可执行文件的目录的路径集合

    type CNIConfig struct {
      Path    []string
    }
    

      

    2、cni/pkg/invoke/exec.go

    func ExecPluginWithResult(pluginPath string, netconf []byte, args CNIArgs) (types.Result, error)

    该函数只是简单地返回 return defaultPluginExec.WithResult(pluginPath, netconf, args)

    其中defaultPluginExec是一个*PluginExec的类型变量,赋值过程如下所示:

    var defaultPluginExec = &PluginExec{
      RawExec:      &RawExec{Stderr: os.Stderr},    --->RawExec又是在raw_exec.go中定义的一个结构类型,其中只有一个Stderr的io.Writer类型
      VersionDecoder:   &version.PluginDecoder{},
    }
    
    // 其中PluginExec的定义如下所示:
    type PluginExec struct {
      RawExec interface {
        ExecPlugin(pluginPath string, stdinData []byte, environ []string) ([]byte, error)
      }
      VersionDecoder interface {     Decode(jsonBytes []byte) (version.PluginInfo, error)   } }

      

    3、cni/pkg/invoke/exec.go

    func (e *PluginExec) WithResult(pluginPath string, netconf []byte, args CNIArgs) (*types.Result, error)

    (1)、调用stdoutBytes, err := e.RawExec.ExecPlugin(pluginPath, netconf, args.AsEnv()),args.AsEnv()将args里的内容转变为环境变量返回,例如CNI_COMMAND=ADD等等

    // Plugin must return result in same version as specified in netconf

    (2)、调用versionDecoder := &version.ConfigDecoder{}和confVersion, err := versionDecoder.Decode(netconf)从netconf中解析处CNI的版本

    (3)、最后调用return version.NewResult(confVersion, stdoutBytes)返回相应版本的Result

    4、cni/pkg/invoke/args.go

    func (args *Args) AsEnv() []string

    1、调用env := os.Environ()获取已有的环境变量

    2、若args.PluginArgsStr为"",则将args.PluginArgs拼接为“A=B;C=D”的形式

    3、调用env = append(env, 

      "CNI_COMMAND=" + args.Command,

      "CNI_CONTAINERID=" + args.ContainerID,

      "CNI_NETNS=" + args.NetNS,

      "CNI_ARGS=" + pluginArgsStr,

      "CNI_IFNAME=" + args.IfName,

      "CNI_PATH="+args.Path)

    ),将参数都作为环境变量传递给plugin

    RawExec的结构如下所示:

    type RawExec struct {
      Stderr  io.Writer
    }
    

    5、cni/pkg/invoke/raw_exec.go

    func (e *RawExec) ExecPlugin(pluginPath string, stdinData []byte, environ []string) ([]byte, error)

    (1)、首先获得stdout := bytes.Buffer{}作为输出缓冲器

    (2)、创建执行命令并调用c.Run()运行

    c := exec.Cmd {
      Env:      environ,
      Path:     pluginPath,
      Args:     []string{pluginPath},
      Stdin:     bytes.NewBuffer(stdinData),
      Stdout:    stdout,
      Stderr:    e.Stderr,
    }
    

    (3)、最后返回stdout.Bytes(),插件直接将结果输出到stdout

  • 相关阅读:
    Application package 'AndroidManifest.xml' must have a minimum of 2 segments.
    让“是男人就下到100层”在Android平台上跑起来
    移植一个cocos2d-x游戏
    cocos2d-x宏定义
    职场之需求
    cocos2d-x for android配置 & 运行 Sample on Linux OS
    input函数出现的问题(Python)
    职场之英语
    职场之随手记
    应用商店后台MIS的一些思考
  • 原文地址:https://www.cnblogs.com/YaoDD/p/6024535.html
Copyright © 2011-2022 走看看