FTTB support

Change-Id: I4fec06a4c9ce65b8ba27f03dc63768307333c49a
diff --git a/internal/pkg/application/application.go b/internal/pkg/application/application.go
index fa9e649..74b72f8 100644
--- a/internal/pkg/application/application.go
+++ b/internal/pkg/application/application.go
@@ -215,6 +215,7 @@
 	FlowDelEventMap              *util.ConcurrentMap //map[string]*FlowEvent
 	MigratingServices            *util.ConcurrentMap //<vnetID,<RequestID, MigrateServicesRequest>>
 	GlobalDhcpFlowAdded          bool
+	NniDhcpTrapVid               of.VlanType
 }
 
 // NewVoltDevice : Constructor for the device
@@ -234,6 +235,11 @@
 	d.FlowAddEventMap = util.NewConcurrentMap()
 	d.FlowDelEventMap = util.NewConcurrentMap()
 	d.GlobalDhcpFlowAdded = false
+	if config, ok := GetApplication().DevicesConfig.Load(slno); ok {
+		//Update nni dhcp vid
+		deviceConfig := config.(DeviceConfig)
+		d.NniDhcpTrapVid = of.VlanType(deviceConfig.NniDhcpTrapVid)
+	}
 	return &d
 }
 
@@ -443,6 +449,7 @@
 	PortAlarmProfileCache     map[string]map[string]int // [portAlarmID][ThresholdLevelString]ThresholdLevel
 	vendorID                  string
 	OltFlowServiceConfig      OltFlowService
+	DevicesConfig             sync.Map
 }
 
 // PonPortCfg contains NB port config and activeIGMPChannels count
@@ -791,14 +798,16 @@
 
 // GetDeviceBySerialNo to get a device by serial number.
 // TODO - Transform this into a MAP instead
