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)和allocator, err := allocator.NewIPAllocator(ipamConf, store)获取allocator
4、调用ipConf, routes, err := allocator.Get(args.ContainerID)获取IP和路由配置
5、最后result.IPs = []*current.IPConfig{ipConf}和result.Routes = routes,并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, args string) (*IPAMConfig, string, error)
1、首先设置n := Net{},再调用json.Unmarshal(bytes, &n)进行解析
2、若args不为nil,调用types.LoadArgs(args, n.IPAM.Args)
3、最后调用n.IPAM.Name = n.Name ---> Copy net name into IPAM so not to drag Net struct around
Net数据结构如下所示:
type Net struct { Name string CNIVersion string IPAM *IPAMConfig }
IPAMConfig数据结构如下所示:
// IPAMConfig represents the IP related network configuration type IPAMConfig struct { Name string Type string RangeStart net.IP RangeEnd net.IP Subnet types.IPNet Gateway net.IP Routes []types.Route DataDir string ResolvConf string Args *IPAMArgs }
// 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)并且调用lk, err := NewFileLock(dir)
3、最后返回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(conf *IPAMConfig, store backend.Store) (*IPAllocator, error)
1、对子网的大小进行检测,太小则报错
2、调用start, end, err = networkRange((*net.IPNet)(&conf.Subnet))
3、调用start = ip.NextIP(start)跳过.0的地址
4、若conf.RangeStart不为空,则调用validateRangeIP(conf.RangeStart, (*net.IPNet)(&conf.Subnet), nil, nil)进行检测,并且设置start = conf.RangeStart,对于conf.RangeEnd同理
IPAllocator数据结构如下所示:
type IPAllocator struct { // start is inclusive and may be allocated start net.IP // end is inclusive and may be allocated end net.IP conf *IPAMConfig store backend.Store }
// cni/plugins/ipam/host-local/backend/allocator/allocator.go
// Returns newly allocated IP along with its config
5、func (a *IPAllocator) Get(id string) (*current.IPConfig, []*types.Route, error)
1、设置gw := a.conf.Gateway,若gw == nil,则gw = ip.NextIP(a.conf.Subnet.IP)
2、若a.conf.Args不为nil,则requestedIP = a.conf.Args.IP,若requestedIP不为nil,则
- 若requestedIP和gateway相等,则报错
- 创建subnet := net.IPNet{IP: a.conf.Subnet.IP, Mask: a.conf.Subnet.Mask},最后调用validateRangeIP(requestedIP, &subnet, a.start, a.end)对IP进行验证
- 调用reserved, err := a.store.Reserve(id, requestedIP)
- 若reserved为真,则ipConfig := ¤t.IPConfig{...},routes := convertRoutesToCurrent(a.conf.Routes),最后返回ipConfig和routes
3、若没有指定requestedIP,则遍历获取IP
- 调用startIP, endIP := a.getSearchRange()
- 从startIP开始对IP进行遍历,跳过gateway IP,若找到合适的IP,则类似地调用reserved, err := a.store.Reserve(id, cur)以及返回ipConfig和routes
- 最后,若到达endIP则退出