in cni/ipam/ipam.go [141:274]
func (plugin *ipamPlugin) Add(args *cniSkel.CmdArgs) error {
var result *cniTypesCurr.Result
var err error
logger.Info("Processing ADD command",
zap.String("ContainerId", args.ContainerID),
zap.String("Netns", args.Netns),
zap.String("IfName", args.IfName),
zap.String("Args", args.Args),
zap.String("Path", args.Path),
zap.ByteString("StdinData", args.StdinData))
defer func() {
logger.Info("ADD command completed",
zap.Any("result", result),
zap.Error(err))
}()
// Parse network configuration from stdin.
nwCfg, err := plugin.Configure(args.StdinData)
if err != nil {
err = plugin.Errorf("Failed to parse network configuration: %v", err)
return err
}
// assign the container id
options := make(map[string]string)
options[ipam.OptAddressID] = args.ContainerID
// Check if an address pool is specified.
if nwCfg.IPAM.Subnet == "" {
var poolID string
var subnet string
isIpv6 := false
if nwCfg.IPAM.Type == ipamV6 {
isIpv6 = true
}
// Select the requested interface.
options[ipam.OptInterfaceName] = nwCfg.Master
// Allocate an address pool.
poolID, subnet, err = plugin.am.RequestPool(nwCfg.IPAM.AddrSpace, "", "", options, isIpv6)
if err != nil {
err = plugin.Errorf("Failed to allocate pool: %v", err)
return err
}
// On failure, release the address pool.
defer func() {
if err != nil && poolID != "" {
logger.Info("Releasing pool",
zap.String("poolId", poolID))
_ = plugin.am.ReleasePool(nwCfg.IPAM.AddrSpace, poolID)
}
}()
nwCfg.IPAM.Subnet = subnet
logger.Info("Allocated address with subnet",
zap.String("poolId", poolID),
zap.String("subnet", subnet))
}
// Allocate an address for the endpoint.
address, err := plugin.am.RequestAddress(nwCfg.IPAM.AddrSpace, nwCfg.IPAM.Subnet, nwCfg.IPAM.Address, options)
if err != nil {
err = plugin.Errorf("Failed to allocate address: %v", err)
return err
}
// On failure, release the address.
defer func() {
if err != nil && address != "" {
logger.Info("Releasing address", zap.String("address", address))
_ = plugin.am.ReleaseAddress(nwCfg.IPAM.AddrSpace, nwCfg.IPAM.Subnet, address, options)
}
}()
logger.Info("Allocated address", zap.String("address", address))
// Parse IP address.
ipAddress, err := platform.ConvertStringToIPNet(address)
if err != nil {
err = plugin.Errorf("Failed to parse address: %v", err)
return err
}
// Query pool information for gateways and DNS servers.
apInfo, err := plugin.am.GetPoolInfo(nwCfg.IPAM.AddrSpace, nwCfg.IPAM.Subnet)
if err != nil {
err = plugin.Errorf("Failed to get pool information: %v", err)
return err
}
// Populate result.
result = &cniTypesCurr.Result{
IPs: []*cniTypesCurr.IPConfig{
{
Address: *ipAddress,
Gateway: apInfo.Gateway,
},
},
Routes: []*cniTypes.Route{
{
Dst: ipv4DefaultRouteDstPrefix,
GW: apInfo.Gateway,
},
},
}
// Populate DNS servers.
for _, dnsServer := range apInfo.DnsServers {
result.DNS.Nameservers = append(result.DNS.Nameservers, dnsServer.String())
}
// Convert result to the requested CNI version.
res, err := result.GetAsVersion(nwCfg.CNIVersion)
if err != nil {
err = plugin.Errorf("Failed to convert result: %v", err)
return err
}
// Output the result.
if nwCfg.IPAM.Type == cni.Internal {
// Called via the internal interface. Pass output back in args.
args.StdinData, _ = json.Marshal(res)
} else {
// Called via the executable interface. Print output to stdout.
res.Print()
}
return nil
}