Merge "[VOL-4552] Test FTTB support in BBSIM"
diff --git a/internal/bbsim/devices/flows_test.go b/internal/bbsim/devices/flows_test.go
new file mode 100644
index 0000000..391b39e
--- /dev/null
+++ b/internal/bbsim/devices/flows_test.go
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package devices
+
+import (
+ "context"
+ "testing"
+ "time"
+
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
+ "github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
+ "github.com/opencord/bbsim/internal/common"
+ "github.com/opencord/voltha-protos/v5/go/openolt"
+ "github.com/stretchr/testify/assert"
+)
+
+func getTestOlt(t *testing.T, ctx context.Context, services []common.ServiceYaml) (olt *OltDevice, pon *PonPort, onu *Onu, uni *UniPort, stream *mockStream) {
+ common.Services = services
+
+ common.Config = &common.GlobalConfig{
+ Olt: common.OltConfig{
+ ID: 1,
+ NniPorts: 1,
+ PonPorts: 1,
+ OnusPonPort: 1,
+ UniPorts: 1,
+ },
+ }
+
+ olt = CreateOLT(*common.Config, common.Services, true)
+
+ stream = &mockStream{
+ Calls: make(map[int]*openolt.Indication),
+ }
+ olt.OpenoltStream = stream
+ olt.enableContext = ctx
+
+ if len(olt.Pons) <= 0 {
+ assert.Fail(t, "No PONs on OLT")
+ return
+ }
+ pon = olt.Pons[0]
+
+ if len(pon.Onus) <= 0 {
+ assert.Fail(t, "No ONUs on PON")
+ return
+ }
+ onu = pon.Onus[0]
+
+ if len(onu.UniPorts) <= 0 {
+ assert.Fail(t, "No UNIs on ONU")
+ return
+ }
+ uni = onu.UniPorts[0].(*UniPort)
+
+ _, err := olt.ActivateOnu(ctx, &openolt.Onu{
+ IntfId: pon.ID,
+ OnuId: onu.ID,
+ SerialNumber: onu.SerialNumber,
+ })
+
+ assert.Nil(t, err)
+
+ assert.Equal(t, len(services), len(uni.Services))
+ for i, s := range uni.Services {
+ service := s.(*Service)
+ assert.Equal(t, services[i].Name, service.Name)
+ assert.Equal(t, services[i].NeedsDhcp, service.NeedsDhcp)
+ }
+
+ err = onu.InternalState.Event(OnuTxInitialize)
+ assert.Nil(t, err)
+
+ //A mock ONU won't start processing messages, so we have to call it manually
+ go onu.ProcessOnuMessages(ctx, stream, nil)
+
+ err = onu.InternalState.Event(OnuTxDiscover)
+ assert.Nil(t, err)
+ err = onu.InternalState.Event(OnuTxEnable)
+ assert.Nil(t, err)
+
+ err = uni.Enable()
+ assert.Nil(t, err)
+
+ return
+}
+
+func addTestFlow(t *testing.T, ctx context.Context, olt *OltDevice, onu *Onu, flow openolt.Flow) {
+ //Check if the flow is correctly added
+ _, err := olt.FlowAdd(ctx, &flow)
+ assert.Nil(t, err)
+}
+
+func removeTestFlow(t *testing.T, ctx context.Context, olt *OltDevice, onu *Onu, flow openolt.Flow) {
+ //Check if the flow is correctly removed
+ _, err := olt.FlowRemove(ctx, &flow)
+ assert.Nil(t, err)
+}
+
+func Test_Flows_FttbTrapRules(t *testing.T) {
+ const (
+ VID_VENDOR_MGMT = 6
+ VID_NETWORK_DPU_MGMT = 60
+
+ allocId = int32(1024)
+ gemportId = int32(1024)
+ uniPortNo = uint32(256)
+ nniId = 0
+ nniPortNo = 0x1000000
+ pbitNone = 255
+
+ dhcpServiceName = "dpu_dhcp"
+ hsiaServicename = "hsia"
+ )
+
+ testServices := []common.ServiceYaml{
+ {Name: dhcpServiceName, CTag: 60, CTagAllocation: common.TagAllocationShared.String(), STagAllocation: common.TagAllocationShared.String(), NeedsDhcp: true, TechnologyProfileID: 64},
+ {Name: hsiaServicename, UniTagMatch: 4096, CTag: 4096, CTagAllocation: common.TagAllocationShared.String(), STag: 3101, STagAllocation: common.TagAllocationUnique.String(), TechnologyProfileID: 64},
+ }
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ olt, pon, onu, uni, stream := getTestOlt(t, ctx, testServices)
+
+ flows := []openolt.Flow{
+ {
+ AccessIntfId: int32(pon.ID),
+ OnuId: int32(onu.ID),
+ UniId: int32(uni.ID),
+ FlowId: 1,
+ FlowType: flowTypeUpstream,
+ AllocId: allocId,
+ NetworkIntfId: nniId,
+ GemportId: gemportId,
+ Classifier: &openolt.Classifier{
+ OVid: VID_NETWORK_DPU_MGMT,
+ OPbits: pbitNone,
+ EthType: uint32(layers.EthernetTypeIPv4),
+ IpProto: uint32(layers.IPProtocolUDP),
+ SrcPort: 68,
+ DstPort: 67,
+ PktTagType: flowTagTypeSingle,
+ },
+ Action: &openolt.Action{
+ Cmd: &openolt.ActionCmd{
+ TrapToHost: true,
+ },
+ },
+ Priority: 40000,
+ PortNo: uniPortNo,
+ },
+ {
+ AccessIntfId: -1,
+ OnuId: -1,
+ UniId: -1,
+ FlowId: 2,
+ FlowType: flowTypeDownstream,
+ AllocId: -1,
+ NetworkIntfId: nniId,
+ GemportId: -1,
+ Classifier: &openolt.Classifier{
+ OVid: VID_NETWORK_DPU_MGMT,
+ OPbits: pbitNone,
+ EthType: uint32(layers.EthernetTypeIPv4),
+ IpProto: uint32(layers.IPProtocolUDP),
+ SrcPort: 67,
+ PktTagType: flowTagTypeDouble,
+ },
+ Action: &openolt.Action{
+ Cmd: &openolt.ActionCmd{
+ TrapToHost: true,
+ },
+ },
+ Priority: 40000,
+ PortNo: nniPortNo,
+ },
+ }
+
+ for _, f := range flows {
+ addTestFlow(t, ctx, olt, onu, f)
+ }
+
+ //Wait a bit for messages on various channels to be processed
+ time.Sleep(time.Second)
+
+ //Check if a DHCP request is sent correctly after trap rules have been added
+ assert.True(t, stream.CallCount > 0)
+ dhcpCall := stream.Calls[stream.CallCount]
+
+ switch ind := dhcpCall.Data.(type) {
+ case *openolt.Indication_PktInd:
+ assert.Equal(t, uniPortNo, ind.PktInd.PortNo)
+ assert.Equal(t, pon.ID, ind.PktInd.IntfId)
+ assert.Equal(t, "pon", ind.PktInd.IntfType)
+ assert.Equal(t, uint32(gemportId), ind.PktInd.GemportId)
+
+ packet := gopacket.NewPacket(ind.PktInd.Pkt, layers.LayerTypeEthernet, gopacket.Default)
+ _, err := dhcp.GetDhcpLayer(packet)
+ assert.Nil(t, err)
+ default:
+ assert.Fail(t, "Wrong indication type for DHCP request")
+ }
+
+ for _, f := range flows {
+ removeTestFlow(t, ctx, olt, onu, f)
+ }
+}
diff --git a/internal/bbsim/devices/helpers.go b/internal/bbsim/devices/helpers.go
index 1389162..bc88dca 100644
--- a/internal/bbsim/devices/helpers.go
+++ b/internal/bbsim/devices/helpers.go
@@ -43,6 +43,14 @@
"both": Both,
}
+//Constants for openolt Flows
+const (
+ flowTypeUpstream = "upstream"
+ flowTypeDownstream = "downstream"
+ flowTagTypeSingle = "single_tag"
+ flowTagTypeDouble = "double_tag"
+)
+
var newFSM = fsm.NewFSM
func getOperStateFSM(cb fsm.Callback) *fsm.FSM {
diff --git a/internal/bbsim/devices/onu.go b/internal/bbsim/devices/onu.go
index b19cf39..e460956 100644
--- a/internal/bbsim/devices/onu.go
+++ b/internal/bbsim/devices/onu.go
@@ -1674,7 +1674,7 @@
OnuId: int32(o.ID),
UniId: int32(0), // NOTE do not hardcode this, we need to support multiple UNIs
FlowId: uint64(o.ID),
- FlowType: "downstream",
+ FlowType: flowTypeDownstream,
NetworkIntfId: int32(0),
Classifier: &classifierProto,
Action: &actionProto,
@@ -1725,7 +1725,7 @@
OnuId: int32(o.ID),
UniId: int32(0), // BBR only supports a single UNI
FlowId: uint64(o.ID),
- FlowType: "downstream",
+ FlowType: flowTypeDownstream,
NetworkIntfId: int32(0),
Classifier: &classifierProto,
Action: &actionProto,
diff --git a/internal/bbsim/devices/onu_flow_test.go b/internal/bbsim/devices/onu_flow_test.go
index 66a775f..f0d55fd 100644
--- a/internal/bbsim/devices/onu_flow_test.go
+++ b/internal/bbsim/devices/onu_flow_test.go
@@ -17,12 +17,13 @@
package devices
import (
+ "testing"
+
"github.com/google/gopacket/layers"
"github.com/looplab/fsm"
"github.com/opencord/bbsim/internal/bbsim/types"
"github.com/opencord/voltha-protos/v5/go/openolt"
"gotest.tools/assert"
- "testing"
)
// test that BBR correctly sends the EAPOL Flow
@@ -43,7 +44,7 @@
assert.Equal(t, client.FlowAddSpy.Calls[1].OnuId, int32(onu.ID))
assert.Equal(t, client.FlowAddSpy.Calls[1].UniId, int32(0))
assert.Equal(t, client.FlowAddSpy.Calls[1].FlowId, uint64(onu.ID))
- assert.Equal(t, client.FlowAddSpy.Calls[1].FlowType, "downstream")
+ assert.Equal(t, client.FlowAddSpy.Calls[1].FlowType, flowTypeDownstream)
assert.Equal(t, client.FlowAddSpy.Calls[1].PortNo, onu.ID)
}
@@ -152,7 +153,7 @@
OnuId: int32(onu.ID),
UniId: int32(0),
FlowId: uint64(onu.ID),
- FlowType: "downstream",
+ FlowType: flowTypeDownstream,
AllocId: int32(0),
NetworkIntfId: int32(0),
Classifier: &openolt.Classifier{
@@ -199,7 +200,7 @@
OnuId: int32(onu.ID),
UniId: int32(0),
FlowId: uint64(onu.ID),
- FlowType: "downstream",
+ FlowType: flowTypeDownstream,
AllocId: int32(0),
NetworkIntfId: int32(0),
Classifier: &openolt.Classifier{
@@ -240,7 +241,7 @@
OnuId: int32(onu.ID),
UniId: int32(1),
FlowId: uint64(onu.ID),
- FlowType: "downstream",
+ FlowType: flowTypeDownstream,
AllocId: int32(0),
NetworkIntfId: int32(0),
Classifier: &openolt.Classifier{
@@ -282,7 +283,7 @@
OnuId: int32(onu.ID),
UniId: int32(0),
FlowId: uint64(onu.ID),
- FlowType: "downstream",
+ FlowType: flowTypeDownstream,
AllocId: int32(0),
NetworkIntfId: int32(0),
Classifier: &openolt.Classifier{
@@ -326,7 +327,7 @@
OnuId: int32(onu.ID),
UniId: int32(0),
FlowId: uint64(onu.ID),
- FlowType: "downstream",
+ FlowType: flowTypeDownstream,
AllocId: int32(0),
NetworkIntfId: int32(0),
Classifier: &openolt.Classifier{
@@ -370,7 +371,7 @@
OnuId: int32(onu.ID),
UniId: int32(0),
FlowId: uint64(onu.ID),
- FlowType: "downstream",
+ FlowType: flowTypeDownstream,
AllocId: int32(0),
NetworkIntfId: int32(0),
Classifier: &openolt.Classifier{
@@ -413,7 +414,7 @@
OnuId: int32(onu.ID),
UniId: int32(0),
FlowId: uint64(onu.ID),
- FlowType: "downstream",
+ FlowType: flowTypeDownstream,
AllocId: int32(0),
NetworkIntfId: int32(0),
Classifier: &openolt.Classifier{
@@ -458,7 +459,7 @@
OnuId: int32(onu.ID),
UniId: int32(0),
FlowId: uint64(onu.ID),
- FlowType: "downstream",
+ FlowType: flowTypeDownstream,
AllocId: int32(0),
NetworkIntfId: int32(0),
Classifier: &openolt.Classifier{