[VOL-2778] Introducing Service definition in order to support the TT workflow

Change-Id: Ib171502e8940b5d0b219620a4503f7095d376d7a
diff --git a/internal/bbsim/devices/olt.go b/internal/bbsim/devices/olt.go
index 21b57f2..eff9c86 100644
--- a/internal/bbsim/devices/olt.go
+++ b/internal/bbsim/devices/olt.go
@@ -18,6 +18,7 @@
 
 import (
 	"context"
+	"encoding/hex"
 	"fmt"
 	"net"
 	"sync"
@@ -73,7 +74,7 @@
 	enableContext       context.Context
 	enableContextCancel context.CancelFunc
 
-	OpenoltStream *openolt.Openolt_EnableIndicationServer
+	OpenoltStream openolt.Openolt_EnableIndicationServer
 	enablePerf    bool
 }
 
@@ -84,7 +85,7 @@
 	return &olt
 }
 
-func CreateOLT(options common.BBSimYamlConfig, isMock bool) *OltDevice {
+func CreateOLT(options common.GlobalConfig, services []common.ServiceYaml, isMock bool) *OltDevice {
 	oltLogger.WithFields(log.Fields{
 		"ID":           options.Olt.ID,
 		"NumNni":       options.Olt.NniPorts,
@@ -146,44 +147,61 @@
 		olt.Nnis = append(olt.Nnis, &nniPort)
 	}
 
+	// Create device and Services
+
+	nextCtag := map[string]int{}
+	nextStag := map[string]int{}
+
 	// create PON ports
+	for i := 0; i < olt.NumPon; i++ {
+		p := CreatePonPort(&olt, uint32(i))
 
-	if options.BBSim.STagAllocation == common.TagAllocationShared && options.BBSim.CTagAllocation == common.TagAllocationShared {
-		oltLogger.Fatalf("This configuration will result in duplicate C/S tags combination")
-	} else if options.BBSim.STagAllocation == common.TagAllocationUnique && options.BBSim.CTagAllocation == common.TagAllocationUnique {
-		oltLogger.Fatalf("This configuration is not supported yet")
-	} else if options.BBSim.STagAllocation == common.TagAllocationShared && options.BBSim.CTagAllocation == common.TagAllocationUnique {
-		// ATT case
-		availableCTag := options.BBSim.CTag
-		for i := 0; i < olt.NumPon; i++ {
-			p := CreatePonPort(&olt, uint32(i))
+		// create ONU devices
+		for j := 0; j < olt.NumOnuPerPon; j++ {
+			delay := time.Duration(olt.Delay*j) * time.Millisecond
+			o := CreateONU(&olt, p, uint32(j+1), delay, isMock)
 
-			// create ONU devices
-			for j := 0; j < olt.NumOnuPerPon; j++ {
-				delay := time.Duration(olt.Delay*j) * time.Millisecond
-				o := CreateONU(&olt, p, uint32(j+1), options.BBSim.STag, availableCTag, options.BBSim.EnableAuth, options.BBSim.EnableDhcp, delay, isMock)
-				p.Onus = append(p.Onus, o)
-				availableCTag = availableCTag + 1
+			for k, s := range common.Services {
+
+				// find the correct cTag for this service
+				if _, ok := nextCtag[s.Name]; !ok {
+					// it's the first time we iterate over this service,
+					// so we start from the config value
+					nextCtag[s.Name] = s.CTag
+				} else {
+					// we have a previous value, so we check it
+					// if Allocation is unique, we increment,
+					// otherwise (shared) we do nothing
+					if s.CTagAllocation == common.TagAllocationUnique.String() {
+						nextCtag[s.Name] = nextCtag[s.Name] + 1
+					}
+				}
+
+				// find the correct sTag for this service
+				if _, ok := nextStag[s.Name]; !ok {
+					nextStag[s.Name] = s.STag
+				} else {
+					if s.STagAllocation == common.TagAllocationUnique.String() {
+						nextStag[s.Name] = nextStag[s.Name] + 1
+					}
+				}
+
+				mac := net.HardwareAddr{0x2e, 0x60, byte(olt.ID), byte(p.ID), byte(o.ID), byte(k)}
+				service, err := NewService(s.Name, mac, o, nextCtag[s.Name], nextStag[s.Name],
+					s.NeedsEapol, s.NeedsDchp, s.NeedsIgmp, s.TechnologyProfileID, s.UniTagMatch,
+					s.ConfigureMacAddress, s.UsPonCTagPriority, s.UsPonSTagPriority, s.DsPonCTagPriority, s.DsPonSTagPriority)
+
+				if err != nil {
+					oltLogger.WithFields(log.Fields{
+						"Err": err.Error(),
+					}).Fatal("Can't create Service")
+				}
+
+				o.Services = append(o.Services, service)
 			}
-
-			olt.Pons = append(olt.Pons, p)
+			p.Onus = append(p.Onus, o)
 		}
-	} else if options.BBSim.STagAllocation == common.TagAllocationUnique && options.BBSim.CTagAllocation == common.TagAllocationShared {
-		// DT case
-		availableSTag := options.BBSim.STag
-		for i := 0; i < olt.NumPon; i++ {
-			p := CreatePonPort(&olt, uint32(i))
-
-			// create ONU devices
-			for j := 0; j < olt.NumOnuPerPon; j++ {
-				delay := time.Duration(olt.Delay*j) * time.Millisecond
-				o := CreateONU(&olt, p, uint32(j+1), availableSTag, options.BBSim.CTag, options.BBSim.EnableAuth, options.BBSim.EnableDhcp, delay, isMock)
-				p.Onus = append(p.Onus, o)
-				availableSTag = availableSTag + 1
-			}
-
-			olt.Pons = append(olt.Pons, p)
-		}
+		olt.Pons = append(olt.Pons, p)
 	}
 
 	if !isMock {
@@ -238,7 +256,7 @@
 
 func (o *OltDevice) RestartOLT() error {
 
-	rebootDelay := common.Options.Olt.OltRebootDelay
+	rebootDelay := common.Config.Olt.OltRebootDelay
 
 	oltLogger.WithFields(log.Fields{
 		"oltId": o.ID,
@@ -298,7 +316,7 @@
 
 // newOltServer launches a new grpc server for OpenOLT
 func (o *OltDevice) newOltServer() (*grpc.Server, error) {
-	address := common.Options.BBSim.OpenOltAddress
+	address := common.Config.BBSim.OpenOltAddress
 	lis, err := net.Listen("tcp", address)
 	if err != nil {
 		oltLogger.Fatalf("OLT failed to listen: %v", err)
@@ -351,7 +369,7 @@
 	wg := sync.WaitGroup{}
 	wg.Add(3)
 
-	o.OpenoltStream = &stream
+	o.OpenoltStream = stream
 
 	// create Go routine to process all OLT events
 	go o.processOltMessages(o.enableContext, stream, &wg)
@@ -444,7 +462,7 @@
 				"messageType": message.Type,
 				"OnuId":       message.Data.OnuId,
 				"IntfId":      message.Data.IntfId,
-			}).Info("Received message on OMCI Sim channel")
+			}).Debug("Received message on OMCI Sim channel")
 
 			onuId := message.Data.OnuId
 			intfId := message.Data.IntfId
@@ -577,7 +595,7 @@
 
 func (o *OltDevice) sendPonIndication(ponPortID uint32) {
 
-	stream := *o.OpenoltStream
+	stream := o.OpenoltStream
 	pon, _ := o.GetPonById(ponPortID)
 	// Send IntfIndication for PON port
 	discoverData := &openolt.Indication_IntfInd{IntfInd: &openolt.IntfIndication{
@@ -624,7 +642,7 @@
 		data := &openolt.Indication_PortStats{
 			PortStats: stats,
 		}
-		stream := *o.OpenoltStream
+		stream := o.OpenoltStream
 		if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
 			oltLogger.Errorf("Failed to send PortStats: %v", err)
 			return
@@ -743,7 +761,7 @@
 				return
 			}
 
-			onu, err := o.FindOnuByMacAddress(onuMac)
+			s, err := o.FindServiceByMacAddress(onuMac)
 			if err != nil {
 				log.WithFields(log.Fields{
 					"IntfType":   "nni",
@@ -754,7 +772,9 @@
 				return
 			}
 
-			doubleTaggedPkt, err := packetHandlers.PushDoubleTag(onu.STag, onu.CTag, message.Pkt)
+			service := s.(*Service)
+
+			doubleTaggedPkt, err := packetHandlers.PushDoubleTag(service.STag, service.CTag, message.Pkt)
 			if err != nil {
 				log.Error("Fail to add double tag to packet")
 			}
@@ -773,9 +793,9 @@
 			oltLogger.WithFields(log.Fields{
 				"IntfType": data.PktInd.IntfType,
 				"IntfId":   nniId,
-				"Pkt":      doubleTaggedPkt.Data(),
-				"OnuSn":    onu.Sn(),
-			}).Tracef("Sent PktInd indication")
+				"Pkt":      hex.EncodeToString(doubleTaggedPkt.Data()),
+				"OnuSn":    service.Onu.Sn(),
+			}).Trace("Sent PktInd indication (from NNI to VOLTHA)")
 		}
 	}
 	wg.Done()
@@ -815,19 +835,20 @@
 	return &Onu{}, fmt.Errorf("cannot-find-onu-by-id-%v-%v", intfId, onuId)
 }
 
-// returns an ONU with a given Mac Address
-func (o *OltDevice) FindOnuByMacAddress(mac net.HardwareAddr) (*Onu, error) {
+// returns a Service with a given Mac Address
+func (o *OltDevice) FindServiceByMacAddress(mac net.HardwareAddr) (ServiceIf, error) {
 	// TODO this function can be a performance bottleneck when we have many ONUs,
 	// memoizing it will remove the bottleneck
 	for _, pon := range o.Pons {
 		for _, onu := range pon.Onus {
-			if onu.HwAddress.String() == mac.String() {
-				return onu, nil
+			s, err := onu.findServiceByMacAddress(mac)
+			if err == nil {
+				return s, nil
 			}
 		}
 	}
 
-	return &Onu{}, fmt.Errorf("cannot-find-onu-by-mac-address-%s", mac)
+	return nil, fmt.Errorf("cannot-find-service-by-mac-address-%s", mac)
 }
 
 // GRPC Endpoints
@@ -963,7 +984,7 @@
 			OnuID:     onu.ID,
 			OnuSN:     onu.SerialNumber,
 		}
-		onu.sendOnuIndication(onuIndication, *o.OpenoltStream)
+		onu.sendOnuIndication(onuIndication, o.OpenoltStream)
 
 	}
 
@@ -999,7 +1020,7 @@
 			OnuID:     onu.ID,
 			OnuSN:     onu.SerialNumber,
 		}
-		onu.sendOnuIndication(onuIndication, *o.OpenoltStream)
+		onu.sendOnuIndication(onuIndication, o.OpenoltStream)
 
 	}
 
@@ -1174,11 +1195,11 @@
 		"PonPorts": o.NumPon,
 	}).Info("OLT receives GetDeviceInfo call from VOLTHA")
 	devinfo := new(openolt.DeviceInfo)
-	devinfo.Vendor = common.Options.Olt.Vendor
-	devinfo.Model = common.Options.Olt.Model
-	devinfo.HardwareVersion = common.Options.Olt.HardwareVersion
-	devinfo.FirmwareVersion = common.Options.Olt.FirmwareVersion
-	devinfo.Technology = common.Options.Olt.Technology
+	devinfo.Vendor = common.Config.Olt.Vendor
+	devinfo.Model = common.Config.Olt.Model
+	devinfo.HardwareVersion = common.Config.Olt.HardwareVersion
+	devinfo.FirmwareVersion = common.Config.Olt.FirmwareVersion
+	devinfo.Technology = common.Config.Olt.Technology
 	devinfo.PonPorts = uint32(o.NumPon)
 	devinfo.OnuIdStart = 1
 	devinfo.OnuIdEnd = 255
@@ -1189,7 +1210,7 @@
 	devinfo.FlowIdStart = 1
 	devinfo.FlowIdEnd = 16383
 	devinfo.DeviceSerialNumber = o.SerialNumber
-	devinfo.DeviceId = common.Options.Olt.DeviceId
+	devinfo.DeviceId = common.Config.Olt.DeviceId
 
 	return devinfo, nil
 }
@@ -1254,20 +1275,34 @@
 		"IntfId": onu.PonPortID,
 		"OnuId":  onu.ID,
 		"OnuSn":  onu.Sn(),
-	}).Tracef("Received OnuPacketOut")
+	}).Info("Received OnuPacketOut")
 
 	rawpkt := gopacket.NewPacket(onuPkt.Pkt, layers.LayerTypeEthernet, gopacket.Default)
 	pktType, _ := packetHandlers.IsEapolOrDhcp(rawpkt)
 
+	pktMac, err := packetHandlers.GetDstMacAddressFromPacket(rawpkt)
+
+	if err != nil {
+		log.WithFields(log.Fields{
+			"IntfId": onu.PonPortID,
+			"OnuId":  onu.ID,
+			"OnuSn":  onu.Sn(),
+			"Pkt":    rawpkt.Data(),
+		}).Error("Can't find Dst MacAddress in packet, droppint it")
+		return new(openolt.Empty), nil
+	}
+
 	msg := Message{
 		Type: OnuPacketOut,
 		Data: OnuPacketMessage{
-			IntfId: onuPkt.IntfId,
-			OnuId:  onuPkt.OnuId,
-			Packet: rawpkt,
-			Type:   pktType,
+			IntfId:     onuPkt.IntfId,
+			OnuId:      onuPkt.OnuId,
+			Packet:     rawpkt,
+			Type:       pktType,
+			MacAddress: pktMac,
 		},
 	}
+
 	onu.Channel <- msg
 
 	return new(openolt.Empty), nil