feature: support host-local wire (#24490)

Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
Jian Qiu
2026-03-20 01:36:29 +08:00
committed by GitHub
co-authored by Qiu Jian
parent bc43d884c5
commit 70fbfe8946
21 changed files with 409 additions and 109 deletions
+3 -2
View File
@@ -15,8 +15,9 @@
package compute
const (
HostVpcBridge = "__vpc_bridge__"
HostTapBridge = "__tap_bridge__"
HostVpcBridge = "__vpc_bridge__"
HostTapBridge = "__tap_bridge__"
HostLocalBridge = "brlocal"
)
type SMirrorConfig struct {
+3
View File
@@ -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__"
)
+16 -13
View File
@@ -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)
+12
View File
@@ -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
+29 -2
View File
@@ -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)
+1 -2
View File
@@ -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))
+53 -16
View File
@@ -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(
+2
View File
@@ -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)
+18 -4
View File
@@ -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() {
+43
View File
@@ -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
}
+1 -5
View File
@@ -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)
}
}
+51 -16
View File
@@ -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")
}
+57 -5
View File
@@ -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)
+3
View File
@@ -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(),
+13 -1
View File
@@ -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 {
+17 -1
View File
@@ -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
+16
View File
@@ -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
)
+1 -1
View File
@@ -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"`
@@ -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
+49 -36
View File
@@ -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
+11 -4
View File
@@ -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
}