Skip to content

Commit

Permalink
Changing IPAM code in cnidel so centralized API driven IPAM now works…
Browse files Browse the repository at this point in the history
… for all backends requesting it.

Also MACVLAN plugin recently was enhanced to tolerate the absence of "ipam" key in the CNI config, so "ip":"none" is now enabled for all dynamic backends.
The user will be responsible of making sure unsupported IPAM request types are not used for backends not supporting it.
  • Loading branch information
Levovar committed Jul 18, 2019
1 parent 21125b7 commit 24a639c
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 13 deletions.
19 changes: 17 additions & 2 deletions pkg/cnidel/cniconfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,25 @@ var (

//This function creates CNI configuration for all static-level backends
//The CNI binary matching with NetowrkType is invoked with the CNI config file matching with NetworkID parameter
func readCniConfigFile(cniconfDir string, netInfo *danmtypes.DanmNet) ([]byte, error) {
func readCniConfigFile(cniconfDir string, netInfo *danmtypes.DanmNet, ipamOptions datastructs.IpamConfig) ([]byte, error) {
cniConfig := netInfo.Spec.NetworkID
rawConfig, err := ioutil.ReadFile(cniconfDir + "/" + cniConfig + ".conf")
if err != nil {
return nil, errors.New("Could not load CNI config file: " + cniConfig +".conf for plugin:" + netInfo.Spec.NetworkType + " from directory:" + cniconfDir)
}
//Only overwrite "ipam" of the static CNI config if user wants
if len(ipamOptions.Ips) > 0 {
genericCniConf := map[string]interface{}{}
err = json.Unmarshal(rawConfig, &genericCniConf)
if err != nil {
return nil, errors.New("could not Unmarshal CNI config file:" + cniConfig + ".conf for plugin: " + netInfo.Spec.NetworkType + ", because:" + err.Error())
}
ipamRaw,_ := json.Marshal(ipamOptions)
ipamInGenericFormat := map[string]interface{}{}
json.Unmarshal(ipamRaw, &ipamInGenericFormat)
genericCniConf["ipam"] = ipamInGenericFormat
rawConfig,_ = json.Marshal(genericCniConf)
}
return rawConfig, nil
}

Expand Down Expand Up @@ -78,7 +91,9 @@ func getMacvlanCniConfig(netInfo *danmtypes.DanmNet, ipamOptions datastructs.Ipa
macvlanConfig.Master = danmep.DetermineHostDeviceName(netInfo)
macvlanConfig.Mode = "bridge" //TODO: make these params configurable if required
macvlanConfig.MTU = 1500
macvlanConfig.Ipam = ipamOptions
if len(ipamOptions.Ips) > 0 {
macvlanConfig.Ipam = ipamOptions
}
rawConfig, err := json.Marshal(macvlanConfig)
if err != nil {
return nil, errors.New("Error putting together CNI config for MACVLAN plugin: " + err.Error())
Expand Down
26 changes: 16 additions & 10 deletions pkg/cnidel/cnidel.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cnidel
import (
"errors"
"log"
"net"
"os"
"strconv"
"strings"
Expand Down Expand Up @@ -47,7 +48,7 @@ func DelegateInterfaceSetup(netConf *datastructs.NetConf, danmClient danmclients
err error
ipamOptions datastructs.IpamConfig
)
if isIpamNeeded(netInfo.Spec.NetworkType) {
if isIpamNeeded(netInfo, ep) {
ep.Spec.Iface.Address, ep.Spec.Iface.AddressIPv6, _, err = ipam.Reserve(danmClient, *netInfo, ep.Spec.Iface.Address, ep.Spec.Iface.AddressIPv6)
if err != nil {
return nil, errors.New("IP address reservation failed for network:" + netInfo.ObjectMeta.Name + " with error:" + err.Error())
Expand Down Expand Up @@ -83,12 +84,16 @@ func DelegateInterfaceSetup(netConf *datastructs.NetConf, danmClient danmclients
return cniResult, nil
}

func isIpamNeeded(cniType string) bool {
if cni, ok := SupportedNativeCnis[strings.ToLower(cniType)]; ok {
func isIpamNeeded(netInfo *danmtypes.DanmNet, ep *danmtypes.DanmEp) bool {
if cni, ok := SupportedNativeCnis[strings.ToLower(netInfo.Spec.NetworkType)]; ok {
return cni.ipamNeeded
} else {
return false
}
//For static delegates we should only overwrite the original IPAM if both the network is L3, and IP was requested from the Pod
if (ep.Spec.Iface.Address != "" && netInfo.Spec.Options.Cidr != "" ) ||
(ep.Spec.Iface.AddressIPv6 != "" && netInfo.Spec.Options.Net6 != "" ) {
return true
}
return false
}

func IsDeviceNeeded(cniType string) bool {
Expand All @@ -101,9 +106,6 @@ func IsDeviceNeeded(cniType string) bool {

func getCniIpamConfig(netinfo *danmtypes.DanmNet, ip4, ip6 string) (datastructs.IpamConfig, error) {
var ipSlice = []datastructs.IpamIp{}
if ip4 == "" && ip6 == "" && netinfo.Spec.NetworkType != "sriov" {
return datastructs.IpamConfig{}, errors.New("unfortunetaly 3rd party CNI plugins usually don't support foregoing putting any IPs on an interface, so with heavy hearts but we need to fail this network delegation operation")
}
if ip4 != "" {
ipSlice = append(ipSlice, datastructs.IpamIp{
IpCidr: ip4,
Expand All @@ -126,7 +128,7 @@ func getCniPluginConfig(netConf *datastructs.NetConf, netInfo *danmtypes.DanmNet
if cni, ok := SupportedNativeCnis[strings.ToLower(netInfo.Spec.NetworkType)]; ok {
return cni.readConfig(netInfo, ipamOptions, ep, cni.CNIVersion)
} else {
return readCniConfigFile(netConf.CniConfigDir, netInfo)
return readCniConfigFile(netConf.CniConfigDir, netInfo, ipamOptions)
}
}

Expand Down Expand Up @@ -212,7 +214,11 @@ func freeDelegatedIp(danmClient danmclientset.Interface, netInfo *danmtypes.Danm
if netInfo.Spec.NetworkType == "flannel" && ip != ""{
flannelIpExhaustionWorkaround(ip)
}
if isIpamNeeded(netInfo.Spec.NetworkType) && ip != "" {
_, v4Subnet, _ := net.ParseCIDR(netInfo.Spec.Options.Cidr)
_, v6Subnet, _ := net.ParseCIDR(netInfo.Spec.Options.Net6)
parsedIp := net.ParseIP(ip)
//We only need to Free an IP if it was allocated by DANM IPAM, and it was allocated by DANM only if it falls into any of the defined subnets
if parsedIp != nil && ((v4Subnet != nil && v4Subnet.Contains(parsedIp)) || (v6Subnet != nil && v6Subnet.Contains(parsedIp))) {
err := ipam.Free(danmClient, *netInfo, ip)
if err != nil {
return errors.New("cannot give back ip address: " + ip + " for network:" + netInfo.ObjectMeta.Name +
Expand Down
2 changes: 1 addition & 1 deletion test/uts/cnidel_test/cnidel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ var expectedCniConfigs = []CniConf {
{"sriov-l3", []byte(`{"cniexp":{"cnitype":"sriov","ip":"192.168.1.65/26","env":{"CNI_COMMAND":"ADD","CNI_IFNAME":"eth0"}},"cniconf":{"cniVersion":"0.3.1","name":"sriov-test","type":"sriov","master":"enp175s0f1","l2enable":false,"vlan":500,"deviceID":"0000:af:06.0","ipam":{"type":"fakeipam","ips":[{"ipcidr":"192.168.1.65/26","version":4}]}}}`)},
{"sriov-l2", []byte(`{"cniexp":{"cnitype":"sriov","env":{"CNI_COMMAND":"ADD","CNI_IFNAME":"eth0"}},"cniconf":{"cniVersion":"0.3.1","name":"sriov-test","type":"sriov","master":"enp175s0f1","l2enable":true,"vlan":500,"deviceID":"0000:af:06.0"}}`)},
{"deleteflannel", []byte(`{"cniexp":{"cnitype":"flannel","env":{"CNI_COMMAND":"DEL","CNI_IFNAME":"eth0"}},"cniconf":{"name":"cbr0","type":"flannel","delegate":{"hairpinMode":true,"isDefaultGateway":true}}}`)},
{"deletemacvlan", []byte(`{"cniexp":{"cnitype":"macvlan","env":{"CNI_COMMAND":"DEL","CNI_IFNAME":"ens1f0"}},"cniconf":{"cniVersion":"0.3.1","master":"ens1f0","mode":"bridge","mtu":1500,"ipam":{"type":"fakeipam"}}}`)},
{"deletemacvlan", []byte(`{"cniexp":{"cnitype":"macvlan","env":{"CNI_COMMAND":"DEL","CNI_IFNAME":"ens1f0"}},"cniconf":{"cniVersion":"0.3.1","master":"ens1f0","mode":"bridge","mtu":1500}}`)},
}

var testCniConfFiles = []CniConf {
Expand Down

0 comments on commit 24a639c

Please sign in to comment.