CNI IPAM插件分析 --- 以hostlocal為示例


skel.CmdArgs數據結構如下所示:

type CmdArgs struct {

  ContainerID    string
  Netns        string
  IfName        string
  Args         string
  Path         string
  StdinData      []byte
}

  

// cni/plugins/ipam/host-local/main.go

1、func cmdAdd(args *skel.CmdArgs) error

1、調用ipamConf, confVersion, err := allocator.LoadIPAMConfig(args.StdinData, args.Args)加載IPAM的配置和版本號

2、若ipamConf.ResolvConf不為"",則調用dns, err := parseResolvConf(ipamConf.ResolvConf),並且將result.DNS = *dns

3、調用store, err := disk.New(ipamConf.Name, ipamConf.DataDir)

4、調用allocs := []*allocator.IPAllocator{} 獲取allocator,保持該結構,當出錯的時候,可以將所有IP地址釋放

5、創建requestedIPs := map[string]net.IP{}並將ipamConf.IPArgs中的地址都填入其中

6、遍歷for idx, ipRange := range ipamConf.Ranges,調用allocator := allocator.NewIPAllocator(ipamConf.Name, ipRange, store)

7、遍歷requestedIPs,for k, ip := range requestedIPs,如果ipRange.IPInRange(ip)為nil,則說明請求的ip在可分配的地址范圍內,

設置requestedIP = ip,並調用delete(requestedIPs, k)

8、調用ipConf, err := allocator.Get(args.ContainerID, requestedIP),並調用allocs = append(allocs, allocator)和result.IPs = append(result.IPs, ipConf)

9、如果最后len(requestedIPs)不為0,則釋放所有的allocator並報錯

10、設置result.Routes = ipamConf.Routes

11、最后return types.PrintResult(result, confVersion)

 

// cni/plugins/ipam/host-local/backend/allocator/config.go

// NewIPAMConfig creates a NetworkConfig from the given network name.

2、func LoadIPAMConfig(bytes []byte, envArgs string) (*IPAMConfig, string, error)

1、首先設置n := Net{},再調用json.Unmarshal(bytes, &n)進行解析

2、如果envArgs不為"",或者n.Args不為nil,則將他們都添加到n.IPAM.IPArgs中

3、如果n.IPAM.Range不為nil,說明使用的是老的配置方式,將n.IPAM.Range遷移到n.IPAM.Ranges中

4、遍歷n.IPAM.Ranges,對IPv4或IPv6的range進行計數,若他們的數目大於1,切cni版本小於0.3.0則報錯

5、檢測各個range之間是否有重合

6、將n.IPAM.Name賦值為n.Name

7、最后return n.IPAM, n.CNIVersion, nil

 

Net數據結構如下所示:

type Net struct {
  Name       string
  CNIVersion    string
  IPAM       *IPAMConfig
  Args       *struct {
    A *IPAMArgs
  }
}

  

IPAMConfig數據結構如下所示:

// IPAMConfig represents the IP related network configuration
// 保留Range是為了向后兼容 type IPAMConfig struct {
  *Range   Name      string   Type       string   Routes      []*types.Route   DataDir      string   ResolvConf    string
  Ranges       []Range   IPArgs       []net.IP    // Requested IPs from CNI_ARGS and args }

  

Range結構如下所示:

type Range struct {
  RangeStart    net.IP
  RangeEnd     net.IP
  Subnet      types.IPNet
  Gateway      net.IP
}

 

IPAMArgs結構如下所示:

type IPAMArgs struct {
  IPs    []net.IP
}

  

// cni/plugins/ipam/host-local/backend/disk/backend.go

3、func New(network, dataDir string) (*Store, error)

1、若dataDir為"",設置defaultDataDir為"/var/lib/cni/networks"

2、調用dir := filepath.Join(dataDir, network)並且調用os.MkdirAll(dir, 0755)創建目錄

3、調用lk, err := NewFileLock(dir)

4、最后返回return &Store{*lk, dir}, nil

 

Store數據結構如下所示:

type Store struct {
  FileLock        // FileLock wraps os.File to be used as a lock using flock
  dataDir   string  // 默認為/var/lib/cni/networks/NETWORKNAME
}

  

// cni/plugins/ipam/host-local/backend/allocator/allocator.go

4、func NewIPAllocator(netName string, r Range, store backend.Store) *IPAllocator

1、調用rangeID := base64.URLEncoding.EncodeToString(r.RangeStart)

2、返回return &IPAllocator{......}

 

IPAllocator數據結構如下所示:

type IPAllocator struct {
  netName    string
  ipRange     Range
  store      backend.Store
  rangeID      string    // Used for tracking last reserved ip
}

  

// cni/plugins/ipam/host-local/backend/allocator/allocator.go

5、func (a *IPAllocator) Get(id string, requestedIP net.IP) (*current.IPConfig, error)

1、調用gw := a.ipRange

2、如果requestedIP 不為nil,首先判斷requestedIP和gw不能相等,否則報錯

如果a.ipRange.IPInRange(requestedIP)返回錯誤,則報錯,否則調用reserved, err := a.store.Reserve(id, requestedIP, a.rangeID)將結果保存

最后,設置reservedIP為requestedIP

3、如果requestedIP不為nil,先調用iter, err := a.GetIter(),再調用for循環遍歷iter,獲取下一個可用的IP,之后的動作和2中相同

4、最后返回return &current.IPConfig{....}, nil

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM