// IsAciConfigured returns true if aci is configured on netmaster. func IsAciConfigured() (res bool, err error) { // Get the state driver stateDriver, uErr := utils.GetStateDriver() if uErr != nil { log.Warnf("Couldn't read global config %v", uErr) return false, uErr } // read global config masterGc := &mastercfg.GlobConfig{} masterGc.StateDriver = stateDriver uErr = masterGc.Read("config") if core.ErrIfKeyExists(uErr) != nil { log.Errorf("Couldn't read global config %v", uErr) return false, uErr } if uErr != nil { log.Warnf("Couldn't read global config %v", uErr) return false, nil } if masterGc.NwInfraType != "aci" { log.Debugf("NwInfra type is %v, no ACI", masterGc.NwInfraType) return false, nil } return true, nil }
func createContainerEpOper(netPlugin *plugin.NetPlugin, contUUID, contName string) error { epIDs, err := getEpIDByContainerName(netPlugin, contName) if err != nil { log.Debugf("unable to find ep for container %s, error %v\n", contName, err) return err } for _, epID := range epIDs { operEp := &drivers.OvsOperEndpointState{} operEp.StateDriver = netPlugin.StateDriver err = operEp.Read(epID) if core.ErrIfKeyExists(err) != nil { return err } if err == nil { operEp.ContUUID = contUUID err = operEp.Write() if err != nil { log.Errorf("error updating oper state for ep %s \n", contName) return err } log.Infof("updating container '%s' with id '%s' \n", contName, contUUID) } else { err = netPlugin.CreateEndpoint(epID) if err != nil { log.Errorf("Endpoint creation failed. Error: %s", err) return err } log.Infof("Endpoint operation create succeeded") } } return err }
// Init initializes the OVS driver. func (d *OvsDriver) Init(config *core.Config, info *core.InstanceInfo) error { if config == nil || info == nil || info.StateDriver == nil { return core.Errorf("Invalid arguments. cfg: %+v, instance-info: %+v", config, info) } _, ok := config.V.(*OvsDriverConfig) if !ok { return core.Errorf("Invalid type passed") } d.oper.StateDriver = info.StateDriver d.localIP = info.VtepIP // restore the driver's runtime state if it exists err := d.oper.Read(info.HostLabel) if core.ErrIfKeyExists(err) != nil { log.Printf("Failed to read driver oper state for key %q. Error: %s", info.HostLabel, err) return err } else if err != nil { // create the oper state as it is first time start up d.oper.ID = info.HostLabel d.oper.CurrPortNum = 0 err = d.oper.Write() if err != nil { return err } } log.Infof("Initializing ovsdriver") // Init switch DB d.switchDb = make(map[string]*OvsSwitch) // Create Vxlan switch d.switchDb["vxlan"], err = NewOvsSwitch(vxlanBridgeName, "vxlan", info.VtepIP, info.FwdMode) if err != nil { log.Fatalf("Error creating vlan switch. Err: %v", err) } // Create Vlan switch d.switchDb["vlan"], err = NewOvsSwitch(vlanBridgeName, "vlan", info.VtepIP, info.FwdMode, info.VlanIntf) if err != nil { log.Fatalf("Error creating vlan switch. Err: %v", err) } // Add uplink to VLAN switch if info.VlanIntf != "" { err = d.switchDb["vlan"].AddUplinkPort(info.VlanIntf) if err != nil { log.Errorf("Could not add uplink %s to vlan OVS. Err: %v", info.VlanIntf, err) } } return nil }
// The following function derives the number of available vlan tags. // XXX: Since it is run at netmaster, it is guaranteed to have a consistent view of // resource usage. Revisit if this assumption changes, as then it might need to // be moved to resource-manager func deriveAvailableVLANs(stateDriver core.StateDriver) (*bitset.BitSet, error) { // available vlans = vlan-space - For each tenant (vlans + local-vxlan-vlans) availableVLANs := netutils.CreateBitset(12) // get all vlans readVLANRsrc := &resources.AutoVLANCfgResource{} readVLANRsrc.StateDriver = stateDriver vlanRsrcs, err := readVLANRsrc.ReadAll() if core.ErrIfKeyExists(err) != nil { return nil, err } else if err != nil { vlanRsrcs = []core.State{} } for _, rsrc := range vlanRsrcs { cfg := rsrc.(*resources.AutoVLANCfgResource) availableVLANs = availableVLANs.Union(cfg.VLANs) } //get all vxlan-vlans readVXLANRsrc := &resources.AutoVXLANCfgResource{} readVXLANRsrc.StateDriver = stateDriver vxlanRsrcs, err := readVXLANRsrc.ReadAll() if core.ErrIfKeyExists(err) != nil { return nil, err } else if err != nil { vxlanRsrcs = []core.State{} } for _, rsrc := range vxlanRsrcs { cfg := rsrc.(*resources.AutoVXLANCfgResource) availableVLANs = availableVLANs.Union(cfg.LocalVLANs) } // subtract to get availableVLANs availableVLANs = availableVLANs.Complement() clearReservedVLANs(availableVLANs) return availableVLANs, nil }
// AssignDefaultNetwork assigns a default network for a tenant based on the configuration // in case configuration is absent it uses the provided network name to be the default // network. It records the default network in oper state (derived or configured) func (gc *Cfg) AssignDefaultNetwork(networkName string) (string, error) { g := &Oper{} g.StateDriver = gc.StateDriver if err := g.Read(""); core.ErrIfKeyExists(err) != nil { return "", err } if g.DefaultNetwork != "" { return "", nil } // not checking if this network exists within a tenant g.DefaultNetwork = networkName if err := g.Write(); err != nil { log.Errorf("error '%s' updating goper state %v \n", err, g) return "", err } return g.DefaultNetwork, nil }
// UnassignNetwork clears the oper state w.r.t. default network name func (gc *Cfg) UnassignNetwork(networkName string) error { if networkName == "" { return nil } g := &Oper{} g.StateDriver = gc.StateDriver if err := g.Read(""); core.ErrIfKeyExists(err) != nil { return err } if networkName == g.DefaultNetwork { g.DefaultNetwork = "" if err := g.Write(); err != nil { log.Errorf("error '%s' updating goper state %v \n", err, g) return err } } return nil }
// XXX: It might be better to keep cache of resources and avoid frequent etcd reads func (rm *StateResourceManager) findResource(id, desc string) (core.Resource, bool, error) { alreadyExists := false rsrcType, ok := resourceRegistry[desc] if !ok { return nil, alreadyExists, core.Errorf("No resource found for description: %q", desc) } val := reflect.New(rsrcType) // sanity checks if !val.Elem().FieldByName("CommonState").IsValid() { return nil, false, core.Errorf("The state structure %v is missing core.CommonState", rsrcType) } //the following works as every core.State is expected to embed core.CommonState struct val.Elem().FieldByName("CommonState").FieldByName("StateDriver").Set(reflect.ValueOf(rm.stateDriver)) val.Elem().FieldByName("CommonState").FieldByName("ID").Set(reflect.ValueOf(id)) rsrc := val.Interface().(core.Resource) rsrcs, err := rsrc.ReadAll() if core.ErrIfKeyExists(err) != nil { return nil, alreadyExists, err } else if err != nil { // set the slice as empty in case of 'key not found' error rsrcs = []core.State{} } for _, r := range rsrcs { //the following works as every core.State is expected to embed core.CommonState struct cs := reflect.ValueOf(r).Elem().FieldByName("CommonState").Interface().(core.CommonState) if cs.ID == id { alreadyExists = true return r.(core.Resource), alreadyExists, nil } } return rsrc, alreadyExists, nil }
// DeleteDelta deletes any existing configuration from netmaster's statestore // that is not present in the configuration passed. This may result in // generating Delete triggers for the netplugin func DeleteDelta(allCfg *intent.Config) error { stateDriver, err := utils.GetStateDriver() if err != nil { return err } readEp := &mastercfg.CfgEndpointState{} readEp.StateDriver = stateDriver epCfgs, err := readEp.ReadAll() if core.ErrIfKeyExists(err) != nil { return err } else if err != nil { err = nil epCfgs = []core.State{} } for _, epCfg := range epCfgs { cfg := epCfg.(*mastercfg.CfgEndpointState) if !epPresent(allCfg, cfg.ID) { _, err1 := DeleteEndpointID(stateDriver, cfg.ID) if err1 != nil { log.Errorf("error '%s' deleting epid %s \n", err1, cfg.ID) err = err1 continue } } } readNet := &mastercfg.CfgNetworkState{} readNet.StateDriver = stateDriver nwCfgs, err := readNet.ReadAll() if core.ErrIfKeyExists(err) != nil { return err } else if err != nil { err = nil nwCfgs = []core.State{} } for _, nwCfg := range nwCfgs { cfg := nwCfg.(*mastercfg.CfgNetworkState) if !netPresent(allCfg, cfg.ID) { err1 := DeleteNetworkID(stateDriver, cfg.ID) if err1 != nil { log.Errorf("error '%s' deleting net %s \n", err1, cfg.ID) err = err1 continue } } } readGlbl := &gstate.Cfg{} readGlbl.StateDriver = stateDriver gCfgs, err := readGlbl.ReadAll() if core.ErrIfKeyExists(err) != nil { return err } else if err != nil { err = nil gCfgs = []core.State{} } for _, gCfg := range gCfgs { cfg := gCfg.(*gstate.Cfg) if !tenantPresent(allCfg, cfg.Tenant) { err1 := DeleteTenantID(stateDriver, cfg.Tenant) if err1 != nil { log.Errorf("error '%s' deleting tenant %s \n", err1, cfg.Tenant) err = err1 continue } } } return err }
// CreateEndpoint creates an endpoint by named identifier func (d *OvsDriver) CreateEndpoint(id string) error { var ( err error intfName string epgKey string epgBandwidth int64 dscp int ) cfgEp := &mastercfg.CfgEndpointState{} cfgEp.StateDriver = d.oper.StateDriver err = cfgEp.Read(id) if err != nil { return err } // Get the nw config. cfgNw := mastercfg.CfgNetworkState{} cfgNw.StateDriver = d.oper.StateDriver err = cfgNw.Read(cfgEp.NetID) if err != nil { log.Errorf("Unable to get network %s. Err: %v", cfgEp.NetID, err) return err } pktTagType := cfgNw.PktTagType pktTag := cfgNw.PktTag cfgEpGroup := &mastercfg.EndpointGroupState{} // Read pkt tags from endpoint group if available if cfgEp.EndpointGroupKey != "" { cfgEpGroup.StateDriver = d.oper.StateDriver err = cfgEpGroup.Read(cfgEp.EndpointGroupKey) if err == nil { log.Debugf("pktTag: %v ", cfgEpGroup.PktTag) pktTagType = cfgEpGroup.PktTagType pktTag = cfgEpGroup.PktTag epgKey = cfgEp.EndpointGroupKey dscp = cfgEpGroup.DSCP log.Infof("Received endpoint create with bandwidth:%s", cfgEpGroup.Bandwidth) if cfgEpGroup.Bandwidth != "" { epgBandwidth = netutils.ConvertBandwidth(cfgEpGroup.Bandwidth) } } else if core.ErrIfKeyExists(err) == nil { log.Infof("EPG %s not found: %v. will use network based tag ", cfgEp.EndpointGroupKey, err) } else { return err } } // Find the switch based on network type var sw *OvsSwitch if pktTagType == "vxlan" { sw = d.switchDb["vxlan"] } else { sw = d.switchDb["vlan"] } // Skip Veth pair creation for infra nw endpoints skipVethPair := (cfgNw.NwType == "infra") operEp := &OvsOperEndpointState{} operEp.StateDriver = d.oper.StateDriver err = operEp.Read(id) if core.ErrIfKeyExists(err) != nil { return err } else if err == nil { // check if oper state matches cfg state. In case of mismatch cleanup // up the EP and continue add new one. In case of match just return. if operEp.Matches(cfgEp) { log.Printf("Found matching oper state for ep %s, noop", id) // Ask the switch to update the port err = sw.UpdatePort(operEp.PortName, cfgEp, pktTag, cfgNw.PktTag, dscp, skipVethPair) if err != nil { log.Errorf("Error creating port %s. Err: %v", intfName, err) return err } return nil } log.Printf("Found mismatching oper state for Ep, cleaning it. Config: %+v, Oper: %+v", cfgEp, operEp) d.DeleteEndpoint(operEp.ID) } if cfgNw.NwType == "infra" { // For infra nw, port name is network name intfName = cfgNw.NetworkName } else { // Get the interface name to use intfName, err = d.getIntfName() if err != nil { return err } } // Get OVS port name ovsPortName := getOvsPortName(intfName, skipVethPair) // Ask the switch to create the port err = sw.CreatePort(intfName, cfgEp, pktTag, cfgNw.PktTag, cfgEpGroup.Burst, dscp, skipVethPair, epgBandwidth) if err != nil { log.Errorf("Error creating port %s. Err: %v", intfName, err) return err } // save local endpoint info d.oper.localEpInfoMutex.Lock() d.oper.LocalEpInfo[id] = &EpInfo{ Ovsportname: ovsPortName, EpgKey: epgKey, BridgeType: pktTagType, } d.oper.localEpInfoMutex.Unlock() err = d.oper.Write() if err != nil { return err } // Save the oper state operEp = &OvsOperEndpointState{ NetID: cfgEp.NetID, EndpointID: cfgEp.EndpointID, ServiceName: cfgEp.ServiceName, IPAddress: cfgEp.IPAddress, MacAddress: cfgEp.MacAddress, IntfName: cfgEp.IntfName, PortName: intfName, HomingHost: cfgEp.HomingHost, VtepIP: cfgEp.VtepIP} operEp.StateDriver = d.oper.StateDriver operEp.ID = id err = operEp.Write() if err != nil { return err } defer func() { if err != nil { operEp.Clear() } }() return nil }
// Init initializes the OVS driver. func (d *OvsDriver) Init(info *core.InstanceInfo) error { if info == nil || info.StateDriver == nil { return core.Errorf("Invalid arguments. instance-info: %+v", info) } d.oper.StateDriver = info.StateDriver d.localIP = info.VtepIP // restore the driver's runtime state if it exists err := d.oper.Read(info.HostLabel) if core.ErrIfKeyExists(err) != nil { log.Errorf("Failed to read driver oper state for key %q. Error: %s", info.HostLabel, err) return err } else if err != nil { // create the oper state as it is first time start up d.oper.ID = info.HostLabel d.oper.CurrPortNum = 0 // create local endpoint info map d.oper.LocalEpInfo = make(map[string]*EpInfo) // write the oper err = d.oper.Write() if err != nil { return err } } // make sure LocalEpInfo exists if d.oper.LocalEpInfo == nil { d.oper.LocalEpInfo = make(map[string]*EpInfo) // write the oper err = d.oper.Write() if err != nil { return err } } log.Infof("Initializing ovsdriver") // Init switch DB d.switchDb = make(map[string]*OvsSwitch) // Create Vxlan switch d.switchDb["vxlan"], err = NewOvsSwitch(vxlanBridgeName, "vxlan", info.VtepIP, info.FwdMode) if err != nil { log.Fatalf("Error creating vlan switch. Err: %v", err) } // Create Vlan switch d.switchDb["vlan"], err = NewOvsSwitch(vlanBridgeName, "vlan", info.VtepIP, info.FwdMode, info.VlanIntf) if err != nil { log.Fatalf("Error creating vlan switch. Err: %v", err) } // Add uplink to VLAN switch if info.VlanIntf != "" { err = d.switchDb["vlan"].AddUplinkPort(info.VlanIntf) if err != nil { log.Errorf("Could not add uplink %s to vlan OVS. Err: %v", info.VlanIntf, err) } } // Create Host Access switch d.switchDb["host"], err = NewOvsSwitch(hostBridgeName, "host", info.VtepIP, info.FwdMode) if err != nil { log.Fatalf("Error creating host switch. Err: %v", err) } if maxPortNum > 0xfffe { log.Fatalf("Host bridge logic assumes maxPortNum <= 0xfffe") } // Add host port. err = d.switchDb["host"].AddHostPort(hostPortName, maxPortNum, true) if err != nil { log.Errorf("Could not add host port %s to OVS. Err: %v", hostPortName, err) } // Add a masquerade rule to ip tables. netutils.SetIPMasquerade(hostPortName, hostPvtSubnet) // Initialize the node proxy d.HostProxy, err = NewNodeProxy() return err }
// CreateEndpoint creates an endpoint by named identifier func (d *OvsDriver) CreateEndpoint(id string) error { var ( err error intfName string ) cfgEp := &mastercfg.CfgEndpointState{} cfgEp.StateDriver = d.oper.StateDriver err = cfgEp.Read(id) if err != nil { return err } // Ignore VTEP endpoints and uplink endpoints // FIXME: we need to stop publiching these from netmaster if cfgEp.VtepIP != "" { return nil } if cfgEp.IntfName != "" { return nil } cfgEpGroup := &mastercfg.EndpointGroupState{} cfgEpGroup.StateDriver = d.oper.StateDriver err = cfgEpGroup.Read(strconv.Itoa(cfgEp.EndpointGroupID)) if err == nil { log.Debugf("pktTag: %v ", cfgEpGroup.PktTag) } else if core.ErrIfKeyExists(err) == nil { // FIXME: this should be deprecated once we remove old style intent // In case EpGroup is not specified, get the tag from nw. // this is mainly for the intent based system tests log.Warnf("%v will use network based tag ", err) cfgNw := mastercfg.CfgNetworkState{} cfgNw.StateDriver = d.oper.StateDriver err1 := cfgNw.Read(cfgEp.NetID) if err1 != nil { log.Errorf("Unable to get tag neither epg nor nw") return err1 } cfgEpGroup.PktTagType = cfgNw.PktTagType cfgEpGroup.PktTag = cfgNw.PktTag } else { return err } // Find the switch based on network type var sw *OvsSwitch if cfgEpGroup.PktTagType == "vxlan" { sw = d.switchDb["vxlan"] } else { sw = d.switchDb["vlan"] } operEp := &OvsOperEndpointState{} operEp.StateDriver = d.oper.StateDriver err = operEp.Read(id) if core.ErrIfKeyExists(err) != nil { return err } else if err == nil { // check if oper state matches cfg state. In case of mismatch cleanup // up the EP and continue add new one. In case of match just return. if operEp.Matches(cfgEp) { log.Printf("Found matching oper state for ep %s, noop", id) // Ask the switch to update the port err = sw.UpdatePort(operEp.PortName, cfgEp, cfgEpGroup.PktTag) if err != nil { log.Errorf("Error creating port %s. Err: %v", intfName, err) return err } return nil } log.Printf("Found mismatching oper state for Ep, cleaning it. Config: %+v, Oper: %+v", cfgEp, operEp) d.DeleteEndpoint(operEp.ID) } // add an internal ovs port with vlan-tag information from the state // XXX: revisit, the port name might need to come from user. Also revisit // the algorithm to take care of port being deleted and reuse unused port // numbers d.oper.CurrPortNum++ err = d.oper.Write() if err != nil { return err } intfName = d.getIntfName() // Ask the switch to create the port err = sw.CreatePort(intfName, cfgEp, cfgEpGroup.PktTag) if err != nil { log.Errorf("Error creating port %s. Err: %v", intfName, err) return err } // Save the oper state operEp = &OvsOperEndpointState{ NetID: cfgEp.NetID, AttachUUID: cfgEp.AttachUUID, ContName: cfgEp.ContName, ServiceName: cfgEp.ServiceName, IPAddress: cfgEp.IPAddress, MacAddress: cfgEp.MacAddress, IntfName: cfgEp.IntfName, PortName: intfName, HomingHost: cfgEp.HomingHost, VtepIP: cfgEp.VtepIP} operEp.StateDriver = d.oper.StateDriver operEp.ID = id err = operEp.Write() if err != nil { return err } defer func() { if err != nil { operEp.Clear() } }() return nil }
// CreateEndpoint creates an endpoint by named identifier func (d *OvsDriver) CreateEndpoint(id string) error { var ( err error intfName string ) cfgEp := &mastercfg.CfgEndpointState{} cfgEp.StateDriver = d.oper.StateDriver err = cfgEp.Read(id) if err != nil { return err } // Get the nw config. cfgNw := mastercfg.CfgNetworkState{} cfgNw.StateDriver = d.oper.StateDriver err = cfgNw.Read(cfgEp.NetID) if err != nil { log.Errorf("Unable to get network %s. Err: %v", cfgEp.NetID, err) return err } cfgEpGroup := &mastercfg.EndpointGroupState{} cfgEpGroup.StateDriver = d.oper.StateDriver err = cfgEpGroup.Read(strconv.Itoa(cfgEp.EndpointGroupID)) if err == nil { log.Debugf("pktTag: %v ", cfgEpGroup.PktTag) } else if core.ErrIfKeyExists(err) == nil { log.Infof("%v will use network based tag ", err) cfgEpGroup.PktTagType = cfgNw.PktTagType cfgEpGroup.PktTag = cfgNw.PktTag } else { return err } // Find the switch based on network type var sw *OvsSwitch if cfgEpGroup.PktTagType == "vxlan" { sw = d.switchDb["vxlan"] } else { sw = d.switchDb["vlan"] } operEp := &OvsOperEndpointState{} operEp.StateDriver = d.oper.StateDriver err = operEp.Read(id) if core.ErrIfKeyExists(err) != nil { return err } else if err == nil { // check if oper state matches cfg state. In case of mismatch cleanup // up the EP and continue add new one. In case of match just return. if operEp.Matches(cfgEp) { log.Printf("Found matching oper state for ep %s, noop", id) // Ask the switch to update the port err = sw.UpdatePort(operEp.PortName, cfgEp, cfgEpGroup.PktTag) if err != nil { log.Errorf("Error creating port %s. Err: %v", intfName, err) return err } return nil } log.Printf("Found mismatching oper state for Ep, cleaning it. Config: %+v, Oper: %+v", cfgEp, operEp) d.DeleteEndpoint(operEp.ID) } // Get the interface name to use intfName, err = d.getIntfName() if err != nil { return err } // Ask the switch to create the port err = sw.CreatePort(intfName, cfgEp, cfgEpGroup.PktTag, cfgNw.PktTag) if err != nil { log.Errorf("Error creating port %s. Err: %v", intfName, err) return err } // Save the oper state operEp = &OvsOperEndpointState{ NetID: cfgEp.NetID, AttachUUID: cfgEp.AttachUUID, ContName: cfgEp.ContName, ServiceName: cfgEp.ServiceName, IPAddress: cfgEp.IPAddress, MacAddress: cfgEp.MacAddress, IntfName: cfgEp.IntfName, PortName: intfName, HomingHost: cfgEp.HomingHost, VtepIP: cfgEp.VtepIP} operEp.StateDriver = d.oper.StateDriver operEp.ID = id err = operEp.Write() if err != nil { return err } defer func() { if err != nil { operEp.Clear() } }() return nil }
// CreateEndpoint creates an endpoint by named identifier func (d *OvsDriver) CreateEndpoint(id string) error { var ( err error intfName string intfType string ) cfgEp := &OvsCfgEndpointState{} cfgEp.StateDriver = d.oper.StateDriver err = cfgEp.Read(id) if err != nil { return err } // Ignore VTEP endpoints and uplink endpoints // FIXME: we need to stop publiching these from netmaster if cfgEp.VtepIP != "" { return nil } if cfgEp.IntfName != "" { return nil } cfgNw := OvsCfgNetworkState{} cfgNw.StateDriver = d.oper.StateDriver err = cfgNw.Read(cfgEp.NetID) if err != nil { return err } // Find the switch based on network type var sw *OvsSwitch if cfgNw.PktTagType == "vxlan" { sw = d.switchDb["vxlan"] } else { sw = d.switchDb["vlan"] } operEp := &OvsOperEndpointState{} operEp.StateDriver = d.oper.StateDriver err = operEp.Read(id) if core.ErrIfKeyExists(err) != nil { return err } else if err == nil { // check if oper state matches cfg state. In case of mismatch cleanup // up the EP and continue add new one. In case of match just return. if operEp.Matches(cfgEp) { log.Printf("Found matching oper state for ep %s, noop", id) // Ask the switch to update the port err = sw.UpdatePort(operEp.PortName, cfgEp, cfgNw.PktTag) if err != nil { log.Errorf("Error creating port %s. Err: %v", intfName, err) return err } return nil } log.Printf("Found mismatching oper state for Ep, cleaning it. Config: %+v, Oper: %+v", cfgEp, operEp) d.DeleteEndpoint(operEp.ID) } // add an internal ovs port with vlan-tag information from the state // XXX: revisit, the port name might need to come from user. Also revisit // the algorithm to take care of port being deleted and reuse unused port // numbers d.oper.CurrPortNum++ err = d.oper.Write() if err != nil { return err } intfName = d.getIntfName() intfType = "internal" // Ask the switch to create the port err = sw.CreatePort(intfName, intfType, cfgEp, cfgNw.PktTag) if err != nil { log.Errorf("Error creating port %s. Err: %v", intfName, err) return err } // Save the oper state operEp = &OvsOperEndpointState{ NetID: cfgEp.NetID, AttachUUID: cfgEp.AttachUUID, ContName: cfgEp.ContName, IPAddress: cfgEp.IPAddress, MacAddress: cfgEp.MacAddress, IntfName: cfgEp.IntfName, PortName: intfName, HomingHost: cfgEp.HomingHost, VtepIP: cfgEp.VtepIP} operEp.StateDriver = d.oper.StateDriver operEp.ID = id err = operEp.Write() if err != nil { return err } defer func() { if err != nil { operEp.Clear() } }() return nil }