[VOL-2778] Accepting PBit 255 as valid classifier to start DHCP state machine

Change-Id: I8cd0c7e20277a1b6f790a1ee0381b5a2e02b0a70
diff --git a/internal/bbsim/devices/onu.go b/internal/bbsim/devices/onu.go
index 56fba07..f385a45 100644
--- a/internal/bbsim/devices/onu.go
+++ b/internal/bbsim/devices/onu.go
@@ -35,7 +35,7 @@
 	omcilib "github.com/opencord/bbsim/internal/common/omci"
 	omcisim "github.com/opencord/omci-sim"
 	"github.com/opencord/voltha-protos/v2/go/openolt"
-	tech_profile "github.com/opencord/voltha-protos/v2/go/tech_profile"
+	"github.com/opencord/voltha-protos/v2/go/tech_profile"
 	log "github.com/sirupsen/logrus"
 )
 
@@ -459,7 +459,7 @@
 		log.WithFields(log.Fields{
 			"OnuId":  message.Data.OnuId,
 			"IntfId": message.Data.IntfId,
-			"OnuSn": o.Sn(),
+			"OnuSn":  o.Sn(),
 		}).Infof("GemPort Added")
 
 		// NOTE if we receive the GemPort but we don't have EAPOL flows
@@ -737,15 +737,27 @@
 	} else if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeIPv4) &&
 		msg.Flow.Classifier.SrcPort == uint32(68) &&
 		msg.Flow.Classifier.DstPort == uint32(67) &&
-		msg.Flow.Classifier.OPbits == 0 {
+		(msg.Flow.Classifier.OPbits == 0 || msg.Flow.Classifier.OPbits == 255) {
 
-		// keep track that we received the DHCP Flows so that we can transition the state to dhcp_started
-		o.DhcpFlowReceived = true
 
 		if o.Dhcp == true {
-			// NOTE we are receiving multiple DHCP flows but we shouldn't call the transition multiple times
-			if err := o.InternalState.Event("start_dhcp"); err != nil {
-				log.Errorf("Can't go to dhcp_started: %v", err)
+			if o.DhcpFlowReceived == false {
+				// keep track that we received the DHCP Flows
+				// so that we can transition the state to dhcp_started
+				// this is needed as a check in case someone trigger DHCP from the CLI
+				o.DhcpFlowReceived = true
+
+				// now start the DHCP state machine
+				if err := o.InternalState.Event("start_dhcp"); err != nil {
+					log.Errorf("Can't go to dhcp_started: %v", err)
+				}
+			} else {
+				onuLogger.WithFields(log.Fields{
+					"IntfId":           o.PonPortID,
+					"OnuId":            o.ID,
+					"SerialNumber":     o.Sn(),
+					"DhcpFlowReceived": o.DhcpFlowReceived,
+				}).Warn("DHCP already started")
 			}
 		} else {
 			onuLogger.WithFields(log.Fields{
diff --git a/internal/bbsim/devices/onu_flow_test.go b/internal/bbsim/devices/onu_flow_test.go
index 6a4a153..e8fa451 100644
--- a/internal/bbsim/devices/onu_flow_test.go
+++ b/internal/bbsim/devices/onu_flow_test.go
@@ -272,6 +272,7 @@
 			EthType: uint32(layers.EthernetTypeIPv4),
 			SrcPort: uint32(68),
 			DstPort: uint32(67),
+			OPbits: 0,
 		},
 		Action:   &openolt.Action{},
 		Priority: int32(100),
@@ -289,6 +290,88 @@
 	assert.Equal(t, onu.DhcpFlowReceived, true)
 }
 
+func Test_HandleFlowUpdateDhcpPBit255(t *testing.T) {
+	onu := createMockOnu(1, 1, 900, 900, false, true)
+
+	onu.InternalState = fsm.NewFSM(
+		"eap_response_success_received",
+		fsm.Events{
+			{Name: "start_dhcp", Src: []string{"eap_response_success_received"}, Dst: "dhcp_started"},
+		},
+		fsm.Callbacks{},
+	)
+
+	flow := openolt.Flow{
+		AccessIntfId:  int32(onu.PonPortID),
+		OnuId:         int32(onu.ID),
+		UniId:         int32(0),
+		FlowId:        uint32(onu.ID),
+		FlowType:      "downstream",
+		AllocId:       int32(0),
+		NetworkIntfId: int32(0),
+		Classifier: &openolt.Classifier{
+			EthType: uint32(layers.EthernetTypeIPv4),
+			SrcPort: uint32(68),
+			DstPort: uint32(67),
+			OPbits: 0,
+		},
+		Action:   &openolt.Action{},
+		Priority: int32(100),
+		PortNo:   uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
+	}
+
+	msg := OnuFlowUpdateMessage{
+		PonPortID: 1,
+		OnuID:     1,
+		Flow:      &flow,
+	}
+
+	onu.handleFlowUpdate(msg)
+	assert.Equal(t, onu.InternalState.Current(), "dhcp_started")
+	assert.Equal(t, onu.DhcpFlowReceived, true)
+}
+
+func Test_HandleFlowUpdateDhcpIgnoreByPbit(t *testing.T) {
+	onu := createMockOnu(1, 1, 900, 900, false, true)
+
+	onu.InternalState = fsm.NewFSM(
+		"eap_response_success_received",
+		fsm.Events{
+			{Name: "start_dhcp", Src: []string{"eap_response_success_received"}, Dst: "dhcp_started"},
+		},
+		fsm.Callbacks{},
+	)
+
+	flow := openolt.Flow{
+		AccessIntfId:  int32(onu.PonPortID),
+		OnuId:         int32(onu.ID),
+		UniId:         int32(0),
+		FlowId:        uint32(onu.ID),
+		FlowType:      "downstream",
+		AllocId:       int32(0),
+		NetworkIntfId: int32(0),
+		Classifier: &openolt.Classifier{
+			EthType: uint32(layers.EthernetTypeIPv4),
+			SrcPort: uint32(68),
+			DstPort: uint32(67),
+			OPbits: 1,
+		},
+		Action:   &openolt.Action{},
+		Priority: int32(100),
+		PortNo:   uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
+	}
+
+	msg := OnuFlowUpdateMessage{
+		PonPortID: 1,
+		OnuID:     1,
+		Flow:      &flow,
+	}
+
+	onu.handleFlowUpdate(msg)
+	assert.Equal(t, onu.InternalState.Current(), "eap_response_success_received")
+	assert.Equal(t, onu.DhcpFlowReceived, false)
+}
+
 func Test_HandleFlowUpdateDhcpNoDhcp(t *testing.T) {
 	onu := createMockOnu(1, 1, 900, 900, false, false)
 
@@ -326,5 +409,5 @@
 
 	onu.handleFlowUpdate(msg)
 	assert.Equal(t, onu.InternalState.Current(), "eap_response_success_received")
-	assert.Equal(t, onu.DhcpFlowReceived, true)
+	assert.Equal(t, onu.DhcpFlowReceived, false)
 }