首页 > 代码库 > CNI IPAM插件分析 --- 以hostlocal为示例

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)和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,则

  1. 若requestedIP和gateway相等,则报错
  2. 创建subnet := net.IPNet{IP: a.conf.Subnet.IP, Mask: a.conf.Subnet.Mask},最后调用validateRangeIP(requestedIP, &subnet, a.start, a.end)对IP进行验证
  3. 调用reserved, err := a.store.Reserve(id, requestedIP)
  4. 若reserved为真,则ipConfig := &current.IPConfig{...},routes := convertRoutesToCurrent(a.conf.Routes),最后返回ipConfig和routes

3、若没有指定requestedIP,则遍历获取IP

  1. 调用startIP, endIP := a.getSearchRange()
  2. 从startIP开始对IP进行遍历,跳过gateway IP,若找到合适的IP,则类似地调用reserved, err := a.store.Reserve(id, cur)以及返回ipConfig和routes
  3. 最后,若到达endIP则退出

 

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