blob: 512782a51cfcaf5b56c486c0d368ac6215071899 [file] [log] [blame]
Elia Battiston560e9552022-01-31 10:44:15 +01001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package devices
18
19import (
20 "context"
21 "testing"
22 "time"
23
24 "github.com/google/gopacket"
25 "github.com/google/gopacket/layers"
26 "github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
27 "github.com/opencord/bbsim/internal/common"
28 "github.com/opencord/voltha-protos/v5/go/openolt"
29 "github.com/stretchr/testify/assert"
30)
31
32func getTestOlt(t *testing.T, ctx context.Context, services []common.ServiceYaml) (olt *OltDevice, pon *PonPort, onu *Onu, uni *UniPort, stream *mockStream) {
33 common.Services = services
34
35 common.Config = &common.GlobalConfig{
36 Olt: common.OltConfig{
37 ID: 1,
38 NniPorts: 1,
39 PonPorts: 1,
40 OnusPonPort: 1,
41 UniPorts: 1,
42 },
43 }
44
Elia Battistonb7bea222022-02-18 16:25:00 +010045 allocIdPerOnu := uint32(common.Config.Olt.UniPorts * uint32(len(common.Services)))
46 common.PonsConfig = &common.PonPortsConfig{
47 Number: common.Config.Olt.PonPorts,
48 Ranges: []common.PonRangeConfig{
49 {
50 PonRange: common.IdRange{StartId: 0, EndId: common.Config.Olt.PonPorts - 1},
51 Technology: common.XGSPON.String(),
52 OnuRange: common.IdRange{StartId: 1, EndId: 1 + (common.Config.Olt.OnusPonPort - 1)},
53 AllocIdRange: common.IdRange{StartId: 1024, EndId: 1024 + (common.Config.Olt.OnusPonPort * allocIdPerOnu)},
54 GemportRange: common.IdRange{StartId: 1024, EndId: 1024 + common.Config.Olt.OnusPonPort*allocIdPerOnu*8},
55 },
56 },
57 }
58
Elia Battiston560e9552022-01-31 10:44:15 +010059 olt = CreateOLT(*common.Config, common.Services, true)
60
61 stream = &mockStream{
62 Calls: make(map[int]*openolt.Indication),
63 }
64 olt.OpenoltStream = stream
65 olt.enableContext = ctx
66
67 if len(olt.Pons) <= 0 {
68 assert.Fail(t, "No PONs on OLT")
69 return
70 }
71 pon = olt.Pons[0]
72
73 if len(pon.Onus) <= 0 {
74 assert.Fail(t, "No ONUs on PON")
75 return
76 }
77 onu = pon.Onus[0]
78
79 if len(onu.UniPorts) <= 0 {
80 assert.Fail(t, "No UNIs on ONU")
81 return
82 }
83 uni = onu.UniPorts[0].(*UniPort)
84
85 _, err := olt.ActivateOnu(ctx, &openolt.Onu{
86 IntfId: pon.ID,
87 OnuId: onu.ID,
88 SerialNumber: onu.SerialNumber,
89 })
90
91 assert.Nil(t, err)
92
93 assert.Equal(t, len(services), len(uni.Services))
94 for i, s := range uni.Services {
95 service := s.(*Service)
96 assert.Equal(t, services[i].Name, service.Name)
97 assert.Equal(t, services[i].NeedsDhcp, service.NeedsDhcp)
98 }
99
100 err = onu.InternalState.Event(OnuTxInitialize)
101 assert.Nil(t, err)
102
103 //A mock ONU won't start processing messages, so we have to call it manually
104 go onu.ProcessOnuMessages(ctx, stream, nil)
105
106 err = onu.InternalState.Event(OnuTxDiscover)
107 assert.Nil(t, err)
108 err = onu.InternalState.Event(OnuTxEnable)
109 assert.Nil(t, err)
110
111 err = uni.Enable()
112 assert.Nil(t, err)
113
114 return
115}
116
117func addTestFlow(t *testing.T, ctx context.Context, olt *OltDevice, onu *Onu, flow openolt.Flow) {
118 //Check if the flow is correctly added
119 _, err := olt.FlowAdd(ctx, &flow)
120 assert.Nil(t, err)
121}
122
123func removeTestFlow(t *testing.T, ctx context.Context, olt *OltDevice, onu *Onu, flow openolt.Flow) {
124 //Check if the flow is correctly removed
125 _, err := olt.FlowRemove(ctx, &flow)
126 assert.Nil(t, err)
127}
128
129func Test_Flows_FttbTrapRules(t *testing.T) {
130 const (
131 VID_VENDOR_MGMT = 6
132 VID_NETWORK_DPU_MGMT = 60
133
134 allocId = int32(1024)
135 gemportId = int32(1024)
136 uniPortNo = uint32(256)
137 nniId = 0
138 nniPortNo = 0x1000000
139 pbitNone = 255
140
141 dhcpServiceName = "dpu_dhcp"
142 hsiaServicename = "hsia"
143 )
144
145 testServices := []common.ServiceYaml{
146 {Name: dhcpServiceName, CTag: 60, CTagAllocation: common.TagAllocationShared.String(), STagAllocation: common.TagAllocationShared.String(), NeedsDhcp: true, TechnologyProfileID: 64},
147 {Name: hsiaServicename, UniTagMatch: 4096, CTag: 4096, CTagAllocation: common.TagAllocationShared.String(), STag: 3101, STagAllocation: common.TagAllocationUnique.String(), TechnologyProfileID: 64},
148 }
149
150 ctx, cancel := context.WithCancel(context.Background())
151 defer cancel()
152
153 olt, pon, onu, uni, stream := getTestOlt(t, ctx, testServices)
154
155 flows := []openolt.Flow{
156 {
157 AccessIntfId: int32(pon.ID),
158 OnuId: int32(onu.ID),
159 UniId: int32(uni.ID),
160 FlowId: 1,
161 FlowType: flowTypeUpstream,
162 AllocId: allocId,
163 NetworkIntfId: nniId,
164 GemportId: gemportId,
165 Classifier: &openolt.Classifier{
166 OVid: VID_NETWORK_DPU_MGMT,
167 OPbits: pbitNone,
168 EthType: uint32(layers.EthernetTypeIPv4),
169 IpProto: uint32(layers.IPProtocolUDP),
170 SrcPort: 68,
171 DstPort: 67,
172 PktTagType: flowTagTypeSingle,
173 },
174 Action: &openolt.Action{
175 Cmd: &openolt.ActionCmd{
176 TrapToHost: true,
177 },
178 },
179 Priority: 40000,
180 PortNo: uniPortNo,
181 },
182 {
183 AccessIntfId: -1,
184 OnuId: -1,
185 UniId: -1,
186 FlowId: 2,
187 FlowType: flowTypeDownstream,
188 AllocId: -1,
189 NetworkIntfId: nniId,
190 GemportId: -1,
191 Classifier: &openolt.Classifier{
192 OVid: VID_NETWORK_DPU_MGMT,
193 OPbits: pbitNone,
194 EthType: uint32(layers.EthernetTypeIPv4),
195 IpProto: uint32(layers.IPProtocolUDP),
196 SrcPort: 67,
197 PktTagType: flowTagTypeDouble,
198 },
199 Action: &openolt.Action{
200 Cmd: &openolt.ActionCmd{
201 TrapToHost: true,
202 },
203 },
204 Priority: 40000,
205 PortNo: nniPortNo,
206 },
207 }
208
209 for _, f := range flows {
210 addTestFlow(t, ctx, olt, onu, f)
211 }
212
213 //Wait a bit for messages on various channels to be processed
214 time.Sleep(time.Second)
215
216 //Check if a DHCP request is sent correctly after trap rules have been added
217 assert.True(t, stream.CallCount > 0)
218 dhcpCall := stream.Calls[stream.CallCount]
219
220 switch ind := dhcpCall.Data.(type) {
221 case *openolt.Indication_PktInd:
222 assert.Equal(t, uniPortNo, ind.PktInd.PortNo)
223 assert.Equal(t, pon.ID, ind.PktInd.IntfId)
224 assert.Equal(t, "pon", ind.PktInd.IntfType)
225 assert.Equal(t, uint32(gemportId), ind.PktInd.GemportId)
226
227 packet := gopacket.NewPacket(ind.PktInd.Pkt, layers.LayerTypeEthernet, gopacket.Default)
228 _, err := dhcp.GetDhcpLayer(packet)
229 assert.Nil(t, err)
230 default:
231 assert.Fail(t, "Wrong indication type for DHCP request")
232 }
233
234 for _, f := range flows {
235 removeTestFlow(t, ctx, olt, onu, f)
236 }
237}