SEBA-906 handle reenable OLT

Change-Id: I406466a5afc542d5c2e50dac5de0b33d82a54024
diff --git a/internal/bbsim/devices/olt.go b/internal/bbsim/devices/olt.go
index 1832aeb..6464c18 100644
--- a/internal/bbsim/devices/olt.go
+++ b/internal/bbsim/devices/olt.go
@@ -20,11 +20,11 @@
 	"context"
 	"errors"
 	"fmt"
-	"github.com/google/gopacket/pcap"
 	"net"
 	"sync"
 	"time"
 
+	"github.com/google/gopacket/pcap"
 	"github.com/google/gopacket"
 	"github.com/google/gopacket/layers"
 	"github.com/looplab/fsm"
@@ -130,27 +130,16 @@
 	// create PON ports
 	availableCTag := cTagInit
 	for i := 0; i < pon; i++ {
-		p := PonPort{
-			NumOnu: olt.NumOnuPerPon,
-			ID:     uint32(i),
-			Type:   "pon",
-			Olt:    olt,
-			Onus:   []*Onu{},
-		}
-		p.OperState = getOperStateFSM(func(e *fsm.Event) {
-			oltLogger.WithFields(log.Fields{
-				"ID": p.ID,
-			}).Debugf("Changing PON Port OperState from %s to %s", e.Src, e.Dst)
-		})
+		p := CreatePonPort(olt, uint32(i))
 
 		// create ONU devices
 		for j := 0; j < onuPerPon; j++ {
-			o := CreateONU(olt, p, uint32(j+1), sTag, availableCTag, auth, dhcp)
+			o := CreateONU(olt, *p, uint32(j+1), sTag, availableCTag, auth, dhcp)
 			p.Onus = append(p.Onus, o)
 			availableCTag = availableCTag + 1
 		}
 
-		olt.Pons = append(olt.Pons, &p)
+		olt.Pons = append(olt.Pons, p)
 	}
 
 	if isMock != true {
@@ -639,6 +628,26 @@
 	}).Warn("Stopped handling NNI Channel")
 }
 
+func (o *OltDevice) handleReenableOlt() {
+	// enable OLT
+	oltMsg := Message{
+		Type: OltIndication,
+		Data: OltIndicationMessage{
+			OperState: UP,
+		},
+	}
+	o.channel <- oltMsg
+
+	for i := range olt.Pons {
+		for _, onu := range olt.Pons[i].Onus {
+			if err := onu.InternalState.Event("discover"); err != nil {
+				log.Errorf("Error discover ONU: %v", err)
+			}
+		}
+	}
+
+}
+
 // returns an ONU with a given Serial Number
 func (o OltDevice) FindOnuBySn(serialNumber string) (*Onu, error) {
 	// TODO this function can be a performance bottleneck when we have many ONUs,
@@ -933,7 +942,25 @@
 }
 
 func (o OltDevice) ReenableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
-	oltLogger.Error("ReenableOlt not implemented")
+	oltLogger.WithFields(log.Fields{
+		"oltId": o.ID,
+	}).Info("Received ReenableOlt request from VOLTHA")
+
+	for _, pon := range o.Pons {
+		msg := Message{
+			Type: PonIndication,
+			Data: PonIndicationMessage{
+				OperState: UP,
+				PonPortID: pon.ID,
+			},
+		}
+		o.channel <- msg
+	}
+
+	// Openolt adapter will start processing indications only after success reponse of ReenableOlt
+	// thats why need to send OLT and ONU indications after return of this function
+	go o.handleReenableOlt()
+
 	return new(openolt.Empty), nil
 }
 
