Commit e3607277 authored by Kevin Di Lallo's avatar Kevin Di Lallo
Browse files

pdu session connectivity support in net-char-mgr

parent 4d68dd97
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ const fieldSandboxName = "sandbox-name"
const fieldScenarioName = "scenario-name"
const fieldEventType = "event-type"
const fieldNodeName = "node-name"
const fieldPduSessionId = "pdu-id"

// Event types
const (
@@ -535,6 +536,9 @@ func ceTerminateScenario(w http.ResponseWriter, r *http.Request) {
		log.Error("Failed to send message. Error: ", err.Error())
	}

	// Delete all PDU sessions
	sbxCtrl.pduSessionStore.DeleteAllPduSessions()

	// Use new model instance
	sbxCtrl.activeModel, err = mod.NewModel(sbxCtrl.modelCfg)
	if err != nil {
@@ -1125,6 +1129,18 @@ func ceCreatePduSession(w http.ResponseWriter, r *http.Request) {
		return
	}

	// Send message to inform other modules of terminated PDU session
	msg := sbxCtrl.mqLocal.CreateMsg(mq.MsgPduSessionCreated, mq.TargetAll, mq.TargetAll)
	msg.Payload[fieldNodeName] = ueName
	msg.Payload[fieldPduSessionId] = pduSessionId
	log.Debug("TX MSG: ", mq.PrintMsg(msg))
	err = sbxCtrl.mqLocal.SendMsg(msg)
	if err != nil {
		log.Error("Failed to send message. Error: ", err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
}
@@ -1146,6 +1162,18 @@ func ceTerminatePduSession(w http.ResponseWriter, r *http.Request) {
		return
	}

	// Send message to inform other modules of terminated PDU session
	msg := sbxCtrl.mqLocal.CreateMsg(mq.MsgPduSessionTerminated, mq.TargetAll, mq.TargetAll)
	msg.Payload[fieldNodeName] = ueName
	msg.Payload[fieldPduSessionId] = pduSessionId
	log.Debug("TX MSG: ", mq.PrintMsg(msg))
	err = sbxCtrl.mqLocal.SendMsg(msg)
	if err != nil {
		log.Error("Failed to send message. Error: ", err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
}
+2 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ require (
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-model v0.0.0
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-mq v0.0.0
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-net-char-mgr v0.0.0
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-pdu-session-store v0.0.0 // indirect
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-redis v0.0.0
	github.com/gogo/protobuf v1.2.1 // indirect
	github.com/google/btree v1.0.0 // indirect
@@ -41,5 +42,6 @@ replace (
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-model => ../../go-packages/meep-model
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-mq => ../../go-packages/meep-mq
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-net-char-mgr => ../../go-packages/meep-net-char-mgr
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-pdu-session-store => ../../go-packages/meep-pdu-session-store
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-redis => ../../go-packages/meep-redis
)
+35 −13
Original line number Diff line number Diff line
@@ -69,6 +69,11 @@ const (
	EventRemoveNode     string = "EVENT-REMOVE-NODE"
)

const (
	ConnectivityModelOpen string = "OPEN"
	ConnectivityModelPdu  string = "PDU"
)

const Disconnected = "DISCONNECTED"

// ModelCfg - Model Configuration
@@ -94,6 +99,7 @@ type Model struct {
	svcMap            []dataModel.NodeServiceMaps
	nodeMap           *NodeMap
	networkGraph      *NetworkGraph
	connectivityModel string
	lock              sync.RWMutex
}

@@ -119,6 +125,7 @@ func NewModel(cfg ModelCfg) (m *Model, err error) {
	m.subscribed = false
	m.activeKey = dkm.GetKeyRoot(m.namespace) + activeKey
	m.scenario = new(dataModel.Scenario)
	m.connectivityModel = ConnectivityModelOpen

	// Process scenario
	err = m.parseNodes()
@@ -944,6 +951,14 @@ func (m *Model) GetNetworkGraph() *dijkstra.Graph {
	return m.networkGraph.graph
}

// GetConnectivityModel - Get the connectivity model
func (m *Model) GetConnectivityModel() string {
	m.lock.RLock()
	defer m.lock.RUnlock()

	return m.connectivityModel
}

//---Internal Funcs---

func (m *Model) parseNodes() (err error) {
@@ -958,6 +973,9 @@ func (m *Model) parseNodes() (err error) {
			ctx := NewNodeContext(m.scenario.Name, "", "", "", "")
			m.nodeMap.AddNode(NewNode(m.scenario.Name, "DEPLOYMENT", deployment, &deployment.Domains, m.scenario, ctx))
			m.svcMap = make([]dataModel.NodeServiceMaps, 0)
			if deployment.Connectivity != nil {
				m.connectivityModel = deployment.Connectivity.Model
			}

			// Domains
			for iDomain := range m.scenario.Deployment.Domains {
@@ -1199,6 +1217,10 @@ func IsProc(typ string) bool {
	return typ == NodeTypeCloudApp || typ == NodeTypeEdgeApp || typ == NodeTypeUEApp
}

func IsUe(typ string) bool {
	return typ == NodeTypeUE
}

func validateParentType(nodeType string, parentType string) bool {
	if IsScenario(nodeType) {
		return parentType == ""
+4 −0
Original line number Diff line number Diff line
@@ -63,6 +63,10 @@ const (
	MsgScenarioUpdate    Message = "SCENARIO-UPDATE"
	MsgScenarioTerminate Message = "SCENARIO-TERMINATE"

	// PDU Session Management
	MsgPduSessionCreated    Message = "PDU-SESSION-CREATED"
	MsgPduSessionTerminated Message = "PDU-SESSION-TERMINATED"

	// Mobility Groups
	MsgMgLbRulesUpdate Message = "MG-LB-RULES-UPDATE"

+73 −14
Original line number Diff line number Diff line
@@ -118,6 +118,7 @@ type SegmentAlgorithm struct {
	BaseKey           string
	FlowMap           map[string]*SegAlgoFlow
	SegmentMap        map[string]*SegAlgoSegment
	ConnectivityModel string
	Config            SegAlgoConfig
	rc                *redis.Connector
}
@@ -132,6 +133,7 @@ func NewSegmentAlgorithm(name string, namespace string, redisAddr string) (*Segm
	algo.BaseKey = dkm.GetKeyRoot(namespace) + metricsKey
	algo.FlowMap = make(map[string]*SegAlgoFlow)
	algo.SegmentMap = make(map[string]*SegAlgoSegment)
	algo.ConnectivityModel = mod.ConnectivityModelOpen
	algo.Config.MaxBwPerInactiveFlow = 20.0
	algo.Config.MaxBwPerInactiveFlowFloor = 6.0
	algo.Config.MinActivityThreshold = 0.3
@@ -154,7 +156,7 @@ func NewSegmentAlgorithm(name string, namespace string, redisAddr string) (*Segm
}

// ProcessScenario -
func (algo *SegmentAlgorithm) ProcessScenario(model *mod.Model) error {
func (algo *SegmentAlgorithm) ProcessScenario(model *mod.Model, pduSessions map[string]map[string]*dataModel.PduSessionInfo) error {
	var netElemList []SegAlgoNetElem

	// Process empty scenario
@@ -165,6 +167,9 @@ func (algo *SegmentAlgorithm) ProcessScenario(model *mod.Model) error {
		algo.FlowMap = make(map[string]*SegAlgoFlow)
	}

	// Get scenario connectivity model
	algo.ConnectivityModel = model.GetConnectivityModel()

	// Clear segment & flow maps
	algo.SegmentMap = make(map[string]*SegAlgoSegment)
	// Process active scenario
@@ -235,7 +240,7 @@ func (algo *SegmentAlgorithm) ProcessScenario(model *mod.Model) error {
		for _, elemDest := range netElemList {
			if elemSrc.Name != elemDest.Name {
				// Create flow
				algo.populateFlow(elemSrc.Name+":"+elemDest.Name, &elemSrc, &elemDest, 0, model)
				algo.populateFlow(elemSrc.Name+":"+elemDest.Name, &elemSrc, &elemDest, 0, model, pduSessions)

				// Create DB entry to begin collecting metrics for this flow
				algo.createMetricsEntry(elemSrc.Name, elemDest.Name)
@@ -399,7 +404,8 @@ func (algo *SegmentAlgorithm) deleteMetricsEntries() {
}

// populateFlow - Create/Update flow
func (algo *SegmentAlgorithm) populateFlow(flowName string, srcElement *SegAlgoNetElem, destElement *SegAlgoNetElem, maxBw float64, model *mod.Model) {
func (algo *SegmentAlgorithm) populateFlow(flowName string, srcElement *SegAlgoNetElem, destElement *SegAlgoNetElem, maxBw float64,
	model *mod.Model, pduSessions map[string]map[string]*dataModel.PduSessionInfo) {

	// Use existing flow if present or Create new flow
	flow := algo.FlowMap[flowName]
@@ -430,7 +436,7 @@ func (algo *SegmentAlgorithm) populateFlow(flowName string, srcElement *SegAlgoN
	flow.ConfiguredNetChar.PacketLoss = 0
	// Create a new path for this flow
	oldPath := flow.Path
	flow.Path = algo.createPath(flowName, srcElement, destElement, model)
	flow.Path = algo.createPath(flowName, srcElement, destElement, model, pduSessions)
	flow.UpdateRequired = algo.comparePath(oldPath, flow.Path)
}

@@ -453,7 +459,8 @@ func (algo *SegmentAlgorithm) comparePath(oldPath *SegAlgoPath, newPath *SegAlgo
}

// createPath -
func (algo *SegmentAlgorithm) createPath(flowName string, srcElement *SegAlgoNetElem, destElement *SegAlgoNetElem, model *mod.Model) *SegAlgoPath {
func (algo *SegmentAlgorithm) createPath(flowName string, srcElement *SegAlgoNetElem, destElement *SegAlgoNetElem,
	model *mod.Model, pduSessions map[string]map[string]*dataModel.PduSessionInfo) *SegAlgoPath {

	direction := ""
	var segment *SegAlgoSegment
@@ -485,19 +492,71 @@ func (algo *SegmentAlgorithm) createPath(flowName string, srcElement *SegAlgoNet

	// Check if src or dest Physical location is disconnected
	// NOTE: Does not apply to apps on same physical node
	var srcPhyLoc *dataModel.PhysicalLocation
	srcPhyLocNode := model.GetNode(srcElement.PhyLocName)
	if srcPhyLocNode != nil {
		if srcPhyLoc, ok := srcPhyLocNode.(*dataModel.PhysicalLocation); ok {
		var ok bool
		if srcPhyLoc, ok = srcPhyLocNode.(*dataModel.PhysicalLocation); ok {
			path.Disconnected = path.Disconnected || !srcPhyLoc.Connected
		}
	}
	var destPhyLoc *dataModel.PhysicalLocation
	destPhyLocNode := model.GetNode(destElement.PhyLocName)
	if destPhyLocNode != nil {
		if destPhyLoc, ok := destPhyLocNode.(*dataModel.PhysicalLocation); ok {
		var ok bool
		if destPhyLoc, ok = destPhyLocNode.(*dataModel.PhysicalLocation); ok {
			path.Disconnected = path.Disconnected || !destPhyLoc.Connected
		}
	}

	// If in PDU Connectivity mode, check if src or dest UE has PDU connectivity to DN
	// NOTE: For LADN, additionally verify that UE and edge app are in the same zone
	if !path.Disconnected && algo.ConnectivityModel == mod.ConnectivityModelPdu {
		if mod.IsUe(srcPhyLoc.Type_) {
			pduMap, ok := pduSessions[srcPhyLoc.Name]
			if !ok || mod.IsUe(destPhyLoc.Type_) || destPhyLoc.DataNetwork == nil {
				path.Disconnected = true
			} else if destPhyLoc.DataNetwork.Ladn && srcElement.ZoneName != destElement.ZoneName {
				// LADN & not in same zone
				path.Disconnected = true
			} else {
				// Find matching DNN
				var found bool
				for _, pdu := range pduMap {
					if pdu.Dnn == destPhyLoc.DataNetwork.Dnn {
						found = true
						break
					}
				}
				if !found {
					path.Disconnected = true
				}
			}
		}

		if mod.IsUe(destPhyLoc.Type_) {
			pduMap, ok := pduSessions[destPhyLoc.Name]
			if !ok || mod.IsUe(srcPhyLoc.Type_) || srcPhyLoc.DataNetwork == nil {
				path.Disconnected = true
			} else if srcPhyLoc.DataNetwork.Ladn && srcElement.ZoneName != destElement.ZoneName {
				// LADN & not in same zone
				path.Disconnected = true
			} else {
				// Find matching DNN
				var found bool
				for _, pdu := range pduMap {
					if pdu.Dnn == srcPhyLoc.DataNetwork.Dnn {
						found = true
						break
					}
				}
				if !found {
					path.Disconnected = true
				}
			}
		}
	}

	//network location ul, dl
	if srcElement.Type == "UE" {
		direction = "uplink"
Loading