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 ¤t.IPConfig{....}, nil