diff --git a/internal/bbsim/devices/onu.go b/internal/bbsim/devices/onu.go
index 51d9642..a37455e 100644
--- a/internal/bbsim/devices/onu.go
+++ b/internal/bbsim/devices/onu.go
@@ -113,12 +113,14 @@
 		fsm.Events{
 			// DEVICE Lifecycle
 			{Name: "initialize", Src: []string{"created", "disabled"}, Dst: "initialized"},
-			{Name: "discover", Src: []string{"initialized"}, Dst: "discovered"},
+			{Name: "discover", Src: []string{"initialized", "pon_disabled"}, Dst: "discovered"},
 			{Name: "enable", Src: []string{"discovered", "disabled"}, Dst: "enabled"},
 			{Name: "receive_eapol_flow", Src: []string{"enabled", "gem_port_added"}, Dst: "eapol_flow_received"},
 			{Name: "add_gem_port", Src: []string{"enabled", "eapol_flow_received"}, Dst: "gem_port_added"},
 			// NOTE should disabled state be different for oper_disabled (emulating an error) and admin_disabled (received a disabled call via VOLTHA)?
 			{Name: "disable", Src: []string{"enabled", "eap_response_success_received", "auth_failed", "dhcp_ack_received", "dhcp_failed"}, Dst: "disabled"},
+			// ONU state when PON port is disabled but ONU is power ON(more states should be added in src?)
+			{Name: "pon_disabled", Src: []string{"enabled", "gem_port_added", "eapol_flow_received", "eap_response_success_received", "auth_failed", "dhcp_ack_received", "dhcp_failed"}, Dst:"pon_disabled"},
 			// EAPOL
 			{Name: "start_auth", Src: []string{"eapol_flow_received", "gem_port_added", "eap_start_sent", "eap_response_identity_sent", "eap_response_challenge_sent", "eap_response_success_received", "auth_failed", "dhcp_ack_received", "dhcp_failed"}, Dst: "auth_started"},
 			{Name: "eap_start_sent", Src: []string{"auth_started"}, Dst: "eap_start_sent"},
diff --git a/internal/bbsim/devices/pon.go b/internal/bbsim/devices/pon.go
index 024716d..24b541b 100644
--- a/internal/bbsim/devices/pon.go
+++ b/internal/bbsim/devices/pon.go
@@ -23,6 +23,7 @@
 
 	"github.com/looplab/fsm"
 	"github.com/opencord/voltha-protos/v2/go/openolt"
+	log "github.com/sirupsen/logrus"
 )
 
 type PonPort struct {
@@ -39,6 +40,45 @@
 	// NOTE do we need a state machine for the PON Ports?
 }
 
+// CreatePonPort creates pon port object
+func CreatePonPort(olt OltDevice, id uint32) *PonPort {
+
+	ponPort := PonPort{
+		NumOnu: olt.NumOnuPerPon,
+		ID:     id,
+		Type:   "pon",
+		Olt:    olt,
+		Onus:   []*Onu{},
+	}
+
+	ponPort.OperState = fsm.NewFSM(
+		"down",
+		fsm.Events{
+			{Name: "enable", Src: []string{"down"}, Dst: "up"},
+			{Name: "disable", Src: []string{"up"}, Dst: "down"},
+		},
+		fsm.Callbacks{
+			"enter_up": func(e *fsm.Event) {
+				oltLogger.WithFields(log.Fields{
+					"ID": ponPort.ID,
+				}).Debugf("Changing PON Port OperState from %s to %s", e.Src, e.Dst)
+			},
+			"enter_down": func(e *fsm.Event) {
+				oltLogger.WithFields(log.Fields{
+					"ID": ponPort.ID,
+				}).Debugf("Changing PON Port OperState from %s to %s", e.Src, e.Dst)
+
+				for _, onu := range ponPort.Onus {
+					if err := onu.InternalState.Event("pon_disabled"); err != nil {
+						oltLogger.Errorf("Failed to move ONU in pon_disabled states: %v", err)
+					}
+				}
+			},
+		},
+	)
+	return &ponPort
+}
+
 func (p PonPort) GetOnuBySn(sn *openolt.SerialNumber) (*Onu, error) {
 	for _, onu := range p.Onus {
 		if bytes.Equal(onu.SerialNumber.VendorSpecific, sn.VendorSpecific) {