-func (va *VoltApplication) GetDeviceBySerialNo(slno string) *VoltDevice {
+func (va *VoltApplication) GetDeviceBySerialNo(slno string) (*VoltDevice, string) {
 	var device *VoltDevice
+	var deviceID string
 	getserial := func(key interface{}, value interface{}) bool {
 		device = value.(*VoltDevice)
+		deviceID = key.(string)
 		return device.SerialNum != slno
 	}
 	va.DevicesDisc.Range(getserial)
-	return device
+	return device, deviceID
 }
 
 // PortAddInd : This is a PORT add indication coming from the VPAgent, which is essentially
@@ -1740,7 +1749,7 @@
 // UpdateDeviceSerialNumberList to update the device serial number list after device serial number is updated for vnet and mvlan
 func (va *VoltApplication) UpdateDeviceSerialNumberList(oldOltSlNo string, newOltSlNo string) {
 
-	voltDevice := va.GetDeviceBySerialNo(oldOltSlNo)
+	voltDevice, _ := va.GetDeviceBySerialNo(oldOltSlNo)
 
 	if voltDevice != nil {
 		// Device is present with old serial number ID
@@ -2080,7 +2089,7 @@
 		if vnetIntf, _ := va.VnetsByName.Load(vnetName); vnetIntf != nil {
 			vnet := vnetIntf.(*VoltVnet)
 			logger.Warnw(ctx, "Triggering Pending Vnet flows delete", log.Fields{"Vnet": vnet.Name})
-			if d := va.GetDeviceBySerialNo(vnet.PendingDeviceToDelete); d != nil && d.SerialNum == vnet.PendingDeviceToDelete {
+			if d, _ := va.GetDeviceBySerialNo(vnet.PendingDeviceToDelete); d != nil && d.SerialNum == vnet.PendingDeviceToDelete {
 				va.DeleteDevFlowForVlanFromDevice(cntx, vnet, vnet.PendingDeviceToDelete)
 				va.deleteVnetConfig(vnet)
 			} else {
@@ -2124,3 +2133,34 @@
 	}
 	logger.Infow(ctx, "updated OltFlowServiceConfig from DB", log.Fields{"OltFlowServiceConfig": va.OltFlowServiceConfig})
 }
+
+type DeviceConfig struct {
+	SerialNumber       string
+	UplinkPort         int
+	HardwareIdentifier string
+	IPAddress          net.IP
+	NasID              string
+	NniDhcpTrapVid     int
+}
+
+func (va *VoltApplication) UpdateDeviceConfig(cntx context.Context, sn, mac, nasID string, port, dhcpVid int, ip net.IP) {
+	if d, ok := va.DevicesConfig.Load(sn); ok {
+		logger.Infow(ctx, "Device configuration already exists", log.Fields{"DeviceInfo": d})
+	}
+	d := DeviceConfig {
+		SerialNumber       : sn,
+		UplinkPort         : port,
+		HardwareIdentifier : mac,
+		IPAddress          : ip,
+		NasID              : nasID,
+		NniDhcpTrapVid     : dhcpVid,
+	}
+	logger.Infow(ctx, "Added OLT configurations", log.Fields{"DeviceInfo": d})
+	va.DevicesConfig.Store(sn, d)
+	// If device is already discovered update the VoltDevice structure
+	device, id := va.GetDeviceBySerialNo(sn)
+	if device != nil {
+		device.NniDhcpTrapVid = of.VlanType(dhcpVid)
+		va.DevicesDisc.Store(id, device)
+	}
+}
diff --git a/internal/pkg/application/igmp.go b/internal/pkg/application/igmp.go
index 2e49a41..a63370d 100644
--- a/internal/pkg/application/igmp.go
+++ b/internal/pkg/application/igmp.go
@@ -1413,7 +1413,7 @@
 	va.delOltFromMvlan(cntx, MvlanProfileID, OltSerialNum)
 	va.deleteMcastConfig(OltSerialNum, MvlanProfileID)
 	_ = db.DelMcastConfig(cntx, McastConfigKey(OltSerialNum, MvlanProfileID))
-	if d := va.GetDeviceBySerialNo(OltSerialNum); d != nil {
+	if d, _ := va.GetDeviceBySerialNo(OltSerialNum); d != nil {
 		if mvp := va.GetMvlanProfileByName(MvlanProfileID); mvp != nil {
 			va.RemoveGroupsFromPendingPool(cntx, d.Name, mvp.Mvlan)
 		}
diff --git a/internal/pkg/application/igmpprofiles.go b/internal/pkg/application/igmpprofiles.go
index 192c8e2..b855eb8 100644
--- a/internal/pkg/application/igmpprofiles.go
+++ b/internal/pkg/application/igmpprofiles.go
@@ -405,7 +405,7 @@
                 return
         }
 
-        d := GetApplication().GetDeviceBySerialNo(OLTSerialNum)
+        d, _ := GetApplication().GetDeviceBySerialNo(OLTSerialNum)
         if d == nil {
                 logger.Warnw(ctx, "Skipping Igmp & Mcast Flow processing: Device Not Found", log.Fields{"Device_SrNo": OLTSerialNum, "Mvlan": mvp.Mvlan})
                 return
@@ -437,7 +437,7 @@
         mvp.mvpLock.RLock()
         defer mvp.mvpLock.RUnlock()
 
-        if d := GetApplication().GetDeviceBySerialNo(oltSerialNum); d != nil {
+        if d, _ := GetApplication().GetDeviceBySerialNo(oltSerialNum); d != nil {
                 p := d.GetPort(d.NniPort)
                 if p != nil {
                         logger.Infow(ctx, "NNI Port Status is: UP", log.Fields{"Device": d, "port": p})
@@ -1028,7 +1028,7 @@
         va := GetApplication()
         logger.Debugw(ctx, "Update of Active Channel Subscriber Alarm", log.Fields{"Mvlan": mvp.Mvlan})
         for srNo := range mvp.DevicesList {
-                d := va.GetDeviceBySerialNo(srNo)
+                d, _ := va.GetDeviceBySerialNo(srNo)
                 if d == nil {
                         logger.Warnw(ctx, "Device info not found", log.Fields{"Device_SrNo": srNo, "Mvlan": mvp.Mvlan})
                         return
diff --git a/internal/pkg/application/service.go b/internal/pkg/application/service.go
index 4ddd45d..9315b5b 100644
--- a/internal/pkg/application/service.go
+++ b/internal/pkg/application/service.go
@@ -71,6 +71,10 @@
 	SVlanTpid                  layers.EthernetType
 	MacAddr                    net.HardwareAddr
 	Pbits                      []of.PbitType
+	UsPonCTagPriority          of.PbitType
+	UsPonSTagPriority          of.PbitType
+	DsPonCTagPriority          of.PbitType
+	DsPonSTagPriority          of.PbitType
 	DsRemarkPbitsMap           map[int]int // Ex: Remark case {0:0,1:0} and No-remark case {1:1}
 	TechProfileID              uint16
 	CircuitID                  string
@@ -99,6 +103,7 @@
 	MaxDataRateDs              uint32
 	IsActivated                bool
 	Trigger                    ServiceTrigger
+	ServiceType                string
 }
 
 // VoltServiceOper structure
@@ -285,6 +290,25 @@
 	}
 }
 
+func (vs *VoltService) AddMeterToDevice(cntx context.Context) error {
+	if vs.DeleteInProgress || vs.UpdateInProgress {
+		logger.Errorw(ctx, "Ignoring Meter Push, Service deleteion In-Progress", log.Fields{"Device": vs.Device, "Service": vs.Name})
+	}
+	va := GetApplication()
+	logger.Infow(ctx, "Configuring Meters for FTTB", log.Fields{"ServiceName": vs.Name})
+	device, err := va.GetDeviceFromPort(vs.Port)
+	if err != nil {
+		logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
+		return errorCodes.ErrDeviceNotFound
+	} else if device.State != controller.DeviceStateUP {
+		logger.Warnw(ctx, "Device state Down. Ignoring Meter Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
+		return nil
+	}
+	va.AddMeterToDevice(vs.Port, device.Name, vs.UsMeterID, 0)
+	va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
+	return nil
+}
+
 // AddUsHsiaFlows - Add US HSIA Flows for the service
 func (vs *VoltService) AddUsHsiaFlows(cntx context.Context) error {
 
@@ -306,9 +330,11 @@
 		}
 
 		vs.Device = device.Name
-		va.AddMeterToDevice(vs.Port, device.Name, vs.UsMeterID, 0)
-		va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
-
+		/* In case of DPU_MGMT_TRAFFIC the meters will be configured before US flow creation*/
+		if vs.ServiceType != DPU_MGMT_TRAFFIC {
+			va.AddMeterToDevice(vs.Port, device.Name, vs.UsMeterID, 0)
+			va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
+		}
 		logger.Infow(ctx, "Adding HSIA flows", log.Fields{"Name": vs.Name})
 		pBits := vs.Pbits
 
@@ -560,7 +586,6 @@
 		if pbits != PbitMatchNone {
 			subflow1.SetMatchPbit(pbits)
 		}
-
 		if remarkExists && (of.PbitType(remarkPbit) != pbits) {
 			subflow1.SetPcp(of.PbitType(remarkPbit))
 			// match & action pbits are different, set remark-pbit action
@@ -703,14 +728,6 @@
 	// PortName and PortID to be used for validation of port before flow pushing
 	flow.PortID = inport
 	flow.PortName = vs.Port
-	allowTransparent := 0
-	reqBwInfo := 0
-	if vs.AllowTransparent {
-		allowTransparent = 1
-	}
-	if vs.BwAvailInfo == "" {
-		reqBwInfo = 1
-	}
 
 	// Add Table-0 flow that deals with the inner VLAN in ONU
 	{
@@ -719,42 +736,24 @@
 		subflow1.SetGoToTable(1)
 		subflow1.SetInPort(inport)
 
+		if vs.ServiceType == DPU_MGMT_TRAFFIC {
+			subflow1.SetMatchPbit(vs.UsPonCTagPriority)
+			subflow1.SetPcp(vs.UsPonSTagPriority)
+		} else if vs.ServiceType == DPU_ANCP_TRAFFIC {
+			subflow1.SetPcp(vs.UsPonSTagPriority)
+		}
 		if err := vs.setUSMatchActionVlanT0(subflow1); err != nil {
 			return nil, err
 		}
 		subflow1.SetMeterID(vs.UsMeterID)
 
-		if GetApplication().GetVendorID() == Radisys {
-			if pbits != PbitMatchNone {
-				subflow1.SetMatchPbit(pbits)
-			}
-			/* WriteMetaData 8 Byte(uint64) usage:
-			| Byte8    | Byte7    | Byte6 | Byte5  | Byte4  | Byte3   | Byte2  | Byte1 |
-			| reserved | reserved | TpID  | TpID   | uinID  | uniID   | uniID  | uniID | */
-			metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
-			subflow1.SetWriteMetadata(metadata)
-			/* TableMetaData 8 Byte(uint64) usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
-			|                         Byte8                     |  Byte7    |  Byte6    |      Byte5       |  Byte4    | Byte3    | Byte2    | Byte1   |
-			| 000      |    0      |    00     |    0     |  0  |  00000000 |  00000000 |  0000   0000     |  00000000 | 00000000 | 00000000 | 00000000|
-			| reserved | reqBwInfo | svlanTpID |  Buff us |  AT |  schedID  |  schedID  | onteth  vlanCtrl |  unitag   | unitag   | ctag     | ctag    | */
-			metadata = uint64(reqBwInfo)<<60 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
+		/* WriteMetaData 8 Byte(uint64) usage:
+		| Byte8    | Byte7    | Byte6 | Byte5  | Byte4  | Byte3   | Byte2  | Byte1 |
+		| reserved | reserved | TpID  | TpID   | uinID  | uniID   | uniID  | uniID | */
+		//metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
+		metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
+		subflow1.SetWriteMetadata(metadata)
 
-			// // In case of MAC Learning enabled voltha will buffer the US flow installation.
-			// if NonZeroMacAddress(vs.MacAddr) {
-			// 	subflow1.SetMatchSrcMac(vs.MacAddr)
-			// } else if vs.MacLearning != MacLearning {
-			// 	metadata |= 1 << 57
-			// 	logger.Infow(ctx, "Buffer us flow at adapter", log.Fields{"metadata": metadata})
-			// }
-			subflow1.SetTableMetadata(metadata)
-		} else {
-			/* WriteMetaData 8 Byte(uint64) usage:
-			| Byte8    | Byte7    | Byte6 | Byte5  | Byte4  | Byte3   | Byte2  | Byte1 |
-			| reserved | reserved | TpID  | TpID   | uinID  | uniID   | uniID  | uniID | */
-			//metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
-			metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
-			subflow1.SetWriteMetadata(metadata)
-		}
 		if vs.VlanControl == OLTCVlanOLTSVlan {
 			/**
 			 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
@@ -783,33 +782,17 @@
 		if err := vs.setUSMatchActionVlanT1(subflow2); err != nil {
 			return nil, err
 		}
+		if vs.ServiceType == DPU_MGMT_TRAFFIC {
+			subflow2.SetMatchSrcMac(vs.MacAddr)
+		}
 		subflow2.SetInPort(inport)
 		subflow2.SetOutPort(outport)
 		subflow2.SetMeterID(vs.UsMeterID)
 
-		if GetApplication().GetVendorID() == Radisys {
-			if pbits != PbitMatchNone {
-				subflow2.SetMatchPbit(pbits)
-			}
-			// refer Table-0 flow generation for byte information
-			metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
-			subflow2.SetWriteMetadata(metadata)
-			// refer Table-0 flow generation for byte information
-			metadata = uint64(reqBwInfo)<<60 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
-			// // In case of MAC Learning enabled voltha will buffer the US flow installation.
-			// if NonZeroMacAddress(vs.MacAddr) {
-			// 	subflow2.SetMatchSrcMac(vs.MacAddr)
-			// } else if vs.MacLearning != MacLearningNone {
-			// 	metadata |= 1 << 57
-			// 	logger.Infow(ctx, "Buffer us flow at adapter", log.Fields{"metadata": metadata})
-			// }
-			subflow2.SetTableMetadata(metadata)
-		} else {
-			// refer Table-0 flow generation for byte information
-			metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
-			subflow2.SetWriteMetadata(metadata)
+		// refer Table-0 flow generation for byte information
+		metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
+		subflow2.SetWriteMetadata(metadata)
 
-		}
 		if vs.VlanControl == OLTCVlanOLTSVlan {
 			/**
 			 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
@@ -1085,6 +1068,12 @@
 		return errors.New("VNET doesn't exist")
 	}
 
+	// If the device is already discovered, update the device name in service
+	d, err := va.GetDeviceFromPort(vs.Port)
+	if err == nil {
+		vs.Device = d.Name
+	}
+
 	vs.Version = database.PresentVersionMap[database.ServicePath]
 	// Add the service to the volt application
 	va.ServiceByName.Store(vs.Name, vs)
@@ -1588,7 +1577,7 @@
 		return errors.New("New Vnet Id not found")
 	}
 
-	d := va.GetDeviceBySerialNo(serialNum)
+	d, _ := va.GetDeviceBySerialNo(serialNum)
 	if d == nil {
 		logger.Errorw(ctx, "Error Getting Device", log.Fields{"SerialNum": serialNum})
 		return errorCodes.ErrDeviceNotFound
@@ -2064,6 +2053,7 @@
 		vs := value.(*VoltService)
 		// If svlan if provided, then the tags and tpID of service has to be matching
 		if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
+			logger.Infow(ctx, "Service Activate Request Does not match", log.Fields{"Device": deviceID, "voltService": vs})
 			return true
 		}
 		if portNo == vs.Port && !vs.IsActivated {
diff --git a/internal/pkg/application/vnets.go b/internal/pkg/application/vnets.go
index dffbb00..1313490 100644
--- a/internal/pkg/application/vnets.go
+++ b/internal/pkg/application/vnets.go
@@ -44,6 +44,15 @@
 
 	// Radisys vendor id constant
 	Radisys string = "Radisys"
+
+	// DPU_MGMT_TRAFFIC serviceType, vnetType constant
+	DPU_MGMT_TRAFFIC string = "DPU_MGMT_TRAFFIC"
+
+	// DPU_ANCP_TRAFFIC serviceType, vnetType constant
+	DPU_ANCP_TRAFFIC string = "DPU_ANCP_TRAFFIC"
+
+	// FTTB_SUBSCRIBER_TRAFFIC serviceType, vnetType constant
+	FTTB_SUBSCRIBER_TRAFFIC string = "FTTB_SUBSCRIBER_TRAFFIC"
 )
 
 var (
@@ -109,6 +118,11 @@
 	DevicesList                []string //List of serial number of devices on which this vnet is applied
 	AllowTransparent           bool
 	CtrlPktPbitRemark          map[of.PbitType]of.PbitType
+	UsPonCTagPriority          of.PbitType
+	UsPonSTagPriority          of.PbitType
+	DsPonCTagPriority          of.PbitType
+	DsPonSTagPriority          of.PbitType
+	VnetType                   string
 }
 
 // VnetOper structure
@@ -438,6 +452,11 @@
 	DeleteInProgress           bool
 	Blocked                    bool
 	DhcpPbit                   of.PbitType
+	UsPonCTagPriority          of.PbitType
+	UsPonSTagPriority          of.PbitType
+	DsPonCTagPriority          of.PbitType
+	DsPonSTagPriority          of.PbitType
+	VnetType                   string
 }
 
 //VlanControl vlan control type
@@ -490,6 +509,7 @@
 	vpv.MacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
 	vpv.LearntMacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
 	// for OLTCVLAN SVLAN=CVLAN, UNIVLAN can differ.
+	/*
 	if vpv.VlanControl == ONUCVlan {
 		vpv.CVlan = vpv.SVlan
 	}
@@ -497,11 +517,17 @@
 	// hence assigning UNIVLAN to CVLAN, so that ONU will transparently forward the packet.
 	if vpv.VlanControl == OLTSVlan {
 		vpv.CVlan = vpv.UniVlan
-	}
+	}*/
 	vpv.servicesCount = atomic.NewUint64(0)
 	vpv.SchedID = 0
 	vpv.PendingDeleteFlow = make(map[string]bool)
 	vpv.DhcpPbit = vnet.UsDhcpPbit[0]
+	vpv.UsPonCTagPriority = vnet.UsPonCTagPriority
+	vpv.UsPonSTagPriority = vnet.UsPonSTagPriority
+	vpv.DsPonCTagPriority = vnet.UsPonCTagPriority
+	vpv.DsPonSTagPriority = vnet.UsPonSTagPriority
+
+	vpv.VnetType = vnet.VnetType
 	return &vpv
 }
 
@@ -766,17 +792,24 @@
 		// If MAC Learning is true if no MAC is configured, push DS/US DHCP, US HSIA flows without MAC.
 		// DS HSIA flows are installed after learning the MAC.
 		logger.Infow(ctx, "Port Up - Trap Flows", log.Fields{"Device": device.Name, "Port": port})
-		// no HSIA flows for multicast service
-		if !vpv.McastService {
+		// no HSIA flows for multicast service and DPU_MGMT Service
+		if !vpv.McastService && vpv.VnetType != DPU_MGMT_TRAFFIC {
 			vpv.RangeOnServices(cntx, AddUsHsiaFlows)
 		}
+		if vpv.VnetType == DPU_MGMT_TRAFFIC {
+			vpv.RangeOnServices(cntx, AddMeterToDevice)
+		}
 		vpv.AddTrapFlows(cntx)
 		if vpv.MacLearning == MacLearningNone || NonZeroMacAddress(vpv.MacAddr) {
 			logger.Infow(ctx, "Port Up - DS Flows", log.Fields{"Device": device.Name, "Port": port})
+			/*In case of DPU_MGMT_TRAFFIC, need to install both US and DS traffic */
+			if  vpv.VnetType == DPU_MGMT_TRAFFIC {
+				vpv.RangeOnServices(cntx, AddUsHsiaFlows)
+			}
 			// US & DS DHCP, US HSIA flows are already installed
 			// install only DS HSIA flow here.
 			// no HSIA flows for multicast service
-			if !vpv.McastService {
+			if !vpv.McastService  {
 				vpv.RangeOnServices(cntx, AddDsHsiaFlows)
 			}
 		}
@@ -889,6 +922,10 @@
 	}
 	// Ds Hsia flows has to be pushed
 	if vpv.FlowsApplied {
+		// In case of DPU_MGMT_TRAFFIC install both US and DS Flows
+		if vpv.VnetType == DPU_MGMT_TRAFFIC {
+			vpv.RangeOnServices(cntx, AddUsHsiaFlows)
+		}
 		// no HSIA flows for multicast service
 		if !vpv.McastService {
 			vpv.RangeOnServices(cntx, AddDsHsiaFlows)
@@ -1002,6 +1039,8 @@
 	logger.Debugw(ctx, "Added MAC to VPV", log.Fields{"MacLearning": vpv.MacLearning, "VPV": vpv})
 	//Reconfigure Vlans based on Vlan Control type
 	svc.VlanControl = vpv.VlanControl
+	//TODO Is it good to change NB config?? commenting for now
+	/*
 	// for OLTCVLAN SVLAN=CVLAN, UNIVLAN can differ.
 	if vpv.VlanControl == ONUCVlan {
 		svc.CVlan = svc.SVlan
@@ -1010,7 +1049,7 @@
 	// hence assigning UNIVLAN to CVLAN, so that ONU will transparently forward the packet.
 	if vpv.VlanControl == OLTSVlan {
 		svc.CVlan = svc.UniVlan
-	}
+	}*/
 	if svc.McastService {
 		vpv.McastService = true
 		vpv.McastTechProfileID = svc.TechProfileID
@@ -1172,6 +1211,15 @@
 	return true
 }
 
+// AddMeterToDevice to add meter config to device, used in FTTB case
+func AddMeterToDevice(cntx context.Context, key, value interface{}) bool {
+	svc := value.(*VoltService)
+	if err:= svc.AddMeterToDevice(cntx); err != nil {
+		logger.Warnw(ctx, "Add Meter failed", log.Fields{"service": svc.Name, "Error": err})
+	}
+	return true
+}
+
 //AddTrapFlows - Adds US & DS Trap flows
 func (vpv *VoltPortVnet) AddTrapFlows(cntx context.Context) {
 
@@ -1331,7 +1379,8 @@
 		logger.Errorw(ctx, "DS DHCP Flow Push Failed- Device not found", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
 		return errorCodes.ErrDeviceNotFound
 	}
-	if GetApplication().GetVendorID() != Radisys && vd.GlobalDhcpFlowAdded {
+	if vd.GlobalDhcpFlowAdded {
+		logger.Info(ctx, "Global Dhcp flow already exists")
 		return nil
 	}
 
@@ -1685,17 +1734,20 @@
 	subFlow := of.NewVoltSubFlow()
 	subFlow.SetTableID(0)
 
-	if GetApplication().GetVendorID() == Radisys {
-		if err := vpv.setUsMatchVlan(subFlow); err != nil {
-			return nil, err
-		}
+
+	if vpv.VnetType == DPU_MGMT_TRAFFIC {
+		subFlow.SetMatchVlan(vpv.CVlan)
+		subFlow.SetMatchPbit(vpv.UsPonCTagPriority)
+		subFlow.SetPcp(vpv.UsPonSTagPriority)
+		subFlow.SetSetVlan(vpv.SVlan)
 	} else {
 		subFlow.SetMatchVlan(vpv.UniVlan)
 		subFlow.SetSetVlan(vpv.CVlan)
+		subFlow.SetPcp(vpv.DhcpPbit)
 	}
 	subFlow.SetUdpv4Match()
-	subFlow.SrcPort = 68
 	subFlow.DstPort = 67
+	subFlow.SrcPort = 68
 	uniport, err := GetApplication().GetPortID(vpv.Port)
 	if err != nil {
 		logger.Errorw(ctx, "Failed to fetch uni port from vpv", log.Fields{"error": err, "port": vpv.Port})
@@ -1709,23 +1761,28 @@
 
 	// Set techprofile, meterid of first service
 	vpv.services.Range(func(key, value interface{}) bool {
-		svc := value.(*VoltService)
-		writemetadata := uint64(svc.TechProfileID) << 32
+		vs := value.(*VoltService)
+		var writemetadata uint64
+		if vpv.VnetType == DPU_MGMT_TRAFFIC {
+			writemetadata = uint64(vs.SVlan)<<48 + uint64(vs.TechProfileID)<<32
+		} else {
+			writemetadata = uint64(vs.TechProfileID) << 32
+		}
 		subFlow.SetWriteMetadata(writemetadata)
-		subFlow.SetMeterID(svc.UsMeterID)
+		subFlow.SetMeterID(vs.UsMeterID)
 		return false
 	})
 
-	subFlow.SetPcp(vpv.DhcpPbit)
 	// metadata := uint64(uniport)
 	// subFlow.SetWriteMetadata(metadata)
 	allowTransparent := 0
 	if vpv.AllowTransparent {
 		allowTransparent = 1
 	}
-	metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
-	subFlow.SetTableMetadata(metadata)
-
+	if vpv.VnetType != DPU_MGMT_TRAFFIC {
+		metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
+		subFlow.SetTableMetadata(metadata)
+	}
 	//| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
 	subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.DhcpArpFlowMask | of.UsFlowMask
 	subFlow.Priority = of.DhcpFlowPriority
@@ -1743,9 +1800,9 @@
 	flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
 	subFlow := of.NewVoltSubFlow()
 	subFlow.SetTableID(0)
-	// If dhcp trap rule is global rule, No need to match on vlan
-	if GetApplication().GetVendorID() == Radisys {
-		vpv.setDsMatchVlan(subFlow)
+	// match on vlan only for fttb case
+	if vpv.VnetType == DPU_MGMT_TRAFFIC {
+		subFlow.SetMatchVlan(vpv.SVlan)
 	}
 	subFlow.SetUdpv4Match()
 	subFlow.SrcPort = 67
@@ -1769,12 +1826,14 @@
 	if vpv.AllowTransparent {
 		allowTransparent = 1
 	}
-	metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
-	subFlow.SetTableMetadata(metadata)
+	if vpv.VnetType != DPU_MGMT_TRAFFIC {
+		metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
+		subFlow.SetTableMetadata(metadata)
+		subFlow.Priority = of.DhcpFlowPriority
+	}
 	subFlow.SetReportToController()
 	//| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
 	subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.DhcpArpFlowMask | of.DsFlowMask
-	subFlow.Priority = of.DhcpFlowPriority
 
 	flow.SubFlows[subFlow.Cookie] = subFlow
 	logger.Infow(ctx, "Built DS DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "Flow": flow})
diff --git a/voltha-go-controller/nbi/sadissubscriber.go b/voltha-go-controller/nbi/subscriber.go
similarity index 81%
rename from voltha-go-controller/nbi/sadissubscriber.go
rename to voltha-go-controller/nbi/subscriber.go
index 0bfe39c..dca6fa2 100644
--- a/voltha-go-controller/nbi/sadissubscriber.go
+++ b/voltha-go-controller/nbi/subscriber.go
@@ -42,6 +42,7 @@
 	NasID              string              `json:"nasId"`
 	CircuitID          string              `json:"circuitId"`
 	RemoteID           string              `json:"remoteId"`
+	NniDhcpTrapVid     int                 `json:"nniDhcpTrapVid"`
 	UniTagList         []UniTagInformation `json:"uniTagList"`
 }
 
@@ -121,7 +122,12 @@
 func addAllService(cntx context.Context, srvInfo *SubscriberDeviceInfo) {
 
 	//vsCfgList := getVoltServiceFromSrvInfo(srvInfo)
-
+	va := app.GetApplication()
+	if len(srvInfo.UniTagList) == 0 {
+		logger.Debugw(ctx, "Received OLT configuration", log.Fields{"req": srvInfo})
+		va.UpdateDeviceConfig(cntx, srvInfo.ID, srvInfo.HardwareIdentifier, srvInfo.NasID, srvInfo.UplinkPort, srvInfo.NniDhcpTrapVid, srvInfo.IPAddress)
+		return
+	}
 	for _, uniTagInfo := range srvInfo.UniTagList {
 		var vs application.VoltServiceCfg
 
@@ -136,14 +142,22 @@
 		vs.SVlan = of.VlanType(uniTagInfo.PonSTag)
 		vs.CVlan = of.VlanType(uniTagInfo.PonCTag)
 		vs.UniVlan = of.VlanType(uniTagInfo.UniTagMatch)
+		vs.UsPonCTagPriority = of.PbitType(uniTagInfo.UsPonCTagPriority)
+		vs.UsPonSTagPriority = of.PbitType(uniTagInfo.UsPonSTagPriority)
+		vs.DsPonCTagPriority = of.PbitType(uniTagInfo.UsPonCTagPriority)
+		vs.DsPonSTagPriority = of.PbitType(uniTagInfo.UsPonSTagPriority)
 		vs.TechProfileID = uint16(uniTagInfo.TechnologyProfileID)
 		vs.UsMeterProfile = uniTagInfo.UpstreamBandwidthProfile
 		vs.DsMeterProfile = uniTagInfo.DownstreamBandwidthProfile
 		vs.IgmpEnabled = uniTagInfo.IsIgmpRequired
-		//vs.McastService = uniTagInfo.IsIgmpRequired
-		if vs.IgmpEnabled {
-			vs.MvlanProfileName = "mvlan" + strconv.Itoa(uniTagInfo.PonSTag)
-		}
+		vs.ServiceType = uniTagInfo.ServiceName
+
+		if uniTagInfo.ServiceName == app.DPU_MGMT_TRAFFIC ||
+		   uniTagInfo.ServiceName == app.DPU_ANCP_TRAFFIC ||
+		   uniTagInfo.ServiceName == app.FTTB_SUBSCRIBER_TRAFFIC {
+			vs.UniVlan = vs.CVlan
+			vs.Pbits = append(vs.Pbits, of.PbitMatchAll)
+		} else {
 		if uniTagInfo.UsPonSTagPriority == -1 {
 			vs.Pbits = append(vs.Pbits, of.PbitMatchAll)
 		// Process the p-bits received in the request
@@ -156,7 +170,11 @@
 				vs.Pbits = append(vs.Pbits, of.PbitType(uniTagInfo.DsPonCTagPriority))
 			}
 		}
-
+		}
+		//vs.McastService = uniTagInfo.IsIgmpRequired
+		if vs.IgmpEnabled {
+			vs.MvlanProfileName = "mvlan" + strconv.Itoa(uniTagInfo.PonSTag)
+		}
 		/*
 		var err error
 		if vs.MacAddr, err = net.ParseMAC(srvInfo.HardwareIdentifier); err != nil {
@@ -173,22 +191,35 @@
 		vnetName = vnetName + strconv.FormatUint(uint64(vs.UniVlan), 10)
 
 		vnetcfg := app.VnetConfig{
-			Name:       vnetName,
-			SVlan:      vs.SVlan,
-			CVlan:      vs.CVlan,
-			UniVlan:    vs.UniVlan,
-			SVlanTpid:  layers.EthernetTypeDot1Q,
-			DhcpRelay:  uniTagInfo.IsDhcpRequired,
-			//MacLearning:                req.MacLearning,
+			Name:              vnetName,
+			SVlan:             vs.SVlan,
+			CVlan:             vs.CVlan,
+			UniVlan:           vs.UniVlan,
+			SVlanTpid:         layers.EthernetTypeDot1Q,
+			DhcpRelay:         uniTagInfo.IsDhcpRequired,
+			VnetType:          uniTagInfo.ServiceName,
+			UsPonCTagPriority: vs.UsPonCTagPriority,
+			UsPonSTagPriority: vs.UsPonSTagPriority,
+			DsPonCTagPriority: vs.UsPonCTagPriority,
+			DsPonSTagPriority: vs.UsPonSTagPriority,
 			//ONTEtherTypeClassification: req.ONTEtherTypeClassification,
 			//VlanControl:                app.VlanControl(req.VlanControl), //TODO
 		}
+		if uniTagInfo.EnableMacLearning {
+			vnetcfg.MacLearning = app.Learn
+		}
 		if uniTagInfo.UsPonSTagPriority < 8 {
 			vnetcfg.UsDhcpPbit = append(vnetcfg.UsDhcpPbit, of.PbitType(uniTagInfo.UsPonSTagPriority))
 		}
-
 		if vs.CVlan != of.VlanAny && vs.SVlan != of.VlanAny {
-			vnetcfg.VlanControl = app.ONUCVlanOLTSVlan
+			if uniTagInfo.ServiceName == app.DPU_MGMT_TRAFFIC ||
+			   uniTagInfo.ServiceName == app.DPU_ANCP_TRAFFIC {
+				vnetcfg.VlanControl = app.ONUCVlan
+			} else if uniTagInfo.ServiceName == app.FTTB_SUBSCRIBER_TRAFFIC {
+				vnetcfg.VlanControl = app.OLTSVlan
+			} else {
+				vnetcfg.VlanControl = app.ONUCVlanOLTSVlan
+			}
 		} else if vs.CVlan == of.VlanAny && vs.UniVlan == of.VlanAny {
 			vnetcfg.VlanControl = app.OLTSVlan
 		}