From 70fbfe89465a7afd446f1ce9b2cc956bf58e9a61 Mon Sep 17 00:00:00 2001 From: Jian Qiu Date: Thu, 19 Mar 2026 17:36:29 +0000 Subject: [PATCH] feature: support host-local wire (#24490) Co-authored-by: Qiu Jian --- pkg/apis/compute/host_tap.go | 5 +- pkg/apis/compute/wire_const.go | 3 + pkg/compute/models/capabilities.go | 29 ++++--- pkg/compute/models/guestnetworks.go | 12 +++ pkg/compute/models/hosts.go | 31 ++++++- pkg/compute/models/initdb.go | 3 +- pkg/compute/models/networks.go | 69 +++++++++++---- pkg/compute/models/vpcs.go | 2 + pkg/compute/models/wireresource.go | 22 ++++- pkg/compute/models/wires.go | 43 ++++++++++ pkg/hostman/guestman/qemu-kvm.go | 6 +- pkg/hostman/hostinfo/finalize_network.go | 67 +++++++++++---- pkg/hostman/hostinfo/hostbridge/hostbridge.go | 62 ++++++++++++-- pkg/hostman/hostinfo/hostbridge/ovs.go | 3 + pkg/hostman/hostinfo/hostinfo.go | 14 ++- pkg/hostman/hostinfo/hostinfohelper.go | 18 +++- pkg/hostman/options/options.go | 16 ++++ pkg/mcclient/options/compute/network.go | 2 +- .../algorithm/predicates/network_predicate.go | 11 ++- pkg/scheduler/cache/candidate/base.go | 85 +++++++++++-------- pkg/util/netutils2/netutils.go | 15 +++- 21 files changed, 409 insertions(+), 109 deletions(-) diff --git a/pkg/apis/compute/host_tap.go b/pkg/apis/compute/host_tap.go index f70fbdaced..6c81d729f6 100644 --- a/pkg/apis/compute/host_tap.go +++ b/pkg/apis/compute/host_tap.go @@ -15,8 +15,9 @@ package compute const ( - HostVpcBridge = "__vpc_bridge__" - HostTapBridge = "__tap_bridge__" + HostVpcBridge = "__vpc_bridge__" + HostTapBridge = "__tap_bridge__" + HostLocalBridge = "brlocal" ) type SMirrorConfig struct { diff --git a/pkg/apis/compute/wire_const.go b/pkg/apis/compute/wire_const.go index 7b8d5c6f62..270d23dad2 100644 --- a/pkg/apis/compute/wire_const.go +++ b/pkg/apis/compute/wire_const.go @@ -21,4 +21,7 @@ const ( WIRE_STATUS_READY_DEPRECATED = "ready" WIRE_STATUS_MERGE_NETWORK = "merge_network" WIRE_STATUS_MERGE_NETWORK_FAILED = "merge_network_failed" + + DEFAULT_HOST_LOCAL_WIRE_NAME = "hostlocal" + DEFAULT_HOST_LOCAL_WIRE_ID = "__host_local__" ) diff --git a/pkg/compute/models/capabilities.go b/pkg/compute/models/capabilities.go index e6d587051d..21d6bbb5f3 100644 --- a/pkg/compute/models/capabilities.go +++ b/pkg/compute/models/capabilities.go @@ -1032,22 +1032,25 @@ func getNetworkCountByFilter(ctx context.Context, userCred mcclient.TokenCredent q := networks.Query() - if zone != nil && !utils.IsInStringArray(region.Provider, api.REGIONAL_NETWORK_PROVIDERS) { - wires := WireManager.Query("id").Equals("zone_id", zone.Id) - q = q.In("wire_id", wires.SubQuery()) - } else if region != nil { - if utils.IsInStringArray(region.Provider, api.REGIONAL_NETWORK_PROVIDERS) { - wires := WireManager.Query().SubQuery() - vpcs := VpcManager.Query().SubQuery() - subq := wires.Query(wires.Field("id")). - Join(vpcs, sqlchemy.Equals(wires.Field("vpc_id"), vpcs.Field("id"))). - Filter(sqlchemy.Equals(vpcs.Field("cloudregion_id"), region.Id)) - q = q.Filter(sqlchemy.In(q.Field("wire_id"), subq)) + if zone != nil || region != nil { + wires := WireManager.Query("id") + var zoneFilter sqlchemy.ICondition + if zone != nil { + zoneFilter = sqlchemy.Equals(wires.Field("zone_id"), zone.Id) } else { subq := getRegionZoneSubq(region) - wires := WireManager.Query("id").In("zone_id", subq) - q = q.In("wire_id", wires.SubQuery()) + zoneFilter = sqlchemy.In(wires.Field("zone_id"), subq) } + vpcs := VpcManager.Query().SubQuery() + wires = wires.Join(vpcs, sqlchemy.Equals(wires.Field("vpc_id"), vpcs.Field("id"))) + wires = wires.Filter(sqlchemy.OR( + zoneFilter, + sqlchemy.AND( + sqlchemy.IsNullOrEmpty(wires.Field("zone_id")), + sqlchemy.Equals(vpcs.Field("cloudregion_id"), region.Id), + ), + )) + q = q.In("wire_id", wires.SubQuery()) } q = NetworkManager.FilterByOwner(ctx, q, NetworkManager, userCred, ownerId, scope) diff --git a/pkg/compute/models/guestnetworks.go b/pkg/compute/models/guestnetworks.go index a3f6106a3a..83f85f9fd9 100644 --- a/pkg/compute/models/guestnetworks.go +++ b/pkg/compute/models/guestnetworks.go @@ -580,8 +580,13 @@ func (gn *SGuestnetwork) getJsonDescAtHost(ctx context.Context, host *SHost) *ap network, _ = gn.GetNetwork() ) if network.isOneCloudVpcNetwork() { + // onecloud vpc nic ret = gn.getJsonDescOneCloudVpc(network) + } else if network.WireId == api.DEFAULT_HOST_LOCAL_WIRE_ID { + // host local nic + ret = gn.getJsonDescHostLocal(network) } else { + // classic nic netifs := host.getNetifsOnWire(network.WireId) var netif *SNetInterface for i := range netifs { @@ -659,6 +664,13 @@ func (gn *SGuestnetwork) getJsonDescOneCloudVpc(network *SNetwork) *api.Guestnet return desc } +func (gn *SGuestnetwork) getJsonDescHostLocal(network *SNetwork) *api.GuestnetworkJsonDesc { + desc := gn.getJsonDesc() + desc.Bridge = api.HostLocalBridge + desc.WireId = api.DEFAULT_HOST_LOCAL_WIRE_ID + return desc +} + func (gn *SGuestnetwork) getJsonDesc() *api.GuestnetworkJsonDesc { net, _ := gn.GetNetwork() var wire *SWire diff --git a/pkg/compute/models/hosts.go b/pkg/compute/models/hosts.go index 6fcb35a27e..5d064b8da8 100644 --- a/pkg/compute/models/hosts.go +++ b/pkg/compute/models/hosts.go @@ -52,6 +52,7 @@ import ( baremetalapi "yunion.io/x/onecloud/pkg/apis/baremetal" billing_api "yunion.io/x/onecloud/pkg/apis/billing" api "yunion.io/x/onecloud/pkg/apis/compute" + computeapi "yunion.io/x/onecloud/pkg/apis/compute" hostapi "yunion.io/x/onecloud/pkg/apis/host" napi "yunion.io/x/onecloud/pkg/apis/notify" "yunion.io/x/onecloud/pkg/appsrv" @@ -3335,7 +3336,7 @@ func (hh *SHost) GetNetinterfacesWithIdAndCredential(netId string, userCred mccl } func (hh *SHost) GetNetworkWithId(netId string, reserved bool) (*SNetwork, error) { - var q1, q2, q3 *sqlchemy.SQuery + var q1, q2, q3, q4 *sqlchemy.SQuery { // classic network networks := NetworkManager.Query() @@ -3384,8 +3385,34 @@ func (hh *SHost) GetNetworkWithId(netId string, reserved bool) (*SNetwork, error q3 = q3.Filter(sqlchemy.Equals(networks.Field("id"), netId)) q3 = q3.Filter(sqlchemy.Equals(hosts.Field("id"), hh.Id)) } + { + // host local network + networks := NetworkManager.Query() + wires := WireManager.Query().SubQuery() + vpcs := VpcManager.Query().SubQuery() + regions := CloudregionManager.Query().SubQuery() + q4 = networks + q4 = q4.Join(wires, sqlchemy.Equals(wires.Field("id"), networks.Field("wire_id"))) + q4 = q4.Join(vpcs, sqlchemy.Equals(vpcs.Field("id"), wires.Field("vpc_id"))) + q4 = q4.Join(regions, sqlchemy.Equals(regions.Field("id"), vpcs.Field("cloudregion_id"))) + q4 = q4.Filter(sqlchemy.Equals(networks.Field("id"), netId)) + q4 = q4.Filter( + sqlchemy.OR( + sqlchemy.AND( + sqlchemy.Equals(regions.Field("provider"), api.CLOUD_PROVIDER_ONECLOUD), + sqlchemy.Equals(vpcs.Field("id"), api.DEFAULT_VPC_ID), + sqlchemy.Equals(wires.Field("id"), computeapi.DEFAULT_HOST_LOCAL_WIRE_ID), + ), + sqlchemy.AND( + sqlchemy.Equals(regions.Field("provider"), api.CLOUD_PROVIDER_CLOUDPODS), + sqlchemy.Equals(vpcs.Field("external_id"), api.DEFAULT_VPC_ID), + sqlchemy.Equals(wires.Field("external_id"), computeapi.DEFAULT_HOST_LOCAL_WIRE_ID), + ), + ), + ) + } - q := sqlchemy.Union(q1, q2, q3).Query().Distinct() + q := sqlchemy.Union(q1, q2, q3, q4).Query().Distinct() net := SNetwork{} net.SetModelManager(NetworkManager, &net) diff --git a/pkg/compute/models/initdb.go b/pkg/compute/models/initdb.go index c13c88aa65..b706ad3cbc 100644 --- a/pkg/compute/models/initdb.go +++ b/pkg/compute/models/initdb.go @@ -18,7 +18,6 @@ import ( "time" "yunion.io/x/log" - "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/proxy" @@ -87,7 +86,7 @@ func InitDB() error { now := time.Now() err := manager.InitializeData() if err != nil { - return errors.Wrapf(err, "%s initializeData", manager.Keyword()) + log.Errorf("%s initializeData fail %s", manager.Keyword(), err) } if cost := time.Now().Sub(now); cost > time.Duration(time.Second)*15 { log.Infof("%s initializeData cost %s", manager.Keyword(), cost.Round(time.Second)) diff --git a/pkg/compute/models/networks.go b/pkg/compute/models/networks.go index ce06835137..e5c5ea284c 100644 --- a/pkg/compute/models/networks.go +++ b/pkg/compute/models/networks.go @@ -1856,6 +1856,11 @@ func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred } else { return input, httperrors.NewInputParameterError("zone and vpc info required when wire is absent") } + { + if wire.Id == api.DEFAULT_HOST_LOCAL_WIRE_ID { + input.ServerType = api.NETWORK_TYPE_HOSTLOCAL + } + } input.WireId = wire.Id if vpc.Status != api.VPC_STATUS_AVAILABLE { @@ -1864,11 +1869,11 @@ func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred if input.ServerType == api.NETWORK_TYPE_EIP && vpc.Id != api.DEFAULT_VPC_ID { return input, httperrors.NewInputParameterError("eip network can only exist in default vpc, got %s(%s)", vpc.Name, vpc.Id) } - if input.ServerType != api.NETWORK_TYPE_EIP { - input.BgpType = "" - } + // if input.ServerType != api.NETWORK_TYPE_EIP { + // input.BgpType = "" + // } // check class metadata - if wire != nil { + { // wire != nil var projectId string if len(input.ProjectId) > 0 { projectId = input.ProjectId @@ -1986,6 +1991,9 @@ func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred if ipEnd.NetAddr(masklen) != netAddr { return input, httperrors.NewInputParameterError("start and end ip not in the same subnet") } + if wire.Id == api.DEFAULT_HOST_LOCAL_WIRE_ID && len(input.GuestGateway) == 0 { + return input, httperrors.NewInputParameterError("host local wire only support gateway ip") + } } var ( @@ -2045,6 +2053,9 @@ func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred if !ip6End.NetAddr(masklen6).Equals(netAddr6) { return input, httperrors.NewInputParameterError("v6 start and end ip not in the same subnet") } + if wire.Id == api.DEFAULT_HOST_LOCAL_WIRE_ID && len(input.GuestGateway6) == 0 { + return input, httperrors.NewInputParameterError("host local wire only support gateway v6 ip") + } } if ipRange == nil && ipRange6 == nil { @@ -2225,6 +2236,10 @@ func (snet *SNetwork) validateUpdateData(ctx context.Context, userCred mcclient. if endIp.NetAddr(masklen) != netAddr { return input, httperrors.NewInputParameterError("start, end ip must be in the same subnet") } + + if snet.WireId == api.DEFAULT_HOST_LOCAL_WIRE_ID && input.GuestGateway != nil && len(*input.GuestGateway) == 0 { + return input, httperrors.NewInputParameterError("host local wire only support gateway ip") + } } else { startIp, _ := netutils.NewIPV4Addr(snet.GuestIpStart) netAddr = startIp.NetAddr(masklen) @@ -2287,6 +2302,9 @@ func (snet *SNetwork) validateUpdateData(ctx context.Context, userCred mcclient. if !netRange.EndIp().NetAddr(masklen6).Equals(netAddr6) { return input, httperrors.NewInputParameterError("start, end v6 ip must be in the same subnet") } + if snet.WireId == api.DEFAULT_HOST_LOCAL_WIRE_ID && input.GuestGateway6 != nil && len(*input.GuestGateway6) == 0 { + return input, httperrors.NewInputParameterError("host local wire only support gateway ip") + } } else if len(snet.GuestIp6Start) > 0 { startIp, _ := netutils.NewIPV6Addr(snet.GuestIp6Start) netAddr6 = startIp.NetAddr(masklen6) @@ -2346,8 +2364,13 @@ func (snet *SNetwork) validateUpdateData(ctx context.Context, userCred mcclient. } } - if len(input.ServerType) > 0 && !api.IsInNetworkTypes(input.ServerType, api.ALL_NETWORK_TYPES) { - return input, errors.Wrapf(httperrors.ErrInputParameter, "invalid server_type %q", input.ServerType) + if len(input.ServerType) > 0 { + if !api.IsInNetworkTypes(input.ServerType, api.ALL_NETWORK_TYPES) { + return input, errors.Wrapf(httperrors.ErrInputParameter, "invalid server_type %q", input.ServerType) + } + if snet.WireId == api.DEFAULT_HOST_LOCAL_WIRE_ID && input.ServerType != api.NETWORK_TYPE_HOSTLOCAL { + return input, httperrors.NewInputParameterError("host local wire only support hostlocal server_type") + } } return input, nil @@ -2706,28 +2729,42 @@ func (manager *SNetworkManager) ListItemFilter( hostsQ := hosts.SubQuery() classicWiresIdQ = classicWiresIdQ.Join(hostsQ, sqlchemy.Equals(netifs.Field("baremetal_id"), hostsQ.Field("id"))) - wireIdQ := classicWiresIdQ.SubQuery() + wireIdQueries := []sqlchemy.IQuery{ + classicWiresIdQ, + } - if input.HostType == api.HOST_TYPE_HYPERVISOR { - // should consider VPC network - vpcHostQ := HostManager.Query().IsNotEmpty("ovn_version") - if len(input.HostType) > 0 { - vpcHostQ = vpcHostQ.Equals("host_type", input.HostType) - } + if input.HostType == api.HOST_TYPE_HYPERVISOR || input.HostType == api.HOST_TYPE_CONTAINER { + vpcHostQ := HostManager.Query().Equals("host_type", input.HostType) if len(input.HostId) > 0 { vpcHostQ = vpcHostQ.In("id", input.HostId) } + hostCnt, err := vpcHostQ.CountWithError() + if err != nil { + return nil, errors.Wrap(err, "vpcHostQ.CountWithError") + } + if hostCnt > 0 { + // should consider host local wire + hostLocalWireQ := WireManager.Query("id").Equals("id", api.DEFAULT_HOST_LOCAL_WIRE_ID) + wireIdQueries = append(wireIdQueries, hostLocalWireQ) + } + vpcHostQ = vpcHostQ.IsNotEmpty("ovn_version") vpcHostCnt, err := vpcHostQ.CountWithError() if err != nil { return nil, errors.Wrap(err, "vpcHostQ.CountWithError") } if vpcHostCnt > 0 { + // should consider VPC network wire vpcWiresIdQ := WireManager.Query("id").NotEquals("vpc_id", api.DEFAULT_VPC_ID) - - wireIdUnion := sqlchemy.Union(classicWiresIdQ, vpcWiresIdQ) - wireIdQ = wireIdUnion.Query().SubQuery() + wireIdQueries = append(wireIdQueries, vpcWiresIdQ) } } + var wireIdQ *sqlchemy.SSubQuery + if len(wireIdQueries) > 1 { + wireIdQ = sqlchemy.Union(wireIdQueries...).Query().SubQuery() + } else { + wireIdQ = classicWiresIdQ.SubQuery() + } + additionalQ := NetworkAdditionalWireManager.Query("network_id") additionalQ = additionalQ.Join(wireIdQ, sqlchemy.Equals(wireIdQ.Field("id"), additionalQ.Field("wire_id"))) q = q.Filter(sqlchemy.OR( diff --git a/pkg/compute/models/vpcs.go b/pkg/compute/models/vpcs.go index 7d650f28f2..4d22f50aee 100644 --- a/pkg/compute/models/vpcs.go +++ b/pkg/compute/models/vpcs.go @@ -35,6 +35,7 @@ import ( "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" + identityapi "yunion.io/x/onecloud/pkg/apis/identity" "yunion.io/x/onecloud/pkg/cloudcommon/consts" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" @@ -813,6 +814,7 @@ func (manager *SVpcManager) InitializeData() error { defVpc.IsDefault = true defVpc.IsPublic = true defVpc.PublicScope = string(rbacscope.ScopeSystem) + defVpc.DomainId = identityapi.DEFAULT_DOMAIN_ID err = manager.TableSpec().Insert(context.TODO(), &defVpc) if err != nil { log.Errorf("Insert default vpc fail: %s", err) diff --git a/pkg/compute/models/wireresource.go b/pkg/compute/models/wireresource.go index 8af48dc428..1e19861b9b 100644 --- a/pkg/compute/models/wireresource.go +++ b/pkg/compute/models/wireresource.go @@ -22,7 +22,6 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/reflectutils" - "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" api "yunion.io/x/onecloud/pkg/apis/compute" @@ -192,7 +191,7 @@ func (manager *SWireResourceBaseManager) ListItemFilter( } if len(query.ZoneList()) > 0 { - region := &SCloudregion{} + /* region := &SCloudregion{} firstZone := query.FirstZone() sq := ZoneManager.Query().SubQuery() regionQ := CloudregionManager.Query() @@ -210,8 +209,23 @@ func (manager *SWireResourceBaseManager) ListItemFilter( err = regionQ.First(region) if err != nil { return nil, errors.Wrap(err, "regionQ.First") + } */ + var err error + zoneQuery := api.ZonalFilterListInput{ + ZonalFilterListBase: query.ZonalFilterListBase, } - if utils.IsInStringArray(region.Provider, api.REGIONAL_NETWORK_PROVIDERS) { + wireZoneQ := WireManager.Query("zone_id").Snapshot() + wireZoneQ, err = manager.SZoneResourceBaseManager.ListItemFilter(ctx, wireZoneQ, userCred, zoneQuery) + if err != nil { + return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemFilter") + } + if wireZoneQ.IsAltered() { + wireQ = wireQ.Filter(sqlchemy.OR( + sqlchemy.IsNullOrEmpty(wireQ.Field("zone_id")), + sqlchemy.In(wireQ.Field("zone_id"), wireZoneQ.SubQuery()), + )) + } + /*if utils.IsInStringArray(region.Provider, api.REGIONAL_NETWORK_PROVIDERS) { vpcQ := VpcManager.Query().SubQuery() wireQ = wireQ.Join(vpcQ, sqlchemy.Equals(vpcQ.Field("id"), wireQ.Field("vpc_id"))). Filter(sqlchemy.Equals(vpcQ.Field("cloudregion_id"), region.Id)) @@ -223,7 +237,7 @@ func (manager *SWireResourceBaseManager) ListItemFilter( if err != nil { return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemFilter") } - } + }*/ } if wireQ.IsAltered() { diff --git a/pkg/compute/models/wires.go b/pkg/compute/models/wires.go index 9bc9577415..f6435f99d2 100644 --- a/pkg/compute/models/wires.go +++ b/pkg/compute/models/wires.go @@ -34,6 +34,7 @@ import ( "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" + identityapi "yunion.io/x/onecloud/pkg/apis/identity" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" @@ -168,6 +169,9 @@ func (wire *SWire) ValidateUpdateData(ctx context.Context, userCred mcclient.Tok } func (wire *SWire) ValidateDeleteCondition(ctx context.Context, info *api.WireDetails) error { + if wire.Id == api.DEFAULT_HOST_LOCAL_WIRE_ID { + return httperrors.NewProtectedResourceError("not allow to delete default host local wire") + } if gotypes.IsNil(info) { info = &api.WireDetails{} usage, err := WireManager.TotalResourceCount([]string{wire.Id}) @@ -1154,6 +1158,12 @@ func chooseCandidateNetworksByNetworkType(nets []SNetwork, isExit bool, serverTy } func (manager *SWireManager) InitializeData() error { + { + err := manager.initHostLocalWire() + if err != nil { + return errors.Wrap(err, "initHostLocalWire") + } + } { err := manager.initVpcId() if err != nil { @@ -1966,3 +1976,36 @@ func (wire *SWire) Delete(ctx context.Context, userCred mcclient.TokenCredential } return wire.SStatusInfrasResourceBase.Delete(ctx, userCred) } + +func (manager *SWireManager) initHostLocalWire() error { + if _, err := manager.FetchById(api.DEFAULT_HOST_LOCAL_WIRE_ID); err != nil { + if err == sql.ErrNoRows { + defWire := SWire{} + defWire.SetModelManager(WireManager, &defWire) + + defWire.Id = api.DEFAULT_HOST_LOCAL_WIRE_ID + defWire.Name = api.DEFAULT_HOST_LOCAL_WIRE_NAME + defWire.VpcId = api.DEFAULT_VPC_ID + defWire.ZoneId = "" // host local wire is not associated with a zone + defWire.ManagerId = "" // host local wire is not associated with a manager + defWire.IsEmulated = false + defWire.ExternalId = "" // host local wire is not associated with an external id + defWire.IsPublic = true + defWire.PublicScope = string(rbacscope.ScopeSystem) + defWire.Status = api.WIRE_STATUS_AVAILABLE + defWire.Description = "Host local wire" + defWire.Bandwidth = 10000 + defWire.Mtu = 1500 + defWire.ScheduleRank = 0 + defWire.DomainId = identityapi.DEFAULT_DOMAIN_ID + err = manager.TableSpec().Insert(context.TODO(), &defWire) + if err != nil { + log.Errorf("Insert default host local wire fail: %s", err) + } + return err + } else { + return err + } + } + return nil +} diff --git a/pkg/hostman/guestman/qemu-kvm.go b/pkg/hostman/guestman/qemu-kvm.go index 65f2773f5a..b80f403ffa 100644 --- a/pkg/hostman/guestman/qemu-kvm.go +++ b/pkg/hostman/guestman/qemu-kvm.go @@ -2520,12 +2520,8 @@ func (s *SKVMGuestInstance) compareDescNetworks(newDesc *desc.SGuestDesc, func getNicBridge(nic *desc.SGuestNetwork) string { if nic.Bridge == "" && nic.Vpc.Provider == api.VPC_PROVIDER_OVN { return options.HostOptions.OvnIntegrationBridge - } else if nic.Bridge == api.HostTapBridge { - return options.HostOptions.TapBridgeName - } else if nic.Bridge == api.HostVpcBridge { - return options.HostOptions.OvnIntegrationBridge } else { - return nic.Bridge + return options.HostOptions.NicBridgeDevName(nic.Bridge) } } diff --git a/pkg/hostman/hostinfo/finalize_network.go b/pkg/hostman/hostinfo/finalize_network.go index 6b507223e7..30c62138a3 100644 --- a/pkg/hostman/hostinfo/finalize_network.go +++ b/pkg/hostman/hostinfo/finalize_network.go @@ -34,14 +34,28 @@ import ( "yunion.io/x/onecloud/pkg/util/procutils" ) +func (h *SHostInfo) findExternalInterfaces() []string { + interfaces := make([]string, 0) + for i := 0; i < len(h.Nics); i++ { + if !h.Nics[i].IsHostLocal() && len(h.Nics[i].Ip) > 0 { + interfaces = append(interfaces, h.Nics[i].Bridge) + } + } + if len(options.HostOptions.ListenInterface) > 0 { + interfaces = append(interfaces, options.HostOptions.ListenInterface) + } + return interfaces +} + func (h *SHostInfo) finalizeNetworkSetup(ctx context.Context) error { for i := 0; i < len(h.Nics); i++ { if err := h.Nics[i].SetupDhcpRelay(); err != nil { return errors.Wrapf(err, "SetupDhcpRelay %s", h.Nics[i]) } } + extInterfaces := h.findExternalInterfaces() for i := 0; i < len(h.Nics); i++ { - if err := h.Nics[i].setupHostLocalNetworks(ctx); err != nil { + if err := h.Nics[i].setupHostLocalNetworks(ctx, extInterfaces); err != nil { return errors.Wrapf(err, "SetupHostLocalNetworks %s", h.Nics[i]) } } @@ -52,7 +66,7 @@ func (n *SNIC) String() string { return fmt.Sprintf("%s/%s/%s", n.Inter, n.Bridge, n.Ip) } -func (n *SNIC) setupHostLocalNetworks(ctx context.Context) error { +func (n *SNIC) setupHostLocalNetworks(ctx context.Context, extInterfaces []string) error { nets, err := n.fetchHostLocalNetworks(ctx) if err != nil { return errors.Wrap(err, "fetchHostLocalNetworks") @@ -63,7 +77,7 @@ func (n *SNIC) setupHostLocalNetworks(ctx context.Context) error { if len(net.GuestGateway) == 0 { continue } - err := n.setupHostLocalNet(ctx, net) + err := n.setupHostLocalNet(ctx, net, extInterfaces) if err != nil { return errors.Wrapf(err, "setupHostLocalNet of %s", jsonutils.Marshal(net)) } @@ -75,15 +89,15 @@ func (n *SNIC) setupHostLocalNetworks(ctx context.Context) error { return nil } -func (n *SNIC) setupHostLocalNet(ctx context.Context, netInfo computeapis.NetworkDetails) error { +func (n *SNIC) setupHostLocalNet(ctx context.Context, netInfo computeapis.NetworkDetails, extInterfaces []string) error { // setup gateway ip - if err := n.setupSlaveIp(ctx, netInfo.GuestGateway, netInfo.GuestIpMask); err != nil { + if err := n.setupSlaveIp(ctx, netInfo.GuestGateway, netInfo.GuestIpMask, extInterfaces); err != nil { return errors.Wrapf(err, "setupSlaveIp %s %s", n, netInfo.GuestGateway) } return nil } -func (n *SNIC) setupSlaveIp(ctx context.Context, gatewayIp string, maskLen byte) error { +func (n *SNIC) setupSlaveIp(ctx context.Context, gatewayIp string, maskLen byte, extInterfaces []string) error { bridgeIf := netutils2.NewNetInterface(n.Bridge) slaveAddrs := bridgeIf.GetSlaveAddresses() var curGatewayIp string @@ -108,7 +122,7 @@ func (n *SNIC) setupSlaveIp(ctx context.Context, gatewayIp string, maskLen byte) }); err != nil { return errors.Wrap(err, "SetupSlaveAddresses") } - if err := n.setupMasqueradeRule(ctx, gatewayIp, maskLen); err != nil { + if err := n.setupMasqueradeRule(ctx, gatewayIp, maskLen, extInterfaces); err != nil { return errors.Wrap(err, "setupMasqueradeRule") } if isMaskUpdate { @@ -120,7 +134,7 @@ func (n *SNIC) setupSlaveIp(ctx context.Context, gatewayIp string, maskLen byte) log.Warningf("%s: delete addr %s: %v", logPrefix, addr, err) } curMaskLenInt := curMaskLen - if err := n.deleteMasqueradeRule(ctx, gatewayIp, byte(curMaskLenInt)); err != nil { + if err := n.deleteMasqueradeRule(ctx, gatewayIp, byte(curMaskLenInt), extInterfaces); err != nil { log.Warningf("%s: delete iptables masqueradeRule: %v", logPrefix, err) } } @@ -134,7 +148,7 @@ const ( IPTABLES_ACTION_DELETE ) -func (n *SNIC) doMasqueradeRule(ctx context.Context, ipStr string, maskLen byte, action IptablesAction) error { +func (n *SNIC) doMasqueradeRule(ctx context.Context, ipStr string, maskLen byte, action IptablesAction, bridge string) error { gwip, err := netutils.NewIPV4Addr(ipStr) if err != nil { return errors.Wrapf(err, "NewIPV4Addr %s", ipStr) @@ -154,35 +168,56 @@ func (n *SNIC) doMasqueradeRule(ctx context.Context, ipStr string, maskLen byte, return errors.Errorf("unknown action %d", action) } cmd := procutils.NewCommand("iptables", "-t", "nat", actionOpt, "POSTROUTING", "-s", - fmt.Sprintf("%s/%s", netip.String(), maskip.String()), "-o", n.Bridge, "-j", "MASQUERADE") + fmt.Sprintf("%s/%s", netip.String(), maskip.String()), "-o", bridge, "-j", "MASQUERADE") if err := cmd.Run(); err != nil { return errors.Wrapf(err, "%s masquerade rule", actionInfo) } return nil } -func (n *SNIC) setupMasqueradeRule(ctx context.Context, ipStr string, maskLen byte) error { - return n.doMasqueradeRule(ctx, ipStr, maskLen, IPTABLES_ACTION_APPEND) +func (n *SNIC) setupMasqueradeRule(ctx context.Context, ipStr string, maskLen byte, extInterfaces []string) error { + if n.IsHostLocal() { + for _, inf := range extInterfaces { + if err := n.doMasqueradeRule(ctx, ipStr, maskLen, IPTABLES_ACTION_APPEND, inf); err != nil { + return errors.Wrapf(err, "setupMasqueradeRule %s %d %s", ipStr, maskLen, inf) + } + } + return nil + } else { + return n.doMasqueradeRule(ctx, ipStr, maskLen, IPTABLES_ACTION_APPEND, n.Bridge) + } } -func (n *SNIC) deleteMasqueradeRule(ctx context.Context, ipStr string, maskLen byte) error { - return n.doMasqueradeRule(ctx, ipStr, maskLen, IPTABLES_ACTION_DELETE) +func (n *SNIC) deleteMasqueradeRule(ctx context.Context, ipStr string, maskLen byte, extInterfaces []string) error { + if n.IsHostLocal() { + for _, inf := range extInterfaces { + if err := n.doMasqueradeRule(ctx, ipStr, maskLen, IPTABLES_ACTION_DELETE, inf); err != nil { + return errors.Wrapf(err, "deleteMasqueradeRule %s %d %s", ipStr, maskLen, inf) + } + } + return nil + } else { + return n.doMasqueradeRule(ctx, ipStr, maskLen, IPTABLES_ACTION_DELETE, n.Bridge) + } } func (n *SNIC) fetchHostLocalNetworks(ctx context.Context) ([]computeapis.NetworkDetails, error) { + return fetchHostLocalNetworksByWireId(ctx, n.WireId) +} + +func fetchHostLocalNetworksByWireId(ctx context.Context, wireId string) ([]computeapis.NetworkDetails, error) { s := hostutils.GetComputeSession(ctx) params := computeoptions.NetworkListOptions{} params.ServerType = "hostlocal" limit := 50 params.Limit = &limit - params.Wire = n.WireId params.Scope = "system" total := -1 nets := make([]computeapis.NetworkDetails, 0) for total < 0 || len(nets) < total { offset := len(nets) params.Offset = &offset - results, err := computemodules.Networks.List(s, jsonutils.Marshal(params)) + results, err := computemodules.Networks.ListInContext(s, jsonutils.Marshal(params), &computemodules.Wires, wireId) if err != nil { return nil, errors.Wrap(err, "Networks.List") } diff --git a/pkg/hostman/hostinfo/hostbridge/hostbridge.go b/pkg/hostman/hostinfo/hostbridge/hostbridge.go index 7fa25fe2b4..1ee7c1e06d 100644 --- a/pkg/hostman/hostinfo/hostbridge/hostbridge.go +++ b/pkg/hostman/hostinfo/hostbridge/hostbridge.go @@ -15,6 +15,7 @@ package hostbridge import ( + "encoding/json" "fmt" "os" "strconv" @@ -29,6 +30,7 @@ import ( "yunion.io/x/pkg/util/regutils" "yunion.io/x/pkg/utils" + "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/hostman/guestman/desc" "yunion.io/x/onecloud/pkg/hostman/options" "yunion.io/x/onecloud/pkg/util/fileutils2" @@ -121,19 +123,64 @@ func NewBaseBridgeDriver(bridge, inter, ip string, maskLen int, ip6 string, mask return bd, nil } +func (d *SBaseBridgeDriver) fetchHostLocalConf() ([]compute.NetworkDetails, error) { + hostLocalNics := make([]compute.NetworkDetails, 0) + fn := options.HostOptions.HostLocalNetconfPath(d.bridge.String()) + if fileutils2.IsFile(fn) { + contBytes, err := os.ReadFile(fn) + if err != nil { + log.Errorf("read host local conf file %s failed: %s", fn, err) + return nil, errors.Wrap(err, "read host local conf file") + } + err = json.Unmarshal(contBytes, &hostLocalNics) + if err != nil { + log.Errorf("unmarshal host local conf file %s failed: %s", fn, err) + return nil, errors.Wrap(err, "unmarshal host local conf file") + } + return hostLocalNics, nil + } + return hostLocalNics, nil +} + +func (d *SBaseBridgeDriver) hostLocalGatewayIps() ([]string, error) { + hostLocalNics, err := d.fetchHostLocalConf() + if err != nil { + log.Errorf("fetch host local conf failed: %s", err) + return nil, errors.Wrap(err, "fetch host local conf") + } + gatewayIps := make([]string, 0) + for _, net := range hostLocalNics { + if net.GuestGateway != "" { + gatewayIps = append(gatewayIps, net.GuestGateway) + } + if net.GuestGateway6 != "" { + gatewayIps = append(gatewayIps, net.GuestGateway6) + } + } + return gatewayIps, nil +} + func (d *SBaseBridgeDriver) FetchConfig() { - d.bridge.FetchConfig2(d.ip, d.ip6) + hostLocalGatewayIps, _ := d.hostLocalGatewayIps() + d.bridge.FetchConfig2(d.ip, d.ip6, hostLocalGatewayIps) d.inter.FetchConfig() } func (d *SBaseBridgeDriver) GetMac() string { - if len(d.inter.GetMac()) == 0 { - d.inter.FetchConfig() + dev := d.inter + if dev == nil { + dev = d.bridge } - return d.inter.GetMac() + if len(dev.GetMac()) == 0 { + dev.FetchConfig() + } + return dev.GetMac() } func (d *SBaseBridgeDriver) GetVlanId() int { + if d.inter == nil { + return 1 + } if len(d.inter.GetMac()) == 0 { d.inter.FetchConfig() } @@ -327,7 +374,12 @@ func (d *SBaseBridgeDriver) ConfirmToConfig() (bool, string, error) { return false, "", err } if exist { - d.bridge.FetchConfig2(d.ip, d.ip6) + hostLocalGatewayIps, err := d.hostLocalGatewayIps() + if err != nil { + log.Errorf("fetch host local gateway ips failed: %s", err) + // return false, "", errors.Wrap(err, "fetch host local gateway ips") + } + d.bridge.FetchConfig2(d.ip, d.ip6, hostLocalGatewayIps) if len(d.ip) > 0 { if len(d.bridge.Addr) == 0 { log.Infof("bridge %s has no ip assignment initially", d.bridge) diff --git a/pkg/hostman/hostinfo/hostbridge/ovs.go b/pkg/hostman/hostinfo/hostbridge/ovs.go index d57ae3d85b..bfece572d3 100644 --- a/pkg/hostman/hostinfo/hostbridge/ovs.go +++ b/pkg/hostman/hostinfo/hostbridge/ovs.go @@ -100,6 +100,9 @@ func (o *SOVSBridgeDriver) SetupBridgeDev() error { } func (d *SOVSBridgeDriver) PersistentConfig() error { + if d.inter == nil { + return nil + } args := []string{ "ovs-vsctl", "set", "Bridge", d.bridge.String(), "other-config:hwaddr=" + d.inter.GetMac(), diff --git a/pkg/hostman/hostinfo/hostinfo.go b/pkg/hostman/hostinfo/hostinfo.go index ce05e18b1a..4662c8844e 100644 --- a/pkg/hostman/hostinfo/hostinfo.go +++ b/pkg/hostman/hostinfo/hostinfo.go @@ -159,8 +159,9 @@ func (h *SHostInfo) GetIsolatedDeviceManager() isolated_device.IsolatedDeviceMan } func (h *SHostInfo) GetBridgeDev(bridge string) hostbridge.IBridgeDriver { + bridgeDev := options.HostOptions.NicBridgeDevName(bridge) for _, n := range h.Nics { - if bridge == n.Bridge { + if bridgeDev == n.Bridge { return n.BridgeDev } } @@ -403,6 +404,14 @@ func (h *SHostInfo) parseConfig() error { } h.Nics = append(h.Nics, nic) } + { + // host local bridge + nic, err := NewNIC(fmt.Sprintf("/%s/%s", options.HostOptions.HostLocalBridgeName, api.DEFAULT_HOST_LOCAL_WIRE_NAME)) + if err != nil { + return errors.Wrapf(err, "NewNic for host local bridge %s", options.HostOptions.HostLocalBridgeName) + } + h.Nics = append(h.Nics, nic) + } if len(options.HostOptions.ListenInterface) > 0 { h.MasterNic = netutils2.NewNetInterface(options.HostOptions.ListenInterface) @@ -1887,6 +1896,9 @@ func (h *SHostInfo) uploadNetworkInfo() error { var hostDetails *api.HostDetails for _, nic := range h.Nics { log.Infof("host nic: %s", jsonutils.Marshal(nic).String()) + if nic.IsHostLocal() { + continue + } if len(nic.WireId) == 0 { // nic info not uploaded yet if len(nic.Wire) == 0 { diff --git a/pkg/hostman/hostinfo/hostinfohelper.go b/pkg/hostman/hostinfo/hostinfohelper.go index 17efe93a03..bf739f2dd7 100644 --- a/pkg/hostman/hostinfo/hostinfohelper.go +++ b/pkg/hostman/hostinfo/hostinfohelper.go @@ -32,6 +32,7 @@ import ( "yunion.io/x/pkg/util/netutils" "yunion.io/x/pkg/util/regutils" + computeapi "yunion.io/x/onecloud/pkg/apis/compute" hostapi "yunion.io/x/onecloud/pkg/apis/host" "yunion.io/x/onecloud/pkg/cloudcommon/types" "yunion.io/x/onecloud/pkg/hostman/hostinfo/hostbridge" @@ -283,7 +284,7 @@ func NewNIC(desc string) (*SNIC, error) { // in case nic bonding is too slow var max, wait = 30, 0 for wait < max { - inf := netutils2.NewNetInterfaceWithExpectIp(nic.Inter, nic.Ip, nic.Ip6) + inf := netutils2.NewNetInterfaceWithExpectIp(nic.Inter, nic.Ip, nic.Ip6, nil) if len(nic.Ip) > 0 && inf.Addr == nic.Ip { mask, _ := inf.Mask.Size() if mask > 0 { @@ -393,6 +394,21 @@ func NewNIC(desc string) (*SNIC, error) { return nic, nil } +func (n *SNIC) IsHostLocal() bool { + if n.Bridge == options.HostOptions.HostLocalBridgeName { + n.setupHostLocal() + return true + } + return false +} + +func (n *SNIC) setupHostLocal() { + if n.WireId == "" { + n.Wire = computeapi.DEFAULT_HOST_LOCAL_WIRE_NAME + n.WireId = computeapi.DEFAULT_HOST_LOCAL_WIRE_ID + } +} + type SSysInfo struct { *types.SSystemInfo diff --git a/pkg/hostman/options/options.go b/pkg/hostman/options/options.go index da665f24c6..7acef3fa04 100644 --- a/pkg/hostman/options/options.go +++ b/pkg/hostman/options/options.go @@ -22,6 +22,7 @@ import ( "yunion.io/x/log" "yunion.io/x/structarg" + computeapi "yunion.io/x/onecloud/pkg/apis/compute" common_options "yunion.io/x/onecloud/pkg/cloudcommon/options" "yunion.io/x/onecloud/pkg/util/fileutils2" "yunion.io/x/onecloud/pkg/util/ovnutils" @@ -196,6 +197,8 @@ type SHostOptions struct { SdnEnableTapMan bool `help:"enable tap service" default:"$SDN_ENABLE_TAP_MAN|true"` TapBridgeName string `help:"bridge name for tap service" default:"brtap"` + HostLocalBridgeName string `help:"bridge name for host local network" default:"brlocal"` + SdnAllowConntrackInvalid bool `help:"allow packets marked by conntrack as INVALID to pass" default:"$SDN_ALLOW_CONNTRACK_INVALID|false"` SdnFetchDataFromComputeService bool `help:"fetch network releated data from compute service" default:"$SDN_FETCH_DATA_FROM_COMPUTE_SERVICE|true"` @@ -281,6 +284,19 @@ func (o SHostOptions) HostLocalNetconfPath(br string) string { return filepath.Join(o.ServersPath, fmt.Sprintf("host_local_netconf_%s.json", br)) } +func (o SHostOptions) NicBridgeDevName(bridge string) string { + switch bridge { + case computeapi.HostVpcBridge: + return o.OvnIntegrationBridge + case computeapi.HostTapBridge: + return o.TapBridgeName + case computeapi.HostLocalBridge: + return o.HostLocalBridgeName + default: + return bridge + } +} + var ( HostOptions SHostOptions ) diff --git a/pkg/mcclient/options/compute/network.go b/pkg/mcclient/options/compute/network.go index 76c44641fe..8c8b2e966f 100644 --- a/pkg/mcclient/options/compute/network.go +++ b/pkg/mcclient/options/compute/network.go @@ -34,7 +34,7 @@ type NetworkListOptions struct { Region string `help:"search networks belongs to a CloudRegion" json:"cloudregion"` City string `help:"search networks belongs to a city"` Usable *bool `help:"search usable networks"` - ServerType string `help:"search networks belongs to a ServerType" choices:"baremetal|container|eip|guest|ipmi|pxe"` + ServerType string `help:"search networks belongs to a ServerType" choices:"baremetal|container|eip|guest|ipmi|pxe|hostlocal"` Schedtag string `help:"filter networks by schedtag"` HostSchedtagId string `help:"filter by host schedtag"` diff --git a/pkg/scheduler/algorithm/predicates/network_predicate.go b/pkg/scheduler/algorithm/predicates/network_predicate.go index 80c1728602..13e46772c9 100644 --- a/pkg/scheduler/algorithm/predicates/network_predicate.go +++ b/pkg/scheduler/algorithm/predicates/network_predicate.go @@ -116,11 +116,16 @@ func IsNetworksAvailable(ctx context.Context, c core.Candidater, data *api.Sched ovnCapable := c.Getter().OvnCapable() ovnNetworks := []*api.CandidateNetwork{} + hostLocalNetworks := []*api.CandidateNetwork{} for i := len(networks) - 1; i >= 0; i -= 1 { net := networks[i] if net.Provider == computeapi.CLOUD_PROVIDER_ONECLOUD || net.Provider == computeapi.CLOUD_PROVIDER_CLOUDPODS { networks = append(networks[:i], networks[i+1:]...) - ovnNetworks = append(ovnNetworks, net) + if net.WireId == computeapi.DEFAULT_HOST_LOCAL_WIRE_ID { + hostLocalNetworks = append(hostLocalNetworks, net) + } else { + ovnNetworks = append(ovnNetworks, net) + } } } @@ -140,6 +145,10 @@ func IsNetworksAvailable(ctx context.Context, c core.Candidater, data *api.Sched checkNets(ovnNetworks) } + if len(hostLocalNetworks) > 0 { + checkNets(hostLocalNetworks) + } + // reuse network if data.ReuseNetwork { return freeCnt, nil diff --git a/pkg/scheduler/cache/candidate/base.go b/pkg/scheduler/cache/candidate/base.go index c4e35726d3..70b4aaece8 100644 --- a/pkg/scheduler/cache/candidate/base.go +++ b/pkg/scheduler/cache/candidate/base.go @@ -390,11 +390,17 @@ func newBaseHostDesc(b *baseBuilder, host *computemodels.SHost, netGetter *netwo if err := desc.fillOnecloudVpcNetworks(netGetter); err != nil { return nil, fmt.Errorf("Fill onecloud vpc networks error: %v", err) } + if err := desc.fillOneCloudHostLocalNetworks(netGetter); err != nil { + return nil, fmt.Errorf("Fill onecloud host local networks error: %v", err) + } } - if sets.NewString(computeapi.HOST_TYPE_HYPERVISOR, computeapi.HOST_TYPE_BAREMETAL).Has(host.HostType) && len(host.ManagerId) > 0 { + if sets.NewString(computeapi.HOST_TYPE_HYPERVISOR, computeapi.HOST_TYPE_BAREMETAL, computeapi.HOST_TYPE_CONTAINER).Has(host.HostType) && len(host.ManagerId) > 0 { if err := desc.fillCloudpodsVpcNetworks(netGetter); err != nil { return nil, fmt.Errorf("Fill cloudpods vpc networks error: %v", err) } + if err := desc.fillCloudpodsHostLocalNetworks(netGetter); err != nil { + return nil, fmt.Errorf("Fill cloudpods host local networks error: %v", err) + } } if err := desc.fillZone(host); err != nil { @@ -693,7 +699,7 @@ func (b *BaseHostDesc) fillCloudpodsVpcNetworks(netGetter *networkGetter) error nets := computemodels.NetworkManager.Query() wires := computemodels.WireManager.Query().SubQuery() vpcs := computemodels.VpcManager.Query().SubQuery() - regions := computemodels.CloudregionManager.Query().SubQuery() + regions := computemodels.CloudregionManager.Query().Equals("provider", computeapi.CLOUD_PROVIDER_CLOUDPODS).SubQuery() q := nets.AppendField(nets.QueryFields()...) q = q.AppendField( vpcs.Field("id", "vpc_id"), @@ -702,44 +708,17 @@ func (b *BaseHostDesc) fillCloudpodsVpcNetworks(netGetter *networkGetter) error q = q.Join(wires, sqlchemy.Equals(wires.Field("id"), nets.Field("wire_id"))) q = q.Join(vpcs, sqlchemy.Equals(vpcs.Field("id"), wires.Field("vpc_id"))) q = q.Join(regions, sqlchemy.Equals(regions.Field("id"), vpcs.Field("cloudregion_id"))) - q = q.Filter(sqlchemy.AND( - sqlchemy.Equals(regions.Field("provider"), computeapi.CLOUD_PROVIDER_CLOUDPODS), + q = q.Filter( sqlchemy.NOT(sqlchemy.Equals(vpcs.Field("external_id"), computeapi.DEFAULT_VPC_ID)), - )) - - type Row struct { - computemodels.SNetwork - VpcId string - Provider string - } - rows := []Row{} - if err := q.All(&rows); err != nil { - return errors.Wrap(err, "query cloudpods vpc networks") - } - for i := range rows { - row := &rows[i] - net := &row.SNetwork - net.SetModelManager(computemodels.NetworkManager, net) - freePort, err := netGetter.GetFreePort(b.SHost, net) - if err != nil { - return errors.Wrapf(err, "GetFreeAddressCount for network %s(%s)", net.GetName(), net.GetId()) - } - candidateNet := &api.CandidateNetwork{ - SNetwork: net, - FreePort: freePort, - VpcId: row.VpcId, - Provider: row.Provider, - } - b.Networks = append(b.Networks, candidateNet) - } - return nil + ) + return b.fillNetworksByQuery(netGetter, q) } func (b *BaseHostDesc) fillOnecloudVpcNetworks(netGetter *networkGetter) error { nets := computemodels.NetworkManager.Query() wires := computemodels.WireManager.Query().SubQuery() vpcs := computemodels.VpcManager.Query().SubQuery() - regions := computemodels.CloudregionManager.Query().SubQuery() + regions := computemodels.CloudregionManager.Query().Equals("provider", computeapi.CLOUD_PROVIDER_ONECLOUD).SubQuery() q := nets.AppendField(nets.QueryFields()...) q = q.AppendField( vpcs.Field("id", "vpc_id"), @@ -748,11 +727,45 @@ func (b *BaseHostDesc) fillOnecloudVpcNetworks(netGetter *networkGetter) error { q = q.Join(wires, sqlchemy.Equals(wires.Field("id"), nets.Field("wire_id"))) q = q.Join(vpcs, sqlchemy.Equals(vpcs.Field("id"), wires.Field("vpc_id"))) q = q.Join(regions, sqlchemy.Equals(regions.Field("id"), vpcs.Field("cloudregion_id"))) - q = q.Filter(sqlchemy.AND( - sqlchemy.Equals(regions.Field("provider"), computeapi.CLOUD_PROVIDER_ONECLOUD), + q = q.Filter( sqlchemy.NOT(sqlchemy.Equals(vpcs.Field("id"), computeapi.DEFAULT_VPC_ID)), - )) + ) + return b.fillNetworksByQuery(netGetter, q) +} +func (b *BaseHostDesc) fillOneCloudHostLocalNetworks(netGetter *networkGetter) error { + nets := computemodels.NetworkManager.Query() + wires := computemodels.WireManager.Query().Equals("id", computeapi.DEFAULT_HOST_LOCAL_WIRE_ID).SubQuery() + vpcs := computemodels.VpcManager.Query().Equals("id", computeapi.DEFAULT_VPC_ID).SubQuery() + regions := computemodels.CloudregionManager.Query().Equals("provider", computeapi.CLOUD_PROVIDER_ONECLOUD).SubQuery() + q := nets.AppendField(nets.QueryFields()...) + q = q.AppendField( + vpcs.Field("id", "vpc_id"), + regions.Field("provider"), + ) + q = q.Join(wires, sqlchemy.Equals(wires.Field("id"), nets.Field("wire_id"))) + q = q.Join(vpcs, sqlchemy.Equals(vpcs.Field("id"), wires.Field("vpc_id"))) + q = q.Join(regions, sqlchemy.Equals(regions.Field("id"), vpcs.Field("cloudregion_id"))) + return b.fillNetworksByQuery(netGetter, q) +} + +func (b *BaseHostDesc) fillCloudpodsHostLocalNetworks(netGetter *networkGetter) error { + nets := computemodels.NetworkManager.Query() + wires := computemodels.WireManager.Query().Equals("external_id", computeapi.DEFAULT_HOST_LOCAL_WIRE_ID).SubQuery() + vpcs := computemodels.VpcManager.Query().Equals("external_id", computeapi.DEFAULT_VPC_ID).SubQuery() + regions := computemodels.CloudregionManager.Query().Equals("provider", computeapi.CLOUD_PROVIDER_CLOUDPODS).SubQuery() + q := nets.AppendField(nets.QueryFields()...) + q = q.AppendField( + vpcs.Field("id", "vpc_id"), + regions.Field("provider"), + ) + q = q.Join(wires, sqlchemy.Equals(wires.Field("id"), nets.Field("wire_id"))) + q = q.Join(vpcs, sqlchemy.Equals(vpcs.Field("id"), wires.Field("vpc_id"))) + q = q.Join(regions, sqlchemy.Equals(regions.Field("id"), vpcs.Field("cloudregion_id"))) + return b.fillNetworksByQuery(netGetter, q) +} + +func (b *BaseHostDesc) fillNetworksByQuery(netGetter *networkGetter, q *sqlchemy.SQuery) error { type Row struct { computemodels.SNetwork VpcId string diff --git a/pkg/util/netutils2/netutils.go b/pkg/util/netutils2/netutils.go index 320239d48c..7ebb3540db 100644 --- a/pkg/util/netutils2/netutils.go +++ b/pkg/util/netutils2/netutils.go @@ -27,6 +27,7 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/netutils" "yunion.io/x/pkg/util/regutils" + "yunion.io/x/pkg/utils" "yunion.io/x/onecloud/pkg/cloudcommon/types" "yunion.io/x/onecloud/pkg/util/procutils" @@ -477,10 +478,10 @@ func NewNetInterface(name string) *SNetInterface { return n } -func NewNetInterfaceWithExpectIp(name string, expectIp string, expectIp6 string) *SNetInterface { +func NewNetInterfaceWithExpectIp(name string, expectIp string, expectIp6 string, excludeIps []string) *SNetInterface { n := new(SNetInterface) n.name = name - n.FetchConfig2(expectIp, expectIp6) + n.FetchConfig2(expectIp, expectIp6, excludeIps) return n } @@ -503,11 +504,11 @@ func (n *SNetInterface) FetchInter() *net.Interface { } func (n *SNetInterface) FetchConfig() { - n.FetchConfig2("", "") + n.FetchConfig2("", "", nil) } // FetchConfig2 is used to fetch config with expectIp and expectIp6 -func (n *SNetInterface) FetchConfig2(expectIp string, expectIp6 string) { +func (n *SNetInterface) FetchConfig2(expectIp string, expectIp6 string, excludeIps []string) { n.Addr = "" n.Mask = nil n.mac = "" @@ -528,6 +529,9 @@ func (n *SNetInterface) FetchConfig2(expectIp string, expectIp6 string) { if strings.HasPrefix(ipnet.IP.To4().String(), SECRET_PREFIX) { n.Addr4LinkLocal = ipnet.IP.String() } else if (len(expectIp) > 0 && ipnet.IP.String() == expectIp) || (len(expectIp) == 0 && n.Addr == "") { + if len(excludeIps) > 0 && utils.IsInStringArray(ipnet.IP.String(), excludeIps) { + continue + } n.Addr = ipnet.IP.String() n.Mask = ipnet.Mask } @@ -535,6 +539,9 @@ func (n *SNetInterface) FetchConfig2(expectIp string, expectIp6 string) { if ipnet.IP.IsLinkLocalUnicast() { n.Addr6LinkLocal = ipnet.IP.String() } else if (len(expectIp6) > 0 && ipnet.IP.String() == expectIp6) || (len(expectIp6) == 0 && n.Addr6 == "") { + if len(excludeIps) > 0 && utils.IsInStringArray(ipnet.IP.String(), excludeIps) { + continue + } n.Addr6 = ipnet.IP.String() n.Mask6 = ipnet.Mask }