diff --git a/pkg/compute/models/guestnetworks.go b/pkg/compute/models/guestnetworks.go index 2d9efe5360..70ecc9426e 100644 --- a/pkg/compute/models/guestnetworks.go +++ b/pkg/compute/models/guestnetworks.go @@ -26,6 +26,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/netutils" "yunion.io/x/pkg/util/regutils" "yunion.io/x/sqlchemy" @@ -151,7 +152,7 @@ func (manager *SGuestnetworkManager) GenerateMac(netId string, suggestion string func (manager *SGuestnetworkManager) newGuestNetwork(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest, network *SNetwork, index int8, address string, mac string, driver string, bwLimit int, virtual bool, reserved bool, - allocDir api.IPAllocationDirection, requiredDesignatedIp bool, ifName string, teamWithMac string) (*SGuestnetwork, error) { + allocDir api.IPAllocationDirection, requiredDesignatedIp bool, ifname string, teamWithMac string) (*SGuestnetwork, error) { gn := SGuestnetwork{} gn.SetModelManager(GuestnetworkManager, &gn) @@ -192,17 +193,11 @@ func (manager *SGuestnetworkManager) newGuestNetwork(ctx context.Context, userCr } gn.IpAddr = ipAddr } - ifTable := network.GetUsedIfnames() - if len(ifName) > 0 { - if _, ok := ifTable[ifName]; ok { - ifName = "" - log.Infof("ifname %s has been used, to release ...", ifName) - } + ifname, err = gn.checkOrAllocateIfname(network, ifname) + if err != nil { + return nil, err } - if len(ifName) == 0 { - ifName = gn.GetFreeIfname(network, ifTable) - } - gn.Ifname = ifName + gn.Ifname = ifname gn.TeamWith = teamWithMac err = manager.TableSpec().Insert(&gn) if err != nil { @@ -238,21 +233,38 @@ func (self *SGuestnetwork) generateIfname(network *SNetwork, virtual bool, rando } } -func (self *SGuestnetwork) GetFreeIfname(network *SNetwork, ifTable map[string]bool) string { - ifname := self.generateIfname(network, self.Virtual, false) - if _, exist := ifTable[ifname]; exist { - if !self.Virtual { - ifname = self.generateIfname(network, true, false) - } - for { - if _, exist = ifTable[ifname]; exist { - ifname = self.generateIfname(network, true, true) - } else { - break - } - } +func (man *SGuestnetworkManager) ifnameUsed(ifname string) bool { + count, err := GuestnetworkManager.Query().Equals("ifname", ifname).CountWithError() + if err != nil { + panic(errors.Wrap(err, "query if ifname is used")) } - return ifname + return count > 0 +} + +func (self *SGuestnetwork) checkOrAllocateIfname(network *SNetwork, preferIfname string) (string, error) { + man := GuestnetworkManager + if !man.ifnameUsed(preferIfname) { + return preferIfname, nil + } + ifname := self.generateIfname(network, self.Virtual, false) + if !man.ifnameUsed(ifname) { + return ifname, nil + } + if !self.Virtual { + ifname = self.generateIfname(network, true, false) + } + found := false + for i := 0; i < 5; i++ { + if !man.ifnameUsed(ifname) { + found = true + break + } + ifname = self.generateIfname(network, true, true) + } + if !found { + return "", httperrors.NewConflictError("cannot allocate ifname") + } + return ifname, nil } func (self *SGuestnetwork) GetGuest() *SGuest { diff --git a/pkg/compute/models/networks.go b/pkg/compute/models/networks.go index c8260cb16d..06a6b711ed 100644 --- a/pkg/compute/models/networks.go +++ b/pkg/compute/models/networks.go @@ -389,28 +389,6 @@ func (self *SNetwork) GetFreeIP(ctx context.Context, userCred mcclient.TokenCred return cand, nil } -func (self *SNetwork) GetUsedIfnames() map[string]bool { - used := make(map[string]bool) - tbl := GuestnetworkManager.Query().SubQuery() - q := tbl.Query(tbl.Field("ifname")).Equals("network_id", self.Id) - rows, err := q.Rows() - if err != nil { - log.Errorf("GetUsedIfnames query fail: %s", err) - return nil - } - defer rows.Close() - for rows.Next() { - var ifname string - err = rows.Scan(&ifname) - if err != nil { - log.Errorf("GetUsedIfnames scan fail: %s", err) - return nil - } - used[ifname] = true - } - return used -} - func (self *SNetwork) GetNetAddr() netutils.IPV4Addr { startIp, _ := netutils.NewIPV4Addr(self.GuestIpStart) return startIp.NetAddr(self.GuestIpMask)